[gradle] 03/16: Imported Upstream version 2.7
Kai-Chung Yan
seamlik-guest at moszumanska.debian.org
Wed Sep 30 00:37:57 UTC 2015
This is an automated email from the git hooks/post-receive script.
seamlik-guest pushed a commit to branch master
in repository gradle.
commit 8af35fb0a36bd6f8b03d09f579b4c78f73f11265
Author: Kai-Chung Yan <seamlikok at gmail.com>
Date: Wed Sep 30 05:01:05 2015 +0800
Imported Upstream version 2.7
---
build.gradle | 28 +-
.../docs/dsl/docbook/ClassDescriptionRenderer.java | 55 +-
.../docs/dsl/docbook/ClassDocSuperTypeBuilder.java | 2 +
.../build/docs/dsl/docbook/model/ClassDoc.groovy | 7 +
.../docs/dsl/docbook/ClassDocRendererTest.groovy | 100 +-
config/checkstyle/suppressions.xml | 7 +
gradle/dependencies.gradle | 2 +-
gradle/groovyProject.gradle | 9 +-
gradle/idea.gradle | 1 -
gradle/integTest.gradle | 21 +-
gradle/java9.gradle | 6 +-
gradle/pullRequestBuild.gradle | 76 ++
gradle/testGroupings.gradle | 15 +-
gradle/wrapper/gradle-wrapper.properties | 4 +-
settings.gradle | 1 +
.../antlr/AbstractAntlrIntegrationTest.groovy | 1 +
.../antlr/Antlr2PluginIntegrationTest.groovy | 40 +-
.../antlr/Antlr3PluginIntegrationTest.groovy | 47 +-
.../antlr/Antlr4PluginIntegrationTest.groovy | 73 +-
.../plugins/antlr/AntlrSourceVirtualDirectory.java | 2 +-
.../org/gradle/api/plugins/antlr/AntlrTask.java | 60 +-
.../api/plugins/antlr/internal/AntlrExecuter.java | 222 +++-
.../api/plugins/antlr/internal/AntlrSpec.java | 17 +-
.../plugins/antlr/internal/AntlrSpecFactory.java | 5 +-
.../antlr/internal/antlr2/MetadataExtracter.java | 63 +-
.../antlr/internal/AntlrSpecFactoryTest.groovy | 27 +-
.../internal/antlr2/MetadataExtracterTest.groovy | 105 ++
.../gradle/groovy/scripts/internal/AstUtils.java | 23 +-
.../ScriptSourceDescriptionTransformer.java | 41 -
.../scripts/internal/ScriptSourceTransformer.java | 50 +
.../java/org/gradle/internal/SystemProperties.java | 4 +
.../internal/file/RelativeFilePathResolver.java | 21 +
.../java/org/gradle/internal/hash/HashUtil.java | 12 +
.../src/main/java/org/gradle/internal/jvm/Jvm.java | 17 +
.../org/gradle/internal/reflect/ClassDetails.java | 9 +
.../gradle/internal/reflect/ClassInspector.java | 187 +--
.../internal/reflect/JavaReflectionUtil.java | 46 +
.../org/gradle/internal/reflect/MethodSet.java | 49 +
.../gradle/internal/reflect/MethodSignature.java | 40 +
.../reflect/MethodSignatureEquivalence.java | 16 +-
.../internal/reflect/MutableClassDetails.java | 87 ++
.../internal/reflect/MutablePropertyDetails.java | 53 +
.../gradle/internal/reflect/PropertyDetails.java | 20 +
.../src/main/java/org/gradle/util/TextUtil.java | 6 +-
.../org/gradle/internal/hash/HashUtilTest.groovy | 27 +-
.../groovy/org/gradle/internal/jvm/JvmTest.groovy | 26 +-
.../internal/reflect/ClassInspectorTest.groovy | 64 +
.../internal/reflect/JavaReflectionUtilTest.groovy | 17 +
.../internal/reflect/MethodDescriptionTest.groovy | 11 +
.../plugins/internal/BuildInitServices.java | 3 +
.../AbstractFindBugsPluginIntegrationTest.groovy | 44 +-
...ckstylePluginDependenciesIntegrationTest.groovy | 80 ++
.../quality/CheckstylePluginIntegrationTest.groovy | 164 +--
.../CheckstylePluginVersionIntegrationTest.groovy | 177 +++
.../internal/FindBugsSpecBuilderTest.groovy | 12 +-
.../gradle/api/plugins/quality/Checkstyle.groovy | 8 +-
.../api/plugins/quality/CheckstylePlugin.groovy | 1 -
.../api/plugins/quality/CheckstyleReports.java | 2 +-
.../org/gradle/api/plugins/quality/FindBugs.groovy | 30 +-
.../api/plugins/quality/FindBugsExtension.groovy | 13 +
.../api/plugins/quality/FindBugsPlugin.groovy | 2 +
.../internal/findbugs/FindBugsSpecBuilder.java | 26 +-
.../plugins/quality/CheckstylePluginTest.groovy | 18 +-
.../api/plugins/quality/FindBugsPluginTest.groovy | 8 +-
.../gradle/api/plugins/quality/FindBugsTest.groovy | 17 +
.../integtest/fixtures/CheckstyleCoverage.groovy | 29 +
.../api/BuildScriptErrorIntegrationTest.groovy | 29 +
.../api/ProgressLoggingIntegrationTest.groovy | 52 +
.../BuildScriptVisibilityIntegrationTest.groovy | 245 ++++
.../api/dsl/DynamicObjectIntegrationTest.groovy | 1 +
.../ClassLoadersCachingIntegrationTest.groovy | 27 +-
.../taskfactory/TaskFactoryIntegrationTest.groovy | 38 +
.../api/tasks/CopyTaskIntegrationTest.groovy | 29 +
.../api/tasks/TaskRemovalIntegrationTest.groovy | 2 +-
.../RuleBasedTaskActionsIntegrationTest.groovy | 87 ++
.../RuleBasedTaskReferenceIntegrationTest.groovy | 90 ++
.../execution/taskgraph/WithRuleBasedTasks.groovy | 48 +
...tiveBuildScriptEvaluationIntegrationTest.groovy | 2 +
.../ScriptPluginClassLoadingIntegrationTest.groovy | 2 +-
.../api/tasks/copyTestResources/src/two/two.b | 4 +-
.../src/main/groovy/org/gradle/StartParameter.java | 4 +-
.../groovy/org/gradle/TaskExecutionLogger.java | 8 +-
.../org/gradle/api/artifacts/ResolveContext.java | 28 -
.../org/gradle/api/artifacts/ResolveException.java | 12 +-
.../org/gradle/api/artifacts/ResolvedArtifact.java | 6 +
.../component/ComponentArtifactIdentifier.java | 35 +
.../component/LibraryBinaryIdentifier.java | 44 +
.../component/LibraryComponentIdentifier.java | 28 -
.../component/LibraryComponentSelector.java | 17 +
.../api/artifacts/dsl/DependencyHandler.java | 22 +-
.../repositories/AuthenticationContainer.java | 28 +
.../repositories/AuthenticationSupported.java | 38 +-
.../org/gradle/api/file/ContentFilterable.java | 3 +-
.../api/internal/DependencyClassPathProvider.java | 8 +
.../gradle/api/internal/DocumentationRegistry.java | 6 +-
.../api/internal/GradleDistributionLocator.java | 11 +
.../dsl/dependencies/DefaultDependencyHandler.java | 6 +-
.../dsl/dependencies/DependencyFactory.java | 4 +-
.../repositories/DefaultPasswordCredentials.java | 0
.../DefaultGradleDistributionLocator.java | 117 ++
.../internal/classpath/DefaultModuleRegistry.java | 145 +--
.../org/gradle/api/internal/classpath/Module.java | 6 +-
.../api/internal/classpath/ModuleRegistry.java | 7 +
.../org/gradle/api/internal/file/FileResolver.java | 5 +-
.../gradle/api/internal/file/copy/LineFilter.java | 33 +-
.../initialization/DefaultScriptHandler.java | 30 +-
.../DefaultScriptHandlerFactory.java | 8 +-
.../plugins/DefaultObjectConfigurationAction.java | 3 +-
.../org/gradle/api/internal/plugins/DslObject.java | 13 +-
.../api/internal/project/AbstractProject.java | 60 +-
.../project/DeferredProjectConfiguration.java | 8 +-
.../api/internal/project/ProjectInternal.java | 5 +-
.../api/internal/rules/ModelMapCreators.java | 2 +-
.../groovy/org/gradle/api/invocation/Gradle.java | 2 +-
.../main/groovy/org/gradle/api/tasks/Input.java | 5 +
.../org/gradle/api/tasks/InputDirectory.java | 4 +
.../groovy/org/gradle/api/tasks/InputFile.java | 4 +
.../groovy/org/gradle/api/tasks/InputFiles.java | 3 +
.../org/gradle/api/tasks/OutputDirectories.java | 3 +
.../org/gradle/api/tasks/OutputDirectory.java | 3 +
.../groovy/org/gradle/api/tasks/OutputFile.java | 3 +
.../groovy/org/gradle/api/tasks/OutputFiles.java | 3 +
.../tasks/incremental/IncrementalTaskInputs.java | 6 +-
.../configuration/DefaultInitScriptProcessor.java | 3 +-
.../configuration/DefaultScriptPluginFactory.java | 82 +-
.../gradle/configuration/DefaultScriptTarget.java | 71 ++
.../org/gradle/configuration/InitScriptTarget.java | 42 +
.../gradle/configuration/ProjectScriptTarget.java | 75 ++
.../gradle/configuration/ScriptPluginFactory.java | 3 +-
.../org/gradle/configuration/ScriptTarget.java | 54 +
.../gradle/configuration/SettingScriptTarget.java | 38 +
.../project/BuildScriptProcessor.java | 3 +-
.../internal/DefaultDeploymentRegistry.java | 88 ++
.../deployment/internal/DeploymentHandle.java | 25 +
.../deployment/internal/DeploymentRegistry.java | 48 +
.../BuildConfigurationActionExecuter.java | 37 +
.../groovy/org/gradle/execution/BuildExecuter.java | 12 +-
.../DefaultBuildConfigurationActionExecuter.java | 59 +
.../org/gradle/execution/DefaultBuildExecuter.java | 35 +-
.../gradle/execution/TaskSelectionException.java | 5 +-
.../taskgraph/DefaultTaskGraphExecuter.java | 29 +-
.../scripts/DefaultScriptCompilerFactory.java | 6 +-
.../org/gradle/groovy/scripts/ScriptAware.java | 20 -
.../org/gradle/groovy/scripts/ScriptCompiler.java | 2 +-
.../groovy/scripts/ScriptExecutionListener.java | 4 +-
.../org/gradle/groovy/scripts/ScriptRunner.java | 26 +-
.../internal/AsmBackedEmptyScriptGenerator.java | 86 --
.../groovy/scripts/internal/BuildScriptData.java | 36 +
.../internal/BuildScriptDataSerializer.java | 33 +
.../scripts/internal/BuildScriptTransformer.java | 10 +-
.../internal/CachingScriptClassCompiler.java | 22 +-
.../internal/ClassCachingCompiledScript.java | 42 -
.../groovy/scripts/internal/CompileOperation.java | 3 +
.../groovy/scripts/internal/CompiledScript.java | 9 +
.../internal/DefaultScriptCompilationHandler.java | 213 ++--
.../internal/DefaultScriptRunnerFactory.java | 30 +-
.../FileCacheBackedScriptClassCompiler.java | 16 +-
.../ImperativeStatementDetectingTransformer.java | 298 +----
.../scripts/internal/ScriptClassCompiler.java | 2 +-
.../scripts/internal/ScriptCompilationHandler.java | 4 +-
.../internal/ShortCircuitEmptyScriptCompiler.java | 25 +-
.../initialization/DefaultExceptionAnalyser.java | 11 +-
.../initialization/DefaultGradleLauncher.java | 70 +-
.../DefaultGradleLauncherFactory.java | 40 +-
.../org/gradle/initialization/GradleLauncher.java | 14 +-
.../initialization/GradleLauncherFactory.java | 4 +-
.../gradle/initialization/InitScriptHandler.java | 24 +-
.../initialization/NotifyingSettingsLoader.java | 39 +
.../initialization/NotifyingSettingsProcessor.java | 46 +
.../ScriptEvaluatingSettingsProcessor.java | 2 +-
.../org/gradle/initialization/SettingsHandler.java | 3 +-
.../org/gradle/initialization/SettingsLoader.java | 24 +
.../gradle/initialization/SettingsProcessor.java | 2 +-
.../initialization/TasksCompletionListener.java | 26 -
.../buildsrc/BuildSourceBuilder.java | 18 +-
.../buildsrc/BuildSrcUpdateFactory.java | 1 -
.../AuthenticationSupportedInternal.java | 11 +-
.../authentication/AbstractAuthentication.java | 84 ++
.../authentication/AllSchemesAuthentication.java | 41 +
.../authentication/AuthenticationInternal.java | 36 +
.../DefaultAuthenticationContainer.java | 30 +
.../ScriptUsageLocationReporter.java | 7 +-
.../internal/graph/CachingDirectedGraphWalker.java | 6 +-
.../internal/progress/BuildOperationDetails.java | 74 ++
.../internal/progress/BuildOperationExecutor.java | 36 +-
.../internal/progress/BuildOperationInternal.java | 10 +-
.../internal/progress/BuildOperationType.java | 45 -
.../progress/DefaultBuildOperationExecutor.java | 71 +-
.../internal/progress/InternalBuildListener.java | 3 +
.../gradle/internal/progress/LoggerProvider.java | 2 +-
.../internal/progress/OperationIdGenerator.java | 11 -
.../internal/progress/OperationIdentifier.java | 21 +-
.../internal/progress/OperationsHierarchy.java | 91 --
.../progress/OperationsHierarchyKeeper.java | 40 -
.../service/scopes/BuildScopeServices.java | 74 +-
.../service/scopes/BuildSessionScopeServices.java | 45 +
.../service/scopes/GlobalScopeServices.java | 47 +-
.../service/scopes/GradleScopeServices.java | 16 +-
.../service/scopes/PluginServiceRegistry.java | 6 +
.../service/scopes/ProjectScopeServices.java | 11 +-
.../groovy/org/gradle/logging/ProgressLogger.java | 10 +-
.../org/gradle/logging/ProgressLoggerFactory.java | 9 +-
.../internal/ConsoleBackedProgressRenderer.java | 6 +-
.../internal/DefaultProgressLoggerFactory.java | 72 +-
.../org/gradle/logging/internal/LogEvent.java | 4 +-
.../org/gradle/logging/internal/OutputEvent.java | 4 +-
.../org/gradle/logging/internal/ProgressEvent.java | 2 +-
.../internal/ProgressLogEventGenerator.java | 15 +-
.../logging/internal/ProgressStartEvent.java | 14 +-
.../logging/internal/StyledTextOutputEvent.java | 12 +
.../internal/progress/ProgressOperations.java | 11 +-
.../collection/internal/BridgedCollections.java | 4 +-
.../internal/PolymorphicModelMapProjection.java | 8 +-
.../use/internal/PluginRequestsSerializer.java | 3 -
.../gradle/process/internal/DefaultExecHandle.java | 3 +-
.../internal/DefaultProcessForkOptions.java | 2 +-
.../org/gradle/process/internal/ExecHandle.java | 3 +
.../internal/streams/ExecOutputHandleRunner.java | 8 +-
.../testfixtures/internal/ProjectBuilderImpl.java | 4 +-
.../internal/TestBuildScopeServices.java | 7 +-
.../org/gradle/util/AvailablePortFinder.java | 1 +
.../src/main/groovy/org/gradle/util/GUtil.java | 2 +-
.../DependencyClassPathProviderTest.groovy | 14 +-
.../api/internal/DocumentationRegistryTest.groovy | 6 +-
.../DefaultDependencyHandlerTest.groovy | 13 +
.../DefaultGradleDistributionLocatorTest.groovy | 124 ++
.../classpath/DefaultModuleRegistryTest.groovy | 104 +-
.../api/internal/file/copy/LineFilterTest.groovy | 16 +
.../initialization/DefaultScriptHandlerTest.groovy | 17 +-
.../DefaultObjectConfigurationActionTest.groovy | 7 +-
.../api/internal/project/DefaultProjectTest.groovy | 47 +-
.../project/taskfactory/TaskFactoryTest.groovy | 1 -
.../internal/tasks/DefaultTaskContainerTest.groovy | 2 +-
.../util/DefaultProcessForkOptionsTest.groovy | 6 +-
.../internal/AbstractFileLockManagerTest.groovy | 26 +-
.../DefaultInitScriptProcessorTest.groovy | 3 +-
.../DefaultScriptPluginFactoryTest.groovy | 143 ++-
.../project/BuildScriptProcessorTest.groovy | 3 +-
.../internal/DefaultDeploymentRegistryTest.groovy | 108 ++
...aultBuildConfigurationActionExecuterTest.groovy | 114 ++
.../execution/DefaultBuildExecuterTest.groovy | 70 +-
...askExecutionPlanParallelTaskHandlingTest.groovy | 8 +-
.../DefaultScriptCompilerFactoryTest.groovy | 4 +-
.../AsmBackedEmptyScriptGeneratorTest.groovy | 37 -
.../internal/BuildScriptDataSerializerTest.groovy | 32 +
.../internal/BuildScriptTransformerSpec.groovy | 199 ++-
.../internal/CachingScriptClassCompilerTest.groovy | 38 +-
.../DefaultScriptCompilationHandlerTest.groovy | 404 ++++++
.../DefaultScriptCompilationHandlerTest.java | 346 ------
.../internal/DefaultScriptRunnerFactoryTest.java | 79 +-
.../FileCacheBackedScriptClassCompilerTest.groovy | 17 +-
.../ShortCircuitEmptyScriptCompilerTest.groovy | 21 +-
.../DefaultExceptionAnalyserTest.java | 7 +-
.../DefaultGradleLauncherFactoryTest.groovy | 10 +-
.../initialization/DefaultGradleLauncherTest.java | 77 +-
.../initialization/InitScriptHandlerTest.groovy | 43 +-
.../buildsrc/BuildSourceBuilderTest.groovy | 18 +-
.../DefaultAuthenticationContainerTest.groovy | 64 +
.../ScriptUsageLocationReporterTest.groovy | 20 +-
.../filewatch/DefaultFileWatcherFactoryTest.groovy | 5 +-
.../graph/CachingDirectedGraphWalkerTest.groovy | 19 +
.../DefaultBuildOperationExecutorTest.groovy | 261 +++-
.../progress/OperationsHierarchyKeeperTest.groovy | 64 -
.../progress/OperationsHierarchyTest.groovy | 138 ---
.../service/scopes/BuildScopeServicesTest.groovy | 8 +-
.../service/scopes/GlobalScopeServicesTest.java | 19 +-
.../service/scopes/GradleScopeServicesTest.groovy | 10 +
.../DefaultProgressLoggerFactoryTest.groovy | 166 ++-
.../logging/internal/OutputSpecification.groovy | 8 +-
.../progress/ProgressOperationsTest.groovy | 43 +-
.../process/internal/DefaultExecHandleSpec.groovy | 5 +-
.../streams/ExecOutputHandleRunnerTest.groovy | 44 +
.../test/groovy/org/gradle/util/GUtilTest.groovy | 8 +
.../util/ports/AbstractPortAllocatorTest.groovy | 33 +
.../ports/FixedAvailablePortAllocatorTest.groovy | 134 ++
.../gradle/util/ports/ReservedPortRangeTest.groovy | 137 +++
.../gradle/test/fixtures/ConcurrentTestUtil.groovy | 800 ------------
.../ports/AbstractAvailablePortAllocator.groovy | 107 ++
.../gradle/util/ports/DefaultPortDetector.groovy | 46 +
.../ports/DefaultReservedPortRangeFactory.groovy | 25 +
.../util/ports/FixedAvailablePortAllocator.groovy | 73 ++
.../org/gradle/util/ports/PortAllocator.groovy | 35 +
.../org/gradle/util/ports/PortDetector.groovy | 22 +
.../org/gradle/util/ports/ReservedPortRange.groovy | 112 ++
.../util/ports/ReservedPortRangeFactory.groovy | 22 +
.../ArtifactDependenciesIntegrationTest.groovy | 2 +
...ModuleDependenciesResolveIntegrationTest.groovy | 4 +-
...pendencyHandlerApiResolveIntegrationTest.groovy | 126 ++
.../ProjectDependencyResolveIntegrationTest.groovy | 58 +-
.../ResolveCrossVersionIntegrationTest.groovy | 2 +
.../integtests/resolve/ResolveTestFixture.groovy | 13 +-
.../CacheReuseCrossVersionIntegrationTest.groovy | 2 +
...ationDependencyResolutionIntegrationTest.groovy | 278 ++++-
...amicRevisionRemoteResolveIntegrationTest.groovy | 2 +-
...IvyDynamicRevisionResolveIntegrationTest.groovy | 36 +
.../ivy/IvyFileRepoResolveIntegrationTest.groovy | 30 +
...yModuleArtifactResolutionIntegrationTest.groovy | 30 +
.../MavenFileRepoResolveIntegrationTest.groovy | 30 +
.../MavenVersionRangeResolveIntegrationTest.groovy | 61 +
.../artifacts/ArtifactDependencyResolver.java | 12 +-
.../artifacts/ComponentMetadataProcessor.java | 6 +
.../ComponentModuleMetadataProcessor.java | 7 +
.../DefaultDependencyManagementServices.java | 46 +-
.../artifacts/DefaultResolvedArtifact.java | 14 +-
.../internal/artifacts/DefaultResolverResults.java | 125 ++
.../DependencyManagementBuildScopeServices.java | 149 ++-
.../DependencyManagementGlobalScopeServices.java | 36 +-
.../api/internal/artifacts/DependencyServices.java | 3 +
.../artifacts/GlobalDependencyResolutionRules.java | 13 +
.../api/internal/artifacts/ResolveContext.java | 36 +
.../internal/artifacts/ResolveContextInternal.java | 31 -
.../api/internal/artifacts/ResolverResults.java | 108 +-
.../configurations/ConfigurationInternal.java | 2 +-
.../configurations/DefaultConfiguration.java | 48 +-
.../configurations/DirectBuildDependencies.java | 55 +
.../artifacts/dsl/ModuleReplacementsData.java | 8 +
.../CacheLockingArtifactDependencyResolver.java | 26 +-
.../ivyservice/DefaultConfigurationResolver.java | 79 +-
.../ivyservice/DefaultIvyDependencyPublisher.java | 3 +-
.../ivyservice/DefaultLenientConfiguration.java | 21 +-
.../ErrorHandlingArtifactDependencyResolver.java | 267 ----
.../ErrorHandlingConfigurationResolver.java | 265 ++++
.../ivyservice/IvyBackedArtifactPublisher.java | 40 +-
.../ivyservice/LocalComponentConverter.java | 24 +
.../ivyservice/LocalComponentFactory.java | 24 -
...lfResolvingDependencyConfigurationResolver.java | 115 ++
.../SelfResolvingDependencyResolver.java | 118 --
.../ShortCircuitEmptyConfigurationResolver.java | 110 ++
...cuitEmptyConfigsArtifactDependencyResolver.java | 114 --
.../ivyservice/ivyresolve/ComponentResolvers.java | 28 +
.../ivyresolve/DelegatingComponentResolvers.java | 59 +
.../ivyservice/ivyresolve/IvyContextualiser.java | 28 -
.../ivyresolve/NoRepositoriesResolver.java | 2 +-
.../ivyservice/ivyresolve/RepositoryChain.java | 28 -
.../ivyservice/ivyresolve/ResolveIvyFactory.java | 9 +-
.../ivyresolve/ResolverProviderFactory.java | 24 +
.../ivyservice/ivyresolve/UserResolverChain.java | 2 +-
.../memcache/InMemoryArtifactsCache.java | 4 +-
.../InMemoryCachedModuleComponentRepository.java | 1 -
.../parser/GradlePomModuleDescriptorBuilder.java | 1 -
.../ivyservice/ivyresolve/parser/PomReader.java | 57 +-
.../ivyresolve/strategy/VersionRangeSelector.java | 16 +-
.../moduleconverter/ComponentConverterSource.java | 39 -
.../CompositeResolveLocalComponentFactory.java | 50 -
.../ConfigurationBackedComponent.java | 39 +
.../ConfigurationLocalComponentConverter.java | 75 ++
.../ConfigurationsToArtifactsConverter.java | 4 +-
.../ConfigurationsToModuleDescriptorConverter.java | 4 +-
.../DefaultConfigurationsToArtifactsConverter.java | 4 +-
...tConfigurationsToModuleDescriptorConverter.java | 11 +-
.../ResolveLocalComponentFactory.java | 75 --
...ultDependenciesToModuleDescriptorConverter.java | 8 +-
.../DependenciesToModuleDescriptorConverter.java | 4 +-
.../ProjectIvyDependencyDescriptorFactory.java | 2 -
.../DefaultProjectComponentRegistry.java | 12 +-
.../projectmodule/ProjectArtifactResolver.java | 78 --
.../projectmodule/ProjectDependencyResolver.java | 63 +-
.../resolveengine/ComponentResolversChain.java | 141 +++
.../DefaultArtifactDependencyResolver.java | 183 +++
.../resolveengine/DefaultDependencyResolver.java | 175 ---
.../resolveengine/artifact/ArtifactSet.java | 28 +
.../resolveengine/artifact/DefaultArtifactSet.java | 97 ++
.../artifact/DefaultResolvedArtifactResults.java | 73 ++
.../artifact/DefaultResolvedArtifactsBuilder.java | 38 +
.../artifact/DependencyArtifactsVisitor.java | 24 +
.../artifact/ResolvedArtifactResults.java | 25 +
.../resolveengine/artifact/ResolvedArtifacts.java | 24 +
.../artifact/ResolvedArtifactsBuilder.java | 20 +
.../artifact/ResolvedArtifactsGraphVisitor.java | 112 ++
.../resolveengine/graph/AbstractArtifactSet.java | 102 --
.../resolveengine/graph/ArtifactSet.java | 28 -
.../graph/CompositeDependencyArtifactsVisitor.java | 46 +
.../graph/CompositeDependencyGraphVisitor.java | 12 +-
.../graph/ConfigurationArtifactSet.java | 53 -
.../resolveengine/graph/DependencyArtifactSet.java | 48 -
.../graph/DependencyGraphBuilder.java | 85 +-
.../resolveengine/graph/DependencyGraphEdge.java | 39 +
.../resolveengine/graph/DependencyGraphNode.java | 41 +
.../graph/DependencyGraphPathResolver.java | 83 ++
.../graph/DependencyGraphVisitor.java | 10 +-
.../ResolutionResultDependencyGraphVisitor.java | 43 -
...esolvedConfigurationDependencyGraphVisitor.java | 210 ----
...lvedProjectConfigurationResultGraphVisitor.java | 50 -
.../oldresult/DefaultResolvedArtifactResults.java | 71 --
.../oldresult/DefaultResolvedArtifactsBuilder.java | 33 -
.../DefaultResolvedConfigurationBuilder.java | 8 +-
.../oldresult/ResolvedArtifactResults.java | 29 -
.../oldresult/ResolvedArtifactsBuilder.java | 26 -
.../oldresult/ResolvedConfigurationBuilder.java | 4 +-
...esolvedConfigurationDependencyGraphVisitor.java | 105 ++
.../TransientConfigurationResultsBuilder.java | 21 +-
.../TransientConfigurationResultsLoader.java | 1 +
.../DefaultResolvedLocalComponentsResult.java | 42 +
...efaultResolvedLocalComponentsResultBuilder.java | 53 +
...tResolvedProjectConfigurationResultBuilder.java | 54 -
...DefaultResolvedProjectConfigurationResults.java | 32 -
.../ResolvedLocalComponentsResult.java | 24 +
.../ResolvedLocalComponentsResultBuilder.java | 26 +
.../ResolvedLocalComponentsResultGraphVisitor.java | 62 +
.../ResolvedProjectConfigurationResultBuilder.java | 25 -
.../ResolvedProjectConfigurationResults.java | 21 -
.../result/ComponentIdentifierSerializer.java | 11 +-
.../result/ComponentSelectorSerializer.java | 4 +-
.../ResolutionResultDependencyGraphVisitor.java | 44 +
.../store/ResolutionResultsStoreFactory.java | 4 +-
.../ivyservice/resolveengine/store/StoreSet.java | 4 +-
.../query/DefaultArtifactResolutionQuery.java | 15 +-
.../AbstractAuthenticationSupportedRepository.java | 50 +-
.../repositories/DefaultBaseRepositoryFactory.java | 26 +-
.../DefaultFlatDirArtifactRepository.java | 8 +-
.../repositories/DefaultIvyArtifactRepository.java | 7 +-
.../DefaultMavenArtifactRepository.java | 8 +-
.../DefaultMavenLocalArtifactRepository.java | 8 +-
.../DefaultExternalResourceArtifactResolver.java | 8 +-
.../resolver/ExternalResourceArtifactResolver.java | 2 -
.../resolver/ExternalResourceResolver.java | 25 +-
...rnalResourceResolverDescriptorParseContext.java | 6 +-
...ueSnapshotExternalResourceArtifactResolver.java | 4 -
.../transport/RepositoryTransportFactory.java | 91 +-
.../model/BuildableIvyModulePublishMetaData.java | 17 +-
.../model/DefaultIvyModulePublishMetaData.java | 28 +-
.../model/ModuleComponentArtifactIdentifier.java | 2 +-
.../model/BuildableLocalComponentMetaData.java | 34 +
.../model/DefaultLibraryBinaryIdentifier.java | 81 ++
.../model/DefaultLibraryComponentIdentifier.java | 74 --
.../model/DefaultLibraryComponentSelector.java | 23 +-
.../local/model/DefaultLocalComponentMetaData.java | 128 +-
.../model/LocalComponentArtifactIdentifier.java | 2 +-
.../local/model/LocalComponentMetaData.java | 16 +-
.../local/model/LocalConfigurationMetaData.java | 6 +
.../local/model/MutableLocalComponentMetaData.java | 33 -
.../PublishArtifactLocalArtifactMetaData.java | 15 +-
.../model/ComponentArtifactIdentifier.java | 34 -
.../component/model/ComponentArtifactMetaData.java | 1 +
.../component/model/ComponentResolveMetaData.java | 1 -
.../component/model/DefaultIvyArtifactName.java | 7 +-
.../DefaultModuleDescriptorArtifactMetaData.java | 50 +
.../model/LocalComponentDependencyMetaData.java | 1 -
.../model/ModuleComponentArtifactsMetaData.java | 20 -
.../model/ModuleDescriptorArtifactMetaData.java | 22 +
.../resolve/ArtifactNotFoundException.java | 2 +-
.../internal/resolve/ArtifactResolveException.java | 2 +-
.../ResolveContextToComponentResolver.java | 2 +-
.../result/BuildableArtifactResolveResult.java | 2 +-
.../DefaultBuildableArtifactResolveResult.java | 2 +-
.../transport/file/FileConnectorFactory.java | 42 +
.../artifacts/DefaultResolvedArtifactTest.groovy | 12 +-
.../artifacts/DefaultResolvedDependencyTest.java | 5 +-
.../artifacts/DefaultResolverResultsSpec.groovy | 53 +
.../internal/artifacts/ResolverResultsSpec.groovy | 69 --
.../configurations/DefaultConfigurationSpec.groovy | 34 +-
...cheLockingArtifactDependencyResolverTest.groovy | 17 +-
...orHandlingArtifactDependencyResolverTest.groovy | 164 ---
.../ErrorHandlingConfigurationResolverTest.groovy | 164 +++
...lvingDependencyConfigurationResolverTest.groovy | 137 +++
.../SelfResolvingDependencyResolverTest.groovy | 142 ---
...ortCircuitEmptyConfigurationResolverSpec.groovy | 74 ++
...ptyConfigsArtifactDependencyResolverSpec.groovy | 78 --
.../ErrorHandlingArtifactResolverTest.groovy | 6 +-
.../RepositoryChainArtifactResolverTest.groovy | 128 --
...sitoryChainComponentMetaDataResolverTest.groovy | 580 ---------
.../ivyresolve/ResolveIvyFactoryTest.groovy | 2 +-
.../ResolverProviderArtifactResolverTest.groovy | 128 ++
...verProviderComponentMetaDataResolverTest.groovy | 580 +++++++++
.../GradlePomModuleDescriptorParserTest.groovy | 50 +
.../ivyresolve/parser/PomReaderProfileTest.groovy | 8 +-
.../ivyresolve/parser/PomReaderTest.groovy | 38 +-
.../DefaultVersionSelectorSchemeTest.groovy | 2 +
.../strategy/VersionRangeSelectorTest.groovy | 13 +
...ConfigurationLocalComponentConverterTest.groovy | 56 +
...ltConfigurationsToArtifactsConverterTest.groovy | 4 +-
...figurationsToModuleDescriptorConverterTest.java | 17 +-
.../ResolveLocalComponentFactoryTest.groovy | 58 -
...endenciesToModuleDescriptorConverterTest.groovy | 4 +-
.../ProjectDependencyResolverTest.groovy | 33 +-
.../DependencyGraphBuilderTest.groovy | 190 ++-
.../ComponentIdentifierSerializerTest.groovy | 8 +-
.../result/ComponentSelectorSerializerTest.groovy | 17 +-
.../store/ResolutionResultsStoreFactoryTest.groovy | 12 +-
.../DefaultArtifactResolutionQueryTest.groovy | 5 +-
...actAuthenticationSupportedRepositoryTest.groovy | 51 +-
.../DefaultBaseRepositoryFactoryTest.groovy | 6 +-
.../DefaultFlatDirArtifactRepositoryTest.groovy | 2 +-
.../DefaultIvyArtifactRepositoryTest.groovy | 22 +-
.../DefaultMavenArtifactRepositoryTest.groovy | 10 +-
.../DefaultMavenLocalRepositoryTest.groovy | 6 +-
...shotExternalResourceArtifactResolverTest.groovy | 3 -
.../RepositoryTransportFactoryTest.groovy | 108 +-
.../DefaultIvyModulePublishMetaDataTest.groovy | 6 +-
.../DefaultLibraryBinaryIdentifierTest.groovy | 80 ++
.../DefaultLibraryComponentIdentifierTest.groovy | 69 --
.../DefaultLibraryComponentSelectorTest.groovy | 79 +-
.../model/DefaultLocalComponentMetaDataTest.groovy | 74 +-
.../model/DefaultIvyArtifactNameTest.groovy | 7 +-
.../resolve/ArtifactNotFoundExceptionTest.groovy | 2 +-
...efaultBuildableArtifactResolveResultTest.groovy | 3 +-
...tractIvyRemoteRepoResolveIntegrationTest.groovy | 2 +
.../DetailedModelReportIntegrationTest.groovy | 201 +++
.../model/ModelReportIntegrationTest.groovy | 343 ++++--
.../internal/AbstractBinaryRenderer.java | 15 +
.../components/internal/ComponentRenderer.java | 2 +-
.../internal/ComponentReportRenderer.java | 2 +-
.../components/internal/DiagnosticsServices.java | 3 +
.../components/internal/SourceSetRenderer.java | 2 +-
.../gradle/api/reporting/model/ModelReport.java | 4 +
.../model/internal/ModelNodeRenderer.java | 96 +-
.../internal/text/DefaultTextReportBuilder.java | 10 +
.../internal/text/TextReportBuilder.java | 2 +
.../internal/ComponentReportRendererTest.groovy | 2 +-
.../model/ModelReportNodeBuilderTest.groovy | 42 +
.../reporting/model/ModelReportParserTest.groovy | 142 +++
.../api/reporting/model/ReportNodeTest.groovy | 42 +
.../model/internal/ModelNodeRendererTest.groovy | 44 +
.../JvmComponentReportOutputFormatter.groovy | 32 +
.../PlayComponentReportOutputFormatter.groovy | 29 +
.../api/reporting/model/ConsoleReportOutput.groovy | 76 --
.../reporting/model/ModelReportNodeBuilder.groovy | 61 +
.../api/reporting/model/ModelReportOutput.groovy | 86 ++
.../api/reporting/model/ModelReportParser.groovy | 140 +++
.../api/reporting/model/ParsedModelReport.groovy | 31 +
.../gradle/api/reporting/model/ReportNode.groovy | 66 +
.../gradle/AllDistributionIntegrationSpec.groovy | 2 +-
.../gradle/BinDistributionIntegrationSpec.groovy | 2 +-
subprojects/docs/docs.gradle | 2 +
subprojects/docs/src/docs/css/dsl.css | 3 +-
subprojects/docs/src/docs/css/javadoc.css | 2 +-
subprojects/docs/src/docs/css/userguide.css | 6 +-
subprojects/docs/src/docs/dsl/dsl.xml | 93 +-
.../docs/src/docs/dsl/org.gradle.api.Buildable.xml | 41 +
.../dsl/org.gradle.api.BuildableModelElement.xml | 44 +
...gradle.api.PolymorphicDomainObjectContainer.xml | 47 +
...ifacts.repositories.AuthenticationContainer.xml | 38 +
...ifacts.repositories.AuthenticationSupported.xml | 8 +-
....artifacts.repositories.PasswordCredentials.xml | 44 +
.../org.gradle.api.credentials.AwsCredentials.xml | 44 +
.../dsl/org.gradle.api.credentials.Credentials.xml | 38 +
.../org.gradle.api.tasks.compile.JavaCompile.xml | 2 +-
.../dsl/org.gradle.api.tasks.javadoc.Javadoc.xml | 2 +-
.../org.gradle.authentication.Authentication.xml | 38 +
...dle.authentication.http.BasicAuthentication.xml | 38 +
...le.authentication.http.DigestAuthentication.xml | 38 +
...adle.nativeplatform.NativeLibraryBinarySpec.xml | 38 +
.../dsl/org.gradle.platform.base.BinarySpec.xml | 4 +-
.../dsl/org.gradle.platform.base.ToolChain.xml | 41 +
.../src/docs/dsl/org.gradle.play.JvmClasses.xml | 47 +
.../org.gradle.play.PlayApplicationBinarySpec.xml | 53 +
.../dsl/org.gradle.play.PlayApplicationSpec.xml | 44 +
.../src/docs/dsl/org.gradle.play.PublicAssets.xml | 44 +
...play.distribution.PlayDistributionContainer.xml | 22 +
.../dsl/org.gradle.play.platform.PlayPlatform.xml | 47 +
.../dsl/org.gradle.play.tasks.JavaScriptMinify.xml | 44 +
...g.gradle.play.tasks.PlayCoffeeScriptCompile.xml | 38 +
.../src/docs/dsl/org.gradle.play.tasks.PlayRun.xml | 53 +
.../dsl/org.gradle.play.tasks.RoutesCompile.xml | 56 +
.../dsl/org.gradle.play.tasks.TwirlCompile.xml | 44 +
.../org.gradle.play.toolchain.PlayToolChain.xml | 38 +
...javascript.coffeescript.CoffeeScriptCompile.xml | 38 +
subprojects/docs/src/docs/dsl/plugins.xml | 7 +-
subprojects/docs/src/docs/release/notes.md | 404 ++----
subprojects/docs/src/docs/stylesheets/dslHtml.xsl | 5 +-
.../docs/src/docs/userguide/antlrPlugin.xml | 3 +-
.../src/docs/userguide/buildScriptsTutorial.xml | 2 +-
.../docs/src/docs/userguide/continuousBuild.xml | 3 +-
.../docs/src/docs/userguide/customPlugins.xml | 2 +-
subprojects/docs/src/docs/userguide/depMngmt.xml | 50 +-
.../docs/src/docs/userguide/gradleDaemon.xml | 10 +-
.../docs/src/docs/userguide/gradleWrapper.xml | 35 +-
.../src/docs/userguide/img/playPluginModel.graphml | 210 ++++
.../src/docs/userguide/img/playPluginModel.png | Bin 0 -> 27543 bytes
.../docs/src/docs/userguide/mavenPlugin.xml | 20 +-
.../docs/src/docs/userguide/multiproject.xml | 2 +-
.../docs/src/docs/userguide/nativeBinaries.xml | 4 +-
.../docs/src/docs/userguide/newJavaPlugin.xml | 313 +++++
subprojects/docs/src/docs/userguide/newModel.xml | 164 ++-
.../docs/src/docs/userguide/organizeBuildLogic.xml | 4 +-
subprojects/docs/src/docs/userguide/playPlugin.xml | 560 +++++++++
.../docs/src/docs/userguide/scalaPlugin.xml | 5 +-
.../docs/src/docs/userguide/standardPlugins.xml | 2 +-
subprojects/docs/src/docs/userguide/testKit.xml | 180 +++
subprojects/docs/src/docs/userguide/userguide.xml | 3 +
.../src/samples/jvmComponents/java/build.gradle | 26 -
.../main/java/org/gradle/samples/HelloWorld.java | 7 -
.../modelRules/basicRuleSourcePlugin/build.gradle | 60 +-
.../samples/native-binaries/cpp-exe/build.gradle | 23 +-
.../native-binaries/sourceset-variant/build.gradle | 28 +
.../sourceset-variant/src/main/c/main.c | 10 +
.../sourceset-variant/src/main/headers/platform.h | 17 +
.../src/main/linux/platform-linux.c | 9 +
.../sourceset-variant/src/main/mac/platform-mac.c | 9 +
.../src/main/windows/platform-windows.c | 10 +
.../newJavaPlugin/multiplecomponents/build.gradle | 45 +
.../multiplecomponents/settings.gradle | 2 +
.../src/client/java/org/gradle/Client.java | 9 +
.../src/core/java/org/gradle/Person.java | 29 +
.../src/core/resources/org/gradle/resource.xml | 1 +
.../src/server/java/org/gradle/PersonServer.java | 10 +
.../multiplecomponents/util/build.gradle | 11 +
.../util/src/main/java/org/gradle/Utils.java | 5 +
.../samples/newJavaPlugin/quickstart/build.gradle | 38 +
.../src/main/java/org/gradle/Person.java | 29 +
.../src/main/resources/org/gradle/resource.xml | 1 +
.../targetplatforms/core/build.gradle | 28 +
.../core/src/main/java/org/gradle/Person.java | 29 +
.../core/src/main/java6/org/gradle/Person6.java | 10 +
.../src/main/resources/org/gradle/resource.xml | 1 +
.../targetplatforms/server/build.gradle | 22 +
.../server/src/main/java/org/gradle/Server.java | 7 +
.../newJavaPlugin/targetplatforms/settings.gradle | 2 +
.../docs/src/samples/play/advanced/build.gradle | 24 +-
.../docs/src/samples/play/advanced/conf/routes | 2 +-
.../docs/src/samples/play/basic/build.gradle | 23 +-
.../app/controllers/Application.scala | 14 +
.../configure-compiler/app/views/index.scala.html | 7 +
.../configure-compiler/app/views/main.scala.html | 15 +
.../samples/play/configure-compiler/build.gradle | 35 +
.../play/configure-compiler/conf/application.conf | 62 +
.../samples/play/configure-compiler/conf/routes | 9 +
.../configure-compiler/public/images/favicon.png | Bin 0 -> 687 bytes
.../configure-compiler/public/javascripts/hello.js | 3 +
.../public/stylesheets/main.css | 0
.../configure-compiler/test/ApplicationSpec.scala | 41 +
.../configure-compiler/test/IntegrationSpec.scala | 24 +
.../app/controllers/Application.scala | 14 +
.../play/custom-assets/app/views/index.scala.html | 7 +
.../play/custom-assets/app/views/main.scala.html | 15 +
.../src/samples/play/custom-assets/build.gradle | 74 ++
.../play/custom-assets/conf/application.conf | 62 +
.../src/samples/play/custom-assets/conf/routes | 9 +
.../src/samples/play/custom-assets/copyright.txt | 15 +
.../play/custom-assets/public/images/favicon.png | Bin 0 -> 687 bytes
.../play/custom-assets/public/javascripts/hello.js | 3 +
.../custom-assets}/public/stylesheets/main.css | 0
.../play/custom-assets/raw-assets/sample.js | 9 +
.../src/samples/play/custom-distribution/LICENSE | 202 +++
.../src/samples/play/custom-distribution/README.md | 2 +
.../app/controllers/Application.scala | 14 +
.../custom-distribution/app/views/index.scala.html | 7 +
.../custom-distribution/app/views/main.scala.html | 15 +
.../samples/play/custom-distribution/build.gradle | 36 +
.../play/custom-distribution/conf/application.conf | 62 +
.../samples/play/custom-distribution/conf/routes | 9 +
.../custom-distribution/public/images/favicon.png | Bin 0 -> 687 bytes
.../public/javascripts/hello.js | 3 +
.../public/stylesheets/main.css | 0
.../scripts/runPlayBinaryAsUser.sh | 14 +
.../src/samples/play/multiproject/build.gradle | 15 +-
.../play-2.4/app/controllers/Application.scala | 14 +
.../play/play-2.4/app/views/index.scala.html | 7 +
.../play/play-2.4/app/views/main.scala.html | 15 +
.../docs/src/samples/play/play-2.4/build.gradle | 39 +
.../samples/play/play-2.4/conf/application.conf | 62 +
.../docs/src/samples/play/play-2.4/conf/routes | 9 +
.../play/play-2.4/public/images/favicon.png | Bin 0 -> 687 bytes
.../play/play-2.4/public/javascripts/hello.js | 3 +
.../play/play-2.4}/public/stylesheets/main.css | 0
.../java/controllers/hello/HelloController.java | 30 +
.../sourcesets/additional/javascript/old_sample.js | 10 +
.../sourcesets/additional/javascript/sample.js | 9 +
.../play/sourcesets/app/assets/greetings.js | 4 +
.../sourcesets/app/controllers/Application.scala | 14 +
.../docs/src/samples/play/sourcesets/build.gradle | 62 +
.../samples/play/sourcesets/conf/application.conf | 62 +
.../docs/src/samples/play/sourcesets/conf/routes | 13 +
.../java/controllers/date/DateController.java | 32 +
.../play/sourcesets/extra/routes/date.routes | 2 +
.../play/sourcesets/extra/routes/hello.routes | 3 +
.../play/sourcesets/extra/twirl/main.scala.html | 15 +
.../play/sourcesets/public/images/favicon.png | Bin 0 -> 687 bytes
.../play/sourcesets/public/javascripts/hello.js | 3 +
.../play/sourcesets}/public/stylesheets/main.css | 0
.../src/samples/testKit/testKitJunit/build.gradle | 17 +
.../gradle/sample/BuildLogicFunctionalTest.java | 77 ++
.../src/samples/testKit/testKitSpock/build.gradle | 16 +
.../gradle/sample/BuildLogicFunctionalTest.groovy | 55 +
.../testKit/testKitSpockClasspath/lib/build.gradle | 5 +
.../groovy/org/gradle/sample/lib/Messages.groovy | 5 +
.../testKitSpockClasspath/plugin/build.gradle | 36 +
.../groovy/org/gradle/sample/HelloWorld.groovy | 28 +
.../org/gradle/sample/HelloWorldPlugin.groovy | 26 +
.../gradle/sample/BuildLogicFunctionalTest.groovy | 69 ++
.../testKit/testKitSpockClasspath/settings.gradle | 1 +
.../artifacts/defineRepository/build.gradle | 30 +
.../src/samples/userguide/files/copy/build.gradle | 6 +-
.../basicRuleSourcePlugin-model-task.out | 127 +-
.../userguideOutput/newJavaComponentReport.out | 29 +
.../newJavaMultiComponents-clientJar.out | 9 +
.../newJavaMultiComponents-serverJar.out | 9 +
.../samples/userguideOutput/newJavaQuickstart.out | 9 +
.../newJavaTargetPlatforms-java6MainJar.out | 8 +
.../newJavaTargetPlatforms-server.out | 20 +
.../userguideOutput/newJavaTargetPlatforms.out | 14 +
.../userguideOutput/playComponentReport.out | 38 +
.../gradle/ide/cdt/model/CprojectSettings.groovy | 4 +-
.../internal/DefaultVisualStudioExtension.java | 6 +-
.../internal/DefaultVisualStudioProject.groovy | 9 +-
.../VisualStudioProjectConfiguration.groovy | 9 +-
.../internal/VisualStudioProjectResolver.java | 17 +-
.../visualstudio/plugins/VisualStudioPlugin.java | 6 +-
.../tasks/GenerateFiltersFileTask.groovy | 5 +-
.../tasks/GenerateProjectFileTask.groovy | 4 +-
.../internal/AbsoluteFileNameTransformer.java | 26 -
.../internal/RelativeFileNameTransformer.java | 10 +-
.../VisualStudioProjectConfigurationTest.groovy | 10 +-
.../VisualStudioProjectRegistryTest.groovy | 13 +-
.../RelativeFileNameTransformerTest.groovy | 44 +
.../eclipse/EclipseClasspathIntegrationTest.groovy | 116 ++
.../EclipseLinkedResourceIntegrationTest.groovy | 68 ++
.../ide/eclipse/EclipseProjectFixture.groovy | 5 +
.../plugins/ide/eclipse/model/SourceFolder.groovy | 12 +-
.../model/internal/SourceFoldersCreator.groovy | 80 +-
.../ide/internal/tooling/EclipseModelBuilder.java | 9 +-
.../plugins/ide/eclipse/EclipsePluginTest.groovy | 3 +
.../ide/eclipse/model/SourceFolderTest.groovy | 17 +-
.../model/internal/SourceFoldersCreatorTest.groovy | 137 +++
subprojects/integ-test/integ-test.gradle | 8 +-
.../integtests/ApplicationIntegrationSpec.groovy | 2 +-
.../BuildScriptClasspathIntegrationTest.java | 5 +-
.../integtests/CacheProjectIntegrationTest.groovy | 4 +-
.../integtests/CommandLineIntegrationTest.groovy | 37 +-
.../ParallelTaskExecutionIntegrationTest.groovy | 6 +-
.../gradle/integtests/StdioIntegrationTest.groovy | 24 +-
.../BuildEnvironmentIntegrationTest.groovy | 5 +-
.../SamplesWebQuickstartIntegrationTest.groovy | 19 +-
.../samples/UserGuideSamplesIntegrationTest.groovy | 6 +
.../samples/UserGuideSamplesRunner.groovy | 5 +-
.../AbstractHttpDependencyResolutionTest.groovy | 4 +-
.../fixtures/AbstractIntegrationSpec.groovy | 31 +-
.../integtests/fixtures/AvailableJavaHomes.java | 1 +
.../PersistentBuildProcessIntegrationTest.groovy | 3 +-
.../fixtures/daemon/AbstractDaemonFixture.groovy | 7 +
.../integtests/fixtures/daemon/DaemonFixture.java | 7 +
.../fixtures/daemon/DaemonIntegrationSpec.groovy | 17 +-
.../fixtures/executer/AbstractGradleExecuter.java | 252 ++--
.../fixtures/executer/DaemonGradleExecuter.java | 53 +-
.../executer/DefaultGradleDistribution.java | 26 +
.../fixtures/executer/ForkingGradleExecuter.java | 57 +-
.../fixtures/executer/ForkingGradleHandle.java | 57 +-
.../executer/GradleContextualExecuter.java | 2 +-
.../fixtures/executer/GradleDistribution.java | 11 +
.../fixtures/executer/GradleExecuter.java | 74 +-
.../integtests/fixtures/executer/GradleHandle.java | 22 +
.../fixtures/executer/GradleVersions.java | 2 +-
.../fixtures/executer/InProcessGradleExecuter.java | 50 +-
.../executer/OutputScrapingExecutionFailure.java | 5 +-
.../executer/ParallelForkingGradleExecuter.java | 2 +-
.../executer/ParallelForkingGradleHandle.java | 5 +-
.../executer/ProgressLoggingFixture.groovy | 10 +-
.../fixtures/jvm/InstalledJvmLocator.java | 2 +-
.../integtests/fixtures/jvm/JvmInstallation.java | 3 +
.../gradle/test/fixtures/ivy/IvyFileModule.groovy | 6 +-
.../test/fixtures/server/http/HttpServer.groovy | 35 +-
.../fixtures/server/http/TestProxyServer.groovy | 6 +-
.../test/fixtures/server/sftp/SFTPServer.groovy | 15 +-
.../fixtures/jvm/UbuntuJvmLocatorTest.groovy | 9 +-
.../gradle/integtests/fixtures/UrlValidator.groovy | 26 +-
.../gradle/test/fixtures/ConcurrentTestUtil.groovy | 806 ++++++++++++
.../fixtures/archive/ArchiveTestFixture.groovy | 12 +
.../file/AbstractTestDirectoryProvider.java | 48 +-
.../org/gradle/test/fixtures/file/ClassFile.groovy | 48 +-
.../test/fixtures/file/LeaksFileHandles.java | 6 +
.../file/TestDistributionDirectoryProvider.java | 7 +-
.../file/TestNameTestDirectoryProvider.java | 7 +-
.../internal/NativeServicesTestFixture.java | 9 +-
.../src/main/groovy/org/gradle/util/Matchers.java | 5 +-
.../org/gradle/util/SetSystemProperties.java | 9 +-
.../groovy/org/gradle/util/TestPrecondition.groovy | 17 +-
.../publish/ivy/IvyPublishBasicIntegTest.groovy | 4 +-
...yPublishDescriptorCustomizationIntegTest.groovy | 2 +-
.../publish/ivy/IvyPublishHttpsIntegTest.groovy | 1 +
.../publish/ivy/internal/IvyPublishServices.java | 4 +-
.../internal/tasks/compile/ApiGroovyCompiler.java | 1 +
.../org/gradle/api/tasks/compile/package-info.java | 20 -
...ustomComponentJarBinariesIntegrationTest.groovy | 136 +++
.../language/java/JarBinaryTypeVariantsTest.groovy | 116 ++
...braryDependencyResolutionIntegrationTest.groovy | 1011 +++++++++++++++
...guageDependencyResolutionIntegrationTest.groovy | 1292 +++++++++++++++++++-
.../java/JavaLanguageIntegrationTest.groovy | 7 +-
.../java/JavaSourceSetIntegrationTest.groovy | 61 +-
.../MultipleBinaryTypesWithVariantsTest.groovy | 227 ++++
.../java/SampleJavaLanguageIntegrationTest.groovy | 69 +-
.../java/SingleBinaryTypeWithVariantsTest.groovy | 392 ++++++
.../VariantAwareDependencyResolutionSpec.groovy | 322 +++++
.../compile/incremental/SelectiveCompiler.java | 2 +-
.../gradle/api/tasks/compile/CompileOptions.java | 12 +-
.../org/gradle/api/tasks/compile/JavaCompile.java | 24 +-
.../org/gradle/api/tasks/compile/package-info.java | 20 -
.../java/org/gradle/api/tasks/javadoc/Javadoc.java | 24 +-
.../internal/DefaultJavaLanguageSourceSet.java | 4 +-
.../internal/DefaultJavaLocalComponentFactory.java | 87 --
.../DefaultJavaSourceSetResolveContext.java | 75 --
.../JavaLanguagePluginServiceRegistry.java | 5 +-
.../internal/JavaToolChainServiceRegistry.java | 3 +
.../internal/ProjectLibraryDependencyResolver.java | 94 --
.../language/java/plugins/JavaLanguagePlugin.java | 122 +-
.../api/tasks/compile/JavaCompileTest.groovy | 18 +-
.../gradle/api/tasks/javadoc/JavadocTest.groovy | 22 +-
.../DefaultJavaLanguageSourceSetTest.groovy | 28 +-
.../DefaultJavaLocalComponentFactoryTest.groovy | 142 ---
.../DefaultJavaSourceSetResolveContextTest.groovy | 58 -
.../ResourceOnlyJvmLibraryIntegrationTest.groovy | 2 +-
.../jvm/internal/JvmPluginServiceRegistry.java | 5 +-
.../language/jvm/plugins/JvmResourcesPlugin.java | 2 +-
.../AbstractJvmLanguageIntegrationTest.groovy | 20 +-
...AbstractJvmPluginLanguageIntegrationTest.groovy | 4 +-
...anguageIncrementalCompileIntegrationTest.groovy | 3 +
.../language/c/CLanguageIntegrationTest.groovy | 2 +-
.../language/cpp/CppLanguageIntegrationTest.groovy | 2 +-
.../ParallelNativePluginsIntegrationTest.groovy | 2 +
.../plugins/internal/AssembleTaskConfig.java | 3 +-
.../nativeplatform/internal/CompileTaskConfig.java | 3 +-
.../internal/registry/NativeLanguageServices.java | 3 +
.../WindowsResourcesCompileTaskConfig.java | 3 +-
.../AbstractNativeComponentPluginTest.groovy | 7 +-
.../assembler/plugins/AssemblerPluginTest.groovy | 3 +-
subprojects/language-scala/language-scala.gradle | 4 +-
.../scala/JointScalaLangIntegrationTest.groovy | 45 +
.../internal/tasks/scala/ZincScalaCompiler.java | 5 +-
.../toolchain/DefaultScalaToolProvider.java | 2 +-
.../toolchain/DownloadingScalaToolChain.java | 4 +-
.../toolchain/ScalaToolChainServiceRegistry.java | 5 +-
.../scala/plugins/ScalaLanguagePlugin.java | 2 +-
.../language/scala/tasks/PlatformScalaCompile.java | 6 +-
subprojects/launcher/launcher.gradle | 3 +
.../BuildEnvironmentIntegrationTest.groovy | 11 +-
.../GradleConfigurabilityIntegrationSpec.groovy | 2 +-
.../AbstractContinuousIntegrationTest.groovy | 206 ----
.../CancellationContinuousIntegrationTest.groovy | 26 +-
...ntinuousBuildCancellationIntegrationTest.groovy | 102 ++
.../JdkVersionsContinuousIntegrationTest.groovy | 16 +-
.../jdk7/SymlinkContinuousIntegrationTest.groovy | 3 +
.../DaemonHealthLoggingIntegrationTest.groovy | 9 +-
.../daemon/DaemonJvmSettingsIntegrationTest.groovy | 37 +
.../launcher/daemon/DaemonLifecycleSpec.groovy | 10 +-
.../DaemonOutputToggleIntegrationTest.groovy | 9 +-
...emonPerformanceMonitoringIntegrationTest.groovy | 13 +-
.../daemon/DaemonReuseIntegrationTest.groovy | 1 -
.../DaemonStartupMessageIntegrationTest.groovy | 13 +-
.../DaemonSystemPropertiesIntegrationTest.groovy | 4 +-
.../launcher/daemon/IsolatedDaemonSpec.groovy | 37 -
.../daemon/SingleUseDaemonIntegrationTest.groovy | 36 +-
.../gradle/launcher/cli/BuildActionsFactory.java | 16 +-
.../org/gradle/launcher/cli/RunBuildAction.java | 8 +-
.../PropertiesToDaemonParametersConverter.java | 6 +-
.../launcher/daemon/bootstrap/DaemonMain.java | 9 +-
.../daemon/bootstrap/ForegroundDaemonAction.java | 3 +-
.../launcher/daemon/client/DaemonClient.java | 51 +-
.../daemon/client/DaemonClientConnection.java | 11 +-
.../daemon/client/DaemonClientGlobalServices.java | 14 +
.../daemon/client/DaemonClientInputForwarder.java | 25 +-
.../daemon/client/DaemonClientServices.java | 11 +-
.../launcher/daemon/client/DaemonConnector.java | 8 +-
.../daemon/client/DefaultDaemonConnector.java | 12 +-
.../daemon/client/DefaultDaemonStarter.java | 40 +-
.../client/EmbeddedDaemonClientServices.java | 1 +
.../launcher/daemon/client/JvmVersionDetector.java | 78 ++
.../daemon/client/JvmVersionValidator.java | 56 +-
.../client/NoUsableDaemonFoundException.java | 8 +-
.../daemon/client/SingleUseDaemonClient.java | 3 +-
.../launcher/daemon/client/StopDispatcher.java | 7 +-
.../daemon/configuration/CurrentProcess.java | 31 +-
.../daemon/configuration/DaemonParameters.java | 46 +-
.../daemon/context/DaemonContextBuilder.java | 2 +-
.../launcher/daemon/protocol/CloseInput.java | 5 +-
.../launcher/daemon/protocol/CommandFailure.java | 29 -
.../launcher/daemon/protocol/DaemonFailure.java | 29 -
.../daemon/protocol/DaemonMessageSerializer.java | 295 +++++
.../gradle/launcher/daemon/protocol/Failure.java | 2 +-
.../launcher/daemon/protocol/ForwardInput.java | 5 +-
.../launcher/daemon/protocol/InputMessage.java | 19 +
.../gradle/launcher/daemon/protocol/IoCommand.java | 22 -
.../launcher/daemon/protocol/OutputMessage.java | 30 +
.../launcher/daemon/server/DaemonServices.java | 6 +-
.../daemon/server/DaemonTcpServerConnector.java | 8 +-
.../daemon/server/DefaultDaemonConnection.java | 22 +-
.../server/DefaultIncomingConnectionHandler.java | 19 +-
.../daemon/server/IncomingConnectionHandler.java | 3 +-
.../server/SynchronizedDispatchConnection.java | 24 +-
.../server/exec/DefaultDaemonCommandExecuter.java | 7 +-
.../launcher/daemon/server/exec/ExecuteBuild.java | 13 +-
.../launcher/daemon/server/exec/ReturnResult.java | 4 +-
.../server/exec/StartBuildOrRespondWithBusy.java | 4 +-
.../gradle/launcher/exec/BuildActionExecuter.java | 3 +-
.../exec/ContinuousBuildActionExecuter.java | 26 +-
.../DaemonUsageSuggestingBuildActionExecuter.java | 5 +-
.../exec/InProcessBuildActionExecuter.java | 13 +-
.../internal/provider/BuildModelAction.java | 11 +-
.../provider/ClientProvidedBuildAction.java | 12 +-
.../internal/provider/ConnectionScopeServices.java | 11 +-
.../provider/DaemonBuildActionExecuter.java | 5 +-
.../internal/provider/DefaultConnection.java | 18 +-
.../internal/provider/LauncherServices.java | 8 +-
.../LoggingBridgingBuildActionExecuter.java | 5 +-
.../internal/provider/ProviderConnection.java | 58 +-
.../internal/provider/SubscribableBuildAction.java | 34 +
.../provider/TestExecutionRequestAction.java | 94 ++
.../connection/ProviderOperationParameters.java | 2 +
.../provider/events/DefaultTestDescriptor.java | 7 +-
.../test/ProviderInternalJvmTestRequest.java | 67 +
.../test/ProviderInternalTestExecutionRequest.java | 31 +
.../launcher/cli/BuildActionsFactoryTest.groovy | 12 +-
.../gradle/launcher/cli/RunBuildActionTest.groovy | 7 +-
...ropertiesToDaemonParametersConverterTest.groovy | 2 +-
.../client/DaemonClientConnectionTest.groovy | 27 +-
.../client/DaemonClientInputForwarderTest.groovy | 3 +-
.../daemon/client/DaemonClientServicesTest.groovy | 1 +
.../launcher/daemon/client/DaemonClientTest.groovy | 25 +-
.../daemon/client/JvmVersionDetectorTest.groovy | 67 +
.../daemon/client/JvmVersionValidatorTest.groovy | 65 -
.../daemon/configuration/CurrentProcessTest.groovy | 21 +-
.../configuration/DaemonParametersTest.groovy | 51 +-
.../context/DaemonCompatibilitySpecSpec.groovy | 8 +-
.../protocol/DaemonMessageSerializerTest.groovy | 181 +++
.../DaemonServerExceptionHandlingTest.groovy | 10 +-
.../daemon/server/DaemonServicesTest.groovy | 3 +-
.../server/DefaultDaemonConnectionTest.groovy | 26 +-
.../exec/ContinuousBuildActionExecuterTest.groovy | 51 +-
...onUsageSuggestingBuildActionExecuterTest.groovy | 10 +-
.../exec/InProcessBuildActionExecuterTest.groovy | 34 +-
.../provider/DaemonBuildActionExecuterTest.groovy | 6 +-
.../LoggingBridgingBuildActionExecuterTest.groovy | 14 +-
.../provider/TestExecutionRequestActionTest.groovy | 46 +
.../AbstractContinuousIntegrationTest.groovy | 215 ++++
.../Java7RequiringContinuousIntegrationTest.groovy | 0
.../maven/MavenPublishBasicIntegTest.groovy | 6 +-
.../publish/maven/MavenPublishHttpIntegTest.groovy | 54 +-
.../maven/MavenPublishHttpsIntegTest.groovy | 1 -
.../maven/MavenPublishMultiProjectIntegTest.groovy | 2 +-
.../action/AbstractMavenPublishAction.java | 17 +
.../maven/internal/action/MavenDeployAction.java | 22 +-
.../internal/action/SnapshotVersionManager.java | 18 -
.../ProjectDependencyArtifactIdExtractorHack.java | 2 +-
.../maven/internal/MavenPublishServices.java | 4 +-
.../internal/publisher/MavenRemotePublisher.java | 5 +-
.../internal/event/AbstractBroadcastDispatch.java | 58 +
.../gradle/internal/event/BroadcastDispatch.java | 34 +-
.../internal/event/DefaultListenerManager.java | 247 +++-
.../org/gradle/internal/event/ListenerManager.java | 27 +-
.../internal/serialize/BaseSerializerFactory.java | 15 +
.../org/gradle/internal/serialize/Decoder.java | 2 +-
.../serialize/DefaultSerializerRegistry.java | 69 +-
.../internal/serialize/ObjectArraySerializer.java | 43 +
.../gradle/internal/serialize/ObjectReader.java | 9 +-
.../org/gradle/internal/serialize/Serializer.java | 6 +-
.../internal/serialize/SerializerRegistry.java | 12 +
.../org/gradle/internal/serialize/Serializers.java | 51 +
.../internal/serialize/StatefulSerializer.java | 29 +
.../internal/serialize/kryo/JavaSerializer.java | 5 +-
.../serialize/kryo/StatefulSerializer.java | 28 -
.../serialize/kryo/TypeSafeSerializer.java | 5 +-
.../messaging/remote/ObjectConnectionBuilder.java | 6 +-
.../internal/KryoBackedMessageSerializer.java | 60 +
.../internal/hub/InterHubMessageSerializer.java | 31 +-
.../hub/MessageHubBackedObjectConnection.java | 29 +-
.../internal/hub/MethodInvocationSerializer.java | 2 +-
.../remote/internal/inet/SocketConnection.java | 29 +-
.../remote/internal/inet/TcpIncomingConnector.java | 9 +-
.../remote/internal/inet/TcpOutgoingConnector.java | 38 +-
.../event/DefaultListenerManagerTest.groovy | 763 ++++++++++++
.../internal/event/DefaultListenerManagerTest.java | 226 ----
.../internal/serialize/AbstractCodecTest.groovy | 14 +-
.../serialize/BaseSerializerFactoryTest.groovy | 75 +-
.../serialize/DefaultSerializerRegistryTest.groovy | 49 +-
.../serialize/ObjectArraySerializerTest.groovy | 31 +
.../internal/serialize/SerializersTest.groovy | 52 +
.../KryoBackedMessageSerializerTest.groovy | 43 +
.../hub/InterHubMessageSerializerTest.groovy | 15 +-
.../hub/MethodInvocationSerializerTest.groovy | 7 +-
.../internal/inet/MulticastConnectionTest.groovy | 7 +-
.../remote/internal/inet/TcpConnectorTest.groovy | 177 ++-
.../internal/serialize/SerializerSpec.groovy | 21 +-
subprojects/model-core/model-core.gradle | 1 +
.../model/ConfigurationCycleIntegrationTest.groovy | 14 +-
.../ModelRuleBindingFailureIntegrationTest.groovy | 109 +-
...odelRuleBindingValidationIntegrationTest.groovy | 10 +-
.../model/ModelRuleSamplesIntegrationTest.groovy | 2 +
.../ModelRuleValidationIntegrationTest.groovy | 4 +-
.../model/PluginRuleSourceIntegrationTest.groovy | 8 +-
.../model/ScopedRuleSourceIntegrationTest.groovy | 23 +-
.../model/TaskCreationIntegrationTest.groovy | 51 +-
.../ComplexManagedTypeIntegrationTest.groovy | 219 ----
.../CyclicalManagedTypeIntegrationTest.groovy | 4 +-
...validManagedModelMutationIntegrationTest.groovy | 14 +-
.../InvalidManagedModelRuleIntegrationTest.groovy | 8 +-
.../managed/ManagedModelMapIntegrationTest.groovy | 6 +-
...odelPropertyTargetingRuleIntegrationTest.groovy | 73 +-
.../model/managed/ManagedSetIntegrationTest.groovy | 47 +-
.../ManagedTypeReferencesIntegrationTest.groovy | 92 ++
.../model/managed/ModelSetIntegrationTest.groovy | 45 +-
.../NestedManagedTypeIntegrationTest.groovy | 148 +++
.../PolymorphicManagedTypeIntegrationTest.groovy | 5 +
.../PrimitivesInManagedModelIntegrationTest.groovy | 231 ----
...ScalarTypesInManagedModelIntegrationTest.groovy | 570 +++++++++
.../src/main/java/org/gradle/model/Managed.java | 12 +-
.../src/main/java/org/gradle/model/ModelMap.java | 2 +-
.../internal/ModelMapModelProjection.java | 10 +-
.../internal/core/ChildNodeCreatorStrategy.java | 27 -
.../core/ChildNodeInitializerStrategy.java | 26 +
.../model/internal/core/EmptyModelProjection.java | 1 +
.../internal/core/FactoryBasedNodeInitializer.java | 50 +
.../gradle/model/internal/core/ModelAdapter.java | 2 +-
.../gradle/model/internal/core/ModelCreator.java | 2 +-
.../model/internal/core/ModelCreatorFactory.java | 41 -
.../gradle/model/internal/core/ModelCreators.java | 22 +-
.../internal/core/ModelMapGroovyDecorator.java | 6 +
.../org/gradle/model/internal/core/ModelNode.java | 19 +
.../model/internal/core/MutableModelNode.java | 3 -
.../model/internal/core/NodeBackedModelMap.java | 122 +-
.../model/internal/core/NodeBackedModelSet.java | 19 +-
.../model/internal/core/NodeInitializer.java | 37 +
.../core/ProjectionBackedModelCreator.java | 6 +-
.../core/SpecializedModelMapProjection.java | 4 +-
.../TypeCompatibilityModelProjectionSupport.java | 8 +-
.../rule/describe/AbstractModelRuleDescriptor.java | 1 -
.../rule/describe/MethodModelRuleDescriptor.java | 17 +-
.../core/rule/describe/ModelRuleDescriptor.java | 4 +
.../rule/describe/NestedModelRuleDescriptor.java | 19 +
.../rule/describe/SimpleModelRuleDescriptor.java | 17 +
.../inspect/DefaultModelCreatorFactory.java | 262 ----
.../inspect/ManagedChildNodeCreatorStrategy.java | 43 +
.../inspect/ManagedModelCreationRuleExtractor.java | 23 +-
.../internal/inspect/ManagedModelInitializer.java | 70 +-
.../inspect/MethodModelRuleExtractors.java | 15 +-
.../inspect/ProjectionOnlyNodeInitializer.java | 46 +
.../manage/instance/ManagedProxyFactory.java | 17 +-
.../manage/projection/ManagedModelProjection.java | 31 +-
.../manage/schema/AbstractModelSchema.java | 35 +
.../manage/schema/AbstractModelStructSchema.java | 77 ++
.../manage/schema/ManagedImplModelSchema.java | 29 +
.../manage/schema/ModelCollectionSchema.java | 36 +-
.../schema/ModelManagedImplStructSchema.java | 57 +
.../internal/manage/schema/ModelMapSchema.java | 9 +-
.../internal/manage/schema/ModelProperty.java | 56 +-
.../model/internal/manage/schema/ModelSchema.java | 76 +-
.../internal/manage/schema/ModelStructSchema.java | 34 +-
.../schema/ModelUnmanagedImplStructSchema.java | 31 +
.../internal/manage/schema/ModelValueSchema.java | 30 +
.../schema/extract/DefaultModelSchemaStore.java | 9 +-
.../manage/schema/extract/EnumStrategy.java | 13 +-
.../schema/extract/JdkValueTypeStrategy.java | 45 +-
...dImplStructSchemaExtractionStrategySupport.java | 376 ++++++
.../schema/extract/ManagedImplStructStrategy.java | 80 ++
.../schema/extract/ManagedProxyClassGenerator.java | 282 ++++-
.../manage/schema/extract/ManagedSetStrategy.java | 68 +-
.../manage/schema/extract/ModelMapStrategy.java | 43 +-
.../extract/ModelPropertyExtractionResult.java | 45 +
.../manage/schema/extract/ModelSchemaAspect.java | 20 +
.../extract/ModelSchemaAspectExtractionResult.java | 43 +
.../ModelSchemaAspectExtractionStrategy.java | 26 +
.../schema/extract/ModelSchemaAspectExtractor.java | 52 +
.../extract/ModelSchemaExtractionContext.java | 11 +-
.../extract/ModelSchemaExtractionStrategy.java | 5 +-
.../schema/extract/ModelSchemaExtractor.java | 75 +-
.../manage/schema/extract/ModelSchemaUtils.java | 172 +++
.../manage/schema/extract/ModelSetStrategy.java | 67 +-
.../manage/schema/extract/PrimitiveStrategy.java | 28 +-
.../extract/PropertyAccessorExtractionContext.java | 86 ++
.../manage/schema/extract/SetStrategy.java | 56 +-
.../schema/extract/SpecializedMapStrategy.java | 12 +-
.../StructSchemaExtractionStrategySupport.java | 231 ++++
.../manage/schema/extract/StructStrategy.java | 442 -------
.../extract/UnmanagedImplStructStrategy.java | 74 ++
.../manage/schema/extract/UnmanagedStrategy.java | 32 -
.../internal/registry/DefaultModelRegistry.java | 189 +--
.../model/internal/registry/ModelNodeInternal.java | 49 +-
.../internal/registry/ModelReferenceNode.java | 199 +++
.../registry/UnboundModelRulesException.java | 4 +-
.../internal/report/unbound/UnboundRuleInput.java | 4 +-
.../report/unbound/UnboundRulesReporter.java | 62 +-
.../org/gradle/model/internal/type/ModelType.java | 15 +
.../internal/type/TypeVariableTypeWrapper.java | 161 +++
.../gradle/model/ManagedModelMapTypesTest.groovy | 28 +-
.../org/gradle/model/ManagedNamedTest.groovy | 12 +-
.../model/ManagedNodeBackedModelMapTest.groovy | 25 +-
.../model/UnmanagedNodeBackedModelMapTest.groovy | 14 +-
.../describe/MethodModelRuleDescriptorTest.groovy | 28 +-
.../internal/inspect/ModelRuleBindingTest.groovy | 2 +-
.../internal/inspect/ModelRuleExtractorTest.groovy | 24 +-
.../inspect/ModelRuleSourceDetectorTest.groovy | 4 +-
.../inspect/MutationRuleExecutionOrderTest.groovy | 2 +-
.../projection/ModelSetModelProjectionTest.groovy | 16 +-
.../extract/DefaultModelSchemaStoreTest.groovy | 12 +-
.../extract/ManagedProxyClassGeneratorTest.groovy | 210 +++-
.../schema/extract/ModelSchemaExtractorTest.groovy | 520 +++++++-
.../schema/extract/ModelSchemaUtilsTest.groovy | 92 ++
.../extract/ScalarTypesInManagedModelTest.groovy | 69 ++
...TypeWithManagedSuperTypeExtractionStrategy.java | 36 +
.../registry/DefaultModelRegistryTest.groovy | 244 ++--
.../internal/registry/ModelNodeInternalTest.groovy | 65 +
.../model/internal/registry/RegistrySpec.groovy | 8 +-
.../model/internal/registry/ScopedRuleTest.groovy | 41 +-
.../report/unbound/UnboundRulesReporterTest.groovy | 23 +-
.../internal/fixture/ModelRegistryHelper.java | 3 +-
.../unbound/UnboundRulesReportMatchers.groovy | 38 -
.../dsl/ModelDslCreationIntegrationTest.groovy | 3 +-
...odelDslRuleInputDetectionIntegrationSpec.groovy | 84 +-
.../internal/NonTransformedModelDslBacking.java | 28 +-
.../dsl/internal/TransformedModelDslBacking.java | 50 +-
.../model/dsl/internal/transform/RuleMetadata.java | 2 +
.../model/dsl/internal/transform/RuleVisitor.java | 1 +
.../model/dsl/internal/transform/RulesVisitor.java | 13 +-
.../dsl/internal/transform/SourceLocation.java | 7 +-
.../NonTransformedModelDslBackingTest.groovy | 4 +-
.../internal/TransformedModelDslBackingTest.groovy | 5 +-
.../nativeintegration/services/NativeServices.java | 10 +-
.../NativePlatformConsoleDetectorTest.groovy | 7 +-
subprojects/performance/performance.gradle | 8 +-
.../OldJavaPluginBigProjectPerformanceTest.groovy | 4 +-
.../ProjectDependenciesPerformanceTest.groovy | 3 -
.../performance/VariantsPerformanceTest.groovy | 12 +-
.../src/templates/native-pch-source/pch.h | 10 +-
.../CrossVersionPerformanceTestRunnerTest.groovy | 5 +
.../fixture/GCLoggingCollectorTest.groovy | 2 +-
.../fixture/BuildEventTimestampCollector.java | 2 +-
.../performance/fixture/BuildExperimentRunner.java | 4 +-
.../fixture/CompositeDataCollector.java | 4 +-
.../gradle/performance/fixture/DataCollector.java | 2 +-
.../performance/fixture/GCLoggingCollector.java | 2 +-
.../org/gradle/performance/fixture/Git.groovy | 2 +-
.../fixture/GradleExecuterBackedSession.groovy | 8 +-
.../fixture/GradleInvocationSpec.groovy | 12 +-
.../performance/fixture/MemoryInfoCollector.groovy | 2 +-
.../fixture/ToolingApiBackedGradleSession.groovy | 2 +-
subprojects/platform-base/platform-base.gradle | 1 +
.../base/ComponentModelIntegrationTest.groovy | 217 ++--
.../base/CustomBinaryIntegrationTest.groovy | 6 +-
.../CustomComponentBinariesIntegrationTest.groovy | 4 +-
.../CustomComponentPluginIntegrationTest.groovy | 6 +-
.../CustomComponentSourceSetIntegrationTest.groovy | 170 +++
.../VariantAspectExtractionIntegrationTest.groovy | 126 ++
.../AbstractLocalLibraryDependencyResolver.java | 178 +++
.../resolve/DefaultProjectModelResolver.java | 43 +
.../LibraryResolutionErrorMessageBuilder.java | 163 +++
.../api/internal/resolve/ProjectModelResolver.java | 26 +
.../api/internal/resolve/VariantsMatcher.java | 135 ++
.../gradle/language/base/FunctionalSourceSet.java | 2 -
.../base/internal/DefaultFunctionalSourceSet.java | 11 -
.../base/internal/DependentSourceSetInternal.java | 2 +-
.../base/internal/LanguageSourceSetContainer.java | 50 -
.../base/internal/SourceSetNotationParser.java | 70 --
.../base/internal/SourceTransformTaskConfig.java | 4 +-
.../base/internal/model/ComponentBinaryRules.java | 61 +
.../base/internal/model/ComponentRules.java | 9 +-
.../DefaultLibraryLocalComponentMetaData.java | 51 +
.../model/DefaultVariantDimensionSelector.java | 35 +
.../DefaultVariantDimensionSelectorFactory.java | 41 +
.../internal/model/DefaultVariantsMetaData.java | 104 ++
.../internal/model/VariantDimensionSelector.java | 39 +
.../model/VariantDimensionSelectorFactory.java | 20 +
.../base/internal/model/VariantsMetaData.java | 35 +
.../internal/model/VariantsMetaDataHelper.java | 35 +
.../DependentSourceSetLocalComponentConverter.java | 85 ++
.../resolve/DependentSourceSetResolveContext.java | 79 ++
.../internal/resolve/LibraryResolveException.java | 32 +
.../base/plugins/ComponentModelBasePlugin.java | 52 +-
.../language/base/plugins/LanguageBasePlugin.java | 2 +-
.../base/sources/BaseLanguageSourceSet.java | 2 +-
.../core/DomainObjectCollectionBackedModelMap.java | 239 ++++
.../core/DomainObjectSetBackedModelMap.java | 232 ----
.../java/org/gradle/platform/base/BinarySpec.java | 30 +-
.../org/gradle/platform/base/ComponentSpec.java | 8 +
.../platform/base/DependencySpecContainer.java | 22 +-
.../platform/base/PlatformAwareComponentSpec.java | 2 +-
.../java/org/gradle/platform/base/Variant.java | 39 +
.../platform/base/binary/BaseBinarySpec.java | 58 +-
.../platform/base/component/BaseComponentSpec.java | 47 +-
.../platform/base/internal/BinaryNamingScheme.java | 5 -
.../platform/base/internal/BinarySpecInternal.java | 10 +-
.../base/internal/ComponentSpecInternal.java | 4 +-
.../internal/DefaultDependencySpecContainer.java | 81 +-
.../platform/base/internal/VariantAspect.java | 35 +
.../internal/VariantAspectExtractionStrategy.java | 56 +
.../base/internal/builder/TypeBuilderFactory.java | 23 +
.../internal/registry/AbstractTypeBuilder.java | 13 +-
.../registry/BinaryTasksModelRuleExtractor.java | 2 +-
.../registry/BinaryTypeModelRuleExtractor.java | 18 +-
.../ComponentModelBaseServiceRegistry.java | 50 +-
.../registry/ComponentTypeModelRuleExtractor.java | 21 +-
.../registry/LanguageTypeModelRuleExtractor.java | 18 +-
.../internal/registry/TypeModelRuleExtractor.java | 17 +-
.../toolchain/DefaultResolvedCompiler.java | 45 -
.../internal/toolchain/DefaultResolvedTool.java | 43 -
.../internal/toolchain/DefaultToolResolver.java | 178 ---
.../base/internal/toolchain/ResolvedTool.java | 21 -
.../base/internal/toolchain/ToolResolver.java | 29 -
.../internal/resolve/VariantsMatcherTest.groovy | 233 ++++
.../ComponentTypeModelRuleExtractorTest.groovy | 10 +-
.../internal/SourceSetNotationParserTest.groovy | 54 -
.../model/DefaultVariantsMetaDataTest.groovy | 73 ++
.../internal/model/ParametrizedBinaryString.java | 26 +
.../model/ParametrizedBinaryVariantDimension1.java | 26 +
.../base/internal/model/ParametrizedVariant.java | 24 +
.../base/internal/model/VariantDimension1.java | 22 +
.../base/internal/model/VariantDimension2.java | 22 +
.../base/internal/model/VariantDimension3.java | 20 +
.../model/VariantsMetaDataHelperTest.groovy | 100 ++
.../LanguageTypeModelRuleExtractorTest.groovy | 6 +-
...dentSourceSetLocalComponentConverterTest.groovy | 136 +++
.../DependentSourceSetResolveContextTest.groovy | 64 +
.../testinterfaces/CustomLanguageSourceSet.groovy | 21 +
.../internal/testinterfaces/NotBinarySpec.groovy | 19 +
.../testinterfaces/NotComponentSpec.groovy | 19 +
.../base/internal/testinterfaces/RawLibrary.groovy | 21 +
.../internal/testinterfaces/SomeBinarySpec.groovy | 21 +
.../testinterfaces/SomeBinarySubType.groovy | 19 +
.../testinterfaces/SomeComponentSpec.groovy | 21 +
.../internal/testinterfaces/SomeLibrary.groovy | 21 +
...DomainObjectCollectionBackedModelMapTest.groovy | 45 +
.../platform/base/binary/BaseBinarySpecTest.groovy | 42 +
.../base/component/BaseComponentSpecTest.groovy | 14 +-
...SpecSpecializationSchemaExtractionStrategy.java | 38 +
.../BinaryTasksModelRuleExtractorTest.groovy | 13 +-
.../BinaryTypeModelRuleExtractorTest.groovy | 36 +-
.../ComponentBinariesModelRuleExtractorTest.groovy | 12 +-
.../toolchain/DefaultToolResolverTest.groovy | 128 --
.../base/component/BaseComponentFixtures.groovy | 10 +-
.../jvm/ComponentReportIntegrationTest.groovy | 66 +-
...ustomJarBinarySpecSubtypeIntegrationTest.groovy | 237 ++++
.../gradle/jvm/JarBinariesIntegrationTest.groovy | 6 +-
.../JvmComponentPluginIntegrationTest.groovy | 37 +-
.../JvmLibraryResolutionErrorMessageBuilder.java | 151 +++
.../resolve/JvmLocalLibraryDependencyResolver.java | 44 +
.../internal/resolve/LibraryPublishArtifact.java | 37 +
.../main/java/org/gradle/jvm/JarBinarySpec.java | 6 +
.../main/java/org/gradle/jvm/JvmBinarySpec.java | 10 +-
.../java/org/gradle/jvm/JvmComponentExtension.java | 33 -
.../org/gradle/jvm/internal/BuildDirHolder.java | 31 +
.../gradle/jvm/internal/DefaultJarBinarySpec.java | 28 +-
...efaultJavaPlatformVariantDimensionSelector.java | 31 +
.../jvm/internal/DependencyResolvingClasspath.java | 155 +++
.../org/gradle/jvm/internal/JarBinaryRules.java | 45 +
.../gradle/jvm/internal/JarBinarySpecInternal.java | 8 +-
.../gradle/jvm/internal/PlatformJvmServices.java | 35 -
...arBinarySpecSpecializationModelInitializer.java | 60 +
...SpecSpecializationSchemaExtractionStrategy.java | 40 +
.../plugins/DefaultJvmComponentExtension.java | 34 -
.../jvm/internal/services/PlatformJvmServices.java | 87 ++
.../jvm/platform/internal/DefaultJavaPlatform.java | 9 +-
.../org/gradle/jvm/plugins/JvmComponentPlugin.java | 195 ++-
...e.internal.service.scopes.PluginServiceRegistry | 2 +-
.../JvmLocalLibraryDependencyResolverTest.groovy | 250 ++++
...JavaPlatformVariantDimensionSelectorTest.groovy | 74 ++
.../jvm/internal/DefaultJvmLibrarySpecTest.groovy | 2 +-
.../internal/plugins/CreateJvmBinariesTest.groovy | 22 +-
.../internal/DefaultJavaPlatformTest.groovy | 4 +-
.../BinaryBuildTypesIntegrationTest.groovy | 6 +-
.../BinaryConfigurationIntegrationTest.groovy | 155 +--
.../BinaryFlavorsIntegrationTest.groovy | 5 +-
.../ComponentReportIntegrationTest.groovy | 11 +-
.../LibraryDependenciesIntegrationTest.groovy | 2 +-
.../NativeBinariesIntegrationTest.groovy | 2 +-
.../NativePlatformSamplesIntegrationTest.groovy | 30 +
.../TestSuiteDefinitionIntegrationSpec.groovy | 41 +-
.../TestSuiteModelIntegrationSpec.groovy | 82 +-
.../BinaryNativePlatformIntegrationTest.groovy | 2 +-
.../GeneratedSourcesIntegrationTest.groovy | 2 +-
...GccToolChainCustomisationIntegrationTest.groovy | 2 +
.../GccToolChainDiscoveryIntegrationTest.groovy | 2 +
.../internal/AbstractNativeBinarySpec.java | 6 +-
.../internal/AbstractNativeComponentSpec.java | 8 +-
.../internal/AbstractNativeLibraryBinarySpec.java | 6 +-
.../internal/DefaultSharedLibraryBinarySpec.java | 4 +-
.../internal/configure/NativeComponentRules.java | 2 +-
.../prebuilt/PrebuiltLibraryBinaryLocator.java | 14 +-
.../resolve/ChainedLibraryBinaryLocator.java | 1 +
.../resolve/CurrentProjectModelResolver.java | 39 +
.../internal/resolve/DefaultLibraryResolver.java | 1 +
.../internal/resolve/DefaultProjectLocator.java | 42 -
.../internal/resolve/LibraryResolveException.java | 32 -
.../resolve/NativeDependencyResolverServices.java | 15 +-
.../resolve/ProjectLibraryBinaryLocator.java | 21 +-
.../internal/resolve/ProjectLocator.java | 22 -
.../internal/services/NativeBinaryServices.java | 3 +
.../nativeplatform/platform/Architecture.java | 33 +
.../nativeplatform/platform/NativePlatform.java | 62 +-
.../nativeplatform/platform/OperatingSystem.java | 23 +
.../plugins/NativeComponentModelPlugin.java | 187 ++-
.../plugins/NativeComponentPlugin.groovy | 132 --
.../plugins/NativeComponentPlugin.java | 33 +
.../internal/DefaultNativeTestSuiteBinarySpec.java | 2 +-
.../test/plugins/NativeBinariesTestPlugin.java | 13 +-
.../gcc/AbstractGccCompatibleToolChain.java | 13 +
.../DefaultSharedLibraryBinarySpecTest.groovy | 9 +-
.../DefaultStaticLibraryBinarySpecTest.groovy | 4 +-
.../internal/NativeBinarySpecTest.groovy | 40 +-
.../resolve/ProjectLibraryBinaryLocatorTest.groovy | 34 +-
.../configure/TestNativeBinariesFactory.java | 2 +-
subprojects/platform-play/platform-play.gradle | 4 +-
...xedPlayAndJavaLangProjectIntegrationTest.groovy | 71 --
...dPlayAndJvmLibraryProjectIntegrationTest.groovy | 76 ++
...edPlayAndScalaLangProjectIntegrationTest.groovy | 70 --
.../PlayAppWithFailingTestsIntegrationTest.groovy | 12 +-
.../PlayBinaryApplicationIntegrationTest.groovy | 32 +-
...ayDistributionApplicationIntegrationTest.groovy | 20 +-
...ayMultiProjectApplicationIntegrationTest.groovy | 111 +-
.../integtest/PlayPlatformIntegrationTest.groovy | 43 +-
.../PlayTestApplicationIntegrationTest.groovy | 25 +-
.../advanced/AdvancedAppContentVerifier.groovy | 41 -
.../PlayBinaryAdvancedAppIntegrationTest.groovy | 12 +-
...ayDistributionAdvancedAppIntegrationTest.groovy | 14 +-
.../PlayContinuousBuildIntegrationTest.groovy | 95 ++
...ltiProjectContinuousBuildIntegrationTest.groovy | 181 +++
.../PlayMultiProjectReloadIntegrationTest.groovy | 208 ++++
.../continuous/PlayReloadIntegrationTest.groovy | 203 +++
.../DistributionTestExecHandleBuilder.groovy | 76 --
.../play/integtest/fixtures/PlayCoverage.groovy | 21 -
...ayMultiVersionApplicationIntegrationTest.groovy | 50 -
.../PlayMultiVersionIntegrationTest.groovy | 28 -
...ultiVersionRunApplicationIntegrationTest.groovy | 47 -
.../AbstractPlaySampleIntegrationTest.groovy | 32 +-
.../MultiprojectPlaySampleIntegrationTest.groovy | 11 +-
.../UserGuidePlaySamplesIntegrationTest.groovy | 131 ++
.../PlayApplicationPluginIntegrationTest.groovy | 69 +-
.../PlayCoffeeScriptPluginIntegrationTest.groovy | 9 +-
.../PlayDistributionPluginIntegrationTest.groovy | 23 +-
.../PlayJavaScriptPluginIntegrationTest.groovy | 4 +-
.../AbstractRoutesCompileIntegrationTest.groovy | 305 +++++
.../CoffeeScriptCompileIntegrationTest.groovy | 45 +-
...offeeScriptImplementationIntegrationTest.groovy | 16 +-
.../tasks/DistributionZipIntegrationTest.groovy | 11 +-
.../tasks/JavaScriptMinifyIntegrationTest.groovy | 29 +-
.../Play23RoutesCompileIntegrationTest.groovy | 65 +
.../Play24RoutesCompileIntegrationTest.groovy | 99 ++
.../play/tasks/PlayRunIntegrationTest.groovy | 84 ++
.../play/tasks/RoutesCompileIntegrationTest.groovy | 246 ----
.../play/tasks/TwirlCompileIntegrationTest.groovy | 48 +-
.../play/tasks/TwirlVersionIntegrationTest.groovy | 34 +-
.../fixtures/app/advancedplayapp/build.gradle | 16 -
.../fixtures/app/basicplayapp/build.gradle | 11 -
.../app/basicplayapp/test/ApplicationSpec.scala | 35 -
.../app/basicplayapp/test/IntegrationSpec.scala | 34 -
.../app/playappwithdependencies/build.gradle | 16 -
.../test/ApplicationSpec.scala | 36 -
.../test/IntegrationSpec.scala | 38 -
.../fixtures/app/playmultiproject/build.gradle | 9 -
.../test/FailingApplicationSpec.scala | 36 -
.../test/FailingIntegrationSpec.scala | 36 -
.../src/main/java/org/gradle/play/JvmClasses.java | 1 -
.../org/gradle/play/PlayApplicationBinarySpec.java | 25 +-
.../java/org/gradle/play/PlayApplicationSpec.java | 46 +-
.../gradle/play/distribution/PlayDistribution.java | 4 +
.../internal/DefaultPlayApplicationBinarySpec.java | 24 +-
.../play/internal/DefaultPlayApplicationSpec.java | 11 +
.../gradle/play/internal/DefaultPlayPlatform.java | 1 +
.../PlayApplicationBinarySpecInternal.java | 8 +-
.../play/internal/PlayPlatformNotationParser.java | 7 +-
.../gradle/play/internal/PlayPlatformResolver.java | 2 +-
.../gradle/play/internal/PlaySourceSetRules.java | 79 ++
.../play/internal/platform/PlayMajorVersion.java | 8 +-
.../internal/routes/DefaultRoutesCompileSpec.java | 29 +-
.../DefaultVersionedRoutesCompilerAdapter.java | 12 +-
.../play/internal/routes/RoutesCompileSpec.java | 9 +
.../play/internal/routes/RoutesCompiler.java | 2 +-
.../internal/routes/RoutesCompilerAdapterV22X.java | 13 +-
.../internal/routes/RoutesCompilerAdapterV23X.java | 11 +-
.../internal/routes/RoutesCompilerAdapterV24X.java | 83 ++
.../internal/routes/RoutesCompilerFactory.java | 2 +
.../routes/VersionedRoutesCompilerAdapter.java | 5 +-
.../play/internal/run/DefaultPlayRunSpec.java | 28 +-
.../run/DefaultVersionedPlayRunAdapter.java | 107 +-
.../run/PlayApplicationDeploymentHandle.java | 74 ++
.../play/internal/run/PlayApplicationRunner.java | 12 +-
.../internal/run/PlayApplicationRunnerFactory.java | 40 +
.../internal/run/PlayApplicationRunnerToken.java | 27 +-
.../play/internal/run/PlayRunAdapterV22X.java | 9 +
.../play/internal/run/PlayRunAdapterV23X.java | 73 ++
.../play/internal/run/PlayRunAdapterV24X.java | 33 +
.../org/gradle/play/internal/run/PlayRunSpec.java | 8 +
.../internal/run/PlayRunWorkerServerProtocol.java | 2 +
.../gradle/play/internal/run/PlayWorkerServer.java | 57 +-
.../play/internal/run/VersionedPlayRunAdapter.java | 12 +-
.../spec/PlayApplicationBinaryRenderer.java | 1 -
.../internal/toolchain/DefaultPlayToolChain.java | 2 +-
.../toolchain/DefaultPlayToolProvider.java | 39 +-
.../toolchain/PlayToolChainServiceRegistry.java | 4 +
.../internal/twirl/TwirlCompilerAdapterV10X.java | 2 +-
.../internal/twirl/TwirlCompilerAdapterV22X.java | 3 +-
.../play/internal/twirl/TwirlCompilerFactory.java | 6 +-
.../twirl/VersionedTwirlCompilerAdapter.java | 2 +-
.../org/gradle/play/platform/PlayPlatform.java | 12 +
.../gradle/play/plugins/PlayApplicationPlugin.java | 176 ++-
.../play/plugins/PlayCoffeeScriptPlugin.java | 20 +-
.../play/plugins/PlayDistributionPlugin.java | 50 +-
.../gradle/play/plugins/PlayJavaScriptPlugin.java | 30 +-
.../play/plugins/PlayPluginConfigurations.java | 51 +-
.../org/gradle/play/plugins/PlayTestPlugin.java | 13 +-
.../org/gradle/play/tasks/JavaScriptMinify.java | 32 +-
.../gradle/play/tasks/PlayCoffeeScriptCompile.java | 2 +-
.../main/java/org/gradle/play/tasks/PlayRun.java | 119 +-
.../java/org/gradle/play/tasks/RoutesCompile.java | 99 +-
.../java/org/gradle/play/tasks/TwirlCompile.java | 59 +-
.../gradle/scala/internal/reflect/ScalaMethod.java | 37 +-
.../gradle/scala/internal/reflect/ScalaObject.java | 71 ++
.../DefaultPlayApplicationBinarySpecTest.groovy | 17 +-
.../play/internal/DefaultPlayToolChainTest.groovy | 2 +-
.../play/internal/PlayPlatformResolverTest.groovy | 2 +-
.../run/PlayApplicationDeploymentHandleTest.groovy | 98 ++
.../run/PlayApplicationRunnerTokenTest.groovy | 56 +
.../toolchain/DefaultPlayToolProviderTest.groovy | 26 +-
.../play/plugins/PlayCoffeeScriptPluginTest.groovy | 13 +-
.../play/plugins/PlayDistributionPluginTest.groovy | 2 -
.../play/plugins/PlayJavaScriptPluginTest.groovy | 11 +-
.../gradle/play/plugins/PlayTestPluginTest.groovy | 4 +
.../org/gradle/play/tasks/PlayRunTest.groovy | 27 +-
.../org/gradle/play/tasks/TwirlCompileTest.groovy | 24 +-
...ersionPlayContinuousBuildIntegrationTest.groovy | 33 +
...actMultiVersionPlayReloadIntegrationTest.groovy | 24 +
...stractPlayContinuousBuildIntegrationTest.groovy | 68 ++
.../fixtures/AdvancedRunningPlayApp.groovy | 48 +
.../DistributionTestExecHandleBuilder.groovy | 110 ++
.../fixtures/MultiProjectRunningPlayApp.groovy | 36 +
.../play/integtest/fixtures/PlayCoverage.groovy | 29 +
...ayMultiVersionApplicationIntegrationTest.groovy | 51 +
.../PlayMultiVersionIntegrationTest.groovy | 30 +
...ultiVersionRunApplicationIntegrationTest.groovy | 33 +
.../play/integtest/fixtures/RunningPlayApp.groovy | 110 ++
.../integtest/fixtures/app/AdvancedPlayApp.groovy | 0
.../integtest/fixtures/app/BasicPlayApp.groovy | 0
.../play/integtest/fixtures/app/PlayApp.groovy | 0
.../fixtures/app/PlayAppWithDependencies.groovy | 0
.../integtest/fixtures/app/PlayMultiProject.groovy | 0
.../fixtures/app/WithFailingTestsApp.groovy | 0
.../app/assets/javascripts/sample.js | 0
.../app/assets/javascripts/test.coffee | 0
.../app/controllers/Application.scala | 0
.../app/controllers/jva/PureJava.java | 0
.../app/controllers/scala/MixedJava.java | 0
.../app/advancedplayapp/app/models/DataType.java | 0
.../advancedplayapp/app/models/ScalaClass.scala | 0
.../app/special/strangename/Application.scala | 0
.../app/views/awesome/index.scala.html | 0
.../app/advancedplayapp/app/views/index.scala.html | 0
.../app/advancedplayapp/app/views/main.scala.html | 0
.../fixtures/app/advancedplayapp/build.gradle | 21 +
.../fixtures/app/advancedplayapp/conf/jva.routes | 0
.../fixtures/app/advancedplayapp/conf/routes | 0
.../fixtures/app/advancedplayapp/conf/scala.routes | 0
.../basicplayapp/app/controllers/Application.scala | 0
.../app/basicplayapp/app/views/index.scala.html | 0
.../app/basicplayapp/app/views/main.scala.html | 0
.../fixtures/app/basicplayapp/build.gradle | 16 +
.../fixtures/app/basicplayapp/conf/routes | 0
.../app/basicplayapp/test/ApplicationSpec.scala | 26 +
.../app/basicplayapp/test/IntegrationSpec.scala | 23 +
.../fixtures/app/basicplayapp/test/notATest.yaml | 0
.../app/controllers/Application.scala | 0
.../app/views/index.scala.html | 0
.../app/views/main.scala.html | 0
.../app/playappwithdependencies/build.gradle | 21 +
.../app/playappwithdependencies/conf/routes | 0
.../test/ApplicationSpec.scala | 26 +
.../test/IntegrationSpec.scala | 23 +
.../app/playappwithdependencies/test/notATest.yaml | 0
.../fixtures/app/playmultiproject/build.gradle | 14 +
.../app/playmultiproject/javalibrary/build.gradle | 0
.../javalibrary/src/main/java/org/test/Util.java | 0
.../primary/app/controllers/Application.scala | 0
.../app/playmultiproject/primary/build.gradle | 0
.../playmultiproject/primary/conf/application.conf | 0
.../app/playmultiproject/primary/conf/routes | 0
.../playmultiproject/primary/public/primary.txt | 0
.../fixtures/app/playmultiproject/settings.gradle | 0
.../app/controllers/submodule/Application.scala | 0
.../app/playmultiproject/submodule/build.gradle | 0
.../submodule/public/submodule.txt | 0
.../play/integtest/fixtures/app/shared/README | 0
.../fixtures/app/shared/conf/application.conf | 0
.../integtest/fixtures/app/shared/conf/logback.xml | 22 +
.../fixtures/app/shared/public/images/favicon.svg | 0
.../app/shared/public/javascripts/hello.js | 0
.../app/shared/public/stylesheets/main.css | 0
.../test/FailingApplicationSpec.scala | 28 +
.../test/FailingIntegrationSpec.scala | 25 +
.../PluginUseClassLoadingIntegrationSpec.groovy | 2 +
.../plugin/use/PluginUseDslIntegrationSpec.groovy | 2 +-
...esolutionDeprecatedClientIntegrationTest.groovy | 2 +-
...ginResolutionServiceCommsIntegrationTest.groovy | 13 +-
.../internal/PluginUsePluginServiceRegistry.java | 9 +-
subprojects/plugins/plugins.gradle | 1 +
.../api/plugins/BasePluginIntegrationTest.groovy | 7 +-
.../BasicGroovyCompilerIntegrationSpec.groovy | 16 +
.../compile/InvokeDynamicGroovyCompilerSpec.groovy | 2 +
.../BasicJavaCompilerIntegrationSpec.groovy | 3 +-
.../gradle/testing/fixture/JUnitCoverage.groovy | 6 +-
.../gradle/testing/fixture/TestNGCoverage.groovy | 8 +-
.../JUnitClassLevelFilteringIntegrationTest.groovy | 88 ++
.../junit/JUnitFilteringIntegrationTest.groovy | 53 +-
.../JUnitFilteringSupportIntegrationTest.groovy | 55 +-
...itIgnoreClassMultiVersionIntegrationSpec.groovy | 2 +-
.../internal/java/AbstractLanguageSourceSet.java | 2 +
.../jvm/DefaultClassDirectoryBinarySpec.java | 44 +-
.../gradle/api/internal/tasks/CompileServices.java | 3 +
.../tasks/testing/NoMatchingTestsReporter.java | 6 +-
.../tasks/testing/filter/DefaultTestFilter.java | 23 +-
.../testing/junit/JUnitTestClassExecuter.java | 58 +-
.../tasks/testing/junit/JUnitTestEventAdapter.java | 14 +-
.../tasks/testing/junit/JUnitTestFramework.java | 20 -
.../testing/worker/ForkingTestClassProcessor.java | 2 +-
.../tasks/testing/worker/TestEventSerializer.java | 47 +-
.../internal/tasks/testing/worker/TestWorker.java | 4 +-
.../api/plugins/LegacyJavaComponentPlugin.java | 11 +-
.../groovy/org/gradle/api/tasks/testing/Test.java | 2 +-
.../api/tasks/testing/TestExecutionException.java | 36 +
.../org/gradle/api/tasks/testing/TestFilter.java | 38 +-
.../main/groovy/org/gradle/jvm/package-info.java | 20 -
.../api/internal/plugins/unixStartScript.txt | 6 +-
.../jvm/DefaultClassDirectoryBinarySpecTest.groovy | 3 +-
.../plugins/UnixStartScriptGeneratorTest.groovy | 2 +-
.../testing/filter/DefaultTestFilterTest.groovy | 10 +
.../junit/JUnitTestClassProcessorData.groovy | 4 +-
.../junit/JUnitTestClassProcessorTest.groovy | 25 +
.../testing/worker/TestEventSerializerTest.groovy | 22 +-
.../tasks/testing/worker/TestWorkerTest.groovy | 107 +-
.../gradle/api/plugins/JavaBasePluginTest.groovy | 2 +-
.../api/publish/internal/PublishServices.java | 3 +
subprojects/resources-http/resources-http.gradle | 2 +-
.../authentication/http/BasicAuthentication.java | 27 +
.../authentication/http/DigestAuthentication.java | 27 +
.../gradle/authentication/http/package-info.java | 25 +
.../authentication/DefaultBasicAuthentication.java | 26 +
.../DefaultDigestAuthentication.java | 26 +
.../http/AlwaysRedirectRedirectStrategy.java | 19 +-
.../transport/http/DefaultHttpSettings.java | 22 +-
.../transport/http/HttpClientConfigurer.java | 95 +-
.../transport/http/HttpConnectorFactory.java | 17 +-
.../resource/transport/http/HttpProxySettings.java | 5 +-
.../http/HttpResourcesPluginServiceRegistry.java | 16 +
.../resource/transport/http/HttpSettings.java | 8 +-
.../http/RepeatableInputStreamEntity.java | 7 +-
.../transport/http/ntlm/NTLMCredentials.java | 2 +-
.../transport/http/HttpClientConfigurerTest.groovy | 14 +-
.../transport/http/HttpClientHelperTest.groovy | 2 +-
.../transport/http/ntlm/NTLMCredentialsTest.groovy | 2 +-
.../s3/ivy/IvyS3RepoResolveIntegrationTest.groovy | 30 +
.../maven/MavenS3RepoErrorsIntegrationTest.groovy | 22 +
.../resource/transport/aws/s3/S3Client.java | 2 +-
.../transport/aws/s3/S3ConnectorFactory.java | 16 +-
.../aws/s3/S3ResourcesPluginServiceRegistry.java | 3 +
.../ivy/IvySftpRepoErrorsIntegrationTest.groovy | 30 +
.../MavenSftpRepoResolveIntegrationTest.groovy | 31 +
.../resource/transport/sftp/SftpClientFactory.java | 2 +-
.../transport/sftp/SftpConnectorFactory.java | 12 +-
.../internal/resource/transport/sftp/SftpHost.java | 2 +-
.../resource/transport/sftp/SftpResource.java | 2 +-
.../transport/sftp/SftpResourceAccessor.java | 2 +-
.../transport/sftp/SftpResourceLister.java | 2 +-
.../transport/sftp/SftpResourceUploader.java | 2 +-
.../sftp/SftpResourcesPluginServiceRegistry.java | 3 +
.../transport/sftp/SftpClientFactoryTest.groovy | 24 +-
.../org/gradle/authentication/Authentication.java | 29 +
.../org/gradle/authentication/package-info.java | 25 +
.../AuthenticationSchemeRegistry.java | 26 +
.../DefaultAuthenticationSchemeRegistry.java | 37 +
.../internal/resource/PasswordCredentials.java | 41 -
.../connector/ResourceConnectorFactory.java | 3 +
.../connector/ResourceConnectorSpecification.java | 7 +-
subprojects/scala/scala.gradle | 2 +-
.../gradle/integtests/fixtures/ZincCoverage.groovy | 24 +
.../gradle/scala/ScalaPluginIntegrationTest.groovy | 5 +-
...AntInProcessScalaCompilerIntegrationTest.groovy | 9 +-
...ProcessOlderScalaCompilerIntegrationTest.groovy | 2 +-
...ScalaCompilerMultiVersionIntegrationTest.groovy | 80 ++
.../groovy/org/gradle/api/tasks/ScalaRuntime.java | 2 +-
.../org/gradle/api/tasks/scala/package-info.java | 20 -
.../plugins/sonar/SonarSmokeIntegrationTest.groovy | 13 +-
.../org/gradle/sonar/runner/SonarTestServer.groovy | 15 +-
.../testkit/TestKitEndUserIntegrationTest.groovy | 485 ++++++++
.../testkit/TestKitSamplesIntegrationTest.groovy | 53 +
.../AbstractGradleRunnerIntegrationTest.groovy | 91 ++
.../GradleRunnerArgumentsIntegrationTest.groovy | 111 ++
.../GradleRunnerBuildFailureIntegrationTest.groovy | 165 +++
...radleRunnerIsolatedDaemonIntegrationTest.groovy | 184 +++
...leRunnerMechanicalFailureIntegrationTest.groovy | 141 +++
.../GradleRunnerResultIntegrationTest.groovy | 114 ++
.../runner/GradleRunnerSmokeIntegrationTest.groovy | 113 ++
.../org/gradle/testkit/runner/BuildResult.java | 103 ++
.../java/org/gradle/testkit/runner/BuildTask.java | 46 +
.../org/gradle/testkit/runner/GradleRunner.java | 183 +++
.../InvalidRunnerConfigurationException.java | 37 +
.../org/gradle/testkit/runner/TaskOutcome.java | 48 +
.../testkit/runner/UnexpectedBuildFailure.java | 32 +
.../testkit/runner/UnexpectedBuildSuccess.java | 32 +
.../internal/ConstantTestKitDirProvider.java | 32 +
.../runner/internal/DefaultBuildResult.java | 80 ++
.../testkit/runner/internal/DefaultBuildTask.java | 38 +
.../runner/internal/DefaultGradleRunner.java | 200 +++
.../runner/internal/GradleExecutionResult.java | 60 +
.../testkit/runner/internal/GradleExecutor.java | 24 +
.../runner/internal/TempTestKitDirProvider.java | 33 +
.../runner/internal/TestKitDirProvider.java | 23 +
.../runner/internal/TestKitGradleExecutor.java | 151 +++
.../org/gradle/testkit/runner/package-info.java | 22 +
.../runner/internal/DefaultBuildResultTest.groovy | 61 +
.../runner/internal/DefaultGradleRunnerTest.groovy | 246 ++++
.../internal/TempTestKitDirProviderTest.groovy | 46 +
subprojects/test-kit/test-kit.gradle | 7 +
.../test/cunit/CUnitIntegrationTest.groovy | 52 +-
.../googletest/GoogleTestIntegrationTest.groovy | 3 +-
.../test/cunit/plugins/CUnitPlugin.java | 4 +-
.../internal/DefaultGoogleTestTestSuiteSpec.java | 1 -
.../test/googletest/plugins/GoogleTestPlugin.java | 8 +-
.../nativeplatform/test/cunit/CUnitTest.groovy | 2 +-
.../test/googletest/GoogleTestTest.groovy | 2 +-
.../runner/BuildClientSubscriptionsSetup.java | 39 -
.../provider/runner/BuildModelActionRunner.java | 4 -
.../runner/ClientForwardingBuildListener.java | 4 +-
.../runner/ClientForwardingTestListener.java | 35 +-
.../runner/ClientProvidedBuildActionRunner.java | 4 -
.../runner/SubscribableBuildActionRunner.java | 60 +
.../TestExecutionBuildConfigurationAction.java | 121 ++
.../runner/TestExecutionRequestActionRunner.java | 71 ++
.../runner/TestExecutionResultEvaluator.java | 154 +++
.../provider/runner/ToolingBuilderServices.java | 19 +-
...estExecutionBuildConfigurationActionTest.groovy | 131 ++
.../TestExecutionRequestActionRunnerTest.groovy | 35 +
.../runner/TestExecutionResultEvaluatorTest.groovy | 105 ++
.../integtests/tooling/TestLauncherSpec.groovy | 259 ++++
...lingApiUnsupportedVersionIntegrationTest.groovy | 22 +-
.../ContinuousBuildToolingApiSpecification.groovy | 22 +-
.../tooling/fixture/GradleBuildCancellation.groovy | 56 +
.../tooling/fixture/ProgressEvents.groovy | 233 ++++
.../integtests/tooling/fixture/TextUtil.java | 23 +
.../integtests/tooling/fixture/ToolingApi.groovy | 23 +-
.../ToolingApiCompatibilitySuiteRunner.groovy | 1 +
.../ToolingApiEclipseModelCrossVersionSpec.groovy | 37 +-
.../m3/ToolingApiLoggingCrossVersionSpec.groovy | 1 -
.../m8/JavaConfigurabilityCrossVersionSpec.groovy | 4 +-
.../m8/ToolingApiLoggingCrossVersionSpec.groovy | 1 -
...adlePropertiesToolingApiCrossVersionSpec.groovy | 10 +-
.../M9JavaConfigurabilityCrossVersionSpec.groovy | 50 +-
...singCommandLineArgumentsCrossVersionSpec.groovy | 24 +-
.../ToolingApiDeprecationsCrossVersionSpec.groovy | 101 --
...ingApiUnsupportedVersionCrossVersionSpec.groovy | 121 ++
.../r112/UserHomeDirCrossVersionSpec.groovy | 4 +
.../ProjectOutcomesModuleCrossVersionSpec.groovy | 4 +-
...pportedOperationFeedbackCrossVersionSpec.groovy | 2 +-
...ApiConfigurationOnDemandCrossVersionSpec.groovy | 4 +-
.../tooling/r18/BuildActionCrossVersionSpec.groovy | 4 +-
.../r18/BuildScriptModelCrossVersionSpec.groovy | 2 +
...ngApiUnsupportedBuildJvmCrossVersionSpec.groovy | 19 +-
.../tooling/r22/BuildActionCrossVersionSpec.groovy | 4 +-
.../r22/ClientShutdownCrossVersionSpec.groovy | 6 +-
.../r23/StandardStreamsCrossVersionSpec.groovy | 18 +-
.../r24/TestProgressCrossVersionSpec.groovy | 3 +
.../r25/BuildProgressCrossVersionSpec.groovy | 316 +----
...nuousBuildProgressEventsCrossVersionSpec.groovy | 11 +-
...usUnsupportedJavaVersionCrossVersionSpec.groovy | 2 +
...entHandleContinuousBuildCrossVersionSpec.groovy | 134 ++
.../tooling/r25/ProgressCrossVersionSpec.groovy | 120 +-
.../r25/TaskProgressCrossVersionSpec.groovy | 440 +------
.../r25/TestProgressCrossVersionSpec.groovy | 538 +++-----
.../r26/BuildProgressCrossVersionSpec.groovy | 85 ++
.../r26/TestLauncherCrossVersionSpec.groovy | 482 ++++++++
.../r27/TestLauncherCrossVersionSpec.groovy | 204 ++++
...piEclipseLinkedResourcesCrossVersionSpec.groovy | 98 ++
.../org/gradle/tooling/BuildActionExecuter.java | 104 +-
.../java/org/gradle/tooling/BuildLauncher.java | 94 +-
.../org/gradle/tooling/ConfigurableLauncher.java | 136 +++
.../org/gradle/tooling/LongRunningOperation.java | 85 +-
.../main/java/org/gradle/tooling/ModelBuilder.java | 100 +-
.../java/org/gradle/tooling/ProjectConnection.java | 18 +
.../org/gradle/tooling/TestExecutionException.java | 36 +
.../main/java/org/gradle/tooling/TestLauncher.java | 114 ++
.../gradle/tooling/events/OperationDescriptor.java | 2 +
.../gradle/tooling/events/ProgressListener.java | 2 +-
.../internal/DefaultOperationDescriptor.java | 15 +-
.../internal/OperationDescriptorWrapper.java | 23 +
.../internal/DefaultTaskOperationDescriptor.java | 5 +-
.../DefaultJvmTestOperationDescriptor.java | 6 +-
.../internal/DefaultTestOperationDescriptor.java | 6 +-
.../consumer/AbstractLongRunningOperation.java | 34 +-
.../internal/consumer/ConnectionFactory.java | 4 +-
.../consumer/DefaultBuildActionExecuter.java | 2 +-
.../internal/consumer/DefaultBuildLauncher.java | 5 +-
.../internal/consumer/DefaultGradleConnector.java | 2 -
.../consumer/DefaultInternalJvmTestRequest.java | 62 +
.../internal/consumer/DefaultModelBuilder.java | 12 +-
.../consumer/DefaultProjectConnection.java | 5 +
.../internal/consumer/DefaultTestLauncher.java | 137 +++
.../internal/consumer/ResultHandlerAdapter.java | 4 +
.../internal/consumer/TestExecutionRequest.java | 63 +
.../connection/AbstractConsumerConnection.java | 6 +
.../BuildActionRunnerBackedConsumerConnection.java | 2 +-
...ConnectionVersion4BackedConsumerConnection.java | 69 --
.../consumer/connection/ConsumerConnection.java | 5 +-
...InternalConnectionBackedConsumerConnection.java | 27 +-
.../ModelBuilderBackedConsumerConnection.java | 2 +-
.../connection/NoToolingApiConnection.java | 11 +-
.../NonCancellableConsumerConnectionAdapter.java | 5 +
.../RethrowingErrorsConsumerActionExecutor.java | 42 +
.../TestExecutionConsumerConnection.java | 41 +
.../connection/UnsupportedActionRunner.java | 9 +-
.../UnsupportedOlderVersionConnection.java | 75 ++
.../loader/DefaultToolingImplementationLoader.java | 7 +-
.../parameters/BuildProgressListenerAdapter.java | 8 +-
.../parameters/ConsumerOperationParameters.java | 41 +-
.../internal/protocol/ConnectionVersion4.java | 3 +-
.../protocol/test/InternalJvmTestRequest.java | 31 +
.../test/InternalTestExecutionConnection.java | 36 +
.../test/InternalTestExecutionException.java | 30 +
.../test/InternalTestExecutionRequest.java | 34 +
.../gradle/tooling/model/internal/Exceptions.java | 17 +-
.../AbstractLongRunningOperationTest.groovy | 105 ++
.../consumer/DefaultTestLauncherTest.groovy | 93 ++
.../consumer/DistributionFactoryTest.groovy | 4 +
...ActionRunnerBackedConsumerConnectionTest.groovy | 3 +-
...tionVersion4BackedConsumerConnectionTest.groovy | 60 -
...alConnectionBackedConsumerConnectionTest.groovy | 19 +-
...ModelBuilderBackedConsumerConnectionTest.groovy | 3 +-
.../TestExecutionConsumerConnectionTest.groovy | 55 +
.../UnsupportedOlderVersionConnectionTest.groovy | 60 +
.../DefaultToolingImplementationLoaderTest.groovy | 2 +-
.../ConsumerOperationParametersTest.groovy | 48 +-
subprojects/tooling-api/tooling-api.gradle | 7 +
.../integtests/LiveOutputIntegrationTest.groovy | 2 +-
.../ModelTasksGradleUIIntegrationTest.groovy | 2 +-
...projectProjectAndTaskListIntegrationTest.groovy | 2 +-
.../org/gradle/integtests/OpenApiUiTest.groovy | 4 +-
.../org/gradle/integtests/OutputUILordTest.groovy | 4 +
.../gradleplugin/foundation/GradlePluginLord.java | 4 +-
.../WrapperChecksumVerificationTest.groovy | 90 ++
.../WrapperConcurrentDownloadTest.groovy | 2 +
.../WrapperCrossVersionIntegrationTest.groovy | 60 +-
.../WrapperGenerationIntegrationTest.groovy | 2 +-
.../integtests/WrapperHttpIntegrationTest.groovy | 2 +
.../WrapperLoggingIntegrationTest.groovy | 2 +
.../WrapperProjectIntegrationTest.groovy | 2 +
.../WrapperUserHomeIntegrationTest.groovy | 2 +
.../src/main/java/org/gradle/wrapper/Install.java | 63 +-
.../org/gradle/wrapper/WrapperConfiguration.java | 9 +
.../java/org/gradle/wrapper/WrapperExecutor.java | 16 +-
.../groovy/org/gradle/wrapper/InstallTest.groovy | 3 +
.../org/gradle/wrapper/WrapperExecutorTest.groovy | 6 +-
.../org/gradle/wrapper/wrapper.properties | 1 +
version.txt | 2 +-
1734 files changed, 53095 insertions(+), 20297 deletions(-)
diff --git a/build.gradle b/build.gradle
index 5ef32b2..db03d6a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -41,16 +41,16 @@ buildTypes {
quickTest "runtimeTests", "runtimeIntegTests", "performance:test"
// Used for builds to run all tests, but not necessarily on all platforms
- fullTest "runtimeTests", "runtimeIntegTests", useIncomingDistributions: true, defaultIntegTestExecuter: "forking", testAllVersions: true
+ fullTest "runtimeTests", "runtimeForkingIntegTests", useIncomingDistributions: true, testAllVersions: true
// Used for builds to test the code on certain platforms
- platformTest "runtimeTests", "runtimeIntegTests", "performance:test", useIncomingDistributions: true, defaultIntegTestExecuter: "forking", testAllVersions: true, testAllPlatforms: true
+ platformTest "runtimeTests", "runtimeForkingIntegTests", "performance:test", useIncomingDistributions: true, testAllVersions: true, testAllPlatforms: true
// Tests using the daemon mode
- daemonTest "runtimeIntegTests", useIncomingDistributions: true, defaultIntegTestExecuter: "daemon"
+ daemonTest "runtimeDaemonIntegTests", useIncomingDistributions: true
// Run the integration tests using the parallel executer
- parallelTest "runtimeIntegTests", useIncomingDistributions: true, defaultIntegTestExecuter: "parallel"
+ parallelTest "runtimeParallelIntegTests", useIncomingDistributions: true
// Run the performance tests
performanceTest "performance:performanceTest", useIncomingDistributions: true
@@ -104,13 +104,13 @@ ext {
project(it)
}
publishedProjects = [
- project(':core'),
- project(':toolingApi'),
- project(':wrapper'),
- project(':baseServices'),
- project(':baseServicesGroovy'),
- project(':messaging'),
- project(':resources')
+ project(':core'),
+ project(':toolingApi'),
+ project(':wrapper'),
+ project(':baseServices'),
+ project(':baseServicesGroovy'),
+ project(':messaging'),
+ project(':resources')
]
}
@@ -181,12 +181,13 @@ dependencies {
sonar libraries.logback_classic
gradlePlugins pluginProjects
gradlePlugins project(':dependencyManagement')
+ gradlePlugins project(':testKit')
}
task verifyIsProductionBuildEnvironment << {
- assert javaVersion.java7 : "Must use a Java 7 compatible JVM to perform this build. Current JVM is ${jvm}"
+ assert javaVersion.java7: "Must use a Java 7 compatible JVM to perform this build. Current JVM is ${jvm}"
def systemCharset = java.nio.charset.Charset.defaultCharset().name()
- assert systemCharset == "UTF-8" : "Platform encoding must be UTF-8. Is currently $systemCharset. Set -Dfile.encoding=UTF-8."
+ assert systemCharset == "UTF-8": "Platform encoding must be UTF-8. Is currently $systemCharset. Set -Dfile.encoding=UTF-8."
}
task waitForDaemonsToDie {
@@ -220,3 +221,4 @@ task installAll(type: Install) {
apply from: "gradle/intTestImage.gradle"
+apply from: 'gradle/pullRequestBuild.gradle'
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDescriptionRenderer.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDescriptionRenderer.java
index 6870357..bed326e 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDescriptionRenderer.java
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDescriptionRenderer.java
@@ -32,6 +32,24 @@ public class ClassDescriptionRenderer {
parent.appendChild(title);
title.appendChild(document.createTextNode(classDoc.getSimpleName()));
+ addApiDocumentationLink(classDoc, parent, document);
+ addSubtypeLinks(classDoc, parent, document);
+
+ warningsRenderer.renderTo(classDoc, "class", parent);
+
+ for (Element element : classDoc.getComment()) {
+ parent.appendChild(document.importNode(element, true));
+ }
+ NodeList otherContent = classDoc.getClassSection().getChildNodes();
+ for (int i = 0; i < otherContent.getLength(); i++) {
+ Node child = otherContent.item(i);
+ if (child instanceof Element && !((Element) child).getTagName().equals("section")) {
+ parent.appendChild(document.importNode(child, true));
+ }
+ }
+ }
+
+ private void addApiDocumentationLink(ClassDoc classDoc, Element parent, Document document) {
Element list = document.createElement("segmentedlist");
parent.appendChild(list);
Element segtitle = document.createElement("segtitle");
@@ -45,18 +63,37 @@ public class ClassDescriptionRenderer {
seg.appendChild(apilink);
apilink.setAttribute("class", classDoc.getName());
apilink.setAttribute("style", classDoc.getStyle());
+ }
- warningsRenderer.renderTo(classDoc, "class", parent);
+ private void addSubtypeLinks(ClassDoc classDoc, Element parent, Document document) {
+ if (!classDoc.getSubClasses().isEmpty()) {
+ Element list = document.createElement("segmentedlist");
+ parent.appendChild(list);
+ Element segtitle = document.createElement("segtitle");
+ list.appendChild(segtitle);
+ segtitle.appendChild(document.createTextNode("Known Subtypes"));
+ Element listItem = document.createElement("seglistitem");
+ list.appendChild(listItem);
+ Element seg = document.createElement("seg");
+ listItem.appendChild(seg);
+ Element simplelist = document.createElement("simplelist");
- for (Element element : classDoc.getComment()) {
- parent.appendChild(document.importNode(element, true));
- }
- NodeList otherContent = classDoc.getClassSection().getChildNodes();
- for (int i = 0; i < otherContent.getLength(); i++) {
- Node child = otherContent.item(i);
- if (child instanceof Element && !((Element) child).getTagName().equals("section")) {
- parent.appendChild(document.importNode(child, true));
+ int columns = 3;
+ if (classDoc.getSubClasses().size() <= 3) {
+ // if there are only 3 or fewer known subtypes, render them
+ // in a single column
+ columns = 1;
+ }
+ simplelist.setAttribute("columns", String.valueOf(columns));
+ simplelist.setAttribute("type", "vert");
+ for (ClassDoc subClass : classDoc.getSubClasses()) {
+ Element member = document.createElement("member");
+ Element apilink = document.createElement("apilink");
+ apilink.setAttribute("class", subClass.getName());
+ member.appendChild(apilink);
+ simplelist.appendChild(member);
}
+ seg.appendChild(simplelist);
}
}
}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDocSuperTypeBuilder.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDocSuperTypeBuilder.java
index 3bdb457..a23f4d0 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDocSuperTypeBuilder.java
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDocSuperTypeBuilder.java
@@ -40,6 +40,7 @@ public class ClassDocSuperTypeBuilder {
// Assume this is a class and so has implemented all properties and methods somewhere in the superclass hierarchy
ClassDoc superClass = model.getClassDoc(superClassName);
classDoc.setSuperClass(superClass);
+ superClass.addSubClass(classDoc);
}
List<String> interfaceNames = classMetaData.getInterfaceNames();
@@ -47,6 +48,7 @@ public class ClassDocSuperTypeBuilder {
ClassDoc superInterface = model.findClassDoc(interfaceName);
if (superInterface != null) {
classDoc.getInterfaces().add(superInterface);
+ superInterface.addSubClass(classDoc);
}
}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/model/ClassDoc.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/model/ClassDoc.groovy
index c2b8cf0..dfefd23 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/model/ClassDoc.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/model/ClassDoc.groovy
@@ -37,6 +37,7 @@ class ClassDoc implements DslElementDoc {
private final Element methodsSection
ClassDoc superClass
List<ClassDoc> interfaces = []
+ List<ClassDoc> subClasses = []
List<Element> comment = []
ClassDoc(String className, Element classContent, Document targetDocument, ClassMetaData classMetaData, ClassExtensionMetaData extensionMetaData) {
@@ -118,6 +119,12 @@ class ClassDoc implements DslElementDoc {
def getBlockDetailsSection() { return getSection('Script block details') }
+ List<ClassDoc> getSubClasses() {
+ return subClasses
+ }
+ void addSubClass(ClassDoc subClass) {
+ subClasses.add(subClass)
+ }
ClassDoc mergeContent() {
classProperties.sort { it.name }
classMethods.sort { it.metaData.overrideSignature }
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
index f4d0881..ad1b3a7 100644
--- a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
@@ -14,18 +14,12 @@
* limitations under the License.
*/
package org.gradle.build.docs.dsl.docbook
-
import org.gradle.build.docs.XmlSpecification
-import org.gradle.build.docs.dsl.source.model.PropertyMetaData
-import org.gradle.build.docs.dsl.source.model.TypeMetaData
+import org.gradle.build.docs.dsl.docbook.model.*
import org.gradle.build.docs.dsl.source.model.MethodMetaData
import org.gradle.build.docs.dsl.source.model.ParameterMetaData
-import org.gradle.build.docs.dsl.docbook.model.BlockDoc
-import org.gradle.build.docs.dsl.docbook.model.ExtraAttributeDoc
-import org.gradle.build.docs.dsl.docbook.model.MethodDoc
-import org.gradle.build.docs.dsl.docbook.model.PropertyDoc
-import org.gradle.build.docs.dsl.docbook.model.ClassDoc
-import org.gradle.build.docs.dsl.docbook.model.ClassExtensionDoc
+import org.gradle.build.docs.dsl.source.model.PropertyMetaData
+import org.gradle.build.docs.dsl.source.model.TypeMetaData
class ClassDocRendererTest extends XmlSpecification {
final LinkRenderer linkRenderer = linkRenderer()
@@ -43,6 +37,61 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> []
_ * classDoc.classBlocks >> []
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
+
+ when:
+ def result = parse('<root/>')
+ withCategories {
+ renderer.mergeContent(classDoc, result)
+ }
+
+ then:
+ formatTree(result) == '''<root>
+ <chapter id="classId">
+ <title>Class</title>
+ <segmentedlist>
+ <segtitle>API Documentation</segtitle>
+ <seglistitem>
+ <seg>
+ <apilink class="org.gradle.Class" style="java"/>
+ </seg>
+ </seglistitem>
+ </segmentedlist>
+ <para>class comment</para>
+ <section>
+ <title>Properties</title>
+ <para>No properties</para>
+ </section>
+ <section>
+ <title>Methods</title>
+ <para>No methods</para>
+ </section>
+ <section>
+ <title>Script blocks</title>
+ <para>No script blocks</para>
+ </section>
+ </chapter>
+</root>'''
+ }
+
+ def rendersKnownSubtypes() {
+ def sourceContent = parse('''
+ <chapter>
+ <section><title>Properties</title></section>
+ </chapter>
+ ''')
+
+ ClassDoc classDoc = classDoc('org.gradle.Class', id: 'classId', content: sourceContent, comment: 'class comment')
+ _ * classDoc.classProperties >> []
+ _ * classDoc.classMethods >> []
+ _ * classDoc.classBlocks >> []
+ _ * classDoc.classExtensions >> []
+ def subtypes = [ "org.gradle.Subtype1", "org.gradle.Subtype2", "org.gradle.Subtype3", "org.gradle.Subtype4" ].collect {
+ ClassDoc subtype = Mock()
+ _ * subtype.name >> it
+ subtype
+ }
+ _ * classDoc.subClasses >> subtypes
when:
def result = parse('<root/>')
@@ -62,6 +111,27 @@ class ClassDocRendererTest extends XmlSpecification {
</seg>
</seglistitem>
</segmentedlist>
+ <segmentedlist>
+ <segtitle>Known Subtypes</segtitle>
+ <seglistitem>
+ <seg>
+ <simplelist columns="3" type="vert">
+ <member>
+ <apilink class="org.gradle.Subtype1"/>
+ </member>
+ <member>
+ <apilink class="org.gradle.Subtype2"/>
+ </member>
+ <member>
+ <apilink class="org.gradle.Subtype3"/>
+ </member>
+ <member>
+ <apilink class="org.gradle.Subtype4"/>
+ </member>
+ </simplelist>
+ </seg>
+ </seglistitem>
+ </segmentedlist>
<para>class comment</para>
<section>
<title>Properties</title>
@@ -91,6 +161,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> []
_ * classDoc.classBlocks >> []
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
when:
def result = parse('<root/>')
@@ -127,7 +198,7 @@ class ClassDocRendererTest extends XmlSpecification {
</chapter>
</root>'''
}
-
+
def mergesPropertyMetaDataIntoPropertiesSection() {
def content = parse('''
<chapter>
@@ -147,6 +218,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> []
_ * classDoc.classBlocks >> []
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
when:
def result = parse('<chapter/>', document)
@@ -222,6 +294,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> []
_ * classDoc.classBlocks >> []
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
when:
def result = parse('<chapter/>', document)
@@ -311,6 +384,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * targetClassDoc.classMethods >> []
_ * targetClassDoc.classBlocks >> []
_ * targetClassDoc.classExtensions >> [extensionDoc]
+ _ * targetClassDoc.subClasses >> []
_ * extensionDoc.extensionProperties >> [propertyDoc]
_ * extensionDoc.extensionMethods >> []
_ * extensionDoc.extensionBlocks >> []
@@ -386,6 +460,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> [method1, method2]
_ * classDoc.classBlocks >> []
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
when:
def result = parse('<chapter/>', document)
@@ -465,6 +540,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> [method1, method2]
_ * classDoc.classBlocks >> []
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
when:
def result = parse('<chapter/>', document)
@@ -551,6 +627,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * targetClassDoc.classMethods >> []
_ * targetClassDoc.classBlocks >> []
_ * targetClassDoc.classExtensions >> [extensionDoc]
+ _ * targetClassDoc.subClasses >> []
_ * extensionDoc.extensionProperties >> []
_ * extensionDoc.extensionMethods >> [methodDoc]
_ * extensionDoc.extensionBlocks >> []
@@ -632,6 +709,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> [method1]
_ * classDoc.classBlocks >> [block1]
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
when:
def result = parse('<chapter/>', document)
@@ -751,6 +829,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * classDoc.classMethods >> []
_ * classDoc.classBlocks >> [block1, block2]
_ * classDoc.classExtensions >> []
+ _ * classDoc.subClasses >> []
when:
def result = parse('<chapter/>', document)
@@ -845,6 +924,7 @@ class ClassDocRendererTest extends XmlSpecification {
_ * targetClassDoc.classMethods >> []
_ * targetClassDoc.classBlocks >> []
_ * targetClassDoc.classExtensions >> [extensionDoc]
+ _ * targetClassDoc.subClasses >> []
_ * extensionDoc.extensionProperties >> []
_ * extensionDoc.extensionMethods >> []
_ * extensionDoc.extensionBlocks >> [blockDoc]
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
index e501566..5099e12 100644
--- a/config/checkstyle/suppressions.xml
+++ b/config/checkstyle/suppressions.xml
@@ -17,6 +17,8 @@
<suppress checks="JavadocPackage"
files=".*[/\\]subprojects[/\\]plugins[/\\]src[/\\]main[/\\]groovy[/\\]org[/\\]gradle[/\\]api[/\\]tasks[/\\][^/\\]+"/>
<suppress checks="JavadocPackage"
+ files=".*[/\\]subprojects[/\\]plugins[/\\]src[/\\]main[/\\]groovy[/\\]org[/\\]gradle[/\\]jvm[/\\][^/\\]+"/>
+ <suppress checks="JavadocPackage"
files=".*[/\\]subprojects[/\\]scala[/\\]src[/\\]main[/\\]groovy[/\\]org[/\\]gradle[/\\]api[/\\]tasks[/\\][^/\\]+"/>
<suppress checks="JavadocPackage"
files=".*[/\\]subprojects[/\\]base-services[/\\]src[/\\]main[/\\]java[/\\]org[/\\]gradle[/\\]api[/\\][^/\\]+"/>
@@ -26,6 +28,11 @@
files=".*[/\\]subprojects[/\\]base-services-groovy[/\\]src[/\\]main[/\\]groovy[/\\]org[/\\]gradle[/\\]api[/\\]specs[/\\][^/\\]+"/>
<suppress checks="JavadocPackage"
files=".*[/\\]subprojects[/\\]language-groovy[/\\]src[/\\]main[/\\]java[/\\]org[/\\]gradle[/\\]api[/\\]tasks[/\\]javadoc[/\\][^/\\]+"/>
+ <suppress checks="JavadocPackage"
+ files=".*[/\\]subprojects[/\\]language-groovy[/\\]src[/\\]main[/\\]java[/\\]org[/\\]gradle[/\\]api[/\\]tasks[/\\]compile[/\\][^/\\]+"/>
+ <suppress checks="JavadocPackage"
+ files=".*[/\\]subprojects[/\\]language-java[/\\]src[/\\]main[/\\]java[/\\]org[/\\]gradle[/\\]api[/\\]tasks[/\\]compile[/\\][^/\\]+"/>
+
<!-- Don't require api docs for projects only used internally -->
<suppress checks="Javadoc.*"
files=".*[/\\]subprojects[/\\]internal-.+[/\\]src[/\\]main[/\\].+"/>
diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle
index f1b6ec4..b40fbfb 100755
--- a/gradle/dependencies.gradle
+++ b/gradle/dependencies.gradle
@@ -160,7 +160,7 @@ libraries.bouncycastle_pgp = dependencies.module("org.bouncycastle:bcpg-jdk15on:
dependency libraries.bouncycastle_provider
}
-libraries.joda = 'joda-time:joda-time:2.7 at jar'
+libraries.joda = 'joda-time:joda-time:2.8.2 at jar'
libraries.awsS3 = [
'com.amazonaws:aws-java-sdk-s3:1.9.19 at jar',
diff --git a/gradle/groovyProject.gradle b/gradle/groovyProject.gradle
index 05991c9..2762e16 100644
--- a/gradle/groovyProject.gradle
+++ b/gradle/groovyProject.gradle
@@ -44,8 +44,9 @@ if (!javaVersion.java7Compatible) {
testTasks.all { task ->
if (isCiServer) {
maxParallelForks = rootProject.maxParallelForks
- }
- if (isCiServer) {
+ systemProperties['org.gradle.test.maxParallelForks'] = maxParallelForks
+ systemProperties['org.gradle.ci.agentCount'] = 2
+ systemProperties['org.gradle.ci.agentNum'] = System.getenv('AGENT_NUMBER')?:1
doFirst {
println "maxParallelForks for '$task.path' is $task.maxParallelForks"
}
@@ -121,3 +122,7 @@ if (buildTypes.isActive("pullRequestValidation")) {
}
}
}
+
+task compileAll {
+ dependsOn tasks.matching { it instanceof JavaCompile || it instanceof GroovyCompile }
+}
diff --git a/gradle/idea.gradle b/gradle/idea.gradle
index 9ac80dd..7c33b96 100644
--- a/gradle/idea.gradle
+++ b/gradle/idea.gradle
@@ -132,7 +132,6 @@ idea {
<option name="FOR_BRACE_FORCE" value="3" />
<codeStyleSettings language="JAVA">
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
- <option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
diff --git a/gradle/integTest.gradle b/gradle/integTest.gradle
index 6a0a25c..a9caca9 100644
--- a/gradle/integTest.gradle
+++ b/gradle/integTest.gradle
@@ -117,7 +117,7 @@ def forEachJavaProcess(Closure action) {
def pidPattern
if (org.gradle.internal.os.OperatingSystem.current().windows) {
exec {
- commandLine('wmic', 'process' ,'get', 'processid,commandline')
+ commandLine('wmic', 'process', 'get', 'processid,commandline')
standardOutput = output
}
pidPattern = /([0-9]+)\s*$/
@@ -131,7 +131,7 @@ def forEachJavaProcess(Closure action) {
output.toString().readLines().each { String line ->
def processMatcher = line =~ queryString
if (processMatcher.find()) {
- def pidMatcher = line =~pidPattern
+ def pidMatcher = line =~ pidPattern
if (pidMatcher.find()) {
def pid = pidMatcher.group(1)
def process = processMatcher.group(1)
@@ -177,7 +177,7 @@ project(":") {
}
task cleanUpDaemons {
- ext.suspiciousDaemons = [:].withDefault {[].asSynchronized()}.asSynchronized()
+ ext.suspiciousDaemons = [:].withDefault { [].asSynchronized() }.asSynchronized()
ext.daemonPids = ([] as Set).asSynchronized()
doLast {
Set alreadyKilled = []
@@ -200,8 +200,8 @@ allprojects {
}
integTestTasks.all { Test task ->
- dependsOn ':intTestImage', ':cleanUpCaches'
- finalizedBy ':cleanUpDaemons'
+ dependsOn ':intTestImage'
+ finalizedBy(':cleanUpDaemons', ':cleanUpCaches')
shouldRunAfter 'test'
testClassesDir = sourceSets.integTest.output.classesDir
@@ -214,9 +214,9 @@ integTestTasks.all { Test task ->
// use -PtestVersions=all or -PtestVersions=1.2,1.3…
systemProperties['org.gradle.integtest.versions'] = project.hasProperty('testVersions') ? project.testVersions : 'latest'
- systemProperties['org.gradle.integtest.cpp.toolChains'] = project.hasProperty("testAllPlatforms") ? 'all' : 'default'
+ systemProperties['org.gradle.integtest.cpp.toolChains'] = project.hasProperty("testAllPlatforms") && project.testAllPlatforms ? 'all' : 'default'
- systemProperties['org.gradle.integtest.multiversion'] = project.hasProperty("multiVersion") ? 'all' : 'default'
+ systemProperties['org.gradle.integtest.multiversion'] = project.hasProperty("testAllVersions") && project.testAllVersions ? 'all' : 'default'
dependsOn project.task("configure${task.name.capitalize()}") << {
configure(task) {
@@ -241,8 +241,8 @@ integTestTasks.all { Test task ->
def daemonPids = rootProject.cleanUpDaemons.daemonPids
def suspiciousDaemons = rootProject.cleanUpDaemons.suspiciousDaemons
daemonListener = [
- beforeTest : {test -> },
- afterTest : { test, result ->},
+ beforeTest : { test -> },
+ afterTest : { test, result -> },
beforeSuite: { suite ->
forEachJavaProcess { pid, process ->
// processes that exist before the test suite execution should
@@ -273,6 +273,9 @@ task integTest(type: Test) {
systemProperties['org.gradle.integtest.debug'] = 'true'
testLogging.showStandardStreams = true
}
+ if (project.hasProperty('org.gradle.integtest.verbose')) {
+ testLogging.showStandardStreams = true
+ }
}
check.dependsOn(integTest)
diff --git a/gradle/java9.gradle b/gradle/java9.gradle
index 41ee991..8b98fb5 100644
--- a/gradle/java9.gradle
+++ b/gradle/java9.gradle
@@ -5,12 +5,16 @@ String jdkVarName = 'JAVA_9'
task java9IntegTest(type: Test) {
include '**/*CompilerIntegrationTest*'
+ include '**/*Daemon*Test.*'
+ include '**/*Daemon*Spec.*'
excludes = [
'InProcessGroovyCompilerIntegrationTest',
'InProcessJavaCompilerIntegrationTest',
'AntForkingScalaCompilerIntegrationTest',
'AntInProcessScalaCompilerIntegrationTest',
- 'ZincScalaCompilerIntegrationTest'
+ 'ZincScalaCompilerIntegrationTest',
+ 'DaemonUsageSuggestionCrossVersionTest',
+ 'TestProgressDaemonErrorsCrossVersionSpec'
].collect { "**/*${it}*" }
}
diff --git a/gradle/pullRequestBuild.gradle b/gradle/pullRequestBuild.gradle
new file mode 100644
index 0000000..279d6ac
--- /dev/null
+++ b/gradle/pullRequestBuild.gradle
@@ -0,0 +1,76 @@
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import java.util.concurrent.ThreadFactory
+
+ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ @Override
+ Thread newThread(Runnable runnable) {
+ Thread thread = Executors.defaultThreadFactory().newThread(runnable)
+ thread.setDaemon(true)
+ return thread
+ }
+})
+
+task startHeartBeat << {
+ logger.lifecycle("Starting heartbeat.")
+ executor.execute(new Heartbeat(logger));
+}
+
+task stopHeartBeat << {
+ logger.lifecycle("Shutting down heartbeat.")
+ executor.shutdownNow();
+}
+
+class Heartbeat implements Runnable {
+ int frequency = 8 * 60 * 1000
+ def logger
+
+ public Heartbeat(logger) {
+ this.logger = logger
+ }
+
+ @Override
+ public void run() {
+ boolean beating = true
+ while (beating) {
+ logger.lifecycle(" [heartbeat] ")
+ try {
+ Thread.sleep(frequency)
+ } catch (InterruptedException e) {
+ beating = false
+ logger.lifecycle("Heartbeat thread Interrupted")
+ }
+ }
+ }
+}
+
+def matrixSize = 4
+def splits = (1..matrixSize).collect { [] }
+project.subprojects.asList().eachWithIndex { project, i ->
+ splits[(i % matrixSize)] << project
+}
+
+splits.eachWithIndex { List<Project> bucket, int i ->
+ def index = i + 1
+ def testTask = project.tasks.create("testSplit${index}", {
+ ext.projectNames = bucket.collect { it.name }
+ })
+
+ bucket.each { Project project ->
+ def checkTask = project.tasks.getByName('check')
+ if (checkTask) {
+ testTask.dependsOn(checkTask)
+ }
+ }
+ project.getExtensions().buildTypes."prBuild${index}"("startHeartBeat", testTask.name, "stopHeartBeat")
+}
+
+gradle.taskGraph.whenReady { graph ->
+ def task = graph.getAllTasks()?.find { it.name.contains('testSplit') }
+ if (task) {
+ logger.quiet("============================================")
+ logger.quiet("${task.name} configured to test the following projects: ")
+ task.projectNames.each { logger.quiet("${it}") }
+ logger.quiet("============================================")
+ }
+}
diff --git a/gradle/testGroupings.gradle b/gradle/testGroupings.gradle
index 52945e1..5d74562 100644
--- a/gradle/testGroupings.gradle
+++ b/gradle/testGroupings.gradle
@@ -4,10 +4,23 @@ def runtimeProjects = subprojects - [':docs', ':distributions', ':performance'].
def runtimeProjectTasks = { String taskName ->
runtimeProjects.collect { it.tasks.findByPath(taskName) }.findAll { it != null }
}
+
task runtimeTests {
dependsOn { runtimeProjectTasks("test") }
}
task runtimeIntegTests {
dependsOn { runtimeProjectTasks("integTest") }
-}
\ No newline at end of file
+}
+
+task runtimeForkingIntegTests {
+ dependsOn { runtimeProjectTasks("forkingIntegTest") }
+}
+
+task runtimeDaemonIntegTests {
+ dependsOn { runtimeProjectTasks("daemonIntegTest") }
+}
+
+task runtimeParallelIntegTests {
+ dependsOn { runtimeProjectTasks("parallelIntegTest") }
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 39fb503..65a5e32 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue May 05 11:22:48 CEST 2015
+#Tue Aug 04 13:22:48 CEST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-2.5-20150528195112+0000-bin.zip
+distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-2.7-20150817015842+0000-bin.zip
diff --git a/settings.gradle b/settings.gradle
index eced905..6497b9a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -71,6 +71,7 @@ include 'modelCore'
include 'modelGroovy'
include 'testingNative'
include 'platformPlay'
+include 'testKit'
rootProject.name = 'gradle'
rootProject.children.each {project ->
diff --git a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/AbstractAntlrIntegrationTest.groovy b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/AbstractAntlrIntegrationTest.groovy
index d528409..dfe1de2 100644
--- a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/AbstractAntlrIntegrationTest.groovy
+++ b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/AbstractAntlrIntegrationTest.groovy
@@ -43,6 +43,7 @@ abstract class AbstractAntlrIntegrationTest extends AbstractIntegrationSpec {
dependencies {
antlr '$antlrDependency'
}
+
"""
}
diff --git a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr2PluginIntegrationTest.groovy b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr2PluginIntegrationTest.groovy
index e9cae24..3bb2d69 100644
--- a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr2PluginIntegrationTest.groovy
+++ b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr2PluginIntegrationTest.groovy
@@ -28,8 +28,9 @@ class Antlr2PluginIntegrationTest extends AbstractAntlrIntegrationTest {
expect:
succeeds("generateGrammarSource")
assertAntlrVersion(2)
- assertGrammarSourceGenerated("TestGrammar")
- assertGrammarSourceGenerated("AnotherGrammar")
+ assertGrammarSourceGenerated("org/acme/TestGrammar")
+ assertGrammarSourceGenerated("org/acme/AnotherGrammar")
+ assertGrammarSourceGenerated("UnpackagedGrammar")
succeeds("build")
}
@@ -66,12 +67,21 @@ Execution failed for task ':generateGrammarSource'.
expect:
succeeds("generateGrammarSource")
assertAntlrVersion(2)
- assertGrammarSourceGenerated("TestGrammar")
+ assertGrammarSourceGenerated("org/acme/TestGrammar")
+ assertGrammarSourceGenerated("org/acme/AnotherGrammar")
+ assertGrammarSourceGenerated("UnpackagedGrammar")
+
succeeds("build")
}
private goodGrammar() {
- file("src/main/antlr/TestGrammar.g") << """class TestGrammar extends Parser;
+ file("src/main/antlr/TestGrammar.g") << """
+ header {
+ package org.acme;
+ }
+
+ class TestGrammar extends Parser;
+
options {
buildAST = true;
}
@@ -86,7 +96,11 @@ Execution failed for task ':generateGrammarSource'.
atom: INT
;"""
- file("src/main/antlr/AnotherGrammar.g") << """class AnotherGrammar extends Parser;
+ file("src/main/antlr/AnotherGrammar.g") << """
+ header {
+ package org.acme;
+ }
+ class AnotherGrammar extends Parser;
options {
buildAST = true;
importVocab = TestGrammar;
@@ -102,6 +116,21 @@ Execution failed for task ':generateGrammarSource'.
atom: INT
;"""
+ file("src/main/antlr/UnpackagedGrammar.g") << """class UnpackagedGrammar extends Parser;
+ options {
+ buildAST = true;
+ }
+
+ expr: mexpr (PLUS^ mexpr)* SEMI!
+ ;
+
+ mexpr
+ : atom (STAR^ atom)*
+ ;
+
+ atom: INT
+ ;"""
+
}
private goodProgram() {
@@ -109,6 +138,7 @@ Execution failed for task ':generateGrammarSource'.
import antlr.Token;
import antlr.TokenStream;
import antlr.TokenStreamException;
+ import org.acme.TestGrammar;
public class Test {
public static void main(String[] args) {
diff --git a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr3PluginIntegrationTest.groovy b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr3PluginIntegrationTest.groovy
index 05ed4b4..2a101bc 100644
--- a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr3PluginIntegrationTest.groovy
+++ b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr3PluginIntegrationTest.groovy
@@ -21,17 +21,45 @@ class Antlr3PluginIntegrationTest extends AbstractAntlrIntegrationTest {
def "analyze good grammar"() {
goodGrammar()
-
+ goodProgram()
expect:
succeeds("generateGrammarSource")
- assertGrammarSourceGenerated("Test")
assertGrammarSourceGenerated("AnotherGrammar")
+ assertGrammarSourceGenerated("org/acme/test/Test")
assertAntlrVersion(3)
+
+ succeeds("build")
+ }
+
+ private goodProgram() {
+ file("src/main/java/com/example/Main.java") << """
+ package com.example;
+ import org.acme.test.TestLexer;
+ import org.acme.test.TestParser;
+ import org.antlr.runtime.CommonTokenStream;
+ import org.antlr.runtime.RecognitionException;
+ import org.antlr.runtime.ANTLRFileStream;
+ import java.io.IOException;
+
+ public class Main {
+ public static void main(String[] args) throws IOException {
+ TestLexer lexer = new TestLexer(new ANTLRFileStream(args[0]));
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ TestParser parser = new TestParser(tokens);
+ try {
+ parser.list();
+ } catch (RecognitionException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ """
}
private void assertGrammarSourceGenerated(String grammarName) {
- assert file("build/generated-src/antlr/main/${grammarName}.tokens").exists()
+ def slashIndex = grammarName.lastIndexOf("/")
+ assert file("build/generated-src/antlr/main/${slashIndex == -1 ? grammarName : grammarName.substring(slashIndex)}.tokens").exists()
assert file("build/generated-src/antlr/main/${grammarName}Lexer.java").exists()
assert file("build/generated-src/antlr/main/${grammarName}Parser.java").exists()
}
@@ -45,11 +73,18 @@ class Antlr3PluginIntegrationTest extends AbstractAntlrIntegrationTest {
}
private goodGrammar() {
- file("src/main/antlr/Test.g") << """grammar Test;
+ file("src/main/antlr/org/acme/test/Test.g") << """grammar Test;
+ @header {
+ package org.acme.test;
+ }
+ @lexer::header {
+ package org.acme.test;
+ }
+
list : item (item)*
;
- item :
+ item :
ID
| INT
;
@@ -83,7 +118,7 @@ class Antlr3PluginIntegrationTest extends AbstractAntlrIntegrationTest {
list : item (item)*
; some extra stuff
- item :
+ item :
ID
| INT
;
diff --git a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr4PluginIntegrationTest.groovy b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr4PluginIntegrationTest.groovy
index 5aa1904..0c811cb 100644
--- a/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr4PluginIntegrationTest.groovy
+++ b/subprojects/antlr/src/integTest/groovy/org/gradle/api/plugins/antlr/Antlr4PluginIntegrationTest.groovy
@@ -21,14 +21,74 @@ class Antlr4PluginIntegrationTest extends AbstractAntlrIntegrationTest {
def "analyze good grammar"() {
goodGrammar()
+ goodProgram()
+ expect:
+ succeeds("generateGrammarSource")
+ assertGrammarSourceGenerated("org/acme/Test")
+ assertGrammarSourceGenerated("Another")
+ assertAntlrVersion(4)
+ succeeds("build")
+ }
+
+ def "can import grammar from root antlr source folder"() {
+ goodGrammar()
+ file("src/main/antlr/GrammarWithImport.g4") << """grammar GrammarWithImport;
+ import Another;
+ r : 'hello' ID ;
+ ID : [a-z]+ ;
+ WS : [ \\t\\r\\n]+ -> skip ;
+ """
expect:
succeeds("generateGrammarSource")
- assertGrammarSourceGenerated("Test")
+ assertGrammarSourceGenerated("org/acme/Test")
+ assertGrammarSourceGenerated("Another")
+ assertGrammarSourceGenerated("GrammarWithImport")
+ assertAntlrVersion(4)
+ }
+
+ def "can import grammar from non root folder using -lib argument"() {
+ goodGrammar()
+ file("src/main/antlr/GrammarWithImport.g4") << """grammar GrammarWithImport;
+ import Test;
+ r : 'hello' ID ;
+ ID : [a-z]+ ;
+ WS : [ \\t\\r\\n]+ -> skip ;
+ """
+ when:
+ buildFile << """
+ generateGrammarSource {
+ arguments << "-lib" << "src/main/antlr/org/acme"
+ }
+ """
+ then:
+ succeeds("generateGrammarSource")
+ assertGrammarSourceGenerated("org/acme/Test")
assertGrammarSourceGenerated("Another")
+ assertGrammarSourceGenerated("GrammarWithImport")
assertAntlrVersion(4)
}
+ void goodProgram() {
+ file("src/main/java/Main.java") << """
+
+ import org.antlr.v4.runtime.ANTLRInputStream;
+ import org.antlr.v4.runtime.CommonTokenStream;
+ import java.io.IOException;
+ import java.io.StringReader;
+ import org.acme.TestLexer;
+ import org.acme.TestParser;
+
+ public class Main {
+ public static void main(String[] args) throws IOException {
+ TestLexer l = new TestLexer(new ANTLRInputStream(new StringReader("test")));
+ TestParser p = new TestParser(new CommonTokenStream(l));
+ }
+ }
+ """
+
+ }
+
private void assertGrammarSourceGenerated(String grammarName) {
assert file("build/generated-src/antlr/main/${grammarName}.tokens").exists()
assert file("build/generated-src/antlr/main/${grammarName}BaseListener.java").exists()
@@ -47,9 +107,12 @@ class Antlr4PluginIntegrationTest extends AbstractAntlrIntegrationTest {
}
private goodGrammar() {
- file("src/main/antlr/Test.g4") << """grammar Test;
- r : 'hello' ID ;
- ID : [a-z]+ ;
+ file("src/main/antlr/org/acme/Test.g4") << """grammar Test;
+ @header {
+ package org.acme;
+ }
+ r : 'hello' ID ;
+ ID : [a-z]+ ;
WS : [ \\t\\r\\n]+ -> skip ;
"""
@@ -63,7 +126,7 @@ class Antlr4PluginIntegrationTest extends AbstractAntlrIntegrationTest {
private badGrammar() {
file("src/main/antlr/Test.g4") << """grammar Test;
r : 'hello' ID ; extrastuff
- ID : [a-z]+ ;
+ ID : [a-z]+ ;
WS : [ \\t\\r\\n]+ -> skip ;
"""
}
diff --git a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrSourceVirtualDirectory.java b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrSourceVirtualDirectory.java
index cd71f72..68919fb 100644
--- a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrSourceVirtualDirectory.java
+++ b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrSourceVirtualDirectory.java
@@ -36,7 +36,7 @@ public interface AntlrSourceVirtualDirectory {
public SourceDirectorySet getAntlr();
/**
- * Configures the Antlr source for this set. The given closure is used to configure the {@code SourceDirectorySet} (see
+ * Configures the Antlr source for this set. The given closure is used to configure the {@link org.gradle.api.file.SourceDirectorySet} (see
* {@link #getAntlr}) which contains the Antlr source.
*
* @param configureClosure The closure to use to configure the Antlr source.
diff --git a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java
index ea372f5..c9a537b 100644
--- a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java
+++ b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java
@@ -18,6 +18,8 @@ package org.gradle.api.plugins.antlr;
import org.gradle.api.Action;
import org.gradle.api.file.FileCollection;
+import org.gradle.api.file.FileTree;
+import org.gradle.api.file.SourceDirectorySet;
import org.gradle.api.plugins.antlr.internal.*;
import org.gradle.api.tasks.*;
import org.gradle.api.tasks.incremental.IncrementalTaskInputs;
@@ -49,6 +51,7 @@ public class AntlrTask extends SourceTask {
private File outputDirectory;
private String maxHeapSize;
+ private SourceDirectorySet sourceDirectorySet;
/**
* Specifies that all rules call {@code traceIn}/{@code traceOut}.
@@ -114,6 +117,7 @@ public class AntlrTask extends SourceTask {
/**
* List of command-line arguments passed to the antlr process
+ *
* @return The antlr command-line arguments
*/
@Input
@@ -170,17 +174,17 @@ public class AntlrTask extends SourceTask {
final Set<File> sourceFiles = getSource().getFiles();
final AtomicBoolean cleanRebuild = new AtomicBoolean();
inputs.outOfDate(
- new Action<InputFileDetails>() {
- public void execute(InputFileDetails details) {
- File input = details.getFile();
- if (sourceFiles.contains(input)) {
- grammarFiles.add(input);
- } else {
- // classpath change?
- cleanRebuild.set(true);
- }
+ new Action<InputFileDetails>() {
+ public void execute(InputFileDetails details) {
+ File input = details.getFile();
+ if (sourceFiles.contains(input)) {
+ grammarFiles.add(input);
+ } else {
+ // classpath change?
+ cleanRebuild.set(true);
}
}
+ }
);
inputs.removed(new Action<InputFileDetails>() {
@Override
@@ -196,7 +200,7 @@ public class AntlrTask extends SourceTask {
}
AntlrWorkerManager manager = new AntlrWorkerManager();
- AntlrSpec spec = new AntlrSpecFactory().create(this, grammarFiles);
+ AntlrSpec spec = new AntlrSpecFactory().create(this, grammarFiles, sourceDirectorySet);
AntlrResult result = manager.runWorker(getProject().getProjectDir(), getWorkerProcessBuilderFactory(), getAntlrClasspath(), spec);
evaluate(result);
}
@@ -207,8 +211,40 @@ public class AntlrTask extends SourceTask {
throw new AntlrSourceGenerationException("There was 1 error during grammar generation", result.getException());
} else if (errorCount > 1) {
throw new AntlrSourceGenerationException("There were "
- + errorCount
- + " errors during grammar generation", result.getException());
+ + errorCount
+ + " errors during grammar generation", result.getException());
+ }
+ }
+
+ /**
+ * Sets the source for this task. Delegates to {@link SourceTask#setSource(Object)}.
+ *
+ * If the source is of type {@link SourceDirectorySet}, then the relative path of each source grammar files
+ * is used to determine the relative output path of the generated source
+ * If the source is not of type {@link SourceDirectorySet}, then the generated source files end up
+ * flattened in the specified output directory.
+ *
+ * @param source The source.
+ */
+ @Override
+ public void setSource(Object source) {
+ super.setSource(source);
+ if (source instanceof SourceDirectorySet) {
+ this.sourceDirectorySet = (SourceDirectorySet) source;
}
}
+
+ /**
+ * Returns the source for this task, after the include and exclude patterns have been applied. Ignores source files which do not exist.
+ *
+ * @return The source.
+ */
+ // This method is here as the Gradle DSL generation can't handle properties with setters and getters in different classes.
+ @InputFiles
+ @SkipWhenEmpty
+ public FileTree getSource() {
+ return super.getSource();
+ }
+
+
}
diff --git a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrExecuter.java b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrExecuter.java
index 3f474a9..ead522c 100644
--- a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrExecuter.java
+++ b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrExecuter.java
@@ -16,12 +16,15 @@
package org.gradle.api.plugins.antlr.internal;
+import com.beust.jcommander.internal.Lists;
import org.gradle.api.GradleException;
import org.gradle.api.plugins.antlr.internal.antlr2.GenerationPlan;
import org.gradle.api.plugins.antlr.internal.antlr2.GenerationPlanBuilder;
import org.gradle.api.plugins.antlr.internal.antlr2.MetadataExtracter;
import org.gradle.api.plugins.antlr.internal.antlr2.XRef;
+import org.gradle.internal.os.OperatingSystem;
import org.gradle.internal.reflect.JavaReflectionUtil;
+import org.gradle.util.GFileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,90 +33,193 @@ import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
-import java.util.Set;
public class AntlrExecuter {
private static final Logger LOGGER = LoggerFactory.getLogger(AntlrExecuter.class);
AntlrResult runAntlr(AntlrSpec spec) throws IOException, InterruptedException {
- String[] commandLine = toArray(spec.asCommandLineWithFiles());
-
- // Try ANTLR 4
- try {
- Object toolObj = loadTool("org.antlr.v4.Tool", commandLine);
+ AntlrTool antlrTool = new Antlr4Tool();
+ if (antlrTool.available()) {
LOGGER.info("Processing with ANTLR 4");
- return processV4(toolObj);
- } catch (ClassNotFoundException e) {
- LOGGER.debug("ANTLR 4 not found on classpath");
+ return antlrTool.process(spec);
}
- // Try ANTLR 3
- try {
- Object toolObj = loadTool("org.antlr.Tool", commandLine);
+ antlrTool = new Antlr3Tool();
+ if (antlrTool.available()) {
LOGGER.info("Processing with ANTLR 3");
- return processV3(toolObj);
- } catch (ClassNotFoundException e) {
- LOGGER.debug("ANTLR 3 not found on classpath");
+ return antlrTool.process(spec);
}
- // Try ANTLR 2
- try {
- Object toolObj = loadTool("antlr.Tool", null);
+ antlrTool = new Antlr2Tool();
+ if (antlrTool.available()) {
LOGGER.info("Processing with ANTLR 2");
- return processV2(toolObj, spec.asCommandLineWithoutFiles(), spec.getGrammarFiles(), spec.getOutputDirectory());
- } catch (ClassNotFoundException e) {
- LOGGER.debug("ANTLR 2 not found on classpath");
+ return antlrTool.process(spec);
}
-
throw new IllegalStateException("No Antlr implementation available");
}
- private String[] toArray(List<String> strings) {
- return strings.toArray(new String[strings.size()]);
+ private static class Antlr3Tool extends AntlrTool {
+ public Antlr3Tool() {
+ }
+
+ @Override
+ int invoke(List<String> arguments, File inputDirectory) throws ClassNotFoundException {
+ final Object backedObject = loadTool("org.antlr.Tool", null);
+ String[] argArray = arguments.toArray(new String[arguments.size()]);
+ if (inputDirectory != null) {
+ JavaReflectionUtil.method(backedObject, Void.class, "setInputDirectory", String.class).invoke(backedObject, inputDirectory.getAbsolutePath());
+ JavaReflectionUtil.method(backedObject, Void.class, "setForceRelativeOutput", boolean.class).invoke(backedObject, true);
+ }
+ JavaReflectionUtil.method(backedObject, Void.class, "processArgs", String[].class).invoke(backedObject, new Object[]{argArray});
+ JavaReflectionUtil.method(backedObject, Void.class, "process").invoke(backedObject);
+ return JavaReflectionUtil.method(backedObject, Integer.class, "getNumErrors").invoke(backedObject);
+ }
+
+ @Override
+ public boolean available() {
+ try {
+ loadTool("org.antlr.Tool", null);
+ } catch (ClassNotFoundException cnf) {
+ return false;
+ }
+ return true;
+ }
}
- /**
- * Utility method to create an instance of the Tool class.
- * @throws ClassNotFoundException if class was not on the runtime classpath.
- */
- Object loadTool(String className, String[] args) throws ClassNotFoundException {
- try {
- Class<?> toolClass = Class.forName(className); // ok to use caller classloader
- if (args == null) {
- return toolClass.newInstance();
+ private abstract static class AntlrTool {
+ /**
+ * Utility method to create an instance of the Tool class.
+ *
+ * @throws ClassNotFoundException if class was not on the runtime classpath.
+ */
+ static Object loadTool(String className, String[] args) throws ClassNotFoundException {
+ try {
+ Class<?> toolClass = Class.forName(className); // ok to use caller classloader
+ if (args == null) {
+ return toolClass.newInstance();
+ } else {
+ Constructor<?> constructor = toolClass.getConstructor(String[].class);
+ return constructor.newInstance(new Object[]{args});
+ }
+ }catch(ClassNotFoundException cnf){
+ throw cnf;
+ } catch (InvocationTargetException e) {
+ throw new GradleException("Failed to load ANTLR", e.getCause());
+ } catch (Exception e) {
+ throw new GradleException("Failed to load ANTLR", e);
+ }
+ }
+
+ public final AntlrResult process(AntlrSpec spec) {
+ try {
+ return doProcess(spec);
+ } catch (ClassNotFoundException e) {
+ //this shouldn't happen if you call check availability with #available first
+ throw new GradleException("Canot process antlr sources", e);
+ }
+ }
+
+ /**
+ * process used for antlr3/4
+ */
+ public AntlrResult doProcess(AntlrSpec spec) throws ClassNotFoundException {
+ int numErrors = 0;
+ if (spec.getInputDirectories().size() == 0) {
+ // we have not root source folder information for the grammar files,
+ // so we don't force relativeOutput as we can't calculate it.
+ // This results in flat generated sources in the output directory
+ numErrors += invoke(spec.asArgumentsWithFiles(), null);
} else {
- Constructor<?> constructor = toolClass.getConstructor(String[].class);
- return constructor.newInstance(new Object[]{args});
+ boolean onWindows = OperatingSystem.current().isWindows();
+ for (File inputDirectory : spec.getInputDirectories()) {
+ final List<String> arguments = spec.getArguments();
+ arguments.add("-o");
+ arguments.add(spec.getOutputDirectory().getAbsolutePath());
+ for (File grammarFile : spec.getGrammarFiles()) {
+ String relativeGrammarFilePath = GFileUtils.relativePath(inputDirectory, grammarFile);
+ if (onWindows) {
+ relativeGrammarFilePath = relativeGrammarFilePath.replace('/', File.separatorChar);
+ }
+ arguments.add(relativeGrammarFilePath);
+ }
+ numErrors += invoke(arguments, inputDirectory);
+ }
}
- } catch (ClassNotFoundException e) {
- throw e;
- } catch (InvocationTargetException e) {
- throw new GradleException("Failed to load ANTLR", e.getCause());
- } catch (Exception e) {
- throw new GradleException("Failed to load ANTLR", e);
+ return new AntlrResult(numErrors);
}
- }
- AntlrResult processV2(Object tool, List<String> arguments, Set<File> grammarFiles, File outputDirectory) {
- XRef xref = new MetadataExtracter().extractMetadata(grammarFiles);
- List<GenerationPlan> generationPlans = new GenerationPlanBuilder(outputDirectory).buildGenerationPlans(xref);
- for (GenerationPlan generationPlan : generationPlans) {
- String[] argArr = arguments.toArray(new String[arguments.size() + 1]);
- argArr[arguments.size()] = generationPlan.getSource().getAbsolutePath();
- JavaReflectionUtil.method(tool, Integer.class, "doEverything", String[].class).invoke(tool, new Object[]{argArr});
+ abstract int invoke(List<String> arguments, File inputDirectory) throws ClassNotFoundException;
+
+ public abstract boolean available();
+
+ protected static String[] toArray(List<String> strings) {
+ return strings.toArray(new String[strings.size()]);
}
- return new AntlrResult(0); // ANTLR 2 always returning 0
- }
- AntlrResult processV3(Object tool) {
- JavaReflectionUtil.method(tool, Void.class, "process").invoke(tool);
- return new AntlrResult(JavaReflectionUtil.method(tool, Integer.class, "getNumErrors").invoke(tool));
}
- AntlrResult processV4(Object tool) {
- JavaReflectionUtil.method(tool, Void.class, "processGrammarsOnCommandLine").invoke(tool);
- return new AntlrResult(JavaReflectionUtil.method(tool, Integer.class, "getNumErrors").invoke(tool));
+ static class Antlr4Tool extends AntlrTool {
+ public Antlr4Tool() {
+ }
+
+ @Override
+ int invoke(List<String> arguments, File inputDirectory) throws ClassNotFoundException {
+ final Object backedObject = loadTool("org.antlr.v4.Tool", toArray(arguments));
+ if (inputDirectory != null) {
+ JavaReflectionUtil.writeableField(backedObject.getClass(), "inputDirectory").setValue(backedObject, inputDirectory);
+ }
+ JavaReflectionUtil.method(backedObject, Void.class, "processGrammarsOnCommandLine").invoke(backedObject);
+ return JavaReflectionUtil.method(backedObject, Integer.class, "getNumErrors").invoke(backedObject);
+ }
+
+ @Override
+ public boolean available() {
+ try {
+ loadTool("org.antlr.v4.Tool", null);
+ } catch (ClassNotFoundException cnf) {
+ return false;
+ }
+ return true;
+ }
}
-}
\ No newline at end of file
+ private static class Antlr2Tool extends AntlrTool {
+ public Antlr2Tool() {
+ }
+
+ public AntlrResult doProcess(AntlrSpec spec) throws ClassNotFoundException {
+ XRef xref = new MetadataExtracter().extractMetadata(spec.getGrammarFiles());
+ List<GenerationPlan> generationPlans = new GenerationPlanBuilder(spec.getOutputDirectory()).buildGenerationPlans(xref);
+ for (GenerationPlan generationPlan : generationPlans) {
+ List<String> generationPlanArguments = Lists.newArrayList(spec.getArguments());
+ generationPlanArguments.add("-o");
+ generationPlanArguments.add(generationPlan.getGenerationDirectory().getAbsolutePath());
+ generationPlanArguments.add(generationPlan.getSource().getAbsolutePath());
+ invoke(generationPlanArguments, null);
+
+ }
+ return new AntlrResult(0); // ANTLR 2 always returning 0
+ }
+
+ /**
+ * inputDirectory is not used in antlr2
+ * */
+ @Override
+ int invoke(List<String> arguments, File inputDirectory) throws ClassNotFoundException {
+ final Object backedAntlrTool = loadTool("antlr.Tool", null);
+ JavaReflectionUtil.method(backedAntlrTool, Integer.class, "doEverything", String[].class).invoke(backedAntlrTool, new Object[]{toArray(arguments)});
+ return 0;
+ }
+
+ @Override
+ public boolean available() {
+ try {
+ loadTool("antlr.Tool", null);
+ } catch (ClassNotFoundException cnf) {
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpec.java b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpec.java
index c745dc4..c471de3 100644
--- a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpec.java
+++ b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpec.java
@@ -26,12 +26,14 @@ import java.util.Set;
public class AntlrSpec implements Serializable {
private List<String> arguments;
+ private Set<File> inputDirectories;
private Set<File> grammarFiles;
private String maxHeapSize;
private File outputDirectory;
- public AntlrSpec(List<String> arguments, Set<File> grammarFiles, File outputDirectory, String maxHeapSize) {
+ public AntlrSpec(List<String> arguments, Set<File> grammarFiles, Set<File> inputDirectories, File outputDirectory, String maxHeapSize) {
this.arguments = arguments;
+ this.inputDirectories = inputDirectories;
this.grammarFiles = grammarFiles;
this.outputDirectory = outputDirectory;
this.maxHeapSize = maxHeapSize;
@@ -53,18 +55,10 @@ public class AntlrSpec implements Serializable {
return outputDirectory;
}
- public List<String> asCommandLineWithoutFiles() {
+ public List<String> asArgumentsWithFiles() {
List<String> commandLine = Lists.newLinkedList(arguments);
-
commandLine.add("-o");
commandLine.add(getOutputDirectory().getAbsolutePath());
-
- return commandLine;
- }
-
- public List<String> asCommandLineWithFiles() {
- List<String> commandLine = Lists.newLinkedList(asCommandLineWithoutFiles());
-
for (File file : getGrammarFiles()) {
commandLine.add(file.getAbsolutePath());
}
@@ -72,4 +66,7 @@ public class AntlrSpec implements Serializable {
return commandLine;
}
+ public Set<File> getInputDirectories() {
+ return inputDirectories;
+ }
}
diff --git a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactory.java b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactory.java
index d2ce8d2..efe1bfe 100644
--- a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactory.java
+++ b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactory.java
@@ -17,6 +17,7 @@
package org.gradle.api.plugins.antlr.internal;
import com.google.common.collect.Lists;
+import org.gradle.api.file.SourceDirectorySet;
import org.gradle.api.plugins.antlr.AntlrTask;
import java.io.File;
@@ -25,7 +26,7 @@ import java.util.Set;
public class AntlrSpecFactory {
- public AntlrSpec create(AntlrTask antlrTask, Set<File> grammarFiles) {
+ public AntlrSpec create(AntlrTask antlrTask, Set<File> grammarFiles, SourceDirectorySet sourceDirectorySet) {
List<String> arguments = Lists.newLinkedList(antlrTask.getArguments());
if (antlrTask.isTrace() && !arguments.contains("-trace")) {
@@ -41,6 +42,6 @@ public class AntlrSpecFactory {
arguments.add("-traceTreeWalker");
}
- return new AntlrSpec(arguments, grammarFiles, antlrTask.getOutputDirectory(), antlrTask.getMaxHeapSize());
+ return new AntlrSpec(arguments, grammarFiles, sourceDirectorySet.getSrcDirs(), antlrTask.getOutputDirectory(), antlrTask.getMaxHeapSize());
}
}
diff --git a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/antlr2/MetadataExtracter.java b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/antlr2/MetadataExtracter.java
index 56c6925..3300cf5 100644
--- a/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/antlr2/MetadataExtracter.java
+++ b/subprojects/antlr/src/main/groovy/org/gradle/api/plugins/antlr/internal/antlr2/MetadataExtracter.java
@@ -15,10 +15,13 @@
*/
package org.gradle.api.plugins.antlr.internal.antlr2;
+import org.gradle.api.Nullable;
import org.gradle.api.UncheckedIOException;
import java.io.*;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Preprocess an Antlr grammar file so that dependencies between grammars can be properly determined such that they can
@@ -47,28 +50,7 @@ public class MetadataExtracter {
for (File grammarFileFile : sources) {
// determine the package name :(
- String grammarPackageName = null;
- try {
- BufferedReader in = new BufferedReader(new FileReader(grammarFileFile));
- try {
- String line;
- while ((line = in.readLine()) != null) {
- line = line.trim();
- if (line.startsWith("package") && line.endsWith(";")) {
- grammarPackageName = line.substring(8, line.length() - 1);
- break;
- }
- }
- } finally {
- try {
- in.close();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
+ String grammarPackageName = getPackageName(grammarFileFile);
final String grammarFilePath = grammarFileFile.getPath();
antlr.preprocessor.GrammarFile antlrGrammarFile = hierarchy.getFile(grammarFilePath);
@@ -81,4 +63,41 @@ public class MetadataExtracter {
return xref;
}
+
+ @Nullable
+ private String getPackageName(File grammarFileFile) {
+ try {
+ return getPackageName(new FileReader(grammarFileFile));
+ } catch (IOException e) {
+ throw new UncheckedIOException("Cannot read antlr grammar file", e);
+ }
+ }
+
+ String getPackageName(Reader reader) throws IOException {
+ String grammarPackageName = null;
+ BufferedReader in = new BufferedReader(reader);
+ try {
+ String line;
+ while ((line = in.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("package") && line.endsWith(";")) {
+ grammarPackageName = line.substring(8, line.length() - 1);
+ }else if(line.startsWith("header")){
+ Pattern p = Pattern.compile("header \\{\\s*package\\s+(.+);\\s+\\}");
+ Matcher m = p.matcher(line);
+ if(m.matches()){
+ grammarPackageName = m.group(1);
+ }
+ }
+
+ }
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ return grammarPackageName;
+ }
}
diff --git a/subprojects/antlr/src/test/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactoryTest.groovy b/subprojects/antlr/src/test/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactoryTest.groovy
index 101db8a..943d992 100644
--- a/subprojects/antlr/src/test/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactoryTest.groovy
+++ b/subprojects/antlr/src/test/groovy/org/gradle/api/plugins/antlr/internal/AntlrSpecFactoryTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.api.plugins.antlr.internal
+import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.antlr.AntlrTask
import spock.lang.Specification
@@ -23,7 +24,11 @@ class AntlrSpecFactoryTest extends Specification {
AntlrExecuter executer = new AntlrExecuter()
private AntlrSpecFactory factory = new AntlrSpecFactory()
+ private SourceDirectorySet sourceDirectorySet = Mock()
+ def setup(){
+ 1 * sourceDirectorySet.getSrcDirs() >> []
+ }
def tracePropertiesAddedToArgumentList() {
when:
AntlrTask task = Mock()
@@ -35,7 +40,7 @@ class AntlrSpecFactoryTest extends Specification {
_ * task.isTraceParser() >> true
_ * task.isTraceTreeWalker() >> true
- def spec = factory.create(task, [] as Set)
+ def spec = factory.create(task, [] as Set, sourceDirectorySet)
then:
spec.arguments.contains("-trace")
@@ -50,7 +55,7 @@ class AntlrSpecFactoryTest extends Specification {
_ * task.outputDirectory >> destFile()
_ * task.getArguments() >> ["-trace", "-traceLexer", "-traceParser", "-traceTreeWalker"]
- def spec = factory.create(task, [] as Set)
+ def spec = factory.create(task, [] as Set, sourceDirectorySet)
then:
spec.arguments.contains("-trace")
@@ -69,7 +74,7 @@ class AntlrSpecFactoryTest extends Specification {
_ * task.isTraceParser() >> true
_ * task.isTraceTreeWalker() >> true
- def spec = factory.create(task, [] as Set)
+ def spec = factory.create(task, [] as Set, sourceDirectorySet)
then:
spec.arguments.count { it == "-trace" } == 1
@@ -78,22 +83,6 @@ class AntlrSpecFactoryTest extends Specification {
spec.arguments.count { it == "-traceTreeWalker" } == 1
}
- def buildCommonArgumentsAddsAllParameters() {
- when:
- AntlrTask task = Mock()
- _ * task.outputDirectory >> destFile()
- _ * task.getArguments() >> ["-test"]
- _ * task.isTrace() >> true
- _ * task.isTraceLexer() >> true
- _ * task.isTraceParser() >> true
- _ * task.isTraceTreeWalker() >> true
-
- def spec = factory.create(task, [] as Set)
-
- then:
- spec.asCommandLineWithoutFiles() == ["-test", "-trace", "-traceLexer", "-traceParser", "-traceTreeWalker", "-o", "/output"]
- }
-
def destFile() {
File dest = Mock()
dest.getAbsolutePath() >> "/output"
diff --git a/subprojects/antlr/src/test/groovy/org/gradle/api/plugins/antlr/internal/antlr2/MetadataExtracterTest.groovy b/subprojects/antlr/src/test/groovy/org/gradle/api/plugins/antlr/internal/antlr2/MetadataExtracterTest.groovy
new file mode 100644
index 0000000..c0c0a71
--- /dev/null
+++ b/subprojects/antlr/src/test/groovy/org/gradle/api/plugins/antlr/internal/antlr2/MetadataExtracterTest.groovy
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.plugins.antlr.internal.antlr2
+
+import spock.lang.Specification
+
+class MetadataExtracterTest extends Specification {
+
+ def "parses package information when defined in a separate line"() {
+ given:
+ def grammar = """
+ header {
+ package org.acme;
+ }
+
+ class TestGrammar extends Parser;
+
+ options {
+ buildAST = true;
+ }
+
+ expr: mexpr (PLUS^ mexpr)* SEMI!
+ ;
+
+ mexpr
+ : atom (STAR^ atom)*
+ ;
+
+ atom: INT
+ ;"""
+ expect:
+ "org.acme" == new MetadataExtracter().getPackageName(new StringReader(grammar))
+ }
+
+ def "parses package information when header is declared as one-liner"() {
+ given:
+ def grammar = """
+ header { package org.acme; }
+
+ class TestGrammar extends Parser;
+
+ options {
+ buildAST = true;
+ }
+
+ expr: mexpr (PLUS^ mexpr)* SEMI!
+ ;
+
+ mexpr
+ : atom (STAR^ atom)*
+ ;
+
+ atom: INT
+ ;"""
+ expect:
+ "org.acme" == new MetadataExtracter().getPackageName(new StringReader(grammar))
+ }
+
+ def "parses package information with header block in cpp syntax"() {
+ given:
+ def grammar = """
+ header
+{
+package org.hibernate.hql.internal.antlr;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.LinkedList;
+
+import org.hibernate.hql.internal.ast.ErrorReporter;
+}
+
+ class TestGrammar extends Parser;
+
+ options {
+ buildAST = true;
+ }
+
+ expr: mexpr (PLUS^ mexpr)* SEMI!
+ ;
+
+ mexpr
+ : atom (STAR^ atom)*
+ ;
+
+ atom: INT
+ ;"""
+ expect:
+ "org.hibernate.hql.internal.antlr" == new MetadataExtracter().getPackageName(new StringReader(grammar))
+ }
+}
diff --git a/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/AstUtils.java b/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/AstUtils.java
index 1297061..5726416 100644
--- a/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/AstUtils.java
+++ b/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/AstUtils.java
@@ -235,17 +235,28 @@ public abstract class AstUtils {
return doCallMethods.get(0);
}
- public static boolean isReturnNullStatement(Statement statement) {
+ /**
+ * Returns true if the the given statement may have some effect as part of a script body.
+ * Returns false when the given statement may be ignored, provided all other statements in the script body may also be ignored.
+ */
+ public static boolean mayHaveAnEffect(Statement statement) {
if (statement instanceof ReturnStatement) {
ReturnStatement returnStatement = (ReturnStatement) statement;
if (returnStatement.getExpression() instanceof ConstantExpression) {
- ConstantExpression constantExpression = (ConstantExpression) returnStatement.getExpression();
- if (constantExpression.getValue() == null) {
- return true;
+ return false;
+ }
+ } else if (statement instanceof ExpressionStatement) {
+ ExpressionStatement expressionStatement = (ExpressionStatement) statement;
+ if (expressionStatement.getExpression() instanceof ConstantExpression) {
+ return false;
+ }
+ if (expressionStatement.getExpression() instanceof DeclarationExpression) {
+ DeclarationExpression declarationExpression = (DeclarationExpression) expressionStatement.getExpression();
+ if (declarationExpression.getRightExpression() instanceof EmptyExpression || declarationExpression.getRightExpression() instanceof ConstantExpression) {
+ return false;
}
}
}
- return false;
+ return true;
}
-
}
diff --git a/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptSourceDescriptionTransformer.java b/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptSourceDescriptionTransformer.java
deleted file mode 100644
index 437b0ab..0000000
--- a/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptSourceDescriptionTransformer.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.groovy.scripts.internal;
-
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.Phases;
-import org.codehaus.groovy.control.SourceUnit;
-
-public class ScriptSourceDescriptionTransformer extends AbstractScriptTransformer {
- public final static String AST_NODE_METADATA_KEY = ScriptSourceDescriptionTransformer.class.getName();
-
- private final String scriptSourceDescription;
-
- ScriptSourceDescriptionTransformer(String scriptSourceDescription) {
- this.scriptSourceDescription = scriptSourceDescription;
- }
-
- @Override
- protected int getPhase() {
- return Phases.CONVERSION;
- }
-
- public void call(SourceUnit source) throws CompilationFailedException {
- source.getAST().setNodeMetaData(AST_NODE_METADATA_KEY, scriptSourceDescription);
- }
-
-}
diff --git a/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptSourceTransformer.java b/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptSourceTransformer.java
new file mode 100644
index 0000000..4c89c4e
--- /dev/null
+++ b/subprojects/base-services-groovy/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptSourceTransformer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.groovy.scripts.internal;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.control.SourceUnit;
+import org.gradle.api.Nullable;
+
+import java.net.URI;
+
+public class ScriptSourceTransformer extends AbstractScriptTransformer {
+ public final static String AST_NODE_DESCRIPTION_METADATA_KEY = "AST_NODE_DESCRIPTION_METADATA_KEY";
+ public final static String AST_NODE_LOCATION_METADATA_KEY = "AST_NODE_LOCATION_METADATA_KEY";
+
+ private final String scriptSourceDescription;
+ private final URI location;
+
+ ScriptSourceTransformer(String scriptSourceDescription, @Nullable URI location) {
+ this.scriptSourceDescription = scriptSourceDescription;
+ this.location = location;
+ }
+
+ @Override
+ protected int getPhase() {
+ return Phases.CONVERSION;
+ }
+
+ public void call(SourceUnit source) throws CompilationFailedException {
+ source.getAST().setNodeMetaData(AST_NODE_DESCRIPTION_METADATA_KEY, scriptSourceDescription);
+ if (null != location) {
+ source.getAST().setNodeMetaData(AST_NODE_LOCATION_METADATA_KEY, location.toString());
+ }
+ }
+
+}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/SystemProperties.java b/subprojects/base-services/src/main/java/org/gradle/internal/SystemProperties.java
index bfc11a0..6073569 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/SystemProperties.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/SystemProperties.java
@@ -86,6 +86,10 @@ public class SystemProperties {
return System.getProperty("user.home");
}
+ public String getUserName() {
+ return System.getProperty("user.name");
+ }
+
public String getJavaVersion() {
return System.getProperty("java.version");
}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/file/RelativeFilePathResolver.java b/subprojects/base-services/src/main/java/org/gradle/internal/file/RelativeFilePathResolver.java
new file mode 100644
index 0000000..d09a21e
--- /dev/null
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/file/RelativeFilePathResolver.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.file;
+
+public interface RelativeFilePathResolver {
+ String resolveAsRelativePath(Object path);
+}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/hash/HashUtil.java b/subprojects/base-services/src/main/java/org/gradle/internal/hash/HashUtil.java
index b9b22fc..8fd9bdc 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/hash/HashUtil.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/hash/HashUtil.java
@@ -85,4 +85,16 @@ public class HashUtil {
public static HashValue sha1(File file) {
return createHash(file, "SHA1");
}
+
+ public static HashValue sha256(byte[] bytes) {
+ return createHash(new ByteArrayInputStream(bytes), "SHA-256");
+ }
+
+ public static HashValue sha256(InputStream inputStream) {
+ return createHash(inputStream, "SHA-256");
+ }
+
+ public static HashValue sha256(File file) {
+ return createHash(file, "SHA-256");
+ }
}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/jvm/Jvm.java b/subprojects/base-services/src/main/java/org/gradle/internal/jvm/Jvm.java
index f7c1ae4..76e78fc 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/jvm/Jvm.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/jvm/Jvm.java
@@ -118,6 +118,23 @@ public class Jvm implements JavaInfo {
return String.format("%s (%s %s)", SystemProperties.getInstance().getJavaVersion(), System.getProperty("java.vm.vendor"), System.getProperty("java.vm.version"));
}
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || obj.getClass() != getClass()) {
+ return false;
+ }
+ Jvm other = (Jvm) obj;
+ return other.javaHome.equals(javaHome);
+ }
+
+ @Override
+ public int hashCode() {
+ return javaHome.hashCode();
+ }
+
private File findExecutable(String command) {
File exec = new File(getJavaHome(), "bin/" + command);
File executable = new File(os.getExecutableName(exec.getAbsolutePath()));
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassDetails.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassDetails.java
index c51d3dc..485f528 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassDetails.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassDetails.java
@@ -47,4 +47,13 @@ public interface ClassDetails {
* Includes inherited methods.
*/
List<Method> getInstanceMethods();
+
+ /**
+ * The ordered super types of this type.
+ *
+ * Entries are ordered by their “distance” from the target type, nearest to furthest.
+ * Superclasses are considered nearer than implemented interfaces.
+ * Interfaces are ordered by declaration order.
+ */
+ Set<Class<?>> getSuperTypes();
}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassInspector.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassInspector.java
index 6af4cf7..fd11005 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassInspector.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/ClassInspector.java
@@ -16,6 +16,8 @@
package org.gradle.internal.reflect;
+import com.google.common.collect.Lists;
+
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
@@ -25,31 +27,43 @@ public class ClassInspector {
* Extracts a view of the given class.
*/
public static ClassDetails inspect(Class<?> type) {
- DefaultClassDetails classDetails = new DefaultClassDetails(type);
+ MutableClassDetails classDetails = new MutableClassDetails(type);
visitGraph(type, classDetails);
return classDetails;
}
- private static void visitGraph(Class<?> type, DefaultClassDetails classDetails) {
+ private static void visitGraph(Class<?> type, MutableClassDetails classDetails) {
Set<Class<?>> seen = new HashSet<Class<?>>();
List<Class<?>> queue = new ArrayList<Class<?>>();
+
+ // fully visit the class hierarchy before any interfaces in order to meet the contract
+ // of PropertyDetails.getGetters() etc.
queue.add(type);
+ Collections.addAll(queue, superClasses(type));
while (!queue.isEmpty()) {
Class<?> current = queue.remove(0);
if (!seen.add(current)) {
continue;
}
- inspectClass(current, classDetails);
- for (Class<?> c : current.getInterfaces()) {
- queue.add(0, c);
- }
- if (current.getSuperclass() != null && current.getSuperclass() != Object.class) {
- queue.add(0, current.getSuperclass());
+ if (!current.equals(type)) {
+ classDetails.superType(current);
}
+ inspectClass(current, classDetails);
+ Collections.addAll(queue, current.getInterfaces());
+ }
+ }
+
+ private static Class<?>[] superClasses(Class<?> current) {
+ List<Class<?>> supers = Lists.newArrayList();
+ Class<?> superclass = current.getSuperclass();
+ while (superclass != null && superclass != Object.class) {
+ supers.add(superclass);
+ superclass = superclass.getSuperclass();
}
+ return supers.toArray(new Class<?>[supers.size()]);
}
- private static void inspectClass(Class<?> type, DefaultClassDetails classDetails) {
+ private static void inspectClass(Class<?> type, MutableClassDetails classDetails) {
for (Method method : type.getDeclaredMethods()) {
classDetails.method(method);
@@ -60,20 +74,20 @@ public class ClassInspector {
Class<?>[] parameterTypes = method.getParameterTypes();
String methodName = method.getName();
if (methodName.startsWith("get")
- && methodName.length() > 3
- && !method.getReturnType().equals(Void.TYPE)
- && parameterTypes.length == 0) {
+ && methodName.length() > 3
+ && !method.getReturnType().equals(Void.TYPE)
+ && parameterTypes.length == 0) {
String propertyName = propertyName(methodName, 3);
classDetails.property(propertyName).addGetter(method);
} else if (methodName.startsWith("is")
- && methodName.length() > 2
- && (method.getReturnType().equals(Boolean.class) || method.getReturnType().equals(Boolean.TYPE))
- && parameterTypes.length == 0) {
+ && methodName.length() > 2
+ && (method.getReturnType().equals(Boolean.class) || method.getReturnType().equals(Boolean.TYPE))
+ && parameterTypes.length == 0) {
String propertyName = propertyName(methodName, 2);
classDetails.property(propertyName).addGetter(method);
} else if (methodName.startsWith("set")
- && methodName.length() > 3
- && parameterTypes.length == 1) {
+ && methodName.length() > 3
+ && parameterTypes.length == 1) {
String propertyName = propertyName(methodName, 3);
classDetails.property(propertyName).addSetter(method);
} else {
@@ -91,143 +105,4 @@ public class ClassInspector {
return Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
}
- private static class MethodSignature {
- final String name;
- final Class<?>[] params;
-
- private MethodSignature(String name, Class<?>[] params) {
- this.name = name;
- this.params = params;
- }
-
- @Override
- public boolean equals(Object obj) {
- MethodSignature other = (MethodSignature) obj;
- return other.name.equals(name) && Arrays.equals(params, other.params);
- }
-
- @Override
- public int hashCode() {
- return name.hashCode() ^ Arrays.hashCode(params);
- }
- }
-
- private static class MethodSet implements Iterable<Method> {
- private final Set<MethodSignature> signatures = new HashSet<MethodSignature>();
- private final List<Method> methods = new ArrayList<Method>();
-
- /**
- * @return true if the method was added, false if not
- */
- public boolean add(Method method) {
- MethodSignature methodSignature = new MethodSignature(method.getName(), method.getParameterTypes());
- if (signatures.add(methodSignature)) {
- methods.add(method);
- return true;
- }
- return false;
- }
-
- public Iterator<Method> iterator() {
- return methods.iterator();
- }
-
- public List<Method> getValues() {
- return methods;
- }
-
- public boolean isEmpty() {
- return methods.isEmpty();
- }
- }
-
- private static class DefaultClassDetails implements ClassDetails {
- private final Class<?> type;
- private final MethodSet instanceMethods = new MethodSet();
- private final Map<String, DefaultPropertyDetails> properties = new TreeMap<String, DefaultPropertyDetails>();
- private final List<Method> methods = new ArrayList<Method>();
-
- private DefaultClassDetails(Class<?> type) {
- this.type = type;
- }
-
- @Override
- public List<Method> getAllMethods() {
- return methods;
- }
-
- @Override
- public List<Method> getInstanceMethods() {
- return instanceMethods.getValues();
- }
-
- @Override
- public Set<String> getPropertyNames() {
- return properties.keySet();
- }
-
- @Override
- public Collection<? extends PropertyDetails> getProperties() {
- return properties.values();
- }
-
- @Override
- public PropertyDetails getProperty(String name) throws NoSuchPropertyException {
- DefaultPropertyDetails property = properties.get(name);
- if (property == null) {
- throw new NoSuchPropertyException(String.format("No property '%s' found on %s.", name, type));
- }
- return property;
- }
-
- public void method(Method method) {
- methods.add(method);
- }
-
- public void instanceMethod(Method method) {
- instanceMethods.add(method);
- }
-
- public DefaultPropertyDetails property(String propertyName) {
- DefaultPropertyDetails property = properties.get(propertyName);
- if (property == null) {
- property = new DefaultPropertyDetails(propertyName);
- properties.put(propertyName, property);
- }
- return property;
- }
- }
-
- private static class DefaultPropertyDetails implements PropertyDetails {
- private final String name;
- private final MethodSet getters = new MethodSet();
- private final MethodSet setters = new MethodSet();
-
- private DefaultPropertyDetails(String name) {
- this.name = name;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public List<Method> getGetters() {
- return getters.getValues();
- }
-
- @Override
- public List<Method> getSetters() {
- return setters.getValues();
- }
-
- public void addGetter(Method method) {
- getters.add(method);
- }
-
- public void addSetter(Method method) {
- setters.add(method);
- }
- }
}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/JavaReflectionUtil.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/JavaReflectionUtil.java
index 7ded4c0..9346083 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/JavaReflectionUtil.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/JavaReflectionUtil.java
@@ -152,6 +152,21 @@ public class JavaReflectionUtil {
throw new NoSuchPropertyException(String.format("Could not find setter method for property '%s' on class %s.", property, target.getSimpleName()));
}
+ /**
+ * Locates the field with the given name as a writable property. Searches only public properties.
+ *
+ * @throws NoSuchPropertyException when the given property does not exist.
+ */
+ public static PropertyMutator writeableField(Class<?> target, String fieldName) throws NoSuchPropertyException {
+ Field field;
+ try {
+ field = target.getField(fieldName);
+ return new FieldBackedPropertyMutator(fieldName, field);
+ } catch (java.lang.NoSuchFieldException e) {
+ throw new NoSuchPropertyException(String.format("Could not find writeable field '%s' on class %s.", fieldName, target.getSimpleName()));
+ }
+ }
+
private static String toMethodName(String prefix, String propertyName) {
return prefix + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
}
@@ -438,6 +453,37 @@ public class JavaReflectionUtil {
}
}
+ private static class FieldBackedPropertyMutator implements PropertyMutator {
+ private final String name;
+ private final Field field;
+
+ public FieldBackedPropertyMutator(String name, Field field) {
+ this.name = name;
+ this.field = field;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("field %s.%s", field.getDeclaringClass().getSimpleName(), name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class<?> getType() {
+ return field.getType();
+ }
+
+ public void setValue(Object target, Object value) {
+ try {
+ field.set(target, value);
+ } catch (IllegalAccessException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+ }
+
private static class InstantiatingFactory<T> implements Factory<T> {
private final Instantiator instantiator;
private final Class<? extends T> type;
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSet.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSet.java
new file mode 100644
index 0000000..ab025f9
--- /dev/null
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSet.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.reflect;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+class MethodSet implements Iterable<Method> {
+ private final Set<MethodSignature> signatures = new HashSet<MethodSignature>();
+ private final List<Method> methods = new ArrayList<Method>();
+
+ /**
+ * @return true if the method was added, false if not
+ */
+ public boolean add(Method method) {
+ MethodSignature methodSignature = new MethodSignature(method.getName(), method.getParameterTypes());
+ if (signatures.add(methodSignature)) {
+ methods.add(method);
+ return true;
+ }
+ return false;
+ }
+
+ public Iterator<Method> iterator() {
+ return methods.iterator();
+ }
+
+ public List<Method> getValues() {
+ return methods;
+ }
+
+ public boolean isEmpty() {
+ return methods.isEmpty();
+ }
+}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSignature.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSignature.java
new file mode 100644
index 0000000..4069043
--- /dev/null
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSignature.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.reflect;
+
+import java.util.Arrays;
+
+class MethodSignature {
+ final String name;
+ final Class<?>[] params;
+
+ MethodSignature(String name, Class<?>[] params) {
+ this.name = name;
+ this.params = params;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ MethodSignature other = (MethodSignature) obj;
+ return other.name.equals(name) && Arrays.equals(params, other.params);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode() ^ Arrays.hashCode(params);
+ }
+}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSignatureEquivalence.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSignatureEquivalence.java
index 4515077..fb36a77 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSignatureEquivalence.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MethodSignatureEquivalence.java
@@ -27,13 +27,13 @@ public class MethodSignatureEquivalence extends Equivalence<Method> {
@Override
protected boolean doEquivalent(Method a, Method b) {
boolean equals = new EqualsBuilder()
- .append(a.getName(), b.getName())
- .append(a.getGenericParameterTypes(), b.getGenericParameterTypes())
- .isEquals();
+ .append(a.getName(), b.getName())
+ .append(a.getGenericParameterTypes(), b.getGenericParameterTypes())
+ .isEquals();
if (equals) {
equals = a.getReturnType().equals(b.getReturnType())
- || a.getReturnType().isAssignableFrom(b.getReturnType())
- || b.getReturnType().isAssignableFrom(a.getReturnType());
+ || a.getReturnType().isAssignableFrom(b.getReturnType())
+ || b.getReturnType().isAssignableFrom(a.getReturnType());
}
return equals;
}
@@ -41,8 +41,8 @@ public class MethodSignatureEquivalence extends Equivalence<Method> {
@Override
protected int doHash(Method method) {
return new HashCodeBuilder()
- .append(method.getName())
- .append(method.getGenericParameterTypes())
- .toHashCode();
+ .append(method.getName())
+ .append(method.getGenericParameterTypes())
+ .toHashCode();
}
}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MutableClassDetails.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MutableClassDetails.java
new file mode 100644
index 0000000..c2366c0
--- /dev/null
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MutableClassDetails.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.reflect;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+class MutableClassDetails implements ClassDetails {
+ private final Class<?> type;
+ private final MethodSet instanceMethods = new MethodSet();
+ private final Map<String, MutablePropertyDetails> properties = new TreeMap<String, MutablePropertyDetails>();
+ private final List<Method> methods = new ArrayList<Method>();
+ private final Set<Class<?>> superTypes = new LinkedHashSet<Class<?>>();
+
+ MutableClassDetails(Class<?> type) {
+ this.type = type;
+ }
+
+ @Override
+ public List<Method> getAllMethods() {
+ return methods;
+ }
+
+ @Override
+ public List<Method> getInstanceMethods() {
+ return instanceMethods.getValues();
+ }
+
+ @Override
+ public Set<Class<?>> getSuperTypes() {
+ return superTypes;
+ }
+
+ @Override
+ public Set<String> getPropertyNames() {
+ return properties.keySet();
+ }
+
+ @Override
+ public Collection<? extends PropertyDetails> getProperties() {
+ return properties.values();
+ }
+
+ @Override
+ public PropertyDetails getProperty(String name) throws NoSuchPropertyException {
+ MutablePropertyDetails property = properties.get(name);
+ if (property == null) {
+ throw new NoSuchPropertyException(String.format("No property '%s' found on %s.", name, type));
+ }
+ return property;
+ }
+
+ void superType(Class<?> type) {
+ superTypes.add(type);
+ }
+
+ void method(Method method) {
+ methods.add(method);
+ }
+
+ void instanceMethod(Method method) {
+ instanceMethods.add(method);
+ }
+
+ MutablePropertyDetails property(String propertyName) {
+ MutablePropertyDetails property = properties.get(propertyName);
+ if (property == null) {
+ property = new MutablePropertyDetails(propertyName);
+ properties.put(propertyName, property);
+ }
+ return property;
+ }
+}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MutablePropertyDetails.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MutablePropertyDetails.java
new file mode 100644
index 0000000..3a327ee
--- /dev/null
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/MutablePropertyDetails.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.reflect;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+class MutablePropertyDetails implements PropertyDetails {
+ private final String name;
+ private final MethodSet getters = new MethodSet();
+ private final MethodSet setters = new MethodSet();
+
+ MutablePropertyDetails(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public List<Method> getGetters() {
+ return getters.getValues();
+ }
+
+ @Override
+ public List<Method> getSetters() {
+ return setters.getValues();
+ }
+
+ void addGetter(Method method) {
+ getters.add(method);
+ }
+
+ void addSetter(Method method) {
+ setters.add(method);
+ }
+}
diff --git a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/PropertyDetails.java b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/PropertyDetails.java
index 4f09c7d..9c5d2c2 100644
--- a/subprojects/base-services/src/main/java/org/gradle/internal/reflect/PropertyDetails.java
+++ b/subprojects/base-services/src/main/java/org/gradle/internal/reflect/PropertyDetails.java
@@ -20,9 +20,29 @@ import java.lang.reflect.Method;
import java.util.List;
public interface PropertyDetails {
+
String getName();
+ /**
+ * The getter methods for a particular type.
+ *
+ * This list will only ever contain more than one method when there are getter methods with <b>different</b> return types.
+ * If a getter is declared multiple times by this type (through inheritance) with identical return types, only one method object will be present for the type.
+ *
+ * As an equivalent getter can be declared multiple times (e.g in a super class, overridden by the target type).
+ * The actual method instance used is significant.
+ * The method instance is for the “nearest” declaration, where classes take precedence over interfaces.
+ * Interface precedence is breadth-first, declaration.
+ *
+ * The order of the methods follows the same precedence.
+ * That is, the “nearer” declarations are earlier in the list.
+ */
List<Method> getGetters();
+ /**
+ * Similar to {@link #getGetters()}, but varies based on the param type instead of return type.
+ *
+ * Has identical ordering semantics.
+ */
List<Method> getSetters();
}
diff --git a/subprojects/base-services/src/main/java/org/gradle/util/TextUtil.java b/subprojects/base-services/src/main/java/org/gradle/util/TextUtil.java
index 233344a..82c372d 100644
--- a/subprojects/base-services/src/main/java/org/gradle/util/TextUtil.java
+++ b/subprojects/base-services/src/main/java/org/gradle/util/TextUtil.java
@@ -123,4 +123,8 @@ public class TextUtil {
return s2;
}
}
-}
\ No newline at end of file
+
+ public static String normaliseFileAndLineSeparators(String in) {
+ return normaliseLineSeparators(normaliseFileSeparators(in));
+ }
+}
diff --git a/subprojects/base-services/src/test/groovy/org/gradle/internal/hash/HashUtilTest.groovy b/subprojects/base-services/src/test/groovy/org/gradle/internal/hash/HashUtilTest.groovy
index 7549391..3b2f24d 100644
--- a/subprojects/base-services/src/test/groovy/org/gradle/internal/hash/HashUtilTest.groovy
+++ b/subprojects/base-services/src/test/groovy/org/gradle/internal/hash/HashUtilTest.groovy
@@ -24,6 +24,7 @@ class HashUtilTest extends Specification {
String stringToHash = "a test string"
String md5HashString = "b1a4cf30d3f4095f0a7d2a6676bcae77"
String sha1HashString = "2da75da5c85478df42df0f917700241ed282f599"
+ String sha256HashString = "b830543dc5d1466110538736d35c37cc61d32076a69de65c42913dfbb1961f46"
def "createHash from String returns MD5 hash" () {
expect:
@@ -39,7 +40,7 @@ class HashUtilTest extends Specification {
HashUtil.createHash(file, "MD5").asHexString() == md5HashString
cleanup:
- file.delete()
+ file?.delete()
}
@Issue("https://issues.gradle.org/browse/GRADLE-2967")
@@ -104,6 +105,28 @@ class HashUtilTest extends Specification {
HashUtil.sha1(file).asHexString() == sha1HashString
cleanup:
- file.delete()
+ file?.delete()
+ }
+
+ def "sha256 from byteArray returns SHA-256 hash" () {
+ expect:
+ HashUtil.sha256(stringToHash.bytes).asHexString() == sha256HashString
+ }
+
+ def "sha256 from InputStream returns SHA-256 hash" () {
+ expect:
+ HashUtil.sha256(new ByteArrayInputStream(stringToHash.bytes)).asHexString() == sha256HashString
+ }
+
+ def "sha256 from File returns SHA-256 hash" () {
+ setup:
+ File file = File.createTempFile("HashUtilTest", null)
+ file << stringToHash
+
+ expect:
+ HashUtil.sha256(file).asHexString() == sha256HashString
+
+ cleanup:
+ file?.delete()
}
}
diff --git a/subprojects/base-services/src/test/groovy/org/gradle/internal/jvm/JvmTest.groovy b/subprojects/base-services/src/test/groovy/org/gradle/internal/jvm/JvmTest.groovy
index 4eac81e..cd61f7c 100644
--- a/subprojects/base-services/src/test/groovy/org/gradle/internal/jvm/JvmTest.groovy
+++ b/subprojects/base-services/src/test/groovy/org/gradle/internal/jvm/JvmTest.groovy
@@ -19,6 +19,7 @@ package org.gradle.internal.jvm
import org.gradle.internal.os.OperatingSystem
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.gradle.util.Matchers
import org.gradle.util.SetSystemProperties
import org.junit.Rule
import spock.lang.Specification
@@ -241,6 +242,27 @@ class JvmTest extends Specification {
'1.5.0_22' | 'jre1.5.0_22' | 'jdk1.5.0_22'
}
+ def "JVMs are equal when their Java home dirs are the same"() {
+ given:
+ TestFile installDir = tmpDir.createDir('software')
+ installDir.create {
+ lib {
+ file 'tools.jar'
+ }
+ bin {
+ file 'java'
+ }
+ }
+
+ expect:
+ def jvm = new Jvm(os, installDir)
+ def current = Jvm.current()
+
+ Matchers.strictlyEquals(jvm, new Jvm(os, installDir))
+ Matchers.strictlyEquals(current, Jvm.forHome(current.javaHome))
+ jvm != current
+ }
+
def "uses system property to determine if Sun/Oracle JVM"() {
when:
System.properties['java.vm.vendor'] = 'Sun'
@@ -291,7 +313,7 @@ class JvmTest extends Specification {
then:
home.file(theOs.getExecutableName("jre/bin/javadoc")).absolutePath ==
- Jvm.forHome(home.file("jre")).getExecutable("javadoc").absolutePath
+ Jvm.forHome(home.file("jre")).getExecutable("javadoc").absolutePath
}
def "finds tools.jar if java home supplied"() {
@@ -308,7 +330,7 @@ class JvmTest extends Specification {
then:
home.file("jdk/lib/tools.jar").absolutePath ==
- Jvm.forHome(home.file("jdk")).toolsJar.absolutePath
+ Jvm.forHome(home.file("jdk")).toolsJar.absolutePath
}
def "provides decent feedback if executable not found"() {
diff --git a/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/ClassInspectorTest.groovy b/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/ClassInspectorTest.groovy
index 5b79594..368098d 100644
--- a/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/ClassInspectorTest.groovy
+++ b/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/ClassInspectorTest.groovy
@@ -16,6 +16,9 @@
package org.gradle.internal.reflect
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import spock.lang.Issue
import spock.lang.Specification
class ClassInspectorTest extends Specification {
@@ -248,6 +251,7 @@ class ClassInspectorTest extends Specification {
interface SomeInterface {
Number getProp()
+
void setProp(Number value)
String getReadOnly()
@@ -265,9 +269,13 @@ class ClassInspectorTest extends Specification {
class PropNames {
String getA() { null }
+
String getB() { null }
+
String getURL() { null }
+
String getUrl() { null }
+
String get_A() { null }
}
@@ -311,6 +319,7 @@ class ClassInspectorTest extends Specification {
interface SubInterface extends SomeInterface {
Long getOther()
+
void setOther(Long l)
}
@@ -354,4 +363,59 @@ class ClassInspectorTest extends Specification {
return ""
}
}
+
+ def "can extract super types"() {
+ expect:
+ ClassInspector.inspect(Object).superTypes.empty
+ ClassInspector.inspect(Serializable).superTypes.empty
+ ClassInspector.inspect(List).superTypes.toList() == [Collection, Iterable]
+ }
+
+ @Requires(TestPrecondition.NOT_JDK_IBM)
+ def "super types ordered by their distance"() {
+ expect:
+ ClassInspector.inspect(ArrayList).superTypes.toList() == [AbstractList, AbstractCollection, List, RandomAccess, Cloneable, Serializable, Collection, Iterable]
+ }
+
+ @Requires(TestPrecondition.JDK_IBM)
+ def "super types ordered by their distance on IBMs jdk"() {
+ expect:
+ ClassInspector.inspect(ArrayList).superTypes.toList() == [AbstractList, AbstractCollection, List, Cloneable, Serializable, RandomAccess, Collection, Iterable]
+ }
+
+ @Issue("GRADLE-3317")
+ def "method for property getter is for nearest declaration"() {
+ expect:
+ def details = ClassInspector.inspect(clazz)
+ def getters = details.getProperty('inputs').getGetters()
+ getters[0].getDeclaringClass() == declaringClass
+
+ where:
+ clazz | declaringClass
+ ImplementingRootClassSubSubImplementsRootInterfaceSub | ImplementingRootClassSub
+ ExtendsImplementingRootClassSubSubImplementsRootInterfaceSub | ExtendsImplementingRootClassSubSubImplementsRootInterfaceSub
+ ExtendsImplementingRootClass | ImplementingRootClass
+ }
+
+ public interface RootInterface {
+ public String getInputs()
+ }
+
+ public interface RootInterfaceSub extends RootInterface {}
+
+ public class ImplementingRootClass implements RootInterface {
+ public String getInputs() { return "super" }
+ }
+
+ public class ImplementingRootClassSub extends ImplementingRootClass {
+ public String getInputs() { return "concrete" }
+ }
+
+ public class ImplementingRootClassSubSubImplementsRootInterfaceSub extends ImplementingRootClassSub implements RootInterfaceSub {}
+
+ public class ExtendsImplementingRootClassSubSubImplementsRootInterfaceSub extends ImplementingRootClassSubSubImplementsRootInterfaceSub {
+ public String getInputs() { return "override" }
+ }
+
+ public class ExtendsImplementingRootClass extends ImplementingRootClass {}
}
diff --git a/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/JavaReflectionUtilTest.groovy b/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/JavaReflectionUtilTest.groovy
index b95efea..2f3285a 100644
--- a/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/JavaReflectionUtilTest.groovy
+++ b/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/JavaReflectionUtilTest.groovy
@@ -99,6 +99,23 @@ class JavaReflectionUtilTest extends Specification {
readableField(JavaTestSubject, Boolean, "myBooleanField").getValue(myProperties) == true
}
+ def "set boolean field" () {
+ when:
+ writeableField(JavaTestSubject, "myBooleanField").setValue(myProperties, false)
+
+ then:
+ readableField(JavaTestSubject, Boolean, "myBooleanField").getValue(myProperties) == false
+ }
+
+ def "cannot set value on non public fields"(){
+ when:
+ writeableField(JavaTestSubject, "myBooleanProperty").setValue(myProperties, false)
+
+ then:
+ thrown(NoSuchPropertyException);
+ }
+
+
def "write boolean property"() {
when:
writeableProperty(JavaTestSubject, "myBooleanProperty").setValue(myProperties, false)
diff --git a/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/MethodDescriptionTest.groovy b/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/MethodDescriptionTest.groovy
index bba3972..19335e9 100644
--- a/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/MethodDescriptionTest.groovy
+++ b/subprojects/base-services/src/test/groovy/org/gradle/internal/reflect/MethodDescriptionTest.groovy
@@ -30,4 +30,15 @@ class MethodDescriptionTest extends Specification {
MethodDescription.name("a").returns(String).owner(String).takes(String, String).toString() == "java.lang.String java.lang.String#a(java.lang.String, java.lang.String)"
MethodDescription.name("a").owner(String).takes(String, String).toString() == "java.lang.String#a(java.lang.String, java.lang.String)"
}
+
+ def "inner class name format"() {
+ expect:
+ MethodDescription.name('a').owner(Outer.Inner).toString() == 'org.gradle.internal.reflect.MethodDescriptionTest$Outer$Inner#a'
+ }
+
+ class Outer {
+ static class Inner {
+
+ }
+ }
}
diff --git a/subprojects/build-init/src/main/groovy/org/gradle/buildinit/plugins/internal/BuildInitServices.java b/subprojects/build-init/src/main/groovy/org/gradle/buildinit/plugins/internal/BuildInitServices.java
index e646b1a..88af442 100644
--- a/subprojects/build-init/src/main/groovy/org/gradle/buildinit/plugins/internal/BuildInitServices.java
+++ b/subprojects/build-init/src/main/groovy/org/gradle/buildinit/plugins/internal/BuildInitServices.java
@@ -29,6 +29,9 @@ public class BuildInitServices implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
diff --git a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/AbstractFindBugsPluginIntegrationTest.groovy b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/AbstractFindBugsPluginIntegrationTest.groovy
index 29054ea..44f6362 100644
--- a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/AbstractFindBugsPluginIntegrationTest.groovy
+++ b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/AbstractFindBugsPluginIntegrationTest.groovy
@@ -185,7 +185,7 @@ abstract class AbstractFindBugsPluginIntegrationTest extends AbstractIntegration
then:
file("build/reports/findbugs/main.html").exists()
}
-
+
def "can generate xml with messages reports"() {
given:
buildFile << """
@@ -392,6 +392,48 @@ abstract class AbstractFindBugsPluginIntegrationTest extends AbstractIntegration
errorOutput.contains 'Caused by: java.lang.NoClassDefFoundError'
}
+ def "valid adjustPriority extra args"() {
+ given:
+ file("src/main/java/org/gradle/ClassUsingCaseConversion.java") <<
+ 'package org.gradle; public class ClassUsingCaseConversion { public boolean useConversion() { return "Hi".toUpperCase().equals("HI"); } }'
+
+ expect:
+ succeeds("check")
+
+ when:
+ // Test extraArgs using DM_CONVERT_CASE which FindBugs treats as a LOW confidence warning. We will use
+ // extraArgs to boost the confidence which should make it be reported
+ buildFile << """
+ findbugsMain {
+ extraArgs '-adjustPriority', 'DM_CONVERT_CASE=raise,DM_CONVERT_CASE=raise'
+ }
+ """
+
+ then:
+ fails("check")
+ failure.assertHasDescription("Execution failed for task ':findbugsMain'.")
+ failure.assertThatCause(startsWith("FindBugs rule violations were found. See the report at:"))
+ file("build/reports/findbugs/main.xml").exists()
+ file("build/reports/findbugs/main.xml").assertContents(containsClass("org.gradle.ClassUsingCaseConversion"))
+ file("build/reports/findbugs/main.xml").assertContents(containsString("DM_CONVERT_CASE"))
+ }
+
+ def "fails when given invalid extraArgs"() {
+ given:
+ goodCode()
+ and:
+ buildFile << """
+ findbugsMain {
+ extraArgs 'gobbledygook'
+ }
+ """
+
+ expect:
+ fails "check"
+ failure.assertHasCause 'FindBugs encountered an error.'
+ failure.assertHasDescription "Execution failed for task ':findbugsMain'."
+ }
+
private static boolean containsXmlMessages(File xmlReportFile) {
new XmlSlurper().parseText(xmlReportFile.text).BugInstance.children().collect { it.name() }.containsAll(['ShortMessage', 'LongMessage'])
}
diff --git a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginDependenciesIntegrationTest.groovy b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginDependenciesIntegrationTest.groovy
new file mode 100644
index 0000000..5e8013e
--- /dev/null
+++ b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginDependenciesIntegrationTest.groovy
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.plugins.quality
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+class CheckstylePluginDependenciesIntegrationTest extends AbstractIntegrationSpec {
+ def setup() {
+ writeBuildFile()
+ writeConfigFile()
+ badCode()
+ }
+
+ def "allows configuring tool dependencies explicitly"() {
+ expect:
+ succeeds("dependencies", "--configuration", "checkstyle")
+ output.contains "com.puppycrawl.tools:checkstyle:"
+
+ when:
+ buildFile << """
+ dependencies {
+ //downgrade version:
+ checkstyle "com.puppycrawl.tools:checkstyle:5.5"
+ }
+ """
+
+ then:
+ fails("check")
+ failure.error.contains("Name 'class1' must match pattern")
+
+ and:
+ succeeds("dependencies", "--configuration", "checkstyle")
+ output.contains "com.puppycrawl.tools:checkstyle:5.5"
+ }
+
+ private void writeBuildFile() {
+ file("build.gradle") << """
+apply plugin: "groovy"
+apply plugin: "checkstyle"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile localGroovy()
+}
+ """
+ }
+
+ private void writeConfigFile() {
+ file("config/checkstyle/checkstyle.xml") << """
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
+<module name="Checker">
+ <module name="TreeWalker">
+ <module name="TypeName"/>
+ </module>
+</module>
+ """
+ }
+
+ private void badCode() {
+ file("src/main/java/org/gradle/class1.java") << "package org.gradle; class class1 { }"
+ }
+}
diff --git a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginIntegrationTest.groovy b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginIntegrationTest.groovy
index e26d904..82685e8 100644
--- a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginIntegrationTest.groovy
+++ b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginIntegrationTest.groovy
@@ -14,15 +14,7 @@
* limitations under the License.
*/
package org.gradle.api.plugins.quality
-
import org.gradle.integtests.fixtures.WellBehavedPluginTest
-import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
-import org.hamcrest.Matcher
-import spock.lang.IgnoreIf
-
-import static org.gradle.util.Matchers.containsLine
-import static org.hamcrest.Matchers.containsString
-import static org.hamcrest.Matchers.startsWith
class CheckstylePluginIntegrationTest extends WellBehavedPluginTest {
@Override
@@ -31,162 +23,8 @@ class CheckstylePluginIntegrationTest extends WellBehavedPluginTest {
}
def setup() {
- writeBuildFile()
- writeConfigFile()
- }
-
- def "allows configuring tool dependencies explicitly"() {
- expect: //defaults exist and can be inspected
- succeeds("dependencies", "--configuration", "checkstyle")
- output.contains "com.puppycrawl.tools:checkstyle:"
-
- when:
- buildFile << """
- dependencies {
- //downgrade version:
- checkstyle "com.puppycrawl.tools:checkstyle:5.5"
- }
- """
-
- then:
- succeeds("dependencies", "--configuration", "checkstyle")
- output.contains "com.puppycrawl.tools:checkstyle:5.5"
- }
-
- def "analyze good code"() {
- goodCode()
-
- expect:
- succeeds('check')
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.Class1"))
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.Class2"))
- file("build/reports/checkstyle/test.xml").assertContents(containsClass("org.gradle.TestClass1"))
- file("build/reports/checkstyle/test.xml").assertContents(containsClass("org.gradle.TestClass2"))
- }
-
- def "analyze bad code"() {
- defaultLanguage('en')
- badCode()
-
- expect:
- fails("check")
- failure.assertHasDescription("Execution failed for task ':checkstyleMain'.")
- failure.assertThatCause(startsWith("Checkstyle rule violations were found. See the report at:"))
- failure.error.contains("Name 'class1' must match pattern")
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class1"))
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class2"))
- }
-
- def "can suppress console output"() {
- given:
- defaultLanguage('en')
- badCode()
-
- when:
- buildFile << "checkstyle { showViolations = false }"
-
- then:
- fails("check")
- failure.assertHasDescription("Execution failed for task ':checkstyleMain'.")
- failure.assertThatCause(startsWith("Checkstyle rule violations were found. See the report at:"))
- !failure.error.contains("Name 'class1' must match pattern")
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class1"))
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class2"))
- }
-
- def "can ignore failures"() {
- badCode()
buildFile << """
- checkstyle {
- ignoreFailures = true
- }
+ apply plugin: 'groovy'
"""
-
- expect:
- succeeds("check")
- output.contains("Checkstyle rule violations were found. See the report at:")
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class1"))
- file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class2"))
- }
-
- @IgnoreIf({GradleContextualExecuter.parallel})
- def "is incremental"() {
- given:
- goodCode()
-
- expect:
- succeeds("checkstyleMain") && ":checkstyleMain" in nonSkippedTasks
- executer.withArgument("-i")
- succeeds("checkstyleMain") && ":checkstyleMain" in skippedTasks
-
- when:
- file("build/reports/checkstyle/main.xml").delete()
-
- then:
- succeeds("checkstyleMain") && ":checkstyleMain" in nonSkippedTasks
- }
-
- def "can configure reporting"() {
- given:
- goodCode()
-
- when:
- buildFile << """
- checkstyleMain.reports { xml.destination "foo.xml" }
- """
-
- then:
- succeeds "checkstyleMain"
- file("foo.xml").exists()
- }
-
- private goodCode() {
- file('src/main/java/org/gradle/Class1.java') << 'package org.gradle; class Class1 { }'
- file('src/test/java/org/gradle/TestClass1.java') << 'package org.gradle; class TestClass1 { }'
- file('src/main/groovy/org/gradle/Class2.java') << 'package org.gradle; class Class2 { }'
- file('src/test/groovy/org/gradle/TestClass2.java') << 'package org.gradle; class TestClass2 { }'
- }
-
- private badCode() {
- file("src/main/java/org/gradle/class1.java") << "package org.gradle; class class1 { }"
- file("src/test/java/org/gradle/testclass1.java") << "package org.gradle; class testclass1 { }"
- file("src/main/groovy/org/gradle/class2.java") << "package org.gradle; class class2 { }"
- file("src/test/groovy/org/gradle/testclass2.java") << "package org.gradle; class testclass2 { }"
- }
-
- private Matcher<String> containsClass(String className) {
- containsLine(containsString(className.replace(".", File.separator)))
- }
-
- private void writeBuildFile() {
- file("build.gradle") << """
-apply plugin: "groovy"
-apply plugin: "checkstyle"
-
-repositories {
- mavenCentral()
-}
-
-dependencies {
- compile localGroovy()
-}
- """
- }
-
- private void writeConfigFile() {
- file("config/checkstyle/checkstyle.xml") << """
-<!DOCTYPE module PUBLIC
- "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
- "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
-<module name="Checker">
- <module name="TreeWalker">
- <module name="TypeName"/>
- </module>
-</module>
- """
- }
-
- private void defaultLanguage(String defaultLanguage) {
- executer.withDefaultLocale(new Locale(defaultLanguage))
}
}
diff --git a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginVersionIntegrationTest.groovy b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginVersionIntegrationTest.groovy
new file mode 100644
index 0000000..0127132
--- /dev/null
+++ b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/CheckstylePluginVersionIntegrationTest.groovy
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.plugins.quality
+import org.gradle.api.JavaVersion
+import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
+import org.gradle.quality.integtest.fixtures.CheckstyleCoverage
+import org.hamcrest.Matcher
+import spock.lang.IgnoreIf
+
+import static org.gradle.util.Matchers.containsLine
+import static org.hamcrest.Matchers.*
+
+ at TargetCoverage({ JavaVersion.current().isJava6() ? CheckstyleCoverage.JDK6_SUPPORTED : CheckstyleCoverage.ALL})
+class CheckstylePluginVersionIntegrationTest extends MultiVersionIntegrationSpec {
+
+ def setup() {
+ writeBuildFile()
+ writeConfigFile()
+ }
+
+ def "analyze good code"() {
+ goodCode()
+
+ expect:
+ succeeds('check')
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.Class1"))
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.Class2"))
+ file("build/reports/checkstyle/test.xml").assertContents(containsClass("org.gradle.TestClass1"))
+ file("build/reports/checkstyle/test.xml").assertContents(containsClass("org.gradle.TestClass2"))
+ }
+
+ def "analyze bad code"() {
+ defaultLanguage('en')
+ badCode()
+
+ expect:
+ fails("check")
+ failure.assertHasDescription("Execution failed for task ':checkstyleMain'.")
+ failure.assertThatCause(startsWith("Checkstyle rule violations were found. See the report at:"))
+ failure.error.contains("Name 'class1' must match pattern")
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class1"))
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class2"))
+ }
+
+ def "can suppress console output"() {
+ given:
+ defaultLanguage('en')
+ badCode()
+
+ when:
+ buildFile << "checkstyle { showViolations = false }"
+
+ then:
+ fails("check")
+ failure.assertHasDescription("Execution failed for task ':checkstyleMain'.")
+ failure.assertThatCause(startsWith("Checkstyle rule violations were found. See the report at:"))
+ !failure.error.contains("Name 'class1' must match pattern")
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class1"))
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class2"))
+ }
+
+ def "can ignore failures"() {
+ badCode()
+ buildFile << """
+ checkstyle {
+ ignoreFailures = true
+ }
+ """
+
+ expect:
+ succeeds("check")
+ output.contains("Checkstyle rule violations were found. See the report at:")
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class1"))
+ file("build/reports/checkstyle/main.xml").assertContents(containsClass("org.gradle.class2"))
+ }
+
+ @IgnoreIf({GradleContextualExecuter.parallel})
+ def "is incremental"() {
+ given:
+ goodCode()
+
+ expect:
+ succeeds("checkstyleMain") && ":checkstyleMain" in nonSkippedTasks
+ executer.withArgument("-i")
+ succeeds("checkstyleMain") && ":checkstyleMain" in skippedTasks
+
+ when:
+ file("build/reports/checkstyle/main.xml").delete()
+
+ then:
+ succeeds("checkstyleMain") && ":checkstyleMain" in nonSkippedTasks
+ }
+
+ def "can configure reporting"() {
+ given:
+ goodCode()
+
+ when:
+ buildFile << """
+ checkstyleMain.reports { xml.destination "foo.xml" }
+ """
+
+ then:
+ succeeds "checkstyleMain"
+ file("foo.xml").exists()
+ }
+
+ private goodCode() {
+ file('src/main/java/org/gradle/Class1.java') << 'package org.gradle; class Class1 { }'
+ file('src/test/java/org/gradle/TestClass1.java') << 'package org.gradle; class TestClass1 { }'
+ file('src/main/groovy/org/gradle/Class2.java') << 'package org.gradle; class Class2 { }'
+ file('src/test/groovy/org/gradle/TestClass2.java') << 'package org.gradle; class TestClass2 { }'
+ }
+
+ private badCode() {
+ file("src/main/java/org/gradle/class1.java") << "package org.gradle; class class1 { }"
+ file("src/test/java/org/gradle/testclass1.java") << "package org.gradle; class testclass1 { }"
+ file("src/main/groovy/org/gradle/class2.java") << "package org.gradle; class class2 { }"
+ file("src/test/groovy/org/gradle/testclass2.java") << "package org.gradle; class testclass2 { }"
+ }
+
+ private Matcher<String> containsClass(String className) {
+ containsLine(containsString(className.replace(".", File.separator)))
+ }
+
+ private void defaultLanguage(String defaultLanguage) {
+ executer.withDefaultLocale(new Locale(defaultLanguage))
+ }
+
+ private void writeBuildFile() {
+ file("build.gradle") << """
+apply plugin: "groovy"
+apply plugin: "checkstyle"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile localGroovy()
+}
+
+checkstyle {
+ toolVersion = '$version'
+}
+ """
+ }
+
+ private void writeConfigFile() {
+ file("config/checkstyle/checkstyle.xml") << """
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
+<module name="Checker">
+ <module name="TreeWalker">
+ <module name="TypeName"/>
+ </module>
+</module>
+ """
+ }
+}
diff --git a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/internal/FindBugsSpecBuilderTest.groovy b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/internal/FindBugsSpecBuilderTest.groovy
index faf4b9e..ae376cb 100644
--- a/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/internal/FindBugsSpecBuilderTest.groovy
+++ b/subprojects/code-quality/src/integTest/groovy/org/gradle/api/plugins/quality/internal/FindBugsSpecBuilderTest.groovy
@@ -124,7 +124,7 @@ class FindBugsSpecBuilderTest extends Specification {
where:
reportType << ["xml", "html", "emacs", "text"]
}
-
+
def "with xml with messages report configured"() {
setup:
FindBugsXmlReportImpl singleReport = Mock()
@@ -150,7 +150,7 @@ class FindBugsSpecBuilderTest extends Specification {
args.contains(arg.toString())
args.contains("-outputFile")
args.contains(destination.absolutePath)
-
+
where:
withMessages << [true, false]
arg << ['-xml:withMessages', '-xml']
@@ -229,4 +229,12 @@ class FindBugsSpecBuilderTest extends Specification {
then:
args.contains("-exclude $file")
}
+
+ def "with extra args"() {
+ when:
+ def args = builder.withExtraArgs([ 'abc', 'def' ]).build().arguments
+
+ then:
+ args.containsAll([ "abc", "def" ])
+ }
}
diff --git a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.groovy b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.groovy
index 288eacc..893f3ff 100644
--- a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.groovy
+++ b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.groovy
@@ -136,8 +136,12 @@ class Checkstyle extends SourceTask implements VerificationTask, Reporting<Check
@TaskAction
public void run() {
def propertyName = "org.gradle.checkstyle.violations"
- antBuilder.withClasspath(getCheckstyleClasspath()).execute {
- ant.taskdef(name: 'checkstyle', classname: 'com.puppycrawl.tools.checkstyle.CheckStyleTask')
+ antBuilder.withClasspath(getCheckstyleClasspath()).execute {
+ try {
+ ant.taskdef(name: 'checkstyle', classname: 'com.puppycrawl.tools.checkstyle.CheckStyleTask')
+ } catch (ClassNotFoundException cnfe) {
+ ant.taskdef(name: 'checkstyle', classname: 'com.puppycrawl.tools.checkstyle.ant.CheckstyleAntTask')
+ }
ant.checkstyle(config: getConfig().asFile(), failOnViolation: false, failureProperty: propertyName) {
getSource().addToAntBuilder(ant, 'fileset', FileCollection.AntType.FileSet)
diff --git a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstylePlugin.groovy b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstylePlugin.groovy
index 3daf583..4e9b18e 100644
--- a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstylePlugin.groovy
+++ b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstylePlugin.groovy
@@ -14,7 +14,6 @@
* limitations under the License.
*/
package org.gradle.api.plugins.quality
-
import org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin
import org.gradle.api.tasks.SourceSet
diff --git a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstyleReports.java b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstyleReports.java
index d4d493a..cffd5a5 100644
--- a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstyleReports.java
+++ b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/CheckstyleReports.java
@@ -20,7 +20,7 @@ import org.gradle.api.reporting.ReportContainer;
import org.gradle.api.reporting.SingleFileReport;
/**
- * The reporting configuration for the {@link Checkstyle} test.
+ * The reporting configuration for the {@link Checkstyle} task.
*/
public interface CheckstyleReports extends ReportContainer<SingleFileReport> {
diff --git a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugs.groovy b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugs.groovy
index 5adf484..4151059 100644
--- a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugs.groovy
+++ b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugs.groovy
@@ -139,6 +139,21 @@ class FindBugs extends SourceTask implements VerificationTask, Reporting<FindBug
@Optional
TextResource excludeBugsFilterConfig
+ /**
+ * Any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to FindBugs.
+ * <p>
+ * Extra arguments are passed to FindBugs after the arguments Gradle understands (like {@code effort} but before the list of classes to analyze.
+ * This should only be used for arguments that cannot be provided by Gradle directly. Gradle does not try to interpret or validate the arguments
+ * before passing them to FindBugs.
+ * <p>
+ * See the <a href="https://code.google.com/p/findbugs/source/browse/findbugs/src/java/edu/umd/cs/findbugs/TextUICommandLine.java">FindBugs TextUICommandLine source</a> for available options.
+ *
+ * @since 2.6
+ */
+ @Input
+ @Optional
+ Collection<String> extraArgs = []
+
@Nested
private final FindBugsReportsImpl reports
@@ -261,6 +276,7 @@ class FindBugs extends SourceTask implements VerificationTask, Reporting<FindBug
.withExcludeFilter(getExcludeFilter())
.withIncludeFilter(getIncludeFilter())
.withExcludeBugsFilter(getExcludeBugsFilter())
+ .withExtraArgs(getExtraArgs())
.configureReports(getReports())
return specBuilder.build()
@@ -291,4 +307,16 @@ class FindBugs extends SourceTask implements VerificationTask, Reporting<FindBug
}
}
}
-}
\ No newline at end of file
+
+ public FindBugs extraArgs(Iterable<String> arguments) {
+ for ( String argument : arguments ) {
+ extraArgs.add(argument);
+ }
+ return this;
+ }
+
+ public FindBugs extraArgs(String... arguments) {
+ extraArgs.addAll( Arrays.asList(arguments) );
+ return this;
+ }
+}
diff --git a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsExtension.groovy b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsExtension.groovy
index a186abd..38a5b6d 100644
--- a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsExtension.groovy
+++ b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsExtension.groovy
@@ -105,6 +105,19 @@ class FindBugsExtension extends CodeQualityExtension {
TextResource excludeBugsFilterConfig
/**
+ * Any additional arguments (not covered here more explicitly like {@code effort}) to be passed along to FindBugs.
+ * <p>
+ * Extra arguments are passed to FindBugs after the arguments Gradle understands (like {@code effort} but before the list of classes to analyze.
+ * This should only be used for arguments that cannot be provided by Gradle directly. Gradle does not try to interpret or validate the arguments
+ * before passing them to FindBugs.
+ * <p>
+ * See the <a href="https://code.google.com/p/findbugs/source/browse/findbugs/src/java/edu/umd/cs/findbugs/TextUICommandLine.java">FindBugs TextUICommandLine source</a> for available options.
+ *
+ * @since 2.6
+ */
+ Collection<String> extraArgs
+
+ /**
* The filename of a filter specifying which bugs are reported.
*/
File getIncludeFilter() {
diff --git a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsPlugin.groovy b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsPlugin.groovy
index 29a8a47..6da025e 100644
--- a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsPlugin.groovy
+++ b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/FindBugsPlugin.groovy
@@ -83,10 +83,12 @@ class FindBugsPlugin extends AbstractCodeQualityPlugin<FindBugs> {
reportLevel = { extension.reportLevel }
visitors = { extension.visitors }
omitVisitors = { extension.omitVisitors }
+
excludeFilterConfig = { extension.excludeFilterConfig }
includeFilterConfig = { extension.includeFilterConfig }
excludeBugsFilterConfig = { extension.excludeBugsFilterConfig }
+ extraArgs = { extension.extraArgs }
}
task.reports.all { Report report ->
report.conventionMapping.with {
diff --git a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/internal/findbugs/FindBugsSpecBuilder.java b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/internal/findbugs/FindBugsSpecBuilder.java
index c7946a8..4c69758 100644
--- a/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/internal/findbugs/FindBugsSpecBuilder.java
+++ b/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/internal/findbugs/FindBugsSpecBuilder.java
@@ -16,11 +16,7 @@
package org.gradle.api.plugins.quality.internal.findbugs;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Set;
-
+import com.google.common.collect.ImmutableSet;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.quality.FindBugsReports;
@@ -28,7 +24,10 @@ import org.gradle.api.plugins.quality.internal.FindBugsReportsImpl;
import org.gradle.api.specs.Spec;
import org.gradle.util.CollectionUtils;
-import com.google.common.collect.ImmutableSet;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
public class FindBugsSpecBuilder {
private static final Set<String> VALID_EFFORTS = ImmutableSet.of("min", "default", "max");
@@ -48,6 +47,7 @@ public class FindBugsSpecBuilder {
private File excludeFilter;
private File includeFilter;
private File excludeBugsFilter;
+ private Collection<String> extraArgs;
private boolean debugEnabled;
public FindBugsSpecBuilder(FileCollection classes) {
@@ -93,7 +93,7 @@ public class FindBugsSpecBuilder {
this.reportLevel = reportLevel;
return this;
}
-
+
public FindBugsSpecBuilder withMaxHeapSize(String maxHeapSize) {
this.maxHeapSize = maxHeapSize;
return this;
@@ -136,6 +136,12 @@ public class FindBugsSpecBuilder {
}
this.excludeBugsFilter = excludeBugsFilter;
+
+ return this;
+ }
+
+ public FindBugsSpecBuilder withExtraArgs(Collection<String> extraArgs) {
+ this.extraArgs = extraArgs;
return this;
}
@@ -219,10 +225,14 @@ public class FindBugsSpecBuilder {
args.add(excludeBugsFilter.getPath());
}
+ if (has(extraArgs)) {
+ args.addAll(extraArgs);
+ }
+
for (File classFile : classes.getFiles()) {
args.add(classFile.getAbsolutePath());
}
-
+
return new FindBugsSpec(args, maxHeapSize, debugEnabled);
}
diff --git a/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/CheckstylePluginTest.groovy b/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/CheckstylePluginTest.groovy
index 613b5bf..740bbe1 100644
--- a/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/CheckstylePluginTest.groovy
+++ b/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/CheckstylePluginTest.groovy
@@ -38,17 +38,17 @@ class CheckstylePluginTest extends Specification {
expect:
project.plugins.hasPlugin(ReportingBasePlugin)
}
-
+
def "configures checkstyle configuration"() {
- def config = project.configurations.findByName("checkstyle")
-
+ def config = project.configurations.findByName("checkstyle")
+
expect:
config != null
!config.visible
config.transitive
config.description == 'The Checkstyle libraries to be used for this project.'
}
-
+
def "configures checkstyle extension"() {
expect:
CheckstyleExtension extension = project.extensions.checkstyle
@@ -88,7 +88,7 @@ class CheckstylePluginTest extends Specification {
assert showViolations
}
}
-
+
def "configures any additional checkstyle tasks"() {
def task = project.tasks.create("checkstyleCustom", Checkstyle)
@@ -110,11 +110,11 @@ class CheckstylePluginTest extends Specification {
test
other
}
-
+
expect:
that(project.tasks['check'], dependsOn(hasItems("checkstyleMain", "checkstyleTest", "checkstyleOther")))
}
-
+
def "can customize settings via extension"() {
project.pluginManager.apply(JavaBasePlugin)
project.sourceSets {
@@ -122,7 +122,7 @@ class CheckstylePluginTest extends Specification {
test
other
}
-
+
project.checkstyle {
sourceSets = [project.sourceSets.main]
config = project.resources.text.fromFile("checkstyle-config")
@@ -131,7 +131,7 @@ class CheckstylePluginTest extends Specification {
ignoreFailures = true
showViolations = true
}
-
+
expect:
hasCustomizedSettings("checkstyleMain", project.sourceSets.main)
hasCustomizedSettings("checkstyleTest", project.sourceSets.test)
diff --git a/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsPluginTest.groovy b/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsPluginTest.groovy
index 7990629..7c1fa08 100644
--- a/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsPluginTest.groovy
+++ b/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsPluginTest.groovy
@@ -100,6 +100,7 @@ class FindBugsPluginTest extends Specification {
excludeFilter == null
includeFilter == null
excludeBugsFilter == null
+ extraArgs == null
}
}
@@ -126,6 +127,7 @@ class FindBugsPluginTest extends Specification {
excludeFilter == null
includeFilter == null
excludeBugsFilter == null
+ extraArgs == null
}
}
@@ -160,6 +162,7 @@ class FindBugsPluginTest extends Specification {
includeFilter = new File("include.txt")
excludeFilter = new File("exclude.txt")
excludeBugsFilter = new File("baselineBugs.txt")
+ extraArgs = [ '-adjustPriority', 'DM_CONVERT_CASE=raise,DM_CONVERT_CASE=raise']
}
expect:
@@ -189,9 +192,10 @@ class FindBugsPluginTest extends Specification {
includeFilter == project.file("include.txt")
excludeFilter == project.file("exclude.txt")
excludeBugsFilter == project.file("baselineBugs.txt")
+ extraArgs == [ '-adjustPriority', 'DM_CONVERT_CASE=raise,DM_CONVERT_CASE=raise' ]
}
}
-
+
def "can customize any additional FindBugs tasks via extension"() {
def task = project.tasks.create("findbugsCustom", FindBugs)
project.findbugs {
@@ -204,6 +208,7 @@ class FindBugsPluginTest extends Specification {
includeFilterConfig = project.resources.text.fromFile("include.txt")
excludeFilterConfig = project.resources.text.fromFile("exclude.txt")
excludeBugsFilterConfig = project.resources.text.fromFile("baselineBugs.txt")
+ extraArgs = [ '-adjustPriority', 'DM_CONVERT_CASE=raise,DM_CONVERT_CASE=raise' ]
}
expect:
@@ -226,6 +231,7 @@ class FindBugsPluginTest extends Specification {
includeFilter == project.file("include.txt")
excludeFilter == project.file("exclude.txt")
excludeBugsFilter == project.file("baselineBugs.txt")
+ extraArgs == [ '-adjustPriority', 'DM_CONVERT_CASE=raise,DM_CONVERT_CASE=raise' ]
}
}
diff --git a/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsTest.groovy b/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsTest.groovy
index 06bd2c2..6c29d0d 100644
--- a/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsTest.groovy
+++ b/subprojects/code-quality/src/test/groovy/org/gradle/api/plugins/quality/FindBugsTest.groovy
@@ -126,4 +126,21 @@ class FindBugsTest extends Specification {
findbugs.excludeBugsFilter == project.file("config/file.txt")
findbugs.excludeBugsFilterConfig.inputFiles.singleFile == project.file("config/file.txt")
}
+
+ def "can add extra args"() {
+ given:
+ findbugs.extraArgs = [ 'abc' ]
+ expect:
+ findbugs.extraArgs == [ 'abc' ]
+
+ when:
+ findbugs.extraArgs 'def'
+ then:
+ findbugs.extraArgs == [ 'abc', 'def' ]
+
+ when:
+ findbugs.extraArgs([ 'ghi', 'jkl' ])
+ then:
+ findbugs.extraArgs == [ 'abc', 'def', 'ghi', 'jkl' ]
+ }
}
diff --git a/subprojects/code-quality/src/testFixtures/groovy/org/gradle/quality/integtest/fixtures/CheckstyleCoverage.groovy b/subprojects/code-quality/src/testFixtures/groovy/org/gradle/quality/integtest/fixtures/CheckstyleCoverage.groovy
new file mode 100644
index 0000000..69dcb54
--- /dev/null
+++ b/subprojects/code-quality/src/testFixtures/groovy/org/gradle/quality/integtest/fixtures/CheckstyleCoverage.groovy
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.quality.integtest.fixtures
+
+import org.gradle.api.plugins.quality.CheckstylePlugin
+import org.gradle.util.VersionNumber
+
+class CheckstyleCoverage {
+ // Note, this only work for major.minor versions
+ final static List<String> ALL = ['6.9', '6.8', '6.5', '6.0', '5.5', CheckstylePlugin.DEFAULT_CHECKSTYLE_VERSION].asImmutable()
+
+ final static List<VersionNumber> ALL_VERSIONS = ALL.collect { VersionNumber.parse(it) }
+ // JDK6 support was dropped in 6.2
+ final static List<String> JDK6_SUPPORTED = ALL_VERSIONS.findAll({ it < VersionNumber.parse("6.2") }).collect({ "${it.major}.${it.minor}" }).asImmutable()
+}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/BuildScriptErrorIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/BuildScriptErrorIntegrationTest.groovy
index f4df3c8..6535c7a 100755
--- a/subprojects/core/src/integTest/groovy/org/gradle/api/BuildScriptErrorIntegrationTest.groovy
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/BuildScriptErrorIntegrationTest.groovy
@@ -95,4 +95,33 @@ include 'child'
.assertHasFileName("Build file '$childBuildFile'")
.assertHasLineNumber(3)
}
+
+ def "produces reasonable error message from a method inherited from a script containing only methods"() {
+ settingsFile << """
+include 'child'
+"""
+ buildFile << """
+// Build script contains only methods
+def broken() {
+ throw new RuntimeException('failure')
+}
+
+def doSomething() {
+ broken()
+}
+"""
+ final childBuildFile = file("child/build.gradle")
+ childBuildFile << """
+ doSomething()
+"""
+
+ when:
+ fails()
+
+ then:
+ failure.assertHasDescription("A problem occurred evaluating project ':child'.")
+ .assertHasCause("failure")
+ .assertHasFileName("Build file '$buildFile'")
+ .assertHasLineNumber(4)
+ }
}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/ProgressLoggingIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/ProgressLoggingIntegrationTest.groovy
new file mode 100644
index 0000000..d7c7a83
--- /dev/null
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/ProgressLoggingIntegrationTest.groovy
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.executer.ProgressLoggingFixture
+
+class ProgressLoggingIntegrationTest extends AbstractIntegrationSpec {
+ @org.junit.Rule
+ ProgressLoggingFixture events = new ProgressLoggingFixture(executer, temporaryFolder)
+
+ def "generates progress events during build"() {
+ when:
+ run()
+
+ then:
+ events.progressLogged("Configure settings")
+ events.progressLogged("Configure projects")
+ events.progressLogged("Configure project :")
+ events.progressLogged("Execute tasks")
+ events.progressLogged("Execute :help")
+ }
+
+ def "generates buildSrc progress events when there is a nested buildSrc build"() {
+ when:
+ run()
+
+ then:
+ !events.progressLogged("Build buildSrc")
+
+ when:
+ file("buildSrc/build.gradle") << "println 'buildSrc'"
+ run()
+
+ then:
+ events.progressLogged("Build buildSrc")
+ }
+}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/dsl/BuildScriptVisibilityIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/dsl/BuildScriptVisibilityIntegrationTest.groovy
new file mode 100644
index 0000000..b0e0bb4
--- /dev/null
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/dsl/BuildScriptVisibilityIntegrationTest.groovy
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.dsl
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+class BuildScriptVisibilityIntegrationTest extends AbstractIntegrationSpec {
+ def "methods defined in project build script are visible to descendant projects"() {
+ settingsFile << "include 'child1'"
+ buildFile << """
+def doSomething(def value) {
+ return "{" + value + "}"
+}
+private String doSomethingElse(def value) {
+ return "[" + value + "]"
+}
+println "root: " + doSomething(10)
+println "root: " + doSomethingElse(10)
+"""
+ file("child1/build.gradle") << """
+println "child: " + doSomething(11)
+println "child: " + doSomethingElse(11)
+"""
+
+ expect:
+ // Invoke twice to exercise script caching
+ succeeds()
+ outputContains("root: {10}")
+ outputContains("root: [10]")
+ outputContains("child: {11}")
+ outputContains("child: [11]")
+
+ and:
+ succeeds()
+ outputContains("root: {10}")
+ outputContains("root: [10]")
+ outputContains("child: {11}")
+ outputContains("child: [11]")
+ }
+
+ def "methods defined in project build script are visible to script plugins applied to project and descendants"() {
+ settingsFile << "include 'child1'"
+ buildFile << """
+def doSomething(def value) {
+ return "{" + value + "}"
+}
+private String doSomethingElse(def value) {
+ return "[" + value + "]"
+}
+apply from: 'script.gradle'
+"""
+ file("child1/build.gradle") << """
+apply from: '../script.gradle'
+"""
+ file("script.gradle") << """
+println project.path + " - " + doSomething(12)
+println project.path + " - " + doSomethingElse(12)
+"""
+
+ expect:
+ // Invoke twice to exercise script caching
+ succeeds()
+ outputContains(": - {12}")
+ outputContains(": - [12]")
+ outputContains(":child1 - {12}")
+ outputContains(":child1 - [12]")
+
+ and:
+ succeeds()
+ outputContains(": - {12}")
+ outputContains(": - [12]")
+ outputContains(":child1 - {12}")
+ outputContains(":child1 - [12]")
+ }
+
+ def "methods defined in project build script are visible to descendant projects when script contains only methods"() {
+ settingsFile << "include 'child1'"
+ buildFile << """
+def doSomething(def value) {
+ return value.toString()
+}
+"""
+ file("child1/build.gradle") << """
+println "child: " + doSomething(11)
+"""
+
+ expect:
+ // Invoke twice to exercise script caching
+ succeeds()
+ outputContains("child: 11")
+
+ and:
+ succeeds()
+ outputContains("child: 11")
+ }
+
+ def "methods defined in project build script are visible to descendant projects when script contains only methods and model block"() {
+ settingsFile << "include 'child1'"
+ buildFile << """
+def doSomething(def value) {
+ return value.toString()
+}
+
+model {
+ tasks {
+ hello(Task)
+ }
+}
+"""
+ file("child1/build.gradle") << """
+println "child: " + doSomething(11)
+"""
+
+ expect:
+ // Invoke twice to exercise script caching
+ succeeds("hello")
+ outputContains("child: 11")
+
+ and:
+ succeeds("hello")
+ outputContains("child: 11")
+ }
+
+ def "properties defined in project build script are not visible to descendant projects"() {
+ settingsFile << "include 'child1'"
+ buildFile << """
+def getProp1() {
+ return "abc"
+}
+
+ at groovy.transform.Field
+String prop2
+
+ at groovy.transform.Field
+String prop3 = "abc"
+
+int prop4 = 12
+
+prop2 = prop1
+
+assert prop1 == "abc"
+assert prop2 == "abc"
+assert prop3 == "abc"
+assert prop4 == 12
+"""
+ file("child1/build.gradle") << """
+try {
+ prop1
+ assert false
+} catch(MissingPropertyException e) {
+ assert e.property == 'prop1'
+}
+try {
+ prop2
+ assert false
+} catch(MissingPropertyException e) {
+ assert e.property == 'prop2'
+}
+try {
+ prop3
+ assert false
+} catch(MissingPropertyException e) {
+ assert e.property == 'prop3'
+}
+try {
+ prop4
+ assert false
+} catch(MissingPropertyException e) {
+ assert e.property == 'prop4'
+}
+println "child1 ok"
+"""
+
+ expect:
+ // Invoke twice to exercise script caching
+ succeeds()
+ outputContains("child1 ok")
+
+ and:
+ succeeds()
+ outputContains("child1 ok")
+ }
+
+ def "properties defined in project build script are not visible to script plugins"() {
+ settingsFile << "include 'child1'"
+ buildFile << """
+def getProp1() {
+ return "abc"
+}
+
+ at groovy.transform.Field
+String prop2
+
+prop2 = prop1
+
+assert prop1 == "abc"
+assert prop2 == "abc"
+apply from: 'script.gradle'
+"""
+ file("child1/build.gradle") << """
+apply from: '../script.gradle'
+"""
+
+ file("script.gradle") << """
+try {
+ prop1
+ assert false
+} catch(MissingPropertyException e) {
+ assert e.property == 'prop1'
+}
+try {
+ prop2
+ assert false
+} catch(MissingPropertyException e) {
+ assert e.property == 'prop2'
+}
+println project.path + " ok"
+"""
+
+ expect:
+ // Invoke twice to exercise script caching
+ succeeds()
+ outputContains(": ok")
+ outputContains(":child1 ok")
+
+ and:
+ succeeds()
+ outputContains(": ok")
+ outputContains(":child1 ok")
+ }
+}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/dsl/DynamicObjectIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/dsl/DynamicObjectIntegrationTest.groovy
index ab940d2..421724f 100644
--- a/subprojects/core/src/integTest/groovy/org/gradle/api/dsl/DynamicObjectIntegrationTest.groovy
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/dsl/DynamicObjectIntegrationTest.groovy
@@ -132,6 +132,7 @@ extensions.test = new ExtensionBean()
assert test instanceof ExtensionBean
test { it ->
+ assert it instanceof ExtensionBean
assert it == project.test
}
class ExtensionBean {
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/internal/initialization/loadercache/ClassLoadersCachingIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/internal/initialization/loadercache/ClassLoadersCachingIntegrationTest.groovy
index bf48246..c04d30a 100644
--- a/subprojects/core/src/integTest/groovy/org/gradle/api/internal/initialization/loadercache/ClassLoadersCachingIntegrationTest.groovy
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/internal/initialization/loadercache/ClassLoadersCachingIntegrationTest.groovy
@@ -18,8 +18,10 @@ package org.gradle.api.internal.initialization.loadercache
import org.gradle.integtests.fixtures.PersistentBuildProcessIntegrationTest
import org.gradle.integtests.fixtures.executer.ExecutionResult
+import org.gradle.test.fixtures.file.LeaksFileHandles
import spock.lang.Ignore
+ at LeaksFileHandles
class ClassLoadersCachingIntegrationTest extends PersistentBuildProcessIntegrationTest {
def cacheSizePerRun = []
@@ -205,7 +207,7 @@ class ClassLoadersCachingIntegrationTest extends PersistentBuildProcessIntegrati
assertCacheDidNotGrow()
}
- def "cache shrinks when buildscript disappears"() {
+ def "cache shrinks as buildscript disappears"() {
addIsCachedCheck()
file("foo.jar") << "foo"
buildFile << """
@@ -234,6 +236,29 @@ class ClassLoadersCachingIntegrationTest extends PersistentBuildProcessIntegrati
assertCacheSizeChange(-1)
}
+ def "cache shrinks when script with buildscript block is removed"() {
+ addIsCachedCheck()
+ file("foo.jar") << "foo"
+ buildFile << """
+ buildscript { dependencies { classpath files("foo.jar") } }
+
+ task foo
+ """
+
+ when:
+ run()
+ run()
+
+ then:
+ isCached()
+ assertCacheSizeChange(0)
+
+ then:
+ buildFile.delete()
+ run()
+ assertCacheSizeChange(-3)
+ }
+
def "refreshes when root project buildscript classpath changes"() {
settingsFile << "include 'foo'"
addIsCachedCheck()
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/internal/project/taskfactory/TaskFactoryIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/internal/project/taskfactory/TaskFactoryIntegrationTest.groovy
new file mode 100644
index 0000000..53358b7
--- /dev/null
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/internal/project/taskfactory/TaskFactoryIntegrationTest.groovy
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.project.taskfactory
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import spock.lang.Issue
+
+class TaskFactoryIntegrationTest extends AbstractIntegrationSpec {
+ @Issue("GRADLE-3317")
+ def "can generate a task when the inject annotation is not present on all of the methods in the hierarchy"() {
+ given:
+ buildFile << """
+ //getInputs() and getOutputs() exists on both org.gradle.api.Task and org.gradle.api.internal.AbstractTask
+ //Only AbstractTask has the @Inject annotation
+
+ public interface BinaryFileProviderTask extends Task {}
+ public class AndroidJarTask extends org.gradle.jvm.tasks.Jar implements BinaryFileProviderTask {}
+
+ task droidTask(type: AndroidJarTask) {}
+ """
+ expect:
+ succeeds "help"
+ }
+}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/CopyTaskIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/CopyTaskIntegrationTest.groovy
index 2d77711..6da13c0 100644
--- a/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/CopyTaskIntegrationTest.groovy
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/CopyTaskIntegrationTest.groovy
@@ -704,4 +704,33 @@ public class CopyTaskIntegrationTest extends AbstractIntegrationTest {
file('dest').assertHasDescendants('bcd.txt', 'abc.log')
file('dest/abc.log').text = 'content'
}
+
+ @Test
+ public void testSingleLineRemoved() {
+ TestFile buildFile = testFile('build.gradle') << '''
+ task (copy, type:Copy) {
+ from "src/two/two.b"
+ into "dest"
+ def lineNumber = 1
+ filter { lineNumber++ % 2 == 0 ? null : it }
+ }'''
+ usingBuildFile(buildFile).withTasks('copy').run()
+ Iterator<String> it = testFile('dest/two.b').readLines().iterator()
+ assertThat(it.next(), startsWith('one'))
+ assertThat(it.next(), startsWith('three'))
+ }
+
+ @Test
+ public void testAllLinesRemoved() {
+ TestFile buildFile = testFile('build.gradle') << '''
+ task (copy, type:Copy) {
+ from "src/two/two.b"
+ into "dest"
+ def lineNumber = 1
+ filter { null }
+ }'''
+ usingBuildFile(buildFile).withTasks('copy').run()
+ Iterator<String> it = testFile('dest/two.b').readLines().iterator()
+ assertFalse(it.hasNext())
+ }
}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/TaskRemovalIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/TaskRemovalIntegrationTest.groovy
index f1f3651..a49ed02 100644
--- a/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/TaskRemovalIntegrationTest.groovy
+++ b/subprojects/core/src/integTest/groovy/org/gradle/api/tasks/TaskRemovalIntegrationTest.groovy
@@ -78,7 +78,7 @@ class TaskRemovalIntegrationTest extends AbstractIntegrationSpec {
fails "dependencies"
then:
- failure.assertThatCause(Matchers.startsWith("The following model rules are unbound"))
+ failure.assertThatCause(Matchers.startsWith("The following model rules could not be applied"))
where:
annotationClass << ["Defaults", "Mutate", "Finalize", "Validate"]
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/RuleBasedTaskActionsIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/RuleBasedTaskActionsIntegrationTest.groovy
new file mode 100644
index 0000000..33eccee
--- /dev/null
+++ b/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/RuleBasedTaskActionsIntegrationTest.groovy
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.execution.taskgraph
+
+import groovy.transform.NotYetImplemented
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+class RuleBasedTaskActionsIntegrationTest extends AbstractIntegrationSpec implements WithRuleBasedTasks {
+
+ @NotYetImplemented
+ def "actions are applied to a rule-source task using all task action constructs"() {
+ given:
+ buildFile << """
+ class OverruleTask extends EchoTask {}
+ ${ruleBasedTasks()}
+
+ class Rules extends RuleSource {
+ @Mutate
+ void addTasks(ModelMap<Task> tasks) {
+ tasks.create("actionMan", EchoTask) {
+ text = 'This is your commander speaking'
+ }
+ tasks.create("climbTask", ClimbTask) {}
+ tasks.create("jumpTask", JumpTask) {}
+ tasks.create("overruleTask", OverruleTask) {}
+ }
+ }
+ apply type: Rules
+ tasks.withType(OverruleTask) { it.text = "actionWoman I'm the real commander" }
+ tasks.withType(ClimbTask).all { it.steps = 14 }
+ tasks.matching { it.name.contains('jump') }.all { it.height = 7 }
+
+
+ //It should be possible to reference the tasks without having to do tasks.realize()
+ assert overruleTask.text == "actionWoman I'm the real commander"
+ assert jumpTask.height == 7
+ assert climbTask.steps == 14
+ """
+
+ when:
+ succeeds('actionMan')
+
+ then:
+ output.contains("actionMan This is your commander speaking")
+ }
+
+ @NotYetImplemented
+ def "rule sources can have a task with some action applied to it as a rule subject"() {
+ given:
+ buildFile << """
+ ${ruleBasedTasks()}
+ class Rules extends RuleSource {
+ @Mutate
+ void addTasks(ModelMap<Task> tasks) {
+ tasks.create("climbTask", ClimbTask) {}
+ }
+
+ @Mutate
+ void plusOne(@Path("tasks.climbTask") ClimbTask climbTask){
+ climbTask.steps += 1
+ }
+ }
+ apply type: Rules
+ tasks.withType(ClimbTask).all { it.steps = 2 }
+
+ //It should be possible to reference the tasks without having to do tasks.realize()
+ assert climbTask.steps == 3
+ """
+
+ expect:
+ succeeds('help')
+ }
+}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/RuleBasedTaskReferenceIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/RuleBasedTaskReferenceIntegrationTest.groovy
new file mode 100644
index 0000000..a48f6c3
--- /dev/null
+++ b/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/RuleBasedTaskReferenceIntegrationTest.groovy
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.execution.taskgraph
+
+import groovy.transform.NotYetImplemented
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import spock.lang.Issue
+
+import static org.gradle.util.TextUtil.normaliseFileSeparators
+
+class RuleBasedTaskReferenceIntegrationTest extends AbstractIntegrationSpec implements WithRuleBasedTasks {
+
+ @NotYetImplemented
+ def "a non-rule-source task can depend on a rule-source task "() {
+ given:
+ buildFile << """
+ ${ruleBasedTasks()}
+
+ class Rules extends RuleSource {
+ @Mutate
+ void addTasks(ModelMap<Task> tasks) {
+ tasks.create("actionMan", EchoTask) {}
+ }
+ }
+ apply type: Rules
+
+ task actionWoman << {
+ println "actionWoman I'm the real commander"
+ }
+ actionWoman.dependsOn tasks.withType(EchoTask)
+ """
+
+ when:
+ succeeds('actionMan')
+
+ then:
+ output.contains("actionWoman I'm the real commander")
+ }
+
+ @NotYetImplemented
+ @Issue("GRADLE-3318")
+ def "can reference rule-source tasks from sub-projects"() {
+ given:
+ def repo = file("maven").createDir()
+ settingsFile << 'include "sub1", "sub2"'
+
+ buildFile << """
+ subprojects{
+ apply plugin: "java"
+ apply plugin: "maven-publish"
+
+ publishing {
+ repositories{ maven{ url '${normaliseFileSeparators(repo.getAbsolutePath())}'}}
+ publications {
+ maven(MavenPublication) {
+ groupId 'org.gradle.sample'
+ version '1.1'
+ from components.java
+ }
+ }
+ }
+ }
+
+ task customPublish(dependsOn: subprojects.collect { Project p -> p.tasks.withType(PublishToMavenLocal)})
+"""
+ when:
+ succeeds('clean', 'build', 'customPublish')
+
+ then:
+ output.contains(":sub1:generatePomFileForMavenPublication")
+ output.contains(":sub1:publishMavenPublicationToMavenRepository")
+ output.contains(":sub2:generatePomFileForMavenPublication")
+ output.contains(":sub2:publishMavenPublicationToMavenRepository")
+ output.contains(":customPublish")
+ }
+}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/WithRuleBasedTasks.groovy b/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/WithRuleBasedTasks.groovy
new file mode 100644
index 0000000..ffaffe8
--- /dev/null
+++ b/subprojects/core/src/integTest/groovy/org/gradle/execution/taskgraph/WithRuleBasedTasks.groovy
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.execution.taskgraph
+
+trait WithRuleBasedTasks {
+
+ String ruleBasedTasks() {
+ """
+ class EchoTask extends DefaultTask {
+ String text = "default"
+ @TaskAction
+ void print() {
+ println(name + ' ' + text)
+ }
+ }
+
+ class ClimbTask extends DefaultTask {
+ int steps = 0
+ @TaskAction
+ void print() {
+ println "Climbing \$steps steps"
+ }
+ }
+
+ class JumpTask extends DefaultTask {
+ int height = 0
+ @TaskAction
+ void print() {
+ println "Jumping \$height centimeters"
+ }
+ }
+"""
+ }
+}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/plugin/NonImperativeBuildScriptEvaluationIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/plugin/NonImperativeBuildScriptEvaluationIntegrationTest.groovy
index 3517de2..3317b64 100644
--- a/subprojects/core/src/integTest/groovy/org/gradle/plugin/NonImperativeBuildScriptEvaluationIntegrationTest.groovy
+++ b/subprojects/core/src/integTest/groovy/org/gradle/plugin/NonImperativeBuildScriptEvaluationIntegrationTest.groovy
@@ -44,6 +44,8 @@ class NonImperativeBuildScriptEvaluationIntegrationTest extends AbstractIntegrat
"""
then:
+ // Invoke twice to exercise script caching
+ succeeds "fromScriptPlugin1", "fromScriptPlugin2"
succeeds "fromScriptPlugin1", "fromScriptPlugin2"
}
}
diff --git a/subprojects/core/src/integTest/groovy/org/gradle/plugin/ScriptPluginClassLoadingIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/plugin/ScriptPluginClassLoadingIntegrationTest.groovy
index b376e08..9df48f6 100644
--- a/subprojects/core/src/integTest/groovy/org/gradle/plugin/ScriptPluginClassLoadingIntegrationTest.groovy
+++ b/subprojects/core/src/integTest/groovy/org/gradle/plugin/ScriptPluginClassLoadingIntegrationTest.groovy
@@ -245,7 +245,7 @@ class ScriptPluginClassLoadingIntegrationTest extends AbstractIntegrationSpec {
output.contains "not in sub"
}
- def "script plugin cannot access classed added by buildscript in applying script"() {
+ def "script plugin cannot access classes added by buildscript in applying script"() {
given:
def jar = file("plugin.jar")
pluginBuilder.addPlugin("project.task('hello')")
diff --git a/subprojects/core/src/integTest/resources/org/gradle/api/tasks/copyTestResources/src/two/two.b b/subprojects/core/src/integTest/resources/org/gradle/api/tasks/copyTestResources/src/two/two.b
index a182e25..4cb29ea 100644
--- a/subprojects/core/src/integTest/resources/org/gradle/api/tasks/copyTestResources/src/two/two.b
+++ b/subprojects/core/src/integTest/resources/org/gradle/api/tasks/copyTestResources/src/two/two.b
@@ -1 +1,3 @@
-Something to copy
\ No newline at end of file
+one
+two
+three
diff --git a/subprojects/core/src/main/groovy/org/gradle/StartParameter.java b/subprojects/core/src/main/groovy/org/gradle/StartParameter.java
index 9e07c34..0a5f673 100644
--- a/subprojects/core/src/main/groovy/org/gradle/StartParameter.java
+++ b/subprojects/core/src/main/groovy/org/gradle/StartParameter.java
@@ -21,7 +21,7 @@ import com.google.common.collect.Sets;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.gradle.api.Incubating;
-import org.gradle.api.internal.classpath.DefaultModuleRegistry;
+import org.gradle.api.internal.classpath.DefaultGradleDistributionLocator;
import org.gradle.initialization.BuildLayoutParameters;
import org.gradle.initialization.CompositeInitScriptFinder;
import org.gradle.initialization.DistributionInitScriptFinder;
@@ -97,7 +97,7 @@ public class StartParameter extends LoggingConfiguration implements Serializable
* Creates a {@code StartParameter} with default values. This is roughly equivalent to running Gradle on the command-line with no arguments.
*/
public StartParameter() {
- gradleHomeDir = new DefaultModuleRegistry().getGradleHome();
+ gradleHomeDir = new DefaultGradleDistributionLocator().getGradleHome();
BuildLayoutParameters layoutParameters = new BuildLayoutParameters();
searchUpwards = layoutParameters.getSearchUpwards();
diff --git a/subprojects/core/src/main/groovy/org/gradle/TaskExecutionLogger.java b/subprojects/core/src/main/groovy/org/gradle/TaskExecutionLogger.java
index c4e37fc..b192b38 100644
--- a/subprojects/core/src/main/groovy/org/gradle/TaskExecutionLogger.java
+++ b/subprojects/core/src/main/groovy/org/gradle/TaskExecutionLogger.java
@@ -35,17 +35,17 @@ public class TaskExecutionLogger implements TaskExecutionListener {
private final Map<Task, ProgressLogger> currentTasks = new HashMap<Task, ProgressLogger>();
private final ProgressLoggerFactory progressLoggerFactory;
- private LoggerProvider parentLoggerPovider;
+ private LoggerProvider parentLoggerProvider;
- public TaskExecutionLogger(ProgressLoggerFactory progressLoggerFactory, LoggerProvider parentLoggerPovider) {
+ public TaskExecutionLogger(ProgressLoggerFactory progressLoggerFactory, LoggerProvider parentLoggerProvider) {
this.progressLoggerFactory = progressLoggerFactory;
- this.parentLoggerPovider = parentLoggerPovider;
+ this.parentLoggerProvider = parentLoggerProvider;
}
public void beforeExecute(Task task) {
assert !currentTasks.containsKey(task);
- ProgressLogger currentTask = progressLoggerFactory.newOperation(TaskExecutionLogger.class, parentLoggerPovider.getLogger());
+ ProgressLogger currentTask = progressLoggerFactory.newOperation(TaskExecutionLogger.class, parentLoggerProvider.getLogger());
String displayName = getDisplayName(task);
currentTask.setDescription("Execute ".concat(displayName));
currentTask.setShortDescription(displayName);
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolveContext.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolveContext.java
deleted file mode 100644
index bbd9f04..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolveContext.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.artifacts;
-
-/**
- * Represents something that can be resolved.
- */
-public interface ResolveContext {
- String getName();
-
- DependencySet getDependencies();
-
- DependencySet getAllDependencies();
-
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolveException.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolveException.java
index 1412a36..09a1d5a 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolveException.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolveException.java
@@ -24,15 +24,15 @@ import org.gradle.internal.exceptions.DefaultMultiCauseException;
*/
@Contextual
public class ResolveException extends DefaultMultiCauseException {
- public ResolveException(ResolveContext configuration, Throwable cause) {
- super(buildMessage(configuration), cause);
+ public ResolveException(String resolveContext, Throwable cause) {
+ super(buildMessage(resolveContext), cause);
}
- public ResolveException(ResolveContext configuration, Iterable<? extends Throwable> causes) {
- super(buildMessage(configuration), causes);
+ public ResolveException(String resolveContext, Iterable<? extends Throwable> causes) {
+ super(buildMessage(resolveContext), causes);
}
- private static String buildMessage(ResolveContext configuration) {
- return String.format("Could not resolve all dependencies for %s.", configuration);
+ private static String buildMessage(String resolveContext) {
+ return String.format("Could not resolve all dependencies for %s.", resolveContext);
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolvedArtifact.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolvedArtifact.java
index 54efc43..99c3a47 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolvedArtifact.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/ResolvedArtifact.java
@@ -15,6 +15,9 @@
*/
package org.gradle.api.artifacts;
+import org.gradle.api.Incubating;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
+
import java.io.File;
/**
@@ -37,4 +40,7 @@ public interface ResolvedArtifact {
String getExtension();
String getClassifier();
+
+ @Incubating
+ ComponentArtifactIdentifier getId();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/ComponentArtifactIdentifier.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/ComponentArtifactIdentifier.java
new file mode 100644
index 0000000..8143bc9
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/ComponentArtifactIdentifier.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.artifacts.component;
+
+import org.gradle.api.Incubating;
+
+/**
+ * An immutable identifier for an artifact that belongs to some component instance.
+ */
+ at Incubating
+public interface ComponentArtifactIdentifier {
+ /**
+ * Returns the id of the component that this artifact belongs to.
+ */
+ ComponentIdentifier getComponentIdentifier();
+
+ /**
+ * Returns some human-consumable display name for this artifact.
+ */
+ String getDisplayName();
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryBinaryIdentifier.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryBinaryIdentifier.java
new file mode 100644
index 0000000..2a53142
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryBinaryIdentifier.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.artifacts.component;
+
+import org.gradle.api.Incubating;
+
+/**
+ * An identifier for a library instance that is built as part of the current build.
+ *
+ */
+ at Incubating
+public interface LibraryBinaryIdentifier extends ComponentIdentifier {
+
+ /**
+ * The project path of the library.
+ * @return The project path of the library.
+ */
+ String getProjectPath();
+
+ /**
+ * The name of the library
+ * @return the name of the library
+ */
+ String getLibraryName();
+
+ /**
+ * The variant of the library.
+ * @return the variant identifier of the library.
+ */
+ String getVariant();
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryComponentIdentifier.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryComponentIdentifier.java
deleted file mode 100644
index ffb900e..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryComponentIdentifier.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.artifacts.component;
-
-import org.gradle.api.Incubating;
-
-/**
- * An identifier for a library instance that is built as part of the current build.
- *
- */
- at Incubating
-public interface LibraryComponentIdentifier extends ComponentIdentifier {
- String getProjectPath();
- String getLibraryName();
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryComponentSelector.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryComponentSelector.java
index 59d51ce..3122813 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryComponentSelector.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/component/LibraryComponentSelector.java
@@ -17,6 +17,7 @@
package org.gradle.api.artifacts.component;
import org.gradle.api.Incubating;
+import org.gradle.api.Nullable;
/**
* Criteria for selecting a library instance that is built as part of the current build.
@@ -24,6 +25,22 @@ import org.gradle.api.Incubating;
*/
@Incubating
public interface LibraryComponentSelector extends ComponentSelector {
+ /**
+ * Return the project path of the selected library.
+ *
+ * @return the project path of the library
+ */
String getProjectPath();
+
+ /**
+ * Return the library name of the selected library.
+ * If the library name is null then it is expected to find a single library defined in same project
+ * as the requesting component or dependency resolution will fail.
+ * If not <code>null</code> then the name will never be empty.
+ *
+ * @return the library name
+ */
+ @Nullable
String getLibraryName();
+
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java
index 81998db..7e62f59 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java
@@ -200,9 +200,9 @@ import java.util.Map;
* </pre>
*
* <p>File dependencies are represented using a {@link org.gradle.api.artifacts.SelfResolvingDependency}.</p>
- *
+ *
* <h3>Dependencies to other configurations</h3>
- *
+ *
* <p>You can add a dependency using a {@link org.gradle.api.artifacts.Configuration}.</p>
*
* <p>When the configuration is from the same project as the target configuration, the target configuration is changed
@@ -226,6 +226,9 @@ import java.util.Map;
*
* //our plugin requires Gradle API interfaces and classes to compile:
* compile gradleApi()
+ *
+ * //we will use the Gradle test-kit to test build logic:
+ * testCompile gradleTestKit()
* }
* </pre>
*
@@ -307,17 +310,26 @@ public interface DependencyHandler {
* @return The dependency.
*/
Dependency project(Map<String, ?> notation);
-
+
/**
* Creates a dependency on the API of the current version of Gradle.
*
* @return The dependency.
*/
Dependency gradleApi();
-
+
+ /**
+ * Creates a dependency on the <a href="http://docs.gradle.org/current/docs/userguide/test_kit.html">Gradle test-kit</a> API.
+ *
+ * @return The dependency.
+ * @since 2.6
+ */
+ @Incubating
+ Dependency gradleTestKit();
+
/**
* Creates a dependency on the Groovy that is distributed with the current version of Gradle.
- *
+ *
* @return The dependency.
*/
Dependency localGroovy();
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/repositories/AuthenticationContainer.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/repositories/AuthenticationContainer.java
new file mode 100644
index 0000000..a08cbfa
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/repositories/AuthenticationContainer.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.artifacts.repositories;
+
+import org.gradle.api.Incubating;
+import org.gradle.api.PolymorphicDomainObjectContainer;
+import org.gradle.authentication.Authentication;
+
+/**
+ * Container for configuring repository authentication schemes of type {@link org.gradle.authentication.Authentication}.
+ */
+ at Incubating
+public interface AuthenticationContainer extends PolymorphicDomainObjectContainer<Authentication> {
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/repositories/AuthenticationSupported.java b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/repositories/AuthenticationSupported.java
index b8ecdf3..e915f95 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/artifacts/repositories/AuthenticationSupported.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/artifacts/repositories/AuthenticationSupported.java
@@ -18,10 +18,12 @@ package org.gradle.api.artifacts.repositories;
import org.gradle.api.Action;
import org.gradle.api.Incubating;
import org.gradle.api.credentials.Credentials;
+import org.gradle.internal.HasInternalProtocol;
/**
* An artifact repository which supports username/password authentication.
*/
+ at HasInternalProtocol
public interface AuthenticationSupported {
/**
@@ -46,7 +48,7 @@ public interface AuthenticationSupported {
* @throws IllegalArgumentException when the credentials assigned to this repository are not assignable to the specified type
*/
@Incubating
- public <T extends Credentials> T getCredentials(Class<T> credentialsType);
+ <T extends Credentials> T getCredentials(Class<T> credentialsType);
/**
* Configures the username and password credentials for this repository using the supplied action.
@@ -96,4 +98,38 @@ public interface AuthenticationSupported {
*/
@Incubating
<T extends Credentials> void credentials(Class<T> credentialsType, Action<? super T> action);
+
+ /**
+ * <p>Configures the authentication schemes for this repository.
+ *
+ * <p>This method executes the given action against the {@link AuthenticationContainer} for this project. The {@link
+ * AuthenticationContainer} is passed to the closure as the closure's delegate.
+ * <p>
+ * If no authentication schemes have been assigned to this repository, a default set of authentication schemes are used based on the repository's transport scheme.
+ *
+ * <pre autoTested=''>
+ * repositories {
+ * maven {
+ * url "${url}"
+ * authentication {
+ * basic(BasicAuthentication)
+ * }
+ * }
+ * }
+ * </pre>
+ * <p>
+ * Supported authentication scheme types extend {@link org.gradle.authentication.Authentication}.
+ *
+ * @param action the action to use to configure the authentication schemes.
+ */
+ @Incubating
+ void authentication(Action<? super AuthenticationContainer> action);
+
+ /**
+ * Returns the authentication schemes for this repository.
+ *
+ * @return the authentication schemes for this repository
+ */
+ @Incubating
+ AuthenticationContainer getAuthentication();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/file/ContentFilterable.java b/subprojects/core/src/main/groovy/org/gradle/api/file/ContentFilterable.java
index 722bd4b..f1aa416 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/file/ContentFilterable.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/file/ContentFilterable.java
@@ -61,7 +61,8 @@ public interface ContentFilterable {
/**
* Adds a content filter based on the provided closure. The Closure will be called with each line (stripped of line
- * endings) and should return a String to replace the line.
+ * endings) and should return a String to replace the line or {@code null} to remove the line. If every line is
+ * removed, the result will be an empty file, not an absent one.
*
* @param closure to implement line based filtering
* @return this
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/DependencyClassPathProvider.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/DependencyClassPathProvider.java
index f006c51..8483a31 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/DependencyClassPathProvider.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/DependencyClassPathProvider.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
import static org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory.ClassPathNotation.GRADLE_API;
import static org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory.ClassPathNotation.LOCAL_GROOVY;
+import static org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory.ClassPathNotation.GRADLE_TEST_KIT;
public class DependencyClassPathProvider implements ClassPathProvider {
private final ModuleRegistry moduleRegistry;
@@ -49,6 +50,13 @@ public class DependencyClassPathProvider implements ClassPathProvider {
}
return classpath;
}
+ if (name.equals(GRADLE_TEST_KIT.name())) {
+ ClassPath classpath = new DefaultClassPath();
+ for (Module module : moduleRegistry.getModule("gradle-test-kit").getAllRequiredModules()) {
+ classpath = classpath.plus(module.getClasspath());
+ }
+ return classpath;
+ }
if (name.equals(LOCAL_GROOVY.name())) {
return moduleRegistry.getExternalModule("groovy-all").getClasspath();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/DocumentationRegistry.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/DocumentationRegistry.java
index f479d4b..7ecd039 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/DocumentationRegistry.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/DocumentationRegistry.java
@@ -32,16 +32,16 @@ public class DocumentationRegistry {
* Returns the location the documentation for the given feature, referenced by id. The location may be local or remote.
*/
public String getDocumentationFor(String id) {
- return String.format("http://gradle.org/docs/%s/userguide/%s.html", gradleVersion.getVersion(), id);
+ return String.format("https://docs.gradle.org/%s/userguide/%s.html", gradleVersion.getVersion(), id);
}
public String getDocumentationFor(String id, String section) {
- return String.format("http://gradle.org/docs/%s/userguide/%s.html#%s", gradleVersion.getVersion(), id, section);
+ return String.format("https://docs.gradle.org/%s/userguide/%s.html#%s", gradleVersion.getVersion(), id, section);
}
public String getDslRefForProperty(Class<?> clazz, String property) {
String className = clazz.getName();
- return String.format("http://gradle.org/docs/%s/dsl/%s.html#%s:%s", gradleVersion.getVersion(), className, className, property);
+ return String.format("https://docs.gradle.org/%s/dsl/%s.html#%s:%s", gradleVersion.getVersion(), className, className, property);
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/GradleDistributionLocator.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/GradleDistributionLocator.java
index 9a219fe..644f0c6 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/GradleDistributionLocator.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/GradleDistributionLocator.java
@@ -15,11 +15,22 @@
*/
package org.gradle.api.internal;
+import org.gradle.api.Nullable;
+
import java.io.File;
+import java.util.List;
public interface GradleDistributionLocator {
/**
* Returns the directory containing the Gradle distribution of the current Gradle version. May be null.
*/
+ @Nullable
File getGradleHome();
+
+ /**
+ * Returns the library directory of the Gradle distribution plus its subdirectories. Maybe be an empty list.
+ *
+ * @return Library directories
+ */
+ List<File> getLibDirs();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.java
index bb21507..0e2bec8 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.java
@@ -101,6 +101,10 @@ public class DefaultDependencyHandler extends GroovyObjectSupport implements Dep
return dependencyFactory.createDependency(DependencyFactory.ClassPathNotation.GRADLE_API);
}
+ public Dependency gradleTestKit() {
+ return dependencyFactory.createDependency(DependencyFactory.ClassPathNotation.GRADLE_TEST_KIT);
+ }
+
public Dependency localGroovy() {
return dependencyFactory.createDependency(DependencyFactory.ClassPathNotation.LOCAL_GROOVY);
}
@@ -144,4 +148,4 @@ public class DefaultDependencyHandler extends GroovyObjectSupport implements Dep
public ArtifactResolutionQuery createArtifactResolutionQuery() {
return resolutionQueryFactory.createArtifactResolutionQuery();
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java
index b2ba01f..dcab9cd 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java
@@ -25,9 +25,9 @@ import java.util.Map;
public interface DependencyFactory {
//for gradle distribution specific dependencies
enum ClassPathNotation {
- GRADLE_API, LOCAL_GROOVY
+ GRADLE_API, GRADLE_TEST_KIT, LOCAL_GROOVY
}
-
+
Dependency createDependency(Object dependencyNotation);
ClientModule createModule(Object dependencyNotation, Closure configureClosure);
ProjectDependency createProjectDependencyFromMap(ProjectFinder projectFinder, Map<? extends String, ? extends Object> map);
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultPasswordCredentials.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/repositories/DefaultPasswordCredentials.java
similarity index 100%
rename from subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultPasswordCredentials.java
rename to subprojects/core/src/main/groovy/org/gradle/api/internal/artifacts/repositories/DefaultPasswordCredentials.java
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/DefaultGradleDistributionLocator.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/DefaultGradleDistributionLocator.java
new file mode 100644
index 0000000..0f4c3bc
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/DefaultGradleDistributionLocator.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.classpath;
+
+import org.gradle.api.internal.GradleDistributionLocator;
+import org.gradle.internal.classloader.ClasspathUtil;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class DefaultGradleDistributionLocator implements GradleDistributionLocator {
+ private final File distDir;
+ private final List<File> libDirs = new ArrayList<File>();
+
+ public DefaultGradleDistributionLocator() {
+ this(DefaultGradleDistributionLocator.class);
+ }
+
+ public DefaultGradleDistributionLocator(Class<?> clazz) {
+ this(findDistDir(clazz));
+ }
+
+ public DefaultGradleDistributionLocator(File distDir) {
+ this.distDir = distDir;
+
+ if (distDir != null) {
+ libDirs.addAll(findLibDirs(distDir));
+ }
+ }
+
+ private List<File> findLibDirs(File distDir) {
+ List<File> libDirAndSubdirs = new ArrayList<File>();
+ collectWithSubdirectories(new File(distDir, "lib"), libDirAndSubdirs);
+ return libDirAndSubdirs;
+ }
+
+ private void collectWithSubdirectories(File root, Collection<File> collection) {
+ collection.add(root);
+ File[] subDirs = root.listFiles(DIRECTORY_FILTER);
+
+ if(subDirs != null) {
+ for (File subdirectory : subDirs) {
+ collectWithSubdirectories(subdirectory, collection);
+ }
+ }
+ }
+
+ public static final FileFilter DIRECTORY_FILTER = new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isDirectory();
+ }
+ };
+
+ private static File findDistDir(Class<?> clazz) {
+ File codeSource = ClasspathUtil.getClasspathForClass(clazz);
+ if (codeSource.isFile()) {
+ return determineDistRootDir(codeSource);
+ } else {
+ // Loaded from a classes dir - assume we're running from the ide or tests
+ return null;
+ }
+ }
+
+ /**
+ * Returns the root directory of a distribution based on the code source of a JAR file. The JAR can either sit in the lib or plugins subdirectory. Returns null if distribution doesn't have
+ * expected directory layout.
+ *
+ * The expected directory layout for JARs of a distribution looks as such:
+ *
+ * dist-root
+ * |_ lib
+ * |_ plugins
+ *
+ * @param codeSource Code source of JAR file
+ * @return Distribution root directory
+ */
+ private static File determineDistRootDir(File codeSource) {
+ File parentDir = codeSource.getParentFile();
+
+ if(parentDir.getName().equals("lib")) {
+ File pluginsDir = new File(parentDir, "plugins");
+ return parentDir.isDirectory() && pluginsDir.exists() && pluginsDir.isDirectory() ? parentDir.getParentFile() : null;
+ }
+
+ if(parentDir.getName().equals("plugins")) {
+ File libDir = parentDir.getParentFile();
+ return parentDir.isDirectory() && libDir.exists() && libDir.isDirectory() && libDir.getName().equals("lib") ? libDir.getParentFile() : null;
+ }
+
+ return null;
+ }
+
+ public File getGradleHome() {
+ return distDir;
+ }
+
+ public List<File> getLibDirs() {
+ return libDirs;
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistry.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistry.java
index d15925c..14e1d90 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistry.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistry.java
@@ -19,23 +19,11 @@ import org.gradle.api.UncheckedIOException;
import org.gradle.api.internal.GradleDistributionLocator;
import org.gradle.internal.classpath.ClassPath;
import org.gradle.internal.classpath.DefaultClassPath;
-import org.gradle.internal.classloader.ClasspathUtil;
import org.gradle.util.GUtil;
import java.io.File;
-import java.io.FileFilter;
import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
@@ -44,80 +32,45 @@ import java.util.zip.ZipFile;
/**
* Determines the classpath for a module by looking for a '${module}-classpath.properties' resource with 'name' set to the name of the module.
*/
-public class DefaultModuleRegistry implements ModuleRegistry, GradleDistributionLocator {
- public static final FileFilter DIRECTORY_FILTER = new FileFilter() {
- public boolean accept(File pathname) {
- return pathname.isDirectory();
- }
- };
-
- private final ClassLoader classLoader;
- private final File distDir;
+public class DefaultModuleRegistry implements ModuleRegistry {
+ private final GradleDistributionLocator gradleDistributionLocator;
private final Map<String, Module> modules = new HashMap<String, Module>();
private final List<File> classpath = new ArrayList<File>();
private final Map<String, File> classpathJars = new LinkedHashMap<String, File>();
- private final List<File> libDirs = new ArrayList<File>();
public DefaultModuleRegistry() {
- this(DefaultModuleRegistry.class.getClassLoader(), findDistDir());
+ this(new DefaultClassPath());
}
- DefaultModuleRegistry(ClassLoader classLoader, File distDir) {
- this.classLoader = classLoader;
- this.distDir = distDir;
- for (File classpathFile : new EffectiveClassPath(classLoader).getAsFiles()) {
- classpath.add(classpathFile);
- if (classpathFile.isFile() && !classpathJars.containsKey(classpathFile.getName())) {
- classpathJars.put(classpathFile.getName(), classpathFile);
- }
- }
-
- if (distDir != null) {
- libDirs.addAll(findLibDirs(distDir));
- }
+ public DefaultModuleRegistry(ClassPath additionalModuleClassPath) {
+ this(DefaultModuleRegistry.class.getClassLoader(), additionalModuleClassPath, new DefaultGradleDistributionLocator(DefaultModuleRegistry.class));
}
- private List<File> findLibDirs(File distDir) {
- List<File> libDirAndSubdirs = new ArrayList<File>();
- collectWithSubdirectories(new File(distDir, "lib"), libDirAndSubdirs);
- return libDirAndSubdirs;
+ DefaultModuleRegistry(ClassLoader classLoader, File distDir) {
+ this(classLoader, new DefaultClassPath(), new DefaultGradleDistributionLocator(distDir));
}
- private void collectWithSubdirectories(File root, Collection<File> collection) {
- collection.add(root);
- for (File subdirectory : root.listFiles(DIRECTORY_FILTER)) {
- collectWithSubdirectories(subdirectory, collection);
- }
- }
+ private DefaultModuleRegistry(ClassLoader classLoader, ClassPath additionalModuleClassPath, GradleDistributionLocator gradleDistributionLocator) {
+ this.gradleDistributionLocator = gradleDistributionLocator;
- private static File findDistDir() {
- File codeSource = ClasspathUtil.getClasspathForClass(DefaultModuleRegistry.class);
- if (codeSource.isFile()) {
- // Loaded from a JAR - let's see if its in the lib directory, and there's a lib/plugins directory
- File libDir = codeSource.getParentFile();
- if (!libDir.getName().equals("lib") || !new File(libDir, "plugins").isDirectory()) {
- return null;
+ for (File classpathFile : new EffectiveClassPath(classLoader).plus(additionalModuleClassPath).getAsFiles()) {
+ classpath.add(classpathFile);
+ if (classpathFile.isFile() && !classpathJars.containsKey(classpathFile.getName())) {
+ classpathJars.put(classpathFile.getName(), classpathFile);
}
- return libDir.getParentFile();
- } else {
- // Loaded from a classes dir - assume we're running from the ide or tests
- return null;
}
}
- /**
- * Returns all the candidate JARs to be considered by this registry.
- */
- public Set<File> getFullClasspath() {
- return new LinkedHashSet<File>(classpath);
- }
-
- public File getGradleHome() {
- return distDir;
+ @Override
+ public ClassPath getAdditionalClassPath() {
+ return gradleDistributionLocator.getGradleHome() == null ? new DefaultClassPath(classpath) : new DefaultClassPath();
}
public Module getExternalModule(String name) {
- File externalJar = findExternalJar(name);
+ File externalJar = findJar(name);
+ if (externalJar == null) {
+ throw new UnknownModuleException(String.format("Cannot locate JAR for module '%s' in distribution directory '%s'.", name, gradleDistributionLocator.getGradleHome()));
+ }
return new DefaultModule(name, Collections.singleton(externalJar), Collections.<File>emptySet(), Collections.<Module>emptySet());
}
@@ -131,7 +84,7 @@ public class DefaultModuleRegistry implements ModuleRegistry, GradleDistribution
}
private Module loadModule(String moduleName) {
- File jarFile = findModuleJar(moduleName);
+ File jarFile = findJar(moduleName);
if (jarFile != null) {
Set<File> implementationClasspath = new LinkedHashSet<File>();
implementationClasspath.add(jarFile);
@@ -140,19 +93,22 @@ public class DefaultModuleRegistry implements ModuleRegistry, GradleDistribution
}
String resourceName = String.format("%s-classpath.properties", moduleName);
- URL propertiesUrl = classLoader.getResource(resourceName);
- if (propertiesUrl != null) {
- Set<File> implementationClasspath = new LinkedHashSet<File>();
- findImplementationClasspath(moduleName, implementationClasspath);
- implementationClasspath.add(ClasspathUtil.getClasspathForResource(propertiesUrl, resourceName));
- Properties properties = GUtil.loadProperties(propertiesUrl);
- return module(moduleName, properties, implementationClasspath);
+ Set<File> implementationClasspath = new LinkedHashSet<File>();
+ findImplementationClasspath(moduleName, implementationClasspath);
+ for (File file : implementationClasspath) {
+ if (file.isDirectory()) {
+ File propertiesFile = new File(file, resourceName);
+ if (propertiesFile.isFile()) {
+ Properties properties = GUtil.loadProperties(propertiesFile);
+ return module(moduleName, properties, implementationClasspath);
+ }
+ }
}
- if (distDir == null) {
- throw new UnknownModuleException(String.format("Cannot locate classpath manifest for module '%s' in classpath.", moduleName));
+ if (gradleDistributionLocator.getGradleHome() == null) {
+ throw new UnknownModuleException(String.format("Cannot locate manifest for module '%s' in classpath.", moduleName));
}
- throw new UnknownModuleException(String.format("Cannot locate JAR for module '%s' in distribution directory '%s'.", moduleName, distDir));
+ throw new UnknownModuleException(String.format("Cannot locate JAR for module '%s' in distribution directory '%s'.", moduleName, gradleDistributionLocator.getGradleHome()));
}
private Module module(String moduleName, Properties properties, Set<File> implementationClasspath) {
@@ -193,6 +149,7 @@ public class DefaultModuleRegistry implements ModuleRegistry, GradleDistribution
suffixes.add(String.format("/%s/src/main/resources", projectDirName).replace('/', File.separatorChar));
suffixes.add(String.format("/%s/build/classes/main", projectDirName).replace('/', File.separatorChar));
suffixes.add(String.format("/%s/build/resources/main", projectDirName).replace('/', File.separatorChar));
+ suffixes.add(String.format("/%s/build/generated-resources/main", projectDirName).replace('/', File.separatorChar));
for (File file : classpath) {
if (file.isDirectory()) {
for (String suffix : suffixes) {
@@ -219,7 +176,11 @@ public class DefaultModuleRegistry implements ModuleRegistry, GradleDistribution
try {
ZipFile zipFile = new ZipFile(jarFile);
try {
- ZipEntry entry = zipFile.getEntry(String.format("%s-classpath.properties", name));
+ final String entryName = String.format("%s-classpath.properties", name);
+ ZipEntry entry = zipFile.getEntry(entryName);
+ if (entry == null) {
+ throw new IllegalStateException("Did not find " + entryName + " in " + jarFile.getAbsolutePath());
+ }
return GUtil.loadProperties(zipFile.getInputStream(entry));
} finally {
zipFile.close();
@@ -229,33 +190,21 @@ public class DefaultModuleRegistry implements ModuleRegistry, GradleDistribution
}
}
- private File findModuleJar(String name) {
+ private File findJar(String name) {
Pattern pattern = Pattern.compile(Pattern.quote(name) + "-\\d.+\\.jar");
- for (File libDir : libDirs) {
+ for (File libDir : gradleDistributionLocator.getLibDirs()) {
for (File file : libDir.listFiles()) {
if (pattern.matcher(file.getName()).matches()) {
return file;
}
}
}
- return null;
- }
-
- private File findExternalJar(String name) {
- Pattern pattern = Pattern.compile(Pattern.quote(name) + "-\\d.+\\.jar");
for (File file : classpath) {
if (pattern.matcher(file.getName()).matches()) {
return file;
}
}
- for (File libDir : libDirs) {
- for (File file : libDir.listFiles()) {
- if (pattern.matcher(file.getName()).matches()) {
- return file;
- }
- }
- }
- throw new UnknownModuleException(String.format("Cannot locate JAR for module '%s' in distribution directory '%s'.", name, distDir));
+ return null;
}
private File findDependencyJar(String module, String name) {
@@ -263,16 +212,16 @@ public class DefaultModuleRegistry implements ModuleRegistry, GradleDistribution
if (jarFile != null) {
return jarFile;
}
- if (distDir == null) {
+ if (gradleDistributionLocator.getGradleHome() == null) {
throw new IllegalArgumentException(String.format("Cannot find JAR '%s' required by module '%s' using classpath.", name, module));
}
- for (File libDir : libDirs) {
+ for (File libDir : gradleDistributionLocator.getLibDirs()) {
jarFile = new File(libDir, name);
if (jarFile.isFile()) {
return jarFile;
}
}
- throw new IllegalArgumentException(String.format("Cannot find JAR '%s' required by module '%s' using classpath or distribution directory '%s'", name, module, distDir));
+ throw new IllegalArgumentException(String.format("Cannot find JAR '%s' required by module '%s' using classpath or distribution directory '%s'", name, module, gradleDistributionLocator.getGradleHome()));
}
private static class DefaultModule implements Module {
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/Module.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/Module.java
index 601a74b..5d3be7d 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/Module.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/Module.java
@@ -24,17 +24,17 @@ import java.util.Set;
*/
public interface Module {
/**
- * Returns the classpath for the module implementation. This is the classpath of the module itself.
+ * Returns the classpath for the module implementation. This is the classpath of the module itself. Does not include any dependencies.
*/
ClassPath getImplementationClasspath();
/**
- * Returns the classpath containing the runtime dependencies of the module.
+ * Returns the classpath containing the runtime dependencies of the module. Does not include any other modules.
*/
ClassPath getRuntimeClasspath();
/**
- * Returns implementation + runtime
+ * Returns implementation + runtime.
*/
ClassPath getClasspath();
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/ModuleRegistry.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/ModuleRegistry.java
index 69d05c1..c636848 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/ModuleRegistry.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/classpath/ModuleRegistry.java
@@ -15,6 +15,8 @@
*/
package org.gradle.api.internal.classpath;
+import org.gradle.internal.classpath.ClassPath;
+
/**
* A registry of dynamically loadable modules.
*/
@@ -32,4 +34,9 @@ public interface ModuleRegistry {
* @return the module. Does not return null.
*/
Module getModule(String name) throws UnknownModuleException;
+
+ /**
+ * Returns the classpath used to search for modules, in addition to default locations in the Gradle distribution (if available). May be empty.
+ */
+ ClassPath getAdditionalClassPath();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/file/FileResolver.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/file/FileResolver.java
index b39f3fb..7fc675c 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/file/FileResolver.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/file/FileResolver.java
@@ -19,13 +19,14 @@ import org.gradle.api.PathValidation;
import org.gradle.api.file.FileTree;
import org.gradle.api.resources.ReadableResource;
import org.gradle.internal.Factory;
+import org.gradle.internal.file.RelativeFilePathResolver;
import org.gradle.internal.typeconversion.NotationParser;
import java.io.File;
import java.net.URI;
import java.util.List;
-public interface FileResolver {
+public interface FileResolver extends RelativeFilePathResolver {
File resolve(Object path);
ReadableResource resolveResource(Object path);
@@ -42,7 +43,5 @@ public interface FileResolver {
URI resolveUri(Object path);
- String resolveAsRelativePath(Object path);
-
NotationParser<Object, File> asNotationParser();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/file/copy/LineFilter.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/file/copy/LineFilter.java
index 23c1a3a..3ad8c51 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/file/copy/LineFilter.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/file/copy/LineFilter.java
@@ -24,11 +24,18 @@ import java.io.IOException;
import java.io.Reader;
public class LineFilter extends Reader {
+ private static enum State {
+ NORMAL,
+ SKIP_LINE,
+ EOF
+ };
+
private final Closure closure;
private String transformedLine;
private int transformedIndex;
private final BufferedReader bufferedIn;
private final Reader in;
+ private State state = State.NORMAL;
/**
* Creates a new filtered reader.
@@ -42,7 +49,7 @@ public class LineFilter extends Reader {
this.closure = closure;
}
- private String getTransformedLine() throws IOException {
+ private void readTransformedLine() throws IOException {
StringBuilder line = new StringBuilder();
boolean eol = false;
int ch;
@@ -60,20 +67,26 @@ public class LineFilter extends Reader {
}
}
if (line.length() == 0 && !eol) {
- return null;
+ state = State.EOF;
+ return;
}
-
- StringBuilder result = new StringBuilder();
- result.append(closure.call(line.toString()).toString());
+ Object result = closure.call(line.toString());
+ if (result == null) {
+ state = State.SKIP_LINE;
+ return;
+ }
+ StringBuilder builder = new StringBuilder();
+ builder.append(result.toString());
if (eol) {
- result.append(SystemProperties.getInstance().getLineSeparator());
+ builder.append(SystemProperties.getInstance().getLineSeparator());
}
- return result.toString();
+ state = State.NORMAL;
+ transformedLine = builder.toString();
}
private void ensureData() throws IOException {
- if (transformedLine == null || transformedIndex >= transformedLine.length()) {
- transformedLine = getTransformedLine();
+ while (state == State.SKIP_LINE || state == State.NORMAL && (transformedLine == null || transformedIndex >= transformedLine.length())) {
+ readTransformedLine();
transformedIndex = 0;
}
}
@@ -81,7 +94,7 @@ public class LineFilter extends Reader {
@Override
public int read() throws IOException {
ensureData();
- if (transformedLine == null || transformedLine.length() == 0) {
+ if (state == State.EOF) {
return -1;
}
return transformedLine.charAt(transformedIndex++);
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandler.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandler.java
index 3c451b5..9c9f7ee 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandler.java
@@ -21,6 +21,7 @@ import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.initialization.dsl.ScriptHandler;
+import org.gradle.api.internal.artifacts.DependencyResolutionServices;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.groovy.scripts.ScriptSource;
@@ -35,21 +36,17 @@ public class DefaultScriptHandler implements ScriptHandler, ScriptHandlerInterna
private static final Logger LOGGER = Logging.getLogger(DefaultScriptHandler.class);
private final ScriptSource scriptSource;
- private final RepositoryHandler repositoryHandler;
- private final DependencyHandler dependencyHandler;
- private final ConfigurationContainer configContainer;
private final ClassLoaderScope classLoaderScope;
+ private final DependencyResolutionServices dependencyResolutionServices;
+ // The following values are relatively expensive to create, so defer creation until required
+ private RepositoryHandler repositoryHandler;
+ private DependencyHandler dependencyHandler;
+ private ConfigurationContainer configContainer;
private Configuration classpathConfiguration;
- public DefaultScriptHandler(
- ScriptSource scriptSource, RepositoryHandler repositoryHandler,
- DependencyHandler dependencyHandler, ConfigurationContainer configContainer,
- ClassLoaderScope classLoaderScope
- ) {
- this.repositoryHandler = repositoryHandler;
- this.dependencyHandler = dependencyHandler;
+ public DefaultScriptHandler(ScriptSource scriptSource, DependencyResolutionServices dependencyResolutionServices, ClassLoaderScope classLoaderScope) {
+ this.dependencyResolutionServices = dependencyResolutionServices;
this.scriptSource = scriptSource;
- this.configContainer = configContainer;
this.classLoaderScope = classLoaderScope;
}
@@ -72,15 +69,21 @@ public class DefaultScriptHandler implements ScriptHandler, ScriptHandlerInterna
public DependencyHandler getDependencies() {
defineConfiguration();
+ if (dependencyHandler == null) {
+ dependencyHandler = dependencyResolutionServices.getDependencyHandler();
+ }
return dependencyHandler;
}
public RepositoryHandler getRepositories() {
+ if (repositoryHandler == null) {
+ repositoryHandler = dependencyResolutionServices.getResolveRepositoryHandler();
+ }
return repositoryHandler;
}
public void repositories(Closure configureClosure) {
- ConfigureUtil.configure(configureClosure, repositoryHandler);
+ ConfigureUtil.configure(configureClosure, getRepositories());
}
public ConfigurationContainer getConfigurations() {
@@ -90,6 +93,9 @@ public class DefaultScriptHandler implements ScriptHandler, ScriptHandlerInterna
private void defineConfiguration() {
// Defer creation and resolution of configuration until required. Short-circuit when script does not require classpath
+ if (configContainer == null) {
+ configContainer = dependencyResolutionServices.getConfigurationContainer();
+ }
if (classpathConfiguration == null) {
classpathConfiguration = configContainer.create(CLASSPATH_CONFIGURATION);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerFactory.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerFactory.java
index 793e551..f7829f5 100755
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerFactory.java
@@ -17,9 +17,6 @@
package org.gradle.api.internal.initialization;
import org.gradle.api.UnknownProjectException;
-import org.gradle.api.artifacts.ConfigurationContainer;
-import org.gradle.api.artifacts.dsl.DependencyHandler;
-import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.internal.DomainObjectContext;
import org.gradle.api.internal.artifacts.DependencyManagementServices;
import org.gradle.api.internal.artifacts.DependencyResolutionServices;
@@ -53,10 +50,7 @@ public class DefaultScriptHandlerFactory implements ScriptHandlerFactory {
public ScriptHandlerInternal create(ScriptSource scriptSource, ClassLoaderScope classLoaderScope, DomainObjectContext context) {
DependencyResolutionServices services = dependencyManagementServices.create(fileResolver, dependencyMetaDataProvider, projectFinder, context);
- RepositoryHandler repositoryHandler = services.getResolveRepositoryHandler();
- ConfigurationContainer configurationContainer = services.getConfigurationContainer();
- DependencyHandler dependencyHandler = services.getDependencyHandler();
- return new DefaultScriptHandler(scriptSource, repositoryHandler, dependencyHandler, configurationContainer, classLoaderScope);
+ return new DefaultScriptHandler(scriptSource, services, classLoaderScope);
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationAction.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationAction.java
index eb84650..57e50bb 100755
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationAction.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationAction.java
@@ -25,7 +25,6 @@ import org.gradle.api.plugins.ObjectConfigurationAction;
import org.gradle.api.plugins.PluginAware;
import org.gradle.configuration.ScriptPlugin;
import org.gradle.configuration.ScriptPluginFactory;
-import org.gradle.groovy.scripts.DefaultScript;
import org.gradle.groovy.scripts.UriScriptSource;
import org.gradle.util.GUtil;
@@ -97,7 +96,7 @@ public class DefaultObjectConfigurationAction implements ObjectConfigurationActi
UriScriptSource scriptSource = new UriScriptSource("script", scriptUri);
ClassLoaderScope classLoaderScopeChild = classLoaderScope.createChild("script-" + scriptUri.toString());
ScriptHandler scriptHandler = scriptHandlerFactory.create(scriptSource, classLoaderScopeChild);
- ScriptPlugin configurer = configurerFactory.create(scriptSource, scriptHandler, classLoaderScopeChild, classLoaderScope, "buildscript", DefaultScript.class, false);
+ ScriptPlugin configurer = configurerFactory.create(scriptSource, scriptHandler, classLoaderScopeChild, classLoaderScope, false);
for (Object target : targets) {
configurer.apply(target);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DslObject.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DslObject.java
index 3500ecc..d0875c0 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DslObject.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/plugins/DslObject.java
@@ -23,7 +23,7 @@ import org.gradle.api.plugins.ExtensionContainer;
/**
* Provides a unified, typed, interface to an enhanced DSL object.
- *
+ *
* This is intended to be used with objects that have been decorated by the class generator.
* <p>
* Accessing each “aspect” of a DSL object may fail (with an {@link IllegalStateException}) if the DSL
@@ -36,7 +36,7 @@ public class DslObject implements DynamicObjectAware, ExtensionAware, IConventio
private ExtensionContainer extensionContainer;
private ConventionMapping conventionMapping;
private Convention convention;
-
+
private final Object object;
public DslObject(Object object) {
@@ -49,7 +49,7 @@ public class DslObject implements DynamicObjectAware, ExtensionAware, IConventio
}
return dynamicObject;
}
-
+
public Convention getConvention() {
if (convention == null) {
this.convention = toType(object, HasConvention.class).getConvention();
@@ -71,8 +71,11 @@ public class DslObject implements DynamicObjectAware, ExtensionAware, IConventio
return conventionMapping;
}
- public Class getDeclaredType(){
- return object.getClass().getSuperclass();
+ public Class getDeclaredType() {
+ if (object instanceof DynamicObjectAware) {
+ return object.getClass().getSuperclass();
+ }
+ return object.getClass();
}
private static <T> T toType(Object delegate, Class<T> type) {
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/project/AbstractProject.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/project/AbstractProject.java
index 6397866..d7f28e5 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/project/AbstractProject.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/project/AbstractProject.java
@@ -63,7 +63,10 @@ import org.gradle.logging.LoggingManagerInternal;
import org.gradle.logging.StandardOutputCapture;
import org.gradle.model.dsl.internal.NonTransformedModelDslBacking;
import org.gradle.model.dsl.internal.TransformedModelDslBacking;
-import org.gradle.model.internal.core.*;
+import org.gradle.model.internal.core.ModelCreator;
+import org.gradle.model.internal.core.ModelCreators;
+import org.gradle.model.internal.core.ModelPath;
+import org.gradle.model.internal.core.ModelReference;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.process.ExecResult;
@@ -187,19 +190,19 @@ public abstract class AbstractProject extends AbstractPluginAware implements Pro
private void populateModelRegistry(ModelRegistry modelRegistry) {
ModelPath taskFactoryPath = ModelPath.path("taskFactory");
ModelCreator taskFactoryCreator = ModelCreators.bridgedInstance(ModelReference.of(taskFactoryPath, ITaskFactory.class), services.get(ITaskFactory.class))
- .descriptor("Project.<init>.taskFactory")
- .ephemeral(true)
- .hidden(true)
- .build();
+ .descriptor("Project.<init>.taskFactory")
+ .ephemeral(true)
+ .hidden(true)
+ .build();
modelRegistry.createOrReplace(taskFactoryCreator);
modelRegistry.createOrReplace(
ModelCreators.bridgedInstance(ModelReference.of("serviceRegistry", ServiceRegistry.class), services)
- .descriptor("Project.<init>.serviceRegistry()")
- .ephemeral(true)
- .hidden(true)
- .build()
+ .descriptor("Project.<init>.serviceRegistry()")
+ .ephemeral(true)
+ .hidden(true)
+ .build()
);
modelRegistry.createOrReplace(
@@ -208,26 +211,26 @@ public abstract class AbstractProject extends AbstractPluginAware implements Pro
return getBuildDir();
}
})
- .descriptor("Project.<init>.buildDir()")
- .ephemeral(true)
- .hidden(true)
- .build()
+ .descriptor("Project.<init>.buildDir()")
+ .ephemeral(true)
+ .hidden(true)
+ .build()
);
modelRegistry.createOrReplace(
ModelCreators.bridgedInstance(ModelReference.of("projectIdentifier", ProjectIdentifier.class), this)
- .descriptor("Project.<init>.projectIdentifier()")
- .ephemeral(true)
- .hidden(true)
- .build()
+ .descriptor("Project.<init>.projectIdentifier()")
+ .ephemeral(true)
+ .hidden(true)
+ .build()
);
modelRegistry.createOrReplace(
ModelCreators.bridgedInstance(ModelReference.of("extensions", ExtensionContainer.class), getExtensions())
- .descriptor("Project.<init>.extensions()")
- .ephemeral(true)
- .hidden(true)
- .build()
+ .descriptor("Project.<init>.extensions()")
+ .ephemeral(true)
+ .hidden(true)
+ .build()
);
}
@@ -901,12 +904,6 @@ public abstract class AbstractProject extends AbstractPluginAware implements Pro
throw new UnsupportedOperationException();
}
- @Inject
- protected ModelCreatorFactory getModelCreatorFactory() {
- // Decoration takes care of the implementation
- throw new UnsupportedOperationException();
- }
-
@Override
protected DefaultObjectConfigurationAction createObjectConfigurationAction() {
return new DefaultObjectConfigurationAction(getFileResolver(), getScriptPluginFactory(), getScriptHandlerFactory(), getBaseClassLoaderScope(), this);
@@ -964,16 +961,14 @@ public abstract class AbstractProject extends AbstractPluginAware implements Pro
return (ExtensionContainerInternal) getConvention();
}
-
+ // Not part of the public API
public void model(Closure<?> modelRules) {
ModelRegistry modelRegistry = getModelRegistry();
ModelSchemaStore modelSchemaStore = getModelSchemaStore();
- ModelCreatorFactory modelCreatorFactory = getModelCreatorFactory();
-
if (TransformedModelDslBacking.isTransformedBlock(modelRules)) {
- ClosureBackedAction.execute(new TransformedModelDslBacking(modelRegistry, modelSchemaStore, modelCreatorFactory), modelRules);
+ ClosureBackedAction.execute(new TransformedModelDslBacking(modelRegistry, modelSchemaStore, this.getRootProject().getFileResolver()), modelRules);
} else {
- new NonTransformedModelDslBacking(modelRegistry, modelSchemaStore, modelCreatorFactory).configure(modelRules);
+ new NonTransformedModelDslBacking(modelRegistry, modelSchemaStore).configure(modelRules);
}
}
@@ -991,5 +986,4 @@ public abstract class AbstractProject extends AbstractPluginAware implements Pro
public void fireDeferredConfiguration() {
getDeferredProjectConfiguration().fire();
}
-
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/project/DeferredProjectConfiguration.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/project/DeferredProjectConfiguration.java
index d6ed911..c1f59f6 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/project/DeferredProjectConfiguration.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/project/DeferredProjectConfiguration.java
@@ -56,8 +56,12 @@ public class DeferredProjectConfiguration {
firedSentinel = new Exception("Project '" + project.getPath() + "' deferred configuration fired");
}
fired = true;
- for (Runnable runnable : configuration) {
- runnable.run();
+ try {
+ for (Runnable runnable : configuration) {
+ runnable.run();
+ }
+ } finally {
+ configuration.clear();
}
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/project/ProjectInternal.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/project/ProjectInternal.java
index e5f42c8..01a0e41 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/project/ProjectInternal.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/project/ProjectInternal.java
@@ -31,7 +31,6 @@ import org.gradle.api.internal.plugins.ExtensionContainerInternal;
import org.gradle.api.internal.plugins.PluginAwareInternal;
import org.gradle.api.internal.tasks.TaskContainerInternal;
import org.gradle.configuration.project.ProjectConfigurationActionContainer;
-import org.gradle.groovy.scripts.ScriptAware;
import org.gradle.groovy.scripts.ScriptSource;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.service.scopes.ServiceRegistryFactory;
@@ -39,7 +38,7 @@ import org.gradle.logging.StandardOutputCapture;
import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.model.internal.registry.ModelRegistryScope;
-public interface ProjectInternal extends Project, ProjectIdentifier, ScriptAware, FileOperations, ProcessOperations, DomainObjectContext, DependencyMetaDataProvider, ModelRegistryScope, PluginAwareInternal {
+public interface ProjectInternal extends Project, ProjectIdentifier, FileOperations, ProcessOperations, DomainObjectContext, DependencyMetaDataProvider, ModelRegistryScope, PluginAwareInternal {
// These constants are defined here and not with the rest of their kind in HelpTasksPlugin because they are referenced
// in the ‘core’ and ‘ui’ modules, which don't depend on ‘plugins’ where HelpTasksPlugin is defined.
@@ -93,6 +92,8 @@ public interface ProjectInternal extends Project, ProjectIdentifier, ScriptAware
ClassLoaderScope getBaseClassLoaderScope();
+ void setScript(groovy.lang.Script script);
+
void addDeferredConfiguration(Runnable configuration);
void fireDeferredConfiguration();
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/internal/rules/ModelMapCreators.java b/subprojects/core/src/main/groovy/org/gradle/api/internal/rules/ModelMapCreators.java
index 5bab321..9fb8055 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/internal/rules/ModelMapCreators.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/internal/rules/ModelMapCreators.java
@@ -34,7 +34,7 @@ public class ModelMapCreators {
ModelReference<? extends InstanceFactory<? super T, String>> factoryReference,
ModelRuleDescriptor descriptor) {
- ChildNodeCreatorStrategy<T> childFactory = NodeBackedModelMap.createUsingFactory(factoryReference);
+ ChildNodeInitializerStrategy<T> childFactory = NodeBackedModelMap.createUsingFactory(factoryReference);
ModelType<C> containerType = ModelType.of(containerClass);
ModelType<T> modelType = ModelType.of(typeClass);
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/invocation/Gradle.java b/subprojects/core/src/main/groovy/org/gradle/api/invocation/Gradle.java
index 394306d..e88e29c 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/invocation/Gradle.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/invocation/Gradle.java
@@ -59,7 +59,7 @@ public interface Gradle extends PluginAware {
* If an existing daemon process is running that is deemed compatible (e.g. has the desired JVM characteristics)
* then this daemon may be used instead of starting a new process and it may have been started from a different “gradle home”.
* However, it is guaranteed to be the same version of Gradle. For more information on the Gradle Daemon, please consult
- * <a href="http://www.gradle.org/docs/current/userguide/gradle_daemon.html">the user guide</a>.
+ * <a href="http://docs.gradle.org/current/userguide/gradle_daemon.html">the user guide</a>.
*
* @return The home directory. May return null.
*/
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/Input.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/Input.java
index ae48955..45ea8d9 100755
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/Input.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/Input.java
@@ -21,6 +21,11 @@ import java.lang.annotation.*;
* <p>Attached to a task property to indicate that the property specifies some input value for the task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the property has changed. When used on a
+ * {@link java.io.File} object that refers to a file or directory, the up-to-date check is only dependent on the
+ * path and not the contents of the file or directory. To make it depend on the contents, use
+ * {@link org.gradle.api.tasks.InputFile} or {@link org.gradle.api.tasks.InputDirectory} respectively.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputDirectory.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputDirectory.java
index 0ff0ec2..eb4dc03 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputDirectory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputDirectory.java
@@ -21,6 +21,10 @@ import java.lang.annotation.*;
* <p>Marks a property as specifying an input directory for a task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the directory location or contents
+ * have changed. To make the task dependent on the directory location but not the
+ * contents, use an {@link org.gradle.api.tasks.Input} annotation instead.</p>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFile.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFile.java
index 3a6c1e3..4e0723e 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFile.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFile.java
@@ -21,6 +21,10 @@ import java.lang.annotation.*;
* <p>Marks a property as specifying an input file for a task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the file path or contents
+ * have changed. To make the up-to-date check only dependent on the path and not the contents
+ * of the file or directory, annotate it instead with {@link org.gradle.api.tasks.Input}.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFiles.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFiles.java
index 3813185..1b0d3ff 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFiles.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/InputFiles.java
@@ -21,6 +21,9 @@ import java.lang.annotation.*;
* <p>Marks a property as specifying the input files for a task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the file paths or contents
+ * have changed. Also see {@link org.gradle.api.tasks.InputDirectory}.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectories.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectories.java
index 37be99f..54081c7 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectories.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectories.java
@@ -22,6 +22,9 @@ import java.lang.annotation.*;
* <p>Marks a property as specifying one or more output directories for a task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the directory paths or task
+ * output to those directories have been modified since the task was last run.</p>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectory.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectory.java
index f0c98a0..e164f5b 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputDirectory.java
@@ -21,6 +21,9 @@ import java.lang.annotation.*;
* <p>Marks a property as specifying an output directory for a task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the directory path or task
+ * output to that directory has been modified since the task was last run.</p>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFile.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFile.java
index b802536..383b907 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFile.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFile.java
@@ -21,6 +21,9 @@ import java.lang.annotation.*;
* <p>Marks a property as specifying an output file for a task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the file path or contents
+ * are different to when the task was last run.</p>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFiles.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFiles.java
index 103ca98..f2b52ab 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFiles.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/OutputFiles.java
@@ -22,6 +22,9 @@ import java.lang.annotation.*;
* <p>Marks a property as specifying one or more output files for a task.</p>
*
* <p>This annotation should be attached to the getter method or the field for the property.</p>
+ *
+ * <p>This will cause the task to be considered out-of-date when the file paths or contents
+ * are different to when the task was last run.</p>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/subprojects/core/src/main/groovy/org/gradle/api/tasks/incremental/IncrementalTaskInputs.java b/subprojects/core/src/main/groovy/org/gradle/api/tasks/incremental/IncrementalTaskInputs.java
index a724912..be5099f 100644
--- a/subprojects/core/src/main/groovy/org/gradle/api/tasks/incremental/IncrementalTaskInputs.java
+++ b/subprojects/core/src/main/groovy/org/gradle/api/tasks/incremental/IncrementalTaskInputs.java
@@ -29,13 +29,13 @@ import org.gradle.api.NonExtensible;
*
* <pre autoTested="true">
* class IncrementalReverseTask extends DefaultTask {
- * @InputDirectory
+ * {@literal @}InputDirectory
* def File inputDir
*
- * @OutputDirectory
+ * {@literal @}OutputDirectory
* def File outputDir
*
- * @TaskAction
+ * {@literal @}TaskAction
* void execute(IncrementalTaskInputs inputs) {
* if (!inputs.incremental)
* project.delete(outputDir.listFiles())
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultInitScriptProcessor.java b/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultInitScriptProcessor.java
index cb2360d..c94e636 100644
--- a/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultInitScriptProcessor.java
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultInitScriptProcessor.java
@@ -20,7 +20,6 @@ import org.gradle.api.internal.GradleInternal;
import org.gradle.api.internal.initialization.ClassLoaderScope;
import org.gradle.api.internal.initialization.ScriptHandlerFactory;
import org.gradle.groovy.scripts.ScriptSource;
-import org.gradle.initialization.InitScript;
import org.gradle.internal.id.IdGenerator;
import org.gradle.internal.id.LongIdGenerator;
@@ -46,7 +45,7 @@ public class DefaultInitScriptProcessor implements InitScriptProcessor {
String id = uri == null ? idGenerator.generateId().toString() : uri.toString();
ClassLoaderScope scriptScope = baseScope.createChild("init-" + id);
ScriptHandler scriptHandler = scriptHandlerFactory.create(initScript, scriptScope);
- ScriptPlugin configurer = configurerFactory.create(initScript, scriptHandler, scriptScope, baseScope, "initscript", InitScript.class, false);
+ ScriptPlugin configurer = configurerFactory.create(initScript, scriptHandler, scriptScope, baseScope, true);
configurer.apply(gradle);
}
}
\ No newline at end of file
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultScriptPluginFactory.java b/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultScriptPluginFactory.java
index 5306604..1c36eea 100755
--- a/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultScriptPluginFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultScriptPluginFactory.java
@@ -18,20 +18,19 @@ package org.gradle.configuration;
import org.gradle.api.initialization.dsl.ScriptHandler;
import org.gradle.api.internal.DocumentationRegistry;
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.api.internal.SettingsInternal;
import org.gradle.api.internal.file.FileLookup;
import org.gradle.api.internal.initialization.ClassLoaderScope;
import org.gradle.api.internal.initialization.ScriptHandlerFactory;
import org.gradle.api.internal.initialization.ScriptHandlerInternal;
-import org.gradle.api.internal.plugins.PluginAwareInternal;
import org.gradle.api.internal.plugins.PluginManagerInternal;
import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.api.internal.project.ProjectScript;
import org.gradle.groovy.scripts.*;
import org.gradle.groovy.scripts.internal.*;
import org.gradle.internal.Actions;
import org.gradle.internal.Factory;
import org.gradle.internal.reflect.Instantiator;
-import org.gradle.internal.serialize.BaseSerializerFactory;
import org.gradle.internal.service.DefaultServiceRegistry;
import org.gradle.logging.LoggingManagerInternal;
import org.gradle.model.dsl.internal.transform.ClosureCreationInterceptingVerifier;
@@ -51,6 +50,8 @@ public class DefaultScriptPluginFactory implements ScriptPluginFactory {
private final FileLookup fileLookup;
private final DocumentationRegistry documentationRegistry;
private final ModelRuleSourceDetector modelRuleSourceDetector;
+ private final BuildScriptDataSerializer buildScriptDataSerializer = new BuildScriptDataSerializer();
+ private final PluginRequestsSerializer pluginRequestsSerializer = new PluginRequestsSerializer();
public DefaultScriptPluginFactory(ScriptCompilerFactory scriptCompilerFactory,
Factory<LoggingManagerInternal> loggingManagerFactory,
@@ -70,30 +71,25 @@ public class DefaultScriptPluginFactory implements ScriptPluginFactory {
this.modelRuleSourceDetector = modelRuleSourceDetector;
}
- public ScriptPlugin create(ScriptSource scriptSource, ScriptHandler scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, String classpathClosureName, Class<? extends BasicScript> scriptClass, boolean ownerScript) {
- return new ScriptPluginImpl(scriptSource, (ScriptHandlerInternal) scriptHandler, targetScope, baseScope, classpathClosureName, scriptClass, ownerScript);
+ public ScriptPlugin create(ScriptSource scriptSource, ScriptHandler scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, boolean topLevelScript) {
+ return new ScriptPluginImpl(scriptSource, (ScriptHandlerInternal) scriptHandler, targetScope, baseScope, topLevelScript);
}
private class ScriptPluginImpl implements ScriptPlugin {
private final ScriptSource scriptSource;
private final ClassLoaderScope targetScope;
private final ClassLoaderScope baseScope;
- private final String classpathClosureName;
- private final Class<? extends BasicScript> scriptType;
private final ScriptHandlerInternal scriptHandler;
- private final boolean ownerScript;
+ private final boolean topLevelScript;
- public ScriptPluginImpl(ScriptSource scriptSource, ScriptHandlerInternal scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, String classpathClosureName, Class<? extends BasicScript> scriptType, boolean ownerScript) {
+ public ScriptPluginImpl(ScriptSource scriptSource, ScriptHandlerInternal scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, boolean topLevelScript) {
this.scriptSource = scriptSource;
this.targetScope = targetScope;
this.baseScope = baseScope;
- this.classpathClosureName = classpathClosureName;
this.scriptHandler = scriptHandler;
- this.scriptType = scriptType;
- this.ownerScript = ownerScript;
+ this.topLevelScript = topLevelScript;
}
-
public ScriptSource getSource() {
return scriptSource;
}
@@ -109,52 +105,68 @@ public class DefaultScriptPluginFactory implements ScriptPluginFactory {
services.add(FileLookup.class, fileLookup);
services.add(ModelRuleSourceDetector.class, modelRuleSourceDetector);
- final ScriptCompiler compiler = scriptCompilerFactory.createCompiler(scriptSource);
+ final ScriptTarget scriptTarget = wrap(target);
+
+ ScriptCompiler compiler = scriptCompilerFactory.createCompiler(scriptSource);
// Pass 1, extract plugin requests and execute buildscript {}, ignoring (i.e. not even compiling) anything else
- boolean supportsPluginsBlock = ProjectScript.class.isAssignableFrom(scriptType);
+ Class<? extends BasicScript> scriptType = scriptTarget.getScriptClass();
+ boolean supportsPluginsBlock = scriptTarget.getSupportsPluginsBlock();
String onPluginBlockError = supportsPluginsBlock ? null : "Only Project build scripts can contain plugins {} blocks";
-
+ String classpathClosureName = scriptTarget.getClasspathBlockName();
InitialPassStatementTransformer initialPassStatementTransformer = new InitialPassStatementTransformer(classpathClosureName, onPluginBlockError, scriptSource, documentationRegistry);
SubsetScriptTransformer initialTransformer = new SubsetScriptTransformer(initialPassStatementTransformer);
- CompileOperation<PluginRequests> initialOperation = new FactoryBackedCompileOperation<PluginRequests>(classpathClosureName, initialTransformer, initialPassStatementTransformer, PluginRequestsSerializer.INSTANCE);
+ CompileOperation<PluginRequests> initialOperation = new FactoryBackedCompileOperation<PluginRequests>("cp_" + scriptTarget.getId(), initialTransformer, initialPassStatementTransformer, pluginRequestsSerializer);
- ScriptRunner<? extends BasicScript, PluginRequests> initialRunner = compiler.compile(scriptType, initialOperation, baseScope.getExportClassLoader(), classpathClosureName, Actions.doNothing());
- initialRunner.getScript().init(target, services);
- initialRunner.run();
+ ScriptRunner<? extends BasicScript, PluginRequests> initialRunner = compiler.compile(scriptType, initialOperation, baseScope.getExportClassLoader(), Actions.doNothing());
+ initialRunner.run(target, services);
- PluginRequests pluginRequests = initialRunner.getCompiledScript().getData();
- PluginManagerInternal pluginManager = target instanceof PluginAwareInternal ? ((PluginAwareInternal) target).getPluginManager() : null;
+ PluginRequests pluginRequests = initialRunner.getData();
+ PluginManagerInternal pluginManager = scriptTarget.getPluginManager();
pluginRequestApplicator.applyPlugins(pluginRequests, scriptHandler, pluginManager, targetScope);
// Pass 2, compile everything except buildscript {} and plugin requests, then run
BuildScriptTransformer buildScriptTransformer = new BuildScriptTransformer(classpathClosureName, scriptSource);
- String operationId = "no_" + classpathClosureName;
+ String operationId = scriptTarget.getId();
if (ModelBlockTransformer.isEnabled()) {
operationId = "m_".concat(operationId);
}
- CompileOperation<Boolean> operation = new FactoryBackedCompileOperation<Boolean>(operationId, buildScriptTransformer, buildScriptTransformer, BaseSerializerFactory.BOOLEAN_SERIALIZER);
+ CompileOperation<BuildScriptData> operation = new FactoryBackedCompileOperation<BuildScriptData>(operationId, buildScriptTransformer, buildScriptTransformer, buildScriptDataSerializer);
- final ScriptRunner<? extends BasicScript, Boolean> runner = compiler.compile(scriptType, operation, targetScope.getLocalClassLoader(), classpathClosureName, ClosureCreationInterceptingVerifier.INSTANCE);
+ final ScriptRunner<? extends BasicScript, BuildScriptData> runner = compiler.compile(scriptType, operation, targetScope.getLocalClassLoader(), ClosureCreationInterceptingVerifier.INSTANCE);
+ if (scriptTarget.getSupportsMethodInheritance() && runner.getHasMethods()) {
+ scriptTarget.attachScript(runner.getScript());
+ }
+ if (!runner.getRunDoesSomething()) {
+ return;
+ }
Runnable buildScriptRunner = new Runnable() {
public void run() {
- BasicScript script = runner.getScript();
- script.init(target, services);
- if (ownerScript && target instanceof ScriptAware) {
- ((ScriptAware) target).setScript(script);
- }
- runner.run();
+ runner.run(target, services);
}
};
- Boolean hasImperativeStatements = runner.getCompiledScript().getData();
- if (!hasImperativeStatements && target instanceof ProjectInternal) {
- ((ProjectInternal) target).addDeferredConfiguration(buildScriptRunner);
+ boolean hasImperativeStatements = runner.getData().getHasImperativeStatements();
+ scriptTarget.addConfiguration(buildScriptRunner, !hasImperativeStatements);
+ }
+
+ private ScriptTarget wrap(Object target) {
+ if (target instanceof ProjectInternal && topLevelScript) {
+ // Only use this for top level project scripts
+ return new ProjectScriptTarget((ProjectInternal) target);
+ }
+ if (target instanceof GradleInternal && topLevelScript) {
+ // Only use this for top level init scripts
+ return new InitScriptTarget((GradleInternal) target);
+ }
+ if (target instanceof SettingsInternal && topLevelScript) {
+ // Only use this for top level settings scripts
+ return new SettingScriptTarget((SettingsInternal) target);
} else {
- buildScriptRunner.run();
+ return new DefaultScriptTarget(target);
}
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultScriptTarget.java b/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultScriptTarget.java
new file mode 100644
index 0000000..ab0bfb1
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/DefaultScriptTarget.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.configuration;
+
+import groovy.lang.Script;
+import org.gradle.api.internal.plugins.PluginAwareInternal;
+import org.gradle.api.internal.plugins.PluginManagerInternal;
+import org.gradle.groovy.scripts.BasicScript;
+import org.gradle.groovy.scripts.DefaultScript;
+
+public class DefaultScriptTarget implements ScriptTarget {
+ private final Object target;
+
+ public DefaultScriptTarget(Object target) {
+ this.target = target;
+ }
+
+ @Override
+ public String getId() {
+ return "dsl";
+ }
+
+ @Override
+ public PluginManagerInternal getPluginManager() {
+ return target instanceof PluginAwareInternal ? ((PluginAwareInternal) target).getPluginManager() : null;
+ }
+
+ @Override
+ public Class<? extends BasicScript> getScriptClass() {
+ return DefaultScript.class;
+ }
+
+ @Override
+ public String getClasspathBlockName() {
+ return "buildscript";
+ }
+
+ @Override
+ public boolean getSupportsPluginsBlock() {
+ return false;
+ }
+
+ @Override
+ public boolean getSupportsMethodInheritance() {
+ return false;
+ }
+
+ @Override
+ public void attachScript(Script script) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addConfiguration(Runnable runnable, boolean deferrable) {
+ runnable.run();
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/InitScriptTarget.java b/subprojects/core/src/main/groovy/org/gradle/configuration/InitScriptTarget.java
new file mode 100644
index 0000000..beff83c
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/InitScriptTarget.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.configuration;
+
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.groovy.scripts.BasicScript;
+import org.gradle.initialization.InitScript;
+
+public class InitScriptTarget extends DefaultScriptTarget {
+ public InitScriptTarget(GradleInternal target) {
+ super(target);
+ }
+
+ @Override
+ public String getId() {
+ return "init";
+ }
+
+ @Override
+ public Class<? extends BasicScript> getScriptClass() {
+ return InitScript.class;
+ }
+
+ @Override
+ public String getClasspathBlockName() {
+ return "initscript";
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/ProjectScriptTarget.java b/subprojects/core/src/main/groovy/org/gradle/configuration/ProjectScriptTarget.java
new file mode 100644
index 0000000..83fc50a
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/ProjectScriptTarget.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.configuration;
+
+import groovy.lang.Script;
+import org.gradle.api.internal.plugins.PluginManagerInternal;
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.project.ProjectScript;
+import org.gradle.groovy.scripts.BasicScript;
+
+public class ProjectScriptTarget implements ScriptTarget {
+ private final ProjectInternal target;
+
+ public ProjectScriptTarget(ProjectInternal target) {
+ this.target = target;
+ }
+
+ @Override
+ public PluginManagerInternal getPluginManager() {
+ return target.getPluginManager();
+ }
+
+ @Override
+ public String getId() {
+ return "proj";
+ }
+
+ @Override
+ public String getClasspathBlockName() {
+ return "buildscript";
+ }
+
+ @Override
+ public boolean getSupportsPluginsBlock() {
+ return true;
+ }
+
+ @Override
+ public boolean getSupportsMethodInheritance() {
+ return true;
+ }
+
+ @Override
+ public Class<? extends BasicScript> getScriptClass() {
+ return ProjectScript.class;
+ }
+
+ @Override
+ public void attachScript(Script script) {
+ target.setScript(script);
+ }
+
+ @Override
+ public void addConfiguration(Runnable runnable, boolean deferrable) {
+ if (deferrable) {
+ target.addDeferredConfiguration(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/ScriptPluginFactory.java b/subprojects/core/src/main/groovy/org/gradle/configuration/ScriptPluginFactory.java
index 6897068..4d2ce83 100755
--- a/subprojects/core/src/main/groovy/org/gradle/configuration/ScriptPluginFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/ScriptPluginFactory.java
@@ -17,9 +17,8 @@ package org.gradle.configuration;
import org.gradle.api.initialization.dsl.ScriptHandler;
import org.gradle.api.internal.initialization.ClassLoaderScope;
-import org.gradle.groovy.scripts.BasicScript;
import org.gradle.groovy.scripts.ScriptSource;
public interface ScriptPluginFactory {
- ScriptPlugin create(ScriptSource scriptSource, ScriptHandler scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, String classpathClosureName, Class<? extends BasicScript> scriptClass, boolean canonicalScript);
+ ScriptPlugin create(ScriptSource scriptSource, ScriptHandler scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, boolean topLevelScript);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/ScriptTarget.java b/subprojects/core/src/main/groovy/org/gradle/configuration/ScriptTarget.java
new file mode 100644
index 0000000..2bab9b4
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/ScriptTarget.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.configuration;
+
+import groovy.lang.Script;
+import org.gradle.api.internal.plugins.PluginManagerInternal;
+import org.gradle.groovy.scripts.BasicScript;
+
+/**
+ * A view over the target of a script. Represents the DSL that will be applied to the target.
+ */
+public interface ScriptTarget {
+ /**
+ * Returns a unique id for the DSL, used in paths and such.
+ */
+ String getId();
+
+ /**
+ * Attaches the target's main script to the target, if it needs it
+ */
+ void attachScript(Script script);
+
+ String getClasspathBlockName();
+
+ Class<? extends BasicScript> getScriptClass();
+
+ boolean getSupportsPluginsBlock();
+
+ boolean getSupportsMethodInheritance();
+
+ PluginManagerInternal getPluginManager();
+
+ /**
+ * Add a configuration action to be applied to the target.
+ *
+ * @param runnable The action. Should be run in the order provided.
+ * @param deferrable true when the action can be deferred
+ */
+ void addConfiguration(Runnable runnable, boolean deferrable);
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/SettingScriptTarget.java b/subprojects/core/src/main/groovy/org/gradle/configuration/SettingScriptTarget.java
new file mode 100644
index 0000000..1bbbb62
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/SettingScriptTarget.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.configuration;
+
+import org.gradle.api.internal.SettingsInternal;
+import org.gradle.groovy.scripts.BasicScript;
+import org.gradle.initialization.SettingsScript;
+
+public class SettingScriptTarget extends DefaultScriptTarget {
+ public SettingScriptTarget(SettingsInternal target) {
+ super(target);
+ }
+
+ @Override
+ public String getId() {
+ return "settings";
+ }
+
+ @Override
+ public Class<? extends BasicScript> getScriptClass() {
+ return SettingsScript.class;
+ }
+}
+
diff --git a/subprojects/core/src/main/groovy/org/gradle/configuration/project/BuildScriptProcessor.java b/subprojects/core/src/main/groovy/org/gradle/configuration/project/BuildScriptProcessor.java
index 5e6244d..9436ee1 100644
--- a/subprojects/core/src/main/groovy/org/gradle/configuration/project/BuildScriptProcessor.java
+++ b/subprojects/core/src/main/groovy/org/gradle/configuration/project/BuildScriptProcessor.java
@@ -16,7 +16,6 @@
package org.gradle.configuration.project;
import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.api.internal.project.ProjectScript;
import org.gradle.configuration.ScriptPlugin;
import org.gradle.configuration.ScriptPluginFactory;
import org.gradle.util.Clock;
@@ -35,7 +34,7 @@ public class BuildScriptProcessor implements ProjectConfigureAction {
LOGGER.info(String.format("Evaluating %s using %s.", project, project.getBuildScriptSource().getDisplayName()));
Clock clock = new Clock();
try {
- ScriptPlugin configurer = configurerFactory.create(project.getBuildScriptSource(), project.getBuildscript(), project.getClassLoaderScope(), project.getBaseClassLoaderScope(), "buildscript", ProjectScript.class, true);
+ ScriptPlugin configurer = configurerFactory.create(project.getBuildScriptSource(), project.getBuildscript(), project.getClassLoaderScope(), project.getBaseClassLoaderScope(), true);
configurer.apply(project);
} finally {
LOGGER.debug("Timing: Running the build script took " + clock.getTime());
diff --git a/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DefaultDeploymentRegistry.java b/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DefaultDeploymentRegistry.java
new file mode 100644
index 0000000..f6af37c
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DefaultDeploymentRegistry.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.deployment.internal;
+
+import com.google.common.collect.Maps;
+import org.gradle.api.invocation.Gradle;
+import org.gradle.internal.Cast;
+import org.gradle.internal.concurrent.CompositeStoppable;
+
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class DefaultDeploymentRegistry implements DeploymentRegistry {
+ private final Lock lock = new ReentrantLock();
+ private final Map<String, DeploymentHandle> handles = Maps.newHashMap();
+ private boolean stopped;
+
+ @Override
+ public void register(String id, DeploymentHandle handle) {
+ lock.lock();
+ try {
+ failIfStopped();
+ if (!handles.containsKey(id)) {
+ handles.put(id, handle);
+ } else {
+ throw new IllegalStateException("A deployment with id '" + id + "' is already registered.");
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public <T extends DeploymentHandle> T get(Class<T> handleType, String id) {
+ lock.lock();
+ try {
+ failIfStopped();
+ return Cast.cast(handleType, handles.get(id));
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public void onNewBuild(Gradle gradle) {
+ lock.lock();
+ try {
+ for (DeploymentHandle handle : handles.values()) {
+ handle.onNewBuild(gradle);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public void stop() {
+ lock.lock();
+ try {
+ CompositeStoppable.stoppable(handles.values()).stop();
+ } finally {
+ stopped = true;
+ handles.clear();
+ lock.unlock();
+ }
+ }
+
+ private void failIfStopped() {
+ if (stopped) {
+ throw new IllegalStateException("Cannot modify deployment handles once the registry has been stopped.");
+ }
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DeploymentHandle.java b/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DeploymentHandle.java
new file mode 100644
index 0000000..2c08879
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DeploymentHandle.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.deployment.internal;
+
+import org.gradle.api.invocation.Gradle;
+import org.gradle.internal.concurrent.Stoppable;
+
+public interface DeploymentHandle extends Stoppable {
+ boolean isRunning();
+ void onNewBuild(Gradle gradle);
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DeploymentRegistry.java b/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DeploymentRegistry.java
new file mode 100644
index 0000000..1bf2bd9
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/deployment/internal/DeploymentRegistry.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.deployment.internal;
+
+import net.jcip.annotations.ThreadSafe;
+import org.gradle.api.Nullable;
+import org.gradle.api.invocation.Gradle;
+import org.gradle.internal.concurrent.Stoppable;
+
+/**
+ * A registry of deployment handles.
+ */
+ at ThreadSafe
+public interface DeploymentRegistry extends Stoppable {
+ /**
+ * Registers a given deployment handle in the registry.
+ */
+ void register(String id, DeploymentHandle handle);
+
+ /**
+ * Retrieves a deployment handle from the registry with the given id and type.
+ *
+ * @return the registered deployment handle; null if no deployment is registered with the given id
+ */
+ @Nullable
+ <T extends DeploymentHandle> T get(Class<T> handleType, String id);
+
+ /**
+ * Passes the new Gradle build to all registered handles.
+ *
+ * @param gradle new Gradle build
+ */
+ void onNewBuild(Gradle gradle);
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/execution/BuildConfigurationActionExecuter.java b/subprojects/core/src/main/groovy/org/gradle/execution/BuildConfigurationActionExecuter.java
new file mode 100644
index 0000000..7a069d2
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/execution/BuildConfigurationActionExecuter.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.execution;
+
+import org.gradle.api.internal.GradleInternal;
+
+import java.util.List;
+
+
+/**
+ * Selects the tasks requested for a build.
+ */
+public interface BuildConfigurationActionExecuter {
+ /**
+ * Selects the tasks to execute, if any. This method is called before any other methods on this executer.
+ */
+ void select(GradleInternal gradle);
+
+ /**
+ * registers actions allowing late customization of handled BuildConfigurationActions, if any. This method is called before any other methods on this executer.
+ */
+ void setTaskSelectors(List<? extends BuildConfigurationAction> taskSelectors);
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/execution/BuildExecuter.java b/subprojects/core/src/main/groovy/org/gradle/execution/BuildExecuter.java
index 1a153d4..318703e 100644
--- a/subprojects/core/src/main/groovy/org/gradle/execution/BuildExecuter.java
+++ b/subprojects/core/src/main/groovy/org/gradle/execution/BuildExecuter.java
@@ -18,17 +18,11 @@ package org.gradle.execution;
import org.gradle.api.internal.GradleInternal;
/**
- * Selects and executes the tasks requested for a build.
+ * Executes the tasks requested for a build.
*/
public interface BuildExecuter {
-
- /**
- * Selects the tasks to execute, if any. This method is called before any other methods on this executer.
- */
- void select(GradleInternal gradle);
-
/**
- * Executes the selected tasks. Called after {@link #select(org.gradle.api.internal.GradleInternal)}.
+ * Executes the selected tasks.
*/
- void execute();
+ void execute(GradleInternal gradle);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/execution/DefaultBuildConfigurationActionExecuter.java b/subprojects/core/src/main/groovy/org/gradle/execution/DefaultBuildConfigurationActionExecuter.java
new file mode 100644
index 0000000..e6c7575
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/execution/DefaultBuildConfigurationActionExecuter.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.execution;
+
+import com.google.common.collect.Lists;
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.util.CollectionUtils;
+
+import java.util.List;
+
+public class DefaultBuildConfigurationActionExecuter implements BuildConfigurationActionExecuter {
+ private final List<BuildConfigurationAction> configurationActions;
+ private List<? extends BuildConfigurationAction> taskSelectors;
+
+ public DefaultBuildConfigurationActionExecuter(Iterable<? extends BuildConfigurationAction> configurationActions, Iterable<? extends BuildConfigurationAction> defaultTaskSelectors) {
+ this.taskSelectors = Lists.newArrayList(defaultTaskSelectors);
+ this.configurationActions = Lists.newArrayList(configurationActions);
+ }
+
+ public void select(GradleInternal gradle) {
+ List<BuildConfigurationAction> processingBuildActions = CollectionUtils.flattenCollections(BuildConfigurationAction.class, configurationActions, taskSelectors);
+ configure(processingBuildActions, gradle, 0);
+ }
+
+ @Override
+ public void setTaskSelectors(List<? extends BuildConfigurationAction> taskSelectors) {
+ this.taskSelectors = taskSelectors;
+ }
+
+ private void configure(final List<BuildConfigurationAction> processingConfigurationActions, final GradleInternal gradle, final int index) {
+ if (index >= processingConfigurationActions.size()) {
+ return;
+ }
+ processingConfigurationActions.get(index).configure(new BuildExecutionContext() {
+ public GradleInternal getGradle() {
+ return gradle;
+ }
+
+ public void proceed() {
+ configure(processingConfigurationActions, gradle, index + 1);
+ }
+
+ });
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/execution/DefaultBuildExecuter.java b/subprojects/core/src/main/groovy/org/gradle/execution/DefaultBuildExecuter.java
index 5591c20..9cc3535 100644
--- a/subprojects/core/src/main/groovy/org/gradle/execution/DefaultBuildExecuter.java
+++ b/subprojects/core/src/main/groovy/org/gradle/execution/DefaultBuildExecuter.java
@@ -21,41 +21,16 @@ import org.gradle.api.internal.GradleInternal;
import java.util.List;
public class DefaultBuildExecuter implements BuildExecuter {
- private final List<BuildConfigurationAction> configurationActions;
private final List<BuildExecutionAction> executionActions;
- private GradleInternal gradle;
- public DefaultBuildExecuter(Iterable<? extends BuildConfigurationAction> configurationActions, Iterable<? extends BuildExecutionAction> executionActions) {
- this.configurationActions = Lists.newArrayList(configurationActions);
+ public DefaultBuildExecuter(Iterable<? extends BuildExecutionAction> executionActions) {
this.executionActions = Lists.newArrayList(executionActions);
}
-
- public void select(GradleInternal gradle) {
- this.gradle = gradle;
- configure(0);
- }
-
- private void configure(final int index) {
- if (index >= configurationActions.size()) {
- return;
- }
- configurationActions.get(index).configure(new BuildExecutionContext() {
- public GradleInternal getGradle() {
- return gradle;
- }
-
- public void proceed() {
- configure(index + 1);
- }
-
- });
- }
-
- public void execute() {
- execute(0);
+ public void execute(GradleInternal gradle) {
+ execute(gradle, 0);
}
- private void execute(final int index) {
+ private void execute(final GradleInternal gradle, final int index) {
if (index >= executionActions.size()) {
return;
}
@@ -65,7 +40,7 @@ public class DefaultBuildExecuter implements BuildExecuter {
}
public void proceed() {
- execute(index + 1);
+ execute(gradle, index + 1);
}
});
diff --git a/subprojects/core/src/main/groovy/org/gradle/execution/TaskSelectionException.java b/subprojects/core/src/main/groovy/org/gradle/execution/TaskSelectionException.java
index 9375fb3..e30f1f8 100644
--- a/subprojects/core/src/main/groovy/org/gradle/execution/TaskSelectionException.java
+++ b/subprojects/core/src/main/groovy/org/gradle/execution/TaskSelectionException.java
@@ -24,10 +24,9 @@ import org.gradle.logging.StyledTextOutput;
import static org.gradle.logging.StyledTextOutput.Style.UserInput;
/**
- * A {@code TaskSelectionException} is thrown when the tasks to execute cannot be selected due to some user input
- * problem.
+ * A {@code TaskSelectionException} is thrown when the tasks to execute cannot be selected due to some user input problem.
*/
-public class TaskSelectionException extends InvalidUserDataException implements FailureResolutionAware{
+public class TaskSelectionException extends InvalidUserDataException implements FailureResolutionAware {
public TaskSelectionException(String message) {
super(message);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/execution/taskgraph/DefaultTaskGraphExecuter.java b/subprojects/core/src/main/groovy/org/gradle/execution/taskgraph/DefaultTaskGraphExecuter.java
index 0ae28ad..a86cf97 100644
--- a/subprojects/core/src/main/groovy/org/gradle/execution/taskgraph/DefaultTaskGraphExecuter.java
+++ b/subprojects/core/src/main/groovy/org/gradle/execution/taskgraph/DefaultTaskGraphExecuter.java
@@ -64,7 +64,6 @@ public class DefaultTaskGraphExecuter implements TaskGraphExecuter {
private final ListenerBroadcast<InternalTaskExecutionListener> internalTaskListeners;
private final DefaultTaskExecutionPlan taskExecutionPlan;
private final BuildOperationExecutor buildOperationExecutor;
- private final Object eventNotificationLock = new Object();
private TaskGraphState taskGraphState = TaskGraphState.EMPTY;
public DefaultTaskGraphExecuter(ListenerManager listenerManager, TaskPlanExecutor taskPlanExecutor, Factory<? extends TaskExecuter> taskExecuter, BuildCancellationToken cancellationToken, TimeProvider timeProvider, BuildOperationExecutor buildOperationExecutor) {
@@ -108,7 +107,7 @@ public class DefaultTaskGraphExecuter implements TaskGraphExecuter {
graphListeners.getSource().graphPopulated(this);
try {
- taskPlanExecutor.process(taskExecutionPlan, new EventFiringTaskWorker(taskExecuter.create()));
+ taskPlanExecutor.process(taskExecutionPlan, new EventFiringTaskWorker(taskExecuter.create(), buildOperationExecutor.getCurrentOperationId()));
logger.debug("Timing: Executing the DAG took " + clock.getTime());
} finally {
taskExecutionPlan.clear();
@@ -185,35 +184,27 @@ public class DefaultTaskGraphExecuter implements TaskGraphExecuter {
*/
private class EventFiringTaskWorker implements Action<TaskInternal> {
private final TaskExecuter taskExecuter;
+ private final Object parentOperationId;
- public EventFiringTaskWorker(TaskExecuter taskExecuter) {
+ public EventFiringTaskWorker(TaskExecuter taskExecuter, Object parentOperationId) {
this.taskExecuter = taskExecuter;
+ this.parentOperationId = parentOperationId;
}
@Override
public void execute(TaskInternal task) {
Object id = OperationIdGenerator.generateId(task);
- Object parentId = buildOperationExecutor.getCurrentOperationId();
- TaskOperationInternal taskOperation = new TaskOperationInternal(id, parentId, task);
+ TaskOperationInternal taskOperation = new TaskOperationInternal(id, parentOperationId, task);
TaskStateInternal state = task.getState();
long startTime = timeProvider.getCurrentTime();
- // TODO - move serialization to ListenerManager contract
- synchronized (eventNotificationLock) {
- internalTaskListeners.getSource().beforeExecute(taskOperation, new OperationStartEvent(startTime));
- }
+ internalTaskListeners.getSource().beforeExecute(taskOperation, new OperationStartEvent(startTime));
try {
- synchronized (eventNotificationLock) {
- taskListeners.getSource().beforeExecute(task);
- }
+ taskListeners.getSource().beforeExecute(task);
taskExecuter.execute(task, task.getState(), new DefaultTaskExecutionContext());
- synchronized (eventNotificationLock) {
- taskListeners.getSource().afterExecute(task, state);
- }
+ taskListeners.getSource().afterExecute(task, state);
} finally {
- synchronized (eventNotificationLock) {
- long endTime = timeProvider.getCurrentTime();
- internalTaskListeners.getSource().afterExecute(taskOperation, new OperationResult(startTime, endTime, task.getState().getFailure()));
- }
+ long endTime = timeProvider.getCurrentTime();
+ internalTaskListeners.getSource().afterExecute(taskOperation, new OperationResult(startTime, endTime, task.getState().getFailure()));
}
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactory.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactory.java
index 2c31a15..76f5a7f 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactory.java
@@ -45,10 +45,10 @@ public class DefaultScriptCompilerFactory implements ScriptCompilerFactory {
}
@Override
- public <T extends Script, M> ScriptRunner<T, M> compile(Class<T> scriptType, CompileOperation<M> extractingTransformer, ClassLoader classloader, String classpathClosureName, Action<? super ClassNode> verifier) {
+ public <T extends Script, M> ScriptRunner<T, M> compile(Class<T> scriptType, CompileOperation<M> extractingTransformer, ClassLoader classloader, Action<? super ClassNode> verifier) {
ClassLoaderId classLoaderId = ClassLoaderIds.buildScript(source.getFileName(), extractingTransformer.getId());
- CompiledScript<T, M> scriptClass = scriptClassCompiler.compile(source, classloader, classLoaderId, extractingTransformer, classpathClosureName, scriptType, verifier);
- return scriptRunnerFactory.create(scriptClass, source, classloader);
+ CompiledScript<T, M> compiledScript = scriptClassCompiler.compile(source, classloader, classLoaderId, extractingTransformer, scriptType, verifier);
+ return scriptRunnerFactory.create(compiledScript, source, classloader);
}
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptAware.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptAware.java
deleted file mode 100755
index 4e43808..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptAware.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2009 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.groovy.scripts;
-
-public interface ScriptAware {
- void setScript(groovy.lang.Script script);
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptCompiler.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptCompiler.java
index d5cfe91..350240b 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptCompiler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptCompiler.java
@@ -30,5 +30,5 @@ public interface ScriptCompiler {
* @return a {@code ScriptRunner} for the script.
* @throws ScriptCompilationException On compilation failure.
*/
- <T extends Script, M> ScriptRunner<T, M> compile(Class<T> scriptType, CompileOperation<M> extractingTransformer, ClassLoader classloader, String classpathClosureName, Action<? super ClassNode> verifier);
+ <T extends Script, M> ScriptRunner<T, M> compile(Class<T> scriptType, CompileOperation<M> extractingTransformer, ClassLoader classloader, Action<? super ClassNode> verifier);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptExecutionListener.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptExecutionListener.java
index 5ab3ebc..074b5d0 100755
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptExecutionListener.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptExecutionListener.java
@@ -16,7 +16,5 @@
package org.gradle.groovy.scripts;
public interface ScriptExecutionListener {
- void beforeScript(Script script);
-
- void afterScript(Script script, Throwable result);
+ void scriptClassLoaded(ScriptSource source, Class<? extends Script> scriptClass);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptRunner.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptRunner.java
index ecbf76c..5d70bef 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptRunner.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/ScriptRunner.java
@@ -15,27 +15,39 @@
*/
package org.gradle.groovy.scripts;
-import groovy.lang.Script;
import org.gradle.api.GradleScriptException;
-import org.gradle.groovy.scripts.internal.CompiledScript;
+import org.gradle.internal.service.ServiceRegistry;
/**
* Executes a script of type T.
*/
-public interface ScriptRunner<T extends Script, M> extends Runnable {
+public interface ScriptRunner<T extends Script, M> {
/**
- * Returns the script which will be executed by this runner.
+ * Returns the script which will be executed by this runner. This method is relatively expensive.
*
* @return the script.
*/
T getScript();
- CompiledScript<T, M> getCompiledScript();
+ /**
+ * Returns the data extracted at compilation time.
+ */
+ M getData();
+
+ /**
+ * Returns true when the script will run some code when executed. Returns false for a script whose `run()` method is effectively empty.
+ */
+ boolean getRunDoesSomething();
+
+ /**
+ * Returns true when the script defines some methods.
+ */
+ boolean getHasMethods();
/**
- * Executes the script.
+ * Executes the script. This is generally more efficient than using {@link #getScript()}.
*
* @throws GradleScriptException On execution failure.
*/
- void run() throws GradleScriptException;
+ void run(Object target, ServiceRegistry scriptServices) throws GradleScriptException;
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/AsmBackedEmptyScriptGenerator.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/AsmBackedEmptyScriptGenerator.java
deleted file mode 100644
index 8df45a8..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/AsmBackedEmptyScriptGenerator.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.groovy.scripts.internal;
-
-import groovy.lang.Script;
-import org.gradle.internal.reflect.JavaReflectionUtil;
-import org.gradle.internal.reflect.JavaMethod;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class AsmBackedEmptyScriptGenerator implements EmptyScriptGenerator {
- private static final Map<Class<?>, Class<?>> CACHED_CLASSES = new HashMap<Class<?>, Class<?>>();
-
- public <T extends Script> Class<? extends T> generate(Class<T> type) {
- Class<?> subclass = CACHED_CLASSES.get(type);
- if (subclass == null) {
- subclass = generateEmptyScriptClass(type);
- CACHED_CLASSES.put(type, subclass);
- }
- return subclass.asSubclass(type);
- }
-
- private <T extends Script> Class<? extends T> generateEmptyScriptClass(Class<T> type) {
- ClassWriter visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- String typeName = type.getName() + "_Decorated";
- Type generatedType = Type.getType("L" + typeName.replaceAll("\\.", "/") + ";");
- Type superclassType = Type.getType(type);
- visitor.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, generatedType.getInternalName(), null,
- superclassType.getInternalName(), new String[0]);
-
- // Constructor
-
- String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[0]);
- MethodVisitor methodVisitor = visitor.visitMethod(Opcodes.ACC_PUBLIC, "<init>", constructorDescriptor, null,
- new String[0]);
- methodVisitor.visitCode();
-
- // super()
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
- methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superclassType.getInternalName(), "<init>",
- constructorDescriptor);
-
- methodVisitor.visitInsn(Opcodes.RETURN);
- methodVisitor.visitMaxs(0, 0);
- methodVisitor.visitEnd();
-
- // run() method
-
- String runDesciptor = Type.getMethodDescriptor(Type.getType(Object.class), new Type[0]);
- methodVisitor = visitor.visitMethod(Opcodes.ACC_PUBLIC, "run", runDesciptor, null, new String[0]);
- methodVisitor.visitCode();
-
- // return null
- methodVisitor.visitInsn(Opcodes.ACONST_NULL);
-
- methodVisitor.visitInsn(Opcodes.ARETURN);
- methodVisitor.visitMaxs(0, 0);
- methodVisitor.visitEnd();
-
- visitor.visitEnd();
-
- byte[] bytecode = visitor.toByteArray();
- JavaMethod<ClassLoader, Class> method = JavaReflectionUtil.method(ClassLoader.class, Class.class, "defineClass", String.class, byte[].class, int.class, int.class);
- @SuppressWarnings("unchecked")
- Class<T> clazz = method.invoke(type.getClassLoader(), typeName, bytecode, 0, bytecode.length);
- return clazz;
- }
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptData.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptData.java
new file mode 100644
index 0000000..1496059
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptData.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.groovy.scripts.internal;
+
+/**
+ * Data extracted from a build script at compile time.
+ */
+public class BuildScriptData {
+ private final boolean hasImperativeStatements;
+
+ public BuildScriptData(boolean hasImperativeStatements) {
+ this.hasImperativeStatements = hasImperativeStatements;
+ }
+
+ /**
+ * Returns true when the build script contains legacy imperative statements. When false, the script contains only model rule statements and its execution
+ * can be deferred until rule execution is required.
+ */
+ public boolean getHasImperativeStatements() {
+ return hasImperativeStatements;
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptDataSerializer.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptDataSerializer.java
new file mode 100644
index 0000000..24e08dd
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptDataSerializer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.groovy.scripts.internal;
+
+import org.gradle.internal.serialize.Decoder;
+import org.gradle.internal.serialize.Encoder;
+import org.gradle.internal.serialize.Serializer;
+
+public class BuildScriptDataSerializer implements Serializer<BuildScriptData> {
+ @Override
+ public BuildScriptData read(Decoder decoder) throws Exception {
+ return new BuildScriptData(decoder.readBoolean());
+ }
+
+ @Override
+ public void write(Encoder encoder, BuildScriptData value) throws Exception {
+ encoder.writeBoolean(value.getHasImperativeStatements());
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformer.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformer.java
index 11c85d2..5a2f753 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformer.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformer.java
@@ -26,7 +26,7 @@ import org.gradle.model.dsl.internal.transform.ModelBlockTransformer;
import java.util.Arrays;
import java.util.List;
-public class BuildScriptTransformer implements Transformer, Factory<Boolean> {
+public class BuildScriptTransformer implements Transformer, Factory<BuildScriptData> {
private final Spec<? super Statement> filter;
private final ScriptSource scriptSource;
@@ -47,15 +47,15 @@ public class BuildScriptTransformer implements Transformer, Factory<Boolean> {
public void register(CompilationUnit compilationUnit) {
new FilteringScriptTransformer(filter).register(compilationUnit);
new TaskDefinitionScriptTransformer().register(compilationUnit);
- new FixMainScriptTransformer().register(compilationUnit); // TODO - remove this
+ new FixMainScriptTransformer().register(compilationUnit);
new StatementLabelsScriptTransformer().register(compilationUnit);
- new ScriptSourceDescriptionTransformer(scriptSource.getDisplayName()).register(compilationUnit);
+ new ScriptSourceTransformer(scriptSource.getDisplayName(), scriptSource.getResource().getURI()).register(compilationUnit);
new ModelBlockTransformer().register(compilationUnit);
imperativeStatementDetectingTransformer.register(compilationUnit);
}
@Override
- public Boolean create() {
- return imperativeStatementDetectingTransformer.create();
+ public BuildScriptData create() {
+ return new BuildScriptData(imperativeStatementDetectingTransformer.isImperativeStatementDetected());
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompiler.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompiler.java
index e6c0b08..242d151 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompiler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompiler.java
@@ -34,11 +34,11 @@ public class CachingScriptClassCompiler implements ScriptClassCompiler {
}
@Override
- public <T extends Script, M> CompiledScript<T, M> compile(ScriptSource source, ClassLoader classLoader, final ClassLoaderId classLoaderId, CompileOperation<M> operation, String classpathClosureName, Class<T> scriptBaseClass, Action<? super ClassNode> verifier) {
- Key key = new Key(source.getClassName(), classLoader, operation.getId(), scriptBaseClass.getName());
+ public <T extends Script, M> CompiledScript<T, M> compile(ScriptSource source, ClassLoader classLoader, ClassLoaderId classLoaderId, CompileOperation<M> operation, Class<T> scriptBaseClass, Action<? super ClassNode> verifier) {
+ Key key = new Key(source.getClassName(), classLoader, operation.getId());
CompiledScript<T, M> compiledScript = Cast.uncheckedCast(cachedCompiledScripts.get(key));
if (compiledScript == null) {
- compiledScript = scriptClassCompiler.compile(source, classLoader, classLoaderId, operation, classpathClosureName, scriptBaseClass, verifier);
+ compiledScript = scriptClassCompiler.compile(source, classLoader, classLoaderId, operation, scriptBaseClass, verifier);
cachedCompiledScripts.put(key, compiledScript);
}
return compiledScript;
@@ -47,14 +47,12 @@ public class CachingScriptClassCompiler implements ScriptClassCompiler {
private static class Key {
private final String className;
private final ClassLoader classLoader;
- private final String transformerId;
- private final String baseClassName;
+ private final String dslId;
- public Key(String className, ClassLoader classLoader, String transformerId, String baseClassName) {
+ public Key(String className, ClassLoader classLoader, String dslId) {
this.className = className;
this.classLoader = classLoader;
- this.transformerId = transformerId;
- this.baseClassName = baseClassName;
+ this.dslId = dslId;
}
@Override
@@ -68,18 +66,16 @@ public class CachingScriptClassCompiler implements ScriptClassCompiler {
Key key = (Key) o;
- return baseClassName.equals(key.baseClassName)
- && classLoader.equals(key.classLoader)
+ return classLoader.equals(key.classLoader)
&& className.equals(key.className)
- && transformerId.equals(key.transformerId);
+ && dslId.equals(key.dslId);
}
@Override
public int hashCode() {
int result = className.hashCode();
result = 31 * result + classLoader.hashCode();
- result = 31 * result + transformerId.hashCode();
- result = 31 * result + baseClassName.hashCode();
+ result = 31 * result + dslId.hashCode();
return result;
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ClassCachingCompiledScript.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ClassCachingCompiledScript.java
deleted file mode 100644
index 9055ebe..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ClassCachingCompiledScript.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.groovy.scripts.internal;
-
-import groovy.lang.Script;
-
-public class ClassCachingCompiledScript<T extends Script, M> implements CompiledScript<T, M> {
-
- private final CompiledScript<T, M> delegate;
- private Class<? extends T> scriptClass;
-
- public ClassCachingCompiledScript(CompiledScript<T, M> delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public Class<? extends T> loadClass() {
- if (scriptClass == null) {
- scriptClass = delegate.loadClass();
- }
- return scriptClass;
- }
-
- @Override
- public M getData() {
- return delegate.getData();
- }
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompileOperation.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompileOperation.java
index 998c6ab..003cb23 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompileOperation.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompileOperation.java
@@ -40,6 +40,9 @@ public interface CompileOperation<T> {
Transformer getTransformer();
+ /**
+ * The data extracted from the script. Note that this method may be called without the transformer ever being invoked, in this case of an empty script.
+ */
T getExtractedData();
Serializer<T> getDataSerializer();
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompiledScript.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompiledScript.java
index 1328bd0..8f104c8 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompiledScript.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/CompiledScript.java
@@ -19,6 +19,15 @@ package org.gradle.groovy.scripts.internal;
import groovy.lang.Script;
public interface CompiledScript<T extends Script, D> {
+ /**
+ * Returns true if the `run()` method of this script is effectively empty and can be ignored.
+ */
+ boolean getRunDoesSomething();
+
+ /**
+ * Returns true if the script declares any methods.
+ */
+ boolean getHasMethods();
Class<? extends T> loadClass();
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandler.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandler.java
index 4bbe6f2..1a4ad80 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandler.java
@@ -31,7 +31,6 @@ import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
import org.codehaus.groovy.syntax.SyntaxException;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
-import org.gradle.api.UncheckedIOException;
import org.gradle.api.internal.initialization.loadercache.ClassLoaderCache;
import org.gradle.api.internal.initialization.loadercache.ClassLoaderId;
import org.gradle.configuration.ImportsReader;
@@ -48,7 +47,9 @@ import org.gradle.util.GFileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
@@ -58,20 +59,19 @@ import java.util.List;
public class DefaultScriptCompilationHandler implements ScriptCompilationHandler {
private Logger logger = LoggerFactory.getLogger(DefaultScriptCompilationHandler.class);
private static final NoOpGroovyResourceLoader NO_OP_GROOVY_RESOURCE_LOADER = new NoOpGroovyResourceLoader();
- private static final String EMPTY_SCRIPT_MARKER_FILE_NAME = "emptyScript.txt";
private static final String METADATA_FILE_NAME = "metadata.bin";
- private final EmptyScriptGenerator emptyScriptGenerator;
+ private static final int EMPTY_FLAG = 1;
+ private static final int HAS_METHODS_FLAG = 2;
private final ClassLoaderCache classLoaderCache;
private final String[] defaultImportPackages;
- public DefaultScriptCompilationHandler(EmptyScriptGenerator emptyScriptGenerator, ClassLoaderCache classLoaderCache, ImportsReader importsReader) {
- this.emptyScriptGenerator = emptyScriptGenerator;
+ public DefaultScriptCompilationHandler(ClassLoaderCache classLoaderCache, ImportsReader importsReader) {
this.classLoaderCache = classLoaderCache;
defaultImportPackages = importsReader.getImportPackages();
}
@Override
- public void compileToDir(ScriptSource source, ClassLoader classLoader, File classesDir, File metadataDir, CompileOperation<?> extractingTransformer, String classpathClosureName,
+ public void compileToDir(ScriptSource source, ClassLoader classLoader, File classesDir, File metadataDir, CompileOperation<?> extractingTransformer,
Class<? extends Script> scriptBaseClass, Action<? super ClassNode> verifier) {
Clock clock = new Clock();
GFileUtils.deleteDirectory(classesDir);
@@ -79,9 +79,10 @@ public class DefaultScriptCompilationHandler implements ScriptCompilationHandler
CompilerConfiguration configuration = createBaseCompilerConfiguration(scriptBaseClass);
configuration.setTargetDirectory(classesDir);
try {
- compileScript(source, classLoader, configuration, classesDir, metadataDir, extractingTransformer, verifier, classpathClosureName);
+ compileScript(source, classLoader, configuration, classesDir, metadataDir, extractingTransformer, verifier);
} catch (GradleException e) {
GFileUtils.deleteDirectory(classesDir);
+ GFileUtils.deleteDirectory(metadataDir);
throw e;
}
@@ -90,7 +91,7 @@ public class DefaultScriptCompilationHandler implements ScriptCompilationHandler
}
private void compileScript(final ScriptSource source, ClassLoader classLoader, CompilerConfiguration configuration, File classesDir, File metadataDir,
- final CompileOperation<?> extractingTransformer, final Action<? super ClassNode> customVerifier, String classpathClosureName) {
+ final CompileOperation<?> extractingTransformer, final Action<? super ClassNode> customVerifier) {
final Transformer transformer = extractingTransformer != null ? extractingTransformer.getTransformer() : null;
logger.info("Compiling {} using {}.", source.getDisplayName(), transformer != null ? transformer.getClass().getSimpleName() : "no transformer");
@@ -114,7 +115,6 @@ public class DefaultScriptCompilationHandler implements ScriptCompilationHandler
compilationUnit.addPhaseOperation(emptyScriptDetector, Phases.CANONICALIZATION);
return compilationUnit;
}
-
};
groovyClassLoader.setResourceLoader(NO_OP_GROOVY_RESOURCE_LOADER);
@@ -133,35 +133,27 @@ public class DefaultScriptCompilationHandler implements ScriptCompilationHandler
throw new UnsupportedOperationException(String.format("%s should not contain a package statement.",
StringUtils.capitalize(source.getDisplayName())));
}
- if (emptyScriptDetector.isEmptyScript()) {
- GFileUtils.touch(new File(classesDir, EMPTY_SCRIPT_MARKER_FILE_NAME));
- }
- serializeMetadata(source, extractingTransformer, metadataDir);
+ serializeMetadata(source, extractingTransformer, metadataDir, emptyScriptDetector.isEmptyScript(), emptyScriptDetector.getHasMethods());
}
- private <M> void serializeMetadata(ScriptSource scriptSource, CompileOperation<M> extractingTransformer, File metadataDir) {
- if (extractingTransformer == null || extractingTransformer.getDataSerializer() == null) {
- return;
- }
- GFileUtils.mkdirs(metadataDir);
+ private <M> void serializeMetadata(ScriptSource scriptSource, CompileOperation<M> extractingTransformer, File metadataDir, boolean emptyScript, boolean hasMethods) {
File metadataFile = new File(metadataDir, METADATA_FILE_NAME);
- FileOutputStream outputStream;
- try {
- outputStream = new FileOutputStream(metadataFile);
- } catch (FileNotFoundException e) {
- throw new UncheckedIOException("Could not create or open build script metadata file " + metadataFile.getAbsolutePath(), e);
- }
- KryoBackedEncoder encoder = new KryoBackedEncoder(outputStream);
- Serializer<M> serializer = extractingTransformer.getDataSerializer();
try {
- serializer.write(encoder, extractingTransformer.getExtractedData());
+ GFileUtils.mkdirs(metadataDir);
+ KryoBackedEncoder encoder = new KryoBackedEncoder(new FileOutputStream(metadataFile));
+ try {
+ byte flags = (byte) ((emptyScript ? EMPTY_FLAG : 0) | (hasMethods ? HAS_METHODS_FLAG : 0));
+ encoder.writeByte(flags);
+ if (extractingTransformer != null && extractingTransformer.getDataSerializer() != null) {
+ Serializer<M> serializer = extractingTransformer.getDataSerializer();
+ serializer.write(encoder, extractingTransformer.getExtractedData());
+ }
+ } finally {
+ encoder.close();
+ }
} catch (Exception e) {
- String transformerName = extractingTransformer.getTransformer().getClass().getName();
- throw new IllegalStateException(String.format("Failed to serialize script metadata extracted using %s for %s", transformerName, scriptSource.getDisplayName()), e);
- } finally {
- encoder.close();
+ throw new GradleException(String.format("Failed to serialize script metadata extracted for %s", scriptSource.getDisplayName()), e);
}
-
}
private void wrapCompilationFailure(ScriptSource source, MultipleCompilationErrorsException e) {
@@ -194,63 +186,31 @@ public class DefaultScriptCompilationHandler implements ScriptCompilationHandler
return configuration;
}
- public <T extends Script, M> CompiledScript<T, M> loadFromDir(final ScriptSource source, final ClassLoader classLoader, final File scriptCacheDir,
- File metadataCacheDir, final CompileOperation<M> transformer, final Class<T> scriptBaseClass, final ClassLoaderId classLoaderId) {
-
- final M metadata = deserializeMetadata(source, transformer, metadataCacheDir);
-
- return new ClassCachingCompiledScript<T, M>(new CompiledScript<T, M>() {
-
- @Override
- public Class<? extends T> loadClass() {
- if (new File(scriptCacheDir, EMPTY_SCRIPT_MARKER_FILE_NAME).isFile()) {
- classLoaderCache.remove(classLoaderId);
- return emptyScriptGenerator.generate(scriptBaseClass);
- }
-
- try {
- ClassLoader loader = classLoaderCache.get(classLoaderId, new DefaultClassPath(scriptCacheDir), classLoader, null);
- return loader.loadClass(source.getClassName()).asSubclass(scriptBaseClass);
- } catch (Exception e) {
- File expectedClassFile = new File(scriptCacheDir, source.getClassName() + ".class");
- if (!expectedClassFile.exists()) {
- throw new GradleException(String.format("Could not load compiled classes for %s from cache. Expected class file %s does not exist.", source.getDisplayName(), expectedClassFile.getAbsolutePath()), e);
- }
- throw new GradleException(String.format("Could not load compiled classes for %s from cache.", source.getDisplayName()), e);
- }
- }
-
- @Override
- public M getData() {
- return metadata;
- }
- });
- }
-
- private <M> M deserializeMetadata(ScriptSource scriptSource, CompileOperation<M> extractingTransformer, File metadataCacheDir) {
- if (extractingTransformer == null || extractingTransformer.getDataSerializer() == null) {
- return null;
- }
+ public <T extends Script, M> CompiledScript<T, M> loadFromDir(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
+ File metadataCacheDir, CompileOperation<M> transformer, Class<T> scriptBaseClass,
+ ClassLoaderId classLoaderId) {
File metadataFile = new File(metadataCacheDir, METADATA_FILE_NAME);
- FileInputStream inputStream;
- try {
- inputStream = new FileInputStream(metadataFile);
- } catch (FileNotFoundException e) {
- throw new UncheckedIOException("Could not open build script metadata file " + metadataFile.getAbsolutePath(), e);
- }
- KryoBackedDecoder decoder = new KryoBackedDecoder(inputStream);
- Serializer<M> serializer = extractingTransformer.getDataSerializer();
try {
- return serializer.read(decoder);
- } catch (Exception e) {
- String transformerName = extractingTransformer.getTransformer().getClass().getName();
- throw new IllegalStateException(String.format("Failed to deserialize script metadata extracted using %s for %s", transformerName, scriptSource.getDisplayName()), e);
- } finally {
+ KryoBackedDecoder decoder = new KryoBackedDecoder(new FileInputStream(metadataFile));
try {
+ byte flags = decoder.readByte();
+ boolean isEmpty = (flags & EMPTY_FLAG) != 0;
+ boolean hasMethods = (flags & HAS_METHODS_FLAG) != 0;
+ if (isEmpty) {
+ classLoaderCache.remove(classLoaderId);
+ }
+ M data;
+ if (transformer != null && transformer.getDataSerializer() != null) {
+ data = transformer.getDataSerializer().read(decoder);
+ } else {
+ data = null;
+ }
+ return new ClassesDirCompiledScript<T, M>(isEmpty, hasMethods, classLoaderId, scriptBaseClass, scriptCacheDir, classLoader, source, data);
+ } finally {
decoder.close();
- } catch (IOException e) {
- throw new UncheckedIOException("Failed to close script metadata file decoder backed by " + metadataFile.getAbsolutePath(), e);
}
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Failed to deserialize script metadata extracted for %s", source.getDisplayName()), e);
}
}
@@ -265,25 +225,30 @@ public class DefaultScriptCompilationHandler implements ScriptCompilationHandler
private static class EmptyScriptDetector extends CompilationUnit.SourceUnitOperation {
private boolean emptyScript;
+ private boolean hasMethods;
@Override
- public void call(SourceUnit source) throws CompilationFailedException {
+ public void call(SourceUnit source) {
+ if (!source.getAST().getMethods().isEmpty()) {
+ hasMethods = true;
+ }
emptyScript = isEmpty(source);
}
private boolean isEmpty(SourceUnit source) {
- if (!source.getAST().getMethods().isEmpty()) {
- return false;
- }
List<Statement> statements = source.getAST().getStatementBlock().getStatements();
- if (statements.size() > 1) {
- return false;
- }
- if (statements.isEmpty()) {
- return true;
+ for (Statement statement : statements) {
+ if (AstUtils.mayHaveAnEffect(statement)) {
+ return false;
+ }
}
- return AstUtils.isReturnNullStatement(statements.get(0));
+ // No statements, or no statements that have an effect
+ return true;
+ }
+
+ public boolean getHasMethods() {
+ return hasMethods;
}
public boolean isEmptyScript() {
@@ -331,4 +296,62 @@ public class DefaultScriptCompilationHandler implements ScriptCompilationHandler
};
}
}
+
+ private class ClassesDirCompiledScript<T extends Script, M> implements CompiledScript<T, M> {
+ private final boolean isEmpty;
+ private final boolean hasMethods;
+ private final ClassLoaderId classLoaderId;
+ private final Class<T> scriptBaseClass;
+ private final File scriptCacheDir;
+ private final ClassLoader classLoader;
+ private final ScriptSource source;
+ private final M metadata;
+ private Class<? extends T> scriptClass;
+
+ public ClassesDirCompiledScript(boolean isEmpty, boolean hasMethods, ClassLoaderId classLoaderId, Class<T> scriptBaseClass, File scriptCacheDir, ClassLoader classLoader, ScriptSource source, M metadata) {
+ this.isEmpty = isEmpty;
+ this.hasMethods = hasMethods;
+ this.classLoaderId = classLoaderId;
+ this.scriptBaseClass = scriptBaseClass;
+ this.scriptCacheDir = scriptCacheDir;
+ this.classLoader = classLoader;
+ this.source = source;
+ this.metadata = metadata;
+ }
+
+ @Override
+ public boolean getRunDoesSomething() {
+ return !isEmpty;
+ }
+
+ @Override
+ public boolean getHasMethods() {
+ return hasMethods;
+ }
+
+ @Override
+ public M getData() {
+ return metadata;
+ }
+
+ @Override
+ public Class<? extends T> loadClass() {
+ if (scriptClass == null) {
+ if (isEmpty && !hasMethods) {
+ throw new UnsupportedOperationException("Cannot load script that does nothing.");
+ }
+ try {
+ ClassLoader loader = classLoaderCache.get(classLoaderId, new DefaultClassPath(scriptCacheDir), classLoader, null);
+ scriptClass = loader.loadClass(source.getClassName()).asSubclass(scriptBaseClass);
+ } catch (Exception e) {
+ File expectedClassFile = new File(scriptCacheDir, source.getClassName() + ".class");
+ if (!expectedClassFile.exists()) {
+ throw new GradleException(String.format("Could not load compiled classes for %s from cache. Expected class file %s does not exist.", source.getDisplayName(), expectedClassFile.getAbsolutePath()), e);
+ }
+ throw new GradleException(String.format("Could not load compiled classes for %s from cache.", source.getDisplayName()), e);
+ }
+ }
+ return scriptClass;
+ }
+ }
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactory.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactory.java
index 2f98d3e..c7cbdb0 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactory.java
@@ -21,6 +21,7 @@ import org.gradle.groovy.scripts.ScriptExecutionListener;
import org.gradle.groovy.scripts.ScriptRunner;
import org.gradle.groovy.scripts.ScriptSource;
import org.gradle.internal.reflect.Instantiator;
+import org.gradle.internal.service.ServiceRegistry;
public class DefaultScriptRunnerFactory implements ScriptRunnerFactory {
private final ScriptExecutionListener listener;
@@ -44,29 +45,45 @@ public class DefaultScriptRunnerFactory implements ScriptRunnerFactory {
public ScriptRunnerImpl(CompiledScript<T, M> compiledScript, ScriptSource source, ClassLoader contextClassLoader) {
this.compiledScript = compiledScript;
this.source = source;
- this.contextClassLoader= contextClassLoader;
+ this.contextClassLoader = contextClassLoader;
}
@Override
public T getScript() {
if (script == null) {
- script = instantiator.newInstance(compiledScript.loadClass());
+ Class<? extends T> scriptClass = compiledScript.loadClass();
+ script = instantiator.newInstance(scriptClass);
script.setScriptSource(source);
script.setContextClassloader(contextClassLoader);
+ listener.scriptClassLoaded(source, scriptClass);
}
return script;
}
@Override
- public CompiledScript<T, M> getCompiledScript() {
- return compiledScript;
+ public M getData() {
+ return compiledScript.getData();
}
@Override
- public void run() throws GradleScriptException {
+ public boolean getRunDoesSomething() {
+ return compiledScript.getRunDoesSomething();
+ }
+
+ @Override
+ public boolean getHasMethods() {
+ return compiledScript.getHasMethods();
+ }
+
+ @Override
+ public void run(Object target, ServiceRegistry scriptServices) throws GradleScriptException {
+ if (!compiledScript.getRunDoesSomething()) {
+ return;
+ }
+
ClassLoader originalLoader = Thread.currentThread().getContextClassLoader();
T script = getScript();
- listener.beforeScript(script);
+ script.init(target, scriptServices);
GradleScriptException failure = null;
Thread.currentThread().setContextClassLoader(script.getContextClassloader());
script.getStandardOutputCapture().start();
@@ -77,7 +94,6 @@ public class DefaultScriptRunnerFactory implements ScriptRunnerFactory {
}
script.getStandardOutputCapture().stop();
Thread.currentThread().setContextClassLoader(originalLoader);
- listener.afterScript(script, failure);
if (failure != null) {
throw failure;
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompiler.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompiler.java
index 2443bbd..f43c2bf 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompiler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompiler.java
@@ -52,19 +52,19 @@ public class FileCacheBackedScriptClassCompiler implements ScriptClassCompiler,
}
@Override
- public <T extends Script, M> CompiledScript<T, M> compile(final ScriptSource source, final ClassLoader classLoader, final ClassLoaderId classLoaderId, CompileOperation<M> operation, String classpathClosureName, final Class<T> scriptBaseClass,
+ public <T extends Script, M> CompiledScript<T, M> compile(final ScriptSource source, final ClassLoader classLoader, final ClassLoaderId classLoaderId, CompileOperation<M> operation, final Class<T> scriptBaseClass,
Action<? super ClassNode> verifier) {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("source.filename", source.getFileName());
properties.put("source.hash", HashUtil.createCompactMD5(source.getResource().getText()));
- String transformerId = operation.getId();
- String cacheName = String.format("scripts/%s/%s/%s", source.getClassName(), scriptBaseClass.getSimpleName(), transformerId);
+ String dslId = operation.getId();
+ String cacheName = String.format("scripts/%s/%s", source.getClassName(), dslId);
PersistentCache cache = cacheRepository.cache(cacheName)
.withProperties(properties)
.withValidator(validator)
- .withDisplayName(String.format("%s class cache for %s", transformerId, source.getDisplayName()))
- .withInitializer(new ProgressReportingInitializer(progressLoggerFactory, new CacheInitializer(source, classLoader, operation, classpathClosureName, verifier, scriptBaseClass)))
+ .withDisplayName(String.format("%s class cache for %s", dslId, source.getDisplayName()))
+ .withInitializer(new ProgressReportingInitializer(progressLoggerFactory, new CacheInitializer(source, classLoader, operation, verifier, scriptBaseClass)))
.open();
// This isn't quite right. The cache will be closed at the end of the build, releasing the shared lock on the classes. Instead, the cache for a script should be
@@ -94,15 +94,13 @@ public class FileCacheBackedScriptClassCompiler implements ScriptClassCompiler,
private final Class<? extends Script> scriptBaseClass;
private final ClassLoader classLoader;
private final CompileOperation<?> transformer;
- private final String classpathClosureName;
private final ScriptSource source;
- public <T extends Script> CacheInitializer(ScriptSource source, ClassLoader classLoader, CompileOperation<?> transformer, String classpathClosureName,
+ public <T extends Script> CacheInitializer(ScriptSource source, ClassLoader classLoader, CompileOperation<?> transformer,
Action<? super ClassNode> verifier, Class<T> scriptBaseClass) {
this.source = source;
this.classLoader = classLoader;
this.transformer = transformer;
- this.classpathClosureName = classpathClosureName;
this.verifier = verifier;
this.scriptBaseClass = scriptBaseClass;
}
@@ -110,7 +108,7 @@ public class FileCacheBackedScriptClassCompiler implements ScriptClassCompiler,
public void execute(PersistentCache cache) {
File classesDir = classesDir(cache);
File metadataDir = metadataDir(cache);
- scriptCompilationHandler.compileToDir(source, classLoader, classesDir, metadataDir, transformer, classpathClosureName, scriptBaseClass, verifier);
+ scriptCompilationHandler.compileToDir(source, classLoader, classesDir, metadataDir, transformer, scriptBaseClass, verifier);
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ImperativeStatementDetectingTransformer.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ImperativeStatementDetectingTransformer.java
index 273cd6c..a24c49a 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ImperativeStatementDetectingTransformer.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ImperativeStatementDetectingTransformer.java
@@ -16,21 +16,17 @@
package org.gradle.groovy.scripts.internal;
-import org.codehaus.groovy.ast.GroovyCodeVisitor;
-import org.codehaus.groovy.ast.expr.*;
-import org.codehaus.groovy.ast.stmt.*;
-import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.Phases;
import org.codehaus.groovy.control.SourceUnit;
-import org.gradle.internal.Factory;
import org.gradle.model.dsl.internal.transform.ModelBlockTransformer;
import java.util.List;
-public class ImperativeStatementDetectingTransformer extends AbstractScriptTransformer implements Factory<Boolean>, GroovyCodeVisitor {
-
+public class ImperativeStatementDetectingTransformer extends AbstractScriptTransformer {
private boolean imperativeStatementDetected;
@Override
@@ -43,292 +39,24 @@ public class ImperativeStatementDetectingTransformer extends AbstractScriptTrans
return Phases.CANONICALIZATION;
}
- @Override
- public Boolean create() {
+ public boolean isImperativeStatementDetected() {
return imperativeStatementDetected;
}
@Override
public void call(SourceUnit source) throws CompilationFailedException {
- if (!source.getAST().getMethods().isEmpty()) {
- imperativeStatementDetected = true;
- return;
- }
-
BlockStatement statementBlock = source.getAST().getStatementBlock();
List<Statement> statements = statementBlock.getStatements();
- if (statements.size() == 1 && AstUtils.isReturnNullStatement(statements.get(0))) {
- return;
- }
-
- for (int i = 0; i < statements.size() && !imperativeStatementDetected; i++) {
- statements.get(i).visit(this);
- }
- }
-
-
- @Override
- public void visitBlockStatement(BlockStatement block) {
- for (Statement statement : block.getStatements()) {
- statement.visit(this);
- }
- }
-
- @Override
- public void visitForLoop(ForStatement forLoop) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitWhileLoop(WhileStatement loop) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitDoWhileLoop(DoWhileStatement loop) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitIfElse(IfStatement ifElse) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitExpressionStatement(ExpressionStatement statement) {
- statement.getExpression().visit(this);
- }
-
- @Override
- public void visitReturnStatement(ReturnStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitAssertStatement(AssertStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitTryCatchFinally(TryCatchStatement finally1) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitSwitch(SwitchStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitCaseStatement(CaseStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitBreakStatement(BreakStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitContinueStatement(ContinueStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitThrowStatement(ThrowStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitSynchronizedStatement(SynchronizedStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitCatchStatement(CatchStatement statement) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitMethodCallExpression(MethodCallExpression call) {
- String methodName = AstUtils.extractConstantMethodName(call);
- if (methodName == null) {
+ for (Statement statement : statements) {
+ if (!AstUtils.mayHaveAnEffect(statement)) {
+ continue;
+ }
+ ScriptBlock scriptBlock = AstUtils.detectScriptBlock(statement);
+ if (scriptBlock != null && scriptBlock.getName().equals(ModelBlockTransformer.MODEL)) {
+ continue;
+ }
imperativeStatementDetected = true;
- return;
+ break;
}
-
- ClosureExpression closureExpression = AstUtils.getSingleClosureArg(call);
- if (closureExpression == null || !methodName.equals(ModelBlockTransformer.MODEL)) {
- imperativeStatementDetected = true;
- }
- }
-
- @Override
- public void visitStaticMethodCallExpression(StaticMethodCallExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitConstructorCallExpression(ConstructorCallExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitTernaryExpression(TernaryExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitShortTernaryExpression(ElvisOperatorExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitBinaryExpression(BinaryExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitPrefixExpression(PrefixExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitPostfixExpression(PostfixExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitBooleanExpression(BooleanExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitClosureExpression(ClosureExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitTupleExpression(TupleExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitMapExpression(MapExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitMapEntryExpression(MapEntryExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitListExpression(ListExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitRangeExpression(RangeExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitPropertyExpression(PropertyExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitAttributeExpression(AttributeExpression attributeExpression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitFieldExpression(FieldExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitMethodPointerExpression(MethodPointerExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitConstantExpression(ConstantExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitClassExpression(ClassExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitVariableExpression(VariableExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitDeclarationExpression(DeclarationExpression expression) {
- }
-
- @Override
- public void visitGStringExpression(GStringExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitArrayExpression(ArrayExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitSpreadExpression(SpreadExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitSpreadMapExpression(SpreadMapExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitNotExpression(NotExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitUnaryMinusExpression(UnaryMinusExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitUnaryPlusExpression(UnaryPlusExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitCastExpression(CastExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitArgumentlistExpression(ArgumentListExpression expression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitClosureListExpression(ClosureListExpression closureListExpression) {
- imperativeStatementDetected = true;
- }
-
- @Override
- public void visitBytecodeExpression(BytecodeExpression expression) {
- imperativeStatementDetected = true;
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptClassCompiler.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptClassCompiler.java
index 8c2db37..2b28f88 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptClassCompiler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptClassCompiler.java
@@ -22,6 +22,6 @@ import org.gradle.api.internal.initialization.loadercache.ClassLoaderId;
import org.gradle.groovy.scripts.ScriptSource;
public interface ScriptClassCompiler {
- <T extends Script, M> CompiledScript<T, M> compile(ScriptSource source, ClassLoader classLoader, ClassLoaderId classLoaderId, CompileOperation<M> transformer, String classpathClosureName, Class<T> scriptBaseClass,
+ <T extends Script, M> CompiledScript<T, M> compile(ScriptSource source, ClassLoader classLoader, ClassLoaderId classLoaderId, CompileOperation<M> transformer, Class<T> scriptBaseClass,
Action<? super ClassNode> verifier);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptCompilationHandler.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptCompilationHandler.java
index 02305c9..5ecbb48 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptCompilationHandler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ScriptCompilationHandler.java
@@ -25,9 +25,9 @@ import java.io.File;
public interface ScriptCompilationHandler {
- void compileToDir(ScriptSource source, ClassLoader classLoader, File classesDir, File metadataDir, CompileOperation<?> transformer, String classpathClosureName,
+ void compileToDir(ScriptSource source, ClassLoader classLoader, File classesDir, File metadataDir, CompileOperation<?> transformer,
Class<? extends Script> scriptBaseClass, Action<? super ClassNode> verifier);
<T extends Script, M> CompiledScript<T, M> loadFromDir(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
- File metadataCacheDir, CompileOperation<M> transformer, Class<T> scriptBaseClass, final ClassLoaderId classLoaderId);
+ File metadataCacheDir, CompileOperation<M> transformer, Class<T> scriptBaseClass, ClassLoaderId classLoaderId);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompiler.java b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompiler.java
index b04d4ef..a6d3954 100644
--- a/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompiler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompiler.java
@@ -24,33 +24,40 @@ import org.gradle.groovy.scripts.ScriptSource;
public class ShortCircuitEmptyScriptCompiler implements ScriptClassCompiler {
private final ScriptClassCompiler compiler;
- private final EmptyScriptGenerator emptyScriptGenerator;
private final ClassLoaderCache classLoaderCache;
- public ShortCircuitEmptyScriptCompiler(ScriptClassCompiler compiler, EmptyScriptGenerator emptyScriptGenerator, ClassLoaderCache classLoaderCache) {
+ public ShortCircuitEmptyScriptCompiler(ScriptClassCompiler compiler, ClassLoaderCache classLoaderCache) {
this.compiler = compiler;
- this.emptyScriptGenerator = emptyScriptGenerator;
this.classLoaderCache = classLoaderCache;
}
@Override
- public <T extends Script, M> CompiledScript<T, M> compile(final ScriptSource source, final ClassLoader classLoader, final ClassLoaderId classLoaderId, final CompileOperation<M> operation, String classpathClosureName,
+ public <T extends Script, M> CompiledScript<T, M> compile(final ScriptSource source, final ClassLoader classLoader, final ClassLoaderId classLoaderId, final CompileOperation<M> operation,
final Class<T> scriptBaseClass, Action<? super ClassNode> verifier) {
if (source.getResource().getText().matches("\\s*")) {
- return new ClassCachingCompiledScript<T, M>(new CompiledScript<T, M>() {
+ classLoaderCache.remove(classLoaderId);
+ return new CompiledScript<T, M>() {
+ @Override
+ public boolean getRunDoesSomething() {
+ return false;
+ }
+
+ @Override
+ public boolean getHasMethods() {
+ return false;
+ }
public Class<? extends T> loadClass() {
- classLoaderCache.remove(classLoaderId);
- return emptyScriptGenerator.generate(scriptBaseClass);
+ throw new UnsupportedOperationException("Cannot load a script that does nothing.");
}
@Override
public M getData() {
return operation.getExtractedData();
}
- });
+ };
}
- return compiler.compile(source, classLoader, classLoaderId, operation, classpathClosureName, scriptBaseClass, verifier);
+ return compiler.compile(source, classLoader, classLoaderId, operation, scriptBaseClass, verifier);
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultExceptionAnalyser.java b/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultExceptionAnalyser.java
index 498e508..19f6118 100755
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultExceptionAnalyser.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultExceptionAnalyser.java
@@ -16,15 +16,15 @@
package org.gradle.initialization;
import org.gradle.api.GradleScriptException;
-import org.gradle.internal.exceptions.Contextual;
import org.gradle.api.internal.ExceptionAnalyser;
-import org.gradle.internal.exceptions.LocationAwareException;
import org.gradle.api.tasks.TaskExecutionException;
import org.gradle.groovy.scripts.Script;
import org.gradle.groovy.scripts.ScriptCompilationException;
import org.gradle.groovy.scripts.ScriptExecutionListener;
import org.gradle.groovy.scripts.ScriptSource;
import org.gradle.internal.event.ListenerManager;
+import org.gradle.internal.exceptions.Contextual;
+import org.gradle.internal.exceptions.LocationAwareException;
import java.util.HashMap;
import java.util.Map;
@@ -36,14 +36,11 @@ public class DefaultExceptionAnalyser implements ExceptionAnalyser, ScriptExecut
listenerManager.addListener(this);
}
- public void beforeScript(Script script) {
- ScriptSource source = script.getScriptSource();
+ @Override
+ public void scriptClassLoaded(ScriptSource source, Class<? extends Script> scriptClass) {
scripts.put(source.getFileName(), source);
}
- public void afterScript(Script script, Throwable result) {
- }
-
public Throwable transform(Throwable exception) {
Throwable actualException = findDeepestRootException(exception);
if (actualException instanceof LocationAwareException) {
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncher.java b/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncher.java
index 251d324..b5bfde7 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncher.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncher.java
@@ -19,59 +19,56 @@ import org.gradle.BuildListener;
import org.gradle.BuildResult;
import org.gradle.api.internal.ExceptionAnalyser;
import org.gradle.api.internal.GradleInternal;
-import org.gradle.api.internal.SettingsInternal;
import org.gradle.api.logging.StandardOutputListener;
import org.gradle.configuration.BuildConfigurer;
+import org.gradle.execution.BuildConfigurationActionExecuter;
import org.gradle.execution.BuildExecuter;
import org.gradle.internal.Factory;
import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.progress.BuildOperationExecutor;
-import org.gradle.internal.progress.BuildOperationType;
-import org.gradle.internal.progress.OperationIdGenerator;
import org.gradle.logging.LoggingManagerInternal;
import java.io.Closeable;
public class DefaultGradleLauncher extends GradleLauncher {
+
private enum Stage {
Configure, Build
}
private final GradleInternal gradle;
private final InitScriptHandler initScriptHandler;
- private final SettingsHandler settingsHandler;
- private final BuildLoader buildLoader;
+ private final SettingsLoader settingsLoader;
private final BuildConfigurer buildConfigurer;
private final ExceptionAnalyser exceptionAnalyser;
private final LoggingManagerInternal loggingManager;
private final BuildListener buildListener;
private final ModelConfigurationListener modelConfigurationListener;
- private final TasksCompletionListener tasksCompletionListener;
private final BuildCompletionListener buildCompletionListener;
private final BuildOperationExecutor buildOperationExecutor;
+ private final BuildConfigurationActionExecuter buildConfigurationActionExecuter;
private final BuildExecuter buildExecuter;
private final Closeable buildServices;
/**
* Creates a new instance.
*/
- public DefaultGradleLauncher(GradleInternal gradle, InitScriptHandler initScriptHandler, SettingsHandler settingsHandler,
- BuildLoader buildLoader, BuildConfigurer buildConfigurer, ExceptionAnalyser exceptionAnalyser,
+ public DefaultGradleLauncher(GradleInternal gradle, InitScriptHandler initScriptHandler, SettingsLoader settingsLoader,
+ BuildConfigurer buildConfigurer, ExceptionAnalyser exceptionAnalyser,
LoggingManagerInternal loggingManager, BuildListener buildListener,
- ModelConfigurationListener modelConfigurationListener, TasksCompletionListener tasksCompletionListener,
+ ModelConfigurationListener modelConfigurationListener,
BuildCompletionListener buildCompletionListener, BuildOperationExecutor operationExecutor,
- BuildExecuter buildExecuter, Closeable buildServices) {
+ BuildConfigurationActionExecuter buildConfigurationActionExecuter, BuildExecuter buildExecuter, Closeable buildServices) {
this.gradle = gradle;
this.initScriptHandler = initScriptHandler;
- this.settingsHandler = settingsHandler;
- this.buildLoader = buildLoader;
+ this.settingsLoader = settingsLoader;
this.buildConfigurer = buildConfigurer;
this.exceptionAnalyser = exceptionAnalyser;
this.buildListener = buildListener;
this.loggingManager = loggingManager;
this.modelConfigurationListener = modelConfigurationListener;
- this.tasksCompletionListener = tasksCompletionListener;
this.buildOperationExecutor = operationExecutor;
+ this.buildConfigurationActionExecuter = buildConfigurationActionExecuter;
this.buildExecuter = buildExecuter;
this.buildCompletionListener = buildCompletionListener;
this.buildServices = buildServices;
@@ -94,13 +91,12 @@ public class DefaultGradleLauncher extends GradleLauncher {
private BuildResult doBuild(final Stage upTo) {
loggingManager.start();
- return runRootBuildOperation(BuildOperationType.RUNNING_BUILD, new Factory<BuildResult>() {
+ return buildOperationExecutor.run("Run build", new Factory<BuildResult>() {
@Override
public BuildResult create() {
- buildListener.buildStarted(gradle);
-
Throwable failure = null;
try {
+ buildListener.buildStarted(gradle);
doBuildStages(upTo);
} catch (Throwable t) {
failure = exceptionAnalyser.transform(t);
@@ -118,26 +114,13 @@ public class DefaultGradleLauncher extends GradleLauncher {
private void doBuildStages(Stage upTo) {
// Evaluate init scripts
- runBuildOperation(BuildOperationType.EVALUATING_INIT_SCRIPTS, new Runnable() {
- @Override
- public void run() {
- initScriptHandler.executeScripts(gradle);
- }
- });
+ initScriptHandler.executeScripts(gradle);
- // Evaluate settings script
- runBuildOperation(BuildOperationType.EVALUATING_SETTINGS, new Runnable() {
- @Override
- public void run() {
- SettingsInternal settings = settingsHandler.findAndLoadSettings(gradle);
- buildListener.settingsEvaluated(settings);
- buildLoader.load(settings.getRootProject(), settings.getDefaultProject(), gradle, settings.getRootClassLoaderScope());
- buildListener.projectsLoaded(gradle);
- }
- });
+ // Calculate projects
+ settingsLoader.findAndLoadSettings(gradle);
// Configure build
- runBuildOperation(BuildOperationType.CONFIGURING_BUILD, new Runnable() {
+ buildOperationExecutor.run("Configure build", new Runnable() {
@Override
public void run() {
buildConfigurer.configure(gradle);
@@ -150,17 +133,15 @@ public class DefaultGradleLauncher extends GradleLauncher {
}
});
-
if (upTo == Stage.Configure) {
return;
}
// Populate task graph
- runBuildOperation(BuildOperationType.POPULATING_TASK_GRAPH, new Runnable() {
+ buildOperationExecutor.run("Calculate task graph", new Runnable() {
@Override
public void run() {
- buildExecuter.select(gradle);
-
+ buildConfigurationActionExecuter.select(gradle);
if (gradle.getStartParameter().isConfigureOnDemand()) {
buildListener.projectsEvaluated(gradle);
}
@@ -168,27 +149,16 @@ public class DefaultGradleLauncher extends GradleLauncher {
});
// Execute build
- runBuildOperation(BuildOperationType.EXECUTING_TASKS, new Runnable() {
+ buildOperationExecutor.run("Run tasks", new Runnable() {
@Override
public void run() {
- buildExecuter.execute();
- tasksCompletionListener.onTasksFinished(gradle);
+ buildExecuter.execute(gradle);
}
});
assert upTo == Stage.Build;
}
- private <T> T runRootBuildOperation(BuildOperationType operationType, Factory<T> factory) {
- Object id = OperationIdGenerator.generateId(gradle);
- return buildOperationExecutor.run(id, operationType, factory);
- }
-
- private void runBuildOperation(BuildOperationType operationType, Runnable action) {
- Object id = OperationIdGenerator.generateId(operationType, gradle);
- buildOperationExecutor.run(id, operationType, action);
- }
-
/**
* <p>Adds a listener to this build instance. The listener is notified of events which occur during the
* execution of the build. See {@link org.gradle.api.invocation.Gradle#addListener(Object)} for supported listener
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java b/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java
index 8cca908..6601279 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java
@@ -23,14 +23,16 @@ import org.gradle.api.internal.ExceptionAnalyser;
import org.gradle.api.internal.GradleInternal;
import org.gradle.api.logging.Logging;
import org.gradle.api.logging.StandardOutputListener;
-import org.gradle.cache.CacheRepository;
import org.gradle.configuration.BuildConfigurer;
+import org.gradle.deployment.internal.DeploymentRegistry;
import org.gradle.execution.BuildExecuter;
-import org.gradle.initialization.buildsrc.BuildSourceBuilder;
-import org.gradle.initialization.layout.BuildLayoutFactory;
+import org.gradle.execution.BuildConfigurationActionExecuter;
import org.gradle.internal.event.ListenerManager;
import org.gradle.internal.featurelifecycle.ScriptUsageLocationReporter;
-import org.gradle.internal.progress.*;
+import org.gradle.internal.progress.BuildOperationExecutor;
+import org.gradle.internal.progress.BuildProgressFilter;
+import org.gradle.internal.progress.BuildProgressLogger;
+import org.gradle.internal.progress.LoggerProvider;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.service.scopes.BuildScopeServices;
@@ -48,8 +50,8 @@ public class DefaultGradleLauncherFactory implements GradleLauncherFactory {
private final NestedBuildTracker tracker;
private final BuildProgressLogger buildProgressLogger;
- public DefaultGradleLauncherFactory(ServiceRegistry globalServices) {
- sharedServices = globalServices;
+ public DefaultGradleLauncherFactory(ServiceRegistry sharedServices) {
+ this.sharedServices = sharedServices;
tracker = new NestedBuildTracker();
// Register default loggers
@@ -81,18 +83,21 @@ public class DefaultGradleLauncherFactory implements GradleLauncherFactory {
cancellationToken = new DefaultBuildCancellationToken();
buildEventConsumer = new NoOpBuildEventConsumer();
}
- return doNewInstance(startParameter, cancellationToken, requestMetaData, buildEventConsumer);
+ return doNewInstance(startParameter, cancellationToken, requestMetaData, buildEventConsumer, sharedServices);
}
@Override
- public GradleLauncher newInstance(StartParameter startParameter, BuildRequestContext requestContext) {
+ public GradleLauncher newInstance(StartParameter startParameter, BuildRequestContext requestContext, ServiceRegistry parentRegistry) {
// This should only be used for top-level builds
assert tracker.getCurrentBuild() == null;
- return doNewInstance(startParameter, requestContext.getCancellationToken(), requestContext, requestContext.getEventConsumer());
+ DefaultGradleLauncher launcher = doNewInstance(startParameter, requestContext.getCancellationToken(), requestContext, requestContext.getEventConsumer(), parentRegistry);
+ DeploymentRegistry deploymentRegistry = parentRegistry.get(DeploymentRegistry.class);
+ deploymentRegistry.onNewBuild(launcher.getGradle());
+ return launcher;
}
- private DefaultGradleLauncher doNewInstance(StartParameter startParameter, BuildCancellationToken cancellationToken, BuildRequestMetaData requestMetaData, BuildEventConsumer buildEventConsumer) {
- final BuildScopeServices serviceRegistry = new BuildScopeServices(sharedServices, startParameter);
+ private DefaultGradleLauncher doNewInstance(StartParameter startParameter, BuildCancellationToken cancellationToken, BuildRequestMetaData requestMetaData, BuildEventConsumer buildEventConsumer, ServiceRegistry parentRegistry) {
+ BuildScopeServices serviceRegistry = new BuildScopeServices(parentRegistry, startParameter);
serviceRegistry.add(BuildRequestMetaData.class, requestMetaData);
serviceRegistry.add(BuildClientMetaData.class, requestMetaData.getClient());
serviceRegistry.add(BuildEventConsumer.class, buildEventConsumer);
@@ -124,24 +129,15 @@ public class DefaultGradleLauncherFactory implements GradleLauncherFactory {
return new DefaultGradleLauncher(
gradle,
serviceRegistry.get(InitScriptHandler.class),
- new SettingsHandler(
- new DefaultSettingsFinder(
- new BuildLayoutFactory()),
- serviceRegistry.get(SettingsProcessor.class),
- new BuildSourceBuilder(
- this,
- serviceRegistry.get(ClassLoaderScopeRegistry.class).getCoreAndPluginsScope(),
- serviceRegistry.get(CacheRepository.class))
- ),
- serviceRegistry.get(BuildLoader.class),
+ serviceRegistry.get(SettingsLoader.class),
serviceRegistry.get(BuildConfigurer.class),
serviceRegistry.get(ExceptionAnalyser.class),
loggingManager,
gradle.getBuildListenerBroadcaster(),
listenerManager.getBroadcaster(ModelConfigurationListener.class),
- listenerManager.getBroadcaster(TasksCompletionListener.class),
listenerManager.getBroadcaster(BuildCompletionListener.class),
serviceRegistry.get(BuildOperationExecutor.class),
+ gradle.getServices().get(BuildConfigurationActionExecuter.class),
gradle.getServices().get(BuildExecuter.class),
serviceRegistry
);
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncher.java b/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncher.java
index 96d4e40..75e1d0c 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncher.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncher.java
@@ -20,8 +20,7 @@ import org.gradle.api.logging.StandardOutputListener;
import org.gradle.internal.concurrent.Stoppable;
/**
- * This was the old Gradle embedding API (it used to be in the public `org.gradle` package). It is now internal and is due to be merged into
- * {@link org.gradle.internal.invocation.BuildController}.
+ * This was the old Gradle embedding API (it used to be in the public `org.gradle` package). It is now internal and is due to be merged into {@link org.gradle.internal.invocation.BuildController}.
*/
public abstract class GradleLauncher implements Stoppable {
@@ -34,8 +33,7 @@ public abstract class GradleLauncher implements Stoppable {
public abstract BuildResult run() throws ReportedException;
/**
- * Evaluates the settings and all the projects. The information about available tasks and projects is accessible via
- * the {@link org.gradle.api.invocation.Gradle#getRootProject()} object.
+ * Evaluates the settings and all the projects. The information about available tasks and projects is accessible via the {@link org.gradle.api.invocation.Gradle#getRootProject()} object.
*
* @return The result. Never returns null.
* @throws ReportedException On build failure. The failure will have been logged.
@@ -43,16 +41,15 @@ public abstract class GradleLauncher implements Stoppable {
public abstract BuildResult getBuildAnalysis() throws ReportedException;
/**
- * <p>Adds a listener to this build instance. The listener is notified of events which occur during the execution of
- * the build. See {@link org.gradle.api.invocation.Gradle#addListener(Object)} for supported listener types.</p>
+ * <p>Adds a listener to this build instance. The listener is notified of events which occur during the execution of the build. See {@link org.gradle.api.invocation.Gradle#addListener(Object)} for
+ * supported listener types.</p>
*
* @param listener The listener to add. Has no effect if the listener has already been added.
*/
public abstract void addListener(Object listener);
/**
- * <p>Adds a {@link StandardOutputListener} to this build instance. The listener is notified of any text written to
- * standard output by Gradle's logging system
+ * <p>Adds a {@link StandardOutputListener} to this build instance. The listener is notified of any text written to standard output by Gradle's logging system
*
* @param listener The listener to add. Has no effect if the listener has already been added.
*/
@@ -64,4 +61,5 @@ public abstract class GradleLauncher implements Stoppable {
* @param listener The listener to add. Has no effect if the listener has already been added.
*/
public abstract void addStandardErrorListener(StandardOutputListener listener);
+
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncherFactory.java b/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncherFactory.java
index 619c36b..d2dd8f2 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncherFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/GradleLauncherFactory.java
@@ -16,6 +16,7 @@
package org.gradle.initialization;
import org.gradle.StartParameter;
+import org.gradle.internal.service.ServiceRegistry;
/**
* <p>A {@code GradleLauncherFactory} is responsible for creating a {@link GradleLauncher} instance for a build, from a {@link
@@ -28,8 +29,9 @@ public interface GradleLauncherFactory {
*
* @param startParameter The settings for the build.
* @param requestContext The context in which the build is running.
+ * @param parent The parent service registry for this build.
*/
- GradleLauncher newInstance(StartParameter startParameter, BuildRequestContext requestContext);
+ GradleLauncher newInstance(StartParameter startParameter, BuildRequestContext requestContext, ServiceRegistry parent);
/**
* Creates a new {@link GradleLauncher} instance for the given parameters.
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/InitScriptHandler.java b/subprojects/core/src/main/groovy/org/gradle/initialization/InitScriptHandler.java
index 4005225..10847fa 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/InitScriptHandler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/InitScriptHandler.java
@@ -18,23 +18,39 @@ package org.gradle.initialization;
import org.gradle.api.internal.GradleInternal;
import org.gradle.configuration.InitScriptProcessor;
import org.gradle.groovy.scripts.UriScriptSource;
+import org.gradle.internal.progress.BuildOperationDetails;
+import org.gradle.internal.progress.BuildOperationExecutor;
import java.io.File;
+import java.util.List;
/**
* Finds and executes all init scripts for a given build.
*/
public class InitScriptHandler {
private final InitScriptProcessor processor;
+ private final BuildOperationExecutor buildOperationExecutor;
- public InitScriptHandler(InitScriptProcessor processor) {
+ public InitScriptHandler(InitScriptProcessor processor, BuildOperationExecutor buildOperationExecutor) {
this.processor = processor;
+ this.buildOperationExecutor = buildOperationExecutor;
}
- public void executeScripts(GradleInternal gradle) {
- for (File script : gradle.getStartParameter().getAllInitScripts()) {
- processor.process(new UriScriptSource("initialization script", script), gradle);
+ public void executeScripts(final GradleInternal gradle) {
+ final List<File> initScripts = gradle.getStartParameter().getAllInitScripts();
+ if (initScripts.isEmpty()) {
+ return;
}
+
+ BuildOperationDetails operationDetails = BuildOperationDetails.displayName("Run init scripts").progressDisplayName("init scripts").build();
+ buildOperationExecutor.run(operationDetails, new Runnable() {
+ @Override
+ public void run() {
+ for (File script : initScripts) {
+ processor.process(new UriScriptSource("initialization script", script), gradle);
+ }
+ }
+ });
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/NotifyingSettingsLoader.java b/subprojects/core/src/main/groovy/org/gradle/initialization/NotifyingSettingsLoader.java
new file mode 100644
index 0000000..6a42780
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/NotifyingSettingsLoader.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.initialization;
+
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.api.internal.SettingsInternal;
+
+public class NotifyingSettingsLoader implements SettingsLoader {
+ private final SettingsHandler settingsHandler;
+ private final BuildLoader buildLoader;
+
+ public NotifyingSettingsLoader(SettingsHandler settingsHandler, BuildLoader buildLoader) {
+ this.settingsHandler = settingsHandler;
+ this.buildLoader = buildLoader;
+ }
+
+ @Override
+ public SettingsInternal findAndLoadSettings(GradleInternal gradle) {
+ SettingsInternal settings = settingsHandler.findAndLoadSettings(gradle);
+ gradle.getBuildListenerBroadcaster().settingsEvaluated(settings);
+ buildLoader.load(settings.getRootProject(), settings.getDefaultProject(), gradle, settings.getRootClassLoaderScope());
+ gradle.getBuildListenerBroadcaster().projectsLoaded(gradle);
+ return settings;
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/NotifyingSettingsProcessor.java b/subprojects/core/src/main/groovy/org/gradle/initialization/NotifyingSettingsProcessor.java
new file mode 100644
index 0000000..efd1382
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/NotifyingSettingsProcessor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.initialization;
+
+import org.gradle.StartParameter;
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.api.internal.SettingsInternal;
+import org.gradle.api.internal.initialization.ClassLoaderScope;
+import org.gradle.internal.Factory;
+import org.gradle.internal.progress.BuildOperationDetails;
+import org.gradle.internal.progress.BuildOperationExecutor;
+
+public class NotifyingSettingsProcessor implements SettingsProcessor {
+ private final SettingsProcessor settingsProcessor;
+ private final BuildOperationExecutor buildOperationExecutor;
+
+ public NotifyingSettingsProcessor(SettingsProcessor settingsProcessor, BuildOperationExecutor buildOperationExecutor) {
+ this.settingsProcessor = settingsProcessor;
+ this.buildOperationExecutor = buildOperationExecutor;
+ }
+
+ @Override
+ public SettingsInternal process(final GradleInternal gradle, final SettingsLocation settingsLocation, final ClassLoaderScope baseClassLoaderScope, final StartParameter startParameter) {
+ BuildOperationDetails operationDetails = BuildOperationDetails.displayName("Configure settings").progressDisplayName("settings").build();
+ return buildOperationExecutor.run(operationDetails, new Factory<SettingsInternal>() {
+ @Override
+ public SettingsInternal create() {
+ return settingsProcessor.process(gradle, settingsLocation, baseClassLoaderScope, startParameter);
+ }
+ });
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/ScriptEvaluatingSettingsProcessor.java b/subprojects/core/src/main/groovy/org/gradle/initialization/ScriptEvaluatingSettingsProcessor.java
index 1bc80df..e806bba 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/ScriptEvaluatingSettingsProcessor.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/ScriptEvaluatingSettingsProcessor.java
@@ -68,7 +68,7 @@ public class ScriptEvaluatingSettingsProcessor implements SettingsProcessor {
ScriptSource settingsScriptSource = settingsLocation.getSettingsScriptSource();
ClassLoaderScope settingsClassLoaderScope = settings.getClassLoaderScope();
ScriptHandler scriptHandler = scriptHandlerFactory.create(settingsScriptSource, settingsClassLoaderScope);
- ScriptPlugin configurer = configurerFactory.create(settingsScriptSource, scriptHandler, settingsClassLoaderScope, settings.getRootClassLoaderScope(), "buildscript", SettingsScript.class, false);
+ ScriptPlugin configurer = configurerFactory.create(settingsScriptSource, scriptHandler, settingsClassLoaderScope, settings.getRootClassLoaderScope(), true);
configurer.apply(settings);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsHandler.java b/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsHandler.java
index d38d400..31ac146 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsHandler.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsHandler.java
@@ -29,7 +29,7 @@ import java.io.File;
* Handles locating and processing setting.gradle files. Also deals with the buildSrc module, since that modules is
* found after settings is located, but needs to be built before settings is processed.
*/
-public class SettingsHandler {
+public class SettingsHandler implements SettingsLoader {
private ISettingsFinder settingsFinder;
private SettingsProcessor settingsProcessor;
private BuildSourceBuilder buildSourceBuilder;
@@ -41,6 +41,7 @@ public class SettingsHandler {
this.buildSourceBuilder = buildSourceBuilder;
}
+ @Override
public SettingsInternal findAndLoadSettings(GradleInternal gradle) {
StartParameter startParameter = gradle.getStartParameter();
SettingsInternal settings = findSettingsAndLoadIfAppropriate(gradle, startParameter);
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsLoader.java b/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsLoader.java
new file mode 100644
index 0000000..064e812
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsLoader.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.initialization;
+
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.api.internal.SettingsInternal;
+
+public interface SettingsLoader {
+ SettingsInternal findAndLoadSettings(GradleInternal gradle);
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsProcessor.java b/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsProcessor.java
index 57257a6..ea72cf6 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsProcessor.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/SettingsProcessor.java
@@ -21,7 +21,7 @@ import org.gradle.api.internal.SettingsInternal;
import org.gradle.api.internal.initialization.ClassLoaderScope;
/**
- * Responsible for locating, constructing, and evaluating the {@link SettingsInternal} for a build.
+ * Responsible for locating, constructing, and configuring the {@link SettingsInternal} for a build.
*/
public interface SettingsProcessor {
SettingsInternal process(GradleInternal gradle,
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/TasksCompletionListener.java b/subprojects/core/src/main/groovy/org/gradle/initialization/TasksCompletionListener.java
deleted file mode 100644
index cc0fdd1..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/TasksCompletionListener.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.initialization;
-
-import org.gradle.api.internal.GradleInternal;
-
-public interface TasksCompletionListener {
- /**
- * Notified when all task execution has completed successfully.
- */
- void onTasksFinished(GradleInternal gradle);
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilder.java b/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilder.java
index b694ca1..95b27ab 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilder.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilder.java
@@ -23,8 +23,11 @@ import org.gradle.cache.PersistentCache;
import org.gradle.cache.internal.FileLockManager;
import org.gradle.initialization.GradleLauncher;
import org.gradle.initialization.GradleLauncherFactory;
+import org.gradle.internal.Factory;
import org.gradle.internal.classpath.ClassPath;
import org.gradle.internal.classpath.DefaultClassPath;
+import org.gradle.internal.progress.BuildOperationDetails;
+import org.gradle.internal.progress.BuildOperationExecutor;
import org.gradle.util.GradleVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,11 +43,13 @@ public class BuildSourceBuilder {
private final GradleLauncherFactory gradleLauncherFactory;
private final ClassLoaderScope classLoaderScope;
private final CacheRepository cacheRepository;
+ private final BuildOperationExecutor buildOperationExecutor;
- public BuildSourceBuilder(GradleLauncherFactory gradleLauncherFactory, ClassLoaderScope classLoaderScope, CacheRepository cacheRepository) {
+ public BuildSourceBuilder(GradleLauncherFactory gradleLauncherFactory, ClassLoaderScope classLoaderScope, CacheRepository cacheRepository, BuildOperationExecutor buildOperationExecutor) {
this.gradleLauncherFactory = gradleLauncherFactory;
this.classLoaderScope = classLoaderScope;
this.cacheRepository = cacheRepository;
+ this.buildOperationExecutor = buildOperationExecutor;
}
public ClassLoaderScope buildAndCreateClassLoader(StartParameter startParameter) {
@@ -55,7 +60,7 @@ public class BuildSourceBuilder {
return childScope;
}
- ClassPath createBuildSourceClasspath(StartParameter startParameter) {
+ ClassPath createBuildSourceClasspath(final StartParameter startParameter) {
assert startParameter.getCurrentDir() != null && startParameter.getBuildFile() == null;
LOGGER.debug("Starting to build the build sources.");
@@ -63,8 +68,15 @@ public class BuildSourceBuilder {
LOGGER.debug("Gradle source dir does not exist. We leave.");
return new DefaultClassPath();
}
- LOGGER.info("================================================" + " Start building buildSrc");
+ return buildOperationExecutor.run(BuildOperationDetails.displayName("Build buildSrc").progressDisplayName("buildSrc").build(), new Factory<ClassPath>() {
+ @Override
+ public ClassPath create() {
+ return buildBuildSrc(startParameter);
+ }
+ });
+ }
+ private ClassPath buildBuildSrc(StartParameter startParameter) {
// If we were not the most recent version of Gradle to build the buildSrc dir, then do a clean build
// Otherwise, just to a regular build
final PersistentCache buildSrcCache = createCache(startParameter);
diff --git a/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSrcUpdateFactory.java b/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSrcUpdateFactory.java
index f49ba8c..939ab8d 100644
--- a/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSrcUpdateFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/initialization/buildsrc/BuildSrcUpdateFactory.java
@@ -50,7 +50,6 @@ public class BuildSrcUpdateFactory implements Factory<DefaultClassPath> {
Collection<File> classpath = listener.getRuntimeClasspath();
LOGGER.debug("Gradle source classpath is: {}", classpath);
- LOGGER.info("================================================" + " Finished building buildSrc");
try {
markerFile.createNewFile();
} catch (IOException e) {
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/artifacts/repositories/AuthenticationSupportedInternal.java b/subprojects/core/src/main/groovy/org/gradle/internal/artifacts/repositories/AuthenticationSupportedInternal.java
index 70e4592..ed779ce 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/artifacts/repositories/AuthenticationSupportedInternal.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/artifacts/repositories/AuthenticationSupportedInternal.java
@@ -17,15 +17,16 @@
package org.gradle.internal.artifacts.repositories;
import org.gradle.api.Incubating;
-import org.gradle.api.Nullable;
import org.gradle.api.artifacts.repositories.AuthenticationSupported;
-import org.gradle.api.credentials.Credentials;
+import org.gradle.authentication.Authentication;
+
+import java.util.Collection;
public interface AuthenticationSupportedInternal extends AuthenticationSupported {
/**
- * Returns the configured credentials used to authenticate with this repository, or <code>null</code> if no credentials have been configured.
+ * Returns the configured authentication schemes or an instance of {@link org.gradle.internal.authentication.AllSchemesAuthentication}
+ * if none have been configured yet credentials have been configured.
*/
@Incubating
- @Nullable
- Credentials getConfiguredCredentials();
+ Collection<Authentication> getConfiguredAuthentication();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AbstractAuthentication.java b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AbstractAuthentication.java
new file mode 100644
index 0000000..4e82e78
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AbstractAuthentication.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import com.google.common.collect.Sets;
+import org.gradle.api.credentials.Credentials;
+import org.gradle.api.specs.Spec;
+import org.gradle.authentication.Authentication;
+import org.gradle.util.CollectionUtils;
+
+import java.util.Set;
+
+public abstract class AbstractAuthentication implements AuthenticationInternal {
+ private final String name;
+ private final Set<Class<? extends Credentials>> supportedCredentials;
+ private final Class<? extends Authentication> type;
+ private Credentials credentials;
+
+ public AbstractAuthentication(String name, Class<? extends Authentication> type) {
+ this.name = name;
+ this.supportedCredentials = Sets.newHashSet();
+ this.type = type;
+ }
+
+ public AbstractAuthentication(String name, Class<? extends Authentication> type, Class<? extends Credentials> supportedCredential) {
+ this.name = name;
+ this.supportedCredentials = Sets.<Class<? extends Credentials>>newHashSet(supportedCredential);
+ this.type = type;
+ }
+
+ @Override
+ public Credentials getCredentials() {
+ return credentials;
+ }
+
+ @Override
+ public void setCredentials(Credentials credentials) {
+ this.credentials = credentials;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Set<Class<? extends Credentials>> getSupportedCredentials() {
+ return supportedCredentials;
+ }
+
+ @Override
+ public boolean supports(final Credentials credentials) {
+ return CollectionUtils.any(getSupportedCredentials(), new Spec<Class<? extends Credentials>>() {
+ @Override
+ public boolean isSatisfiedBy(Class<? extends Credentials> element) {
+ return element.isAssignableFrom(credentials.getClass());
+ }
+ });
+ }
+
+ @Override
+ public Class<? extends Authentication> getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("'%s'(%s)", getName(), getType().getSimpleName());
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AllSchemesAuthentication.java b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AllSchemesAuthentication.java
new file mode 100644
index 0000000..8b5eef1
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AllSchemesAuthentication.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import org.gradle.api.credentials.Credentials;
+import org.gradle.authentication.Authentication;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Authentication scheme representing all supported schemes for a given protocol
+ */
+public class AllSchemesAuthentication extends AbstractAuthentication {
+ public AllSchemesAuthentication(Credentials credentials) {
+ super("all", Authentication.class);
+ this.setCredentials(credentials);
+ }
+
+ @Override
+ public Set<Class<? extends Credentials>> getSupportedCredentials() {
+ // effectively circumvent this check by just returning whatever kind of credentials are configured
+ Set<Class<? extends Credentials>> supported = new HashSet<Class<? extends Credentials>>();
+ supported.add(getCredentials().getClass());
+ return supported;
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AuthenticationInternal.java b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AuthenticationInternal.java
new file mode 100644
index 0000000..b104b8c
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/AuthenticationInternal.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import org.gradle.api.NonExtensible;
+import org.gradle.authentication.Authentication;
+import org.gradle.api.credentials.Credentials;
+
+import java.util.Set;
+
+ at NonExtensible
+public interface AuthenticationInternal extends Authentication {
+ Set<Class<? extends Credentials>> getSupportedCredentials();
+
+ boolean supports(Credentials credentials);
+
+ Credentials getCredentials();
+
+ void setCredentials(Credentials credentials);
+
+ Class<? extends Authentication> getType();
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/authentication/DefaultAuthenticationContainer.java b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/DefaultAuthenticationContainer.java
new file mode 100644
index 0000000..f8e00ab
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/authentication/DefaultAuthenticationContainer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import org.gradle.api.artifacts.repositories.AuthenticationContainer;
+import org.gradle.api.internal.DefaultPolymorphicDomainObjectContainer;
+import org.gradle.authentication.Authentication;
+import org.gradle.internal.reflect.Instantiator;
+
+public class DefaultAuthenticationContainer extends DefaultPolymorphicDomainObjectContainer<Authentication> implements AuthenticationContainer {
+
+ public DefaultAuthenticationContainer(Instantiator instantiator) {
+ super(Authentication.class, instantiator);
+ }
+
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporter.java b/subprojects/core/src/main/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporter.java
index 8e1b375..c470495 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporter.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporter.java
@@ -33,19 +33,16 @@ public class ScriptUsageLocationReporter implements ScriptExecutionListener, Usa
private final Lock lock = new ReentrantLock();
private final Map<String, ScriptSource> scripts = new HashMap<String, ScriptSource>();
- public void beforeScript(Script script) {
+ @Override
+ public void scriptClassLoaded(ScriptSource scriptSource, Class<? extends Script> scriptClass) {
lock.lock();
try {
- ScriptSource scriptSource = script.getScriptSource();
scripts.put(scriptSource.getFileName(), scriptSource);
} finally {
lock.unlock();
}
}
- public void afterScript(Script script, Throwable result) {
- }
-
public void reportLocation(DeprecatedFeatureUsage usage, StringBuilder target) {
lock.lock();
try {
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/graph/CachingDirectedGraphWalker.java b/subprojects/core/src/main/groovy/org/gradle/internal/graph/CachingDirectedGraphWalker.java
index a2eeb73..45b0e6c 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/graph/CachingDirectedGraphWalker.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/graph/CachingDirectedGraphWalker.java
@@ -132,8 +132,10 @@ public class CachingDirectedGraphWalker<N, T> {
for (N connectedNode : details.successors) {
NodeDetails<N, T> connectedNodeDetails = seenNodes.get(connectedNode);
if (!connectedNodeDetails.finished) {
- // part of a cycle
- details.minSeen = Math.min(details.minSeen, connectedNodeDetails.minSeen);
+ // part of a cycle : use the 'minimum' component as the root of the cycle
+ int minSeen = Math.min(details.minSeen, connectedNodeDetails.minSeen);
+ details.minSeen = minSeen;
+ connectedNodeDetails.minSeen = minSeen;
details.stronglyConnected = true;
}
details.values.addAll(connectedNodeDetails.values);
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationDetails.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationDetails.java
new file mode 100644
index 0000000..efd7792
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationDetails.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.progress;
+
+import org.gradle.api.Nullable;
+
+/**
+ * Meta-data about a build operation.
+ */
+public class BuildOperationDetails {
+ private final String displayName;
+ private final String progressDisplayName;
+
+ private BuildOperationDetails(String displayName, String progressDisplayName) {
+ this.displayName = displayName;
+ this.progressDisplayName = progressDisplayName;
+ }
+
+ /**
+ * Returns the display name for the operation. This should be a standalone human consumable description of the
+ * operation, and should describe the operation whether currently running or not, eg "run test A" rather than
+ * "running test A".
+ */
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ /**
+ * Returns the display name to use for progress logging for the operation. Should be short and describe the operation
+ * as it is running, eg "running test A" rather than "run test A".
+ *
+ * <p>When null, no progress logging is generated for the operation. Defaults to null.
+ */
+ @Nullable
+ public String getProgressDisplayName() {
+ return progressDisplayName;
+ }
+
+ public static Builder displayName(String displayName) {
+ return new Builder(displayName);
+ }
+
+ public static class Builder {
+ private final String displayName;
+ private String progressDisplayName;
+
+ private Builder(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public Builder progressDisplayName(String progressDisplayName) {
+ this.progressDisplayName = progressDisplayName;
+ return this;
+ }
+
+ public BuildOperationDetails build() {
+ return new BuildOperationDetails(displayName, progressDisplayName);
+ }
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationExecutor.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationExecutor.java
index 5e85101..434c05b 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationExecutor.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationExecutor.java
@@ -16,32 +16,58 @@
package org.gradle.internal.progress;
+import net.jcip.annotations.ThreadSafe;
import org.gradle.internal.Factory;
/**
- * Runs build operations. These are the pieces of work that make up a build.
+ * Runs build operations. These are the pieces of work that make up a build. Build operations can be nested inside other
+ * build operations.
*
- * <p>Note that the current implementation is not thread safe. This will happen later.</p>
+ * The executor provides several capabilities:
*
- * <p>This is to be synchronized with {@link org.gradle.internal.operations.BuildOperationProcessor}.
+ * <ul>
+ * <p>Fires events via {@link InternalBuildListener}. For example, this means that notification of build operation
+ * execution can be received by tooling AIP clients.</p>
+ * <p>Generates progress logging events.</p>
+ * </ul>
+ *
+ * <p>This is intended to be synchronized with {@link org.gradle.internal.operations.BuildOperationProcessor}, to
+ * allow both synchronous and asynchronous execution of build operations.
*/
+ at ThreadSafe
public interface BuildOperationExecutor {
/**
* Runs the given build operation synchronously. Invokes the given factory from the current thread and returns the result.
*
* <p>Rethrows any exception thrown by the factory.</p>
*/
- <T> T run(Object id, BuildOperationType operationType, Factory<T> factory);
+ <T> T run(String displayName, Factory<T> factory);
+
+ /**
+ * Runs the given build operation synchronously. Invokes the given factory from the current thread and returns the result.
+ *
+ * <p>Rethrows any exception thrown by the factory.</p>
+ */
+ <T> T run(BuildOperationDetails operationDetails, Factory<T> factory);
/**
* Runs the given build operation synchronously. Invokes the given action from the current thread.
*
* <p>Rethrows any exception thrown by the action.</p>
*/
- void run(Object id, BuildOperationType operationType, Runnable action);
+ void run(String displayName, Runnable action);
+
+ /**
+ * Runs the given build operation synchronously. Invokes the given action from the current thread.
+ *
+ * <p>Rethrows any exception thrown by the action.</p>
+ */
+ void run(BuildOperationDetails operationDetails, Runnable action);
/**
* Returns the id of the current operation.
+ *
+ * @throws IllegalStateException When the current thread is not executing an operation.
*/
Object getCurrentOperationId();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationInternal.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationInternal.java
index e5ee549..30b886f 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationInternal.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationInternal.java
@@ -20,12 +20,12 @@ import org.gradle.api.Nullable;
public final class BuildOperationInternal {
private final Object id;
private final Object parentId;
- private final BuildOperationType operationType;
+ private final String displayName;
- public BuildOperationInternal(Object id, Object parentId, BuildOperationType operationType) {
+ public BuildOperationInternal(Object id, Object parentId, String displayName) {
this.id = id;
this.parentId = parentId;
- this.operationType = operationType;
+ this.displayName = displayName;
}
public Object getId() {
@@ -37,7 +37,7 @@ public final class BuildOperationInternal {
return parentId;
}
- public BuildOperationType getOperationType() {
- return operationType;
+ public String getDisplayName() {
+ return displayName;
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationType.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationType.java
deleted file mode 100644
index b4ac6d5..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/BuildOperationType.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.progress;
-
-/**
- * Enumerates the build operations tracked by the progress event infrastructure.
- */
-public enum BuildOperationType {
-
- RUNNING_BUILD("Run build"),
- EVALUATING_INIT_SCRIPTS("Run init scripts"),
- EVALUATING_SETTINGS("Load projects"),
- CONFIGURING_BUILD("Configure build"),
- POPULATING_TASK_GRAPH("Calculate task graph"),
- EXECUTING_TASKS("Run tasks");
-
- private String name;
-
- BuildOperationType(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- public String getDisplayName() {
- return getName();
- }
-
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutor.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutor.java
index bf50117..3039ca3 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutor.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutor.java
@@ -20,46 +20,79 @@ import org.gradle.internal.Factories;
import org.gradle.internal.Factory;
import org.gradle.internal.TimeProvider;
import org.gradle.internal.UncheckedException;
+import org.gradle.logging.ProgressLogger;
+import org.gradle.logging.ProgressLoggerFactory;
-import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicLong;
-// TODO - thread safety
public class DefaultBuildOperationExecutor implements BuildOperationExecutor {
private final InternalBuildListener listener;
private final TimeProvider timeProvider;
- private LinkedList<Object> operationStack = new LinkedList<Object>();
+ private final ProgressLoggerFactory progressLoggerFactory;
+ private final AtomicLong nextId = new AtomicLong();
+ private final ThreadLocal<OperationDetails> currentOperation = new ThreadLocal<OperationDetails>();
- public DefaultBuildOperationExecutor(InternalBuildListener listener, TimeProvider timeProvider) {
+ public DefaultBuildOperationExecutor(InternalBuildListener listener, TimeProvider timeProvider, ProgressLoggerFactory progressLoggerFactory) {
this.listener = listener;
this.timeProvider = timeProvider;
+ this.progressLoggerFactory = progressLoggerFactory;
}
@Override
public Object getCurrentOperationId() {
- if (operationStack.isEmpty()) {
+ OperationDetails current = currentOperation.get();
+ if (current == null) {
throw new IllegalStateException("No operation is currently running.");
}
- return operationStack.getFirst();
+ return current.id;
}
@Override
- public void run(Object id, BuildOperationType operationType, Runnable action) {
- run(id, operationType, Factories.toFactory(action));
+ public void run(String displayName, Runnable action) {
+ run(BuildOperationDetails.displayName(displayName).build(), Factories.toFactory(action));
}
@Override
- public <T> T run(Object id, BuildOperationType operationType, Factory<T> factory) {
- Object parentId = operationStack.isEmpty() ? null : operationStack.getFirst();
- operationStack.addFirst(id);
+ public void run(BuildOperationDetails operationDetails, Runnable action) {
+ run(operationDetails, Factories.toFactory(action));
+ }
+
+ @Override
+ public <T> T run(String displayName, Factory<T> factory) {
+ return run(BuildOperationDetails.displayName(displayName).build(), factory);
+ }
+
+ @Override
+ public <T> T run(BuildOperationDetails operationDetails, Factory<T> factory) {
+ OperationDetails parent = currentOperation.get();
+ OperationIdentifier parentId = parent == null ? null : parent.id;
+ OperationIdentifier id = new OperationIdentifier(nextId.getAndIncrement());
+ currentOperation.set(new OperationDetails(parent, id));
try {
long startTime = timeProvider.getCurrentTime();
- BuildOperationInternal operation = new BuildOperationInternal(id, parentId, operationType);
+ BuildOperationInternal operation = new BuildOperationInternal(id, parentId, operationDetails.getDisplayName());
listener.started(operation, new OperationStartEvent(startTime));
T result = null;
Throwable failure = null;
try {
- result = factory.create();
+ ProgressLogger progressLogger;
+ if (operationDetails.getProgressDisplayName() != null) {
+ progressLogger = progressLoggerFactory.newOperation(DefaultBuildOperationExecutor.class);
+ progressLogger.setDescription(operationDetails.getDisplayName());
+ progressLogger.setShortDescription(operationDetails.getProgressDisplayName());
+ progressLogger.started();
+ } else {
+ progressLogger = null;
+ }
+
+ try {
+ result = factory.create();
+ } finally {
+ if (progressLogger != null) {
+ progressLogger.completed();
+ }
+ }
} catch (Throwable t) {
failure = t;
}
@@ -73,7 +106,17 @@ public class DefaultBuildOperationExecutor implements BuildOperationExecutor {
return result;
} finally {
- operationStack.removeFirst();
+ currentOperation.set(parent);
+ }
+ }
+
+ private static class OperationDetails {
+ final OperationDetails parent;
+ final OperationIdentifier id;
+
+ public OperationDetails(OperationDetails parent, OperationIdentifier id) {
+ this.parent = parent;
+ this.id = id;
}
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/InternalBuildListener.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/InternalBuildListener.java
index f9984d8..05914b6 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/InternalBuildListener.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/InternalBuildListener.java
@@ -15,6 +15,9 @@
*/
package org.gradle.internal.progress;
+/**
+ * A listener that is notified as build operations are executed via a {@link BuildOperationExecutor}.
+ */
public interface InternalBuildListener {
void started(BuildOperationInternal buildOperation, OperationStartEvent startEvent);
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/LoggerProvider.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/LoggerProvider.java
index 050b4da..26e7f3d 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/LoggerProvider.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/LoggerProvider.java
@@ -22,7 +22,7 @@ public interface LoggerProvider {
ProgressLogger getLogger();
- public static LoggerProvider NO_OP = new LoggerProvider() {
+ LoggerProvider NO_OP = new LoggerProvider() {
public ProgressLogger getLogger() {
return null;
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdGenerator.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdGenerator.java
index 85d7341..d7f417e 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdGenerator.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdGenerator.java
@@ -34,17 +34,6 @@ public final class OperationIdGenerator {
}
/**
- * Generates an operation id for the given build operation type.
- *
- * @param operationType the build operation type
- * @param gradle te Gradle instance to which the build operation belongs
- * @return the operation id
- */
- public static Object generateId(BuildOperationType operationType, Gradle gradle) {
- return generateId(gradle) + "-" + operationType.getName();
- }
-
- /**
* Generates an operation id for the given Gradle instance.
*
* @param gradle the Gradle instance
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdentifier.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdentifier.java
index 2f16283..91c8933 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdentifier.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationIdentifier.java
@@ -20,24 +20,18 @@ import java.io.Serializable;
public class OperationIdentifier implements Serializable {
private final long id;
- private final Long parentId;
- public OperationIdentifier(long id, Long parentId) {
+ public OperationIdentifier(long id) {
this.id = id;
- this.parentId = parentId;
}
public long getId() {
return id;
}
- public Long getParentId() {
- return parentId;
- }
-
@Override
public String toString() {
- return id + ":" + parentId;
+ return String.valueOf(id);
}
@Override
@@ -50,18 +44,11 @@ public class OperationIdentifier implements Serializable {
}
OperationIdentifier that = (OperationIdentifier) o;
-
- if (getId() != that.getId()) {
- return false;
- }
- return !(getParentId() != null ? !getParentId().equals(that.getParentId()) : that.getParentId() != null);
-
+ return id == that.id;
}
@Override
public int hashCode() {
- int result = (int) (getId() ^ (getId() >>> 32));
- result = 31 * result + (getParentId() != null ? getParentId().hashCode() : 0);
- return result;
+ return (int) id;
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationsHierarchy.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationsHierarchy.java
deleted file mode 100644
index c3d5308..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationsHierarchy.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.progress;
-
-import java.util.LinkedList;
-import java.util.concurrent.atomic.AtomicLong;
-
-public class OperationsHierarchy {
- final AtomicLong sharedCounter;
- final LinkedList<Long> hierarchy;
- private OperationIdentifier id;
-
- public OperationsHierarchy(AtomicLong sharedCounter, LinkedList<Long> hierarchy) {
- assert sharedCounter != null;
- assert hierarchy != null;
-
- this.sharedCounter = sharedCounter;
- this.hierarchy = hierarchy;
- }
-
- public OperationIdentifier start() {
- if (id == null) {
- Long parent = hierarchy.isEmpty()? null: hierarchy.getLast();
- long operationId = sharedCounter.incrementAndGet();
- hierarchy.addLast(operationId);
- id = new OperationIdentifier(operationId, parent);
- }
-
- return id;
- }
-
- public OperationIdentifier currentOperationId() {
- assertOperationStarted();
- return id;
- }
-
- public OperationIdentifier completeCurrentOperation() {
- OperationIdentifier currentOp = currentOperationId();
- assertHierarchyNotEmpty();
- Long last = hierarchy.getLast();
- if (currentOp.getId() == last) {
- //typical scenario
- hierarchy.removeLast();
- } else {
- //this means that we're removing an operation id that has incomplete children
- //this is not strictly correct, we might fail fast here
- //however, this needs some discussion and making sure child operations are always completed before the parent
- //(even in internal error conditions)
- hierarchy.remove(currentOp.getId());
- }
- id = null;
- return currentOp;
- }
-
- private void assertOperationStarted() {
- if (id == null) {
- throw new NoActiveOperationFound("Cannot provide current operation id because the operation was not started or it was already completed.");
- }
- }
-
- private void assertHierarchyNotEmpty() {
- if (hierarchy.isEmpty()) {
- throw new HierarchyEmptyException("Unable to provide operation id because there are no active operations in the hierarchy. Was the hierarchy list tinkered with?");
- }
- }
-
- static class HierarchyEmptyException extends IllegalStateException {
- public HierarchyEmptyException(String message) {
- super(message);
- }
- }
- static class NoActiveOperationFound extends IllegalStateException {
- public NoActiveOperationFound(String message) {
- super(message);
- }
- }
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationsHierarchyKeeper.java b/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationsHierarchyKeeper.java
deleted file mode 100644
index 836052c..0000000
--- a/subprojects/core/src/main/groovy/org/gradle/internal/progress/OperationsHierarchyKeeper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.progress;
-
-import org.gradle.logging.ProgressLogger;
-
-import java.util.LinkedList;
-import java.util.concurrent.atomic.AtomicLong;
-
-public class OperationsHierarchyKeeper {
-
- private final AtomicLong sharedCounter = new AtomicLong();
- private final ThreadLocal<LinkedList<Long>> hierarchy = new ThreadLocal<LinkedList<Long>>();
-
- public OperationsHierarchy currentHierarchy(ProgressLogger parentHint) {
- LinkedList<Long> h = hierarchy.get();
- if (h == null) {
- h = new LinkedList<Long>();
- if (parentHint != null) {
- h.add(parentHint.currentOperationId().getId());
- }
- hierarchy.set(h);
- }
- return new OperationsHierarchy(sharedCounter, h);
- }
-}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/BuildScopeServices.java b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/BuildScopeServices.java
index b89b9a7..855a23a 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/BuildScopeServices.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/BuildScopeServices.java
@@ -55,9 +55,13 @@ import org.gradle.groovy.scripts.ScriptCompilerFactory;
import org.gradle.groovy.scripts.ScriptExecutionListener;
import org.gradle.groovy.scripts.internal.*;
import org.gradle.initialization.*;
+import org.gradle.initialization.buildsrc.BuildSourceBuilder;
+import org.gradle.initialization.layout.BuildLayoutFactory;
import org.gradle.internal.Factory;
import org.gradle.internal.TimeProvider;
import org.gradle.internal.TrueTimeProvider;
+import org.gradle.internal.authentication.AuthenticationSchemeRegistry;
+import org.gradle.internal.authentication.DefaultAuthenticationSchemeRegistry;
import org.gradle.internal.classloader.ClassLoaderFactory;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.event.ListenerManager;
@@ -121,8 +125,8 @@ public class BuildScopeServices extends DefaultServiceRegistry {
return listenerManager.createChild();
}
- protected BuildOperationExecutor createBuildOperationExecutor(ListenerManager listenerManager, TimeProvider timeProvider) {
- return new DefaultBuildOperationExecutor(listenerManager.getBroadcaster(InternalBuildListener.class), timeProvider);
+ protected BuildOperationExecutor createBuildOperationExecutor(ListenerManager listenerManager, TimeProvider timeProvider, ProgressLoggerFactory progressLoggerFactory) {
+ return new DefaultBuildOperationExecutor(listenerManager.getBroadcaster(InternalBuildListener.class), timeProvider, progressLoggerFactory);
}
protected ClassPathRegistry createClassPathRegistry() {
@@ -183,13 +187,12 @@ public class BuildScopeServices extends DefaultServiceRegistry {
);
}
- protected ScriptCompilerFactory createScriptCompileFactory(ListenerManager listenerManager, EmptyScriptGenerator emptyScriptGenerator, FileCacheBackedScriptClassCompiler scriptCompiler, ClassLoaderCache classLoaderCache) {
+ protected ScriptCompilerFactory createScriptCompileFactory(ListenerManager listenerManager, FileCacheBackedScriptClassCompiler scriptCompiler, ClassLoaderCache classLoaderCache) {
ScriptExecutionListener scriptExecutionListener = listenerManager.getBroadcaster(ScriptExecutionListener.class);
return new DefaultScriptCompilerFactory(
new CachingScriptClassCompiler(
new ShortCircuitEmptyScriptCompiler(
scriptCompiler,
- emptyScriptGenerator,
classLoaderCache
)
),
@@ -200,12 +203,8 @@ public class BuildScopeServices extends DefaultServiceRegistry {
);
}
- protected EmptyScriptGenerator createEmptyScriptGenerator() {
- return new AsmBackedEmptyScriptGenerator();
- }
-
protected FileCacheBackedScriptClassCompiler createFileCacheBackedScriptClassCompiler(
- CacheRepository cacheRepository, EmptyScriptGenerator emptyScriptGenerator, final StartParameter startParameter,
+ CacheRepository cacheRepository, final StartParameter startParameter,
ProgressLoggerFactory progressLoggerFactory, ClassLoaderCache classLoaderCache, ImportsReader importsReader) {
CacheValidator scriptCacheInvalidator = new CacheValidator() {
public boolean isValid() {
@@ -215,7 +214,7 @@ public class BuildScopeServices extends DefaultServiceRegistry {
return new FileCacheBackedScriptClassCompiler(
cacheRepository,
scriptCacheInvalidator,
- new DefaultScriptCompilationHandler(emptyScriptGenerator, classLoaderCache, importsReader),
+ new DefaultScriptCompilationHandler(classLoaderCache, importsReader),
progressLoggerFactory
);
}
@@ -233,28 +232,49 @@ public class BuildScopeServices extends DefaultServiceRegistry {
);
}
- protected InitScriptHandler createInitScriptHandler() {
+ protected SettingsLoader createSettingsLoader(SettingsProcessor settingsProcessor, GradleLauncherFactory gradleLauncherFactory,
+ ClassLoaderScopeRegistry classLoaderScopeRegistry, CacheRepository cacheRepository,
+ BuildLoader buildLoader, BuildOperationExecutor buildOperationExecutor) {
+ return new NotifyingSettingsLoader(
+ new SettingsHandler(
+ new DefaultSettingsFinder(
+ new BuildLayoutFactory()),
+ settingsProcessor,
+ new BuildSourceBuilder(
+ gradleLauncherFactory,
+ classLoaderScopeRegistry.getCoreAndPluginsScope(),
+ cacheRepository,
+ buildOperationExecutor)
+ ),
+ buildLoader);
+ }
+
+ protected InitScriptHandler createInitScriptHandler(ScriptPluginFactory scriptPluginFactory, ScriptHandlerFactory scriptHandlerFactory, BuildOperationExecutor buildOperationExecutor) {
return new InitScriptHandler(
new DefaultInitScriptProcessor(
- get(ScriptPluginFactory.class),
- get(ScriptHandlerFactory.class)
- )
+ scriptPluginFactory,
+ scriptHandlerFactory
+ ),
+ buildOperationExecutor
);
}
- protected SettingsProcessor createSettingsProcessor() {
- return new PropertiesLoadingSettingsProcessor(
- new ScriptEvaluatingSettingsProcessor(
- get(ScriptPluginFactory.class),
- get(ScriptHandlerFactory.class),
- new SettingsFactory(
- get(Instantiator.class),
- get(ServiceRegistryFactory.class)
+ protected SettingsProcessor createSettingsProcessor(ScriptPluginFactory scriptPluginFactory, ScriptHandlerFactory scriptHandlerFactory, Instantiator instantiator,
+ ServiceRegistryFactory serviceRegistryFactory, IGradlePropertiesLoader propertiesLoader, BuildOperationExecutor buildOperationExecutor) {
+ return new NotifyingSettingsProcessor(
+ new PropertiesLoadingSettingsProcessor(
+ new ScriptEvaluatingSettingsProcessor(
+ scriptPluginFactory,
+ scriptHandlerFactory,
+ new SettingsFactory(
+ instantiator,
+ serviceRegistryFactory
+ ),
+ propertiesLoader
),
- get(IGradlePropertiesLoader.class)
+ propertiesLoader
),
- get(IGradlePropertiesLoader.class)
- );
+ buildOperationExecutor);
}
protected ExceptionAnalyser createExceptionAnalyser(ListenerManager listenerManager, LoggingConfiguration loggingConfiguration) {
@@ -338,4 +358,8 @@ public class BuildScopeServices extends DefaultServiceRegistry {
return new DefaultBuildOperationLoggerFactory();
}
+ AuthenticationSchemeRegistry createAuthenticationSchemeRegistry() {
+ return new DefaultAuthenticationSchemeRegistry();
+ }
+
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/BuildSessionScopeServices.java b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/BuildSessionScopeServices.java
new file mode 100644
index 0000000..85f3544
--- /dev/null
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/BuildSessionScopeServices.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.service.scopes;
+
+import org.gradle.api.Action;
+import org.gradle.deployment.internal.DefaultDeploymentRegistry;
+import org.gradle.deployment.internal.DeploymentRegistry;
+import org.gradle.internal.service.DefaultServiceRegistry;
+import org.gradle.internal.service.ServiceRegistration;
+import org.gradle.internal.service.ServiceRegistry;
+
+/**
+ * Contains the services for a single build session, which could be a single build or multiple builds when in continuous mode.
+ */
+public class BuildSessionScopeServices extends DefaultServiceRegistry {
+ public BuildSessionScopeServices(final ServiceRegistry parent) {
+ super(parent);
+ register(new Action<ServiceRegistration>() {
+ @Override
+ public void execute(ServiceRegistration registration) {
+ for (PluginServiceRegistry pluginServiceRegistry : parent.getAll(PluginServiceRegistry.class)) {
+ pluginServiceRegistry.registerBuildSessionServices(registration);
+ }
+ }
+ });
+ }
+
+ DeploymentRegistry createDeploymentRegistry() {
+ return new DefaultDeploymentRegistry();
+ }
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GlobalScopeServices.java b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GlobalScopeServices.java
index a242354..9fa4151 100755
--- a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GlobalScopeServices.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GlobalScopeServices.java
@@ -21,10 +21,7 @@ import org.gradle.StartParameter;
import org.gradle.api.internal.*;
import org.gradle.api.internal.changedetection.state.CachingFileSnapshotter;
import org.gradle.api.internal.changedetection.state.InMemoryTaskArtifactCache;
-import org.gradle.api.internal.classpath.DefaultModuleRegistry;
-import org.gradle.api.internal.classpath.DefaultPluginModuleRegistry;
-import org.gradle.api.internal.classpath.ModuleRegistry;
-import org.gradle.api.internal.classpath.PluginModuleRegistry;
+import org.gradle.api.internal.classpath.*;
import org.gradle.api.internal.file.*;
import org.gradle.api.internal.hash.DefaultHasher;
import org.gradle.api.internal.initialization.loadercache.*;
@@ -39,6 +36,8 @@ import org.gradle.configuration.ImportsReader;
import org.gradle.initialization.*;
import org.gradle.internal.classloader.ClassLoaderFactory;
import org.gradle.internal.classloader.DefaultClassLoaderFactory;
+import org.gradle.internal.classpath.ClassPath;
+import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.internal.concurrent.DefaultExecutorFactory;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.environment.GradleBuildEnvironment;
@@ -56,10 +55,12 @@ import org.gradle.internal.service.ServiceRegistry;
import org.gradle.messaging.remote.MessagingServer;
import org.gradle.messaging.remote.internal.MessagingServices;
import org.gradle.messaging.remote.internal.inet.InetAddressFactory;
-import org.gradle.model.internal.core.ModelCreatorFactory;
-import org.gradle.model.internal.inspect.*;
+import org.gradle.model.internal.inspect.MethodModelRuleExtractor;
+import org.gradle.model.internal.inspect.MethodModelRuleExtractors;
+import org.gradle.model.internal.inspect.ModelRuleExtractor;
+import org.gradle.model.internal.inspect.ModelRuleSourceDetector;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
-import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore;
+import org.gradle.model.internal.manage.schema.extract.*;
import org.gradle.model.internal.persist.AlwaysNewModelRegistryStore;
import org.gradle.model.internal.persist.ModelRegistryStore;
import org.gradle.model.internal.persist.ReusingModelRegistryStore;
@@ -72,10 +73,16 @@ import java.util.List;
public class GlobalScopeServices {
private static final Logger LOGGER = Logging.getLogger(GlobalScopeServices.class);
+ private final ClassPath additionalModuleClassPath;
private GradleBuildEnvironment environment;
public GlobalScopeServices(final boolean longLiving) {
+ this(longLiving, new DefaultClassPath());
+ }
+
+ public GlobalScopeServices(final boolean longLiving, ClassPath additionalModuleClassPath) {
+ this.additionalModuleClassPath = additionalModuleClassPath;
this.environment = new GradleBuildEnvironment() {
public boolean isLongLivingProcess() {
return longLiving;
@@ -114,8 +121,12 @@ public class GlobalScopeServices {
pluginModuleRegistry));
}
- DefaultModuleRegistry createModuleRegistry() {
- return new DefaultModuleRegistry();
+ ModuleRegistry createModuleRegistry() {
+ return new DefaultModuleRegistry(additionalModuleClassPath);
+ }
+
+ GradleDistributionLocator createGradleDistributionLocator() {
+ return new DefaultGradleDistributionLocator();
}
DocumentationRegistry createDocumentationRegistry() {
@@ -188,9 +199,9 @@ public class GlobalScopeServices {
return new DefaultFileLookup(fileSystem);
}
- ModelRuleExtractor createModelRuleInspector(ServiceRegistry services, ModelSchemaStore modelSchemaStore, ModelCreatorFactory modelCreatorFactory) {
+ ModelRuleExtractor createModelRuleInspector(ServiceRegistry services, ModelSchemaStore modelSchemaStore) {
List<MethodModelRuleExtractor> extractors = services.getAll(MethodModelRuleExtractor.class);
- List<MethodModelRuleExtractor> coreExtractors = MethodModelRuleExtractors.coreExtractors(modelSchemaStore, modelCreatorFactory);
+ List<MethodModelRuleExtractor> coreExtractors = MethodModelRuleExtractors.coreExtractors(modelSchemaStore);
return new ModelRuleExtractor(Iterables.concat(coreExtractors, extractors));
}
@@ -207,12 +218,18 @@ public class GlobalScopeServices {
return new DefaultClassLoaderCache(classPathSnapshotter);
}
- private DefaultModelCreatorFactory createModelCreatorFactory(ModelSchemaStore modelSchemaStore) {
- return new DefaultModelCreatorFactory(modelSchemaStore);
+ protected ModelSchemaAspectExtractor createModelSchemaAspectExtractor(ServiceRegistry serviceRegistry) {
+ List<ModelSchemaAspectExtractionStrategy> strategies = serviceRegistry.getAll(ModelSchemaAspectExtractionStrategy.class);
+ return new ModelSchemaAspectExtractor(strategies);
+ }
+
+ protected ModelSchemaExtractor createModelSchemaExtractor(ModelSchemaAspectExtractor aspectExtractor, ServiceRegistry serviceRegistry) {
+ List<ModelSchemaExtractionStrategy> strategies = serviceRegistry.getAll(ModelSchemaExtractionStrategy.class);
+ return new ModelSchemaExtractor(strategies, aspectExtractor);
}
- protected ModelSchemaStore createModelSchemaStore() {
- return DefaultModelSchemaStore.getInstance();
+ protected ModelSchemaStore createModelSchemaStore(ModelSchemaExtractor modelSchemaExtractor) {
+ return new DefaultModelSchemaStore(modelSchemaExtractor);
}
protected ModelRuleSourceDetector createModelRuleSourceDetector() {
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GradleScopeServices.java b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GradleScopeServices.java
index 51f1315..5b414a2 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GradleScopeServices.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/GradleScopeServices.java
@@ -40,6 +40,7 @@ import org.gradle.internal.service.DefaultServiceRegistry;
import org.gradle.internal.service.ServiceRegistration;
import org.gradle.internal.service.ServiceRegistry;
+import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -77,18 +78,19 @@ public class GradleScopeServices extends DefaultServiceRegistry {
return new CommandLineTaskParser(new CommandLineTaskConfigurer(optionReader), taskSelector);
}
- BuildExecuter createBuildExecuter(CommandLineTaskParser commandLineTaskParser, TaskSelector taskSelector, ProjectConfigurer projectConfigurer) {
- List<BuildConfigurationAction> configs = new LinkedList<BuildConfigurationAction>();
- configs.add(new DefaultTasksBuildExecutionAction(projectConfigurer));
- configs.add(new ExcludedTaskFilteringBuildConfigurationAction(taskSelector));
- configs.add(new TaskNameResolvingBuildConfigurationAction(commandLineTaskParser));
-
+ BuildExecuter createBuildExecuter() {
return new DefaultBuildExecuter(
- configs,
asList(new DryRunBuildExecutionAction(),
new SelectedTaskExecutionAction()));
}
+ BuildConfigurationActionExecuter createBuildConfigurationActionExecuter(CommandLineTaskParser commandLineTaskParser, TaskSelector taskSelector, ProjectConfigurer projectConfigurer) {
+ List<BuildConfigurationAction> taskSelectionActions = new LinkedList<BuildConfigurationAction>();
+ taskSelectionActions.add(new DefaultTasksBuildExecutionAction(projectConfigurer));
+ taskSelectionActions.add(new TaskNameResolvingBuildConfigurationAction(commandLineTaskParser));
+ return new DefaultBuildConfigurationActionExecuter(Arrays.asList(new ExcludedTaskFilteringBuildConfigurationAction(taskSelector)), taskSelectionActions);
+ }
+
ProjectFinder createProjectFinder(final GradleInternal gradle) {
return new ProjectFinder() {
public ProjectInternal getProject(String path) {
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/PluginServiceRegistry.java b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/PluginServiceRegistry.java
index 2804f71..1040a7f 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/PluginServiceRegistry.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/PluginServiceRegistry.java
@@ -30,6 +30,12 @@ public interface PluginServiceRegistry {
void registerGlobalServices(ServiceRegistration registration);
/**
+ * Called once per build session to register any build session scoped services. These services are reused across builds when in
+ * continuous mode. They are discarded at the end of the build session.
+ */
+ void registerBuildSessionServices(ServiceRegistration registration);
+
+ /**
* Called once per build, to registry any build scoped services. These services are discarded at the end of the current build.
* All global scoped services are visible to the build scope services, but not vice versa.
*/
diff --git a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/ProjectScopeServices.java b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/ProjectScopeServices.java
index 4474b37..f7d4ac1 100644
--- a/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/ProjectScopeServices.java
+++ b/subprojects/core/src/main/groovy/org/gradle/internal/service/scopes/ProjectScopeServices.java
@@ -163,11 +163,7 @@ public class ProjectScopeServices extends DefaultServiceRegistry {
}
protected DependencyMetaDataProvider createDependencyMetaDataProvider() {
- return new DependencyMetaDataProvider() {
- public ModuleInternal getModule() {
- return new ProjectBackedModule(project);
- }
- };
+ return new ProjectBackedModuleMetaDataProvider();
}
protected ServiceRegistryFactory createServiceRegistryFactory(final ServiceRegistry services) {
@@ -185,4 +181,9 @@ public class ProjectScopeServices extends DefaultServiceRegistry {
return new ComponentRegistry();
}
+ private class ProjectBackedModuleMetaDataProvider implements DependencyMetaDataProvider {
+ public ModuleInternal getModule() {
+ return new ProjectBackedModule(project);
+ }
+ }
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLogger.java b/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLogger.java
index ca16f67..496c899 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLogger.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLogger.java
@@ -16,8 +16,6 @@
package org.gradle.logging;
-import org.gradle.internal.progress.OperationIdentifier;
-
/**
* Used to log the progress of a potentially long running operation.
*
@@ -52,7 +50,7 @@ public interface ProgressLogger {
*
* @param description The description.
*/
- void setDescription(String description);
+ ProgressLogger setDescription(String description);
/**
* Returns the short description of the operation. This is used in place of the full description when display space is limited.
@@ -68,7 +66,7 @@ public interface ProgressLogger {
*
* @param description The short description.
*/
- void setShortDescription(String description);
+ ProgressLogger setShortDescription(String description);
/**
* <p>Returns the logging header for the operation. This is logged before any other log messages for this operation are logged. It is usually
@@ -86,7 +84,7 @@ public interface ProgressLogger {
*
* @param header The header. May be empty or null.
*/
- void setLoggingHeader(String header);
+ ProgressLogger setLoggingHeader(String header);
/**
* Convenience method that sets descriptions and logs started() event.
@@ -125,6 +123,4 @@ public interface ProgressLogger {
* @param status The final status message. Can be null or empty.
*/
void completed(String status);
-
- OperationIdentifier currentOperationId();
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLoggerFactory.java b/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLoggerFactory.java
index 34c7dfe..2d57aa4 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLoggerFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/ProgressLoggerFactory.java
@@ -16,8 +16,9 @@
package org.gradle.logging;
-import org.gradle.TaskExecutionLogger;
-
+/**
+ * Thread-safe, however the progress logger instances created are not.
+ */
public interface ProgressLoggerFactory {
/**
* Creates a new long-running operation which has not been started.
@@ -33,7 +34,7 @@ public interface ProgressLoggerFactory {
* @param loggerCategory The logger category.
* @return The progress logger for the operation.
*/
- ProgressLogger newOperation(Class loggerCategory);
+ ProgressLogger newOperation(Class<?> loggerCategory);
- ProgressLogger newOperation(Class<TaskExecutionLogger> taskExecutionLoggerClass, ProgressLogger parent);
+ ProgressLogger newOperation(Class<?> loggerClass, ProgressLogger parent);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ConsoleBackedProgressRenderer.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ConsoleBackedProgressRenderer.java
index a5eab98..4935f23 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ConsoleBackedProgressRenderer.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ConsoleBackedProgressRenderer.java
@@ -35,14 +35,14 @@ public class ConsoleBackedProgressRenderer implements OutputEventListener {
try {
if (event instanceof ProgressStartEvent) {
ProgressStartEvent startEvent = (ProgressStartEvent) event;
- ProgressOperation op = operations.start(startEvent.getShortDescription(), startEvent.getStatus(), startEvent.getOperationId().getId(), startEvent.getOperationId().getParentId());
+ ProgressOperation op = operations.start(startEvent.getShortDescription(), startEvent.getStatus(), startEvent.getOperationId(), startEvent.getParentId());
updateText(op);
} else if (event instanceof ProgressCompleteEvent) {
- ProgressOperation op = operations.complete(((ProgressCompleteEvent) event).getOperationId().getId());
+ ProgressOperation op = operations.complete(((ProgressCompleteEvent) event).getOperationId());
updateText(op.getParent());
} else if (event instanceof ProgressEvent) {
ProgressEvent progressEvent = (ProgressEvent) event;
- ProgressOperation op = operations.progress(progressEvent.getStatus(), progressEvent.getOperationId().getId());
+ ProgressOperation op = operations.progress(progressEvent.getStatus(), progressEvent.getOperationId());
updateText(op);
}
listener.onOutput(event);
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactory.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactory.java
index a868482..f8c1320 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactory.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactory.java
@@ -18,16 +18,17 @@ package org.gradle.logging.internal;
import org.gradle.internal.TimeProvider;
import org.gradle.internal.progress.OperationIdentifier;
-import org.gradle.internal.progress.OperationsHierarchy;
-import org.gradle.internal.progress.OperationsHierarchyKeeper;
import org.gradle.logging.ProgressLogger;
import org.gradle.logging.ProgressLoggerFactory;
import org.gradle.util.GUtil;
+import java.util.concurrent.atomic.AtomicLong;
+
public class DefaultProgressLoggerFactory implements ProgressLoggerFactory {
private final ProgressListener progressListener;
private final TimeProvider timeProvider;
- private final OperationsHierarchyKeeper hierarchyKeeper = new OperationsHierarchyKeeper();
+ private final AtomicLong nextId = new AtomicLong();
+ private final ThreadLocal<ProgressLoggerImpl> current = new ThreadLocal<ProgressLoggerImpl>();
public DefaultProgressLoggerFactory(ProgressListener progressListener, TimeProvider timeProvider) {
this.progressListener = progressListener;
@@ -42,28 +43,33 @@ public class DefaultProgressLoggerFactory implements ProgressLoggerFactory {
return init(loggerCategory, null);
}
- public ProgressLogger newOperation(Class loggerCategory, ProgressLogger parent) {
- return init(loggerCategory.toString(), parent);
+ public ProgressLogger newOperation(Class loggerClass, ProgressLogger parent) {
+ return init(loggerClass.toString(), parent);
}
- private ProgressLogger init(String loggerCategory, ProgressLogger parentHint) {
- return new ProgressLoggerImpl(hierarchyKeeper.currentHierarchy(parentHint), loggerCategory, progressListener, timeProvider);
+ private ProgressLogger init(String loggerCategory, ProgressLogger parentOperation) {
+ if (parentOperation != null && !(parentOperation instanceof ProgressLoggerImpl)) {
+ throw new IllegalArgumentException("Unexpected parent logger.");
+ }
+ return new ProgressLoggerImpl((ProgressLoggerImpl) parentOperation, nextId.getAndIncrement(), loggerCategory, progressListener, timeProvider);
}
- private static class ProgressLoggerImpl implements ProgressLogger {
- private enum State { idle, started, completed }
+ private enum State { idle, started, completed }
- private final OperationsHierarchy hierarchy;
+ private class ProgressLoggerImpl implements ProgressLogger {
+ private final OperationIdentifier id;
private final String category;
private final ProgressListener listener;
private final TimeProvider timeProvider;
+ private ProgressLoggerImpl parent;
private String description;
private String shortDescription;
private String loggingHeader;
private State state = State.idle;
- public ProgressLoggerImpl(OperationsHierarchy hierarchy, String category, ProgressListener listener, TimeProvider timeProvider) {
- this.hierarchy = hierarchy;
+ public ProgressLoggerImpl(ProgressLoggerImpl parent, long id, String category, ProgressListener listener, TimeProvider timeProvider) {
+ this.parent = parent;
+ this.id = new OperationIdentifier(id);
this.category = category;
this.listener = listener;
this.timeProvider = timeProvider;
@@ -73,27 +79,30 @@ public class DefaultProgressLoggerFactory implements ProgressLoggerFactory {
return description;
}
- public void setDescription(String description) {
+ public ProgressLogger setDescription(String description) {
assertCanConfigure();
this.description = description;
+ return this;
}
public String getShortDescription() {
return shortDescription;
}
- public void setShortDescription(String shortDescription) {
+ public ProgressLogger setShortDescription(String shortDescription) {
assertCanConfigure();
this.shortDescription = shortDescription;
+ return this;
}
public String getLoggingHeader() {
return loggingHeader;
}
- public void setLoggingHeader(String loggingHeader) {
+ public ProgressLogger setLoggingHeader(String loggingHeader) {
assertCanConfigure();
this.loggingHeader = loggingHeader;
+ return this;
}
public ProgressLogger start(String description, String shortDescription) {
@@ -116,14 +125,18 @@ public class DefaultProgressLoggerFactory implements ProgressLoggerFactory {
}
assertNotCompleted();
state = State.started;
- OperationIdentifier id = hierarchy.start();
- listener.started(new ProgressStartEvent(id, timeProvider.getCurrentTime(), category, description, shortDescription, loggingHeader, toStatus(status)));
+ if (parent == null) {
+ parent = current.get();
+ } else {
+ parent.assertRunning();
+ }
+ current.set(this);
+ listener.started(new ProgressStartEvent(id, parent == null ? null : parent.id, timeProvider.getCurrentTime(), category, description, shortDescription, loggingHeader, toStatus(status)));
}
public void progress(String status) {
- assertStarted();
- assertNotCompleted();
- listener.progress(new ProgressEvent(hierarchy.currentOperationId(), timeProvider.getCurrentTime(), category, toStatus(status)));
+ assertRunning();
+ listener.progress(new ProgressEvent(id, timeProvider.getCurrentTime(), category, toStatus(status)));
}
public void completed() {
@@ -131,15 +144,10 @@ public class DefaultProgressLoggerFactory implements ProgressLoggerFactory {
}
public void completed(String status) {
- assertStarted();
- assertNotCompleted();
+ assertRunning();
state = State.completed;
- listener.completed(new ProgressCompleteEvent(hierarchy.completeCurrentOperation(),
- timeProvider.getCurrentTime(), category, description, toStatus(status)));
- }
-
- public OperationIdentifier currentOperationId() {
- return hierarchy.currentOperationId();
+ current.set(parent);
+ listener.completed(new ProgressCompleteEvent(id, timeProvider.getCurrentTime(), category, description, toStatus(status)));
}
private String toStatus(String status) {
@@ -147,14 +155,14 @@ public class DefaultProgressLoggerFactory implements ProgressLoggerFactory {
}
private void assertNotCompleted() {
- if (state == ProgressLoggerImpl.State.completed) {
+ if (state == State.completed) {
throw new IllegalStateException("This operation has completed.");
}
}
- private void assertStarted() {
- if (state == ProgressLoggerImpl.State.idle) {
- throw new IllegalStateException("This operation has not been started.");
+ private void assertRunning() {
+ if (state != State.started) {
+ throw new IllegalStateException("This operation is not running.");
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/LogEvent.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/LogEvent.java
index e0adc2f..6593b6e 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/LogEvent.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/LogEvent.java
@@ -15,6 +15,7 @@
*/
package org.gradle.logging.internal;
+import org.gradle.api.Nullable;
import org.gradle.api.logging.LogLevel;
import org.gradle.logging.StyledTextOutput;
@@ -22,7 +23,7 @@ public class LogEvent extends RenderableOutputEvent {
private final String message;
private final Throwable throwable;
- public LogEvent(long timestamp, String category, LogLevel logLevel, String message, Throwable throwable) {
+ public LogEvent(long timestamp, String category, LogLevel logLevel, String message, @Nullable Throwable throwable) {
super(timestamp, category, logLevel);
this.message = message;
this.throwable = throwable;
@@ -32,6 +33,7 @@ public class LogEvent extends RenderableOutputEvent {
return message;
}
+ @Nullable
public Throwable getThrowable() {
return throwable;
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/OutputEvent.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/OutputEvent.java
index f5af9ca..a44d953 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/OutputEvent.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/OutputEvent.java
@@ -18,12 +18,10 @@ package org.gradle.logging.internal;
import org.gradle.api.Nullable;
import org.gradle.api.logging.LogLevel;
-import java.io.Serializable;
-
/**
* Represents some event which may generate output. All implementations are immutable.
*/
-public abstract class OutputEvent implements Serializable {
+public abstract class OutputEvent {
/**
* Returns the log level for this event.
*/
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressEvent.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressEvent.java
index e7f2f95..2b72199 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressEvent.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressEvent.java
@@ -20,7 +20,7 @@ import org.gradle.internal.progress.OperationIdentifier;
public class ProgressEvent extends CategorisedOutputEvent {
private final String status;
- private OperationIdentifier operationId;
+ private final OperationIdentifier operationId;
public ProgressEvent(OperationIdentifier operationId, long timestamp, String category, String status) {
super(timestamp, category, LogLevel.LIFECYCLE);
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressLogEventGenerator.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressLogEventGenerator.java
index 9d38d75..fa71eb2 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressLogEventGenerator.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressLogEventGenerator.java
@@ -20,6 +20,7 @@ import org.gradle.internal.SystemProperties;
import org.gradle.internal.progress.OperationIdentifier;
import org.gradle.util.GUtil;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -63,7 +64,19 @@ public class ProgressLogEventGenerator implements OutputEventListener {
private void onComplete(ProgressCompleteEvent progressCompleteEvent) {
assert !operations.isEmpty();
Operation operation = operations.remove(progressCompleteEvent.getOperationId());
- assert operation!=null;
+
+ // Didn't find an operation with that id in the map
+ if (operation == null) {
+ // Remove last operation and complete that
+ Iterator<Map.Entry<OperationIdentifier, Operation>> entryIterator = operations.entrySet().iterator();
+ Map.Entry<OperationIdentifier, Operation> lastEntry = entryIterator.next();
+ while (entryIterator.hasNext()) {
+ lastEntry = entryIterator.next();
+ }
+ entryIterator.remove();
+ operation = lastEntry.getValue();
+ // TODO: Do we actually run into this case anymore?
+ }
completeOperation(progressCompleteEvent, operation);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressStartEvent.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressStartEvent.java
index bc4db32..28888ff 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressStartEvent.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/ProgressStartEvent.java
@@ -15,33 +15,43 @@
*/
package org.gradle.logging.internal;
+import org.gradle.api.Nullable;
import org.gradle.api.logging.LogLevel;
import org.gradle.internal.progress.OperationIdentifier;
public class ProgressStartEvent extends CategorisedOutputEvent {
- private OperationIdentifier operationId;
+ private final OperationIdentifier operationId;
+ private final OperationIdentifier parentId;
private final String description;
private final String shortDescription;
private final String loggingHeader;
private final String status;
- public ProgressStartEvent(OperationIdentifier operationId, long timestamp, String category, String description, String shortDescription, String loggingHeader, String status) {
+ public ProgressStartEvent(OperationIdentifier operationId, @Nullable OperationIdentifier parentId, long timestamp, String category, String description, @Nullable String shortDescription, @Nullable String loggingHeader, String status) {
super(timestamp, category, LogLevel.LIFECYCLE);
this.operationId = operationId;
+ this.parentId = parentId;
this.description = description;
this.shortDescription = shortDescription;
this.loggingHeader = loggingHeader;
this.status = status;
}
+ @Nullable
+ public OperationIdentifier getParentId() {
+ return parentId;
+ }
+
public String getDescription() {
return description;
}
+ @Nullable
public String getShortDescription() {
return shortDescription;
}
+ @Nullable
public String getLoggingHeader() {
return loggingHeader;
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/StyledTextOutputEvent.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/StyledTextOutputEvent.java
index 14b6998..9eb3b10 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/StyledTextOutputEvent.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/StyledTextOutputEvent.java
@@ -79,6 +79,10 @@ public class StyledTextOutputEvent extends RenderableOutputEvent {
return new StyledTextOutputEvent(getTimestamp(), getCategory(), logLevel, spans);
}
+ public List<Span> getSpans() {
+ return spans;
+ }
+
@Override
public void render(StyledTextOutput output) {
for (Span span : spans) {
@@ -100,5 +104,13 @@ public class StyledTextOutputEvent extends RenderableOutputEvent {
this.style = Normal;
this.text = text;
}
+
+ public StyledTextOutput.Style getStyle() {
+ return style;
+ }
+
+ public String getText() {
+ return text;
+ }
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/logging/internal/progress/ProgressOperations.java b/subprojects/core/src/main/groovy/org/gradle/logging/internal/progress/ProgressOperations.java
index 7eb4c3a..ad14e06 100644
--- a/subprojects/core/src/main/groovy/org/gradle/logging/internal/progress/ProgressOperations.java
+++ b/subprojects/core/src/main/groovy/org/gradle/logging/internal/progress/ProgressOperations.java
@@ -16,14 +16,17 @@
package org.gradle.logging.internal.progress;
+import org.gradle.api.Nullable;
+import org.gradle.internal.progress.OperationIdentifier;
+
import java.util.HashMap;
import java.util.Map;
public class ProgressOperations {
- private final Map<Long, ProgressOperation> operationsById = new HashMap<Long, ProgressOperation>();
+ private final Map<OperationIdentifier, ProgressOperation> operationsById = new HashMap<OperationIdentifier, ProgressOperation>();
- public ProgressOperation start(String description, String status, long operationId, Long parentOperationId) {
+ public ProgressOperation start(String description, String status, OperationIdentifier operationId, @Nullable OperationIdentifier parentOperationId) {
ProgressOperation parent = null;
if (parentOperationId != null) {
parent = operationsById.get(parentOperationId);
@@ -33,7 +36,7 @@ public class ProgressOperations {
return operation;
}
- public ProgressOperation progress(String description, long operationId) {
+ public ProgressOperation progress(String description, OperationIdentifier operationId) {
ProgressOperation op = operationsById.get(operationId);
if (op == null) {
throw new IllegalStateException("Received progress event for an unknown operation (id: " + operationId + ")");
@@ -42,7 +45,7 @@ public class ProgressOperations {
return op;
}
- public ProgressOperation complete(long operationId) {
+ public ProgressOperation complete(OperationIdentifier operationId) {
ProgressOperation op = operationsById.remove(operationId);
if (op == null) {
throw new IllegalStateException("Received complete event for an unknown operation (id: " + operationId + ")");
diff --git a/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/BridgedCollections.java b/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/BridgedCollections.java
index afdc771..6bdf5ed 100644
--- a/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/BridgedCollections.java
+++ b/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/BridgedCollections.java
@@ -20,6 +20,7 @@ import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectCollection;
import org.gradle.api.Namer;
import org.gradle.api.Transformer;
+import org.gradle.api.internal.plugins.DslObject;
import org.gradle.internal.BiAction;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.StandardDescriptorFactory;
@@ -64,10 +65,9 @@ public abstract class BridgedCollections {
}
if (!containerNode.hasLink(name)) {
- ModelType<I> itemType = ModelType.typeOf(item);
ModelCreator itemCreator = ModelCreators
.unmanagedInstanceOf(
- ModelReference.of(containerPath.child(name), itemType),
+ ModelReference.of(containerPath.child(name), new DslObject(item).getDeclaredType()),
new ExtractFromParentContainer<I, C>(name, containerType)
)
.descriptor(itemDescriptorGenerator.transform(name))
diff --git a/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/PolymorphicModelMapProjection.java b/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/PolymorphicModelMapProjection.java
index 83026eb..82bc703 100644
--- a/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/PolymorphicModelMapProjection.java
+++ b/subprojects/core/src/main/groovy/org/gradle/model/collection/internal/PolymorphicModelMapProjection.java
@@ -17,7 +17,7 @@
package org.gradle.model.collection.internal;
import org.gradle.api.internal.PolymorphicNamedEntityInstantiator;
-import org.gradle.model.internal.core.ChildNodeCreatorStrategy;
+import org.gradle.model.internal.core.ChildNodeInitializerStrategy;
import org.gradle.model.internal.core.ModelProjection;
import org.gradle.model.internal.core.MutableModelNode;
import org.gradle.model.internal.type.ModelType;
@@ -26,15 +26,15 @@ import java.util.Collection;
public class PolymorphicModelMapProjection<T> extends ModelMapModelProjection<T> {
- public static <T> ModelProjection ofEager(ModelType<T> itemType, ChildNodeCreatorStrategy<? super T> creatorStrategy) {
+ public static <T> ModelProjection ofEager(ModelType<T> itemType, ChildNodeInitializerStrategy<? super T> creatorStrategy) {
return new PolymorphicModelMapProjection<T>(itemType, true, creatorStrategy);
}
- public static <T> ModelProjection of(ModelType<T> itemType, ChildNodeCreatorStrategy<? super T> creatorStrategy) {
+ public static <T> ModelProjection of(ModelType<T> itemType, ChildNodeInitializerStrategy<? super T> creatorStrategy) {
return new PolymorphicModelMapProjection<T>(itemType, false, creatorStrategy);
}
- private PolymorphicModelMapProjection(ModelType<T> baseItemType, boolean eager, ChildNodeCreatorStrategy<? super T> creatorStrategy) {
+ private PolymorphicModelMapProjection(ModelType<T> baseItemType, boolean eager, ChildNodeInitializerStrategy<? super T> creatorStrategy) {
super(baseItemType, eager, false, creatorStrategy);
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/plugin/use/internal/PluginRequestsSerializer.java b/subprojects/core/src/main/groovy/org/gradle/plugin/use/internal/PluginRequestsSerializer.java
index e76b531..94e5397 100644
--- a/subprojects/core/src/main/groovy/org/gradle/plugin/use/internal/PluginRequestsSerializer.java
+++ b/subprojects/core/src/main/groovy/org/gradle/plugin/use/internal/PluginRequestsSerializer.java
@@ -25,9 +25,6 @@ import org.gradle.plugin.internal.PluginId;
import java.util.List;
public class PluginRequestsSerializer implements Serializer<PluginRequests> {
-
- public static final Serializer<PluginRequests> INSTANCE = new PluginRequestsSerializer();
-
@Override
public PluginRequests read(Decoder decoder) throws Exception {
int requestCount = decoder.readInt();
diff --git a/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultExecHandle.java b/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultExecHandle.java
index 13340c7..541f671 100755
--- a/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultExecHandle.java
+++ b/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultExecHandle.java
@@ -262,6 +262,7 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
throw new IllegalStateException(String.format("Cannot abort process '%s' because it is not in started or detached state", displayName));
}
this.execHandleRunner.abortProcess();
+ this.waitForFinish();
} finally {
lock.unlock();
}
@@ -380,4 +381,4 @@ public class DefaultExecHandle implements ExecHandle, ProcessSettings {
return "{exitValue=" + exitValue + ", failure=" + failure + "}";
}
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultProcessForkOptions.java b/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultProcessForkOptions.java
index a187be8..370bf20 100755
--- a/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultProcessForkOptions.java
+++ b/subprojects/core/src/main/groovy/org/gradle/process/internal/DefaultProcessForkOptions.java
@@ -72,7 +72,7 @@ public class DefaultProcessForkOptions implements ProcessForkOptions {
public Map<String, String> getActualEnvironment() {
Map<String, String> actual = new HashMap<String, String>();
for (Map.Entry<String, Object> entry : environment.entrySet()) {
- actual.put(entry.getKey(), String.valueOf(entry.getValue().toString()));
+ actual.put(entry.getKey(), String.valueOf(entry.getValue()));
}
return actual;
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/process/internal/ExecHandle.java b/subprojects/core/src/main/groovy/org/gradle/process/internal/ExecHandle.java
index 5c58856..e7697c8 100644
--- a/subprojects/core/src/main/groovy/org/gradle/process/internal/ExecHandle.java
+++ b/subprojects/core/src/main/groovy/org/gradle/process/internal/ExecHandle.java
@@ -41,6 +41,9 @@ public interface ExecHandle {
ExecHandleState getState();
+ /**
+ * Aborts the process, blocking until the process has exited.
+ */
void abort();
/**
diff --git a/subprojects/core/src/main/groovy/org/gradle/process/internal/streams/ExecOutputHandleRunner.java b/subprojects/core/src/main/groovy/org/gradle/process/internal/streams/ExecOutputHandleRunner.java
index b4c7be8..ae36e3a 100644
--- a/subprojects/core/src/main/groovy/org/gradle/process/internal/streams/ExecOutputHandleRunner.java
+++ b/subprojects/core/src/main/groovy/org/gradle/process/internal/streams/ExecOutputHandleRunner.java
@@ -31,15 +31,21 @@ public class ExecOutputHandleRunner implements Runnable {
private final String displayName;
private final InputStream inputStream;
private final OutputStream outputStream;
+ private final int bufferSize;
public ExecOutputHandleRunner(String displayName, InputStream inputStream, OutputStream outputStream) {
+ this(displayName, inputStream, outputStream, 2048);
+ }
+
+ ExecOutputHandleRunner(String displayName, InputStream inputStream, OutputStream outputStream, int bufferSize) {
this.displayName = displayName;
this.inputStream = inputStream;
this.outputStream = outputStream;
+ this.bufferSize = bufferSize;
}
public void run() {
- byte[] buffer = new byte[2048];
+ byte[] buffer = new byte[bufferSize];
try {
while (true) {
int nread = inputStream.read(buffer);
diff --git a/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/ProjectBuilderImpl.java b/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/ProjectBuilderImpl.java
index c6ffe72..62fbfab 100644
--- a/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/ProjectBuilderImpl.java
+++ b/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/ProjectBuilderImpl.java
@@ -33,6 +33,7 @@ import org.gradle.initialization.DefaultProjectDescriptorRegistry;
import org.gradle.internal.nativeintegration.services.NativeServices;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.service.ServiceRegistryBuilder;
+import org.gradle.internal.service.scopes.BuildSessionScopeServices;
import org.gradle.internal.service.scopes.ServiceRegistryFactory;
import org.gradle.invocation.DefaultGradle;
import org.gradle.util.GFileUtils;
@@ -72,7 +73,8 @@ public class ProjectBuilderImpl {
NativeServices.initialize(userHomeDir);
- ServiceRegistry topLevelRegistry = new TestBuildScopeServices(getGlobalServices(), startParameter, homeDir);
+ ServiceRegistry buildSessionScopeServices = new BuildSessionScopeServices(getGlobalServices());
+ ServiceRegistry topLevelRegistry = new TestBuildScopeServices(buildSessionScopeServices, startParameter, homeDir);
GradleInternal gradle = CLASS_GENERATOR.newInstance(DefaultGradle.class, null, startParameter, topLevelRegistry.get(ServiceRegistryFactory.class));
DefaultProjectDescriptor projectDescriptor = new DefaultProjectDescriptor(null, name, projectDir, new DefaultProjectDescriptorRegistry(),
diff --git a/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/TestBuildScopeServices.java b/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/TestBuildScopeServices.java
index dc5aad9..47dfd8f 100644
--- a/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/TestBuildScopeServices.java
+++ b/subprojects/core/src/main/groovy/org/gradle/testfixtures/internal/TestBuildScopeServices.java
@@ -17,6 +17,7 @@ package org.gradle.testfixtures.internal;
import org.gradle.StartParameter;
import org.gradle.api.internal.GradleDistributionLocator;
+import org.gradle.api.internal.classpath.DefaultGradleDistributionLocator;
import org.gradle.configuration.GradleLauncherMetaData;
import org.gradle.initialization.BuildCancellationToken;
import org.gradle.initialization.BuildClientMetaData;
@@ -43,10 +44,6 @@ public class TestBuildScopeServices extends BuildScopeServices {
}
protected GradleDistributionLocator createGradleDistributionLocator() {
- return new GradleDistributionLocator() {
- public File getGradleHome() {
- return homeDir;
- }
- };
+ return new DefaultGradleDistributionLocator(homeDir);
}
}
diff --git a/subprojects/core/src/main/groovy/org/gradle/util/AvailablePortFinder.java b/subprojects/core/src/main/groovy/org/gradle/util/AvailablePortFinder.java
index 677f86f..2ac31b3 100644
--- a/subprojects/core/src/main/groovy/org/gradle/util/AvailablePortFinder.java
+++ b/subprojects/core/src/main/groovy/org/gradle/util/AvailablePortFinder.java
@@ -33,6 +33,7 @@ import java.util.concurrent.locks.ReentrantLock;
* class, there is always a risk that someone else grabs the port between the time it is returned from <tt>getNextAvailable()</tt> and the time the socket is created.
* @see <a href="http://www.iana.org/assignments/port-numbers">IANA.org</a>
*/
+ at Deprecated
@ThreadSafe
public class AvailablePortFinder {
private static final int MIN_PRIVATE_PORT = 49152;
diff --git a/subprojects/core/src/main/groovy/org/gradle/util/GUtil.java b/subprojects/core/src/main/groovy/org/gradle/util/GUtil.java
index b91082d..170f474 100644
--- a/subprojects/core/src/main/groovy/org/gradle/util/GUtil.java
+++ b/subprojects/core/src/main/groovy/org/gradle/util/GUtil.java
@@ -31,7 +31,7 @@ import static java.util.Collections.emptyList;
public class GUtil {
private static final Pattern WORD_SEPARATOR = Pattern.compile("\\W+");
- private static final Pattern UPPER_LOWER = Pattern.compile("(\\p{Upper}*)(\\p{Lower}*)");
+ private static final Pattern UPPER_LOWER = Pattern.compile("(?m)([A-Z]*)([a-z0-9]*)");
public static <T extends Collection> T flatten(Object[] elements, T addTo, boolean flattenMaps) {
return flatten(asList(elements), addTo, flattenMaps);
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/DependencyClassPathProviderTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/DependencyClassPathProviderTest.groovy
index 1dc69a3..9c522ac 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/DependencyClassPathProviderTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/DependencyClassPathProviderTest.groovy
@@ -17,9 +17,9 @@ package org.gradle.api.internal
import org.gradle.api.internal.classpath.Module
import org.gradle.api.internal.classpath.ModuleRegistry
-import spock.lang.Specification
import org.gradle.api.internal.classpath.PluginModuleRegistry
import org.gradle.internal.classpath.DefaultClassPath
+import spock.lang.Specification
class DependencyClassPathProviderTest extends Specification {
final ModuleRegistry moduleRegistry = Mock()
@@ -41,6 +41,18 @@ class DependencyClassPathProviderTest extends Specification {
1 * pluginModuleRegistry.getPluginModules() >> ([module("plugin1"), module("plugin2")] as LinkedHashSet)
}
+ def "uses modules to determine Gradle test-kit classpath"() {
+ when:
+ def classpath = provider.findClassPath("GRADLE_TEST_KIT")
+
+ then:
+ classpath.asFiles.collect{it.name} == ["gradle-test-kit-runtime"]
+
+ and:
+ 1 * moduleRegistry.getModule("gradle-test-kit") >> module("gradle-test-kit")
+ 0 * pluginModuleRegistry.getPluginModules()
+ }
+
def module(String name, Module ... requiredModules) {
Module module = Mock()
_ * module.classpath >> new DefaultClassPath(new File("$name-runtime"))
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/DocumentationRegistryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/DocumentationRegistryTest.groovy
index 9c45b08..1b1c4ed 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/DocumentationRegistryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/DocumentationRegistryTest.groovy
@@ -28,16 +28,16 @@ class DocumentationRegistryTest extends Specification {
def "points users at the gradle docs web site"() {
expect:
- registry.getDocumentationFor('gradle_daemon') == "http://gradle.org/docs/${gradleVersion.version}/userguide/gradle_daemon.html"
+ registry.getDocumentationFor('gradle_daemon') == "https://docs.gradle.org/${gradleVersion.version}/userguide/gradle_daemon.html"
}
def "points users at the gradle docs web site with section"() {
expect:
- registry.getDocumentationFor('gradle_daemon', 'reusing_daemons') == "http://gradle.org/docs/${gradleVersion.version}/userguide/gradle_daemon.html#reusing_daemons"
+ registry.getDocumentationFor('gradle_daemon', 'reusing_daemons') == "https://docs.gradle.org/${gradleVersion.version}/userguide/gradle_daemon.html#reusing_daemons"
}
def "points users at the gradle dsl web site"() {
expect:
- registry.getDslRefForProperty(org.gradle.api.Project, 'name') == "http://gradle.org/docs/${gradleVersion.version}/dsl/org.gradle.api.Project.html#org.gradle.api.Project:name"
+ registry.getDslRefForProperty(org.gradle.api.Project, 'name') == "https://docs.gradle.org/${gradleVersion.version}/dsl/org.gradle.api.Project.html#org.gradle.api.Project:name"
}
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy
index 41709ef..b47d49f 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy
@@ -243,6 +243,19 @@ class DefaultDependencyHandlerTest extends Specification {
1 * dependencyFactory.createDependency(DependencyFactory.ClassPathNotation.GRADLE_API) >> dependency
}
+ void "creates Gradle test-kit dependency"() {
+ Dependency dependency = Mock()
+
+ when:
+ def result = dependencyHandler.gradleTestKit()
+
+ then:
+ result == dependency
+
+ and:
+ 1 * dependencyFactory.createDependency(DependencyFactory.ClassPathNotation.GRADLE_TEST_KIT) >> dependency
+ }
+
void "creates local groovy dependency"() {
Dependency dependency = Mock()
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/classpath/DefaultGradleDistributionLocatorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/classpath/DefaultGradleDistributionLocatorTest.groovy
new file mode 100644
index 0000000..4007d9a
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/classpath/DefaultGradleDistributionLocatorTest.groovy
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.classpath
+
+import org.gradle.internal.concurrent.CompositeStoppable
+import org.gradle.test.fixtures.file.TestFile
+import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import org.junit.Rule
+import org.objectweb.asm.ClassWriter
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.tree.ClassNode
+import spock.lang.Specification
+import spock.lang.Unroll
+
+ at Requires(TestPrecondition.JDK7_OR_LATER)
+// so we can close the classloaders and allow files to be cleaned up
+class DefaultGradleDistributionLocatorTest extends Specification {
+ @Rule
+ final TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()
+ List<Closeable> loaders = []
+
+ TestFile distDir
+
+ def setup() {
+ distDir = tmpDir.createDir("dist")
+ distDir.createDir("lib")
+ distDir.createDir("lib/plugins")
+ }
+
+ def cleanup() {
+ CompositeStoppable.stoppable(loaders).stop()
+ }
+
+ @Unroll
+ def "determines Gradle home by class bundled in JAR located in valid distribution subdirectory '#jarDirectory'"() {
+ given:
+ TestFile jar = distDir.file("$jarDirectory/mydep-1.2.jar")
+ createJarFile(jar)
+
+ when:
+ Class clazz = loadClassFromJar(jar)
+ def gradleDistributionLocator = new DefaultGradleDistributionLocator(clazz)
+
+ then:
+ gradleDistributionLocator.gradleHome == distDir
+ gradleDistributionLocator.libDirs == [new File(distDir, 'lib'), new File(distDir, 'lib/plugins')]
+
+ where:
+ jarDirectory << ['lib', 'lib/plugins']
+ }
+
+ @Unroll
+ def "determines Gradle home by class bundled in JAR located in invalid distribution directory '#jarDirectory'"() {
+ given:
+ TestFile jar = distDir.file("$jarDirectory/mydep-1.2.jar")
+ createJarFile(jar)
+
+ when:
+ Class clazz = loadClassFromJar(jar)
+ def gradleDistributionLocator = new DefaultGradleDistributionLocator(clazz)
+
+ then:
+ !gradleDistributionLocator.gradleHome
+ gradleDistributionLocator.libDirs == []
+
+ where:
+ jarDirectory << ['other', 'other/plugins']
+ }
+
+ private void createJarFile(TestFile jar) {
+ TestFile contents = tmpDir.createDir('contents')
+ TestFile classFile = contents.createFile('org/gradle/MyClass.class')
+
+ ClassNode classNode = new ClassNode()
+ classNode.version = Opcodes.V1_6
+ classNode.access = Opcodes.ACC_PUBLIC
+ classNode.name = 'org/gradle/MyClass'
+ classNode.superName = 'java/lang/Object'
+
+ ClassWriter cw = new ClassWriter(0)
+ classNode.accept(cw)
+
+ classFile.withDataOutputStream {
+ it.write(cw.toByteArray())
+ }
+
+ contents.zipTo(jar)
+ }
+
+ private Class loadClassFromJar(TestFile jar) {
+ // This is to prevent the jar file being held open
+ URL url = new URL("jar:file://valid_jar_url_syntax.jar!/")
+ URLConnection urlConnection = url.openConnection()
+ def original = urlConnection.getDefaultUseCaches()
+ urlConnection.setDefaultUseCaches(false)
+
+ try {
+ URL[] urls = [new URL("jar:${jar.toURI().toURL()}!/")] as URL[]
+ URLClassLoader ucl = new URLClassLoader(urls)
+ if (ucl instanceof Closeable) {
+ loaders << ucl
+ }
+ Class.forName('org.gradle.MyClass', true, ucl)
+ } finally {
+ urlConnection.setDefaultUseCaches(original)
+ }
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistryTest.groovy
index 1c865b5..e666f0d 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/classpath/DefaultModuleRegistryTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.api.internal.classpath
+import org.gradle.internal.classpath.DefaultClassPath
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.junit.Rule
@@ -35,7 +36,7 @@ class DefaultModuleRegistryTest extends Specification {
distDir.createDir("lib/plugins/sonar")
runtimeDep = distDir.createZip("lib/dep-1.2.jar")
- resourcesDir = tmpDir.createDir("classes")
+ resourcesDir = tmpDir.createDir("some-module/build/resources/main")
def properties = new Properties()
properties.runtime = 'dep-1.2.jar'
properties.projects = ''
@@ -45,7 +46,7 @@ class DefaultModuleRegistryTest extends Specification {
resourcesDir.zipTo(jarFile)
}
- def "uses manifest from jar in distribution image"() {
+ def "locates module using jar in distribution image"() {
given:
def cl = new URLClassLoader([] as URL[])
def registry = new DefaultModuleRegistry(cl, distDir)
@@ -56,50 +57,60 @@ class DefaultModuleRegistryTest extends Specification {
module.runtimeClasspath.asFiles == [runtimeDep]
}
- def "uses manifest from classpath when run from IDEA"() {
+ def "locates module using jar from runtime ClassLoader"() {
+ given:
+ def cl = new URLClassLoader([jarFile, runtimeDep].collect { it.toURI().toURL() } as URL[])
+ def registry = new DefaultModuleRegistry(cl, null as File)
+
+ expect:
+ def module = registry.getModule("gradle-some-module")
+ module.implementationClasspath.asFiles == [jarFile]
+ module.runtimeClasspath.asFiles == [runtimeDep]
+ }
+
+ def "locates module using manifest from runtime ClassLoader when run from IDEA"() {
given:
def classesDir = tmpDir.createDir("out/production/someModule")
def staticResourcesDir = tmpDir.createDir("some-module/src/main/resources")
def ignoredDir = tmpDir.createDir("ignore-me-out/production/someModule")
def cl = new URLClassLoader([ignoredDir, classesDir, resourcesDir, staticResourcesDir, runtimeDep].collect { it.toURI().toURL() } as URL[])
- def registry = new DefaultModuleRegistry(cl, null)
+ def registry = new DefaultModuleRegistry(cl, null as File)
expect:
def module = registry.getModule("gradle-some-module")
- module.implementationClasspath.asFiles == [classesDir, staticResourcesDir, resourcesDir]
+ module.implementationClasspath.asFiles == [classesDir, resourcesDir, staticResourcesDir]
module.runtimeClasspath.asFiles == [runtimeDep]
}
- def "uses manifest from classpath when run from Eclipse"() {
+ def "locates module using manifest from runtime ClassLoader when run from Eclipse"() {
given:
def classesDir = tmpDir.createDir("some-module/bin")
def staticResourcesDir = tmpDir.createDir("some-module/src/main/resources")
def cl = new URLClassLoader([classesDir, resourcesDir, staticResourcesDir, runtimeDep].collect { it.toURI().toURL() } as URL[])
- def registry = new DefaultModuleRegistry(cl, null)
+ def registry = new DefaultModuleRegistry(cl, null as File)
expect:
def module = registry.getModule("gradle-some-module")
- module.implementationClasspath.asFiles == [classesDir, staticResourcesDir, resourcesDir]
+ module.implementationClasspath.asFiles == [classesDir, resourcesDir, staticResourcesDir]
module.runtimeClasspath.asFiles == [runtimeDep]
}
- def "uses manifest from classpath when run from build"() {
+ def "locates module using manifest from runtime ClassLoader when run from build"() {
given:
def classesDir = tmpDir.createDir("some-module/build/classes/main")
- def staticResourcesDir = tmpDir.createDir("some-module/build/resources/main")
+ def staticResourcesDir = tmpDir.createDir("some-module/src/main/resources")
def cl = new URLClassLoader([classesDir, resourcesDir, staticResourcesDir, runtimeDep].collect { it.toURI().toURL() } as URL[])
- def registry = new DefaultModuleRegistry(cl, null)
+ def registry = new DefaultModuleRegistry(cl, null as File)
expect:
def module = registry.getModule("gradle-some-module")
- module.implementationClasspath.asFiles == [classesDir, staticResourcesDir, resourcesDir]
+ module.implementationClasspath.asFiles == [classesDir, resourcesDir, staticResourcesDir]
module.runtimeClasspath.asFiles == [runtimeDep]
}
- def "uses manifest from a jar on the classpath"() {
+ def "locates module using jar from additional classpath"() {
given:
- def cl = new URLClassLoader([jarFile, runtimeDep].collect { it.toURI().toURL() } as URL[])
- def registry = new DefaultModuleRegistry(cl, distDir)
+ def registry = new DefaultModuleRegistry(new DefaultClassPath([jarFile, runtimeDep]))
expect:
def module = registry.getModule("gradle-some-module")
@@ -107,6 +118,40 @@ class DefaultModuleRegistryTest extends Specification {
module.runtimeClasspath.asFiles == [runtimeDep]
}
+ def "locates module using manifest from additional classpath when run from IDEA"() {
+ given:
+ def classesDir = tmpDir.createDir("out/production/someModule")
+ def staticResourcesDir = tmpDir.createDir("some-module/src/main/resources")
+ def ignoredDir = tmpDir.createDir("ignore-me-out/production/someModule")
+ def registry = new DefaultModuleRegistry(new DefaultClassPath([ignoredDir, classesDir, resourcesDir, staticResourcesDir, runtimeDep]))
+
+ expect:
+ def module = registry.getModule("gradle-some-module")
+ module.implementationClasspath.asFiles == [classesDir, resourcesDir, staticResourcesDir]
+ module.runtimeClasspath.asFiles == [runtimeDep]
+ }
+
+ def "requires no additional module classpath when run from distribution"() {
+ given:
+ def cl = new URLClassLoader([] as URL[])
+ def registry = new DefaultModuleRegistry(cl, distDir)
+
+ expect:
+ registry.additionalClassPath.empty
+ }
+
+ def "requires additional module classpath when no distribution available"() {
+ given:
+ def classesDir = tmpDir.createDir("out/production/someModule")
+ def staticResourcesDir = tmpDir.createDir("some-module/src/main/resources")
+ def ignoredDir = tmpDir.createDir("ignore-me-out/production/someModule")
+ def cl = new URLClassLoader([ignoredDir, classesDir, resourcesDir, staticResourcesDir, runtimeDep].collect { it.toURI().toURL() } as URL[])
+ def registry = new DefaultModuleRegistry(cl, null as File)
+
+ expect:
+ registry.additionalClassPath.asFiles.containsAll([classesDir, staticResourcesDir, resourcesDir])
+ }
+
def "handles empty classpaths in manifest"() {
given:
def properties = new Properties()
@@ -115,7 +160,7 @@ class DefaultModuleRegistryTest extends Specification {
resourcesDir.file("gradle-some-module-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
def cl = new URLClassLoader([resourcesDir, runtimeDep].collect { it.toURI().toURL() } as URL[])
- def registry = new DefaultModuleRegistry(cl, null)
+ def registry = new DefaultModuleRegistry(cl, null as File)
expect:
def module = registry.getModule("gradle-some-module")
@@ -127,13 +172,15 @@ class DefaultModuleRegistryTest extends Specification {
given:
def properties = new Properties()
properties.projects = 'gradle-module-2'
- resourcesDir.file("gradle-some-module-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
+ def module1Dir = tmpDir.createDir("some-module/build/resources/main")
+ module1Dir.file("gradle-some-module-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
properties = new Properties()
- resourcesDir.file("gradle-module-2-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
+ def module2Dir = tmpDir.createDir("module-2/build/resources/main")
+ module2Dir.file("gradle-module-2-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
- def cl = new URLClassLoader([resourcesDir].collect { it.toURI().toURL() } as URL[])
- def registry = new DefaultModuleRegistry(cl, null)
+ def cl = new URLClassLoader([module1Dir, module2Dir].collect { it.toURI().toURL() } as URL[])
+ def registry = new DefaultModuleRegistry(cl, null as File)
expect:
def module = registry.getModule("gradle-some-module")
@@ -144,18 +191,21 @@ class DefaultModuleRegistryTest extends Specification {
given:
def properties = new Properties()
properties.projects = 'gradle-module-2'
- resourcesDir.file("gradle-some-module-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
+ def module1Dir = tmpDir.createDir("some-module/build/resources/main")
+ module1Dir.file("gradle-some-module-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
properties = new Properties()
properties.projects = 'gradle-module-3'
- resourcesDir.file("gradle-module-2-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
+ def module2Dir = tmpDir.createDir("module-2/build/resources/main")
+ module2Dir.file("gradle-module-2-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
properties = new Properties()
properties.projects = ''
- resourcesDir.file("gradle-module-3-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
+ def module3Dir = tmpDir.createDir("module-3/build/resources/main")
+ module3Dir.file("gradle-module-3-classpath.properties").withOutputStream { outstr -> properties.save(outstr, "header") }
- def cl = new URLClassLoader([resourcesDir].collect { it.toURI().toURL() } as URL[])
- def registry = new DefaultModuleRegistry(cl, null)
+ def cl = new URLClassLoader([module1Dir, module2Dir, module3Dir].collect { it.toURI().toURL() } as URL[])
+ def registry = new DefaultModuleRegistry(cl, null as File)
expect:
def module = registry.getModule("gradle-some-module")
@@ -165,14 +215,14 @@ class DefaultModuleRegistryTest extends Specification {
def "fails when classpath does not contain manifest resource"() {
given:
def cl = new URLClassLoader([] as URL[])
- def registry = new DefaultModuleRegistry(cl, null)
+ def registry = new DefaultModuleRegistry(cl, null as File)
when:
registry.getModule("gradle-some-module")
then:
UnknownModuleException e = thrown()
- e.message == "Cannot locate classpath manifest for module 'gradle-some-module' in classpath."
+ e.message == "Cannot locate manifest for module 'gradle-some-module' in classpath."
}
def "fails when classpath and distribution image do not contain manifest"() {
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/file/copy/LineFilterTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/file/copy/LineFilterTest.groovy
index 15423c1..bde9345 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/file/copy/LineFilterTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/file/copy/LineFilterTest.groovy
@@ -77,6 +77,22 @@ class LineFilterTest {
assertThat(filter.text, equalTo(lines("1 - one", "2 - two", "3 - three")))
}
+ @Test void testClosureReturningNull() {
+ def input = new StringReader("one\ntwo\nthree\n")
+ def lineCount = 1
+ def filter = new LineFilter(input, { lineCount++ % 2 == 0 ? null : it })
+
+ assertThat(filter.text, equalTo(lines("one", "three", "")))
+ }
+
+ @Test void testClosureAlwaysReturningNull() {
+ def input = new StringReader("one\ntwo\nthree\n")
+ def lineCount = 1
+ def filter = new LineFilter(input, { null })
+
+ assertThat(filter.text, equalTo(lines()))
+ }
+
private String lines(String ... lines) {
(lines as List).join(SystemProperties.instance.lineSeparator)
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerTest.groovy
index 975854c..ecce7d2 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/initialization/DefaultScriptHandlerTest.groovy
@@ -19,6 +19,7 @@ import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.artifacts.dsl.RepositoryHandler
+import org.gradle.api.internal.artifacts.DependencyResolutionServices
import org.gradle.groovy.scripts.ScriptSource
import org.gradle.util.ConfigureUtil
import spock.lang.Specification
@@ -29,11 +30,12 @@ class DefaultScriptHandlerTest extends Specification {
def configurationContainer = Mock(ConfigurationContainer)
def configuration = Mock(Configuration)
def scriptSource = Stub(ScriptSource)
+ def depMgmtServices = Mock(DependencyResolutionServices)
def baseClassLoader = new ClassLoader() {}
def classLoaderScope = Stub(ClassLoaderScope) {
getLocalClassLoader() >> baseClassLoader
}
- def handler = new DefaultScriptHandler(scriptSource, repositoryHandler, dependencyHandler, configurationContainer, classLoaderScope)
+ def handler = new DefaultScriptHandler(scriptSource, depMgmtServices, classLoaderScope)
def "adds classpath configuration when configuration container is queried"() {
when:
@@ -41,8 +43,10 @@ class DefaultScriptHandlerTest extends Specification {
handler.configurations
then:
+ 1 * depMgmtServices.configurationContainer >> configurationContainer
1 * configurationContainer.create('classpath') >> configuration
0 * configurationContainer._
+ 0 * depMgmtServices._
}
def "adds classpath configuration when dependencies container is queried"() {
@@ -51,11 +55,14 @@ class DefaultScriptHandlerTest extends Specification {
handler.dependencies
then:
+ 1 * depMgmtServices.configurationContainer >> configurationContainer
1 * configurationContainer.create('classpath') >> configuration
+ 1 * depMgmtServices.dependencyHandler >> dependencyHandler
0 * configurationContainer._
+ 0 * depMgmtServices._
}
- def "does not resolve classpath configuration if configuration container has not been queried"() {
+ def "does not resolve classpath configuration when configuration container has not been queried"() {
when:
def classpath = handler.scriptClassPath
@@ -66,7 +73,7 @@ class DefaultScriptHandlerTest extends Specification {
classpath.empty
}
- def "resolves classpath configuration if configuration container has been queried"() {
+ def "resolves classpath configuration when configuration container has been queried"() {
def file = new File("thing.jar")
def uri = file.toURI()
@@ -75,6 +82,7 @@ class DefaultScriptHandlerTest extends Specification {
def classpath = handler.scriptClassPath
then:
+ 1 * depMgmtServices.configurationContainer >> configurationContainer
1 * configurationContainer.create('classpath') >> configuration
1 * configuration.files >> [file]
@@ -91,6 +99,7 @@ class DefaultScriptHandlerTest extends Specification {
handler.repositories(configure)
then:
+ 1 * depMgmtServices.resolveRepositoryHandler >> repositoryHandler
1 * repositoryHandler.configure(configure) >> { ConfigureUtil.configure(configure, repositoryHandler, false) }
1 * repositoryHandler.mavenCentral()
}
@@ -102,6 +111,8 @@ class DefaultScriptHandlerTest extends Specification {
}
then:
+ 1 * depMgmtServices.dependencyHandler >> dependencyHandler
+ 1 * depMgmtServices.configurationContainer >> configurationContainer
1 * dependencyHandler.add('config', 'dep')
}
}
\ No newline at end of file
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationActionTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationActionTest.groovy
index 1fbd866..4b52e4f 100755
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationActionTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultObjectConfigurationActionTest.groovy
@@ -21,7 +21,6 @@ import org.gradle.api.internal.initialization.ScriptHandlerFactory
import org.gradle.api.internal.initialization.ScriptHandlerInternal
import org.gradle.configuration.ScriptPlugin
import org.gradle.configuration.ScriptPluginFactory
-import org.gradle.groovy.scripts.DefaultScript
import org.junit.Test
import spock.lang.Specification
@@ -50,7 +49,7 @@ class DefaultObjectConfigurationActionTest extends Specification {
1 * resolver.resolveUri('script') >> file
1 * parentCompileScope.createChild("script-$file") >> scriptCompileScope
1 * scriptHandlerFactory.create(_, scriptCompileScope) >> scriptHandler
- 1 * scriptPluginFactory.create(_, scriptHandler, scriptCompileScope, parentCompileScope, "buildscript", DefaultScript, false) >> configurer
+ 1 * scriptPluginFactory.create(_, scriptHandler, scriptCompileScope, parentCompileScope, false) >> configurer
when:
action.from('script')
@@ -66,7 +65,7 @@ class DefaultObjectConfigurationActionTest extends Specification {
Object target2 = new Object()
1 * resolver.resolveUri('script') >> file
1 * scriptHandlerFactory.create(_, scriptCompileScope) >> scriptHandler
- 1 * scriptPluginFactory.create(_, scriptHandler, scriptCompileScope, parentCompileScope, "buildscript", DefaultScript, false) >> configurer
+ 1 * scriptPluginFactory.create(_, scriptHandler, scriptCompileScope, parentCompileScope, false) >> configurer
1 * configurer.apply(target1)
1 * configurer.apply(target2)
1 * parentCompileScope.createChild("script-$file") >> scriptCompileScope
@@ -85,7 +84,7 @@ class DefaultObjectConfigurationActionTest extends Specification {
Object target2 = new Object()
1 * resolver.resolveUri('script') >> file
1 * scriptHandlerFactory.create(_, scriptCompileScope) >> scriptHandler
- 1 * scriptPluginFactory.create(_, scriptHandler, scriptCompileScope, parentCompileScope, "buildscript", DefaultScript, false) >> configurer
+ 1 * scriptPluginFactory.create(_, scriptHandler, scriptCompileScope, parentCompileScope, false) >> configurer
1 * configurer.apply(target1)
1 * configurer.apply(target2)
1 * parentCompileScope.createChild("script-$file") >> scriptCompileScope
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy
index e268e8b..e72a90b 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy
@@ -48,10 +48,10 @@ import org.gradle.groovy.scripts.ScriptSource
import org.gradle.initialization.ProjectAccessListener
import org.gradle.internal.Factory
import org.gradle.internal.reflect.Instantiator
+import org.gradle.internal.resource.StringResource
import org.gradle.internal.service.ServiceRegistry
import org.gradle.internal.service.scopes.ServiceRegistryFactory
import org.gradle.logging.LoggingManagerInternal
-import org.gradle.model.internal.core.ModelCreatorFactory
import org.gradle.model.internal.manage.schema.ModelSchemaStore
import org.gradle.model.internal.registry.ModelRegistry
import org.gradle.util.JUnit4GroovyMockery
@@ -119,10 +119,12 @@ class DefaultProjectTest {
rootDir = new File("/path/root").absoluteFile
testAntBuilder = new DefaultAntBuilder()
+
context.checking {
allowing(antBuilderFactoryMock).create(); will(returnValue(testAntBuilder))
allowing(script).getDisplayName(); will(returnValue('[build file]'))
allowing(script).getClassName(); will(returnValue('scriptClass'))
+ allowing(script).getResource(); will(returnValue(new StringResource("", "")))
allowing(scriptHandlerMock).getSourceFile(); will(returnValue(new File(rootDir, TEST_BUILD_FILE_NAME)))
}
@@ -179,11 +181,6 @@ class DefaultProjectTest {
allowing(serviceRegistryMock).get((Type) ModelSchemaStore); will(returnValue(modelSchemaStore))
allowing(serviceRegistryMock).get(ModelSchemaStore); will(returnValue(modelSchemaStore))
- ModelCreatorFactory modelCreatorFactory = context.mock(ModelCreatorFactory)
- ignoring(modelCreatorFactory)
- allowing(serviceRegistryMock).get((Type) ModelCreatorFactory); will(returnValue(modelCreatorFactory))
- allowing(serviceRegistryMock).get(ModelCreatorFactory); will(returnValue(modelCreatorFactory))
-
Object listener = context.mock(ProjectEvaluationListener)
ignoring(listener)
allowing(build).getProjectEvaluationBroadcaster();
@@ -334,10 +331,10 @@ class DefaultProjectTest {
testScript
}] as ProjectEvaluator
final ProjectEvaluator mockReader2 = [
- evaluate: { DefaultProject project, state ->
- mockReader2Finished = true
- testScript
- }] as ProjectEvaluator
+ evaluate: { DefaultProject project, state ->
+ mockReader2Finished = true
+ testScript
+ }] as ProjectEvaluator
project.projectEvaluator = mockReader1
child1.projectEvaluator = mockReader2
project.evaluate()
@@ -358,15 +355,15 @@ class DefaultProjectTest {
testScript
}] as ProjectEvaluator
final ProjectEvaluator mockReader2 = [
- evaluate: { DefaultProject project, state ->
- child1MockReaderFinished = true
- testScript
- }] as ProjectEvaluator
+ evaluate: { DefaultProject project, state ->
+ child1MockReaderFinished = true
+ testScript
+ }] as ProjectEvaluator
final ProjectEvaluator mockReader3 = [
- evaluate: { DefaultProject project, state ->
- child2MockReaderFinished = true
- testScript
- }] as ProjectEvaluator
+ evaluate: { DefaultProject project, state ->
+ child2MockReaderFinished = true
+ testScript
+ }] as ProjectEvaluator
project.projectEvaluator = mockReader1
child1.projectEvaluator = mockReader2
child2.projectEvaluator = mockReader3
@@ -443,7 +440,7 @@ class DefaultProjectTest {
project.unknownTask
}
- @Test(expected = MissingMethodException)
+ @Test(expected = groovy.lang.MissingMethodException)
void testMethodShortCutForTaskCallWithNonExistingTask() {
project.unknownTask([dependsOn: '/task2'])
}
@@ -759,14 +756,14 @@ def scriptMethod(Closure closure) {
String propValue = 'someValue'
if (configureMethod == 'configure') {
project."$configureMethod" projectsToCheck as java.util.List,
- {
- ext.testSubProp = propValue
- }
+ {
+ ext.testSubProp = propValue
+ }
} else {
project."$configureMethod"(
- {
- ext.testSubProp = propValue
- })
+ {
+ ext.testSubProp = propValue
+ })
}
projectsToCheck.each {
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/project/taskfactory/TaskFactoryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/project/taskfactory/TaskFactoryTest.groovy
index aff351c..ac2deb8 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/project/taskfactory/TaskFactoryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/project/taskfactory/TaskFactoryTest.groovy
@@ -15,7 +15,6 @@
*/
package org.gradle.api.internal.project.taskfactory
-
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.InvalidUserDataException
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/DefaultTaskContainerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/DefaultTaskContainerTest.groovy
index 71d1098..4660c4d 100644
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/DefaultTaskContainerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/DefaultTaskContainerTest.groovy
@@ -436,4 +436,4 @@ public class DefaultTaskContainerTest extends Specification {
}
interface CustomTask extends TaskInternal {}
-}
\ No newline at end of file
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/util/DefaultProcessForkOptionsTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/util/DefaultProcessForkOptionsTest.groovy
index dbb2569..f112389 100755
--- a/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/util/DefaultProcessForkOptionsTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/tasks/util/DefaultProcessForkOptionsTest.groovy
@@ -71,9 +71,9 @@ public class DefaultProcessForkOptionsTest {
@Test
public void convertsEnvironmentToString() {
- options.environment = [key1: 12, key2: "${1+2}"]
+ options.environment = [key1: 12, key2: "${1+2}", key3: null]
- assertThat(options.actualEnvironment, equalTo(key1: '12', key2: '3'))
+ assertThat(options.actualEnvironment, equalTo(key1: '12', key2: '3', key3: 'null'))
}
@Test
@@ -91,7 +91,7 @@ public class DefaultProcessForkOptionsTest {
assertThat(options.environment, equalTo([key: 12, key2: "value"]))
}
-
+
@Test
public void canCopyToTargetOptions() {
options.executable('executable')
diff --git a/subprojects/core/src/test/groovy/org/gradle/cache/internal/AbstractFileLockManagerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/cache/internal/AbstractFileLockManagerTest.groovy
index 1c51557..84c3892 100644
--- a/subprojects/core/src/test/groovy/org/gradle/cache/internal/AbstractFileLockManagerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/cache/internal/AbstractFileLockManagerTest.groovy
@@ -22,10 +22,10 @@ import org.gradle.cache.internal.filelock.LockInfoSerializer
import org.gradle.cache.internal.filelock.LockOptionsBuilder
import org.gradle.cache.internal.locklistener.FileLockContentionHandler
import org.gradle.internal.Factory
+import org.gradle.internal.concurrent.CompositeStoppable
import org.gradle.internal.id.IdGenerator
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
-import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
import org.junit.Rule
@@ -34,9 +34,9 @@ import spock.lang.Specification
import static org.gradle.cache.internal.FileLockManager.LockMode.Exclusive
import static org.gradle.cache.internal.FileLockManager.LockMode.Shared
- at LeaksFileHandles
abstract class AbstractFileLockManagerTest extends Specification {
- @Rule TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()
+ @Rule
+ final TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()
def metaDataProvider = Mock(ProcessMetaDataProvider)
def generator = Stub(IdGenerator)
def contentionHandler = Stub(FileLockContentionHandler)
@@ -48,6 +48,8 @@ abstract class AbstractFileLockManagerTest extends Specification {
TestFile testDir
TestFile testDirLock
+ List<Closeable> openedLocks = []
+
def setup() {
testFile = tmpDir.createFile("state.bin")
testFileLock = tmpDir.file(testFile.name + ".lock")
@@ -60,6 +62,10 @@ abstract class AbstractFileLockManagerTest extends Specification {
generator.generateId() >> 678L
}
+ def cleanup() {
+ CompositeStoppable.stoppable(openedLocks.toArray()).stop()
+ }
+
def "readFile throws integrity exception when not cleanly unlocked file"() {
given:
unlockUncleanly()
@@ -96,7 +102,7 @@ abstract class AbstractFileLockManagerTest extends Specification {
unlockUncleanly()
when:
- createLock(Exclusive).writeFile { }
+ createLock(Exclusive).writeFile {}
then:
notThrown FileIntegrityViolationException
@@ -230,8 +236,8 @@ abstract class AbstractFileLockManagerTest extends Specification {
when:
def lock = createLock(Exclusive)
- lock.writeFile({ })
- lock.updateFile({throw failure} as Runnable)
+ lock.writeFile({})
+ lock.updateFile({ throw failure } as Runnable)
then:
RuntimeException e = thrown()
@@ -491,7 +497,9 @@ abstract class AbstractFileLockManagerTest extends Specification {
abstract void isVersionLockFileWithInfoRegion(TestFile lockFile, boolean dirty, String processIdentifier, String operationalName)
FileLock createLock(LockMode lockMode, File file = testFile, FileLockManager lockManager = manager) {
- lockManager.lock(file, options().withMode(lockMode), "foo", "operation")
+ def lock = lockManager.lock(file, options().withMode(lockMode), "foo", "operation")
+ openedLocks << lock
+ lock
}
protected abstract LockOptionsBuilder options();
@@ -499,7 +507,7 @@ abstract class AbstractFileLockManagerTest extends Specification {
protected void writeFile(FileLockManager lockManager = manager) {
def lock = lockManager.lock(testFile, options().withMode(Exclusive), "foo", "operation")
try {
- lock.writeFile { }
+ lock.writeFile {}
} finally {
lock.close()
}
@@ -512,7 +520,7 @@ abstract class AbstractFileLockManagerTest extends Specification {
lock.writeFile {
throw failure
}
- } catch(RuntimeException e) {
+ } catch (RuntimeException e) {
if (e != failure) {
throw e
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultInitScriptProcessorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultInitScriptProcessorTest.groovy
index 693779b..3a8096a 100644
--- a/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultInitScriptProcessorTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultInitScriptProcessorTest.groovy
@@ -20,7 +20,6 @@ import org.gradle.api.internal.initialization.ClassLoaderScope
import org.gradle.api.internal.initialization.ScriptHandlerFactory
import org.gradle.api.internal.initialization.ScriptHandlerInternal
import org.gradle.groovy.scripts.ScriptSource
-import org.gradle.initialization.InitScript
import org.gradle.internal.resource.Resource
import spock.lang.Specification
@@ -46,7 +45,7 @@ class DefaultInitScriptProcessorTest extends Specification {
1 * gradleScope.createChild("init-$uri") >> siblingScope
1 * scriptHandlerFactory.create(initScriptMock, siblingScope) >> scriptHandler
- 1 * scriptPluginFactory.create(initScriptMock, scriptHandler, siblingScope, gradleScope, "initscript", InitScript, false) >> scriptPlugin
+ 1 * scriptPluginFactory.create(initScriptMock, scriptHandler, siblingScope, gradleScope, true) >> scriptPlugin
1 * scriptPlugin.apply(gradleMock)
DefaultInitScriptProcessor processor = new DefaultInitScriptProcessor(scriptPluginFactory, scriptHandlerFactory)
diff --git a/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultScriptPluginFactoryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultScriptPluginFactoryTest.groovy
index fd168d5..a5967fc 100755
--- a/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultScriptPluginFactoryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/configuration/DefaultScriptPluginFactoryTest.groovy
@@ -23,14 +23,15 @@ import org.gradle.api.internal.file.FileLookup
import org.gradle.api.internal.initialization.ClassLoaderScope
import org.gradle.api.internal.initialization.ScriptHandlerFactory
import org.gradle.api.internal.initialization.ScriptHandlerInternal
+import org.gradle.api.internal.project.ProjectInternal
+import org.gradle.api.internal.project.ProjectScript
import org.gradle.groovy.scripts.*
-import org.gradle.groovy.scripts.internal.CompiledScript
+import org.gradle.groovy.scripts.internal.BuildScriptData
import org.gradle.groovy.scripts.internal.FactoryBackedCompileOperation
import org.gradle.internal.Factory
import org.gradle.internal.reflect.Instantiator
import org.gradle.internal.service.ServiceRegistry
import org.gradle.logging.LoggingManagerInternal
-import org.gradle.model.dsl.internal.transform.ClosureCreationInterceptingVerifier
import org.gradle.model.internal.inspect.ModelRuleSourceDetector
import org.gradle.plugin.use.internal.PluginRequestApplicator
import spock.lang.Specification
@@ -51,14 +52,10 @@ public class DefaultScriptPluginFactoryTest extends Specification {
def pluginRequestApplicator = Mock(PluginRequestApplicator)
def scriptHandler = Mock(ScriptHandlerInternal)
def classPathScriptRunner = Mock(ScriptRunner)
- def classPathScript = Mock(BasicScript)
def loggingManagerFactory = Mock(Factory) as Factory<LoggingManagerInternal>
def loggingManager = Mock(LoggingManagerInternal)
def fileLookup = Mock(FileLookup)
def documentationRegistry = Mock(DocumentationRegistry)
- def classpathClosureName = "buildscript"
- def compiledScript = Mock(CompiledScript)
- def classpathCompiledScript = Mock(CompiledScript)
def factory = new DefaultScriptPluginFactory(scriptCompilerFactory, loggingManagerFactory, instantiator, scriptHandlerFactory, pluginRequestApplicator, fileLookup,
documentationRegistry, new ModelRuleSourceDetector())
@@ -80,43 +77,125 @@ public class DefaultScriptPluginFactoryTest extends Specification {
1 * loggingManagerFactory.create() >> loggingManager
1 * scriptCompilerFactory.createCompiler(scriptSource) >> scriptCompiler
- 1 * scriptCompiler.compile(DefaultScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, classpathClosureName, _) >> classPathScriptRunner
- 1 * classPathScriptRunner.getScript() >> classPathScript
- 1 * classPathScript.init(target, _ as ServiceRegistry)
- 1 * classPathScriptRunner.run()
- 1 * classPathScriptRunner.getCompiledScript() >> classpathCompiledScript
- 1 * scriptCompiler.compile(DefaultScript, { it.transformer != null }, scopeClassLoader, classpathClosureName, ClosureCreationInterceptingVerifier.INSTANCE) >> scriptRunner
- 1 * scriptRunner.getScript() >> script
- 1 * scriptRunner.compiledScript >> compiledScript
- 1 * compiledScript.data >> true
- 1 * script.init(target, _ as ServiceRegistry)
- 1 * scriptRunner.run()
+ 1 * scriptCompiler.compile(DefaultScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, _) >> classPathScriptRunner
+ 1 * classPathScriptRunner.run(target, _ as ServiceRegistry)
+ 1 * scriptCompiler.compile(DefaultScript, { it.transformer != null }, scopeClassLoader, !null) >> scriptRunner
+ _ * scriptRunner.data >> new BuildScriptData(true)
+ _ * scriptRunner.runDoesSomething >> true
+ 1 * scriptRunner.run(target, _ as ServiceRegistry)
+ 0 * scriptRunner._
then:
- ScriptPlugin configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, "buildscript", DefaultScript, false)
+ def configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, false)
configurer.apply(target)
}
- void configuresAScriptAwareObjectUsingScript() {
+ void configuresAProjectObjectUsingScriptWithImperativeAndInheritableCode() {
when:
- def target = Mock(ScriptAware)
+ def target = Mock(ProjectInternal)
1 * loggingManagerFactory.create() >> loggingManager
1 * scriptCompilerFactory.createCompiler(scriptSource) >> scriptCompiler
- 1 * scriptCompiler.compile(DefaultScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, classpathClosureName, _) >> classPathScriptRunner
- 1 * classPathScriptRunner.getScript() >> classPathScript
- 1 * classPathScript.init(target, _ as ServiceRegistry)
- 1 * classPathScriptRunner.run()
- 1 * classPathScriptRunner.getCompiledScript() >> classpathCompiledScript
- 1 * scriptCompiler.compile(DefaultScript, { it.transformer != null }, scopeClassLoader, classpathClosureName, ClosureCreationInterceptingVerifier.INSTANCE) >> scriptRunner
- 1 * scriptRunner.getScript() >> script
- 1 * scriptRunner.compiledScript >> compiledScript
- 1 * compiledScript.data >> true
- 1 * script.init(target, _ as ServiceRegistry)
- 1 * scriptRunner.run()
+ 1 * scriptCompiler.compile(ProjectScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, _) >> classPathScriptRunner
+ 1 * classPathScriptRunner.run(target, _ as ServiceRegistry)
+ 1 * scriptCompiler.compile(ProjectScript, { it.transformer != null }, scopeClassLoader, !null) >> scriptRunner
+ _ * scriptRunner.data >> new BuildScriptData(true)
+ _ * scriptRunner.runDoesSomething >> true
+ _ * scriptRunner.hasMethods >> true
+ 1 * scriptRunner.script >> script
+ 1 * target.setScript(script)
+ 0 * target.addDeferredConfiguration(_)
+ 1 * scriptRunner.run(target, _ as ServiceRegistry)
+ 0 * scriptRunner._
then:
- ScriptPlugin configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, "buildscript", DefaultScript, false)
+ def configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, true)
+ configurer.apply(target)
+ }
+
+ void configuresAProjectObjectUsingScriptWithImperativeCode() {
+ when:
+ def target = Mock(ProjectInternal)
+
+ 1 * loggingManagerFactory.create() >> loggingManager
+ 1 * scriptCompilerFactory.createCompiler(scriptSource) >> scriptCompiler
+ 1 * scriptCompiler.compile(ProjectScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, _) >> classPathScriptRunner
+ 1 * classPathScriptRunner.run(target, _ as ServiceRegistry)
+ 1 * scriptCompiler.compile(ProjectScript, { it.transformer != null }, scopeClassLoader, !null) >> scriptRunner
+ _ * scriptRunner.data >> new BuildScriptData(true)
+ _ * scriptRunner.runDoesSomething >> true
+ _ * scriptRunner.hasMethods >> false
+ 0 * target.setScript(_)
+ 0 * target.addDeferredConfiguration(_)
+ 1 * scriptRunner.run(target, _ as ServiceRegistry)
+ 0 * scriptRunner._
+
+ then:
+ def configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, true)
+ configurer.apply(target)
+ }
+
+ void configuresAProjectObjectUsingScriptWithInheritableAndDeferredCode() {
+ when:
+ def target = Mock(ProjectInternal)
+
+ 1 * loggingManagerFactory.create() >> loggingManager
+ 1 * scriptCompilerFactory.createCompiler(scriptSource) >> scriptCompiler
+ 1 * scriptCompiler.compile(ProjectScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, _) >> classPathScriptRunner
+ 1 * classPathScriptRunner.run(target, _ as ServiceRegistry)
+ 1 * scriptCompiler.compile(ProjectScript, { it.transformer != null }, scopeClassLoader, !null) >> scriptRunner
+ _ * scriptRunner.data >> new BuildScriptData(false)
+ _ * scriptRunner.runDoesSomething >> true
+ _ * scriptRunner.hasMethods >> true
+ 1 * scriptRunner.script >> script
+ 1 * target.setScript(script)
+ 1 * target.addDeferredConfiguration(_)
+ 0 * scriptRunner._
+
+ then:
+ def configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, true)
+ configurer.apply(target)
+ }
+
+ void configuresAProjectObjectUsingScriptWithDeferredCode() {
+ when:
+ def target = Mock(ProjectInternal)
+
+ 1 * loggingManagerFactory.create() >> loggingManager
+ 1 * scriptCompilerFactory.createCompiler(scriptSource) >> scriptCompiler
+ 1 * scriptCompiler.compile(ProjectScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, _) >> classPathScriptRunner
+ 1 * classPathScriptRunner.run(target, _ as ServiceRegistry)
+ 1 * scriptCompiler.compile(ProjectScript, { it.transformer != null }, scopeClassLoader, !null) >> scriptRunner
+ _ * scriptRunner.data >> new BuildScriptData(false)
+ _ * scriptRunner.runDoesSomething >> true
+ _ * scriptRunner.hasMethods >> false
+ 0 * target.setScript(_)
+ 1 * target.addDeferredConfiguration(_)
+ 0 * scriptRunner._
+
+ then:
+ def configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, true)
+ configurer.apply(target)
+ }
+
+ void configuresAProjectObjectUsingEmptyScript() {
+ when:
+ def target = Mock(ProjectInternal)
+
+ 1 * loggingManagerFactory.create() >> loggingManager
+ 1 * scriptCompilerFactory.createCompiler(scriptSource) >> scriptCompiler
+ 1 * scriptCompiler.compile(ProjectScript, _ as FactoryBackedCompileOperation, baseChildClassLoader, _) >> classPathScriptRunner
+ 1 * classPathScriptRunner.run(target, _ as ServiceRegistry)
+ 1 * scriptCompiler.compile(ProjectScript, { it.transformer != null }, scopeClassLoader, !null) >> scriptRunner
+ _ * scriptRunner.data >> new BuildScriptData(false)
+ _ * scriptRunner.runDoesSomething >> false
+ _ * scriptRunner.hasMethods >> false
+ 0 * scriptRunner._
+ 0 * target.setScript(_)
+ 0 * target.addDeferredConfiguration(_)
+
+ then:
+ def configurer = factory.create(scriptSource, scriptHandler, targetScope, baseScope, true)
configurer.apply(target)
}
}
\ No newline at end of file
diff --git a/subprojects/core/src/test/groovy/org/gradle/configuration/project/BuildScriptProcessorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/configuration/project/BuildScriptProcessorTest.groovy
index eedfd4a..f2ede41 100644
--- a/subprojects/core/src/test/groovy/org/gradle/configuration/project/BuildScriptProcessorTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/configuration/project/BuildScriptProcessorTest.groovy
@@ -18,7 +18,6 @@ package org.gradle.configuration.project
import org.gradle.api.initialization.dsl.ScriptHandler
import org.gradle.api.internal.initialization.ClassLoaderScope
import org.gradle.api.internal.project.ProjectInternal
-import org.gradle.api.internal.project.ProjectScript
import org.gradle.configuration.ScriptPlugin
import org.gradle.configuration.ScriptPluginFactory
import org.gradle.groovy.scripts.ScriptSource
@@ -47,7 +46,7 @@ public class BuildScriptProcessorTest extends Specification {
buildScriptProcessor.execute(project)
then:
- 1 * configurerFactory.create(scriptSource, scriptHandler, targetScope, baseScope, "buildscript", ProjectScript, true) >> scriptPlugin
+ 1 * configurerFactory.create(scriptSource, scriptHandler, targetScope, baseScope, true) >> scriptPlugin
1 * scriptPlugin.apply(project)
}
}
\ No newline at end of file
diff --git a/subprojects/core/src/test/groovy/org/gradle/deployment/internal/DefaultDeploymentRegistryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/deployment/internal/DefaultDeploymentRegistryTest.groovy
new file mode 100644
index 0000000..2f41e2a
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/deployment/internal/DefaultDeploymentRegistryTest.groovy
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.deployment.internal
+import org.gradle.api.invocation.Gradle
+import spock.lang.Specification
+
+class DefaultDeploymentRegistryTest extends Specification {
+ DefaultDeploymentRegistry registry = new DefaultDeploymentRegistry()
+
+ def "can register and retrieve a deployment handle" () {
+ DeploymentHandle handle = Mock(DeploymentHandle)
+
+ when:
+ registry.register("test", handle)
+
+ then:
+ registry.get(DeploymentHandle.class, "test") == handle
+ }
+
+ def "notifies all handles when new build starts"() {
+ DeploymentHandle handle = Mock(DeploymentHandle)
+ Gradle gradle = Mock(Gradle)
+
+ when:
+ (1..10).each {
+ registry.register("test$it", handle)
+ }
+ and:
+ registry.onNewBuild(gradle)
+
+ then:
+ 10 * handle.onNewBuild(gradle)
+ }
+
+ def "cannot register a duplicate deployment handle" () {
+ DeploymentHandle handle = Mock(DeploymentHandle)
+
+ when:
+ registry.register("test", handle)
+
+ then:
+ noExceptionThrown()
+ registry.get(DeploymentHandle.class, "test") == handle
+
+ when:
+ registry.register("test", handle)
+
+ then:
+ IllegalStateException e = thrown()
+ e.message == "A deployment with id 'test' is already registered."
+ }
+
+ def "stopping registry stops deployment handles" () {
+ DeploymentHandle handle1 = Mock(DeploymentHandle)
+ DeploymentHandle handle2 = Mock(DeploymentHandle)
+ DeploymentHandle handle3 = Mock(DeploymentHandle)
+ registry.register("test1", handle1)
+ registry.register("test2", handle2)
+ registry.register("test3", handle3)
+
+ when:
+ registry.stop()
+
+ then:
+ 1 * handle1.stop()
+ 1 * handle2.stop()
+ 1 * handle3.stop()
+ }
+
+ def "cannot get a handle once the registry is stopped" () {
+ given:
+ registry.register("test", Mock(DeploymentHandle))
+ registry.stop()
+
+ when:
+ registry.get(DeploymentHandle, "test")
+
+ then:
+ def e = thrown(IllegalStateException)
+ e.message == "Cannot modify deployment handles once the registry has been stopped."
+ }
+
+ def "cannot register a handle once the registry is stopped" () {
+ given:
+ registry.stop()
+
+ when:
+ registry.register("test", Mock(DeploymentHandle))
+
+ then:
+ def e = thrown(IllegalStateException)
+ e.message == "Cannot modify deployment handles once the registry has been stopped."
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/execution/DefaultBuildConfigurationActionExecuterTest.groovy b/subprojects/core/src/test/groovy/org/gradle/execution/DefaultBuildConfigurationActionExecuterTest.groovy
new file mode 100644
index 0000000..5d1a594
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/execution/DefaultBuildConfigurationActionExecuterTest.groovy
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.execution
+
+import org.gradle.api.internal.GradleInternal
+import spock.lang.Specification
+
+class DefaultBuildConfigurationActionExecuterTest extends Specification {
+ final GradleInternal gradleInternal = Mock()
+
+ def "select method calls configure method on first configuration action"() {
+ BuildConfigurationAction configurationAction = Mock()
+ BuildConfigurationAction taskSelectionAction = Mock()
+
+ given:
+ def buildExecution = new DefaultBuildConfigurationActionExecuter([configurationAction], [taskSelectionAction])
+
+ when:
+ buildExecution.select(gradleInternal)
+
+ then:
+ 1 * configurationAction.configure(!null)
+ 0 * _._
+ }
+
+ def "calls next action in chain when configuration action calls proceed"() {
+ BuildConfigurationAction configurationAction = Mock()
+ BuildConfigurationAction taskSelectionAction = Mock()
+
+ given:
+ def buildExecution = new DefaultBuildConfigurationActionExecuter([configurationAction], [taskSelectionAction])
+
+ when:
+ buildExecution.select(gradleInternal)
+
+ then:
+ 1 * configurationAction.configure(!null) >> { it[0].proceed() }
+
+ and:
+ 1 * taskSelectionAction.configure(!null)
+ }
+
+ def "does nothing when last configuration action calls proceed"() {
+ BuildConfigurationAction action1 = Mock()
+
+ given:
+ def buildExecution = new DefaultBuildConfigurationActionExecuter([action1],[])
+
+ when:
+ buildExecution.select(gradleInternal)
+
+ then:
+ 1 * action1.configure(!null) >> { it[0].proceed() }
+ 0 * _._
+ }
+
+ def "makes Gradle instance available to actions"() {
+ BuildConfigurationAction configurationAction = Mock()
+
+ given:
+ def buildExecution = new DefaultBuildConfigurationActionExecuter([configurationAction],[])
+
+ when:
+ buildExecution.select(gradleInternal)
+
+ then:
+ 1 * configurationAction.configure(!null) >> {
+ assert it[0].gradle ==gradleInternal
+ }
+ }
+
+ def "can overwrite default task selectors"() {
+ setup:
+ BuildConfigurationAction configAction1 = Mock()
+ BuildConfigurationAction configAction2 = Mock()
+ BuildConfigurationAction givenTaskSelector2 = Mock()
+ BuildConfigurationAction givenTaskSelector1 = Mock()
+
+ BuildConfigurationAction newTaskSelector = Mock()
+
+
+ def buildExecution = new DefaultBuildConfigurationActionExecuter([configAction1, configAction2],[givenTaskSelector1, givenTaskSelector2])
+
+ when:
+ buildExecution.setTaskSelectors([newTaskSelector])
+ buildExecution.select(gradleInternal)
+
+ then:
+
+ 0 * givenTaskSelector1.configure(!null)
+ 0 * givenTaskSelector2.configure(!null)
+ 1 * configAction1.configure(!null) >> {it[0].proceed()}
+ 1 * configAction2.configure(!null) >> {it[0].proceed()}
+
+ 1 * newTaskSelector.configure(!null) >> {
+ assert it[0].gradle ==gradleInternal
+
+ }
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/execution/DefaultBuildExecuterTest.groovy b/subprojects/core/src/test/groovy/org/gradle/execution/DefaultBuildExecuterTest.groovy
index 6a39fe5..01752a3 100644
--- a/subprojects/core/src/test/groovy/org/gradle/execution/DefaultBuildExecuterTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/execution/DefaultBuildExecuterTest.groovy
@@ -21,62 +21,15 @@ import spock.lang.Specification
class DefaultBuildExecuterTest extends Specification {
final GradleInternal gradleInternal = Mock()
- def "select method calls configure method on first configuration action"() {
- BuildConfigurationAction action1 = Mock()
- BuildConfigurationAction action2 = Mock()
-
- given:
- def buildExecution = new DefaultBuildExecuter([action1, action2], [])
-
- when:
- buildExecution.select(gradleInternal)
-
- then:
- 1 * action1.configure(!null)
- 0 * _._
- }
-
- def "calls next action in chain when configuration action calls proceed"() {
- BuildConfigurationAction action1 = Mock()
- BuildConfigurationAction action2 = Mock()
-
- given:
- def buildExecution = new DefaultBuildExecuter([action1, action2], [])
-
- when:
- buildExecution.select(gradleInternal)
-
- then:
- 1 * action1.configure(!null) >> { it[0].proceed() }
-
- and:
- 1 * action2.configure(!null)
- }
-
- def "does nothing when last configuration action calls proceed"() {
- BuildConfigurationAction action1 = Mock()
-
- given:
- def buildExecution = new DefaultBuildExecuter([action1], [])
-
- when:
- buildExecution.select(gradleInternal)
-
- then:
- 1 * action1.configure(!null) >> { it[0].proceed() }
- 0 * _._
- }
-
def "execute method calls execute method on first execution action"() {
BuildExecutionAction action1 = Mock()
BuildExecutionAction action2 = Mock()
given:
- def buildExecution = new DefaultBuildExecuter([], [action1, action2])
- buildExecution.select(gradleInternal)
+ def buildExecution = new DefaultBuildExecuter([action1, action2])
when:
- buildExecution.execute()
+ buildExecution.execute(gradleInternal)
then:
1 * action1.execute(!null)
@@ -88,11 +41,10 @@ class DefaultBuildExecuterTest extends Specification {
BuildExecutionAction action2 = Mock()
given:
- def buildExecution = new DefaultBuildExecuter([], [action1, action2])
- buildExecution.select(gradleInternal)
+ def buildExecution = new DefaultBuildExecuter([action1, action2])
when:
- buildExecution.execute()
+ buildExecution.execute(gradleInternal)
then:
1 * action1.execute(!null) >> { it[0].proceed() }
@@ -105,11 +57,10 @@ class DefaultBuildExecuterTest extends Specification {
BuildExecutionAction action1 = Mock()
given:
- def buildExecution = new DefaultBuildExecuter([], [action1])
- buildExecution.select(gradleInternal)
+ def buildExecution = new DefaultBuildExecuter([action1])
when:
- buildExecution.execute()
+ buildExecution.execute(gradleInternal)
then:
1 * action1.execute(!null) >> { it[0].proceed() }
@@ -117,20 +68,15 @@ class DefaultBuildExecuterTest extends Specification {
}
def "makes Gradle instance available to actions"() {
- BuildConfigurationAction configurationAction = Mock()
BuildExecutionAction executionAction = Mock()
given:
- def buildExecution = new DefaultBuildExecuter([configurationAction], [executionAction])
+ def buildExecution = new DefaultBuildExecuter([executionAction])
when:
- buildExecution.select(gradleInternal)
- buildExecution.execute()
+ buildExecution.execute(gradleInternal)
then:
- 1 * configurationAction.configure(!null) >> {
- assert it[0].gradle ==gradleInternal
- }
1 * executionAction.execute(!null) >> {
assert it[0].gradle ==gradleInternal
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/execution/taskgraph/DefaultTaskExecutionPlanParallelTaskHandlingTest.groovy b/subprojects/core/src/test/groovy/org/gradle/execution/taskgraph/DefaultTaskExecutionPlanParallelTaskHandlingTest.groovy
index 410c02f..d988388 100644
--- a/subprojects/core/src/test/groovy/org/gradle/execution/taskgraph/DefaultTaskExecutionPlanParallelTaskHandlingTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/execution/taskgraph/DefaultTaskExecutionPlanParallelTaskHandlingTest.groovy
@@ -26,6 +26,7 @@ import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.ParallelizableTask
import org.gradle.initialization.BuildCancellationToken
import org.gradle.internal.nativeintegration.filesystem.FileSystem
+import org.gradle.test.fixtures.ConcurrentTestUtil
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.testfixtures.internal.NativeServicesTestFixture
@@ -33,7 +34,6 @@ import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
import org.junit.Rule
import spock.lang.Specification
-import spock.util.concurrent.PollingConditions
import static org.gradle.util.TestUtil.createChildProject
import static org.gradle.util.TestUtil.createRootProject
@@ -88,11 +88,10 @@ class DefaultTaskExecutionPlanParallelTaskHandlingTest extends Specification {
static class ParallelChild extends Parallel {}
Thread blockedThread(Runnable target) {
- def conditions = new PollingConditions(timeout: 3, delay: 0.01)
def thread = new Thread(target)
thread.start()
- conditions.eventually {
+ ConcurrentTestUtil.poll(3, 0.01) {
assert thread.state == Thread.State.WAITING
}
thread
@@ -319,6 +318,9 @@ class DefaultTaskExecutionPlanParallelTaskHandlingTest extends Specification {
then:
noMoreTasksCurrentlyAvailableForExecution()
+
+ cleanup:
+ assert symlink.delete()
}
def "tasks from two different projects that have the same file in outputs are not executed in parallel"() {
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactoryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactoryTest.groovy
index 4fd8cc4..c598396 100644
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactoryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/DefaultScriptCompilerFactoryTest.groovy
@@ -45,14 +45,14 @@ class DefaultScriptCompilerFactoryTest extends Specification {
def "compiles script into class and wraps instance in script runner"() {
when:
def compiler = factory.createCompiler(source)
- def result = compiler.compile(Script, operation, classLoader, "buildscript", verifier)
+ def result = compiler.compile(Script, operation, classLoader, verifier)
then:
result == runner
1 * scriptClassCompiler.compile({
it instanceof CachingScriptSource
- }, classLoader, ClassLoaderIds.buildScript(source.fileName, operation.id), operation, "buildscript", Script, verifier) >> compiledScript
+ }, classLoader, ClassLoaderIds.buildScript(source.fileName, operation.id), operation, Script, verifier) >> compiledScript
1 * scriptRunnerFactory.create(compiledScript, { it instanceof CachingScriptSource }, classLoader) >> runner
0 * scriptRunnerFactory._
0 * scriptClassCompiler._
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/AsmBackedEmptyScriptGeneratorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/AsmBackedEmptyScriptGeneratorTest.groovy
deleted file mode 100644
index 4d6c6a8..0000000
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/AsmBackedEmptyScriptGeneratorTest.groovy
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.groovy.scripts.internal
-
-import spock.lang.Specification
-
-class AsmBackedEmptyScriptGeneratorTest extends Specification {
- private final AsmBackedEmptyScriptGenerator generator = new AsmBackedEmptyScriptGenerator()
-
- def generatesEmptyScriptClass() {
- expect:
- def cl = generator.generate(groovy.lang.Script.class)
- def script = cl.newInstance()
- script instanceof groovy.lang.Script
- script.run() == null
- }
-
- def cachesScriptClass() {
- expect:
- def cl1 = generator.generate(groovy.lang.Script.class)
- def cl2 = generator.generate(groovy.lang.Script.class)
- cl1 == cl2
- }
-}
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/BuildScriptDataSerializerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/BuildScriptDataSerializerTest.groovy
new file mode 100644
index 0000000..454ddb3
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/BuildScriptDataSerializerTest.groovy
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.groovy.scripts.internal
+
+import org.gradle.internal.serialize.SerializerSpec
+
+class BuildScriptDataSerializerTest extends SerializerSpec {
+ def serializer = new BuildScriptDataSerializer()
+
+ def "serializes data"() {
+ given:
+ def value = new BuildScriptData(true)
+ def result = serialize(value, serializer)
+
+ expect:
+ result.hasImperativeStatements
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformerSpec.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformerSpec.groovy
index 0184a34..ca53e3e 100644
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformerSpec.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/BuildScriptTransformerSpec.groovy
@@ -22,10 +22,10 @@ import org.gradle.api.internal.project.ProjectScript
import org.gradle.configuration.ImportsReader
import org.gradle.groovy.scripts.StringScriptSource
import org.gradle.internal.Actions
-import org.gradle.internal.serialize.BaseSerializerFactory
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.junit.Rule
import spock.lang.Specification
+import spock.lang.Unroll
class BuildScriptTransformerSpec extends Specification {
@@ -36,7 +36,7 @@ class BuildScriptTransformerSpec extends Specification {
getImportPackages() >> ([] as String[])
}
- final DefaultScriptCompilationHandler scriptCompilationHandler = new DefaultScriptCompilationHandler(new AsmBackedEmptyScriptGenerator(), new DummyClassLoaderCache(), importsReader)
+ final DefaultScriptCompilationHandler scriptCompilationHandler = new DefaultScriptCompilationHandler(new DummyClassLoaderCache(), importsReader)
final String classpathClosureName = "buildscript"
File scriptCacheDir
@@ -49,48 +49,205 @@ class BuildScriptTransformerSpec extends Specification {
metadataCacheDir = new File(testProjectDir, "metadata");
}
- private boolean containsImperativeStatements(String script) {
+ private CompiledScript<Script, BuildScriptData> parse(String script) {
def source = new StringScriptSource("test script", script)
def loader = getClass().getClassLoader()
def transformer = new BuildScriptTransformer(classpathClosureName, source)
- def operation = new FactoryBackedCompileOperation("id", transformer, transformer, BaseSerializerFactory.BOOLEAN_SERIALIZER)
- scriptCompilationHandler.compileToDir(source, loader, scriptCacheDir, metadataCacheDir, operation, classpathClosureName, ProjectScript, Actions.doNothing())
- scriptCompilationHandler.loadFromDir(source, loader, scriptCacheDir, metadataCacheDir, operation, ProjectScript, classLoaderId).data
+ def operation = new FactoryBackedCompileOperation<BuildScriptData>("id", transformer, transformer, new BuildScriptDataSerializer())
+ scriptCompilationHandler.compileToDir(source, loader, scriptCacheDir, metadataCacheDir, operation, ProjectScript, Actions.doNothing())
+ return scriptCompilationHandler.loadFromDir(source, loader, scriptCacheDir, metadataCacheDir, operation, ProjectScript, classLoaderId)
}
- def "empty script does not contain imperative code"() {
+ def "empty script does not contain any code"() {
expect:
- !containsImperativeStatements("")
- !containsImperativeStatements("//ignore me")
+ def scriptData = parse(script)
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
+
+ where:
+ script | _
+ "" | _
+ "// ignore me" | _
+ "\r\n\t " | _
}
- def "class, method and property declarations are not considered imperative code"() {
+ def "class declarations are not considered imperative code"() {
+ given:
+ def scriptData = parse("""
+ class SomeClass {
+ String a = 123
+ def doStuff() {
+ int i = 9
+ }
+ }
+ """)
+
expect:
- !containsImperativeStatements("""
- class SomeClass {}
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
+ }
+
+ def "property declarations with constant initializer are not considered imperative code"() {
+ given:
+ def scriptData = parse("""
String a
+ String b = "hi"
+ int c = 12
+ """)
+
+ expect:
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
+ }
+
+ def "field declarations are not considered imperative code"() {
+ given:
+ def scriptData = parse("""
+ @groovy.transform.Field Long c
+ @groovy.transform.Field Long d = 12
+ @groovy.transform.Field Long e = d * foo
""")
+
+ expect:
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
}
- def "non-imperative script blocks are not considered imperative code"() {
+ def "filtered script blocks are not considered imperative code"() {
+ given:
+ def scriptData = parse("""
+plugins {
+ int v = 12
+ println "ignore me"
+}
+buildscript {
+ doStuff()
+}
+buildscript {
+ if ( true ) { return }
+}
+""")
+
expect:
- !containsImperativeStatements("plugins {}; buildscript {}; model {}")
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
+ }
+
+ def "model blocks are not considered imperative code"() {
+ given:
+ def scriptData = parse("""
+model {
+ task { foo(Task) { println "hi" } }
+}
+
+model { println "hi" }
+""")
+
+ expect:
+ scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
+ }
+
+ def "model blocks combined with other non imperative elements are not considered imperative code"() {
+ given:
+ def scriptData = parse("""
+model {
+ task { foo(Task) { println "hi" } }
+}
+
+"constant"
+
+def something() { return 12 }
+
+model { println "hi" }
+
+class Thing { }
+
+return null
+""")
+
+ expect:
+ scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ scriptData.hasMethods
}
def "imports are not considered imperative code"() {
- !containsImperativeStatements("import java.lang.String")
+ expect:
+ def scriptData = parse("""import java.lang.String
+import java.lang.*
+import static java.lang.String.*
+""")
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
}
- def "method declarations are considered imperative code"() {
+ def "method declarations are not considered imperative code"() {
expect:
- containsImperativeStatements("def method() { println 'hi' }")
+ def scriptData = parse("""def method() { println 'hi' }
+private void doSomething() { thing = true }
+""")
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ scriptData.hasMethods
}
- def "imperative code is detected"() {
+ def "constant expressions and constant return are not imperative"() {
expect:
- containsImperativeStatements("foo = 'bar'")
- containsImperativeStatements("foo")
- containsImperativeStatements("println 'hi!'")
+ def scriptData = parse(script)
+ !scriptData.runDoesSomething
+ !scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
+
+ where:
+ script | _
+ "return null" | _
+ "return true" | _
+ "return 'abc'" | _
+ """
+"hi"
+'hi'
+null
+true
+123
+return 12
+""" | _
}
+ @Unroll
+ def "imperative code is detected in #script"() {
+ expect:
+ def scriptData = parse(script)
+ scriptData.runDoesSomething
+ scriptData.data.hasImperativeStatements
+ !scriptData.hasMethods
+
+ where:
+ script | _
+ "foo = 'bar'" | _
+ "foo" | _
+ '"${foo}"' | _
+ "println 'hi!'" | _
+ "return a + 1" | _
+ "return foo" | _
+ 'return "${foo}"' | _
+ 'String s = "a" + "b"' | _
+ "if (a) { return null }; foo" | _
+ """
+plugins {
+}
+println "hi"
+""" | _
+ """
+foo
+return null
+""" | _
+ }
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompilerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompilerTest.groovy
index d9269ec..2a0ec54 100644
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompilerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/CachingScriptClassCompilerTest.groovy
@@ -38,12 +38,12 @@ class CachingScriptClassCompilerTest extends Specification {
CompileOperation<?> transformer = operation()
when:
- def c1 = compiler.compile(script1, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
- def c2 = compiler.compile(script2, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
+ def c1 = compiler.compile(script1, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
+ def c2 = compiler.compile(script2, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
then:
c1 == c2
- 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier) >> compiledScript
+ 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer, Script.class, verifier) >> compiledScript
0 * target._
}
@@ -54,12 +54,12 @@ class CachingScriptClassCompilerTest extends Specification {
CompileOperation<?> transformer = operation()
when:
- compiler.compile(script1, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
- compiler.compile(script2, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
+ compiler.compile(script1, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
+ compiler.compile(script2, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
then:
- 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
- 1 * target.compile(script2, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
+ 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
+ 1 * target.compile(script2, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
}
def "does not cache script class for different transformers"() {
@@ -70,12 +70,12 @@ class CachingScriptClassCompilerTest extends Specification {
CompileOperation<?> transformer2 = operation('t2')
when:
- compiler.compile(script1, parentClassLoader, classLoaderId, transformer1, classpathClosureName, Script.class, verifier)
- compiler.compile(script2, parentClassLoader, classLoaderId, transformer2, classpathClosureName, Script.class, verifier)
+ compiler.compile(script1, parentClassLoader, classLoaderId, transformer1, Script.class, verifier)
+ compiler.compile(script2, parentClassLoader, classLoaderId, transformer2, Script.class, verifier)
then:
- 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer1, classpathClosureName, Script.class, verifier)
- 1 * target.compile(script2, parentClassLoader, classLoaderId, transformer2, classpathClosureName, Script.class, verifier)
+ 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer1, Script.class, verifier)
+ 1 * target.compile(script2, parentClassLoader, classLoaderId, transformer2, Script.class, verifier)
}
def "does not cache script class for different classloaders"() {
@@ -86,12 +86,12 @@ class CachingScriptClassCompilerTest extends Specification {
CompileOperation<?> transformer = operation()
when:
- compiler.compile(script1, parentClassLoader1, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
- compiler.compile(script2, parentClassLoader2, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
+ compiler.compile(script1, parentClassLoader1, classLoaderId, transformer, Script.class, verifier)
+ compiler.compile(script2, parentClassLoader2, classLoaderId, transformer, Script.class, verifier)
then:
- 1 * target.compile(script1, parentClassLoader1, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
- 1 * target.compile(script2, parentClassLoader2, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
+ 1 * target.compile(script1, parentClassLoader1, classLoaderId, transformer, Script.class, verifier)
+ 1 * target.compile(script2, parentClassLoader2, classLoaderId, transformer, Script.class, verifier)
}
def "does not cache script class for different base classes"() {
@@ -101,12 +101,12 @@ class CachingScriptClassCompilerTest extends Specification {
CompileOperation<?> transformer = operation()
when:
- compiler.compile(script1, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
- compiler.compile(script2, parentClassLoader, classLoaderId, transformer, classpathClosureName, TestScript.class, verifier)
+ compiler.compile(script1, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
+ compiler.compile(script2, parentClassLoader, classLoaderId, transformer, TestScript.class, verifier)
then:
- 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer, classpathClosureName, Script.class, verifier)
- 1 * target.compile(script2, parentClassLoader, classLoaderId, transformer, classpathClosureName, TestScript.class, verifier)
+ 1 * target.compile(script1, parentClassLoader, classLoaderId, transformer, Script.class, verifier)
+ 1 * target.compile(script2, parentClassLoader, classLoaderId, transformer, TestScript.class, verifier)
}
def scriptSource(String className = 'script') {
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandlerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandlerTest.groovy
new file mode 100644
index 0000000..6305e24
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandlerTest.groovy
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.groovy.scripts.internal
+
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.CodeVisitorSupport
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ClassExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.control.CompilationFailedException
+import org.codehaus.groovy.control.Phases
+import org.codehaus.groovy.control.SourceUnit
+import org.gradle.api.Action
+import org.gradle.api.GradleException
+import org.gradle.api.internal.initialization.ClassLoaderIds
+import org.gradle.api.internal.initialization.loadercache.ClassLoaderId
+import org.gradle.api.internal.initialization.loadercache.DummyClassLoaderCache
+import org.gradle.configuration.ImportsReader
+import org.gradle.groovy.scripts.ScriptCompilationException
+import org.gradle.groovy.scripts.ScriptSource
+import org.gradle.groovy.scripts.StringScriptSource
+import org.gradle.groovy.scripts.Transformer
+import org.gradle.internal.Actions
+import org.gradle.internal.resource.Resource
+import org.gradle.internal.serialize.BaseSerializerFactory
+import org.gradle.internal.serialize.Serializer
+import org.gradle.internal.serialize.kryo.KryoBackedDecoder
+import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.gradle.util.SetSystemProperties
+import org.junit.Rule
+import spock.lang.Specification
+
+import static org.hamcrest.Matchers.instanceOf
+import static org.junit.Assert.*
+
+class DefaultScriptCompilationHandlerTest extends Specification {
+
+ static final String TEST_EXPECTED_SYSTEMPROP_VALUE = "somevalue"
+ static final String TEST_EXPECTED_SYSTEMPROP_KEY = "somekey"
+
+ private DefaultScriptCompilationHandler scriptCompilationHandler
+
+ private File scriptCacheDir
+ private File metadataCacheDir
+ private File cachedFile
+
+ private String scriptText
+ private String scriptClassName
+ private String scriptFileName
+
+ private ClassLoader classLoader
+
+ private Action<ClassNode> verifier = Actions.doNothing()
+
+ private Class<? extends Script> expectedScriptClass
+
+ private ImportsReader importsReader
+ @Rule
+ public TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()
+ @Rule
+ public SetSystemProperties systemProperties = new SetSystemProperties()
+ private final ClassLoaderId classLoaderId = ClassLoaderIds.buildScript("foo", "bar")
+
+ def setup() {
+ File testProjectDir = tmpDir.createDir("projectDir")
+ classLoader = getClass().getClassLoader()
+ importsReader = Stub(ImportsReader.class)
+ scriptCompilationHandler = new DefaultScriptCompilationHandler(new DummyClassLoaderCache(), importsReader)
+ scriptCacheDir = new File(testProjectDir, "cache")
+ metadataCacheDir = new File(testProjectDir, "metadata")
+ scriptText = "System.setProperty('" + TEST_EXPECTED_SYSTEMPROP_KEY + "', '" + TEST_EXPECTED_SYSTEMPROP_VALUE + "')"
+
+ scriptClassName = "ScriptClassName"
+ scriptFileName = "script-file-name"
+ cachedFile = new File(scriptCacheDir, scriptClassName + ".class")
+ expectedScriptClass = TestBaseScript.class
+ }
+
+ private ScriptSource scriptSource(final String scriptText) {
+ def source = Stub(ScriptSource)
+ def resource = Stub(Resource)
+ _ * source.className >> scriptClassName
+ _ * source.fileName >> scriptFileName
+ _ * source.displayName >> "script-display-name"
+ _ * source.resource >> resource
+ _ * resource.text >> scriptText
+ return source
+ }
+
+ def testCompileScriptToDir() {
+ def scriptSource = scriptSource(scriptText)
+
+ when:
+ scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ checkScriptClassesInCache()
+
+ when:
+ def compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId)
+
+ then:
+ compiledScript.runDoesSomething
+ compiledScript.data == null
+ Script script = compiledScript.loadClass().newInstance()
+ evaluateScript(script)
+ }
+
+ def testCompileScriptToDirWithPackageDeclaration() {
+ ScriptSource scriptSource = scriptSource("""package org.gradle.test
+println 'hi'
+""")
+
+ when:
+ scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ UnsupportedOperationException e = thrown()
+ e.message == "Script-display-name should not contain a package statement."
+ }
+
+ def testCompileScriptToDirWithEmptyScript() {
+ final ScriptSource scriptSource = scriptSource(emptyScript)
+
+ when:
+ scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ checkEmptyScriptInCache()
+
+ when:
+ def compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId)
+
+ then:
+ !compiledScript.runDoesSomething
+ !compiledScript.hasMethods
+ compiledScript.data == null
+
+ where:
+ emptyScript | _
+ "" | _
+ " \r\n\t \n" | _
+ "\n // ignore me" | _
+ "/*\n\n*/" | _
+ "import org.gradle.ignored.*" | _
+ }
+
+ def testCompileScriptToDirWithClassDefinitionOnlyScript() {
+ final ScriptSource scriptSource = scriptSource("class SomeClass {}")
+
+ when:
+ scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ checkEmptyScriptInCache()
+
+ when:
+ def compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId)
+
+ then:
+ !compiledScript.runDoesSomething
+ !compiledScript.hasMethods
+ compiledScript.data == null
+ }
+
+ def testCompileScriptToDirWithMethodOnlyScript() {
+ final ScriptSource scriptSource = scriptSource("def method(def value) { return '[' + value + ']' }")
+
+ when:
+ scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ checkScriptClassesInCache(true)
+
+ when:
+ def compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId)
+
+ then:
+ !compiledScript.runDoesSomething
+ compiledScript.hasMethods
+ compiledScript.data == null
+
+ and:
+ Script script = compiledScript.loadClass().newInstance()
+ expectedScriptClass.isInstance(script)
+ script.method(12) == "[12]"
+ }
+
+ def testCompileScriptToDirWithPropertiesOnlyScript() {
+ final ScriptSource scriptSource = scriptSource("String a")
+
+ when:
+ scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ checkScriptClassesInCache(true)
+
+ when:
+ def compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId)
+
+ then:
+ !compiledScript.runDoesSomething
+ !compiledScript.hasMethods
+ compiledScript.data == null
+ }
+
+ def testLoadFromDirWhenNotAssignableToBaseClass() {
+ def scriptSource = scriptSource("ignoreMe = true")
+
+ given:
+ scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, Script.class, verifier)
+
+ when:
+ scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId).loadClass()
+
+ then:
+ GradleException e = thrown()
+ e.message.contains("Could not load compiled classes for script-display-name from cache.")
+ e.cause instanceof ClassCastException
+ }
+
+ def testCompileToDirWithSyntaxError() {
+ ScriptSource source = new StringScriptSource("script.gradle", "\n\nnew HHHHJSJSJ jsj")
+
+ when:
+ scriptCompilationHandler.compileToDir(source, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ ScriptCompilationException e = thrown()
+ e.lineNumber == 3
+ e.cause.message.contains("script.gradle: 3: unexpected token: jsj")
+
+ and:
+ checkScriptCacheEmpty()
+ }
+
+ def testCanVisitAndTransformScriptClass() {
+ def visitor = new AbstractScriptTransformer() {
+ protected int getPhase() {
+ return Phases.CANONICALIZATION
+ }
+
+ @Override
+ public void call(SourceUnit source) throws CompilationFailedException {
+ source.getAST().getStatementBlock().visit(new CodeVisitorSupport() {
+ @Override
+ public void visitMethodCallExpression(MethodCallExpression call) {
+ call.setObjectExpression(new ClassExpression(ClassHelper.make(System.class)))
+ call.setMethod(new ConstantExpression("setProperty"))
+ ArgumentListExpression arguments = (ArgumentListExpression) call.getArguments()
+ arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_KEY))
+ arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_VALUE))
+ }
+ })
+ }
+ }
+
+ def transformer = new CompileOperation<String>() {
+ @Override
+ public String getId() {
+ return "id"
+ }
+
+ @Override
+ public Transformer getTransformer() {
+ return visitor
+ }
+
+ @Override
+ public String getExtractedData() {
+ return "extracted data"
+ }
+
+ @Override
+ public Serializer<String> getDataSerializer() {
+ return new BaseSerializerFactory().getSerializerFor(String)
+ }
+ }
+
+ def source = scriptSource("transformMe()")
+
+ when:
+ scriptCompilationHandler.compileToDir(source, classLoader, scriptCacheDir, metadataCacheDir, transformer, expectedScriptClass, verifier)
+ def compiledScript = scriptCompilationHandler.loadFromDir(source, classLoader, scriptCacheDir, metadataCacheDir, transformer, expectedScriptClass, classLoaderId)
+
+ then:
+ compiledScript.runDoesSomething
+ !compiledScript.hasMethods
+ compiledScript.data == "extracted data"
+ def script = compiledScript.loadClass().newInstance()
+ evaluateScript(script)
+ }
+
+ def testCanTransformScriptClassToExtractDataAndRemoveStatements() {
+ def visitor = new AbstractScriptTransformer() {
+ protected int getPhase() {
+ return Phases.CANONICALIZATION
+ }
+
+ @Override
+ public void call(SourceUnit source) throws CompilationFailedException {
+ source.getAST().getStatementBlock().getStatements().clear()
+ }
+ }
+
+ def transformer = new CompileOperation<String>() {
+ @Override
+ public String getId() {
+ return "id"
+ }
+
+ @Override
+ public Transformer getTransformer() {
+ return visitor
+ }
+
+ @Override
+ public String getExtractedData() {
+ return "extracted data"
+ }
+
+ @Override
+ public Serializer<String> getDataSerializer() {
+ return new BaseSerializerFactory().getSerializerFor(String)
+ }
+ }
+
+ def source = scriptSource("transformMe()")
+
+ when:
+ scriptCompilationHandler.compileToDir(source, classLoader, scriptCacheDir, metadataCacheDir, transformer, expectedScriptClass, verifier)
+ def compiledScript = scriptCompilationHandler.loadFromDir(source, classLoader, scriptCacheDir, metadataCacheDir, transformer, expectedScriptClass, classLoaderId)
+
+ then:
+ !compiledScript.runDoesSomething
+ !compiledScript.hasMethods
+ compiledScript.data == "extracted data"
+ }
+
+ def testCanVisitAndTransformGeneratedClasses() {
+ def verifier = Mock(Action)
+ ScriptSource source = scriptSource("transformMe()")
+
+ when:
+ scriptCompilationHandler.compileToDir(source, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, verifier)
+
+ then:
+ 1 * verifier.execute(!null)
+ }
+
+ private void checkScriptClassesInCache(boolean empty = false) {
+ assertTrue(scriptCacheDir.isDirectory())
+ assertTrue(cachedFile.isFile())
+ checkEmptyScriptFlagSet(empty)
+ }
+
+ private void checkEmptyScriptInCache() {
+ assertTrue(scriptCacheDir.isDirectory())
+ checkEmptyScriptFlagSet(true)
+ }
+
+ private void checkScriptCacheEmpty() {
+ assertFalse(scriptCacheDir.exists())
+ }
+
+ private void checkEmptyScriptFlagSet(boolean flag) {
+ assertTrue(metadataCacheDir.isDirectory())
+ def metaDataFile = new File(metadataCacheDir, "metadata.bin")
+ assertTrue(metaDataFile.isFile())
+ def decoder = new KryoBackedDecoder(new FileInputStream(metaDataFile))
+ try {
+ assertEquals(decoder.readByte() & 1, flag ? 1 : 0)
+ } finally {
+ decoder.close()
+ }
+ }
+
+ private void evaluateScript(Script script) {
+ assertThat(script, instanceOf(expectedScriptClass))
+ assertEquals(script.getClass().getSimpleName(), scriptClassName)
+ System.setProperty(TEST_EXPECTED_SYSTEMPROP_KEY, "not the expected value")
+ script.run()
+ assertEquals(TEST_EXPECTED_SYSTEMPROP_VALUE, System.getProperty(TEST_EXPECTED_SYSTEMPROP_KEY))
+ }
+
+ public abstract static class TestBaseScript extends Script {
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandlerTest.java b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandlerTest.java
deleted file mode 100644
index 33c1533..0000000
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptCompilationHandlerTest.java
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.groovy.scripts.internal;
-
-import groovy.lang.Script;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.CodeVisitorSupport;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.Phases;
-import org.codehaus.groovy.control.SourceUnit;
-import org.gradle.api.Action;
-import org.gradle.api.GradleException;
-import org.gradle.api.internal.initialization.ClassLoaderIds;
-import org.gradle.api.internal.initialization.loadercache.ClassLoaderId;
-import org.gradle.api.internal.initialization.loadercache.DummyClassLoaderCache;
-import org.gradle.configuration.ImportsReader;
-import org.gradle.groovy.scripts.ScriptCompilationException;
-import org.gradle.groovy.scripts.ScriptSource;
-import org.gradle.groovy.scripts.StringScriptSource;
-import org.gradle.groovy.scripts.Transformer;
-import org.gradle.internal.Actions;
-import org.gradle.internal.resource.Resource;
-import org.gradle.internal.serialize.BaseSerializerFactory;
-import org.gradle.internal.serialize.Serializer;
-import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider;
-import org.jmock.Expectations;
-import org.jmock.integration.junit4.JMock;
-import org.jmock.integration.junit4.JUnit4Mockery;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.gradle.util.Matchers.containsLine;
-import static org.gradle.util.Matchers.isA;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
- at RunWith(JMock.class)
-public class DefaultScriptCompilationHandlerTest {
-
- static final String TEST_EXPECTED_SYSTEMPROP_VALUE = "somevalue";
- static final String TEST_EXPECTED_SYSTEMPROP_KEY = "somekey";
-
- private DefaultScriptCompilationHandler scriptCompilationHandler;
-
- private File scriptCacheDir;
- private File metadataCacheDir;
- private File cachedFile;
-
- private ScriptSource scriptSource;
- private String scriptText;
- private String scriptClassName;
- private String scriptFileName;
- private String classpathClosureName;
-
- private ClassLoader classLoader;
-
- private Action<ClassNode> verifier = Actions.doNothing();
-
- private Class<? extends Script> expectedScriptClass;
-
- private ImportsReader importsReader;
-
- private JUnit4Mockery context = new JUnit4Mockery();
- @Rule
- public TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider();
- private final ClassLoaderId classLoaderId = ClassLoaderIds.buildScript("foo", "bar");
-
- @Before
- public void setUp() throws IOException, ClassNotFoundException {
- File testProjectDir = tmpDir.createDir("projectDir");
- classLoader = getClass().getClassLoader();
- importsReader = context.mock(ImportsReader.class);
- context.checking(new Expectations() {{
- allowing(importsReader).getImportPackages();
- will(returnValue(new String[0]));
- }});
- scriptCompilationHandler = new DefaultScriptCompilationHandler(new AsmBackedEmptyScriptGenerator(), new DummyClassLoaderCache(), importsReader);
- scriptCacheDir = new File(testProjectDir, "cache");
- metadataCacheDir = new File(testProjectDir, "metadata");
- scriptText = "System.setProperty('" + TEST_EXPECTED_SYSTEMPROP_KEY + "', '" + TEST_EXPECTED_SYSTEMPROP_VALUE
- + "')";
-
- scriptClassName = "ScriptClassName";
- scriptFileName = "script-file-name";
- classpathClosureName = "buildscript";
- scriptSource = scriptSource();
- cachedFile = new File(scriptCacheDir, scriptClassName + ".class");
- expectedScriptClass = TestBaseScript.class;
- }
-
- private ScriptSource scriptSource() {
- return scriptSource(scriptText);
- }
-
- private ScriptSource scriptSource(final String scriptText) {
- final ScriptSource source = context.mock(ScriptSource.class, scriptText);
- context.checking(new Expectations() {{
- Resource resource = context.mock(Resource.class, scriptText + "resource");
-
- allowing(source).getClassName();
- will(returnValue(scriptClassName));
- allowing(source).getFileName();
- will(returnValue(scriptFileName));
- allowing(source).getDisplayName();
- will(returnValue("script-display-name"));
- allowing(source).getResource();
- will(returnValue(resource));
- allowing(resource).getText();
- will(returnValue(scriptText));
- }});
- return source;
- }
-
- @After
- public void tearDown() {
- System.getProperties().remove(TEST_EXPECTED_SYSTEMPROP_KEY);
- }
-
- @Test
- public void testCompileScriptToDir() throws Exception {
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
-
- checkScriptClassesInCache();
-
- CompiledScript<? extends Script, Void> compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId);
-
- Script script = compiledScript.loadClass().newInstance();
- evaluateScript(script);
- }
-
- @Test
- public void testCompileScriptToDirWithPackageDeclaration() throws Exception {
- final ScriptSource scriptSource = scriptSource("package org.gradle.test\n" + scriptText);
-
- try {
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
- fail();
- } catch (UnsupportedOperationException e) {
- assertThat(e.getMessage(), equalTo("Script-display-name should not contain a package statement."));
- }
- }
-
- @Test
- public void testCompileScriptToDirWithWhitespaceOnly() throws Exception {
- final ScriptSource scriptSource = scriptSource("// ignore me\n");
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
-
- checkEmptyScriptInCache();
-
- CompiledScript<? extends Script, Void> compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId);
-
- Script script = compiledScript.loadClass().newInstance();
- assertThat(script, isA(expectedScriptClass));
- }
-
- @Test
- public void testCompileScriptToDirWithEmptyScript() throws Exception {
- final ScriptSource scriptSource = scriptSource("");
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
-
- checkEmptyScriptInCache();
-
- CompiledScript<? extends Script, Void> compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId);
-
- Script script = compiledScript.loadClass().newInstance();
- assertThat(script, isA(expectedScriptClass));
- }
-
- @Test
- public void testCompileScriptToDirWithClassDefinitionOnlyScript() throws Exception {
- final ScriptSource scriptSource = scriptSource("class SomeClass {}");
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
-
- checkEmptyScriptInCache();
-
- CompiledScript<? extends Script, Void> compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId);
-
- Script script = compiledScript.loadClass().newInstance();
- assertThat(script, isA(expectedScriptClass));
- }
-
- @Test
- public void testCompileScriptToDirWithMethodOnlyScript() throws Exception {
- final ScriptSource scriptSource = scriptSource("def method() { println 'hi' }");
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
-
- checkScriptClassesInCache();
-
- CompiledScript<? extends Script, Void> compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId);
-
- Script script = compiledScript.loadClass().newInstance();
- assertThat(script, isA(expectedScriptClass));
- }
-
- @Test
- public void testCompileScriptToDirWithPropertiesOnlyScript() throws Exception {
- final ScriptSource scriptSource = scriptSource("String a");
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
-
- checkScriptClassesInCache();
-
- CompiledScript<? extends Script, Void> compiledScript = scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId);
-
- Script script = compiledScript.loadClass().newInstance();
- assertThat(script, isA(expectedScriptClass));
- }
-
- @Test
- public void testLoadFromDirWhenNotAssignableToBaseClass() {
- scriptCompilationHandler.compileToDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, Script.class, verifier);
- try {
- scriptCompilationHandler.loadFromDir(scriptSource, classLoader, scriptCacheDir, metadataCacheDir, null, expectedScriptClass, classLoaderId).loadClass();
- fail();
- } catch (GradleException e) {
- assertThat(e.getMessage(), containsString("Could not load compiled classes for script-display-name from cache."));
- assertThat(e.getCause(), instanceOf(ClassCastException.class));
- }
- }
-
- @Test
- public void testCompileToDirWithSyntaxError() {
- ScriptSource source = new StringScriptSource("script.gradle", "\n\nnew HHHHJSJSJ jsj");
- try {
- scriptCompilationHandler.compileToDir(source, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
- fail();
- } catch (ScriptCompilationException e) {
- assertThat(e.getScriptSource(), sameInstance(source));
- assertThat(e.getLineNumber(), equalTo(3));
- assertThat(e.getCause().getMessage(), containsLine(startsWith("script.gradle: 3: unexpected token: jsj")));
- }
-
- checkScriptCacheEmpty();
- }
-
- @Test
- public void testCanVisitAndTransformScriptClass() throws Exception {
- final Transformer visitor = new AbstractScriptTransformer() {
- protected int getPhase() {
- return Phases.CANONICALIZATION;
- }
-
- @Override
- public void call(SourceUnit source) throws CompilationFailedException {
- source.getAST().getStatementBlock().visit(new CodeVisitorSupport() {
- @Override
- public void visitMethodCallExpression(MethodCallExpression call) {
- call.setObjectExpression(new ClassExpression(ClassHelper.make(System.class)));
- call.setMethod(new ConstantExpression("setProperty"));
- ArgumentListExpression arguments = (ArgumentListExpression) call.getArguments();
- arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_KEY));
- arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_VALUE));
- }
- });
- }
- };
-
- CompileOperation<?> transformer = new CompileOperation<Boolean>() {
- @Override
- public String getId() {
- return "id";
- }
-
- @Override
- public Transformer getTransformer() {
- return visitor;
- }
-
- @Override
- public Boolean getExtractedData() {
- return true;
- }
-
- @Override
- public Serializer<Boolean> getDataSerializer() {
- return BaseSerializerFactory.BOOLEAN_SERIALIZER;
- }
- };
-
- ScriptSource source = scriptSource("transformMe()");
- scriptCompilationHandler.compileToDir(source, classLoader, scriptCacheDir, metadataCacheDir, transformer, classpathClosureName, expectedScriptClass, verifier);
- Script script = scriptCompilationHandler.loadFromDir(source, classLoader, scriptCacheDir, metadataCacheDir, transformer, expectedScriptClass, classLoaderId).loadClass().newInstance();
- evaluateScript(script);
- }
-
- @Test
- public void testCanVisitAndTransformGeneratedClasses() throws Exception {
- final Action<ClassNode> verifier = context.mock(Action.class);
- context.checking(new Expectations() {{
- one(verifier).execute(with(notNullValue(ClassNode.class)));
- }});
-
- ScriptSource source = scriptSource("transformMe()");
- scriptCompilationHandler.compileToDir(source, classLoader, scriptCacheDir, metadataCacheDir, null, classpathClosureName, expectedScriptClass, verifier);
- }
-
- private void checkScriptClassesInCache() {
- assertTrue(scriptCacheDir.isDirectory());
- assertTrue(cachedFile.isFile());
- assertFalse(new File(scriptCacheDir, "emptyScript.txt").exists());
- }
-
- private void checkEmptyScriptInCache() {
- assertTrue(scriptCacheDir.isDirectory());
- assertTrue(new File(scriptCacheDir, "emptyScript.txt").isFile());
- }
-
- private void checkScriptCacheEmpty() {
- assertFalse(scriptCacheDir.exists());
- }
-
- private void evaluateScript(Script script) {
- assertThat(script, instanceOf(expectedScriptClass));
- assertEquals(script.getClass().getSimpleName(), scriptClassName);
- System.setProperty(TEST_EXPECTED_SYSTEMPROP_KEY, "not the expected value");
- script.run();
- assertEquals(TEST_EXPECTED_SYSTEMPROP_VALUE, System.getProperty(TEST_EXPECTED_SYSTEMPROP_KEY));
- }
-
- public abstract static class TestBaseScript extends Script {
- }
-}
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactoryTest.java b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactoryTest.java
index cf93f5d..412f3a4 100644
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactoryTest.java
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/DefaultScriptRunnerFactoryTest.java
@@ -21,6 +21,7 @@ import org.gradle.groovy.scripts.ScriptExecutionListener;
import org.gradle.groovy.scripts.ScriptRunner;
import org.gradle.groovy.scripts.ScriptSource;
import org.gradle.internal.reflect.Instantiator;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.logging.StandardOutputCapture;
import org.hamcrest.Description;
import org.jmock.Expectations;
@@ -50,41 +51,50 @@ public class DefaultScriptRunnerFactoryTest {
private final ScriptSource scriptSourceDummy = context.mock(ScriptSource.class);
private final ScriptExecutionListener scriptExecutionListenerMock = context.mock(ScriptExecutionListener.class);
private final Instantiator instantiatorMock = context.mock(Instantiator.class);
+ private final Object target = new Object();
+ private final ServiceRegistry scriptServices = context.mock(ServiceRegistry.class);
private final DefaultScriptRunnerFactory factory = new DefaultScriptRunnerFactory(scriptExecutionListenerMock, instantiatorMock);
@Before
public void setUp() {
context.checking(new Expectations() {{
- allowing(compiledScriptMock).loadClass();
- will(returnValue(Script.class));
- allowing(instantiatorMock).newInstance(Script.class);
- will(returnValue(scriptMock));
- allowing(scriptMock).getStandardOutputCapture();
- will(returnValue(standardOutputCaptureMock));
- allowing(scriptMock).getScriptSource();
- will(returnValue(scriptSourceDummy));
- allowing(scriptMock).getContextClassloader();
- will(returnValue(classLoaderDummy));
- allowing(scriptMock).setScriptSource(scriptSourceDummy);
- allowing(scriptMock).setContextClassloader(classLoaderDummy);
ignoring(scriptSourceDummy);
}});
}
@Test
- public void createsScriptRunner() {
+ public void doesNotLoadScriptWhenScriptRunnerCreated() {
ScriptRunner<?, Void> scriptRunner = factory.create(compiledScriptMock, scriptSourceDummy, classLoaderDummy);
- assertThat(scriptRunner.getScript(), sameInstance(scriptRunner.getScript()));
+ assertThat(scriptRunner, notNullValue());
}
@Test
- public void redirectsStandardOutputAndSetsContextClassLoaderWhenScriptIsRun() {
+ public void runDoesNothingWhenEmptyScriptIsRun() {
ScriptRunner<?, Void> scriptRunner = factory.create(compiledScriptMock, scriptSourceDummy, classLoaderDummy);
context.checking(new Expectations() {{
+ allowing(compiledScriptMock).getRunDoesSomething();
+ will(returnValue(false));
+ }});
+
+ scriptRunner.run(target, scriptServices);
+ }
+
+ @Test
+ public void setsUpAndTearsDownWhenNonEmptyScriptIsRun() {
+ ScriptRunner<?, Void> scriptRunner = factory.create(compiledScriptMock, scriptSourceDummy, classLoaderDummy);
+
+ expectScriptInstantiated();
+ context.checking(new Expectations() {{
Sequence sequence = context.sequence("seq");
- one(scriptExecutionListenerMock).beforeScript(scriptMock);
+ allowing(compiledScriptMock).getRunDoesSomething();
+ will(returnValue(true));
+
+ one(scriptExecutionListenerMock).scriptClassLoaded(scriptSourceDummy, Script.class);
+ inSequence(sequence);
+
+ one(scriptMock).init(target, scriptServices);
inSequence(sequence);
one(standardOutputCaptureMock).start();
@@ -105,15 +115,12 @@ public class DefaultScriptRunnerFactoryTest {
one(standardOutputCaptureMock).stop();
inSequence(sequence);
-
- one(scriptExecutionListenerMock).afterScript(scriptMock, null);
- inSequence(sequence);
}});
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
assertThat(originalClassLoader, not(sameInstance(classLoaderDummy)));
- scriptRunner.run();
+ scriptRunner.run(target, scriptServices);
assertThat(Thread.currentThread().getContextClassLoader(), sameInstance(originalClassLoader));
}
@@ -124,10 +131,17 @@ public class DefaultScriptRunnerFactoryTest {
ScriptRunner<?, Void> scriptRunner = factory.create(compiledScriptMock, scriptSourceDummy, classLoaderDummy);
+ expectScriptInstantiated();
context.checking(new Expectations() {{
Sequence sequence = context.sequence("seq");
- one(scriptExecutionListenerMock).beforeScript(scriptMock);
+ allowing(compiledScriptMock).getRunDoesSomething();
+ will(returnValue(true));
+
+ one(scriptExecutionListenerMock).scriptClassLoaded(scriptSourceDummy, Script.class);
+ inSequence(sequence);
+
+ one(scriptMock).init(target, scriptServices);
inSequence(sequence);
one(standardOutputCaptureMock).start();
@@ -139,16 +153,13 @@ public class DefaultScriptRunnerFactoryTest {
one(standardOutputCaptureMock).stop();
inSequence(sequence);
-
- one(scriptExecutionListenerMock).afterScript(with(sameInstance(scriptMock)), with(notNullValue(Throwable.class)));
- inSequence(sequence);
}});
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
assertThat(originalClassLoader, not(sameInstance(classLoaderDummy)));
try {
- scriptRunner.run();
+ scriptRunner.run(target, scriptServices);
fail();
} catch (GradleScriptException e) {
assertThat(e.getMessage(), equalTo("A problem occurred evaluating <script-to-string>."));
@@ -157,4 +168,22 @@ public class DefaultScriptRunnerFactoryTest {
assertThat(Thread.currentThread().getContextClassLoader(), sameInstance(originalClassLoader));
}
+
+ void expectScriptInstantiated() {
+ context.checking(new Expectations() {{
+ allowing(compiledScriptMock).loadClass();
+ will(returnValue(Script.class));
+ allowing(instantiatorMock).newInstance(Script.class);
+ will(returnValue(scriptMock));
+ allowing(scriptMock).getStandardOutputCapture();
+ will(returnValue(standardOutputCaptureMock));
+ allowing(scriptMock).getScriptSource();
+ will(returnValue(scriptSourceDummy));
+ allowing(scriptMock).getContextClassloader();
+ will(returnValue(classLoaderDummy));
+ allowing(scriptMock).setScriptSource(scriptSourceDummy);
+ allowing(scriptMock).setContextClassloader(classLoaderDummy);
+ }});
+ }
+
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompilerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompilerTest.groovy
index d637283..d243f5d 100644
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompilerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/FileCacheBackedScriptClassCompilerTest.groovy
@@ -44,7 +44,6 @@ class FileCacheBackedScriptClassCompilerTest extends Specification {
final File metadataDir = new File(cacheDir, "metadata")
final FileCacheBackedScriptClassCompiler compiler = new FileCacheBackedScriptClassCompiler(cacheRepository, validator, scriptCompilationHandler, Stub(ProgressLoggerFactory))
final Action verifier = Stub()
- final String classpathClosureName = "buildscript"
final CompiledScript compiledScript = Stub() {
loadClass() >> Script
}
@@ -64,11 +63,11 @@ class FileCacheBackedScriptClassCompilerTest extends Specification {
def "loads classes from cache directory"() {
when:
- def result = compiler.compile(source, classLoader, classLoaderId, operation, classpathClosureName, Script, verifier).loadClass()
+ def result = compiler.compile(source, classLoader, classLoaderId, operation, Script, verifier).loadClass()
then:
result == Script
- 1 * cacheRepository.cache("scripts/ScriptClassName/Script/TransformerId") >> cacheBuilder
+ 1 * cacheRepository.cache("scripts/ScriptClassName/TransformerId") >> cacheBuilder
1 * cacheBuilder.withProperties(!null) >> { args ->
assert args[0].get('source.filename') == 'ScriptFileName'
assert args[0].containsKey('source.hash')
@@ -84,7 +83,7 @@ class FileCacheBackedScriptClassCompilerTest extends Specification {
def "passes CacheValidator to cacheBuilder"() {
setup:
- cacheRepository.cache("scripts/ScriptClassName/Script/TransformerId") >> cacheBuilder
+ cacheRepository.cache("scripts/ScriptClassName/TransformerId") >> cacheBuilder
cacheBuilder.withProperties(!null) >> cacheBuilder
cacheBuilder.withInitializer(!null) >> cacheBuilder
cacheBuilder.withDisplayName(!null) >> cacheBuilder
@@ -92,12 +91,10 @@ class FileCacheBackedScriptClassCompilerTest extends Specification {
scriptCompilationHandler.loadFromDir(source, classLoader, classesDir, metadataDir, operation, Script, classLoaderId) >> compiledScript
when:
- compiler.compile(source, classLoader, classLoaderId, operation, classpathClosureName, Script, verifier)
+ compiler.compile(source, classLoader, classLoaderId, operation, Script, verifier)
then:
1 * cacheBuilder.withValidator(validator) >> cacheBuilder
-
-
}
def "compiles classes to cache directory when cache is invalid"() {
@@ -106,17 +103,17 @@ class FileCacheBackedScriptClassCompilerTest extends Specification {
def metadataDir = new File(cacheDir, "metadata")
when:
- def result = compiler.compile(source, classLoader, classLoaderId, operation, classpathClosureName, Script, verifier).loadClass()
+ def result = compiler.compile(source, classLoader, classLoaderId, operation, Script, verifier).loadClass()
then:
result == Script
- 1 * cacheRepository.cache("scripts/ScriptClassName/Script/TransformerId") >> cacheBuilder
+ 1 * cacheRepository.cache("scripts/ScriptClassName/TransformerId") >> cacheBuilder
1 * cacheBuilder.withProperties(!null) >> cacheBuilder
1 * cacheBuilder.withDisplayName(!null) >> cacheBuilder
1 * cacheBuilder.withValidator(!null) >> cacheBuilder
1 * cacheBuilder.withInitializer(!null) >> { args -> initializer = args[0]; return cacheBuilder }
1 * cacheBuilder.open() >> { initializer.execute(cache); return cache }
- 1 * scriptCompilationHandler.compileToDir(source, classLoader, classesDir, metadataDir, operation, classpathClosureName, Script, verifier)
+ 1 * scriptCompilationHandler.compileToDir(source, classLoader, classesDir, metadataDir, operation, Script, verifier)
1 * scriptCompilationHandler.loadFromDir(source, classLoader, classesDir, metadataDir, operation, Script, classLoaderId) >> compiledScript
0 * scriptCompilationHandler._
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompilerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompilerTest.groovy
index deff095..6359c3c 100644
--- a/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompilerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/groovy/scripts/internal/ShortCircuitEmptyScriptCompilerTest.groovy
@@ -20,12 +20,10 @@ import org.gradle.api.internal.initialization.ClassLoaderIds
import org.gradle.api.internal.initialization.loadercache.ClassLoaderCache
import org.gradle.groovy.scripts.Script
import org.gradle.groovy.scripts.ScriptSource
-import org.gradle.groovy.scripts.TestScript
import org.gradle.internal.resource.Resource
import spock.lang.Specification
class ShortCircuitEmptyScriptCompilerTest extends Specification {
- final EmptyScriptGenerator emptyScriptGenerator = Mock()
final ScriptClassCompiler target = Mock()
final ScriptSource source = Mock()
final Resource resource = Mock()
@@ -33,8 +31,7 @@ class ShortCircuitEmptyScriptCompilerTest extends Specification {
final CompileOperation<?> operation = Mock()
final Action verifier = Mock()
final classLoaderCache = Mock(ClassLoaderCache)
- final ShortCircuitEmptyScriptCompiler compiler = new ShortCircuitEmptyScriptCompiler(target, emptyScriptGenerator, classLoaderCache)
- String classpathClosureName = "buildscript"
+ final ShortCircuitEmptyScriptCompiler compiler = new ShortCircuitEmptyScriptCompiler(target, classLoaderCache)
def loaderId = ClassLoaderIds.buildScript(source.getFileName(), operation.getId())
def setup() {
@@ -49,16 +46,15 @@ class ShortCircuitEmptyScriptCompilerTest extends Specification {
when:
- def compiledScript = compiler.compile(source, classLoader, loaderId, operation, classpathClosureName, Script, verifier)
- def scriptClass = compiledScript.loadClass()
+ def compiledScript = compiler.compile(source, classLoader, loaderId, operation, Script, verifier)
then:
- scriptClass == TestScript
+ !compiledScript.runDoesSomething
+ !compiledScript.hasMethods
compiledScript.data == metadata
- 1 * emptyScriptGenerator.generate(Script) >> TestScript
- 0 * emptyScriptGenerator._
+
+ and:
0 * target._
- 1 * classLoaderCache.remove(loaderId)
}
def "compiles script when script contains anything other than whitespace"() {
@@ -67,12 +63,11 @@ class ShortCircuitEmptyScriptCompilerTest extends Specification {
CompiledScript<?> compiledScript = Mock()
when:
- def result = compiler.compile(source, classLoader, ClassLoaderIds.buildScript(source.getFileName(), operation.getId()), operation, classpathClosureName, Script, verifier)
+ def result = compiler.compile(source, classLoader, ClassLoaderIds.buildScript(source.getFileName(), operation.getId()), operation, Script, verifier)
then:
result == compiledScript
- 1 * target.compile(source, classLoader, ClassLoaderIds.buildScript(source.getFileName(), operation.getId()), operation, classpathClosureName, Script, verifier) >> compiledScript
- 0 * emptyScriptGenerator._
+ 1 * target.compile(source, classLoader, ClassLoaderIds.buildScript(source.getFileName(), operation.getId()), operation, Script, verifier) >> compiledScript
0 * target._
0 * classLoaderCache._
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultExceptionAnalyserTest.java b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultExceptionAnalyserTest.java
index 4e9ffec..c017a5a 100755
--- a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultExceptionAnalyserTest.java
+++ b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultExceptionAnalyserTest.java
@@ -245,12 +245,7 @@ public class DefaultExceptionAnalyserTest {
}
private void notifyAnalyser(DefaultExceptionAnalyser analyser, final ScriptSource source) {
- final Script script = context.mock(Script.class);
- context.checking(new Expectations() {{
- allowing(script).getScriptSource();
- will(returnValue(source));
- }});
- analyser.beforeScript(script);
+ analyser.scriptClassLoaded(source, Script.class);
}
private DefaultExceptionAnalyser analyser() {
diff --git a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherFactoryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherFactoryTest.groovy
index 6f9c533..5759c83 100644
--- a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherFactoryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherFactoryTest.groovy
@@ -18,14 +18,16 @@ package org.gradle.initialization
import org.gradle.StartParameter
import org.gradle.internal.service.DefaultServiceRegistry
import org.gradle.internal.service.ServiceRegistry
+import org.gradle.internal.service.scopes.BuildSessionScopeServices
import org.gradle.internal.service.scopes.GlobalScopeServices
import org.gradle.logging.LoggingServiceRegistry
import org.gradle.testfixtures.internal.NativeServicesTestFixture
import spock.lang.Specification
class DefaultGradleLauncherFactoryTest extends Specification {
- final ServiceRegistry sharedServices = new DefaultServiceRegistry(LoggingServiceRegistry.newEmbeddableLogging(), NativeServicesTestFixture.getInstance()).addProvider(new GlobalScopeServices(false))
- final DefaultGradleLauncherFactory factory = new DefaultGradleLauncherFactory(sharedServices)
+ final ServiceRegistry globalServices = new DefaultServiceRegistry(LoggingServiceRegistry.newEmbeddableLogging(), NativeServicesTestFixture.getInstance()).addProvider(new GlobalScopeServices(false))
+ final ServiceRegistry sessionServices = new BuildSessionScopeServices(globalServices)
+ final DefaultGradleLauncherFactory factory = new DefaultGradleLauncherFactory(globalServices)
def "makes services from build context available as build scoped services"() {
def startParameter = new StartParameter()
@@ -37,7 +39,7 @@ class DefaultGradleLauncherFactoryTest extends Specification {
}
expect:
- def launcher = factory.newInstance(startParameter, requestContext)
+ def launcher = factory.newInstance(startParameter, requestContext, sessionServices)
launcher.gradle.parent == null
launcher.gradle.startParameter == startParameter
launcher.gradle.services.get(BuildRequestMetaData) == requestContext
@@ -67,7 +69,7 @@ class DefaultGradleLauncherFactoryTest extends Specification {
getEventConsumer() >> eventConsumer
}
- def parent = factory.newInstance(startParameter, requestContext);
+ def parent = factory.newInstance(startParameter, requestContext, sessionServices);
parent.buildListener.buildStarted(parent.gradle)
expect:
diff --git a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherTest.java b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherTest.java
index 777661a..9cfec12 100644
--- a/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherTest.java
+++ b/subprojects/core/src/test/groovy/org/gradle/initialization/DefaultGradleLauncherTest.java
@@ -27,11 +27,12 @@ import org.gradle.api.internal.file.TestFiles;
import org.gradle.api.internal.initialization.ClassLoaderScope;
import org.gradle.api.internal.project.DefaultProject;
import org.gradle.configuration.BuildConfigurer;
+import org.gradle.execution.BuildConfigurationActionExecuter;
import org.gradle.execution.BuildExecuter;
import org.gradle.execution.TaskGraphExecuter;
import org.gradle.internal.Factory;
+import org.gradle.internal.progress.BuildOperationDetails;
import org.gradle.internal.progress.BuildOperationExecutor;
-import org.gradle.internal.progress.BuildOperationType;
import org.gradle.logging.LoggingManagerInternal;
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider;
import org.gradle.util.JUnit4GroovyMockery;
@@ -56,9 +57,8 @@ import static org.junit.Assert.fail;
@RunWith(org.jmock.integration.junit4.JMock.class)
public class DefaultGradleLauncherTest {
- private BuildLoader buildLoaderMock;
private InitScriptHandler initScriptHandlerMock;
- private SettingsHandler settingsHandlerMock;
+ private SettingsLoader settingsLoaderMock;
private BuildConfigurer buildConfigurerMock;
private DefaultProject expectedRootProject;
private DefaultProject expectedCurrentProject;
@@ -66,6 +66,7 @@ public class DefaultGradleLauncherTest {
private StartParameter expectedStartParams;
private GradleInternal gradleMock;
private BuildListener buildBroadcaster;
+ private BuildConfigurationActionExecuter buildConfigurationActionExecuter;
private BuildExecuter buildExecuter;
private GradleLauncher gradleLauncher;
@@ -74,15 +75,12 @@ public class DefaultGradleLauncherTest {
private ProjectDescriptor expectedRootProjectDescriptor;
- private ProjectDescriptor expectedDefaultProjectDescriptor;
-
private JUnit4Mockery context = new JUnit4GroovyMockery();
private ClassLoaderScope baseClassLoaderScope = context.mock(ClassLoaderScope.class);
private ExceptionAnalyser exceptionAnalyserMock = context.mock(ExceptionAnalyser.class);
private LoggingManagerInternal loggingManagerMock = context.mock(LoggingManagerInternal.class);
private ModelConfigurationListener modelListenerMock = context.mock(ModelConfigurationListener.class);
- private TasksCompletionListener tasksCompletionListener = context.mock(TasksCompletionListener.class);
private BuildCompletionListener buildCompletionListener = context.mock(BuildCompletionListener.class);
private BuildOperationExecutor buildOperationExecutor = new TestBuildOperationExecutor();
private Closeable buildServices = context.mock(Closeable.class);
@@ -91,14 +89,14 @@ public class DefaultGradleLauncherTest {
@Before
public void setUp() {
initScriptHandlerMock = context.mock(InitScriptHandler.class);
- settingsHandlerMock = context.mock(SettingsHandler.class);
+ settingsLoaderMock = context.mock(SettingsHandler.class);
settingsMock = context.mock(SettingsInternal.class);
taskExecuterMock = context.mock(TaskGraphExecuter.class);
- buildLoaderMock = context.mock(BuildLoader.class);
buildConfigurerMock = context.mock(BuildConfigurer.class);
gradleMock = context.mock(GradleInternal.class);
buildBroadcaster = context.mock(BuildListener.class);
buildExecuter = context.mock(BuildExecuter.class);
+ buildConfigurationActionExecuter = context.mock(BuildConfigurationActionExecuter.class);
boolean expectedSearchUpwards = false;
File expectedRootDir = tmpDir.file("rootDir");
@@ -107,8 +105,6 @@ public class DefaultGradleLauncherTest {
expectedRootProjectDescriptor = new DefaultProjectDescriptor(null, "someName", new File("somedir"), new DefaultProjectDescriptorRegistry(),
TestFiles.resolver(expectedRootDir));
expectedRootProject = TestUtil.createRootProject(expectedRootDir);
- expectedDefaultProjectDescriptor = new DefaultProjectDescriptor(null, "default", new File("default"), new DefaultProjectDescriptorRegistry(),
- TestFiles.resolver(expectedCurrentDir));
expectedCurrentProject = TestUtil.createRootProject(expectedCurrentDir);
expectedStartParams = new StartParameter();
@@ -116,9 +112,9 @@ public class DefaultGradleLauncherTest {
expectedStartParams.setSearchUpwards(expectedSearchUpwards);
expectedStartParams.setGradleUserHomeDir(tmpDir.createDir("gradleUserHome"));
- gradleLauncher = new DefaultGradleLauncher(gradleMock, initScriptHandlerMock, settingsHandlerMock,
- buildLoaderMock, buildConfigurerMock, exceptionAnalyserMock, loggingManagerMock, buildBroadcaster,
- modelListenerMock, tasksCompletionListener, buildCompletionListener, buildOperationExecutor, buildExecuter,
+ gradleLauncher = new DefaultGradleLauncher(gradleMock, initScriptHandlerMock, settingsLoaderMock,
+ buildConfigurerMock, exceptionAnalyserMock, loggingManagerMock, buildBroadcaster,
+ modelListenerMock, buildCompletionListener, buildOperationExecutor, buildConfigurationActionExecuter, buildExecuter,
buildServices);
context.checking(new Expectations() {
@@ -161,7 +157,6 @@ public class DefaultGradleLauncherTest {
expectSettingsBuilt();
expectBuildListenerCallbacks();
context.checking(new Expectations() {{
- one(buildLoaderMock).load(expectedRootProjectDescriptor, expectedDefaultProjectDescriptor, gradleMock, baseClassLoaderScope);
one(buildConfigurerMock).configure(gradleMock);
}});
BuildResult buildResult = gradleLauncher.getBuildAnalysis();
@@ -175,10 +170,9 @@ public class DefaultGradleLauncherTest {
final RuntimeException transformedException = new RuntimeException();
expectLoggingStarted();
expectInitScriptsExecuted();
- expectSettingsBuilt();
context.checking(new Expectations() {{
one(buildBroadcaster).buildStarted(gradleMock);
- one(buildLoaderMock).load(expectedRootProjectDescriptor, expectedDefaultProjectDescriptor, gradleMock, baseClassLoaderScope);
+ one(settingsLoaderMock).findAndLoadSettings(gradleMock);
will(throwException(exception));
one(exceptionAnalyserMock).transform(exception);
will(returnValue(transformedException));
@@ -199,7 +193,6 @@ public class DefaultGradleLauncherTest {
expectSettingsBuilt();
expectBuildListenerCallbacks();
context.checking(new Expectations() {{
- one(buildLoaderMock).load(expectedRootProjectDescriptor, expectedDefaultProjectDescriptor, gradleMock, baseClassLoaderScope);
one(buildConfigurerMock).configure(gradleMock);
}});
@@ -219,6 +212,27 @@ public class DefaultGradleLauncherTest {
}
@Test
+ public void testNotifiesListenerOnBuildListenerFailure() {
+ final RuntimeException failure = new RuntimeException();
+ final RuntimeException transformedException = new RuntimeException();
+ expectLoggingStarted();
+ context.checking(new Expectations() {{
+ one(buildBroadcaster).buildStarted(gradleMock);
+ will(throwException(failure));
+ one(exceptionAnalyserMock).transform(failure);
+ will(returnValue(transformedException));
+ one(buildBroadcaster).buildFinished(with(result(sameInstance(transformedException))));
+ }});
+
+ try {
+ gradleLauncher.run();
+ fail();
+ } catch (ReportedException e) {
+ assertThat((RuntimeException) e.getCause(), sameInstance(transformedException));
+ }
+ }
+
+ @Test
public void testNotifiesListenerOnSettingsInitWithFailure() {
final RuntimeException failure = new RuntimeException();
final RuntimeException transformedException = new RuntimeException();
@@ -226,7 +240,7 @@ public class DefaultGradleLauncherTest {
expectInitScriptsExecuted();
context.checking(new Expectations() {{
one(buildBroadcaster).buildStarted(gradleMock);
- one(settingsHandlerMock).findAndLoadSettings(gradleMock);
+ one(settingsLoaderMock).findAndLoadSettings(gradleMock);
will(throwException(failure));
one(exceptionAnalyserMock).transform(failure);
will(returnValue(transformedException));
@@ -252,7 +266,6 @@ public class DefaultGradleLauncherTest {
expectTasksRunWithFailure(failure);
context.checking(new Expectations() {{
one(buildBroadcaster).buildStarted(gradleMock);
- one(buildBroadcaster).projectsLoaded(gradleMock);
one(buildBroadcaster).projectsEvaluated(gradleMock);
one(modelListenerMock).onConfigure(gradleMock);
one(exceptionAnalyserMock).transform(failure);
@@ -294,9 +307,8 @@ public class DefaultGradleLauncherTest {
private void expectSettingsBuilt() {
context.checking(new Expectations() {
{
- one(settingsHandlerMock).findAndLoadSettings(gradleMock);
+ one(settingsLoaderMock).findAndLoadSettings(gradleMock);
will(returnValue(settingsMock));
- one(buildBroadcaster).settingsEvaluated(settingsMock);
}
});
}
@@ -305,7 +317,6 @@ public class DefaultGradleLauncherTest {
context.checking(new Expectations() {
{
one(buildBroadcaster).buildStarted(gradleMock);
- one(buildBroadcaster).projectsLoaded(gradleMock);
one(buildBroadcaster).projectsEvaluated(gradleMock);
one(buildBroadcaster).buildFinished(with(result(nullValue(Throwable.class))));
one(modelListenerMock).onConfigure(gradleMock);
@@ -316,9 +327,8 @@ public class DefaultGradleLauncherTest {
private void expectDagBuilt() {
context.checking(new Expectations() {
{
- one(buildLoaderMock).load(expectedRootProjectDescriptor, expectedDefaultProjectDescriptor, gradleMock, baseClassLoaderScope);
one(buildConfigurerMock).configure(gradleMock);
- one(buildExecuter).select(gradleMock);
+ one(buildConfigurationActionExecuter).select(gradleMock);
}
});
}
@@ -326,8 +336,7 @@ public class DefaultGradleLauncherTest {
private void expectTasksRun() {
context.checking(new Expectations() {
{
- one(buildExecuter).execute();
- one(tasksCompletionListener).onTasksFinished(gradleMock);
+ one(buildExecuter).execute(gradleMock);
}
});
}
@@ -335,7 +344,7 @@ public class DefaultGradleLauncherTest {
private void expectTasksRunWithFailure(final Throwable failure) {
context.checking(new Expectations() {
{
- one(buildExecuter).execute();
+ one(buildExecuter).execute(gradleMock);
will(throwException(failure));
}
});
@@ -361,12 +370,22 @@ public class DefaultGradleLauncherTest {
}
@Override
- public <T> T run(Object id, BuildOperationType operationType, Factory<T> factory) {
+ public <T> T run(BuildOperationDetails operationDetails, Factory<T> factory) {
return factory.create();
}
@Override
- public void run(Object id, BuildOperationType operationType, Runnable action) {
+ public <T> T run(String displayName, Factory<T> factory) {
+ return factory.create();
+ }
+
+ @Override
+ public void run(BuildOperationDetails operationDetails, Runnable action) {
+ action.run();
+ }
+
+ @Override
+ public void run(String displayName, Runnable action) {
action.run();
}
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/initialization/InitScriptHandlerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/initialization/InitScriptHandlerTest.groovy
index 132cdb9..d92a374 100644
--- a/subprojects/core/src/test/groovy/org/gradle/initialization/InitScriptHandlerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/initialization/InitScriptHandlerTest.groovy
@@ -19,6 +19,8 @@ import org.gradle.StartParameter
import org.gradle.api.internal.GradleInternal
import org.gradle.configuration.InitScriptProcessor
import org.gradle.groovy.scripts.UriScriptSource
+import org.gradle.internal.progress.BuildOperationDetails
+import org.gradle.internal.progress.BuildOperationExecutor
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.junit.Rule
import spock.lang.Specification
@@ -27,28 +29,43 @@ class InitScriptHandlerTest extends Specification {
@Rule TestNameTestDirectoryProvider testDirectoryProvider
- final InitScriptProcessor processor = Mock()
- final GradleInternal gradle = Mock()
- final InitScriptHandler handler = new InitScriptHandler(processor)
-
+ def processor = Mock(InitScriptProcessor)
+ def executor = Mock(BuildOperationExecutor)
+ def gradle = Mock(GradleInternal)
+ def startParameter = Stub(StartParameter)
+ def handler = new InitScriptHandler(processor, executor)
+
+ def setup() {
+ _ * gradle.startParameter >> startParameter
+ }
+
+ def "does nothing when there are no init scripts"() {
+ given:
+ startParameter.allInitScripts >> []
+
+ when:
+ handler.executeScripts(gradle)
+
+ then:
+ 0 * executor._
+ 0 * processor._
+ }
+
def "finds and processes init scripts"() {
File script1 = testDirectoryProvider.createFile("script1.gradle")
File script2 = testDirectoryProvider.createFile("script2.gradle")
+ given:
+ startParameter.allInitScripts >> [script1, script2]
+
when:
handler.executeScripts(gradle)
then:
- _ * gradle.startParameter >> {
- Mock(StartParameter) {
- getAllInitScripts() >> {
- [script1, script2]
- }
- }
- }
-
+ 1 * executor.run(_, _) >> { BuildOperationDetails details, Runnable r -> r.run() }
1 * processor.process({ UriScriptSource source -> source.resource.file == script1 }, gradle)
1 * processor.process({ UriScriptSource source -> source.resource.file == script2 }, gradle)
- 0 * _._
+ 0 * executor._
+ 0 * processor._
}
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilderTest.groovy b/subprojects/core/src/test/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilderTest.groovy
index 1cfd3c5..3a1c0c6 100644
--- a/subprojects/core/src/test/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilderTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/initialization/buildsrc/BuildSourceBuilderTest.groovy
@@ -22,7 +22,10 @@ import org.gradle.cache.PersistentCache
import org.gradle.initialization.GradleLauncher
import org.gradle.initialization.GradleLauncherFactory
import org.gradle.internal.classpath.ClassPath
+import org.gradle.internal.progress.BuildOperationDetails
+import org.gradle.internal.progress.BuildOperationExecutor
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.gradle.internal.Factory
import org.junit.Rule
import spock.lang.Specification
@@ -30,16 +33,18 @@ class BuildSourceBuilderTest extends Specification {
@Rule TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()
- GradleLauncherFactory launcherFactory = Mock()
- ClassLoaderScope classLoaderScope = Mock()
- CacheRepository cacheRepository = Mock()
- BuildSourceBuilder buildSourceBuilder = Spy(BuildSourceBuilder, constructorArgs: [launcherFactory, classLoaderScope, cacheRepository])
+ def launcherFactory = Mock(GradleLauncherFactory)
+ def classLoaderScope = Mock(ClassLoaderScope)
+ def cacheRepository = Mock(CacheRepository)
+ def executor = Mock(BuildOperationExecutor)
+ def buildSourceBuilder = Spy(BuildSourceBuilder, constructorArgs: [launcherFactory, classLoaderScope, cacheRepository, executor])
- StartParameter parameter = new StartParameter()
+ def parameter = new StartParameter()
void "creates classpath when build src does not exist"() {
when:
- parameter.setCurrentDir(new File('nonexisting'));
+ parameter.setCurrentDir(new File('nonexisting'))
+
then:
buildSourceBuilder.createBuildSourceClasspath(parameter).asFiles == []
}
@@ -48,6 +53,7 @@ class BuildSourceBuilderTest extends Specification {
def cache = Mock(PersistentCache)
def classpath = Mock(ClassPath)
def launcher = Mock(GradleLauncher)
+ executor.run(_, _) >> { BuildOperationDetails details, Factory factory -> return factory.create() }
launcherFactory.newInstance(_) >> launcher
buildSourceBuilder.createCache(parameter) >> cache
cache.useCache(_ as String, _ as BuildSrcUpdateFactory) >> classpath
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/authentication/DefaultAuthenticationContainerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/authentication/DefaultAuthenticationContainerTest.groovy
new file mode 100644
index 0000000..5898670
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/authentication/DefaultAuthenticationContainerTest.groovy
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication
+import org.gradle.authentication.Authentication
+import org.gradle.internal.reflect.DirectInstantiator
+import spock.lang.Specification
+import spock.lang.Subject
+
+public class DefaultAuthenticationContainerTest extends Specification {
+ @Subject
+ def container = new DefaultAuthenticationContainer(DirectInstantiator.INSTANCE)
+
+ def setup() {
+ container.registerBinding(TestAuthentication, DefaultTestAuthentication)
+ container.registerBinding(CustomTestAuthentication, DefaultCustomTestAuthentication)
+ }
+
+ def "can add multiple authentication schemes with common supertype"() {
+ when:
+ container.create('auth1', auth1)
+ container.create('auth2', auth2)
+
+ then:
+ container.size() == 2
+
+ where:
+ auth1 | auth2
+ TestAuthentication | CustomTestAuthentication
+ CustomTestAuthentication | TestAuthentication
+ }
+
+ static interface TestAuthentication extends Authentication {}
+
+ static interface CustomTestAuthentication extends TestAuthentication {}
+
+ static class DefaultTestAuthentication extends AbstractAuthentication implements TestAuthentication {
+ DefaultTestAuthentication(String name) {
+ super(name, TestAuthentication)
+ }
+ DefaultTestAuthentication(String name, Class type) {
+ super(name, type)
+ }
+ }
+
+ static class DefaultCustomTestAuthentication extends DefaultTestAuthentication implements CustomTestAuthentication {
+ DefaultCustomTestAuthentication(String name) {
+ super(name, CustomTestAuthentication)
+ }
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporterTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporterTest.groovy
index 8613b91..79e9a5b 100644
--- a/subprojects/core/src/test/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporterTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/featurelifecycle/ScriptUsageLocationReporterTest.groovy
@@ -16,9 +16,9 @@
package org.gradle.internal.featurelifecycle
+import org.gradle.groovy.scripts.Script
import org.gradle.groovy.scripts.ScriptSource
import spock.lang.Specification
-import org.gradle.groovy.scripts.Script
class ScriptUsageLocationReporterTest extends Specification {
final reporter = new ScriptUsageLocationReporter()
@@ -44,9 +44,6 @@ class ScriptUsageLocationReporterTest extends Specification {
getFileName() >> "some-file.gradle"
getDisplayName() >> "build script 'some-file.gradle'"
}
- def script = Stub(Script) {
- getScriptSource() >> scriptSource
- }
def stack = [
new StackTraceElement("SomeClass", "method", "some-file.gradle", 12),
new StackTraceElement("SomeClass", "method", "some-file.gradle", 77)]
@@ -56,8 +53,7 @@ class ScriptUsageLocationReporterTest extends Specification {
def result = new StringBuilder()
given:
- reporter.beforeScript(script)
- reporter.afterScript(script, null)
+ reporter.scriptClassLoaded(scriptSource, Script)
when:
reporter.reportLocation(usage, result)
@@ -71,9 +67,6 @@ class ScriptUsageLocationReporterTest extends Specification {
getFileName() >> "some-file.gradle"
getDisplayName() >> "build script 'some-file.gradle'"
}
- def script = Stub(Script) {
- getScriptSource() >> scriptSource
- }
def stack = [
new StackTraceElement("SomeLibrary", "method", "SomeLibrary.java", 103),
new StackTraceElement("SomeLibrary", "method", "SomeLibrary.java", 67),
@@ -85,8 +78,7 @@ class ScriptUsageLocationReporterTest extends Specification {
def result = new StringBuilder()
given:
- reporter.beforeScript(script)
- reporter.afterScript(script, null)
+ reporter.scriptClassLoaded(scriptSource, Script)
when:
reporter.reportLocation(usage, result)
@@ -100,9 +92,6 @@ class ScriptUsageLocationReporterTest extends Specification {
getFileName() >> "some-file.gradle"
getDisplayName() >> "build script 'some-file.gradle'"
}
- def script = Stub(Script) {
- getScriptSource() >> scriptSource
- }
def stack = [
new StackTraceElement("SomeLibrary", "method", "SomeLibrary.java", 103),
new StackTraceElement("OtherLibrary", "method", "OtherLibrary.java", 67),
@@ -114,8 +103,7 @@ class ScriptUsageLocationReporterTest extends Specification {
def result = new StringBuilder()
given:
- reporter.beforeScript(script)
- reporter.afterScript(script, null)
+ reporter.scriptClassLoaded(scriptSource, Script)
when:
reporter.reportLocation(usage, result)
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/filewatch/DefaultFileWatcherFactoryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/filewatch/DefaultFileWatcherFactoryTest.groovy
index 4357b12..87cc23a 100644
--- a/subprojects/core/src/test/groovy/org/gradle/internal/filewatch/DefaultFileWatcherFactoryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/filewatch/DefaultFileWatcherFactoryTest.groovy
@@ -20,6 +20,7 @@ import org.gradle.api.Action
import org.gradle.api.internal.file.FileSystemSubset
import org.gradle.internal.Pair
import org.gradle.internal.concurrent.DefaultExecutorFactory
+import org.gradle.test.fixtures.ConcurrentTestUtil
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.testfixtures.internal.NativeServicesTestFixture
import org.gradle.util.Requires
@@ -29,7 +30,6 @@ import org.spockframework.lang.ConditionBlock
import spock.lang.AutoCleanup
import spock.lang.Specification
import spock.util.concurrent.BlockingVariable
-import spock.util.concurrent.PollingConditions
import java.util.concurrent.CountDownLatch
import java.util.concurrent.ExecutionException
@@ -45,7 +45,6 @@ class DefaultFileWatcherFactoryTest extends Specification {
@AutoCleanup("stop")
FileWatcher fileWatcher
- private PollingConditions poll = new PollingConditions()
Throwable thrownInWatchExecution
Action<? super Throwable> onError = {
@@ -252,7 +251,7 @@ class DefaultFileWatcherFactoryTest extends Specification {
@ConditionBlock
private void await(Closure<?> closure) {
- poll.within(waitForEventsMillis / 1000, closure)
+ ConcurrentTestUtil.poll(waitForEventsMillis / 1000 as int, closure)
}
private <T> BlockingVariable<T> blockingVar() {
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/graph/CachingDirectedGraphWalkerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/graph/CachingDirectedGraphWalkerTest.groovy
index 654e59c..ebf6848 100644
--- a/subprojects/core/src/test/groovy/org/gradle/internal/graph/CachingDirectedGraphWalkerTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/graph/CachingDirectedGraphWalkerTest.groovy
@@ -119,6 +119,25 @@ class CachingDirectedGraphWalkerTest extends Specification {
values == ['1', '1->1', '1->2', '2', '2->3', '2->4', '3', '3->2', '4'] as Set
}
+ def collectsValuesAndCyclesInComplexCyclicGraph() {
+ when:
+ walker.add(0)
+
+ and:
+ _ * graph.getNodeValues(0, _, _) >> { args -> args[2] << 4; args[2] << 1 }
+ _ * graph.getNodeValues(1, _, _) >> { args -> args[2] << 4; args[2] << 2 }
+ _ * graph.getNodeValues(2, _, _) >> { args -> args[2] << 1; args[2] << 3 }
+ _ * graph.getNodeValues(3, _, _) >> { args -> args[2] << 2 }
+ _ * graph.getNodeValues(4, _, _) >> { args -> args[2] << 5 }
+ _ * graph.getNodeValues(5, _, _) >> { args -> args[2] << 3 }
+
+ _ * graph.getEdgeValues(_, _, _) >> { args -> args[2] << "${args[0]}->${args[1]}".toString() }
+
+ then:
+ walker.findValues() == ['0->1', '0->4', '1->2', '1->4', '2->1', '2->3', '3->2', '4->5', '5->3'] as Set
+ walker.findCycles() == [[1, 2, 3, 4, 5] as Set]
+ }
+
def locatesCyclesWhenSingleCycleInGraph() {
when:
walker.add(1)
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutorTest.groovy
index 495ac62..d1b356a 100644
--- a/subprojects/core/src/test/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutorTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/progress/DefaultBuildOperationExecutorTest.groovy
@@ -18,34 +18,54 @@ package org.gradle.internal.progress
import org.gradle.internal.Factory
import org.gradle.internal.TimeProvider
-import spock.lang.Specification
+import org.gradle.logging.ProgressLogger
+import org.gradle.logging.ProgressLoggerFactory
+import org.gradle.test.fixtures.concurrent.ConcurrentSpec
-class DefaultBuildOperationExecutorTest extends Specification {
+class DefaultBuildOperationExecutorTest extends ConcurrentSpec {
def listener = Mock(InternalBuildListener)
def timeProvider = Mock(TimeProvider)
- def executor = new DefaultBuildOperationExecutor(listener, timeProvider)
+ def progressLoggerFactory = Mock(ProgressLoggerFactory)
+ def operationExecutor = new DefaultBuildOperationExecutor(listener, timeProvider, progressLoggerFactory)
def "fires events when operation starts and finishes successfully"() {
def action = Mock(Factory)
+ def progressLogger = Mock(ProgressLogger)
+ def operationDetails = BuildOperationDetails.displayName("<some-operation>").progressDisplayName("<some-op>").build()
+ def id
when:
- def result = executor.run("id", BuildOperationType.CONFIGURING_BUILD, action)
+ def result = operationExecutor.run(operationDetails, action)
then:
result == "result"
- and:
+ then:
1 * timeProvider.currentTime >> 123L
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id"
+ id = operation.id
+ assert operation.id != null
assert operation.parentId == null
- assert operation.operationType == BuildOperationType.CONFIGURING_BUILD
+ assert operation.displayName == "<some-operation>"
assert start.startTime == 123L
}
+
+ then:
+ 1 * progressLoggerFactory.newOperation(_) >> progressLogger
+ 1 * progressLogger.setDescription("<some-operation>")
+ 1 * progressLogger.setShortDescription("<some-op>")
+ 1 * progressLogger.started()
+
+ then:
1 * action.create() >> "result"
+
+ then:
+ 1 * progressLogger.completed()
+
+ then:
1 * timeProvider.currentTime >> 124L
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id"
+ assert operation.id == id
assert opResult.startTime == 123L
assert opResult.endTime == 124L
assert opResult.failure == null
@@ -54,53 +74,152 @@ class DefaultBuildOperationExecutorTest extends Specification {
def "fires events when operation starts and fails"() {
def action = Mock(Factory)
+ def operationDetails = BuildOperationDetails.displayName("<some-operation>").progressDisplayName("<some-op>").build()
def failure = new RuntimeException()
+ def progressLogger = Mock(ProgressLogger)
+ def id
when:
- executor.run("id", BuildOperationType.CONFIGURING_BUILD, action)
+ operationExecutor.run(operationDetails, action)
then:
def e = thrown(RuntimeException)
e == failure
- and:
+ then:
1 * timeProvider.currentTime >> 123L
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id"
+ assert operation.id != null
+ id = operation.id
assert operation.parentId == null
- assert operation.operationType == BuildOperationType.CONFIGURING_BUILD
+ assert operation.displayName == "<some-operation>"
assert start.startTime == 123L
}
+
+ then:
+ 1 * progressLoggerFactory.newOperation(_) >> progressLogger
+ 1 * progressLogger.setDescription("<some-operation>")
+ 1 * progressLogger.setShortDescription("<some-op>")
+ 1 * progressLogger.started()
+
+ then:
1 * action.create() >> { throw failure }
+
+ then:
+ 1 * progressLogger.completed()
+
+ then:
1 * timeProvider.currentTime >> 124L
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id"
+ assert operation.id == id
assert opResult.startTime == 123L
assert opResult.endTime == 124L
assert opResult.failure == failure
}
}
+ def "does not generate progress logging when operation has no progress display name"() {
+ def action = Mock(Factory)
+
+ when:
+ def result = operationExecutor.run("<some-operation>", action)
+
+ then:
+ result == "result"
+
+ then:
+ 1 * action.create() >> "result"
+ 0 * progressLoggerFactory._
+ }
+
+ def "multiple threads can run independent operations concurrently"() {
+ def id1
+ def id2
+
+ when:
+ async {
+ start {
+ operationExecutor.run("<thread-1>") {
+ instant.action1Started
+ thread.blockUntil.action2Started
+ }
+ }
+ thread.blockUntil.action1Started
+ operationExecutor.run("<thread-2>") {
+ instant.action2Started
+ thread.blockUntil.action1Finished
+ }
+ }
+
+ then:
+ 1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
+ id1 = operation.id
+ assert operation.id != null
+ assert operation.parentId == null
+ assert operation.displayName == "<thread-1>"
+ }
+ 1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
+ id2 = operation.id
+ assert operation.id != null
+ assert operation.parentId == null
+ assert operation.displayName == "<thread-2>"
+ }
+ 1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
+ assert operation.id == id1
+ assert opResult.failure == null
+ instant.action1Finished
+ }
+ 1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
+ assert operation.id == id2
+ assert opResult.failure == null
+ }
+ }
+
def "can query operation id from inside operation"() {
def action1 = Mock(Runnable)
def action2 = Mock(Runnable)
+ def id
when:
- executor.run("id", BuildOperationType.CONFIGURING_BUILD, action1)
+ operationExecutor.run("<parent>", action1)
then:
1 * action1.run() >> {
- assert executor.currentOperationId == "id"
- executor.run("id2", BuildOperationType.EXECUTING_TASKS, action2)
+ assert operationExecutor.currentOperationId != null
+ id = operationExecutor.currentOperationId
+ operationExecutor.run("<child>", action2)
}
1 * action2.run() >> {
- assert executor.currentOperationId == "id2"
+ assert operationExecutor.currentOperationId != null
+ assert operationExecutor.currentOperationId != id
}
}
def "cannot query operation id when no operation running"() {
when:
- executor.currentOperationId
+ operationExecutor.currentOperationId
+
+ then:
+ IllegalStateException e = thrown()
+ e.message == "No operation is currently running."
+ }
+
+ def "cannot query operation id when no operation running on current thread"() {
+ when:
+ async {
+ start {
+ operationExecutor.run("operation") {
+ instant.operationRunning
+ thread.blockUntil.queried
+ }
+ }
+ thread.blockUntil.operationRunning
+ try {
+ operationExecutor.currentOperationId
+ } finally {
+ instant.queried
+ }
+ }
then:
IllegalStateException e = thrown()
@@ -111,34 +230,38 @@ class DefaultBuildOperationExecutorTest extends Specification {
def action1 = Mock(Factory)
def action2 = Mock(Factory)
def action3 = Mock(Factory)
+ def parentId
+ def child1Id
+ def child2Id
when:
- def result = executor.run("id", BuildOperationType.CONFIGURING_BUILD, action1)
+ def result = operationExecutor.run("<parent>", action1)
then:
result == "result"
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id"
+ assert operation.id != null
+ parentId = operation.id
assert operation.parentId == null
}
1 * action1.create() >> {
- return executor.run("id2", BuildOperationType.EVALUATING_INIT_SCRIPTS, action2)
+ return operationExecutor.run("<op-2>", action2)
}
and:
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id2"
- assert operation.parentId == "id"
+ child1Id = operation.id
+ assert operation.parentId == parentId
}
1 * action2.create() >> {
- return executor.run("id3", BuildOperationType.EXECUTING_TASKS, action3)
+ return operationExecutor.run("<op-3>", action3)
}
and:
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id3"
- assert operation.parentId == "id2"
+ child2Id = operation.id
+ assert operation.parentId == child1Id
}
1 * action3.create() >> {
return "result"
@@ -146,69 +269,127 @@ class DefaultBuildOperationExecutorTest extends Specification {
and:
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id3"
+ assert operation.id == child2Id
}
and:
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id2"
+ assert operation.id == child1Id
}
and:
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id"
+ assert operation.id == parentId
+ }
+ }
+
+ def "attaches correct parent id when multiple threads run nested operations"() {
+ def parent1Id
+ def parent2Id
+ def child1Id
+ def child2Id
+
+ when:
+ async {
+ start {
+ operationExecutor.run("<parent-1>") {
+ operationExecutor.run("<child-1>") {
+ instant.child1Started
+ thread.blockUntil.child2Started
+ }
+ }
+ }
+ start {
+ operationExecutor.run("<parent-2>") {
+ operationExecutor.run("<child-2>") {
+ instant.child2Started
+ thread.blockUntil.child1Started
+ }
+ }
+ }
}
+
+ then:
+ 1 * listener.started({it.displayName == "<parent-1>" }, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
+ assert operation.id != null
+ parent1Id = operation.id
+ assert operation.parentId == null
+ }
+ 1 * listener.started({it.displayName == "<parent-2>" }, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
+ assert operation.id != null
+ parent2Id = operation.id
+ assert operation.parentId == null
+ }
+ 1 * listener.started({it.displayName == "<child-1>" }, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
+ assert operation.id != null
+ child1Id = operation.id
+ assert operation.parentId == parent1Id
+ }
+ 1 * listener.started({it.displayName == "<child-2>" }, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
+ assert operation.id != null
+ child2Id = operation.id
+ assert operation.parentId == parent2Id
+ }
+
+ and:
+ 1 * listener.finished({ it.id == child1Id }, _)
+ 1 * listener.finished({ it.id == child2Id }, _)
+ 1 * listener.finished({ it.id == parent1Id }, _)
+ 1 * listener.finished({ it.id == parent2Id }, _)
}
def "attaches parent id when sibling operation fails"() {
def action1 = Mock(Factory)
def action2 = Mock(Factory)
def action3 = Mock(Factory)
+ def parentId
+ def child1Id
+ def child2Id
when:
- def result = executor.run("id", BuildOperationType.CONFIGURING_BUILD, action1)
+ def result = operationExecutor.run("<parent>", action1)
then:
result == "result"
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id"
+ parentId = operation.id
assert operation.parentId == null
}
1 * action1.create() >> {
try {
- executor.run("id2", BuildOperationType.EVALUATING_INIT_SCRIPTS, action2)
+ operationExecutor.run("<child-1>", action2)
} catch (RuntimeException) {
// Ignore
}
- return executor.run("id3", BuildOperationType.EXECUTING_TASKS, action3)
+ return operationExecutor.run("<child-2>", action3)
}
and:
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id2"
- assert operation.parentId == "id"
+ child1Id = operation.id
+ assert operation.parentId == parentId
}
1 * action2.create() >> { throw new RuntimeException() }
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id2"
+ assert operation.id == child1Id
}
and:
1 * listener.started(_, _) >> { BuildOperationInternal operation, OperationStartEvent start ->
- assert operation.id == "id3"
- assert operation.parentId == "id"
+ child2Id = operation.id
+ assert operation.parentId == parentId
}
1 * action3.create() >> {
return "result"
}
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id3"
+ assert operation.id == child2Id
}
and:
1 * listener.finished(_, _) >> { BuildOperationInternal operation, OperationResult opResult ->
- assert operation.id == "id"
+ assert operation.id == parentId
}
}
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/progress/OperationsHierarchyKeeperTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/progress/OperationsHierarchyKeeperTest.groovy
deleted file mode 100644
index 1f103f9..0000000
--- a/subprojects/core/src/test/groovy/org/gradle/internal/progress/OperationsHierarchyKeeperTest.groovy
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-package org.gradle.internal.progress
-
-import org.gradle.logging.ProgressLogger
-import org.gradle.util.ConcurrentSpecification
-import spock.lang.Subject
-
-class OperationsHierarchyKeeperTest extends ConcurrentSpecification {
-
- @Subject manager = new OperationsHierarchyKeeper()
-
- def "provides hierarchy"() {
- def h1 = manager.currentHierarchy(null)
- def h2 = manager.currentHierarchy(null)
-
- expect:
- h1.hierarchy.is(h2.hierarchy)
- h1.sharedCounter.is(h2.sharedCounter)
- }
-
- def "provides hierarchy per thread"() {
- def h1
- def h2
-
- when:
- start { h1 = manager.currentHierarchy(null) }
- start { h2 = manager.currentHierarchy(null) }
- finished()
-
- then:
- !h1.hierarchy.is(h2.hierarchy)
- h1.sharedCounter.is(h2.sharedCounter)
- }
-
- def "may feed the parent logger"() {
- def parent1 = Stub(ProgressLogger) { currentOperationId() >> new OperationIdentifier(1, 1) }
- def parent2 = Mock(ProgressLogger) { currentOperationId() >> new OperationIdentifier(2, 1) }
-
- when:
- def h1 = manager.currentHierarchy(parent1)
- def h2 = manager.currentHierarchy(parent2)
-
- then:
- h1.hierarchy.is(h2.hierarchy)
- h1.hierarchy == [1]
- }
-}
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/progress/OperationsHierarchyTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/progress/OperationsHierarchyTest.groovy
deleted file mode 100644
index b7b8188..0000000
--- a/subprojects/core/src/test/groovy/org/gradle/internal/progress/OperationsHierarchyTest.groovy
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-
-
-package org.gradle.internal.progress
-
-import spock.lang.Specification
-import spock.lang.Subject
-
-import java.util.concurrent.atomic.AtomicLong
-
-class OperationsHierarchyTest extends Specification {
-
- @Subject hierarchy = new OperationsHierarchy(new AtomicLong(), new LinkedList<Long>())
-
- def "does not have any identifier initially"() {
- when: hierarchy.currentOperationId()
- then: thrown(OperationsHierarchy.NoActiveOperationFound)
-
- when: hierarchy.completeCurrentOperation()
- then: thrown(OperationsHierarchy.NoActiveOperationFound)
- }
-
- def "provides operation identifier"() {
- def id1 = hierarchy.start()
- def id2 = hierarchy.start()
-
- expect:
- id1.id == 1
- id1.parentId == null
-
- id2.id == 1
- id2.parentId == null
- }
-
- def "provides hierarchical operation identifier"() {
- hierarchy = new OperationsHierarchy(new AtomicLong(2), [1L,2L] as LinkedList)
-
- when:
- def id = hierarchy.start()
-
- then:
- id.id == 3
- id.parentId == 2
- }
-
- def "provides current operation id"() {
- hierarchy = new OperationsHierarchy(new AtomicLong(2), [1L,2L] as LinkedList)
-
- when:
- def id1 = hierarchy.start()
-
- then:
- hierarchy.currentOperationId() //can be called many times
- id1 == hierarchy.currentOperationId()
- id1.id == 3
- }
-
- def "removes current operation id"() {
- hierarchy = new OperationsHierarchy(new AtomicLong(12), [1L,2L] as LinkedList)
-
- when: hierarchy.start()
-
- then:
- def currentId = hierarchy.currentOperationId()
- currentId.id == 13
- hierarchy.completeCurrentOperation() == currentId
-
- when: hierarchy.currentOperationId()
-
- then: thrown(OperationsHierarchy.NoActiveOperationFound)
- }
-
- def "new operations respect removed parents"() {
- hierarchy = new OperationsHierarchy(new AtomicLong(12), [1L,2L] as LinkedList)
-
- when:
- def id1 = hierarchy.start()
- def removed = hierarchy.completeCurrentOperation()
- def id2 = hierarchy.start()
-
- then:
- id1.id == 13
- id1.parentId == 2
- removed.id == 13
- id2.id == 14
- id2.parentId == 2
- }
-
- def "incomplete child operations are tolerated"() {
- def ids = [1L,2L] as LinkedList
- hierarchy = new OperationsHierarchy(new AtomicLong(12), ids)
-
- when: hierarchy.start()
-
- then: hierarchy.currentOperationId().id == 13
-
- when: ids << 100L //some child operation is added
-
- then:
- def currentId = hierarchy.currentOperationId()
- currentId.id == 13 //current id is the same
- hierarchy.completeCurrentOperation() == currentId
-
- when:
- def id = hierarchy.start()
-
- then:
- id.id == 14
- id.parentId == 100
- }
-
- def "reports if hierarchy is empty"() {
- def ids = [] as LinkedList
- hierarchy = new OperationsHierarchy(new AtomicLong(12), ids)
- hierarchy.start()
- ids.clear() //this should never happen
-
- when: hierarchy.completeCurrentOperation()
- then: thrown(OperationsHierarchy.HierarchyEmptyException)
- }
-}
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/BuildScopeServicesTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/BuildScopeServicesTest.groovy
index ae1d284..8d9b82c 100644
--- a/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/BuildScopeServicesTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/BuildScopeServicesTest.groovy
@@ -29,11 +29,7 @@ import org.gradle.api.internal.project.*
import org.gradle.cache.CacheRepository
import org.gradle.cache.internal.CacheFactory
import org.gradle.cache.internal.DefaultCacheRepository
-import org.gradle.configuration.BuildConfigurer
-import org.gradle.configuration.DefaultBuildConfigurer
-import org.gradle.configuration.DefaultScriptPluginFactory
-import org.gradle.configuration.ImportsReader
-import org.gradle.configuration.ScriptPluginFactory
+import org.gradle.configuration.*
import org.gradle.groovy.scripts.DefaultScriptCompilerFactory
import org.gradle.groovy.scripts.ScriptCompilerFactory
import org.gradle.initialization.*
@@ -204,7 +200,7 @@ public class BuildScopeServicesTest extends Specification {
setup:
expectListenerManagerCreated()
expect:
- assertThat(registry.get(SettingsProcessor), instanceOf(PropertiesLoadingSettingsProcessor))
+ assertThat(registry.get(SettingsProcessor), instanceOf(NotifyingSettingsProcessor))
assertThat(registry.get(SettingsProcessor), sameInstance(registry.get(SettingsProcessor)))
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GlobalScopeServicesTest.java b/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GlobalScopeServicesTest.java
index 2ec9eb0..f9b8af9 100755
--- a/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GlobalScopeServicesTest.java
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GlobalScopeServicesTest.java
@@ -17,10 +17,7 @@
package org.gradle.internal.service.scopes;
import org.gradle.api.internal.*;
-import org.gradle.api.internal.classpath.DefaultModuleRegistry;
-import org.gradle.api.internal.classpath.DefaultPluginModuleRegistry;
-import org.gradle.api.internal.classpath.ModuleRegistry;
-import org.gradle.api.internal.classpath.PluginModuleRegistry;
+import org.gradle.api.internal.classpath.*;
import org.gradle.api.internal.file.DefaultFileLookup;
import org.gradle.api.internal.file.FileLookup;
import org.gradle.api.internal.file.FileResolver;
@@ -36,12 +33,12 @@ import org.gradle.internal.classloader.ClassLoaderFactory;
import org.gradle.internal.classloader.DefaultClassLoaderFactory;
import org.gradle.internal.concurrent.DefaultExecutorFactory;
import org.gradle.internal.concurrent.ExecutorFactory;
+import org.gradle.internal.event.DefaultListenerManager;
+import org.gradle.internal.event.ListenerManager;
import org.gradle.internal.nativeintegration.ProcessEnvironment;
import org.gradle.internal.nativeintegration.filesystem.FileSystem;
import org.gradle.internal.service.DefaultServiceRegistry;
import org.gradle.internal.service.ServiceRegistry;
-import org.gradle.internal.event.DefaultListenerManager;
-import org.gradle.internal.event.ListenerManager;
import org.gradle.logging.LoggingManagerInternal;
import org.gradle.logging.LoggingServiceRegistry;
import org.gradle.logging.ProgressLoggerFactory;
@@ -109,22 +106,22 @@ public class GlobalScopeServicesTest {
public void providesALoggingManagerFactory() {
assertThat(registry().getFactory(LoggingManagerInternal.class), instanceOf(DefaultLoggingManagerFactory.class));
}
-
+
@Test
public void providesAListenerManager() {
assertThat(registry().get(ListenerManager.class), instanceOf(DefaultListenerManager.class));
}
-
+
@Test
public void providesAProgressLoggerFactory() {
assertThat(registry().get(ProgressLoggerFactory.class), instanceOf(DefaultProgressLoggerFactory.class));
}
-
+
@Test
public void providesAGradleDistributionLocator() {
- assertThat(registry().get(GradleDistributionLocator.class), instanceOf(DefaultModuleRegistry.class));
+ assertThat(registry().get(GradleDistributionLocator.class), instanceOf(DefaultGradleDistributionLocator.class));
}
-
+
@Test
public void providesAClassLoaderFactory() {
assertThat(registry().get(ClassLoaderFactory.class), instanceOf(DefaultClassLoaderFactory.class));
diff --git a/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GradleScopeServicesTest.groovy b/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GradleScopeServicesTest.groovy
index b06d5ad..5e5b88f 100644
--- a/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GradleScopeServicesTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/internal/service/scopes/GradleScopeServicesTest.groovy
@@ -107,6 +107,16 @@ public class GradleScopeServicesTest extends Specification {
buildExecuter sameInstance(secondExecuter)
}
+ def "provides a build configuration action executer"() {
+ when:
+ def firstExecuter = registry.get(BuildConfigurationActionExecuter)
+ def secondExecuter = registry.get(BuildConfigurationActionExecuter)
+
+ then:
+ firstExecuter instanceof BuildConfigurationActionExecuter
+ firstExecuter sameInstance(secondExecuter)
+ }
+
def "provides a task graph executer"() {
when:
def graphExecuter = registry.get(TaskGraphExecuter)
diff --git a/subprojects/core/src/test/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactoryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactoryTest.groovy
index 336ce8d..ddc8129 100644
--- a/subprojects/core/src/test/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactoryTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/logging/internal/DefaultProgressLoggerFactoryTest.groovy
@@ -15,14 +15,14 @@
*/
package org.gradle.logging.internal
-import spock.lang.Specification
-import org.gradle.logging.ProgressLoggerFactory
import org.gradle.internal.TimeProvider
+import org.gradle.internal.progress.OperationIdentifier
+import org.gradle.test.fixtures.concurrent.ConcurrentSpec
-class DefaultProgressLoggerFactoryTest extends Specification {
- private final ProgressListener progressListener = Mock()
- private final TimeProvider timeProvider = Mock()
- private final ProgressLoggerFactory factory = new DefaultProgressLoggerFactory(progressListener, timeProvider)
+class DefaultProgressLoggerFactoryTest extends ConcurrentSpec {
+ def progressListener = Mock(ProgressListener)
+ def timeProvider = Mock(TimeProvider)
+ def factory = new DefaultProgressLoggerFactory(progressListener, timeProvider)
def progressLoggerBroadcastsEvents() {
when:
@@ -33,8 +33,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
then:
logger != null
1 * timeProvider.getCurrentTime() >> 100L
- 1 * progressListener.started(!null) >> { args ->
- def event = args[0]
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
assert event.timestamp == 100L
assert event.category == 'logger'
assert event.description == 'description'
@@ -48,8 +47,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
then:
1 * timeProvider.getCurrentTime() >> 200L
- 1 * progressListener.progress(!null) >> { args ->
- def event = args[0]
+ 1 * progressListener.progress(!null) >> { ProgressEvent event ->
assert event.timestamp == 200L
assert event.category == 'logger'
assert event.status == 'progress'
@@ -60,14 +58,144 @@ class DefaultProgressLoggerFactoryTest extends Specification {
then:
1 * timeProvider.getCurrentTime() >> 300L
- 1 * progressListener.completed(!null) >> { args ->
- def event = args[0]
+ 1 * progressListener.completed(!null) >> { ProgressCompleteEvent event ->
assert event.timestamp == 300L
assert event.category == 'logger'
assert event.status == 'completed'
}
}
+ def "attaches current running operation as parent when operation is started"() {
+ given:
+ def notStarted = factory.newOperation("category").setDescription("ignore-me")
+ def completed = factory.newOperation("category").setDescription("ignore-me")
+ def child = factory.newOperation("category").setDescription("child")
+ def parent = factory.newOperation("category").setDescription("parent")
+ def parentId
+
+ completed.started()
+ completed.completed()
+
+ when:
+ parent.started()
+ child.started()
+
+ then:
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
+ assert event.description == "parent"
+ assert event.parentId == null
+ assert event.operationId != null
+ parentId = event.operationId
+ }
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
+ assert event.description == "child"
+ assert event.operationId != parentId
+ assert event.parentId == parentId
+ }
+ }
+
+ def "can specify the parent of an operation"() {
+ given:
+ def sibling = factory.newOperation("category").setDescription("sibling")
+ def parent = factory.newOperation("category").setDescription("parent")
+ def child = factory.newOperation(String, parent).setDescription("child")
+ def parentId
+
+ when:
+ parent.started()
+ sibling.started()
+ child.started()
+
+ then:
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
+ assert event.description == "parent"
+ parentId = event.operationId
+ }
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
+ assert event.description == "sibling"
+ assert event.parentId == parentId
+ }
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
+ assert event.description == "child"
+ assert event.parentId == parentId
+ }
+ }
+
+ def "multiple threads can log independent operations"() {
+ OperationIdentifier parentId
+ OperationIdentifier childId
+ OperationIdentifier id2
+
+ when:
+ async {
+ start {
+ def parent = factory.newOperation("category").setDescription("op-1")
+ parent.started()
+ def child = factory.newOperation("category").setDescription("child")
+ child.started()
+ instant.op1Running
+ thread.blockUntil.op2Running
+ child.completed()
+ parent.completed()
+ }
+ start {
+ def logger = factory.newOperation("category").setDescription("op-2")
+ logger.started()
+ instant.op2Running
+ thread.blockUntil.op1Running
+ logger.completed()
+ }
+ }
+
+ then:
+ 1 * progressListener.started({it.description == "op-1"}) >> { ProgressStartEvent event ->
+ parentId = event.operationId
+ assert event.parentId == null
+ }
+ 1 * progressListener.started({it.description == "child"}) >> { ProgressStartEvent event ->
+ childId = event.operationId
+ assert event.parentId == parentId
+ }
+ 1 * progressListener.started({it.description == "op-2"}) >> { ProgressStartEvent event ->
+ id2 = event.operationId
+ assert event.parentId == null
+ }
+
+ and:
+ [parentId, childId, id2].toSet().size() == 3
+ }
+
+ def "operation can have parent running in a different thread"() {
+ OperationIdentifier parentId
+
+ when:
+ async {
+ def parent = factory.newOperation("category").setDescription("op-1")
+ start {
+ parent.started()
+ instant.parentRunning
+ thread.blockUntil.childFinished
+ parent.completed()
+ }
+ start {
+ thread.blockUntil.parentRunning
+ def child = factory.newOperation(String, parent).setDescription("child")
+ child.started()
+ child.completed()
+ instant.childFinished
+ }
+ }
+
+ then:
+ 1 * progressListener.started({it.description == "op-1"}) >> { ProgressStartEvent event ->
+ parentId = event.operationId
+ }
+ 1 * progressListener.started({it.description == "child"}) >> { ProgressStartEvent event ->
+ assert event.parentId == parentId
+ assert event.operationId != parentId
+ }
+ }
+
def canSpecifyShortDescription() {
when:
def logger = factory.newOperation('logger')
@@ -76,8 +204,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
logger.started()
then:
- 1 * progressListener.started(!null) >> { args ->
- def event = args[0]
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
assert event.shortDescription == 'short'
}
}
@@ -90,8 +217,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
logger.started()
then:
- 1 * progressListener.started(!null) >> { args ->
- def event = args[0]
+ 1 * progressListener.started(!null) >> { ProgressStartEvent event ->
assert event.loggingHeader == 'header'
}
}
@@ -169,7 +295,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
then:
IllegalStateException e = thrown()
- e.message == 'This operation has not been started.'
+ e.message == 'This operation is not running.'
}
def cannotMakeProgressAfterCompletion() {
@@ -183,7 +309,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
then:
IllegalStateException e = thrown()
- e.message == 'This operation has completed.'
+ e.message == 'This operation is not running.'
}
def cannotCompleteBeforeStart() {
@@ -194,7 +320,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
then:
IllegalStateException e = thrown()
- e.message == 'This operation has not been started.'
+ e.message == 'This operation is not running.'
}
def cannotStartMultipleTimes() {
@@ -235,7 +361,7 @@ class DefaultProgressLoggerFactoryTest extends Specification {
then:
IllegalStateException e = thrown()
- e.message == 'This operation has completed.'
+ e.message == 'This operation is not running.'
}
def "can log start conveniently"() {
diff --git a/subprojects/core/src/test/groovy/org/gradle/logging/internal/OutputSpecification.groovy b/subprojects/core/src/test/groovy/org/gradle/logging/internal/OutputSpecification.groovy
index 5f94e35..bb16231 100644
--- a/subprojects/core/src/test/groovy/org/gradle/logging/internal/OutputSpecification.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/logging/internal/OutputSpecification.groovy
@@ -69,18 +69,16 @@ abstract class OutputSpecification extends Specification {
ProgressStartEvent start(Map args) {
Long parent = counter
long id = ++counter
- return new ProgressStartEvent(new OperationIdentifier(id, parent), tenAm, 'category', args.description, args.shortDescription, args.loggingHeader, args.status)
+ return new ProgressStartEvent(new OperationIdentifier(id), new OperationIdentifier(parent), tenAm, 'category', args.description, args.shortDescription, args.loggingHeader, args.status)
}
ProgressEvent progress(String status) {
- Long parent = counter - 1
long id = counter
- return new ProgressEvent(new OperationIdentifier(id, parent), tenAm, 'category', status)
+ return new ProgressEvent(new OperationIdentifier(id), tenAm, 'category', status)
}
ProgressCompleteEvent complete(String status) {
- Long parent = counter - 1
long id = counter--
- return new ProgressCompleteEvent(new OperationIdentifier(id, parent), tenAm, 'category', 'description', status)
+ return new ProgressCompleteEvent(new OperationIdentifier(id), tenAm, 'category', 'description', status)
}
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/logging/internal/progress/ProgressOperationsTest.groovy b/subprojects/core/src/test/groovy/org/gradle/logging/internal/progress/ProgressOperationsTest.groovy
index 67b5bd8..44b3a13 100644
--- a/subprojects/core/src/test/groovy/org/gradle/logging/internal/progress/ProgressOperationsTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/logging/internal/progress/ProgressOperationsTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.logging.internal.progress
+import org.gradle.internal.progress.OperationIdentifier
import spock.lang.Specification
class ProgressOperationsTest extends Specification {
@@ -24,7 +25,7 @@ class ProgressOperationsTest extends Specification {
def "starts operation"() {
when:
- def op = ops.start("compile", null, 1, null)
+ def op = ops.start("compile", null, new OperationIdentifier(1), null)
then:
op.parent == null
@@ -33,8 +34,8 @@ class ProgressOperationsTest extends Specification {
def "starts operations"() {
when:
- def op1 = ops.start("compile", null, 1, null)
- def op2 = ops.start("resolve", null, 2, 1)
+ def op1 = ops.start("compile", null, new OperationIdentifier(1), null)
+ def op2 = ops.start("resolve", null, new OperationIdentifier(2), new OperationIdentifier(1))
then:
op1.message == "compile"
@@ -45,17 +46,17 @@ class ProgressOperationsTest extends Specification {
def "operation can be started multiple times"() {
expect:
- ops.start("compile", null, 1, null).message == "compile"
- ops.progress("compiling...", 1).message == "compiling..."
- ops.start("resolve", null, 1, null).message == "resolve"
- ops.progress("resolving...", 1).message == "resolving..."
- ops.complete(1).message == "resolving..."
+ ops.start("compile", null, new OperationIdentifier(1), null).message == "compile"
+ ops.progress("compiling...", new OperationIdentifier(1)).message == "compiling..."
+ ops.start("resolve", null, new OperationIdentifier(1), null).message == "resolve"
+ ops.progress("resolving...", new OperationIdentifier(1)).message == "resolving..."
+ ops.complete(new OperationIdentifier(1)).message == "resolving..."
}
def "starts operations from different hierarchies"() {
when:
- def op1 = ops.start("compile", null, 1, null)
- def op2 = ops.start("resolve", null, 2, null)
+ def op1 = ops.start("compile", null, new OperationIdentifier(1), null)
+ def op2 = ops.start("resolve", null, new OperationIdentifier(2), null)
then:
op1.message == "compile"
@@ -66,14 +67,14 @@ class ProgressOperationsTest extends Specification {
def "the operation uses status first"() {
expect:
- ops.start("foo", "compiling now", 1, null).message == "compiling now"
+ ops.start("foo", "compiling now", new OperationIdentifier(1), null).message == "compiling now"
}
def "tracks progress"() {
when:
- ops.start("Building", "", 1, null)
- def op2 = ops.start("Resolving", "", 2, 1)
- def op3 = ops.progress("Download", 2)
+ ops.start("Building", "", new OperationIdentifier(1), null)
+ def op2 = ops.start("Resolving", "", new OperationIdentifier(2), new OperationIdentifier(1))
+ def op3 = ops.progress("Download", new OperationIdentifier(2))
then:
op2 == op3
@@ -83,7 +84,7 @@ class ProgressOperationsTest extends Specification {
def "progress cannot be reported for unknown operation"() {
when:
- ops.progress("Download", 2)
+ ops.progress("Download", new OperationIdentifier(1))
then:
thrown(IllegalStateException)
@@ -91,16 +92,16 @@ class ProgressOperationsTest extends Specification {
def "completed events are no longer tracked"() {
when:
- ops.start("Building", "", 1, null)
- ops.start("Resolving", "", 2, 1)
- def op3 = ops.progress("Download", 2)
- def op4 = ops.complete(2)
+ ops.start("Building", "", new OperationIdentifier(1), null)
+ ops.start("Resolving", "", new OperationIdentifier(2), new OperationIdentifier(1))
+ def op3 = ops.progress("Download", new OperationIdentifier(2))
+ def op4 = ops.complete(new OperationIdentifier(2))
then:
op3 == op4
when:
- ops.progress("foo", 2)
+ ops.progress("foo", new OperationIdentifier(2))
then:
thrown(IllegalStateException)
@@ -108,7 +109,7 @@ class ProgressOperationsTest extends Specification {
def "missing parents are tolerated"() {
when:
- def op = ops.start("Building", "", 1, 112)
+ def op = ops.start("Building", "", new OperationIdentifier(1), new OperationIdentifier(122))
then:
op.parent == null
diff --git a/subprojects/core/src/test/groovy/org/gradle/process/internal/DefaultExecHandleSpec.groovy b/subprojects/core/src/test/groovy/org/gradle/process/internal/DefaultExecHandleSpec.groovy
index c8e705c..fad518d 100644
--- a/subprojects/core/src/test/groovy/org/gradle/process/internal/DefaultExecHandleSpec.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/process/internal/DefaultExecHandleSpec.groovy
@@ -111,11 +111,10 @@ class DefaultExecHandleSpec extends Specification {
when:
execHandle.start();
execHandle.abort();
- def result = execHandle.waitForFinish();
-
then:
execHandle.state == ExecHandleState.ABORTED
- result.exitValue != 0
+ and:
+ execHandle.waitForFinish().exitValue != 0
}
void "clients can listen to notifications"() {
diff --git a/subprojects/core/src/test/groovy/org/gradle/process/internal/streams/ExecOutputHandleRunnerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/process/internal/streams/ExecOutputHandleRunnerTest.groovy
new file mode 100644
index 0000000..8d83ca2
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/process/internal/streams/ExecOutputHandleRunnerTest.groovy
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.process.internal.streams
+
+import groovy.transform.NotYetImplemented
+import org.gradle.internal.io.TextStream
+import org.gradle.util.LineBufferingOutputStream
+import spock.lang.Issue
+import spock.lang.Specification
+
+class ExecOutputHandleRunnerTest extends Specification {
+
+ @Issue("GRADLE-3329")
+ @NotYetImplemented
+ def "passes long Unicode line as single line"() {
+ def bufferLength = 8
+ def text = "a" * (bufferLength - 1) + "\u0151"
+ def action = Mock(TextStream)
+ def output = new LineBufferingOutputStream(action)
+ def input = new ByteArrayInputStream(text.getBytes("utf-8"))
+ def runner = new ExecOutputHandleRunner("test", input, output, bufferLength)
+
+ when:
+ runner.run()
+
+ then:
+ 1 * action.text(text)
+ 1 * action.endOfStream(null)
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/util/GUtilTest.groovy b/subprojects/core/src/test/groovy/org/gradle/util/GUtilTest.groovy
index b6bfade..d2404c5 100644
--- a/subprojects/core/src/test/groovy/org/gradle/util/GUtilTest.groovy
+++ b/subprojects/core/src/test/groovy/org/gradle/util/GUtilTest.groovy
@@ -35,6 +35,8 @@ public class GUtilTest extends spock.lang.Specification {
toCamelCase("Two Words") == "TwoWords"
toCamelCase(" Two \t words\n") == "TwoWords"
toCamelCase("four or so Words") == "FourOrSoWords"
+ toCamelCase("123-project") == "123Project"
+ toCamelCase("i18n-admin") == "I18nAdmin"
toCamelCase("trailing-") == "Trailing"
toCamelCase("ABC") == "ABC"
toCamelCase(".") == ""
@@ -55,6 +57,8 @@ public class GUtilTest extends spock.lang.Specification {
toLowerCamelCase("Two Words") == "twoWords"
toLowerCamelCase(" Two \t words\n") == "twoWords"
toLowerCamelCase("four or so Words") == "fourOrSoWords"
+ toLowerCamelCase("123-project") == "123Project"
+ toLowerCamelCase("i18n-admin") == "i18nAdmin"
toLowerCamelCase("trailing-") == "trailing"
toLowerCamelCase("ABC") == "aBC"
toLowerCamelCase(".") == ""
@@ -83,6 +87,9 @@ public class GUtilTest extends spock.lang.Specification {
toConstant("ABC") == "ABC"
toConstant("ABCThing") == "ABC_THING"
toConstant("ABC Thing") == "ABC_THING"
+ toConstant("123-project") == "123_PROJECT"
+ toConstant("123abc-project") == "123ABC_PROJECT"
+ toConstant("i18n-admin") == "I18N_ADMIN"
toConstant(".") == ""
toConstant("-") == ""
}
@@ -106,6 +113,7 @@ public class GUtilTest extends spock.lang.Specification {
toWords("ABC") == "abc"
toWords("ABCThing") == "abc thing"
toWords("ABC Thing") == "abc thing"
+ toWords("123Thing") == "123 thing"
toWords(".") == ""
toWords("_") == ""
}
diff --git a/subprojects/core/src/test/groovy/org/gradle/util/ports/AbstractPortAllocatorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/util/ports/AbstractPortAllocatorTest.groovy
new file mode 100644
index 0000000..dc2dafc
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/util/ports/AbstractPortAllocatorTest.groovy
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+import spock.lang.Specification
+
+
+abstract class AbstractPortAllocatorTest extends Specification {
+ final PortDetector noPortsAvailable = Stub(PortDetector) { isAvailable(_) >> { false } }
+ final PortDetector portsAlwaysAvailable = Stub(PortDetector) { isAvailable(_) >> { true } }
+
+ ReservedPortRangeFactory portRangeFactory = Mock(ReservedPortRangeFactory)
+
+ static ReservedPortRange getPortRange(PortDetector portDetector, int startPort, int endPort) {
+ ReservedPortRange portRange = new ReservedPortRange(startPort, endPort)
+ portRange.portDetector = portDetector
+ return portRange
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/util/ports/FixedAvailablePortAllocatorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/util/ports/FixedAvailablePortAllocatorTest.groovy
new file mode 100644
index 0000000..eb14840
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/util/ports/FixedAvailablePortAllocatorTest.groovy
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+import spock.lang.Unroll
+
+
+class FixedAvailablePortAllocatorTest extends AbstractPortAllocatorTest {
+
+ @Unroll
+ def "assigns a fixed port range based on worker id (maxForks: #maxForks, workerId: #workerId, agentNum: #agentNum, totalAgents: #totalAgents)" () {
+ FixedAvailablePortAllocator portAllocator = new FixedAvailablePortAllocator(maxForks, workerId, agentNum, totalAgents)
+
+ when:
+ portAllocator.assignPort()
+
+ then:
+ portAllocator.reservations.size() == 1
+ portAllocator.reservations.get(0).startPort == startPort
+ portAllocator.reservations.get(0).endPort == endPort
+
+ where:
+ maxForks | workerId | agentNum | totalAgents | startPort | endPort
+ 2 | 1 | 1 | 2 | 49152 | 53246
+ 2 | 2 | 1 | 2 | 53247 | 57341
+ 2 | 1 | 2 | 2 | 57342 | 61436
+ 2 | 2 | 2 | 2 | 61437 | 65531
+ 2 | 5 | 2 | 2 | 57342 | 61436
+
+ 4 | 1 | 1 | 1 | 49152 | 53246
+ 4 | 2 | 1 | 1 | 53247 | 57341
+ 4 | 3 | 1 | 1 | 57342 | 61436
+ 4 | 4 | 1 | 1 | 61437 | 65531
+ 4 | 10 | 1 | 1 | 53247 | 57341
+
+ 4 | 1 | 1 | 2 | 49152 | 51198
+ 4 | 2 | 1 | 2 | 51199 | 53245
+ 4 | 3 | 1 | 2 | 53246 | 55292
+ 4 | 4 | 1 | 2 | 55293 | 57339
+ 4 | 11 | 1 | 2 | 53246 | 55292
+ 4 | 1 | 2 | 2 | 57340 | 59386
+ 4 | 2 | 2 | 2 | 59387 | 61433
+ 4 | 3 | 2 | 2 | 61434 | 63480
+ 4 | 4 | 2 | 2 | 63481 | 65527
+ 4 | 10 | 2 | 2 | 59387 | 61433
+
+ 6 | 1 | 1 | 2 | 49152 | 50516
+ 6 | 2 | 1 | 2 | 50517 | 51881
+ 6 | 3 | 1 | 2 | 51882 | 53246
+ 6 | 4 | 1 | 2 | 53247 | 54611
+ 6 | 5 | 1 | 2 | 54612 | 55976
+ 6 | 6 | 1 | 2 | 55977 | 57341
+ 6 | 7 | 1 | 2 | 49152 | 50516
+ 6 | 1 | 2 | 2 | 57342 | 58706
+ 6 | 2 | 2 | 2 | 58707 | 60071
+ 6 | 3 | 2 | 2 | 60072 | 61436
+ 6 | 4 | 2 | 2 | 61437 | 62801
+ 6 | 5 | 2 | 2 | 62802 | 64166
+ 6 | 6 | 2 | 2 | 64167 | 65531
+ 6 | 9 | 2 | 2 | 60072 | 61436
+ }
+
+ def "uses all ports when maxForks and workerId are not available" () {
+ FixedAvailablePortAllocator portAllocator = new FixedAvailablePortAllocator(1, -1, 1, 1)
+
+ when:
+ portAllocator.assignPort()
+
+ then:
+ portAllocator.reservations.size() == 1
+ portAllocator.reservations.get(0).startPort == 49152
+ portAllocator.reservations.get(0).endPort == 65534
+ }
+
+ def "throws an exception when all ports in range are exhausted" () {
+ ReservedPortRangeFactory portRangeFactory = Mock(ReservedPortRangeFactory)
+ FixedAvailablePortAllocator portAllocator = new FixedAvailablePortAllocator(6, 1, 1, 1)
+ portAllocator.portRangeFactory = portRangeFactory
+
+ when:
+ 2730.times {
+ portAllocator.assignPort()
+ }
+
+ then:
+ 1 * portRangeFactory.getReservedPortRange(_, _) >> {int startPort, int endPort -> getPortRange(portsAlwaysAvailable, startPort, endPort)}
+
+ when:
+ portAllocator.assignPort()
+
+ then:
+ def e = thrown(NoSuchElementException)
+ e.message == "All available ports in the fixed port range for agent 1, worker 1 have been exhausted."
+ }
+
+ def "can assign ports from the static instance"() {
+ PortAllocator portAllocator = FixedAvailablePortAllocator.getInstance()
+
+ when:
+ def port1 = portAllocator.assignPort()
+
+ then:
+ port1 >= PortAllocator.MIN_PRIVATE_PORT
+ port1 <= PortAllocator.MAX_PRIVATE_PORT
+
+ when:
+ def port2 = portAllocator.assignPort()
+
+ then:
+ port2 >= PortAllocator.MIN_PRIVATE_PORT
+ port2 <= PortAllocator.MAX_PRIVATE_PORT
+
+ and:
+ port2 != port1
+
+ cleanup:
+ portAllocator.releasePort(port1)
+ portAllocator.releasePort(port2)
+ }
+}
diff --git a/subprojects/core/src/test/groovy/org/gradle/util/ports/ReservedPortRangeTest.groovy b/subprojects/core/src/test/groovy/org/gradle/util/ports/ReservedPortRangeTest.groovy
new file mode 100644
index 0000000..73cbfac
--- /dev/null
+++ b/subprojects/core/src/test/groovy/org/gradle/util/ports/ReservedPortRangeTest.groovy
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+import spock.lang.Specification
+
+
+class ReservedPortRangeTest extends Specification {
+ static final int FIRST_PORT = 101
+ static final int LAST_PORT = 110
+ ReservedPortRange range = new ReservedPortRange(FIRST_PORT, LAST_PORT)
+ PortDetector portDetector = Mock(PortDetector)
+
+ def setup() {
+ range.portDetector = portDetector
+ }
+
+ def "can allocate unique ports in port range"() {
+ def reserved = []
+
+ when:
+ 10.times {
+ reserved.add(range.allocate())
+ }
+
+ then:
+ 10 * portDetector.isAvailable(_) >> { true }
+
+ and:
+ reserved.sort() == FIRST_PORT..LAST_PORT
+ }
+
+ def "cannot allocate more ports than in range" () {
+ when:
+ 10.times {
+ range.allocate()
+ }
+
+ then:
+ 10 * portDetector.isAvailable(_) >> { true }
+
+ and:
+ range.allocate() == -1
+ }
+
+ def "ports are allocated in sequence" () {
+ when:
+ def port1 = range.allocate()
+ def port2 = range.allocate()
+ def port3 = range.allocate()
+
+ then:
+ port2 == next(port1)
+ port3 == next(port2)
+
+ and:
+ 3 * portDetector.isAvailable(_) >> { true }
+ }
+
+ def "detects when ports are unavailable" () {
+ def reserved = []
+
+ when:
+ 8.times {
+ reserved.add(range.allocate())
+ }
+
+ then:
+ _ * portDetector.isAvailable(_) >> { int port -> return ! (port in [103,107]) }
+
+ and:
+ ! reserved.contains(103)
+ ! reserved.contains(107)
+
+ and:
+ range.allocate() == -1
+ }
+
+ def "can deallocate ports" () {
+ def reserved = []
+ _ * portDetector.isAvailable(_) >> { true }
+
+ when:
+ 4.times {
+ reserved.add(range.allocate())
+ }
+
+ then:
+ range.allocated.size() == 4
+
+ when:
+ reserved.each { int port ->
+ range.deallocate(port)
+ }
+
+ then:
+ range.allocated.size() == 0
+ }
+
+ def "can reuse deallocated ports" () {
+ _ * portDetector.isAvailable(_) >> { true }
+
+ when:
+ 10.times {
+ range.allocate()
+ }
+
+ then:
+ range.allocate() == -1
+
+ when:
+ range.deallocate(103)
+ range.deallocate(109)
+ range.deallocate(102)
+
+ then:
+ (0..2).collect { range.allocate() }.sort() == [102, 103, 109]
+ }
+
+ int next(int port) {
+ return port == LAST_PORT ? FIRST_PORT : port+1
+ }
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/test/fixtures/ConcurrentTestUtil.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/test/fixtures/ConcurrentTestUtil.groovy
deleted file mode 100644
index 54c3a2e..0000000
--- a/subprojects/core/src/testFixtures/groovy/org/gradle/test/fixtures/ConcurrentTestUtil.groovy
+++ /dev/null
@@ -1,800 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.test.fixtures
-
-import org.gradle.internal.concurrent.ExecutorFactory
-import org.gradle.internal.concurrent.StoppableExecutor
-import org.junit.rules.ExternalResource
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import java.util.concurrent.AbstractExecutorService
-import java.util.concurrent.CopyOnWriteArraySet
-import java.util.concurrent.Executor
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.locks.Condition
-import java.util.concurrent.locks.Lock
-import java.util.concurrent.locks.ReentrantLock
-
-/**
- * <p>A base class for writing specifications which exercise concurrent code.
- *
- * <p>See {@link org.gradle.util.ConcurrentSpecificationTest} for some examples.
- *
- * <p>Provides {@link Executor} and {@link ExecutorFactory} implementations for use during the test. These provide real concurrency.
- * The test threads are cleaned up at the end of the test, and any exceptions thrown by those tests are propagated.
- *
- * <p>Provides some fixtures for testing:</p>
- *
- * <ul>
- * <li>An action starts another action asynchronously without waiting for the result.</li>
- * <li>An action starts another action asynchronously and waits for the result.</li>
- * </ul>
- */
-class ConcurrentTestUtil extends ExternalResource {
- private static final Logger LOG = LoggerFactory.getLogger(ConcurrentTestUtil.class)
-
- private Lock lock = new ReentrantLock()
- private Condition threadsChanged = lock.newCondition()
- private Set<TestThread> threads = [] as Set
- private Closure failureHandler
- private List<Throwable> failures = []
- private timeout = 5000
-
- ConcurrentTestUtil() {}
-
- ConcurrentTestUtil(int timeout) {
- this.timeout = timeout
- }
-
- @Override
- protected void after() {
- finished()
- }
-
- //simplistic polling assertion. attempts asserting every x millis up to some max timeout
- static void poll(int timeout = 10, Closure assertion) {
- def expiry = System.currentTimeMillis() + timeout * 1000 // convert to ms
- long sleepTime = 100
- while(true) {
- try {
- assertion()
- return
- } catch (Throwable t) {
- if (System.currentTimeMillis() > expiry) {
- throw t
- }
- sleepTime = Math.min(250, (long) (sleepTime * 1.2))
- Thread.sleep(sleepTime);
- }
- }
- }
-
- void setShortTimeout(int millis) {
- this.timeout = millis
- }
-
- ExecutorFactory getExecutorFactory() {
- return new ExecutorFactory() {
- StoppableExecutor create(String displayName) {
- return new StoppableExecutorStub(ConcurrentTestUtil.this)
- }
-
- StoppableExecutor create(String displayName, int fixedSize) {
- // Ignores size of thread pool
- return new StoppableExecutorStub(ConcurrentTestUtil.this)
- }
- }
- }
-
- Executor getExecutor() {
- return new Executor() {
- void execute(Runnable runnable) {
- startThread(runnable)
- }
- }
- }
-
- TestThread startThread(Runnable cl) {
- lock.lock()
- try {
- TestThread thread = new TestThread(this, lock, cl)
- thread.start()
- return thread
- } finally {
- lock.unlock()
- }
- }
-
- /**
- * Starts a thread which executes the given action/closure. Does not wait for the thread to complete.
- *
- * @return A handle to the test thread.
- */
- TestParticipant start(Runnable cl) {
- lock.lock()
- try {
- TestThread thread = new TestThread(this, lock, cl)
- thread.start()
- return new TestParticipantImpl(this, thread)
- } finally {
- lock.unlock()
- }
- }
-
- /**
- * Creates a new asynchronous action.
- */
- StartAsyncAction startsAsyncAction() {
- return new StartAsyncAction(this)
- }
-
- /**
- * Creates a new blocking action.
- */
- WaitForAsyncCallback waitsForAsyncCallback() {
- return new WaitForAsyncCallback(this)
- }
-
- /**
- * Creates a new action which waits until an async. action is complete.
- */
- WaitForAsyncAction waitsForAsyncActionToComplete() {
- return new WaitForAsyncAction(this)
- }
-
- /**
- * Returns a composite participant, which you can use to perform atomic operations on.
- *
- * @return A handle to the composite participant.
- */
- TestParticipant all(TestParticipant... participants) {
- return new CompositeTestParticipant(this, lock, participants as List)
- }
-
- void onFailure(Closure cl) {
- lock.lock()
- try {
- failureHandler = cl
- } finally {
- lock.unlock()
- }
- }
-
- private void failed(Throwable t) {
- lock.lock()
- try {
- if (failureHandler != null) {
- failureHandler.call(t)
- } else {
- failures << t
- }
- } finally {
- lock.unlock()
- }
- }
-
- /**
- * Waits for all threads to complete. Asserts that the threads complete in a 'short' time. Rethrows any exceptions thrown by test threads.
- */
- void finished() {
- Date timeout = shortTimeout()
- lock.lock()
- try {
- LOG.info("Waiting for test threads to complete.")
- while (!threads.isEmpty()) {
- if (!threadsChanged.awaitUntil(timeout)) {
- failed(new IllegalStateException("Timeout waiting for test threads to complete."))
- break;
- }
- }
- threads.each { thread ->
- thread.interrupt()
- }
-
- LOG.info("Finishing up.")
- if (!failures.isEmpty()) {
- throw failures[0]
- }
- } finally {
- failureHandler = null
- threads.clear()
- failures.clear()
- lock.unlock()
- }
-
- }
-
- Date shortTimeout() {
- return new Date(System.currentTimeMillis() + timeout)
- }
-
- void run(Closure cl, Date timeout) {
- def thread = new TestThread(this, lock, cl)
- thread.start()
- thread.completesBefore(timeout)
- }
-
- void onThreadStart(TestThread thread) {
- lock.lock()
- try {
- threads << thread
- threadsChanged.signalAll()
- } finally {
- lock.unlock()
- }
- }
-
- void onThreadComplete(TestThread thread, Throwable failure) {
- lock.lock()
- try {
- threads.remove(thread)
- if (failure) {
- failed(failure)
- }
- threadsChanged.signalAll()
- } finally {
- lock.unlock()
- }
- }
-}
-
-class TestThread extends Thread {
- private static final Logger LOG = LoggerFactory.getLogger(TestThread.class)
- private final ConcurrentTestUtil owner
- private final Runnable action
- private final Lock lock
- private final Condition stateChanged
- private boolean complete
-
- TestThread(ConcurrentTestUtil owner, Lock lock, Runnable action) {
- this.owner = owner
- this.action = action
- this.lock = lock
- this.stateChanged = lock.newCondition()
- }
-
- @Override
- void start() {
- LOG.info("$this started.")
-
- lock.lock()
- try {
- owner.onThreadStart(this)
- stateChanged.signalAll()
- } finally {
- lock.unlock()
- }
-
- super.start()
- }
-
- void running() {
- lock.lock()
- try {
- if (complete) {
- throw new IllegalStateException("$this should still be running, but is not.")
- }
- } finally {
- lock.unlock()
- }
- }
-
- void completesBefore(Date timeout) {
- lock.lock()
- try {
- LOG.info("Waiting for $this to complete.")
- while (!complete) {
- if (!stateChanged.awaitUntil(timeout)) {
- interrupt()
- throw new IllegalStateException("Timeout waiting for $this to complete.")
- }
- }
- LOG.info("$this completed.")
- } finally {
- lock.unlock()
- }
- }
-
- @Override
- void run() {
- Throwable failure = null
- try {
- action.run()
- } catch (Throwable t) {
- failure = t
- }
-
- lock.lock()
- try {
- complete = true
- stateChanged.signalAll()
- owner.onThreadComplete(this, failure)
- LOG.info("$this completed.")
- } finally {
- lock.unlock()
- }
- }
-}
-
-/**
- * Some potentially long running operation.
- */
-interface LongRunningAction {
- /**
- * Blocks until this action has completed. Asserts that the action completes in a 'short' time. Rethrows any exception from the action.
- */
- void completed()
-
- /**
- * Blocks until this action has completed. Asserts that the action completes within the specified time. Rethrows any exception from the action.
- */
- void completesWithin(long maxWaitValue, TimeUnit maxWaitUnits)
-
- /**
- * Blocks until this action has completed. Asserts that the action completes before the given time. Rethrows any exception from the action.
- */
- void completesBefore(Date timeout)
-}
-
-interface TestParticipant extends LongRunningAction {
- /**
- * Asserts that this test participant is running.
- */
- void running()
-}
-
-abstract class AbstractAction implements LongRunningAction {
-
- Date defaultExpiry
-
- AbstractAction(Date defaultExpiry) {
- this.defaultExpiry = defaultExpiry
- }
-
- void completed() {
- completesBefore(defaultExpiry)
- }
-
- void completesWithin(long maxWaitValue, TimeUnit maxWaitUnits) {
- Date expiry = new Date(System.currentTimeMillis() + maxWaitUnits.toMillis(maxWaitValue))
- completesBefore(expiry + 500)
- }
-
- abstract void completesBefore(Date timeout)
-}
-
-abstract class AbstractTestParticipant extends AbstractAction implements TestParticipant {
- private final ConcurrentTestUtil owner
-
- AbstractTestParticipant(ConcurrentTestUtil owner) {
- super(owner.shortTimeout())
- this.owner = owner
- }
-}
-
-class TestParticipantImpl extends AbstractTestParticipant {
- private final TestThread thread
-
- TestParticipantImpl(ConcurrentTestUtil owner, TestThread thread) {
- super(owner)
- this.thread = thread
- }
-
- @Override
- void completesBefore(Date timeout) {
- thread.completesBefore(timeout)
- }
-
- void running() {
- thread.running()
- }
-}
-
-class CompositeTestParticipant extends AbstractTestParticipant {
- private final List<TestParticipant> participants
- private final Lock lock
-
- CompositeTestParticipant(ConcurrentTestUtil owner, Lock lock, List<TestParticipant> participants) {
- super(owner)
- this.participants = participants
- this.lock = lock
- }
-
- void running() {
- lock.lock()
- try {
- participants*.running()
- } finally {
- lock.unlock()
- }
- }
-
- @Override
- void completesBefore(Date timeout) {
- lock.lock()
- try {
- participants*.completesBefore(timeout)
- } finally {
- lock.unlock()
- }
- }
-}
-
-class StoppableExecutorStub extends AbstractExecutorService implements StoppableExecutor {
- final ConcurrentTestUtil owner
- final Set<TestThread> threads = new CopyOnWriteArraySet<TestThread>()
-
- StoppableExecutorStub(ConcurrentTestUtil owner) {
- this.owner = owner
- }
-
- void stop() {
- def timeout = owner.shortTimeout()
- threads.each { it.completesBefore(timeout) }
- }
-
- void stop(int timeoutValue, TimeUnit timeoutUnits) {
- throw new UnsupportedOperationException()
- }
-
- void requestStop() {
- throw new UnsupportedOperationException()
- }
-
- void execute(Runnable runnable) {
- threads.add(owner.startThread(runnable))
- }
-
- void shutdown() {
- throw new UnsupportedOperationException()
- }
-
- List<Runnable> shutdownNow() {
- throw new UnsupportedOperationException()
- }
-
- boolean isShutdown() {
- throw new UnsupportedOperationException()
- }
-
- boolean isTerminated() {
- throw new UnsupportedOperationException()
- }
-
- boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
- throw new UnsupportedOperationException()
- }
-}
-
-class AbstractAsyncAction {
- protected final ConcurrentTestUtil owner
- private final Lock lock = new ReentrantLock()
- protected final Condition condition = lock.newCondition()
- protected Throwable failure
-
- AbstractAsyncAction(ConcurrentTestUtil owner) {
- this.owner = owner
- }
-
- protected Date shortTimeout() {
- return owner.shortTimeout()
- }
-
- protected void onFailure(Throwable throwable) {
- withLock {
- failure = throwable
- condition.signalAll()
- }
- }
-
- protected def withLock(Closure cl) {
- lock.lock()
- try {
- return cl.call()
- } finally {
- lock.unlock()
- }
- }
-}
-
-class StartAsyncAction extends AbstractAsyncAction {
- private boolean started
- private boolean completed
- private Thread startThread
-
- StartAsyncAction(ConcurrentTestUtil owner) {
- super(owner)
- }
-
- /**
- * Runs the given action, and then waits until another thread calls {@link #done()}. Asserts that the start action does not block waiting for
- * the async action to complete.
- *
- * @param action The start action
- * @return this
- */
- StartAsyncAction started(Runnable action) {
- owner.onFailure this.&onFailure
- doStart(action)
- waitForStartToComplete()
- waitForFinish()
- return this
- }
-
- /**
- * Marks that the async. action is now finished.
- */
- void done() {
- waitForStartToComplete()
- doFinish()
- }
-
-
- private void doStart(Runnable action) {
- owner.startThread {
- withLock {
- if (startThread != null) {
- throw new IllegalStateException("Cannot start action multiple times.")
- }
- startThread = Thread.currentThread()
- condition.signalAll()
- }
-
- action.run()
-
- withLock {
- started = true
- condition.signalAll()
- }
- }
-
- withLock {
- while (startThread == null) {
- condition.await()
- }
- }
- }
-
- private void doFinish() {
- withLock {
- if (completed) {
- throw new IllegalStateException("Cannot run async action multiple times.")
- }
- completed = true
- condition.signalAll()
- }
- }
-
- private void waitForStartToComplete() {
- Date timeout = shortTimeout()
- withLock {
- if (startThread == null) {
- def e = new IllegalStateException("Action has not been started.")
- e.printStackTrace()
- throw e
- }
- if (Thread.currentThread() == startThread) {
- def e = new IllegalStateException("Cannot wait for action to complete from the thread that is executing it.")
- e.printStackTrace()
- throw e
- }
- while (!started && !failure) {
- if (!condition.awaitUntil(timeout)) {
- throw new IllegalStateException("Expected action to complete quickly, but it did not.")
- }
- }
- if (failure) {
- throw failure
- }
- }
- }
-
- private void waitForFinish() {
- Date timeout = shortTimeout()
- withLock {
- while (!completed && !failure) {
- if (!condition.awaitUntil(timeout)) {
- throw new IllegalStateException("Expected async action to complete, but it did not.")
- }
- }
- if (failure) {
- throw failure
- }
- }
- }
-}
-
-abstract class AbstractWaitAction extends AbstractAsyncAction {
- protected boolean started
- protected boolean completed
-
- AbstractWaitAction(ConcurrentTestUtil owner) {
- super(owner)
- }
-
- protected void waitForBlockingActionToComplete() {
- Date expiry = shortTimeout()
- withLock {
- while (!completed && !failure) {
- if (!condition.awaitUntil(expiry)) {
- throw new IllegalStateException("Expected action to unblock, but it did not.")
- }
- }
- if (failure) {
- throw failure
- }
- }
- }
-
- protected void startBlockingAction(Runnable action) {
- owner.startThread {
- withLock {
- started = true
- condition.signalAll()
- }
-
- action.run()
-
- withLock {
- completed = true
- condition.signalAll()
- }
- }
-
- withLock {
- while (!started) {
- condition.await()
- }
- }
- }
-
- protected void assertBlocked() {
- withLock {
- if (completed) {
- throw new IllegalStateException("Expected action to block, but it did not.")
- }
- }
- }
-}
-
-class WaitForAsyncCallback extends AbstractWaitAction {
- private boolean callbackCompleted
- private Runnable callback
-
- WaitForAsyncCallback(ConcurrentTestUtil owner) {
- super(owner)
- }
-
- /**
- * Runs the given action. Asserts that it blocks until after asynchronous callback is made. The action must register the callback using {@link #callbackLater(Runnable)}.
- */
- WaitForAsyncCallback start(Runnable action) {
- owner.onFailure this.&onFailure
-
- startBlockingAction(action)
- waitForCallbackToBeRegistered()
-
- Thread.sleep(500)
-
- assertBlocked()
- runCallbackAction()
- waitForBlockingActionToComplete()
-
- return this
- }
-
- /**
- * Registers the callback which will unblock the action.
- */
- public void callbackLater(Runnable action) {
- withLock {
- if (callback) {
- throw new IllegalStateException("Cannot register callback action multiple times.")
- }
- if (!started) {
- throw new IllegalStateException("Action has not been started.")
- }
- callback = action
- condition.signalAll()
- }
- }
-
- private def runCallbackAction() {
- owner.startThread {
- callback.run()
-
- withLock {
- callbackCompleted = true
- condition.signalAll()
- }
- }
-
- Date timeout = shortTimeout()
- withLock {
- while (!callbackCompleted && !failure) {
- if (!condition.awaitUntil(timeout)) {
- throw new IllegalStateException("Expected callback action to complete, but it did not.")
- }
- }
- if (failure) {
- throw failure
- }
- }
- }
-
- private void waitForCallbackToBeRegistered() {
- Date expiry = shortTimeout()
- withLock {
- while (!callback && !failure && !completed) {
- if (!condition.awaitUntil(expiry)) {
- throw new IllegalStateException("Expected action to register a callback action, but it did not.")
- }
- }
- if (failure) {
- throw failure
- }
- if (completed) {
- throw new IllegalStateException("Expected action to block, but it did not.")
- }
- }
- }
-}
-
-class WaitForAsyncAction extends AbstractWaitAction {
- boolean asyncActionComplete
-
- WaitForAsyncAction(ConcurrentTestUtil owner) {
- super(owner)
- }
-
- WaitForAsyncAction start(Runnable action) {
- owner.onFailure this.&onFailure
- startBlockingAction(action)
- waitForAsyncAction()
- waitForBlockingActionToComplete()
- return this
- }
-
- WaitForAsyncAction done() {
- Thread.sleep(500)
- assertBlocked()
-
- withLock {
- asyncActionComplete = true
- condition.signalAll()
- }
-
- return this
- }
-
- def waitForAsyncAction() {
- Date expiry = shortTimeout()
- withLock {
- while (!asyncActionComplete && !completed && !failure) {
- if (!condition.awaitUntil(expiry)) {
- throw new IllegalStateException("Expected async action to be started, but it was not.")
- }
- }
- if (failure) {
- throw failure
- }
- if (!asyncActionComplete && completed) {
- throw new IllegalStateException("Expected action to block, but it did not.")
- }
- }
- }
-}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/AbstractAvailablePortAllocator.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/AbstractAvailablePortAllocator.groovy
new file mode 100644
index 0000000..aa764ff
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/AbstractAvailablePortAllocator.groovy
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
+
+
+abstract class AbstractAvailablePortAllocator implements PortAllocator {
+ public static final int RANGE_SIZE = 100
+ List<ReservedPortRange> reservations = []
+ protected final Lock lock = new ReentrantLock()
+ ReservedPortRangeFactory portRangeFactory = new DefaultReservedPortRangeFactory()
+ int rangeSize = RANGE_SIZE
+ int rangeCount = (MAX_PRIVATE_PORT - MIN_PRIVATE_PORT) / RANGE_SIZE
+
+ @Override
+ public int assignPort() {
+ try {
+ lock.lock()
+ return reservePort()
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ @Override
+ public void releasePort(int port) {
+ if (port == null) {
+ return
+ }
+
+ try {
+ lock.lock()
+ for (int i = 0; i < reservations.size(); i++) {
+ ReservedPortRange range = reservations.get(i)
+ if (range.allocated.contains(port)) {
+ range.deallocate(port)
+ if (reservations.size() > 1 && range.allocated.isEmpty()) {
+ releaseRange(range)
+ }
+ }
+ }
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ protected abstract ReservedPortRange reservePortRange()
+
+ protected void releaseRange(ReservedPortRange range) {
+ reservations.remove(range)
+ }
+
+ void clear() {
+ reservations.clear()
+ }
+
+ private int reservePort() {
+ while(true) {
+ for (int i = 0; i < reservations.size(); i++) {
+ ReservedPortRange range = reservations.get(i)
+ int port = range.allocate()
+ if (port > 0) {
+ return port
+ }
+ }
+ // if we couldn't allocate a port from the existing reserved port ranges, get another range
+ reservePortRange()
+ }
+ }
+
+ protected ReservedPortRange reservePortRange(int startPort, int endPort) {
+ ReservedPortRange range = portRangeFactory.getReservedPortRange(startPort, endPort)
+ reservations.add(range)
+ return range
+ }
+
+ protected boolean isReserved(int startPort, int endPort) {
+ return isReservedInList(reservations, startPort, endPort)
+ }
+
+ static boolean isReservedInList(List<ReservedPortRange> reservationList, int startPort, int endPort) {
+ for (int i=0; i<reservationList.size(); i++) {
+ ReservedPortRange range = reservationList.get(i)
+ if ((startPort <= range.endPort && startPort >= range.startPort)
+ || (endPort >= range.startPort && endPort <= range.endPort)) {
+ return true
+ }
+ }
+ return false
+ }
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/DefaultPortDetector.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/DefaultPortDetector.groovy
new file mode 100644
index 0000000..e31cd61
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/DefaultPortDetector.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+
+class DefaultPortDetector implements PortDetector {
+ /**
+ * Checks to see if a specific port is available.
+ *
+ * @param port the port to check for availability
+ * @return <tt>true</tt> if the port is available, <tt>false</tt> otherwise
+ */
+ public boolean isAvailable(int port) {
+ try {
+ ServerSocket ss = new ServerSocket(port)
+ try {
+ ss.setReuseAddress(true)
+ } finally {
+ ss.close()
+ }
+ DatagramSocket ds = new DatagramSocket(port)
+ try {
+ ds.setReuseAddress(true)
+ } finally {
+ ds.close()
+ }
+ return true
+ } catch (IOException e) {
+ return false
+ }
+ }
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/DefaultReservedPortRangeFactory.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/DefaultReservedPortRangeFactory.groovy
new file mode 100644
index 0000000..2257af8
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/DefaultReservedPortRangeFactory.groovy
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+
+class DefaultReservedPortRangeFactory implements ReservedPortRangeFactory {
+ @Override
+ ReservedPortRange getReservedPortRange(int startPort, int endPort) {
+ return new ReservedPortRange(startPort, endPort)
+ }
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/FixedAvailablePortAllocator.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/FixedAvailablePortAllocator.groovy
new file mode 100644
index 0000000..f051b22
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/FixedAvailablePortAllocator.groovy
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+class FixedAvailablePortAllocator extends AbstractAvailablePortAllocator {
+ static final String MAX_FORKS_SYSTEM_PROPERTY = "org.gradle.test.maxParallelForks"
+ static final String WORKER_ID_SYS_PROPERTY = "org.gradle.test.worker";
+ static final String AGENT_NUM_SYS_PROPERTY = "org.gradle.ci.agentNum";
+ static final String TOTAL_AGENTS_SYS_PROPERTY = "org.gradle.ci.agentCount";
+ private static FixedAvailablePortAllocator instance
+ final int workerId
+ final int agentNum
+ final int maxForks
+ final int totalAgents
+
+ FixedAvailablePortAllocator(int maxForks, int workerId, int agentNum, int totalAgents) {
+ this.agentNum = agentNum
+ this.workerId = workerId
+ this.maxForks = maxForks
+ this.totalAgents = totalAgents
+ this.rangeCount = maxForks * totalAgents
+ this.rangeSize = (MAX_PRIVATE_PORT - MIN_PRIVATE_PORT) / rangeCount
+ }
+
+ public static FixedAvailablePortAllocator getInstance() {
+ if (instance == null) {
+ int maxForks = Integer.getInteger(MAX_FORKS_SYSTEM_PROPERTY, 1)
+ int totalAgents = Integer.getInteger(TOTAL_AGENTS_SYS_PROPERTY, 1)
+ int agentNum = Integer.getInteger(AGENT_NUM_SYS_PROPERTY, 1)
+ int workerId = Integer.getInteger(WORKER_ID_SYS_PROPERTY, -1)
+ instance = new FixedAvailablePortAllocator(maxForks, workerId, agentNum, totalAgents)
+ }
+ return instance
+ }
+
+ @Override
+ protected ReservedPortRange reservePortRange() {
+ if (reservations.size() >= 1) {
+ throw new NoSuchElementException("All available ports in the fixed port range for agent ${agentNum}, worker ${workerId} have been exhausted.")
+ }
+
+ if (agentNum > totalAgents) {
+ throw new IllegalArgumentException("Agent number was set to ${agentNum} but totalAgents was set to ${totalAgents}.")
+ }
+
+ int fixedRange = 0
+ if (rangeCount > 1) {
+ if (workerId != -1) {
+ fixedRange = ((workerId - 1) % maxForks) + ((agentNum - 1) * maxForks)
+ } else {
+ throw new IllegalStateException("${MAX_FORKS_SYSTEM_PROPERTY} is set, but ${WORKER_ID_SYS_PROPERTY} was not!")
+ }
+ }
+
+ int startPort = MIN_PRIVATE_PORT + (fixedRange * rangeSize)
+ int endPort = startPort + rangeSize - 1
+ return reservePortRange(startPort, endPort)
+ }
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/PortAllocator.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/PortAllocator.groovy
new file mode 100644
index 0000000..8f40c30
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/PortAllocator.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+
+interface PortAllocator {
+ public static final int MIN_PRIVATE_PORT = 49152
+ public static final int MAX_PRIVATE_PORT = 65535
+
+ /**
+ * Assign and reserve a port
+ * @return the port assigned
+ */
+ int assignPort()
+
+ /**
+ * Release a previously assigned port
+ * @param port
+ */
+ void releasePort(int port)
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/PortDetector.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/PortDetector.groovy
new file mode 100644
index 0000000..0001ca7
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/PortDetector.groovy
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+
+interface PortDetector {
+ boolean isAvailable(int port)
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/ReservedPortRange.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/ReservedPortRange.groovy
new file mode 100644
index 0000000..3af9f9b
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/ReservedPortRange.groovy
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
+
+
+class ReservedPortRange {
+ final int startPort
+ final int endPort
+ private final Lock lock = new ReentrantLock()
+ PortDetector portDetector = new DefaultPortDetector()
+ final List<Integer> allocated = []
+ int current
+
+ public ReservedPortRange(int startPort, int endPort) {
+ this.startPort = startPort
+ this.endPort = endPort
+ current = startPort + new Random().nextInt(endPort - startPort)
+ }
+
+ /**
+ * Allocate an available port
+ *
+ * @return the port that was allocated
+ */
+ public int allocate() {
+ try {
+ lock.lock()
+ return getAvailablePort()
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ /**
+ * Deallocate the given port
+ *
+ * @param port
+ */
+ public void deallocate(int port) {
+ try {
+ lock.lock()
+ allocated.removeAll(port)
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ private int getAvailablePort() {
+ int first = current
+ while (true) {
+ current++
+ if (current > endPort) {
+ current = startPort
+ }
+
+ int candidate = current
+
+ if (!(candidate in allocated) && portDetector.isAvailable(candidate)) {
+ allocated.add(candidate)
+ return candidate
+ } else {
+ if (current == first) {
+ return -1
+ }
+ }
+ }
+ }
+
+ boolean equals(o) {
+ if (this.is(o)) {
+ return true
+ }
+ if (getClass() != o.class) {
+ return false
+ }
+
+ ReservedPortRange that = (ReservedPortRange) o
+
+ if (endPort != that.endPort) {
+ return false
+ }
+ if (startPort != that.startPort) {
+ return false
+ }
+
+ return true
+ }
+
+ int hashCode() {
+ int result
+ result = startPort
+ result = 31 * result + endPort
+ return result
+ }
+}
diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/ReservedPortRangeFactory.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/ReservedPortRangeFactory.groovy
new file mode 100644
index 0000000..6d26d98
--- /dev/null
+++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/ports/ReservedPortRangeFactory.groovy
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.util.ports
+
+
+interface ReservedPortRangeFactory {
+ ReservedPortRange getReservedPortRange(int startPort, int endPort)
+}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ArtifactDependenciesIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ArtifactDependenciesIntegrationTest.groovy
index 325939d..6aefe95 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ArtifactDependenciesIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ArtifactDependenciesIntegrationTest.groovy
@@ -18,6 +18,7 @@ package org.gradle.integtests.resolve
import org.gradle.integtests.fixtures.AbstractIntegrationTest
import org.gradle.integtests.fixtures.FluidDependenciesResolveRunner
import org.gradle.integtests.fixtures.TestResources
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
import org.junit.Before
import org.junit.Rule
@@ -28,6 +29,7 @@ import spock.lang.Issue
import static org.hamcrest.Matchers.containsString
@RunWith(FluidDependenciesResolveRunner)
+ at LeaksFileHandles
class ArtifactDependenciesIntegrationTest extends AbstractIntegrationTest {
@Rule
public final TestResources testResources = new TestResources(testDirectoryProvider)
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ClientModuleDependenciesResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ClientModuleDependenciesResolveIntegrationTest.groovy
index 8b565b3..efc2d2c 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ClientModuleDependenciesResolveIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ClientModuleDependenciesResolveIntegrationTest.groovy
@@ -16,7 +16,9 @@
package org.gradle.integtests.resolve
import org.gradle.integtests.fixtures.AbstractHttpDependencyResolutionTest
+import org.gradle.test.fixtures.file.LeaksFileHandles
+ at LeaksFileHandles
public class ClientModuleDependenciesResolveIntegrationTest extends AbstractHttpDependencyResolutionTest {
public void "uses metadata from Client Module and looks up artifact in declared repositories"() {
given:
@@ -107,4 +109,4 @@ task listClientModuleJars << {
then:
succeeds('listClientModuleJars')
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/DependencyHandlerApiResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/DependencyHandlerApiResolveIntegrationTest.groovy
new file mode 100644
index 0000000..f8c5add
--- /dev/null
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/DependencyHandlerApiResolveIntegrationTest.groovy
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.resolve
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.executer.ExecutionResult
+
+class DependencyHandlerApiResolveIntegrationTest extends AbstractIntegrationSpec {
+ public static final String GRADLE_TEST_KIT_JAR_BASE_NAME = 'gradle-test-kit-'
+
+ def setup() {
+ executer.requireGradleHome()
+
+ buildFile << """
+ apply plugin: 'java'
+
+ task resolveLibs(type: Copy) {
+ ext.extractedDir = file('\$buildDir/libs')
+ from configurations.testCompile
+ into extractedDir
+ }
+
+ task verifyTestKitJars {
+ dependsOn resolveLibs
+ }
+ """
+
+ file('src/test/java/com/gradle/example/MyTest.java') << javaClassReferencingTestKit()
+ }
+
+ def "gradleTestKit dependency API adds test-kit classes and can compile against them"() {
+ given:
+ buildFile << testKitDependency()
+ buildFile << """
+ verifyTestKitJars {
+ doLast {
+ def jarFiles = resolveLibs.extractedDir.listFiles()
+ def testKitFunctionalJar = jarFiles.find { it.name.startsWith('$GRADLE_TEST_KIT_JAR_BASE_NAME') }
+ assert testKitFunctionalJar
+
+ def jar = new java.util.jar.JarFile(testKitFunctionalJar)
+ def jarFileEntries = jar.entries()
+ def classFiles = jarFileEntries.findAll { it.name.endsWith('.class') }
+
+ classFiles.each {
+ assert it.name.startsWith('org/gradle/testkit')
+ }
+ }
+ }
+ """
+
+ when:
+ ExecutionResult result = succeeds('verifyTestKitJars', 'compileTestJava')
+
+ then:
+ result.assertTaskNotSkipped(':compileTestJava')
+ }
+
+ def "gradleApi dependency API does not include test-kit JAR"() {
+ when:
+ buildFile << gradleApiDependency()
+ buildFile << """
+ verifyTestKitJars {
+ doLast {
+ def jarFiles = resolveLibs.extractedDir.listFiles()
+ def testKitFunctionalJar = jarFiles.find { it.name.startsWith('$GRADLE_TEST_KIT_JAR_BASE_NAME') }
+ assert !testKitFunctionalJar
+ }
+ }
+ """
+
+ then:
+ succeeds('verifyTestKitJars')
+ }
+
+ def "gradleApi dependency API cannot compile class that relies on test-kit JAR"() {
+ given:
+ buildFile << gradleApiDependency()
+
+ when:
+ ExecutionResult result = fails('compileTestJava')
+
+ then:
+ result.assertTaskNotSkipped(':compileTestJava')
+ result.error.contains('package org.gradle.testkit.runner does not exist')
+ }
+
+ private String gradleApiDependency() {
+ testCompileDependency('gradleApi()')
+ }
+
+ private String testKitDependency() {
+ testCompileDependency('gradleTestKit()')
+ }
+
+ private String testCompileDependency(String dependencyNotation) {
+ """
+ dependencies {
+ testCompile $dependencyNotation
+ }
+ """
+ }
+
+ private String javaClassReferencingTestKit() {
+ """package com.gradle.example;
+
+ import org.gradle.testkit.runner.GradleRunner;
+
+ public class MyTest {}
+ """
+ }
+}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ProjectDependencyResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ProjectDependencyResolveIntegrationTest.groovy
index 29938e3..19c55d7 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ProjectDependencyResolveIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ProjectDependencyResolveIntegrationTest.groovy
@@ -14,6 +14,7 @@
* limitations under the License.
*/
package org.gradle.integtests.resolve
+
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.FluidDependenciesResolveRunner
import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
@@ -154,7 +155,7 @@ project(":b") {
}
@Issue("GRADLE-2899")
- public void "consuming project can refer to multiple configurations of target project"() {
+ public void "multiple project configurations can refer to different configurations of target project"() {
given:
file('settings.gradle') << "include 'a', 'b'"
@@ -337,18 +338,18 @@ allprojects {
project(":a") {
configurations { 'default' {} }
dependencies { 'default' 'group:externalA:1.5' }
- task aJar(type: Jar) { baseName='a' }
- task bJar(type: Jar) { baseName='b' }
- artifacts { 'default' aJar, bJar }
+ task xJar(type: Jar) { baseName='x' }
+ task yJar(type: Jar) { baseName='y' }
+ artifacts { 'default' xJar, yJar }
}
project(":b") {
configurations { compile }
- dependencies { compile(project(':a')) { artifact { name = 'b'; type = 'jar' } } }
+ dependencies { compile(project(':a')) { artifact { name = 'y'; type = 'jar' } } }
task test {
inputs.files configurations.compile
doFirst {
- assert configurations.compile.files.collect { it.name } == ['b.jar', 'externalA-1.5.jar']
+ assert configurations.compile.files.collect { it.name } == ['y.jar', 'externalA-1.5.jar']
}
}
}
@@ -358,7 +359,7 @@ project(":b") {
succeeds 'b:test'
// Demonstrates superfluous task dependencies for project artifacts
- executedAndNotSkipped ":a:aJar", ":a:bJar" // Should be only the ":a:aJar"
+ executedAndNotSkipped ":a:xJar", ":a:yJar" // Should be only the ":a:yJar"
}
public void "reports project dependency that refers to an unknown artifact"() {
@@ -571,4 +572,47 @@ project('c') {
then:
output.contains "Changed dependencies of configuration ':api:conf' after it has been included in dependency resolution"
}
+
+ @Issue("GRADLE-3330")
+ public void "single project configuration can refer to multiple configurations of target project"() {
+ given:
+ file('settings.gradle') << "include 'a', 'b'"
+
+ and:
+ buildFile << """
+project(':a') {
+ configurations {
+ configA1
+ configA2
+ }
+ task A1jar(type: Jar) {
+ archiveName = 'A1.jar'
+ }
+ task A2jar(type: Jar) {
+ archiveName = 'A2.jar'
+ }
+ artifacts {
+ configA1 A1jar
+ configA2 A2jar
+ }
+}
+
+project(':b') {
+ configurations {
+ configB
+ }
+ dependencies {
+ configB project(path:':a', configuration:'configA1')
+ configB project(path:':a', configuration:'configA2')
+ }
+ task check(dependsOn: configurations.configB) << {
+ assert configurations.configB.collect { it.name } == ['A1.jar', 'A2.jar']
+ }
+}
+"""
+
+ expect:
+ succeeds ":b:check"
+ executedAndNotSkipped ":a:A1jar", ":a:A2jar"
+ }
}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveCrossVersionIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveCrossVersionIntegrationTest.groovy
index 2cf89c5..a43048c 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveCrossVersionIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveCrossVersionIntegrationTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.integtests.resolve
import org.gradle.integtests.fixtures.CrossVersionIntegrationSpec
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.ivy.IvyFileRepository
import org.gradle.test.fixtures.server.http.HttpServer
import org.gradle.test.fixtures.server.http.IvyHttpRepository
@@ -23,6 +24,7 @@ import org.gradle.test.fixtures.server.http.MavenHttpRepository
import org.junit.Rule
import spock.lang.Issue
+ at LeaksFileHandles
class ResolveCrossVersionIntegrationTest extends CrossVersionIntegrationSpec {
@Rule
HttpServer server = new HttpServer()
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveTestFixture.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveTestFixture.groovy
index e700507..915ab3e 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveTestFixture.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ResolveTestFixture.groovy
@@ -285,6 +285,17 @@ allprojects {
}
/**
+ * Defines a dependency from the current node to the given node. The closure delegates to a {@link NodeBuilder} instance that represents the target node.
+ */
+ NodeBuilder edge(String requested, String selectedModuleVersionId, @DelegatesTo(NodeBuilder) Closure cl) {
+ def node = edge(requested, selectedModuleVersionId)
+ cl.resolveStrategy = Closure.DELEGATE_ONLY
+ cl.delegate = node
+ cl.call()
+ return node
+ }
+
+ /**
* Defines a dependency of the current node.
*/
EdgeBuilder dependency(Map requested) {
@@ -349,4 +360,4 @@ public class GenerateGraphTask extends DefaultTask {
}
return "${reason.description}:${reasons.join(',')}"
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/artifactreuse/CacheReuseCrossVersionIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/artifactreuse/CacheReuseCrossVersionIntegrationTest.groovy
index 4a332d6..8cb8c45 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/artifactreuse/CacheReuseCrossVersionIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/artifactreuse/CacheReuseCrossVersionIntegrationTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.integtests.resolve.artifactreuse
import org.gradle.integtests.fixtures.TargetVersions
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.maven.MavenFileRepository
import org.gradle.test.fixtures.server.http.MavenHttpRepository
import org.gradle.test.fixtures.server.http.HttpServer
@@ -26,6 +27,7 @@ import org.gradle.api.internal.artifacts.ivyservice.DefaultCacheLockingManager
@TargetVersions('1.0-milestone-6+')
@IgnoreVersions({ it.artifactCacheLayoutVersion == DefaultCacheLockingManager.CACHE_LAYOUT_VERSION || it.version.version == "1.9-rc-1" })
+ at LeaksFileHandles
class CacheReuseCrossVersionIntegrationTest extends AbstractCacheReuseCrossVersionIntegrationTest {
@Rule public final HttpServer server = new HttpServer()
final MavenHttpRepository httpRepo = new MavenHttpRepository(server, new MavenFileRepository(file("maven-repo")))
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/http/HttpAuthenticationDependencyResolutionIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/http/HttpAuthenticationDependencyResolutionIntegrationTest.groovy
index 726d414..f5b844a 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/http/HttpAuthenticationDependencyResolutionIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/http/HttpAuthenticationDependencyResolutionIntegrationTest.groovy
@@ -14,7 +14,8 @@
* limitations under the License.
*/
package org.gradle.integtests.resolve.http
-
+import org.gradle.authentication.http.BasicAuthentication
+import org.gradle.authentication.http.DigestAuthentication
import org.gradle.integtests.fixtures.AbstractHttpDependencyResolutionTest
import org.gradle.test.fixtures.server.http.HttpServer
import org.hamcrest.Matchers
@@ -24,14 +25,13 @@ class HttpAuthenticationDependencyResolutionIntegrationTest extends AbstractHttp
static String badCredentials = "credentials{username 'testuser'; password 'bad'}"
@Unroll
- public void "can resolve dependencies from #authScheme authenticated HTTP ivy repository"() {
+ def "can resolve dependencies using #authSchemeName scheme from #authScheme authenticated HTTP ivy repository"() {
given:
def moduleA = ivyHttpRepo.module('group', 'projectA', '1.2').publish()
ivyHttpRepo.module('group', 'projectB', '2.1').publish()
ivyHttpRepo.module('group', 'projectB', '2.2').publish()
def moduleB = ivyHttpRepo.module('group', 'projectB', '2.3').publish()
ivyHttpRepo.module('group', 'projectB', '3.0').publish()
-
and:
buildFile << """
repositories {
@@ -42,6 +42,8 @@ repositories {
password 'password'
username 'username'
}
+
+ ${authSchemeType}
}
}
configurations { compile }
@@ -66,9 +68,17 @@ task listJars << {
then:
succeeds('listJars')
+ and:
+ server.authenticationOrder.asList() == authenticationOrder
where:
- authScheme << [HttpServer.AuthScheme.BASIC, HttpServer.AuthScheme.DIGEST]
+ authSchemeName | authSchemeType | authScheme | authenticationOrder
+ 'basic' | 'authentication { auth(BasicAuthentication) }' | HttpServer.AuthScheme.BASIC | ['Basic']
+ 'digest' | 'authentication { auth(DigestAuthentication) }' | HttpServer.AuthScheme.DIGEST | ['None', 'Digest']
+ 'default' | '' | HttpServer.AuthScheme.BASIC | ['None', 'Basic']
+ 'default' | '' | HttpServer.AuthScheme.DIGEST | ['None', 'Digest']
+ 'basic' | 'authentication { auth(BasicAuthentication) }' | HttpServer.AuthScheme.PREEMPTIVE_BASIC | ['Basic']
+ 'basic and digest' | 'authentication { basic(BasicAuthentication)\ndigest(DigestAuthentication) }' | HttpServer.AuthScheme.DIGEST | ['Basic', 'Digest']
}
@Unroll
@@ -91,6 +101,8 @@ repositories {
password 'password'
username 'username'
}
+
+ ${authSchemeType}
}
}
configurations { compile }
@@ -125,9 +137,17 @@ task listJars << {
then:
succeeds('listJars')
+ and:
+ server.authenticationOrder.asList() == authenticationOrder
where:
- authScheme << [HttpServer.AuthScheme.BASIC, HttpServer.AuthScheme.DIGEST]
+ authSchemeName | authSchemeType | authScheme | authenticationOrder
+ 'basic' | 'authentication { auth(BasicAuthentication) }' | HttpServer.AuthScheme.BASIC | ['Basic']
+ 'digest' | 'authentication { auth(DigestAuthentication) }' | HttpServer.AuthScheme.DIGEST | ['None', 'Digest']
+ 'default' | '' | HttpServer.AuthScheme.BASIC | ['None', 'Basic']
+ 'default' | '' | HttpServer.AuthScheme.DIGEST | ['None', 'Digest']
+ 'basic' | 'authentication { auth(BasicAuthentication) }' | HttpServer.AuthScheme.PREEMPTIVE_BASIC | ['Basic']
+ 'basic and digest' | 'authentication { basic(BasicAuthentication)\ndigest(DigestAuthentication) }' | HttpServer.AuthScheme.DIGEST | ['Basic', 'Digest']
}
@Unroll
@@ -137,20 +157,20 @@ task listJars << {
when:
settingsFile << 'rootProject.name = "publish"'
buildFile << """
- repositories {
- ivy {
- url "${ivyHttpRepo.uri}"
- $creds
- }
- }
- configurations { compile }
- dependencies {
- compile 'group:projectA:1.2'
- }
- task listJars << {
- assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
- }
- """
+repositories {
+ ivy {
+ url "${ivyHttpRepo.uri}"
+ $creds
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task listJars << {
+ assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
+}
+"""
and:
server.authenticationScheme = authScheme
@@ -166,9 +186,11 @@ task listJars << {
.assertThatCause(Matchers.containsString('Received status code 401 from server: Unauthorized'))
where:
- authScheme << [HttpServer.AuthScheme.BASIC, HttpServer.AuthScheme.DIGEST, HttpServer.AuthScheme.BASIC, HttpServer.AuthScheme.DIGEST]
- credsName << ['empty', 'empty', 'bad', 'bad']
- creds << ['', '', badCredentials, badCredentials]
+ authScheme | credsName | creds
+ HttpServer.AuthScheme.BASIC | 'missing' | ''
+ HttpServer.AuthScheme.DIGEST | 'missing' | ''
+ HttpServer.AuthScheme.BASIC | 'bad' | badCredentials
+ HttpServer.AuthScheme.DIGEST | 'bad' | badCredentials
}
@Unroll
@@ -179,20 +201,20 @@ task listJars << {
when:
settingsFile << 'rootProject.name = "publish"'
buildFile << """
- repositories {
- maven {
- url "${mavenHttpRepo.uri}"
- $creds
- }
- }
- configurations { compile }
- dependencies {
- compile 'group:projectA:1.2'
- }
- task listJars << {
- assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
- }
- """
+repositories {
+ maven {
+ url "${mavenHttpRepo.uri}"
+ $creds
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task listJars << {
+ assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
+}
+"""
and:
server.authenticationScheme = authScheme
@@ -208,8 +230,186 @@ task listJars << {
.assertThatCause(Matchers.containsString('Received status code 401 from server: Unauthorized'))
where:
- authScheme << [HttpServer.AuthScheme.BASIC, HttpServer.AuthScheme.DIGEST, HttpServer.AuthScheme.BASIC, HttpServer.AuthScheme.DIGEST]
- credsName << ['empty', 'empty', 'bad', 'bad']
- creds << ['', '', badCredentials, badCredentials]
+ authScheme | credsName | creds
+ HttpServer.AuthScheme.BASIC | 'missing' | ''
+ HttpServer.AuthScheme.DIGEST | 'missing' | ''
+ HttpServer.AuthScheme.BASIC | 'bad' | badCredentials
+ HttpServer.AuthScheme.DIGEST | 'bad' | badCredentials
+ }
+
+ @Unroll
+ def "reports failure resolving with #configuredAuthScheme from #authScheme authenticated HTTP ivy repository"() {
+ given:
+ def module = ivyHttpRepo.module('group', 'projectA', '1.2').publish()
+ when:
+ settingsFile << 'rootProject.name = "publish"'
+ buildFile << """
+repositories {
+ ivy {
+ url "${ivyHttpRepo.uri}"
+ credentials {
+ username = 'username'
+ password = 'password'
+ }
+
+ authentication {
+ auth(${configuredAuthScheme})
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task listJars << {
+ assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
+}
+"""
+
+ and:
+ server.authenticationScheme = authScheme
+ server.allowGetOrHead('/repo/group/projectA/1.2/ivy-1.2.xml', 'username', 'password', module.ivyFile)
+
+ then:
+ fails 'listJars'
+
+ and:
+ failure
+ .assertHasDescription('Execution failed for task \':listJars\'.')
+ .assertResolutionFailure(':compile')
+ .assertThatCause(Matchers.containsString('Received status code 401 from server: Unauthorized'))
+
+ where:
+ authScheme | configuredAuthScheme
+ HttpServer.AuthScheme.BASIC | DigestAuthentication.class.getSimpleName()
+ HttpServer.AuthScheme.DIGEST | BasicAuthentication.class.getSimpleName()
+ }
+
+ @Unroll
+ def "reports failure resolving with #configuredAuthScheme from #authScheme authenticated HTTP maven repository"() {
+ given:
+ def module = mavenHttpRepo.module('group', 'projectA', '1.2').publish()
+
+ when:
+ settingsFile << 'rootProject.name = "publish"'
+ buildFile << """
+repositories {
+ maven {
+ url "${mavenHttpRepo.uri}"
+ credentials {
+ username = 'username'
+ password = 'password'
+ }
+
+ authentication {
+ auth(${configuredAuthScheme})
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task listJars << {
+ assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
+}
+"""
+
+ and:
+ server.authenticationScheme = authScheme
+ module.pom.allowGetOrHead('username', 'password')
+
+ then:
+ fails 'listJars'
+
+ and:
+ failure
+ .assertHasDescription('Execution failed for task \':listJars\'.')
+ .assertResolutionFailure(':compile')
+ .assertThatCause(Matchers.containsString('Received status code 401 from server: Unauthorized'))
+
+ where:
+ authScheme | configuredAuthScheme
+ HttpServer.AuthScheme.BASIC | DigestAuthentication.class.getSimpleName()
+ HttpServer.AuthScheme.DIGEST | BasicAuthentication.class.getSimpleName()
+ }
+
+ def "fails resolving from preemptive authenticated HTTP ivy repository"() {
+ given:
+ def module = ivyHttpRepo.module('group', 'projectA', '1.2').publish()
+ when:
+ settingsFile << 'rootProject.name = "publish"'
+ buildFile << """
+repositories {
+ ivy {
+ url "${ivyHttpRepo.uri}"
+ credentials {
+ username = 'username'
+ password = 'password'
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task listJars << {
+ assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
+}
+"""
+
+ and:
+ server.authenticationScheme = HttpServer.AuthScheme.PREEMPTIVE_BASIC
+ server.allowGetOrHead('/repo/group/projectA/1.2/ivy-1.2.xml', 'username', 'password', module.ivyFile)
+ server.allowGetOrHead('/repo/group/projectA/1.2/projectA-1.2.jar', 'username', 'password', module.jarFile)
+
+ then:
+ fails 'listJars'
+
+ and:
+ failure
+ .assertHasDescription('Execution failed for task \':listJars\'.')
+ .assertResolutionFailure(':compile')
+ .assertThatCause(Matchers.containsString('Could not find group:projectA:1.2'))
+ }
+
+ def "fails resolving from preemptive authenticated HTTP maven repository"() {
+ given:
+ def module = mavenHttpRepo.module('group', 'projectA', '1.2').publish()
+
+ when:
+ settingsFile << 'rootProject.name = "publish"'
+ buildFile << """
+repositories {
+ maven {
+ url "${mavenHttpRepo.uri}"
+ credentials {
+ username = 'username'
+ password = 'password'
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task listJars << {
+ assert configurations.compile.collect { it.name } == ['projectA-1.2.jar']
+}
+"""
+
+ and:
+ server.authenticationScheme = HttpServer.AuthScheme.PREEMPTIVE_BASIC
+ module.pom.allowGetOrHead('username', 'password')
+ module.artifact.allowGetOrHead('username', 'password')
+
+ then:
+ fails 'listJars'
+
+ and:
+ failure
+ .assertHasDescription('Execution failed for task \':listJars\'.')
+ .assertResolutionFailure(':compile')
+ .assertThatCause(Matchers.containsString('Could not find group:projectA:1.2'))
}
}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionRemoteResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionRemoteResolveIntegrationTest.groovy
index 86ce267..5c9d10a 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionRemoteResolveIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionRemoteResolveIntegrationTest.groovy
@@ -672,7 +672,7 @@ if (project.hasProperty('noDynamicRevisionCache')) {
}
}
- public void "resolves dynamic version with 2 repositories where first repo results in 404 for directory listing"() {
+ def "resolves dynamic version with 2 repositories where first repo results in 404 for directory listing"() {
given:
def repo1 = ivyHttpRepo("repo1")
def repo2 = ivyHttpRepo("repo2")
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionResolveIntegrationTest.groovy
index 01d2d22..bbf2a76 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionResolveIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyDynamicRevisionResolveIntegrationTest.groovy
@@ -397,6 +397,42 @@ Searched in the following locations:
}
}
+ @Issue("GRADLE-3334")
+ def "can resolve version range with single value specified"() {
+ given:
+ buildFile << """
+repositories {
+ ivy {
+ url "${ivyRepo.uri}"
+ }
+}
+
+configurations { compile }
+
+dependencies {
+ compile group: "org.test", name: "projectA", version: "[1.1]"
+}
+"""
+ and:
+ ivyRepo.module('org.test', 'projectB', '2.0').publish()
+ ivyRepo.module('org.test', 'projectA', '1.1').dependsOn('org.test', 'projectB', '[2.0]').publish()
+
+ def resolve = new ResolveTestFixture(buildFile)
+ resolve.prepare()
+
+ when:
+ succeeds 'checkDeps'
+
+ then:
+ resolve.expectGraph {
+ root(":", ":test:") {
+ edge("org.test:projectA:[1.1]", "org.test:projectA:1.1") {
+ edge("org.test:projectB:2.0", "org.test:projectB:2.0") // Transitive version range is lost when converting to Ivy ModuleDescriptor
+ }
+ }
+ }
+ }
+
@Issue("GRADLE-2502")
def "can resolve dynamic version from different repositories"() {
given:
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyFileRepoResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyFileRepoResolveIntegrationTest.groovy
index 7833d8d..e1403bb 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyFileRepoResolveIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyFileRepoResolveIntegrationTest.groovy
@@ -122,4 +122,34 @@ task retrieve(type: Sync) {
jarC1.assertIsCopyOf(projectC1.jarFile)
jarC1.assertHasChangedSince(jarCsnapshot)
}
+
+ def "cannot define authentication for local file repo"() {
+ given:
+ def repo = ivyRepo()
+ def moduleA = repo.module('group', 'projectA', '1.2')
+ moduleA.publish()
+ and:
+ buildFile << """
+repositories {
+ ivy {
+ url "${ivyRepo().uri}"
+ authentication {
+ auth(BasicAuthentication)
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task retrieve(type: Sync) {
+ from configurations.compile
+ into 'libs'
+}
+"""
+ expect:
+ fails 'retrieve'
+ and:
+ errorOutput.contains("> Authentication scheme 'auth'(BasicAuthentication) is not supported by protocol 'file'")
+ }
}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyModuleArtifactResolutionIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyModuleArtifactResolutionIntegrationTest.groovy
index 7621fb3..2bccc7e 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyModuleArtifactResolutionIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/ivy/IvyModuleArtifactResolutionIntegrationTest.groovy
@@ -113,6 +113,36 @@ repositories {
checkArtifactsResolvedAndCached()
}
+ def "request an ivy descriptor for an ivy module with a custom ivy pattern"() {
+ given:
+ httpRepo = server.getRemoteIvyRepo(true, "[module]/[revision]", "alternate-ivy.xml", "[artifact](.[ext])")
+
+ buildFile.text = """
+repositories {
+ ivy {
+ url '${httpRepo.uri}'
+ layout 'pattern', {
+ artifact '[module]/[revision]/[artifact](.[ext])'
+ ivy '[module]/[revision]/alternate-ivy.xml'
+ }
+ }
+}
+"""
+ fixture = new MetadataArtifactResolveTestFixture(buildFile)
+ fixture.basicSetup()
+ IvyHttpModule module = publishModule()
+
+ when:
+ fixture.requestComponent('IvyModule').requestArtifact('IvyDescriptorArtifact')
+ .expectResolvedComponentResult().expectMetadataFiles(file("ivy-${fixture.id.version}.xml"))
+ .createVerifyTaskModuleComponentIdentifier()
+
+ module.ivy.expectGet()
+
+ then:
+ checkArtifactsResolvedAndCached()
+ }
+
@Unroll
def "updates artifacts for module #condition"() {
given:
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/maven/MavenFileRepoResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/maven/MavenFileRepoResolveIntegrationTest.groovy
index 14a377e..1396619 100644
--- a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/maven/MavenFileRepoResolveIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/maven/MavenFileRepoResolveIntegrationTest.groovy
@@ -133,4 +133,34 @@ task retrieve(type: Sync) {
buildDir.file('projectA-1.2.jar').assertIsCopyOf(artifactsModuleA.artifactFile)
buildDir.file('projectB-9.1.jar').assertIsCopyOf(moduleB.artifactFile)
}
+
+ def "cannot define authentication for local file repo"() {
+ given:
+ def repo = mavenRepo()
+ def moduleA = repo.module('group', 'projectA', '1.2')
+ moduleA.publish()
+ and:
+ buildFile << """
+repositories {
+ maven {
+ url "${repo.uri}"
+ authentication {
+ auth(BasicAuthentication)
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task retrieve(type: Sync) {
+ from configurations.compile
+ into 'libs'
+}
+"""
+ expect:
+ fails 'retrieve'
+ and:
+ errorOutput.contains("> Authentication scheme 'auth'(BasicAuthentication) is not supported by protocol 'file'")
+ }
}
diff --git a/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/maven/MavenVersionRangeResolveIntegrationTest.groovy b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/maven/MavenVersionRangeResolveIntegrationTest.groovy
new file mode 100644
index 0000000..0287ef4
--- /dev/null
+++ b/subprojects/dependency-management/src/integTest/groovy/org/gradle/integtests/resolve/maven/MavenVersionRangeResolveIntegrationTest.groovy
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.resolve.maven
+
+import org.gradle.integtests.fixtures.AbstractDependencyResolutionTest
+import org.gradle.integtests.resolve.ResolveTestFixture
+import spock.lang.Issue
+
+class MavenVersionRangeResolveIntegrationTest extends AbstractDependencyResolutionTest {
+
+ @Issue("GRADLE-3334")
+ def "can resolve version range with single value specified"() {
+ given:
+ settingsFile << "rootProject.name = 'test' "
+ buildFile << """
+repositories {
+ maven {
+ url "${mavenRepo.uri}"
+ }
+}
+
+configurations { compile }
+
+dependencies {
+ compile group: "org.test", name: "projectA", version: "[1.1]"
+}
+"""
+ and:
+ mavenRepo.module('org.test', 'projectB', '2.0').publish()
+ mavenRepo.module('org.test', 'projectA', '1.1').dependsOn('org.test', 'projectB', '[2.0]').publish()
+
+ def resolve = new ResolveTestFixture(buildFile)
+ resolve.prepare()
+
+ when:
+ succeeds 'checkDeps'
+
+ then:
+ resolve.expectGraph {
+ root(":", ":test:") {
+ edge("org.test:projectA:[1.1]", "org.test:projectA:1.1") {
+ edge("org.test:projectB:2.0", "org.test:projectB:2.0") // Transitive version range is lost when converting to Ivy ModuleDescriptor
+ }
+ }
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ArtifactDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ArtifactDependencyResolver.java
index a7d7f10..76e9906 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ArtifactDependencyResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ArtifactDependencyResolver.java
@@ -15,8 +15,8 @@
*/
package org.gradle.api.internal.artifacts;
-import org.gradle.api.artifacts.ResolveContext;
-import org.gradle.api.artifacts.ResolveException;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor;
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
import java.util.List;
@@ -25,10 +25,6 @@ public interface ArtifactDependencyResolver {
void resolve(ResolveContext resolveContext,
List<? extends ResolutionAwareRepository> repositories,
GlobalDependencyResolutionRules metadataHandler,
- ResolverResults results) throws ResolveException;
-
- void resolveArtifacts(ResolveContext resolveContext,
- List<? extends ResolutionAwareRepository> repositories,
- GlobalDependencyResolutionRules metadataHandler,
- ResolverResults results) throws ResolveException;
+ DependencyGraphVisitor graphVisitor,
+ DependencyArtifactsVisitor artifactsVisitor);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentMetadataProcessor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentMetadataProcessor.java
index 7f6aa5e..28554e2 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentMetadataProcessor.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentMetadataProcessor.java
@@ -18,5 +18,11 @@ package org.gradle.api.internal.artifacts;
import org.gradle.internal.component.external.model.MutableModuleComponentResolveMetaData;
public interface ComponentMetadataProcessor {
+ static ComponentMetadataProcessor NO_OP = new ComponentMetadataProcessor() {
+ @Override
+ public void processMetadata(MutableModuleComponentResolveMetaData metadata) {
+ }
+ };
+
void processMetadata(MutableModuleComponentResolveMetaData metadata);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentModuleMetadataProcessor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentModuleMetadataProcessor.java
index 0bde1fc..bafc657 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentModuleMetadataProcessor.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ComponentModuleMetadataProcessor.java
@@ -19,5 +19,12 @@ package org.gradle.api.internal.artifacts;
import org.gradle.api.internal.artifacts.dsl.ModuleReplacementsData;
public interface ComponentModuleMetadataProcessor {
+ ComponentModuleMetadataProcessor NO_OP = new ComponentModuleMetadataProcessor() {
+ @Override
+ public ModuleReplacementsData getModuleReplacements() {
+ return ModuleReplacementsData.NO_OP;
+ }
+ };
+
ModuleReplacementsData getModuleReplacements();
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java
index 21ef60a..d131242 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java
@@ -15,10 +15,11 @@
*/
package org.gradle.api.internal.artifacts;
-import org.gradle.api.Project;
+import org.gradle.StartParameter;
import org.gradle.api.artifacts.PublishArtifact;
import org.gradle.api.artifacts.dsl.*;
import org.gradle.api.internal.DomainObjectContext;
+import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory;
import org.gradle.api.internal.artifacts.configurations.ConfigurationContainerInternal;
import org.gradle.api.internal.artifacts.configurations.DefaultConfigurationContainer;
import org.gradle.api.internal.artifacts.configurations.DependencyMetaDataProvider;
@@ -31,6 +32,10 @@ import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolveIvyFactory
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.GradlePomModuleDescriptorParser;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.ResolverStrategy;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ConfigurationsToArtifactsConverter;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ConfigurationsToModuleDescriptorConverter;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependenciesToModuleDescriptorConverter;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.store.ResolutionResultsStoreFactory;
import org.gradle.api.internal.artifacts.mvnsettings.LocalMavenRepositoryLocator;
import org.gradle.api.internal.artifacts.query.ArtifactResolutionQueryFactory;
import org.gradle.api.internal.artifacts.query.DefaultArtifactResolutionQueryFactory;
@@ -40,6 +45,7 @@ import org.gradle.api.internal.component.ComponentTypeRegistry;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.api.internal.filestore.ivy.ArtifactIdentifierFileStore;
import org.gradle.initialization.ProjectAccessListener;
+import org.gradle.internal.authentication.AuthenticationSchemeRegistry;
import org.gradle.internal.component.external.model.ModuleComponentArtifactMetaData;
import org.gradle.internal.event.ListenerManager;
import org.gradle.internal.reflect.Instantiator;
@@ -75,7 +81,8 @@ public class DefaultDependencyManagementServices implements DependencyManagement
BaseRepositoryFactory createBaseRepositoryFactory(LocalMavenRepositoryLocator localMavenRepositoryLocator, Instantiator instantiator, FileResolver fileResolver,
RepositoryTransportFactory repositoryTransportFactory, LocallyAvailableResourceFinder<ModuleComponentArtifactMetaData> locallyAvailableResourceFinder,
ResolverStrategy resolverStrategy, ArtifactIdentifierFileStore artifactIdentifierFileStore,
- VersionSelectorScheme versionSelectorScheme) {
+ VersionSelectorScheme versionSelectorScheme,
+ AuthenticationSchemeRegistry authenticationSchemeRegistry) {
return new DefaultBaseRepositoryFactory(
localMavenRepositoryLocator,
fileResolver,
@@ -84,7 +91,8 @@ public class DefaultDependencyManagementServices implements DependencyManagement
locallyAvailableResourceFinder,
resolverStrategy,
artifactIdentifierFileStore,
- new GradlePomModuleDescriptorParser(versionSelectorScheme)
+ new GradlePomModuleDescriptorParser(versionSelectorScheme),
+ authenticationSchemeRegistry
);
}
@@ -132,9 +140,25 @@ public class DefaultDependencyManagementServices implements DependencyManagement
return new DefaultGlobalDependencyResolutionRules(componentMetadataProcessor, moduleMetadataProcessor);
}
- ConfigurationResolver createDependencyResolver(ArtifactDependencyResolver artifactDependencyResolver, RepositoryHandler repositories,
- GlobalDependencyResolutionRules metadataHandler) {
- return new DefaultConfigurationResolver(artifactDependencyResolver, repositories, metadataHandler);
+ ConfigurationResolver createDependencyResolver(ArtifactDependencyResolver artifactDependencyResolver,
+ RepositoryHandler repositories,
+ GlobalDependencyResolutionRules metadataHandler,
+ ComponentIdentifierFactory componentIdentifierFactory,
+ CacheLockingManager cacheLockingManager,
+ ResolutionResultsStoreFactory resolutionResultsStoreFactory,
+ StartParameter startParameter) {
+ return new ErrorHandlingConfigurationResolver(
+ new ShortCircuitEmptyConfigurationResolver(
+ new SelfResolvingDependencyConfigurationResolver(
+ new DefaultConfigurationResolver(
+ artifactDependencyResolver,
+ repositories,
+ metadataHandler,
+ cacheLockingManager,
+ resolutionResultsStoreFactory,
+ startParameter.isBuildProjectDependencies())),
+ componentIdentifierFactory)
+ );
}
ArtifactPublicationServices createArtifactPublicationServices(ServiceRegistry services) {
@@ -153,12 +177,6 @@ public class DefaultDependencyManagementServices implements DependencyManagement
}
}
- private static class DependencyMetaDataProviderImpl implements DependencyMetaDataProvider {
- public ModuleInternal getModule() {
- return new DefaultModule("unspecified", "unspecified", Project.DEFAULT_VERSION, Project.DEFAULT_STATUS);
- }
- }
-
private static class DefaultDependencyResolutionServices implements DependencyResolutionServices {
private final ServiceRegistry services;
@@ -194,7 +212,9 @@ public class DefaultDependencyManagementServices implements DependencyManagement
public ArtifactPublisher createArtifactPublisher() {
return new IvyBackedArtifactPublisher(
- services.get(LocalComponentFactory.class),
+ services.get(ConfigurationsToModuleDescriptorConverter.class),
+ services.get(DependenciesToModuleDescriptorConverter.class),
+ services.get(ConfigurationsToArtifactsConverter.class),
services.get(IvyContextManager.class),
new DefaultIvyDependencyPublisher(),
new IvyXmlModuleDescriptorWriter()
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultResolvedArtifact.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultResolvedArtifact.java
index 262d638..2f828ec 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultResolvedArtifact.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultResolvedArtifact.java
@@ -17,20 +17,23 @@ package org.gradle.api.internal.artifacts;
import org.gradle.api.artifacts.ResolvedArtifact;
import org.gradle.api.artifacts.ResolvedModuleVersion;
-import org.gradle.internal.component.model.IvyArtifactName;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.internal.Factory;
+import org.gradle.internal.component.model.IvyArtifactName;
import java.io.File;
public class DefaultResolvedArtifact implements ResolvedArtifact {
private final ResolvedModuleVersion owner;
private final IvyArtifactName artifact;
+ private final ComponentArtifactIdentifier artifactId;
private Factory<File> artifactSource;
private File file;
- public DefaultResolvedArtifact(ResolvedModuleVersion owner, IvyArtifactName artifact, Factory<File> artifactSource) {
+ public DefaultResolvedArtifact(ResolvedModuleVersion owner, IvyArtifactName artifact, ComponentArtifactIdentifier artifactId, Factory<File> artifactSource) {
this.owner = owner;
this.artifact = artifact;
+ this.artifactId = artifactId;
this.artifactSource = artifactSource;
}
@@ -39,6 +42,11 @@ public class DefaultResolvedArtifact implements ResolvedArtifact {
}
@Override
+ public ComponentArtifactIdentifier getId() {
+ return artifactId;
+ }
+
+ @Override
public String toString() {
return String.format("[ResolvedArtifact dependency:%s name:%s classifier:%s extension:%s type:%s]", owner, getName(), getClassifier(), getExtension(), getType());
}
@@ -81,7 +89,7 @@ public class DefaultResolvedArtifact implements ResolvedArtifact {
public String getClassifier() {
return artifact.getClassifier();
}
-
+
public File getFile() {
if (file == null) {
file = artifactSource.create();
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultResolverResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultResolverResults.java
new file mode 100644
index 0000000..34807fb
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultResolverResults.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts;
+
+import org.gradle.api.artifacts.ResolveException;
+import org.gradle.api.artifacts.ResolvedConfiguration;
+import org.gradle.api.artifacts.result.ResolutionResult;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactResults;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactsBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedGraphResults;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.TransientConfigurationResultsBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResult;
+
+public class DefaultResolverResults implements ResolverResults {
+ private ResolvedConfiguration resolvedConfiguration;
+ private ResolutionResult resolutionResult;
+ private ResolveException fatalFailure;
+ private ResolvedLocalComponentsResult resolvedLocalComponentsResult;
+ private TransientConfigurationResultsBuilder transientConfigurationResultsBuilder;
+ private ResolvedGraphResults graphResults;
+ private ResolvedArtifactsBuilder artifactResults;
+
+ @Override
+ public boolean hasError() {
+ if (fatalFailure != null) {
+ return true;
+ }
+ if (resolvedConfiguration != null && resolvedConfiguration.hasError()) {
+ return true;
+ }
+ return false;
+ }
+
+ //old model, slowly being replaced by the new model
+ @Override
+ public ResolvedConfiguration getResolvedConfiguration() {
+ assertHasArtifacts();
+ return resolvedConfiguration;
+ }
+
+ //new model
+ @Override
+ public ResolutionResult getResolutionResult() {
+ assertHasResult();
+ if (fatalFailure != null) {
+ throw fatalFailure;
+ }
+ return resolutionResult;
+ }
+
+ @Override
+ public ResolvedLocalComponentsResult getResolvedLocalComponents() {
+ assertHasResult();
+ if (fatalFailure != null) {
+ throw fatalFailure;
+ }
+ return resolvedLocalComponentsResult;
+ }
+
+ private void assertHasResult() {
+ if (resolutionResult == null && fatalFailure == null) {
+ throw new IllegalStateException("Resolution result has not been attached.");
+ }
+ }
+
+ private void assertHasArtifacts() {
+ if (resolvedConfiguration == null) {
+ throw new IllegalStateException("Resolution artifacts have not been attached.");
+ }
+ }
+
+ @Override
+ public void resolved(ResolutionResult resolutionResult, ResolvedLocalComponentsResult resolvedLocalComponentsResult) {
+ this.resolutionResult = resolutionResult;
+ this.resolvedLocalComponentsResult = resolvedLocalComponentsResult;
+ this.fatalFailure = null;
+ }
+
+ @Override
+ public void failed(ResolveException failure) {
+ this.resolutionResult = null;
+ this.fatalFailure = failure;
+ }
+
+ @Override
+ public void withResolvedConfiguration(ResolvedConfiguration resolvedConfiguration) {
+ this.resolvedConfiguration = resolvedConfiguration;
+ this.graphResults = null;
+ this.transientConfigurationResultsBuilder = null;
+ this.artifactResults = null;
+ }
+
+ // State not exposed via BuildableResolverResults, that is only accessed via DefaultConfigurationResolver
+ public void retainState(ResolvedGraphResults graphResults, ResolvedArtifactsBuilder artifactResults, TransientConfigurationResultsBuilder transientConfigurationResultsBuilder) {
+ this.graphResults = graphResults;
+ this.artifactResults = artifactResults;
+ this.transientConfigurationResultsBuilder = transientConfigurationResultsBuilder;
+ }
+
+ public ResolvedGraphResults getGraphResults() {
+ return graphResults;
+ }
+
+ public ResolvedArtifactResults getResolvedArtifacts() {
+ return artifactResults.resolve();
+ }
+
+ public TransientConfigurationResultsBuilder getTransientConfigurationResultsBuilder() {
+ return transientConfigurationResultsBuilder;
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementBuildScopeServices.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementBuildScopeServices.java
index 8b25479..9d76542 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementBuildScopeServices.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementBuildScopeServices.java
@@ -18,24 +18,24 @@ package org.gradle.api.internal.artifacts;
import org.gradle.StartParameter;
import org.gradle.api.internal.ClassPathRegistry;
-import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory;
import org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory;
import org.gradle.api.internal.artifacts.ivyservice.*;
import org.gradle.api.internal.artifacts.ivyservice.dynamicversions.ModuleVersionsCache;
import org.gradle.api.internal.artifacts.ivyservice.dynamicversions.SingleFileBackedModuleVersionsCache;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolveIvyFactory;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.StartParameterResolutionOverride;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.*;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.memcache.InMemoryCachedRepositoryFactory;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.*;
import org.gradle.api.internal.artifacts.ivyservice.modulecache.DefaultModuleArtifactsCache;
import org.gradle.api.internal.artifacts.ivyservice.modulecache.DefaultModuleMetaDataCache;
import org.gradle.api.internal.artifacts.ivyservice.modulecache.ModuleArtifactsCache;
import org.gradle.api.internal.artifacts.ivyservice.modulecache.ModuleMetaDataCache;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ConfigurationLocalComponentConverter;
import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependencyDescriptorFactory;
import org.gradle.api.internal.artifacts.ivyservice.projectmodule.DefaultProjectComponentRegistry;
import org.gradle.api.internal.artifacts.ivyservice.projectmodule.DefaultProjectPublicationRegistry;
+import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectDependencyResolver;
import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectPublicationRegistry;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultDependencyResolver;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultArtifactDependencyResolver;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.store.ResolutionResultsStoreFactory;
import org.gradle.api.internal.artifacts.mvnsettings.*;
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransportFactory;
@@ -80,14 +80,14 @@ class DependencyManagementBuildScopeServices {
ClassPathRegistry classPathRegistry,
FileLookup fileLookup) {
DefaultProjectDependencyFactory factory = new DefaultProjectDependencyFactory(
- projectAccessListener, instantiator, startParameter.isBuildProjectDependencies());
+ projectAccessListener, instantiator, startParameter.isBuildProjectDependencies());
ProjectDependencyFactory projectDependencyFactory = new ProjectDependencyFactory(factory);
return new DefaultDependencyFactory(
- DependencyNotationParser.parser(instantiator, factory, classPathRegistry, fileLookup),
- new ClientModuleNotationParserFactory(instantiator).create(),
- projectDependencyFactory);
+ DependencyNotationParser.parser(instantiator, factory, classPathRegistry, fileLookup),
+ new ClientModuleNotationParserFactory(instantiator).create(),
+ projectDependencyFactory);
}
CacheLockingManager createCacheLockingManager(CacheRepository cacheRepository) {
@@ -100,39 +100,39 @@ class DependencyManagementBuildScopeServices {
ModuleVersionsCache createModuleVersionsCache(BuildCommencedTimeProvider timeProvider, CacheLockingManager cacheLockingManager) {
return new SingleFileBackedModuleVersionsCache(
- timeProvider,
- cacheLockingManager
+ timeProvider,
+ cacheLockingManager
);
}
ModuleArtifactsCache createModuleArtifactsCache(BuildCommencedTimeProvider timeProvider, CacheLockingManager cacheLockingManager) {
return new DefaultModuleArtifactsCache(
- timeProvider,
- cacheLockingManager
+ timeProvider,
+ cacheLockingManager
);
}
ModuleMetaDataCache createModuleDescriptorCache(BuildCommencedTimeProvider timeProvider, CacheLockingManager cacheLockingManager, ResolverStrategy resolverStrategy) {
return new DefaultModuleMetaDataCache(
- timeProvider,
- cacheLockingManager,
- resolverStrategy
+ timeProvider,
+ cacheLockingManager,
+ resolverStrategy
);
}
ArtifactAtRepositoryCachedArtifactIndex createArtifactAtRepositoryCachedResolutionIndex(BuildCommencedTimeProvider timeProvider, CacheLockingManager cacheLockingManager) {
return new ArtifactAtRepositoryCachedArtifactIndex(
- "artifact-at-repository",
- timeProvider,
- cacheLockingManager
+ "artifact-at-repository",
+ timeProvider,
+ cacheLockingManager
);
}
ByUrlCachedExternalResourceIndex createArtifactUrlCachedResolutionIndex(BuildCommencedTimeProvider timeProvider, CacheLockingManager cacheLockingManager) {
return new ByUrlCachedExternalResourceIndex(
- "artifact-at-url",
- timeProvider,
- cacheLockingManager
+ "artifact-at-url",
+ timeProvider,
+ cacheLockingManager
);
}
@@ -150,9 +150,9 @@ class DependencyManagementBuildScopeServices {
LocallyAvailableResourceFinder<ModuleComponentArtifactMetaData> createArtifactRevisionIdLocallyAvailableResourceFinder(ArtifactCacheMetaData artifactCacheMetaData, LocalMavenRepositoryLocator localMavenRepositoryLocator, ArtifactIdentifierFileStore fileStore) {
LocallyAvailableResourceFinderFactory finderFactory = new LocallyAvailableResourceFinderFactory(
- artifactCacheMetaData,
- localMavenRepositoryLocator,
- fileStore);
+ artifactCacheMetaData,
+ localMavenRepositoryLocator,
+ fileStore);
return finderFactory.create();
}
@@ -175,12 +175,12 @@ class DependencyManagementBuildScopeServices {
CacheLockingManager cacheLockingManager,
ServiceRegistry serviceRegistry) {
return new RepositoryTransportFactory(
- serviceRegistry.getAll(ResourceConnectorFactory.class),
- progressLoggerFactory,
- temporaryFileProvider,
- externalResourceIndex,
- buildCommencedTimeProvider,
- cacheLockingManager
+ serviceRegistry.getAll(ResourceConnectorFactory.class),
+ progressLoggerFactory,
+ temporaryFileProvider,
+ externalResourceIndex,
+ buildCommencedTimeProvider,
+ cacheLockingManager
);
}
@@ -190,42 +190,33 @@ class DependencyManagementBuildScopeServices {
VersionSelectorScheme versionSelectorScheme, VersionComparator versionComparator) {
StartParameterResolutionOverride startParameterResolutionOverride = new StartParameterResolutionOverride(startParameter);
return new ResolveIvyFactory(
- moduleVersionsCache,
- moduleMetaDataCache,
- moduleArtifactsCache,
- artifactAtRepositoryCachedArtifactIndex,
- cacheLockingManager,
- startParameterResolutionOverride,
- buildCommencedTimeProvider,
- inMemoryCachedRepositoryFactory,
- versionSelectorScheme,
- versionComparator);
- }
-
- ArtifactDependencyResolver createArtifactDependencyResolver(ResolveIvyFactory resolveIvyFactory, LocalComponentFactory publishModuleDescriptorConverter, DependencyDescriptorFactory dependencyDescriptorFactory,
- CacheLockingManager cacheLockingManager, IvyContextManager ivyContextManager, ResolutionResultsStoreFactory resolutionResultsStoreFactory,
- VersionComparator versionComparator, ProjectRegistry<ProjectInternal> projectRegistry, ComponentIdentifierFactory componentIdentifierFactory,
- StartParameter startParameter) {
- ArtifactDependencyResolver resolver = new DefaultDependencyResolver(
- resolveIvyFactory,
- publishModuleDescriptorConverter,
- dependencyDescriptorFactory,
- new DefaultProjectComponentRegistry(
- publishModuleDescriptorConverter,
- projectRegistry),
- cacheLockingManager,
- ivyContextManager,
- resolutionResultsStoreFactory,
- versionComparator,
- startParameter.isBuildProjectDependencies()
+ moduleVersionsCache,
+ moduleMetaDataCache,
+ moduleArtifactsCache,
+ artifactAtRepositoryCachedArtifactIndex,
+ cacheLockingManager,
+ startParameterResolutionOverride,
+ buildCommencedTimeProvider,
+ inMemoryCachedRepositoryFactory,
+ versionSelectorScheme,
+ versionComparator);
+ }
+
+ ArtifactDependencyResolver createArtifactDependencyResolver(ResolveIvyFactory resolveIvyFactory,
+ DependencyDescriptorFactory dependencyDescriptorFactory,
+ CacheLockingManager cacheLockingManager,
+ IvyContextManager ivyContextManager,
+ VersionComparator versionComparator,
+ ServiceRegistry serviceRegistry) {
+ DefaultArtifactDependencyResolver resolver = new DefaultArtifactDependencyResolver(
+ serviceRegistry,
+ resolveIvyFactory,
+ dependencyDescriptorFactory,
+ cacheLockingManager,
+ ivyContextManager,
+ versionComparator
);
- return new ErrorHandlingArtifactDependencyResolver(
- new ShortcircuitEmptyConfigsArtifactDependencyResolver(
- new SelfResolvingDependencyResolver(
- new CacheLockingArtifactDependencyResolver(
- cacheLockingManager,
- resolver)),
- componentIdentifierFactory));
+ return new CacheLockingArtifactDependencyResolver(cacheLockingManager, resolver);
}
ResolutionResultsStoreFactory createResolutionResultsStoreFactory(TemporaryFileProvider temporaryFileProvider) {
@@ -235,4 +226,32 @@ class DependencyManagementBuildScopeServices {
ProjectPublicationRegistry createProjectPublicationRegistry() {
return new DefaultProjectPublicationRegistry();
}
+
+ ProjectDependencyResolver createProjectDependencyResolver(ProjectRegistry<ProjectInternal> projectRegistry, ConfigurationLocalComponentConverter publishModuleDescriptorConverter) {
+ return new ProjectDependencyResolver(new DefaultProjectComponentRegistry(
+ publishModuleDescriptorConverter,
+ projectRegistry));
+ }
+
+ ResolverProviderFactory createProjectResolverProviderFactory(final ProjectDependencyResolver resolver) {
+ return new ProjectResolverProviderFactory(resolver);
+ }
+
+ private static class ProjectResolverProviderFactory implements ResolverProviderFactory {
+ private final ProjectDependencyResolver resolver;
+
+ public ProjectResolverProviderFactory(ProjectDependencyResolver resolver) {
+ this.resolver = resolver;
+ }
+
+ @Override
+ public boolean canCreate(ResolveContext context) {
+ return true;
+ }
+
+ @Override
+ public ComponentResolvers create(ResolveContext context) {
+ return DelegatingComponentResolvers.of(resolver);
+ }
+ }
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementGlobalScopeServices.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementGlobalScopeServices.java
index 3cc1953..7e06077 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementGlobalScopeServices.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyManagementGlobalScopeServices.java
@@ -22,6 +22,8 @@ import org.gradle.api.internal.artifacts.ivyservice.DefaultIvyContextManager;
import org.gradle.api.internal.artifacts.ivyservice.IvyContextManager;
import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.*;
import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.*;
+import org.gradle.internal.resource.connector.ResourceConnectorFactory;
+import org.gradle.internal.resource.transport.file.FileConnectorFactory;
class DependencyManagementGlobalScopeServices {
IvyContextManager createIvyContextManager() {
@@ -46,22 +48,28 @@ class DependencyManagementGlobalScopeServices {
DependencyDescriptorFactory createDependencyDescriptorFactory(ExcludeRuleConverter excludeRuleConverter, ExternalModuleIvyDependencyDescriptorFactory descriptorFactory) {
return new DefaultDependencyDescriptorFactory(
- new ProjectIvyDependencyDescriptorFactory(
- excludeRuleConverter),
- descriptorFactory);
+ new ProjectIvyDependencyDescriptorFactory(
+ excludeRuleConverter),
+ descriptorFactory);
}
- CompositeResolveLocalComponentFactory createPublishLocalComponentFactory(ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter,
- DependencyDescriptorFactory dependencyDescriptorFactory,
- ExcludeRuleConverter excludeRuleConverter,
- ComponentIdentifierFactory componentIdentifierFactory) {
- return new CompositeResolveLocalComponentFactory(new ResolveLocalComponentFactory(
- configurationsToModuleDescriptorConverter,
- new DefaultDependenciesToModuleDescriptorConverter(
- dependencyDescriptorFactory,
- excludeRuleConverter),
- componentIdentifierFactory,
- new DefaultConfigurationsToArtifactsConverter()));
+ DependenciesToModuleDescriptorConverter createDependenciesToModuleDescriptorConverter(DependencyDescriptorFactory dependencyDescriptorFactory,
+ ExcludeRuleConverter excludeRuleConverter) {
+ return new DefaultDependenciesToModuleDescriptorConverter(dependencyDescriptorFactory, excludeRuleConverter);
+ }
+
+ ConfigurationsToArtifactsConverter createConfigurationsToArtifactsConverter() {
+ return new DefaultConfigurationsToArtifactsConverter();
+ }
+
+ ConfigurationLocalComponentConverter createConfigurationLocalComponentConverter(ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter,
+ DependenciesToModuleDescriptorConverter dependenciesToModuleDescriptorConverter,
+ ConfigurationsToArtifactsConverter configurationsToArtifactsConverter,
+ ComponentIdentifierFactory componentIdentifierFactory) {
+ return new ConfigurationLocalComponentConverter(configurationsToModuleDescriptorConverter, dependenciesToModuleDescriptorConverter, componentIdentifierFactory, configurationsToArtifactsConverter);
+ }
+ ResourceConnectorFactory createFileConnectorFactory() {
+ return new FileConnectorFactory();
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyServices.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyServices.java
index f78eef7..e798b11 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyServices.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DependencyServices.java
@@ -24,6 +24,9 @@ public class DependencyServices implements PluginServiceRegistry {
registration.addProvider(new DependencyManagementGlobalScopeServices());
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new DependencyManagementBuildScopeServices());
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/GlobalDependencyResolutionRules.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/GlobalDependencyResolutionRules.java
index bbcbfb3..4556418 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/GlobalDependencyResolutionRules.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/GlobalDependencyResolutionRules.java
@@ -16,6 +16,19 @@
package org.gradle.api.internal.artifacts;
public interface GlobalDependencyResolutionRules {
+
+ GlobalDependencyResolutionRules NO_OP = new GlobalDependencyResolutionRules() {
+ @Override
+ public ComponentMetadataProcessor getComponentMetadataProcessor() {
+ return ComponentMetadataProcessor.NO_OP;
+ }
+
+ @Override
+ public ComponentModuleMetadataProcessor getModuleMetadataProcessor() {
+ return ComponentModuleMetadataProcessor.NO_OP;
+ }
+ };
+
ComponentMetadataProcessor getComponentMetadataProcessor();
ComponentModuleMetadataProcessor getModuleMetadataProcessor();
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolveContext.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolveContext.java
new file mode 100644
index 0000000..decf7cb
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolveContext.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts;
+
+import org.gradle.api.artifacts.DependencySet;
+import org.gradle.api.internal.artifacts.configurations.ResolutionStrategyInternal;
+
+/**
+ * Represents something that can be resolved.
+ */
+public interface ResolveContext {
+
+ String getName();
+
+ String getDisplayName();
+
+ DependencySet getDependencies();
+
+ DependencySet getAllDependencies();
+
+ ResolutionStrategyInternal getResolutionStrategy();
+
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolveContextInternal.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolveContextInternal.java
deleted file mode 100644
index 7fa45ec..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolveContextInternal.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts;
-
-import org.gradle.api.artifacts.ResolveContext;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectComponentRegistry;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectDependencyResolver;
-import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
-import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
-
-public interface ResolveContextInternal extends ResolveContext {
- ProjectDependencyResolver newProjectDependencyResolver(
- ProjectComponentRegistry projectComponentRegistry,
- LocalComponentFactory localComponentFactory,
- DependencyToComponentIdResolver delegateIdResolver,
- ComponentMetaDataResolver delegateComponentResolver);
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolverResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolverResults.java
index 2a853e8..e37e10f 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolverResults.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ResolverResults.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 the original author or authors.
+ * Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,115 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.gradle.api.internal.artifacts;
-import org.gradle.api.Action;
import org.gradle.api.artifacts.ResolveException;
import org.gradle.api.artifacts.ResolvedConfiguration;
import org.gradle.api.artifacts.result.ResolutionResult;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedArtifactsBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedGraphResults;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.TransientConfigurationResultsBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfiguration;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResults;
-
-public class ResolverResults {
- private ResolvedConfiguration resolvedConfiguration;
- private ResolutionResult resolutionResult;
- private ResolveException fatalFailure;
- private ResolvedProjectConfigurationResults resolvedProjectConfigurationResults;
- private TransientConfigurationResultsBuilder transientConfigurationResultsBuilder;
- private ResolvedGraphResults graphResults;
- private ResolvedArtifactsBuilder artifactResults;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResult;
- public boolean hasError() {
- if (fatalFailure != null) {
- return true;
- }
- if (graphResults != null && graphResults.hasError()) {
- return true;
- }
- if (resolvedConfiguration != null && resolvedConfiguration.hasError()) {
- return true;
- }
- return false;
- }
+public interface ResolverResults {
+ boolean hasError();
//old model, slowly being replaced by the new model
- public ResolvedConfiguration getResolvedConfiguration() {
- assertHasArtifacts();
- return resolvedConfiguration;
- }
+ ResolvedConfiguration getResolvedConfiguration();
//new model
- public ResolutionResult getResolutionResult() {
- assertHasResult();
- if (fatalFailure != null) {
- throw fatalFailure;
- }
- return resolutionResult;
- }
-
- public void eachResolvedProject(Action<ResolvedProjectConfiguration> action) {
- assertHasResult();
- if (fatalFailure != null) {
- throw fatalFailure;
- }
- for (ResolvedProjectConfiguration resolvedProjectConfiguration : resolvedProjectConfigurationResults.get()) {
- action.execute(resolvedProjectConfiguration);
- }
- }
-
- public ResolvedProjectConfigurationResults getResolvedProjectConfigurationResults() {
- return resolvedProjectConfigurationResults;
- }
-
- private void assertHasResult() {
- if (resolutionResult == null && fatalFailure == null) {
- throw new IllegalStateException("Resolution result has not been attached.");
- }
- }
-
- private void assertHasArtifacts() {
- if (resolvedConfiguration == null) {
- throw new IllegalStateException("Resolution artifacts have not been attached.");
- }
- }
-
- public void resolved(ResolutionResult resolutionResult, ResolvedProjectConfigurationResults resolvedProjectConfigurationResults) {
- this.resolutionResult = resolutionResult;
- this.resolvedProjectConfigurationResults = resolvedProjectConfigurationResults;
- this.fatalFailure = null;
- }
-
- public void failed(ResolveException failure) {
- this.resolutionResult = null;
- this.fatalFailure = failure;
- }
-
- public void retainState(ResolvedGraphResults graphResults, ResolvedArtifactsBuilder artifactResults, TransientConfigurationResultsBuilder transientConfigurationResultsBuilder) {
- this.graphResults = graphResults;
- this.artifactResults = artifactResults;
- this.transientConfigurationResultsBuilder = transientConfigurationResultsBuilder;
- }
+ ResolutionResult getResolutionResult();
- public void withResolvedConfiguration(ResolvedConfiguration resolvedConfiguration) {
- this.resolvedConfiguration = resolvedConfiguration;
- this.graphResults = null;
- this.transientConfigurationResultsBuilder = null;
- this.artifactResults = null;
- }
+ ResolvedLocalComponentsResult getResolvedLocalComponents();
- public ResolvedGraphResults getGraphResults() {
- return graphResults;
- }
+ void resolved(ResolutionResult resolutionResult, ResolvedLocalComponentsResult resolvedLocalComponentsResult);
- public ResolvedArtifactsBuilder getArtifactsBuilder() {
- return artifactResults;
- }
+ void failed(ResolveException failure);
- public TransientConfigurationResultsBuilder getTransientConfigurationResultsBuilder() {
- return transientConfigurationResultsBuilder;
- }
+ void withResolvedConfiguration(ResolvedConfiguration resolvedConfiguration);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java
index 0bfe7e4..b8e1cc4 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/ConfigurationInternal.java
@@ -16,7 +16,7 @@
package org.gradle.api.internal.artifacts.configurations;
import org.gradle.api.artifacts.Configuration;
-import org.gradle.api.artifacts.ResolveContext;
+import org.gradle.api.internal.artifacts.ResolveContext;
public interface ConfigurationInternal extends ResolveContext, Configuration, DependencyMetaDataProvider {
enum InternalState {UNRESOLVED, TASK_DEPENDENCIES_RESOLVED, RESULTS_RESOLVED}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java
index 835dd1e..1e9d325 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java
@@ -32,9 +32,7 @@ import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.
import org.gradle.api.internal.file.AbstractFileCollection;
import org.gradle.api.internal.file.FileSystemSubset;
import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.api.internal.tasks.AbstractTaskDependency;
import org.gradle.api.internal.tasks.DefaultTaskDependency;
-import org.gradle.api.internal.tasks.TaskDependencyResolveContext;
import org.gradle.api.specs.Spec;
import org.gradle.api.specs.Specs;
import org.gradle.api.tasks.TaskDependency;
@@ -94,9 +92,7 @@ public class DefaultConfiguration extends AbstractFileCollection implements Conf
private InternalState resolvedState = InternalState.UNRESOLVED;
private boolean insideBeforeResolve;
- private ResolverResults cachedResolverResults = new ResolverResults();
-
- // TODO:DAZ These should really be protected by the lock as well
+ private ResolverResults cachedResolverResults = new DefaultResolverResults();
private boolean dependenciesModified;
public DefaultConfiguration(String path, String name, ConfigurationsProvider configurationsProvider,
@@ -385,14 +381,11 @@ public class DefaultConfiguration extends AbstractFileCollection implements Conf
}
private void markReferencedProjectConfigurationsObserved(final InternalState requestedState) {
- cachedResolverResults.eachResolvedProject(new Action<ResolvedProjectConfiguration>() {
- @Override
- public void execute(ResolvedProjectConfiguration projectResult) {
- ProjectInternal project = projectFinder.getProject(projectResult.getId().getProjectPath());
- ConfigurationInternal targetConfig = (ConfigurationInternal) project.getConfigurations().getByName(projectResult.getTargetConfiguration());
- targetConfig.markAsObserved(requestedState);
- }
- });
+ for (ResolvedProjectConfiguration projectResult : cachedResolverResults.getResolvedLocalComponents().getResolvedProjectConfigurations()) {
+ ProjectInternal project = projectFinder.getProject(projectResult.getId().getProjectPath());
+ ConfigurationInternal targetConfig = (ConfigurationInternal) project.getConfigurations().getByName(projectResult.getTargetConfiguration());
+ targetConfig.markAsObserved(requestedState);
+ }
}
private void resolveArtifactsIfRequired() {
@@ -407,16 +400,9 @@ public class DefaultConfiguration extends AbstractFileCollection implements Conf
if (resolutionStrategy.resolveGraphToDetermineTaskDependencies()) {
final DefaultTaskDependency taskDependency = new DefaultTaskDependency();
resolveNow(InternalState.TASK_DEPENDENCIES_RESOLVED);
- cachedResolverResults.eachResolvedProject(new Action<ResolvedProjectConfiguration>() {
- @Override
- public void execute(ResolvedProjectConfiguration projectResult) {
- ProjectInternal project = projectFinder.getProject(projectResult.getId().getProjectPath());
- Configuration targetConfig = project.getConfigurations().getByName(projectResult.getTargetConfiguration());
- taskDependency.add(new SelfResolvingDependenciesWithoutProjectDependencies(targetConfig.getAllDependencies()));
- taskDependency.add(targetConfig.getAllArtifacts());
- }
- });
- taskDependency.add(new SelfResolvingDependenciesWithoutProjectDependencies(allDependencies));
+
+ taskDependency.add(cachedResolverResults.getResolvedLocalComponents().getComponentBuildDependencies());
+ taskDependency.add(DirectBuildDependencies.forDependenciesOnly(this));
return taskDependency;
} else {
return allDependencies.getBuildDependencies();
@@ -619,22 +605,6 @@ public class DefaultConfiguration extends AbstractFileCollection implements Conf
}
}
- private static class SelfResolvingDependenciesWithoutProjectDependencies extends AbstractTaskDependency {
- private final DependencySet dependencies;
-
- private SelfResolvingDependenciesWithoutProjectDependencies(DependencySet dependencies) {
- this.dependencies = dependencies;
- }
-
- public void resolve(TaskDependencyResolveContext context) {
- for (SelfResolvingDependency dependency : dependencies.withType(SelfResolvingDependency.class)) {
- if (!(dependency instanceof ProjectDependency)) {
- context.add(dependency);
- }
- }
- }
- }
-
class ConfigurationFileCollection extends AbstractFileCollection {
private Spec<? super Dependency> dependencySpec;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DirectBuildDependencies.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DirectBuildDependencies.java
new file mode 100644
index 0000000..6fcf571
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DirectBuildDependencies.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.configurations;
+
+import org.gradle.api.artifacts.*;
+import org.gradle.api.internal.tasks.AbstractTaskDependency;
+import org.gradle.api.internal.tasks.TaskDependencyResolveContext;
+import org.gradle.api.tasks.TaskDependency;
+
+/**
+ * Represents the direct build dependencies of a Configuration.
+ * These do not include the build dependencies of any transitive dependencies, but does include self-resolving dependencies of this configuration.
+ */
+public class DirectBuildDependencies extends AbstractTaskDependency {
+ private final DependencySet dependencies;
+ private final PublishArtifactSet publishArtifacts;
+
+ public static TaskDependency forDependenciesOnly(Configuration configuration) {
+ return new DirectBuildDependencies(configuration.getAllDependencies(), null);
+ }
+
+ public static TaskDependency forDependenciesAndArtifacts(Configuration configuration) {
+ return new DirectBuildDependencies(configuration.getAllDependencies(), configuration.getAllArtifacts());
+ }
+
+ private DirectBuildDependencies(DependencySet dependencies, PublishArtifactSet artifacts) {
+ this.dependencies = dependencies;
+ this.publishArtifacts = artifacts;
+ }
+
+ public void resolve(TaskDependencyResolveContext context) {
+ for (SelfResolvingDependency dependency : dependencies.withType(SelfResolvingDependency.class)) {
+ if (!(dependency instanceof ProjectDependency)) {
+ context.add(dependency);
+ }
+ }
+ if (publishArtifacts != null) {
+ context.add(publishArtifacts);
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/dsl/ModuleReplacementsData.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/dsl/ModuleReplacementsData.java
index 0ab0603..84d6f38 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/dsl/ModuleReplacementsData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/dsl/ModuleReplacementsData.java
@@ -20,5 +20,13 @@ import org.gradle.api.Nullable;
import org.gradle.api.artifacts.ModuleIdentifier;
public interface ModuleReplacementsData {
+ ModuleReplacementsData NO_OP = new ModuleReplacementsData() {
+ @Nullable
+ @Override
+ public ModuleIdentifier getReplacementFor(ModuleIdentifier sourceModule) {
+ return null;
+ }
+ };
+
@Nullable ModuleIdentifier getReplacementFor(ModuleIdentifier sourceModule);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolver.java
index 581f2ac..bc260a3 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolver.java
@@ -15,11 +15,11 @@
*/
package org.gradle.api.internal.artifacts.ivyservice;
-import org.gradle.api.artifacts.ResolveContext;
-import org.gradle.api.artifacts.ResolveException;
import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
-import org.gradle.api.internal.artifacts.ResolverResults;
+import org.gradle.api.internal.artifacts.ResolveContext;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
import java.util.List;
@@ -33,24 +33,12 @@ public class CacheLockingArtifactDependencyResolver implements ArtifactDependenc
this.resolver = resolver;
}
- public void resolve(final ResolveContext resolveContext,
- final List<? extends ResolutionAwareRepository> repositories,
- final GlobalDependencyResolutionRules metadataHandler,
- final ResolverResults results) throws ResolveException {
+ @Override
+ public void resolve(final ResolveContext resolveContext, final List<? extends ResolutionAwareRepository> repositories, final GlobalDependencyResolutionRules metadataHandler,
+ final DependencyGraphVisitor graphVisitor, final DependencyArtifactsVisitor artifactsVisitor) {
lockingManager.useCache(String.format("resolve %s", resolveContext), new Runnable() {
public void run() {
- resolver.resolve(resolveContext, repositories, metadataHandler, results);
- }
- });
- }
-
- public void resolveArtifacts(final ResolveContext resolveContext,
- final List<? extends ResolutionAwareRepository> repositories,
- final GlobalDependencyResolutionRules metadataHandler,
- final ResolverResults results) throws ResolveException {
- lockingManager.useCache(String.format("resolve %s", resolveContext), new Runnable() {
- public void run() {
- resolver.resolveArtifacts(resolveContext, repositories, metadataHandler, results);
+ resolver.resolve(resolveContext, repositories, metadataHandler, graphVisitor, artifactsVisitor);
}
});
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultConfigurationResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultConfigurationResolver.java
index 168916d..7776be3 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultConfigurationResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultConfigurationResolver.java
@@ -18,13 +18,30 @@ package org.gradle.api.internal.artifacts.ivyservice;
import org.gradle.api.artifacts.ResolveException;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
-import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
-import org.gradle.internal.Transformers;
-import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
-import org.gradle.api.internal.artifacts.ConfigurationResolver;
-import org.gradle.api.internal.artifacts.ResolverResults;
+import org.gradle.api.artifacts.result.ResolvedComponentResult;
+import org.gradle.api.internal.artifacts.*;
import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DefaultResolvedArtifactsBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactResults;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactsBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.CompositeDependencyArtifactsVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.CompositeDependencyGraphVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.*;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.DefaultResolvedLocalComponentsResultBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResultBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResultGraphVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ResolutionResultBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ResolutionResultDependencyGraphVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.StreamingResolutionResultBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.store.ResolutionResultsStoreFactory;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.store.StoreSet;
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
+import org.gradle.api.internal.cache.BinaryStore;
+import org.gradle.api.internal.cache.Store;
+import org.gradle.internal.Factory;
+import org.gradle.internal.Transformers;
import org.gradle.util.CollectionUtils;
import java.util.List;
@@ -33,20 +50,64 @@ public class DefaultConfigurationResolver implements ConfigurationResolver {
private final ArtifactDependencyResolver resolver;
private final RepositoryHandler repositories;
private final GlobalDependencyResolutionRules metadataHandler;
+ private final CacheLockingManager cacheLockingManager;
+ private final ResolutionResultsStoreFactory storeFactory;
+ private final boolean buildProjectDependencies;
- public DefaultConfigurationResolver(ArtifactDependencyResolver resolver, RepositoryHandler repositories, GlobalDependencyResolutionRules metadataHandler) {
+ public DefaultConfigurationResolver(ArtifactDependencyResolver resolver, RepositoryHandler repositories,
+ GlobalDependencyResolutionRules metadataHandler, CacheLockingManager cacheLockingManager,
+ ResolutionResultsStoreFactory storeFactory, boolean buildProjectDependencies) {
this.resolver = resolver;
this.repositories = repositories;
this.metadataHandler = metadataHandler;
+ this.cacheLockingManager = cacheLockingManager;
+ this.storeFactory = storeFactory;
+ this.buildProjectDependencies = buildProjectDependencies;
}
public void resolve(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
List<ResolutionAwareRepository> resolutionAwareRepositories = CollectionUtils.collect(repositories, Transformers.cast(ResolutionAwareRepository.class));
- resolver.resolve(configuration, resolutionAwareRepositories, metadataHandler, results);
+ StoreSet stores = storeFactory.createStoreSet();
+
+ BinaryStore oldModelStore = stores.nextBinaryStore();
+ Store<TransientConfigurationResults> oldModelCache = stores.oldModelCache();
+ TransientConfigurationResultsBuilder oldTransientModelBuilder = new TransientConfigurationResultsBuilder(oldModelStore, oldModelCache);
+ DefaultResolvedConfigurationBuilder oldModelBuilder = new DefaultResolvedConfigurationBuilder(oldTransientModelBuilder);
+ ResolvedConfigurationDependencyGraphVisitor oldModelVisitor = new ResolvedConfigurationDependencyGraphVisitor(oldModelBuilder);
+
+ BinaryStore newModelStore = stores.nextBinaryStore();
+ Store<ResolvedComponentResult> newModelCache = stores.newModelCache();
+ ResolutionResultBuilder newModelBuilder = new StreamingResolutionResultBuilder(newModelStore, newModelCache);
+ DependencyGraphVisitor newModelVisitor = new ResolutionResultDependencyGraphVisitor(newModelBuilder);
+
+ ResolvedLocalComponentsResultBuilder localComponentsResultBuilder = new DefaultResolvedLocalComponentsResultBuilder(buildProjectDependencies);
+ DependencyGraphVisitor projectModelVisitor = new ResolvedLocalComponentsResultGraphVisitor(localComponentsResultBuilder);
+
+ ResolvedArtifactsBuilder artifactsBuilder = new DefaultResolvedArtifactsBuilder();
+
+ DependencyGraphVisitor graphVisitor = new CompositeDependencyGraphVisitor(oldModelVisitor, newModelVisitor, projectModelVisitor);
+ DependencyArtifactsVisitor artifactsVisitor = new CompositeDependencyArtifactsVisitor(oldModelVisitor, artifactsBuilder);
+
+ resolver.resolve(configuration, resolutionAwareRepositories, metadataHandler, graphVisitor, artifactsVisitor);
+
+ DefaultResolverResults defaultResolverResults = (DefaultResolverResults) results;
+ defaultResolverResults.resolved(newModelBuilder.complete(), localComponentsResultBuilder.complete());
+
+ ResolvedGraphResults graphResults = oldModelBuilder.complete();
+ defaultResolverResults.retainState(graphResults, artifactsBuilder, oldTransientModelBuilder);
}
public void resolveArtifacts(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
- List<ResolutionAwareRepository> resolutionAwareRepositories = CollectionUtils.collect(repositories, Transformers.cast(ResolutionAwareRepository.class));
- resolver.resolveArtifacts(configuration, resolutionAwareRepositories, metadataHandler, results);
+ DefaultResolverResults defaultResolverResults = (DefaultResolverResults) results;
+ ResolvedGraphResults graphResults = defaultResolverResults.getGraphResults();
+ ResolvedArtifactResults artifactResults = defaultResolverResults.getResolvedArtifacts();
+ TransientConfigurationResultsBuilder transientConfigurationResultsBuilder = defaultResolverResults.getTransientConfigurationResultsBuilder();
+
+ Factory<TransientConfigurationResults> transientConfigurationResultsFactory =
+ new TransientConfigurationResultsLoader(transientConfigurationResultsBuilder, graphResults, artifactResults);
+
+ DefaultLenientConfiguration result = new DefaultLenientConfiguration(
+ configuration, cacheLockingManager, graphResults.getUnresolvedDependencies(), artifactResults, transientConfigurationResultsFactory);
+ results.withResolvedConfiguration(new DefaultResolvedConfiguration(result));
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultIvyDependencyPublisher.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultIvyDependencyPublisher.java
index 7864a1a..59e26c8 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultIvyDependencyPublisher.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultIvyDependencyPublisher.java
@@ -18,7 +18,6 @@ package org.gradle.api.internal.artifacts.ivyservice;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.artifacts.PublishException;
import org.gradle.api.internal.artifacts.ModuleVersionPublisher;
-import org.gradle.internal.component.external.model.BuildableIvyModulePublishMetaData;
import org.gradle.internal.component.external.model.DefaultIvyModulePublishMetaData;
import org.gradle.internal.component.external.model.IvyModuleArtifactPublishMetaData;
import org.gradle.internal.component.external.model.IvyModulePublishMetaData;
@@ -50,7 +49,7 @@ public class DefaultIvyDependencyPublisher implements IvyDependencyPublisher {
}
}
- private void addPublishedArtifact(IvyModuleArtifactPublishMetaData artifact, BuildableIvyModulePublishMetaData publication) {
+ private void addPublishedArtifact(IvyModuleArtifactPublishMetaData artifact, DefaultIvyModulePublishMetaData publication) {
if (checkArtifactFileExists(artifact)) {
publication.addArtifact(artifact);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultLenientConfiguration.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultLenientConfiguration.java
index 3d7b0dd..9fa5cfc 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultLenientConfiguration.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/DefaultLenientConfiguration.java
@@ -16,8 +16,7 @@
package org.gradle.api.internal.artifacts.ivyservice;
import org.gradle.api.artifacts.*;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedArtifactResults;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedGraphResults;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifacts;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.TransientConfigurationResults;
import org.gradle.api.specs.Spec;
import org.gradle.api.specs.Specs;
@@ -33,34 +32,34 @@ import java.util.*;
public class DefaultLenientConfiguration implements LenientConfiguration {
private CacheLockingManager cacheLockingManager;
private final Configuration configuration;
- private final ResolvedGraphResults graphResults;
- private final ResolvedArtifactResults artifactResults;
+ private final Set<UnresolvedDependency> unresolvedDependencies;
+ private final ResolvedArtifacts artifactResults;
private final Factory<TransientConfigurationResults> transientConfigurationResultsFactory;
- public DefaultLenientConfiguration(Configuration configuration, CacheLockingManager cacheLockingManager, ResolvedGraphResults graphResults, ResolvedArtifactResults artifactResults,
- Factory<TransientConfigurationResults> transientConfigurationResultsLoader) {
+ public DefaultLenientConfiguration(Configuration configuration, CacheLockingManager cacheLockingManager, Set<UnresolvedDependency> unresolvedDependencies,
+ ResolvedArtifacts artifactResults, Factory<TransientConfigurationResults> transientConfigurationResultsLoader) {
this.configuration = configuration;
this.cacheLockingManager = cacheLockingManager;
- this.graphResults = graphResults;
+ this.unresolvedDependencies = unresolvedDependencies;
this.artifactResults = artifactResults;
this.transientConfigurationResultsFactory = transientConfigurationResultsLoader;
}
public boolean hasError() {
- return graphResults.hasError();
+ return unresolvedDependencies.size() > 0;
}
public Set<UnresolvedDependency> getUnresolvedModuleDependencies() {
- return graphResults.getUnresolvedDependencies();
+ return unresolvedDependencies;
}
public void rethrowFailure() throws ResolveException {
if (hasError()) {
List<Throwable> failures = new ArrayList<Throwable>();
- for (UnresolvedDependency unresolvedDependency : graphResults.getUnresolvedDependencies()) {
+ for (UnresolvedDependency unresolvedDependency : unresolvedDependencies) {
failures.add(unresolvedDependency.getProblem());
}
- throw new ResolveException((ResolveContext) configuration, failures);
+ throw new ResolveException(configuration.toString(), failures);
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingArtifactDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingArtifactDependencyResolver.java
deleted file mode 100644
index 926ff2b..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingArtifactDependencyResolver.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice;
-
-import groovy.lang.Closure;
-import org.gradle.api.Action;
-import org.gradle.api.artifacts.*;
-import org.gradle.api.artifacts.result.DependencyResult;
-import org.gradle.api.artifacts.result.ResolutionResult;
-import org.gradle.api.artifacts.result.ResolvedComponentResult;
-import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
-import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
-import org.gradle.api.internal.artifacts.ResolverResults;
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
-import org.gradle.api.specs.Spec;
-
-import java.io.File;
-import java.util.List;
-import java.util.Set;
-
-public class ErrorHandlingArtifactDependencyResolver implements ArtifactDependencyResolver {
- private final ArtifactDependencyResolver dependencyResolver;
-
- public ErrorHandlingArtifactDependencyResolver(ArtifactDependencyResolver dependencyResolver) {
- this.dependencyResolver = dependencyResolver;
- }
-
- public void resolve(ResolveContext resolveContext,
- List<? extends ResolutionAwareRepository> repositories,
- GlobalDependencyResolutionRules metadataHandler,
- ResolverResults results) throws ResolveException {
- try {
- dependencyResolver.resolve(resolveContext, repositories, metadataHandler, results);
- } catch (final Throwable e) {
- results.failed(wrapException(e, resolveContext));
- results.withResolvedConfiguration(new BrokenResolvedConfiguration(e, resolveContext));
- return;
- }
- ResolutionResult wrappedResult = new ErrorHandlingResolutionResult(results.getResolutionResult(), resolveContext);
- results.resolved(wrappedResult, results.getResolvedProjectConfigurationResults());
- }
-
- public void resolveArtifacts(ResolveContext resolveContext, List<? extends ResolutionAwareRepository> repositories, GlobalDependencyResolutionRules metadataHandler, ResolverResults results) throws ResolveException {
- try {
- dependencyResolver.resolveArtifacts(resolveContext, repositories, metadataHandler, results);
- } catch (ResolveException e) {
- results.withResolvedConfiguration(new BrokenResolvedConfiguration(e, resolveContext));
- return;
- }
-
- ResolvedConfiguration wrappedConfiguration = new ErrorHandlingResolvedConfiguration(results.getResolvedConfiguration(), resolveContext);
- results.withResolvedConfiguration(wrappedConfiguration);
- }
-
- private static ResolveException wrapException(Throwable e, ResolveContext configuration) {
- if (e instanceof ResolveException) {
- return (ResolveException) e;
- }
- return new ResolveException(configuration, e);
- }
-
- private static class ErrorHandlingLenientConfiguration implements LenientConfiguration {
- private final LenientConfiguration lenientConfiguration;
- private final ResolveContext resolveContext;
-
- private ErrorHandlingLenientConfiguration(LenientConfiguration lenientConfiguration, ResolveContext resolveContext) {
- this.lenientConfiguration = lenientConfiguration;
- this.resolveContext = resolveContext;
- }
-
- public Set<ResolvedArtifact> getArtifacts(Spec<? super Dependency> dependencySpec) {
- try {
- return lenientConfiguration.getArtifacts(dependencySpec);
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) {
- try {
- return lenientConfiguration.getFirstLevelModuleDependencies(dependencySpec);
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public Set<UnresolvedDependency> getUnresolvedModuleDependencies() {
- try {
- return lenientConfiguration.getUnresolvedModuleDependencies();
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
- try {
- return lenientConfiguration.getFiles(dependencySpec);
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
- }
-
- private static class ErrorHandlingResolutionResult implements ResolutionResult {
- private final ResolutionResult resolutionResult;
- private final ResolveContext resolveContext;
-
- public ErrorHandlingResolutionResult(ResolutionResult resolutionResult, ResolveContext configuration) {
- this.resolutionResult = resolutionResult;
- this.resolveContext = configuration;
- }
-
- public ResolvedComponentResult getRoot() {
- try {
- return resolutionResult.getRoot();
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public void allDependencies(Action<? super DependencyResult> action) {
- resolutionResult.allDependencies(action);
- }
-
- public Set<? extends DependencyResult> getAllDependencies() {
- try {
- return resolutionResult.getAllDependencies();
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public void allDependencies(Closure closure) {
- resolutionResult.allDependencies(closure);
- }
-
- public Set<ResolvedComponentResult> getAllComponents() {
- try {
- return resolutionResult.getAllComponents();
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public void allComponents(Action<? super ResolvedComponentResult> action) {
- resolutionResult.allComponents(action);
- }
-
- public void allComponents(Closure closure) {
- resolutionResult.allComponents(closure);
- }
- }
-
- private static class ErrorHandlingResolvedConfiguration implements ResolvedConfiguration {
- private final ResolvedConfiguration resolvedConfiguration;
- private final ResolveContext resolveContext;
-
- public ErrorHandlingResolvedConfiguration(ResolvedConfiguration resolvedConfiguration,
- ResolveContext resolveContext) {
- this.resolvedConfiguration = resolvedConfiguration;
- this.resolveContext = resolveContext;
- }
-
- public boolean hasError() {
- return resolvedConfiguration.hasError();
- }
-
- public LenientConfiguration getLenientConfiguration() {
- try {
- return new ErrorHandlingLenientConfiguration(resolvedConfiguration.getLenientConfiguration(), resolveContext);
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public void rethrowFailure() throws ResolveException {
- try {
- resolvedConfiguration.rethrowFailure();
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public Set<File> getFiles(Spec<? super Dependency> dependencySpec) throws ResolveException {
- try {
- return resolvedConfiguration.getFiles(dependencySpec);
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies() throws ResolveException {
- try {
- return resolvedConfiguration.getFirstLevelModuleDependencies();
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
- try {
- return resolvedConfiguration.getFirstLevelModuleDependencies(dependencySpec);
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
-
- public Set<ResolvedArtifact> getResolvedArtifacts() throws ResolveException {
- try {
- return resolvedConfiguration.getResolvedArtifacts();
- } catch (Throwable e) {
- throw wrapException(e, resolveContext);
- }
- }
- }
-
- private static class BrokenResolvedConfiguration implements ResolvedConfiguration {
- private final Throwable e;
- private final ResolveContext resolveContext;
-
- public BrokenResolvedConfiguration(Throwable e, ResolveContext resolveContext) {
- this.e = e;
- this.resolveContext = resolveContext;
- }
-
- public boolean hasError() {
- return true;
- }
-
- public LenientConfiguration getLenientConfiguration() {
- throw wrapException(e, resolveContext);
- }
-
- public void rethrowFailure() throws ResolveException {
- throw wrapException(e, resolveContext);
- }
-
- public Set<File> getFiles(Spec<? super Dependency> dependencySpec) throws ResolveException {
- throw wrapException(e, resolveContext);
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies() throws ResolveException {
- throw wrapException(e, resolveContext);
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
- throw wrapException(e, resolveContext);
- }
-
- public Set<ResolvedArtifact> getResolvedArtifacts() throws ResolveException {
- throw wrapException(e, resolveContext);
- }
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingConfigurationResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingConfigurationResolver.java
new file mode 100644
index 0000000..00967f4
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingConfigurationResolver.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice;
+
+import groovy.lang.Closure;
+import org.gradle.api.Action;
+import org.gradle.api.artifacts.*;
+import org.gradle.api.artifacts.result.DependencyResult;
+import org.gradle.api.artifacts.result.ResolutionResult;
+import org.gradle.api.artifacts.result.ResolvedComponentResult;
+import org.gradle.api.internal.artifacts.ConfigurationResolver;
+import org.gradle.api.internal.artifacts.ResolveContext;
+import org.gradle.api.internal.artifacts.ResolverResults;
+import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
+import org.gradle.api.specs.Spec;
+
+import java.io.File;
+import java.util.Set;
+
+public class ErrorHandlingConfigurationResolver implements ConfigurationResolver {
+ private final ConfigurationResolver delegate;
+
+ public ErrorHandlingConfigurationResolver(ConfigurationResolver delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void resolve(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
+ try {
+ delegate.resolve(configuration, results);
+ } catch (final Throwable e) {
+ results.failed(wrapException(e, configuration));
+ results.withResolvedConfiguration(new BrokenResolvedConfiguration(e, configuration));
+ return;
+ }
+ ResolutionResult wrappedResult = new ErrorHandlingResolutionResult(results.getResolutionResult(), configuration);
+ results.resolved(wrappedResult, results.getResolvedLocalComponents());
+ }
+
+ @Override
+ public void resolveArtifacts(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
+ try {
+ delegate.resolveArtifacts(configuration, results);
+ } catch (ResolveException e) {
+ results.withResolvedConfiguration(new BrokenResolvedConfiguration(e, configuration));
+ return;
+ }
+
+ ResolvedConfiguration wrappedConfiguration = new ErrorHandlingResolvedConfiguration(results.getResolvedConfiguration(), configuration);
+ results.withResolvedConfiguration(wrappedConfiguration);
+ }
+
+ private static ResolveException wrapException(Throwable e, ResolveContext resolveContext) {
+ if (e instanceof ResolveException) {
+ return (ResolveException) e;
+ }
+ return new ResolveException(resolveContext.getDisplayName(), e);
+ }
+
+ private static class ErrorHandlingLenientConfiguration implements LenientConfiguration {
+ private final LenientConfiguration lenientConfiguration;
+ private final ResolveContext resolveContext;
+
+ private ErrorHandlingLenientConfiguration(LenientConfiguration lenientConfiguration, ResolveContext resolveContext) {
+ this.lenientConfiguration = lenientConfiguration;
+ this.resolveContext = resolveContext;
+ }
+
+ public Set<ResolvedArtifact> getArtifacts(Spec<? super Dependency> dependencySpec) {
+ try {
+ return lenientConfiguration.getArtifacts(dependencySpec);
+ } catch (Throwable e) {
+ throw wrapException(e, resolveContext);
+ }
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) {
+ try {
+ return lenientConfiguration.getFirstLevelModuleDependencies(dependencySpec);
+ } catch (Throwable e) {
+ throw wrapException(e, resolveContext);
+ }
+ }
+
+ public Set<UnresolvedDependency> getUnresolvedModuleDependencies() {
+ try {
+ return lenientConfiguration.getUnresolvedModuleDependencies();
+ } catch (Throwable e) {
+ throw wrapException(e, resolveContext);
+ }
+ }
+
+ public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
+ try {
+ return lenientConfiguration.getFiles(dependencySpec);
+ } catch (Throwable e) {
+ throw wrapException(e, resolveContext);
+ }
+ }
+ }
+
+ private static class ErrorHandlingResolutionResult implements ResolutionResult {
+ private final ResolutionResult resolutionResult;
+ private final ResolveContext resolveContext;
+
+ public ErrorHandlingResolutionResult(ResolutionResult resolutionResult, ResolveContext configuration) {
+ this.resolutionResult = resolutionResult;
+ this.resolveContext = configuration;
+ }
+
+ public ResolvedComponentResult getRoot() {
+ try {
+ return resolutionResult.getRoot();
+ } catch (Throwable e) {
+ throw wrapException(e, resolveContext);
+ }
+ }
+
+ public void allDependencies(Action<? super DependencyResult> action) {
+ resolutionResult.allDependencies(action);
+ }
+
+ public Set<? extends DependencyResult> getAllDependencies() {
+ try {
+ return resolutionResult.getAllDependencies();
+ } catch (Throwable e) {
+ throw wrapException(e, resolveContext);
+ }
+ }
+
+ public void allDependencies(Closure closure) {
+ resolutionResult.allDependencies(closure);
+ }
+
+ public Set<ResolvedComponentResult> getAllComponents() {
+ try {
+ return resolutionResult.getAllComponents();
+ } catch (Throwable e) {
+ throw wrapException(e, resolveContext);
+ }
+ }
+
+ public void allComponents(Action<? super ResolvedComponentResult> action) {
+ resolutionResult.allComponents(action);
+ }
+
+ public void allComponents(Closure closure) {
+ resolutionResult.allComponents(closure);
+ }
+ }
+
+ private static class ErrorHandlingResolvedConfiguration implements ResolvedConfiguration {
+ private final ResolvedConfiguration resolvedConfiguration;
+ private final ConfigurationInternal configuration;
+
+ public ErrorHandlingResolvedConfiguration(ResolvedConfiguration resolvedConfiguration,
+ ConfigurationInternal configuration) {
+ this.resolvedConfiguration = resolvedConfiguration;
+ this.configuration = configuration;
+ }
+
+ public boolean hasError() {
+ return resolvedConfiguration.hasError();
+ }
+
+ public LenientConfiguration getLenientConfiguration() {
+ try {
+ return new ErrorHandlingLenientConfiguration(resolvedConfiguration.getLenientConfiguration(), configuration);
+ } catch (Throwable e) {
+ throw wrapException(e, configuration);
+ }
+ }
+
+ public void rethrowFailure() throws ResolveException {
+ try {
+ resolvedConfiguration.rethrowFailure();
+ } catch (Throwable e) {
+ throw wrapException(e, configuration);
+ }
+ }
+
+ public Set<File> getFiles(Spec<? super Dependency> dependencySpec) throws ResolveException {
+ try {
+ return resolvedConfiguration.getFiles(dependencySpec);
+ } catch (Throwable e) {
+ throw wrapException(e, configuration);
+ }
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies() throws ResolveException {
+ try {
+ return resolvedConfiguration.getFirstLevelModuleDependencies();
+ } catch (Throwable e) {
+ throw wrapException(e, configuration);
+ }
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
+ try {
+ return resolvedConfiguration.getFirstLevelModuleDependencies(dependencySpec);
+ } catch (Throwable e) {
+ throw wrapException(e, configuration);
+ }
+ }
+
+ public Set<ResolvedArtifact> getResolvedArtifacts() throws ResolveException {
+ try {
+ return resolvedConfiguration.getResolvedArtifacts();
+ } catch (Throwable e) {
+ throw wrapException(e, configuration);
+ }
+ }
+ }
+
+ private static class BrokenResolvedConfiguration implements ResolvedConfiguration {
+ private final Throwable e;
+ private final ConfigurationInternal configuration;
+
+ public BrokenResolvedConfiguration(Throwable e, ConfigurationInternal configuration) {
+ this.e = e;
+ this.configuration = configuration;
+ }
+
+ public boolean hasError() {
+ return true;
+ }
+
+ public LenientConfiguration getLenientConfiguration() {
+ throw wrapException(e, configuration);
+ }
+
+ public void rethrowFailure() throws ResolveException {
+ throw wrapException(e, configuration);
+ }
+
+ public Set<File> getFiles(Spec<? super Dependency> dependencySpec) throws ResolveException {
+ throw wrapException(e, configuration);
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies() throws ResolveException {
+ throw wrapException(e, configuration);
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
+ throw wrapException(e, configuration);
+ }
+
+ public Set<ResolvedArtifact> getResolvedArtifacts() throws ResolveException {
+ throw wrapException(e, configuration);
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/IvyBackedArtifactPublisher.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/IvyBackedArtifactPublisher.java
index c89f767..027fdef 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/IvyBackedArtifactPublisher.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/IvyBackedArtifactPublisher.java
@@ -20,15 +20,19 @@ import org.apache.ivy.core.module.descriptor.Artifact;
import org.apache.ivy.core.module.descriptor.MDArtifact;
import org.gradle.api.Action;
import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
import org.gradle.api.artifacts.PublishException;
import org.gradle.api.internal.artifacts.ArtifactPublisher;
+import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier;
import org.gradle.api.internal.artifacts.ModuleInternal;
import org.gradle.api.internal.artifacts.ModuleVersionPublisher;
-import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ComponentConverterSource;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ConfigurationsToArtifactsConverter;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ConfigurationsToModuleDescriptorConverter;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependenciesToModuleDescriptorConverter;
import org.gradle.api.internal.artifacts.repositories.PublicationAwareRepository;
import org.gradle.internal.component.external.model.BuildableIvyModulePublishMetaData;
+import org.gradle.internal.component.external.model.DefaultIvyModulePublishMetaData;
import org.gradle.internal.component.external.model.IvyModulePublishMetaData;
-import org.gradle.internal.component.local.model.LocalComponentMetaData;
import java.io.File;
import java.util.ArrayList;
@@ -36,16 +40,21 @@ import java.util.List;
import java.util.Set;
public class IvyBackedArtifactPublisher implements ArtifactPublisher {
- private final LocalComponentFactory publishLocalComponentFactory;
+ private final ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter;
+ private final DependenciesToModuleDescriptorConverter dependenciesToModuleDescriptorConverter;
+ private final ConfigurationsToArtifactsConverter configurationsToArtifactsConverter;
private final IvyContextManager ivyContextManager;
private final IvyDependencyPublisher dependencyPublisher;
private final IvyModuleDescriptorWriter ivyModuleDescriptorWriter;
- public IvyBackedArtifactPublisher(LocalComponentFactory publishLocalComponentFactory,
- IvyContextManager ivyContextManager,
+ public IvyBackedArtifactPublisher(ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter,
+ DependenciesToModuleDescriptorConverter dependenciesToModuleDescriptorConverter,
+ ConfigurationsToArtifactsConverter configurationsToArtifactsConverter, IvyContextManager ivyContextManager,
IvyDependencyPublisher dependencyPublisher,
IvyModuleDescriptorWriter ivyModuleDescriptorWriter) {
- this.publishLocalComponentFactory = publishLocalComponentFactory;
+ this.configurationsToModuleDescriptorConverter = configurationsToModuleDescriptorConverter;
+ this.dependenciesToModuleDescriptorConverter = dependenciesToModuleDescriptorConverter;
+ this.configurationsToArtifactsConverter = configurationsToArtifactsConverter;
this.ivyContextManager = ivyContextManager;
this.dependencyPublisher = dependencyPublisher;
this.ivyModuleDescriptorWriter = ivyModuleDescriptorWriter;
@@ -57,15 +66,14 @@ public class IvyBackedArtifactPublisher implements ArtifactPublisher {
Set<Configuration> allConfigurations = configuration.getAll();
Set<Configuration> configurationsToPublish = configuration.getHierarchy();
- LocalComponentMetaData allConfigurationsComponentMetaData = publishLocalComponentFactory.convert(new ComponentConverterSource(allConfigurations, module));
if (descriptor != null) {
- IvyModulePublishMetaData publishMetaData = allConfigurationsComponentMetaData.toPublishMetaData();
+ // Convert once, in order to write the Ivy descriptor with _all_ configurations
+ IvyModulePublishMetaData publishMetaData = toPublishMetaData(module, allConfigurations);
ivyModuleDescriptorWriter.write(publishMetaData.getModuleDescriptor(), publishMetaData.getArtifacts(), descriptor);
}
- // Need to convert a second time, to determine which artifacts to publish (and yes, this isn't a great way to do things...)
- LocalComponentMetaData componentMetaData = publishLocalComponentFactory.convert(new ComponentConverterSource(configurationsToPublish, module));
- BuildableIvyModulePublishMetaData publishMetaData = componentMetaData.toPublishMetaData();
+ // Convert a second time with only the published configurations: this ensures that the correct artifacts are included
+ BuildableIvyModulePublishMetaData publishMetaData = toPublishMetaData(module, configurationsToPublish);
if (descriptor != null) {
Artifact artifact = MDArtifact.newIvyArtifact(publishMetaData.getModuleDescriptor());
publishMetaData.addArtifact(artifact, descriptor);
@@ -81,4 +89,14 @@ public class IvyBackedArtifactPublisher implements ArtifactPublisher {
}
});
}
+
+ private BuildableIvyModulePublishMetaData toPublishMetaData(ModuleInternal module, Set<? extends Configuration> configurations) {
+ ModuleVersionIdentifier id = DefaultModuleVersionIdentifier.newId(module);
+ DefaultIvyModulePublishMetaData publishMetaData = new DefaultIvyModulePublishMetaData(id, module.getStatus());
+ configurationsToModuleDescriptorConverter.addConfigurations(publishMetaData, configurations);
+ dependenciesToModuleDescriptorConverter.addDependencyDescriptors(publishMetaData, configurations);
+ configurationsToArtifactsConverter.addArtifacts(publishMetaData, configurations);
+ return publishMetaData;
+ }
+
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/LocalComponentConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/LocalComponentConverter.java
new file mode 100644
index 0000000..0ce91b6
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/LocalComponentConverter.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2007-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice;
+
+import org.gradle.internal.component.local.model.LocalComponentMetaData;
+
+public interface LocalComponentConverter {
+ boolean canConvert(Object source);
+
+ LocalComponentMetaData convert(Object source);
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/LocalComponentFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/LocalComponentFactory.java
deleted file mode 100644
index 00645af..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/LocalComponentFactory.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2007-2008 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice;
-
-import org.gradle.internal.component.local.model.LocalComponentMetaData;
-
-public interface LocalComponentFactory {
- boolean canConvert(Object source);
-
- LocalComponentMetaData convert(Object source);
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyConfigurationResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyConfigurationResolver.java
new file mode 100644
index 0000000..f976296
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyConfigurationResolver.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice;
+
+import org.gradle.api.GradleException;
+import org.gradle.api.artifacts.*;
+import org.gradle.api.internal.artifacts.CachingDependencyResolveContext;
+import org.gradle.api.internal.artifacts.ConfigurationResolver;
+import org.gradle.api.internal.artifacts.ResolverResults;
+import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
+import org.gradle.api.specs.Spec;
+import org.gradle.util.CollectionUtils;
+
+import java.io.File;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class SelfResolvingDependencyConfigurationResolver implements ConfigurationResolver {
+ private final ConfigurationResolver delegate;
+
+ public SelfResolvingDependencyConfigurationResolver(ConfigurationResolver delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void resolve(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
+ delegate.resolve(configuration, results);
+ }
+
+ @Override
+ public void resolveArtifacts(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
+
+ delegate.resolveArtifacts(configuration, results);
+
+ ResolvedConfiguration resolvedConfiguration = results.getResolvedConfiguration();
+ Set<Dependency> dependencies = configuration.getAllDependencies();
+ CachingDependencyResolveContext resolveContext = new CachingDependencyResolveContext(configuration.isTransitive());
+ SelfResolvingFilesProvider provider = new SelfResolvingFilesProvider(resolveContext, dependencies);
+
+ results.withResolvedConfiguration(new FilesAggregatingResolvedConfiguration(resolvedConfiguration, provider));
+ }
+
+ protected static class SelfResolvingFilesProvider {
+
+ final CachingDependencyResolveContext resolveContext;
+ final Set<Dependency> dependencies;
+
+ public SelfResolvingFilesProvider(CachingDependencyResolveContext resolveContext, Set<Dependency> dependencies) {
+ this.resolveContext = resolveContext;
+ this.dependencies = dependencies;
+ }
+
+ Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
+ Set<Dependency> selectedDependencies = CollectionUtils.filter(dependencies, dependencySpec);
+ for (Dependency dependency : selectedDependencies) {
+ resolveContext.add(dependency);
+ }
+ return resolveContext.resolve().getFiles();
+ }
+ }
+
+ protected static class FilesAggregatingResolvedConfiguration implements ResolvedConfiguration {
+ final ResolvedConfiguration resolvedConfiguration;
+ final SelfResolvingFilesProvider selfResolvingFilesProvider;
+
+ FilesAggregatingResolvedConfiguration(ResolvedConfiguration resolvedConfiguration, SelfResolvingFilesProvider selfResolvingFilesProvider) {
+ this.resolvedConfiguration = resolvedConfiguration;
+ this.selfResolvingFilesProvider = selfResolvingFilesProvider;
+ }
+
+ public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
+ Set<File> files = new LinkedHashSet<File>();
+ files.addAll(selfResolvingFilesProvider.getFiles(dependencySpec));
+ files.addAll(resolvedConfiguration.getFiles(dependencySpec));
+ return files;
+ }
+
+ public Set<ResolvedArtifact> getResolvedArtifacts() {
+ return resolvedConfiguration.getResolvedArtifacts();
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies() {
+ return resolvedConfiguration.getFirstLevelModuleDependencies();
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
+ return resolvedConfiguration.getFirstLevelModuleDependencies(dependencySpec);
+ }
+
+ public boolean hasError() {
+ return resolvedConfiguration.hasError();
+ }
+
+ public LenientConfiguration getLenientConfiguration() {
+ return resolvedConfiguration.getLenientConfiguration();
+ }
+
+ public void rethrowFailure() throws GradleException {
+ resolvedConfiguration.rethrowFailure();
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyResolver.java
deleted file mode 100644
index fa4edc0..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyResolver.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice;
-
-import org.gradle.api.GradleException;
-import org.gradle.api.artifacts.*;
-import org.gradle.api.internal.artifacts.*;
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
-import org.gradle.api.specs.Spec;
-import org.gradle.util.CollectionUtils;
-
-import java.io.File;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-public class SelfResolvingDependencyResolver implements ArtifactDependencyResolver {
- private final ArtifactDependencyResolver resolver;
-
- public SelfResolvingDependencyResolver(ArtifactDependencyResolver resolver) {
- this.resolver = resolver;
- }
-
- public void resolve(ResolveContext resolveContext,
- List<? extends ResolutionAwareRepository> repositories,
- GlobalDependencyResolutionRules metadataHandler,
- ResolverResults results) throws ResolveException {
- resolver.resolve(resolveContext, repositories, metadataHandler, results);
- }
-
- public void resolveArtifacts(ResolveContext contextInternal,
- List<? extends ResolutionAwareRepository> repositories,
- GlobalDependencyResolutionRules metadataHandler,
- ResolverResults results) throws ResolveException {
- resolver.resolveArtifacts(contextInternal, repositories, metadataHandler, results);
-
- ResolvedConfiguration resolvedConfiguration = results.getResolvedConfiguration();
- Configuration configuration = (Configuration) contextInternal;
- Set<Dependency> dependencies = configuration.getAllDependencies();
- CachingDependencyResolveContext resolveContext = new CachingDependencyResolveContext(configuration.isTransitive());
- SelfResolvingFilesProvider provider = new SelfResolvingFilesProvider(resolveContext, dependencies);
-
- results.withResolvedConfiguration(new FilesAggregatingResolvedConfiguration(resolvedConfiguration, provider));
- }
-
- protected static class SelfResolvingFilesProvider {
-
- final CachingDependencyResolveContext resolveContext;
- final Set<Dependency> dependencies;
-
- public SelfResolvingFilesProvider(CachingDependencyResolveContext resolveContext, Set<Dependency> dependencies) {
- this.resolveContext = resolveContext;
- this.dependencies = dependencies;
- }
-
- Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
- Set<Dependency> selectedDependencies = CollectionUtils.filter(dependencies, dependencySpec);
- for (Dependency dependency : selectedDependencies) {
- resolveContext.add(dependency);
- }
- return resolveContext.resolve().getFiles();
- }
- }
-
- protected static class FilesAggregatingResolvedConfiguration implements ResolvedConfiguration {
- final ResolvedConfiguration resolvedConfiguration;
- final SelfResolvingFilesProvider selfResolvingFilesProvider;
-
- FilesAggregatingResolvedConfiguration(ResolvedConfiguration resolvedConfiguration, SelfResolvingFilesProvider selfResolvingFilesProvider) {
- this.resolvedConfiguration = resolvedConfiguration;
- this.selfResolvingFilesProvider = selfResolvingFilesProvider;
- }
-
- public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
- Set<File> files = new LinkedHashSet<File>();
- files.addAll(selfResolvingFilesProvider.getFiles(dependencySpec));
- files.addAll(resolvedConfiguration.getFiles(dependencySpec));
- return files;
- }
-
- public Set<ResolvedArtifact> getResolvedArtifacts() {
- return resolvedConfiguration.getResolvedArtifacts();
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies() {
- return resolvedConfiguration.getFirstLevelModuleDependencies();
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
- return resolvedConfiguration.getFirstLevelModuleDependencies(dependencySpec);
- }
-
- public boolean hasError() {
- return resolvedConfiguration.hasError();
- }
-
- public LenientConfiguration getLenientConfiguration() {
- return resolvedConfiguration.getLenientConfiguration();
- }
-
- public void rethrowFailure() throws GradleException {
- resolvedConfiguration.rethrowFailure();
- }
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ShortCircuitEmptyConfigurationResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ShortCircuitEmptyConfigurationResolver.java
new file mode 100644
index 0000000..f40334a
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ShortCircuitEmptyConfigurationResolver.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice;
+
+import org.gradle.api.artifacts.*;
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.artifacts.result.ResolutionResult;
+import org.gradle.api.internal.artifacts.*;
+import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory;
+import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.DefaultResolvedLocalComponentsResultBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResult;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.DefaultResolutionResultBuilder;
+import org.gradle.api.specs.Spec;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Set;
+
+public class ShortCircuitEmptyConfigurationResolver implements ConfigurationResolver {
+ private final ConfigurationResolver delegate;
+ private final ComponentIdentifierFactory componentIdentifierFactory;
+
+ public ShortCircuitEmptyConfigurationResolver(ConfigurationResolver delegate, ComponentIdentifierFactory componentIdentifierFactory) {
+ this.delegate = delegate;
+ this.componentIdentifierFactory = componentIdentifierFactory;
+ }
+
+ @Override
+ public void resolve(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
+ if (configuration.getAllDependencies().isEmpty()) {
+ ModuleInternal module = configuration.getModule();
+ ModuleVersionIdentifier id = DefaultModuleVersionIdentifier.newId(module);
+ ComponentIdentifier componentIdentifier = componentIdentifierFactory.createComponentIdentifier(module);
+ ResolutionResult emptyResult = new DefaultResolutionResultBuilder().start(id, componentIdentifier).complete();
+ ResolvedLocalComponentsResult emptyProjectResult = new DefaultResolvedLocalComponentsResultBuilder(false).complete();
+ results.resolved(emptyResult, emptyProjectResult);
+ } else {
+ delegate.resolve(configuration, results);
+ }
+ }
+
+ @Override
+ public void resolveArtifacts(ConfigurationInternal configuration, ResolverResults results) throws ResolveException {
+ if (configuration.getAllDependencies().isEmpty()) {
+ results.withResolvedConfiguration(new EmptyResolvedConfiguration());
+ } else {
+ delegate.resolveArtifacts(configuration, results);
+ }
+ }
+
+ private static class EmptyResolvedConfiguration implements ResolvedConfiguration {
+
+ public boolean hasError() {
+ return false;
+ }
+
+ public LenientConfiguration getLenientConfiguration() {
+ return new LenientConfiguration() {
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) {
+ return Collections.emptySet();
+ }
+
+ public Set<UnresolvedDependency> getUnresolvedModuleDependencies() {
+ return Collections.emptySet();
+ }
+
+ public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
+ return Collections.emptySet();
+ }
+
+ public Set<ResolvedArtifact> getArtifacts(Spec<? super Dependency> dependencySpec) {
+ return Collections.emptySet();
+ }
+ };
+ }
+
+ public void rethrowFailure() throws ResolveException {
+ }
+
+ public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
+ return Collections.emptySet();
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies() {
+ return Collections.emptySet();
+ }
+
+ public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
+ return Collections.emptySet();
+ }
+
+ public Set<ResolvedArtifact> getResolvedArtifacts() {
+ return Collections.emptySet();
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ShortcircuitEmptyConfigsArtifactDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ShortcircuitEmptyConfigsArtifactDependencyResolver.java
deleted file mode 100644
index 643757f..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ShortcircuitEmptyConfigsArtifactDependencyResolver.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2009 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice;
-
-import org.gradle.api.artifacts.*;
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.result.ResolutionResult;
-import org.gradle.api.internal.artifacts.*;
-import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory;
-import org.gradle.api.internal.artifacts.configurations.DependencyMetaDataProvider;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.DefaultResolvedProjectConfigurationResultBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResults;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.DefaultResolutionResultBuilder;
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
-import org.gradle.api.specs.Spec;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-public class ShortcircuitEmptyConfigsArtifactDependencyResolver implements ArtifactDependencyResolver {
- private final ArtifactDependencyResolver dependencyResolver;
- private final ComponentIdentifierFactory componentIdentifierFactory;
-
- public ShortcircuitEmptyConfigsArtifactDependencyResolver(ArtifactDependencyResolver dependencyResolver, ComponentIdentifierFactory componentIdentifierFactory) {
- this.dependencyResolver = dependencyResolver;
- this.componentIdentifierFactory = componentIdentifierFactory;
- }
-
- public void resolve(ResolveContext resolveContext,
- List<? extends ResolutionAwareRepository> repositories,
- GlobalDependencyResolutionRules metadataHandler,
- ResolverResults results) throws ResolveException {
- if (resolveContext instanceof Configuration && resolveContext.getAllDependencies().isEmpty()) {
- ModuleInternal module = ((DependencyMetaDataProvider) resolveContext).getModule();
- ModuleVersionIdentifier id = DefaultModuleVersionIdentifier.newId(module);
- ComponentIdentifier componentIdentifier = componentIdentifierFactory.createComponentIdentifier(module);
- ResolutionResult emptyResult = new DefaultResolutionResultBuilder().start(id, componentIdentifier).complete();
- ResolvedProjectConfigurationResults emptyProjectResult = new DefaultResolvedProjectConfigurationResultBuilder(false).complete();
- results.resolved(emptyResult, emptyProjectResult);
- } else {
- dependencyResolver.resolve(resolveContext, repositories, metadataHandler, results);
- }
- }
-
- @Override
- public void resolveArtifacts(ResolveContext resolveContext, List<? extends ResolutionAwareRepository> repositories, GlobalDependencyResolutionRules metadataHandler, ResolverResults results) throws ResolveException {
- if (resolveContext.getAllDependencies().isEmpty()) {
- results.withResolvedConfiguration(new EmptyResolvedConfiguration());
- } else {
- dependencyResolver.resolveArtifacts(resolveContext, repositories, metadataHandler, results);
- }
- }
-
- private static class EmptyResolvedConfiguration implements ResolvedConfiguration {
-
- public boolean hasError() {
- return false;
- }
-
- public LenientConfiguration getLenientConfiguration() {
- return new LenientConfiguration() {
- public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) {
- return Collections.emptySet();
- }
-
- public Set<UnresolvedDependency> getUnresolvedModuleDependencies() {
- return Collections.emptySet();
- }
-
- public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
- return Collections.emptySet();
- }
-
- public Set<ResolvedArtifact> getArtifacts(Spec<? super Dependency> dependencySpec) {
- return Collections.emptySet();
- }
- };
- }
-
- public void rethrowFailure() throws ResolveException {
- }
-
- public Set<File> getFiles(Spec<? super Dependency> dependencySpec) {
- return Collections.emptySet();
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies() {
- return Collections.emptySet();
- }
-
- public Set<ResolvedDependency> getFirstLevelModuleDependencies(Spec<? super Dependency> dependencySpec) throws ResolveException {
- return Collections.emptySet();
- }
-
- public Set<ResolvedArtifact> getResolvedArtifacts() {
- return Collections.emptySet();
- }
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ComponentResolvers.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ComponentResolvers.java
new file mode 100644
index 0000000..6228cd0
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ComponentResolvers.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.ivyresolve;
+
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
+import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
+
+public interface ComponentResolvers {
+ DependencyToComponentIdResolver getComponentIdResolver();
+
+ ComponentMetaDataResolver getComponentResolver();
+
+ ArtifactResolver getArtifactResolver();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/DelegatingComponentResolvers.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/DelegatingComponentResolvers.java
new file mode 100644
index 0000000..0fb8887
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/DelegatingComponentResolvers.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.ivyresolve;
+
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
+import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
+
+public class DelegatingComponentResolvers<T extends ArtifactResolver, U extends DependencyToComponentIdResolver, V extends ComponentMetaDataResolver> implements ComponentResolvers {
+ private final T artifactResolver;
+ private final U componentIdResolver;
+ private final V componentResolver;
+
+ public static <T extends ArtifactResolver, U extends DependencyToComponentIdResolver, V extends ComponentMetaDataResolver> ComponentResolvers of(
+ T artifactResolver,
+ U componentIdResolver,
+ V componentResolver
+ ) {
+ return new DelegatingComponentResolvers<T, U, V>(artifactResolver, componentIdResolver, componentResolver);
+ }
+
+ public static <E extends ArtifactResolver & DependencyToComponentIdResolver & ComponentMetaDataResolver> ComponentResolvers of(E delegate) {
+ return new DelegatingComponentResolvers<E, E, E>(delegate, delegate, delegate);
+ }
+
+ public DelegatingComponentResolvers(T artifactResolver, U componentIdResolver, V componentResolver) {
+ this.artifactResolver = artifactResolver;
+ this.componentIdResolver = componentIdResolver;
+ this.componentResolver = componentResolver;
+ }
+
+ @Override
+ public T getArtifactResolver() {
+ return artifactResolver;
+ }
+
+ @Override
+ public U getComponentIdResolver() {
+ return componentIdResolver;
+ }
+
+ @Override
+ public V getComponentResolver() {
+ return componentResolver;
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/IvyContextualiser.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/IvyContextualiser.java
deleted file mode 100755
index f4c7a63..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/IvyContextualiser.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.ivyresolve;
-
-import org.apache.ivy.core.IvyContext;
-
-public class IvyContextualiser {
- public static IvyContext getIvyContext() {
- IvyContext context = IvyContext.getContext();
- if (context.peekIvy() == null) {
- throw new IllegalStateException("Ivy context not established");
- }
- return context;
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/NoRepositoriesResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/NoRepositoriesResolver.java
index aa05ce8..9acb416 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/NoRepositoriesResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/NoRepositoriesResolver.java
@@ -31,7 +31,7 @@ import org.gradle.internal.resolve.result.BuildableComponentResolveResult;
/**
* Used as a fallback when no repositories are defined for a given resolution.
*/
-public class NoRepositoriesResolver implements RepositoryChain, DependencyToComponentIdResolver, ComponentMetaDataResolver, ArtifactResolver {
+public class NoRepositoriesResolver implements ComponentResolvers, DependencyToComponentIdResolver, ComponentMetaDataResolver, ArtifactResolver {
public DependencyToComponentIdResolver getComponentIdResolver() {
return this;
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChain.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChain.java
deleted file mode 100644
index 24c367f..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChain.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.ivyresolve;
-
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
-import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
-import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
-
-public interface RepositoryChain {
- public DependencyToComponentIdResolver getComponentIdResolver();
-
- public ComponentMetaDataResolver getComponentResolver();
-
- public ArtifactResolver getArtifactResolver();
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactory.java
index 67f52ea..9e7cebd 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactory.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactory.java
@@ -72,7 +72,7 @@ public class ResolveIvyFactory {
this.versionComparator = versionComparator;
}
- public RepositoryChain create(ResolutionStrategyInternal resolutionStrategy,
+ public ComponentResolvers create(ResolutionStrategyInternal resolutionStrategy,
Collection<? extends ResolutionAwareRepository> repositories,
ComponentMetadataProcessor metadataProcessor) {
if (repositories.isEmpty()) {
@@ -91,12 +91,9 @@ public class ResolveIvyFactory {
ConfiguredModuleComponentRepository baseRepository = repository.createResolver();
if (baseRepository instanceof ExternalResourceResolver) {
- ((ExternalResourceResolver) baseRepository).setRepositoryChain(parentModuleResolver);
+ ((ExternalResourceResolver) baseRepository).setComponentResolvers(parentModuleResolver);
}
- // TODO:DAZ In theory we could update this so that _all_ repositories are wrapped in a cache:
- // - would need to add local/remote pattern to artifact download
- // - This might help later when we integrate in-memory caching with file-backed caching.
ModuleComponentRepository moduleComponentRepository = baseRepository;
if (baseRepository.isLocal()) {
moduleComponentRepository = new LocalModuleComponentRepository(baseRepository, metadataProcessor);
@@ -123,7 +120,7 @@ public class ResolveIvyFactory {
/**
* Provides access to the top-level resolver chain for looking up parent modules when parsing module descriptor files.
*/
- private static class ParentModuleLookupResolver implements RepositoryChain, DependencyToComponentIdResolver, ComponentMetaDataResolver, ArtifactResolver {
+ private static class ParentModuleLookupResolver implements ComponentResolvers, DependencyToComponentIdResolver, ComponentMetaDataResolver, ArtifactResolver {
private final CacheLockingManager cacheLockingManager;
private final UserResolverChain delegate;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderFactory.java
new file mode 100644
index 0000000..c9a934a
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderFactory.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.ivyresolve;
+
+import org.gradle.api.internal.artifacts.ResolveContext;
+
+public interface ResolverProviderFactory {
+ boolean canCreate(ResolveContext context);
+
+ ComponentResolvers create(ResolveContext context);
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/UserResolverChain.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/UserResolverChain.java
index 233fae6..508bfc7 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/UserResolverChain.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/UserResolverChain.java
@@ -25,7 +25,7 @@ import org.gradle.internal.resolve.resolver.ArtifactResolver;
import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
-public class UserResolverChain implements RepositoryChain {
+public class UserResolverChain implements ComponentResolvers {
private final RepositoryChainDependencyToComponentIdResolver componentIdResolver;
private final RepositoryChainComponentMetaDataResolver componentResolver;
private final RepositoryChainArtifactResolver artifactResolver;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryArtifactsCache.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryArtifactsCache.java
index cba4f26..7d2f92b 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryArtifactsCache.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryArtifactsCache.java
@@ -16,8 +16,8 @@
package org.gradle.api.internal.artifacts.ivyservice.ivyresolve.memcache;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.internal.resolve.result.BuildableArtifactResolveResult;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
import java.io.File;
import java.util.HashMap;
@@ -46,4 +46,4 @@ class InMemoryArtifactsCache {
artifacts.put(id, result.getFile());
}
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryCachedModuleComponentRepository.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryCachedModuleComponentRepository.java
index 2ad30b0..96b65b0 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryCachedModuleComponentRepository.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/memcache/InMemoryCachedModuleComponentRepository.java
@@ -26,7 +26,6 @@ import org.gradle.internal.component.model.DependencyMetaData;
import org.gradle.internal.resolve.result.BuildableModuleComponentMetaDataResolveResult;
import org.gradle.internal.resolve.result.BuildableModuleVersionListingResolveResult;
-// TODO:DAZ Should share local and remote caches, and use make in-memory caching a decorator over filesystem caching
class InMemoryCachedModuleComponentRepository extends BaseModuleComponentRepository {
final InMemoryCacheStats stats;
private final ModuleComponentRepositoryAccess localAccess;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorBuilder.java
index f370eb7..123b029 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorBuilder.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorBuilder.java
@@ -275,7 +275,6 @@ public class GradlePomModuleDescriptorBuilder {
ivyModuleDescriptor.addDependency(dd);
}
- // TODO:DAZ Would be better if we held onto the VersionSelector and only rendered it when required
private String convertVersionFromMavenSyntax(String version) {
VersionSelector versionSelector = mavenVersionSelectorScheme.parseSelector(version);
return defaultVersionSelectorScheme.renderSelector(versionSelector);
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReader.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReader.java
index 21b2510..4edbeb7 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReader.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReader.java
@@ -112,22 +112,21 @@ public class PomReader implements PomParent {
setActiveProfileProperties();
}
- public void setPomParent(PomParent pomParent) {
- this.pomParent = pomParent;
- setPomParentProperties();
+ private void setDefaultParentGavProperties() {
+ maybeSetGavProperties(GavProperty.PARENT_GROUP_ID, getParentGroupId());
+ maybeSetGavProperties(GavProperty.PARENT_VERSION, getParentVersion());
+ maybeSetGavProperties(GavProperty.PARENT_ARTIFACT_ID, getParentArtifactId());
}
- private void setPomParentProperties() {
- Map<String, String> parentPomProps = pomParent.getProperties();
-
- for(Map.Entry<String, String> entry : parentPomProps.entrySet()) {
- setProperty(entry.getKey(), entry.getValue());
+ private void maybeSetGavProperties(GavProperty gavProperty, String propertyValue) {
+ for(String name : gavProperty.getNames()) {
+ maybeSetProperty(name, propertyValue);
}
}
private void setPomProperties() {
for(Map.Entry<String, String> pomProperty : getPomProperties().entrySet()) {
- setProperty(pomProperty.getKey(), pomProperty.getValue());
+ maybeSetProperty(pomProperty.getKey(), pomProperty.getValue());
}
}
@@ -142,27 +141,40 @@ public class PomReader implements PomParent {
}
}
- private void setDefaultParentGavProperties() {
- setGavPropertyValueWithoutReplacement(GavProperty.PARENT_GROUP_ID, getParentGroupId());
- setGavPropertyValueWithoutReplacement(GavProperty.PARENT_VERSION, getParentVersion());
+ public void setPomParent(PomParent pomParent) {
+ this.pomParent = pomParent;
+ setPomParentProperties();
}
- private void setGavPropertyValueWithoutReplacement(GavProperty gavProperty, String propertyValue) {
- for(String name : gavProperty.getNames()) {
- setProperty(name, propertyValue);
+ private void setPomParentProperties() {
+ Map<String, String> parentPomProps = pomParent.getProperties();
+ for(Map.Entry<String, String> entry : parentPomProps.entrySet()) {
+ maybeSetProperty(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Add a property if not yet set and value is not null.
+ * This guarantee that property keep the first value that is put on it and that the properties
+ * are never null.
+ */
+ private void maybeSetProperty(String prop, String val) {
+ if (!properties.containsKey(prop) && val != null) {
+ properties.put(prop, val);
}
}
private enum GavProperty {
- PARENT_VERSION("parent.version", "project.parent.version"),
PARENT_GROUP_ID("parent.groupId", "project.parent.groupId"),
+ PARENT_ARTIFACT_ID("parent.artifactId", "project.parent.artifactId"),
+ PARENT_VERSION("parent.version", "project.parent.version"),
GROUP_ID("project.groupId", "pom.groupId", "groupId"),
ARTIFACT_ID("project.artifactId", "pom.artifactId", "artifactId"),
VERSION("project.version", "pom.version", "version");
private final String[] names;
- private GavProperty(String... names) {
+ GavProperty(String... names) {
this.names = names;
}
@@ -195,17 +207,6 @@ public class PomReader implements PomParent {
return parentElement != null;
}
- /**
- * Add a property if not yet set and value is not null.
- * This guarantee that property keep the first value that is put on it and that the properties
- * are never null.
- */
- public void setProperty(String prop, String val) {
- if (!properties.containsKey(prop) && val != null) {
- properties.put(prop, val);
- }
- }
-
public Map<String, String> getProperties() {
return properties;
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelector.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelector.java
index 5948edd..b37a70d 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelector.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelector.java
@@ -80,14 +80,18 @@ public class VersionRangeSelector extends AbstractVersionSelector {
private static final String UPPER_INFINITE_PATTERN = OPEN_PATTERN + "\\s*("
+ ANY_NON_SPECIAL_PATTERN + "+)" + SEP_PATTERN + UI_PATTERN;
+ private static final String SINGLE_VALUE_PATTERN = OPEN_INC_PATTERN + "\\s*(" + ANY_NON_SPECIAL_PATTERN + "+)" + CLOSE_INC_PATTERN;
+
private static final Pattern FINITE_RANGE = Pattern.compile(FINITE_PATTERN);
private static final Pattern LOWER_INFINITE_RANGE = Pattern.compile(LOWER_INFINITE_PATTERN);
private static final Pattern UPPER_INFINITE_RANGE = Pattern.compile(UPPER_INFINITE_PATTERN);
+ private static final Pattern SINGLE_VALUE_RANGE = Pattern.compile(SINGLE_VALUE_PATTERN);
+
public static final Pattern ALL_RANGE = Pattern.compile(FINITE_PATTERN + "|"
- + LOWER_INFINITE_PATTERN + "|" + UPPER_INFINITE_PATTERN);
+ + LOWER_INFINITE_PATTERN + "|" + UPPER_INFINITE_PATTERN + "|" + SINGLE_VALUE_RANGE);
private final String upperBound;
private final boolean upperInclusive;
@@ -121,7 +125,15 @@ public class VersionRangeSelector extends AbstractVersionSelector {
upperBound = null;
upperInclusive = true;
} else {
- throw new IllegalArgumentException("Not a version range selector: " + selector);
+ matcher = SINGLE_VALUE_RANGE.matcher(selector);
+ if (matcher.matches()) {
+ lowerBound = matcher.group(1);
+ lowerInclusive = true;
+ upperBound = lowerBound;
+ upperInclusive = true;
+ } else {
+ throw new IllegalArgumentException("Not a version range selector: " + selector);
+ }
}
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ComponentConverterSource.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ComponentConverterSource.java
deleted file mode 100644
index e107e3c..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ComponentConverterSource.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
-
-import org.gradle.api.artifacts.Configuration;
-import org.gradle.api.internal.artifacts.ModuleInternal;
-
-import java.util.Set;
-
-public class ComponentConverterSource {
- private final Set<? extends Configuration> configurations;
- private final ModuleInternal module;
-
- public ComponentConverterSource(Set<? extends Configuration> configurations, ModuleInternal module) {
- this.configurations = configurations;
- this.module = module;
- }
-
- public Set<? extends Configuration> getConfigurations() {
- return configurations;
- }
-
- public ModuleInternal getModule() {
- return module;
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/CompositeResolveLocalComponentFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/CompositeResolveLocalComponentFactory.java
deleted file mode 100644
index b0184d5..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/CompositeResolveLocalComponentFactory.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
-
-import com.google.common.collect.Sets;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
-import org.gradle.internal.component.local.model.LocalComponentMetaData;
-
-import java.util.Set;
-
-public class CompositeResolveLocalComponentFactory implements LocalComponentFactory {
- private final Set<LocalComponentFactory> factories;
-
- public CompositeResolveLocalComponentFactory(LocalComponentFactory... factories) {
- this.factories = Sets.newHashSet(factories);
- }
-
- public void addFactory(LocalComponentFactory factory) {
- factories.add(factory);
- }
-
- @Override
- public boolean canConvert(Object source) {
- return true;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public LocalComponentMetaData convert(Object context) {
- for (LocalComponentFactory factory : factories) {
- if (factory.canConvert(context)) {
- return factory.convert(context);
- }
- }
- throw new IllegalArgumentException("Unable to find a local converter factory for type "+context.getClass());
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationBackedComponent.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationBackedComponent.java
new file mode 100644
index 0000000..bbacf2f
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationBackedComponent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
+
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.internal.artifacts.ModuleInternal;
+
+import java.util.Set;
+
+public class ConfigurationBackedComponent {
+ private final Set<? extends Configuration> configurations;
+ private final ModuleInternal module;
+
+ public ConfigurationBackedComponent(ModuleInternal module, Set<? extends Configuration> configurations) {
+ this.configurations = configurations;
+ this.module = module;
+ }
+
+ public ModuleInternal getModule() {
+ return module;
+ }
+
+ public Set<? extends Configuration> getConfigurations() {
+ return configurations;
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationLocalComponentConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationLocalComponentConverter.java
new file mode 100644
index 0000000..bbb6739
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationLocalComponentConverter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
+
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier;
+import org.gradle.api.internal.artifacts.ModuleInternal;
+import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory;
+import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
+import org.gradle.api.internal.artifacts.ivyservice.LocalComponentConverter;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependenciesToModuleDescriptorConverter;
+import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData;
+import org.gradle.internal.component.local.model.LocalComponentMetaData;
+
+import java.util.Set;
+
+public class ConfigurationLocalComponentConverter implements LocalComponentConverter {
+ private final ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter;
+ private final DependenciesToModuleDescriptorConverter dependenciesToModuleDescriptorConverter;
+ private final ComponentIdentifierFactory componentIdentifierFactory;
+ private final ConfigurationsToArtifactsConverter configurationsToArtifactsConverter;
+
+ public ConfigurationLocalComponentConverter(ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter,
+ DependenciesToModuleDescriptorConverter dependenciesToModuleDescriptorConverter,
+ ComponentIdentifierFactory componentIdentifierFactory,
+ ConfigurationsToArtifactsConverter configurationsToArtifactsConverter) {
+ this.configurationsToModuleDescriptorConverter = configurationsToModuleDescriptorConverter;
+ this.dependenciesToModuleDescriptorConverter = dependenciesToModuleDescriptorConverter;
+ this.componentIdentifierFactory = componentIdentifierFactory;
+ this.configurationsToArtifactsConverter = configurationsToArtifactsConverter;
+ }
+
+ @Override
+ public boolean canConvert(Object source) {
+ return source instanceof ConfigurationBackedComponent || source instanceof Configuration;
+ }
+
+ @Override
+ public LocalComponentMetaData convert(Object source) {
+ ModuleInternal module;
+ Set<? extends Configuration> configurations;
+ if (source instanceof Configuration) {
+ configurations = ((Configuration) source).getAll();
+ module = ((ConfigurationInternal) source).getModule();
+ } else {
+ configurations = ((ConfigurationBackedComponent) source).getConfigurations();
+ module = ((ConfigurationBackedComponent) source).getModule();
+ }
+ assert configurations.size() > 0 : "No configurations found for module: " + module.getName() + ". Configure them or apply a plugin that does it.";
+ ComponentIdentifier componentIdentifier = componentIdentifierFactory.createComponentIdentifier(module);
+ ModuleVersionIdentifier moduleVersionIdentifier = DefaultModuleVersionIdentifier.newId(module);
+ DefaultLocalComponentMetaData metaData = new DefaultLocalComponentMetaData(moduleVersionIdentifier, componentIdentifier, module.getStatus());
+ configurationsToModuleDescriptorConverter.addConfigurations(metaData, configurations);
+ dependenciesToModuleDescriptorConverter.addDependencyDescriptors(metaData, configurations);
+ configurationsToArtifactsConverter.addArtifacts(metaData, configurations);
+ return metaData;
+ }
+
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToArtifactsConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToArtifactsConverter.java
index 548abd9..d7dddae 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToArtifactsConverter.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToArtifactsConverter.java
@@ -16,8 +16,8 @@
package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
import org.gradle.api.artifacts.Configuration;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
public interface ConfigurationsToArtifactsConverter {
- void addArtifacts(MutableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations);
+ void addArtifacts(BuildableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToModuleDescriptorConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToModuleDescriptorConverter.java
index ef8d7d3..e19907f 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToModuleDescriptorConverter.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationsToModuleDescriptorConverter.java
@@ -16,8 +16,8 @@
package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
import org.gradle.api.artifacts.Configuration;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
public interface ConfigurationsToModuleDescriptorConverter {
- void addConfigurations(MutableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations);
+ void addConfigurations(BuildableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverter.java
index 9d235a4..183ace6 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverter.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverter.java
@@ -16,11 +16,11 @@
package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
import org.gradle.api.artifacts.Configuration;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
public class DefaultConfigurationsToArtifactsConverter implements ConfigurationsToArtifactsConverter {
- public void addArtifacts(MutableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations) {
+ public void addArtifacts(BuildableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations) {
for (Configuration configuration : configurations) {
metaData.addArtifacts(configuration.getName(), configuration.getArtifacts());
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverter.java
index a393a87..cd19ec4 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverter.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverter.java
@@ -17,20 +17,23 @@ package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.internal.artifacts.configurations.Configurations;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
+import org.gradle.api.internal.artifacts.configurations.DirectBuildDependencies;
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
import java.util.Set;
public class DefaultConfigurationsToModuleDescriptorConverter implements ConfigurationsToModuleDescriptorConverter {
- public void addConfigurations(MutableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations) {
+ public void addConfigurations(BuildableLocalComponentMetaData metaData, Iterable<? extends Configuration> configurations) {
for (Configuration configuration : configurations) {
addConfiguration(metaData, configuration);
}
}
- private void addConfiguration(MutableLocalComponentMetaData metaData, Configuration configuration) {
+ private void addConfiguration(BuildableLocalComponentMetaData metaData, Configuration configuration) {
Set<String> hierarchy = Configurations.getNames(configuration.getHierarchy());
Set<String> extendsFrom = Configurations.getNames(configuration.getExtendsFrom());
- metaData.addConfiguration(configuration.getName(), configuration.getDescription(), extendsFrom, hierarchy, configuration.isVisible(), configuration.isTransitive());
+ TaskDependency directBuildDependencies = DirectBuildDependencies.forDependenciesAndArtifacts(configuration);
+ metaData.addConfiguration(configuration.getName(), configuration.getDescription(), extendsFrom, hierarchy, configuration.isVisible(), configuration.isTransitive(), directBuildDependencies);
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ResolveLocalComponentFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ResolveLocalComponentFactory.java
deleted file mode 100644
index 6202573..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ResolveLocalComponentFactory.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2007 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
-
-import org.gradle.api.artifacts.Configuration;
-import org.gradle.api.artifacts.ModuleVersionIdentifier;
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier;
-import org.gradle.api.internal.artifacts.ModuleInternal;
-import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory;
-import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
-import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependenciesToModuleDescriptorConverter;
-import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
-
-import java.util.Set;
-
-public class ResolveLocalComponentFactory implements LocalComponentFactory {
- private final ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter;
- private final DependenciesToModuleDescriptorConverter dependenciesToModuleDescriptorConverter;
- private final ComponentIdentifierFactory componentIdentifierFactory;
- private final ConfigurationsToArtifactsConverter configurationsToArtifactsConverter;
-
- public ResolveLocalComponentFactory(ConfigurationsToModuleDescriptorConverter configurationsToModuleDescriptorConverter,
- DependenciesToModuleDescriptorConverter dependenciesToModuleDescriptorConverter,
- ComponentIdentifierFactory componentIdentifierFactory,
- ConfigurationsToArtifactsConverter configurationsToArtifactsConverter) {
- this.configurationsToModuleDescriptorConverter = configurationsToModuleDescriptorConverter;
- this.dependenciesToModuleDescriptorConverter = dependenciesToModuleDescriptorConverter;
- this.componentIdentifierFactory = componentIdentifierFactory;
- this.configurationsToArtifactsConverter = configurationsToArtifactsConverter;
- }
-
- @Override
- public boolean canConvert(Object source) {
- return source instanceof ComponentConverterSource || source instanceof Configuration;
- }
-
- @Override
- public MutableLocalComponentMetaData convert(Object source) {
- Set<? extends Configuration> contexts;
- ModuleInternal module;
- if (source instanceof Configuration) {
- contexts = ((Configuration) source).getAll();
- module = ((ConfigurationInternal)source).getModule();
- } else {
- contexts = ((ComponentConverterSource)source).getConfigurations();
- module = ((ComponentConverterSource)source).getModule();
- }
- assert contexts.size() > 0 : "No configurations found for module: " + module.getName() + ". Configure them or apply a plugin that does it.";
- ComponentIdentifier componentIdentifier = componentIdentifierFactory.createComponentIdentifier(module);
- ModuleVersionIdentifier moduleVersionIdentifier = DefaultModuleVersionIdentifier.newId(module);
- DefaultLocalComponentMetaData metaData = new DefaultLocalComponentMetaData(moduleVersionIdentifier, componentIdentifier, module.getStatus());
- configurationsToModuleDescriptorConverter.addConfigurations(metaData, contexts);
- dependenciesToModuleDescriptorConverter.addDependencyDescriptors(metaData, contexts);
- configurationsToArtifactsConverter.addArtifacts(metaData, contexts);
- return metaData;
- }
-
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverter.java
index 285ffe4..4103c2b 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverter.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverter.java
@@ -19,7 +19,7 @@ import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ExcludeRule;
import org.gradle.api.artifacts.ModuleDependency;
import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ExcludeRuleConverter;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
import java.util.Collection;
@@ -33,13 +33,13 @@ public class DefaultDependenciesToModuleDescriptorConverter implements Dependenc
this.excludeRuleConverter = excludeRuleConverter;
}
- public void addDependencyDescriptors(MutableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations) {
+ public void addDependencyDescriptors(BuildableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations) {
assert !configurations.isEmpty();
addDependencies(metaData, configurations);
addExcludeRules(metaData, configurations);
}
- private void addDependencies(MutableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations) {
+ private void addDependencies(BuildableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations) {
for (Configuration configuration : configurations) {
for (ModuleDependency dependency : configuration.getDependencies().withType(ModuleDependency.class)) {
metaData.addDependency(dependencyDescriptorFactory.createDependencyDescriptor(configuration.getName(), dependency));
@@ -47,7 +47,7 @@ public class DefaultDependenciesToModuleDescriptorConverter implements Dependenc
}
}
- private void addExcludeRules(MutableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations) {
+ private void addExcludeRules(BuildableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations) {
for (Configuration configuration : configurations) {
for (ExcludeRule excludeRule : configuration.getExcludeRules()) {
org.apache.ivy.core.module.descriptor.ExcludeRule rule = excludeRuleConverter.createExcludeRule(
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DependenciesToModuleDescriptorConverter.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DependenciesToModuleDescriptorConverter.java
index bef1e5c..5a9d1ff 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DependenciesToModuleDescriptorConverter.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DependenciesToModuleDescriptorConverter.java
@@ -16,10 +16,10 @@
package org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies;
import org.gradle.api.artifacts.Configuration;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
import java.util.Collection;
public interface DependenciesToModuleDescriptorConverter {
- void addDependencyDescriptors(MutableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations);
+ void addDependencyDescriptors(BuildableLocalComponentMetaData metaData, Collection<? extends Configuration> configurations);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/ProjectIvyDependencyDescriptorFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/ProjectIvyDependencyDescriptorFactory.java
index 2a429ea..0627194 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/ProjectIvyDependencyDescriptorFactory.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/ProjectIvyDependencyDescriptorFactory.java
@@ -40,8 +40,6 @@ public class ProjectIvyDependencyDescriptorFactory extends AbstractIvyDependency
projectDependency.beforeResolved();
((ConfigurationInternal) projectDependency.getProjectConfiguration()).triggerWhenEmptyActionsIfNecessary();
Module module = getProjectModule(dependency);
-
- // TODO:DAZ What are the GAV values for the dependency here?
ModuleVersionSelector requested = new DefaultModuleVersionSelector(module.getGroup(), module.getName(), module.getVersion());
ComponentSelector selector = DefaultProjectComponentSelector.newSelector(projectDependency.getDependencyProject().getPath());
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/DefaultProjectComponentRegistry.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/DefaultProjectComponentRegistry.java
index e4e623e..54ed1d0 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/DefaultProjectComponentRegistry.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/DefaultProjectComponentRegistry.java
@@ -15,18 +15,18 @@
*/
package org.gradle.api.internal.artifacts.ivyservice.projectmodule;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
-import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ComponentConverterSource;
+import org.gradle.api.internal.artifacts.ivyservice.LocalComponentConverter;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ConfigurationBackedComponent;
import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.api.internal.project.ProjectRegistry;
import org.gradle.internal.component.local.model.LocalComponentMetaData;
public class DefaultProjectComponentRegistry implements ProjectComponentRegistry {
- private final LocalComponentFactory localComponentFactory;
+ private final LocalComponentConverter localComponentConverter;
private final ProjectRegistry<ProjectInternal> projectRegistry;
- public DefaultProjectComponentRegistry(LocalComponentFactory localComponentFactory, ProjectRegistry<ProjectInternal> projectRegistry) {
- this.localComponentFactory = localComponentFactory;
+ public DefaultProjectComponentRegistry(LocalComponentConverter localComponentConverter, ProjectRegistry<ProjectInternal> projectRegistry) {
+ this.localComponentConverter = localComponentConverter;
this.projectRegistry = projectRegistry;
}
@@ -35,6 +35,6 @@ public class DefaultProjectComponentRegistry implements ProjectComponentRegistry
if (project == null) {
return null;
}
- return localComponentFactory.convert(new ComponentConverterSource(project.getConfigurations(), project.getModule()));
+ return localComponentConverter.convert(new ConfigurationBackedComponent(project.getModule(), project.getConfigurations()));
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectArtifactResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectArtifactResolver.java
deleted file mode 100644
index aca8cc3..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectArtifactResolver.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.projectmodule;
-
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier;
-import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
-import org.gradle.api.internal.component.ArtifactType;
-import org.gradle.internal.component.local.model.LocalComponentArtifactIdentifier;
-import org.gradle.internal.component.model.ComponentArtifactMetaData;
-import org.gradle.internal.component.model.ComponentResolveMetaData;
-import org.gradle.internal.component.model.ComponentUsage;
-import org.gradle.internal.component.model.ModuleSource;
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
-import org.gradle.internal.resolve.result.BuildableArtifactResolveResult;
-import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
-
-import java.io.File;
-import java.util.Set;
-
-public class ProjectArtifactResolver implements ArtifactResolver {
- private final ArtifactResolver delegate;
-
- public ProjectArtifactResolver(ArtifactResolver delegate) {
- this.delegate = delegate;
- }
-
- public void resolveModuleArtifacts(ComponentResolveMetaData component, ArtifactType artifactType, BuildableArtifactSetResolveResult result) {
- if (isProjectModule(component.getComponentId())) {
- throw new UnsupportedOperationException("Resolving artifacts by type is not yet supported for project modules");
- }
- delegate.resolveModuleArtifacts(component, artifactType, result);
- }
-
- public void resolveModuleArtifacts(ComponentResolveMetaData component, ComponentUsage usage, BuildableArtifactSetResolveResult result) {
- if (isProjectModule(component.getComponentId()) || isLibrary(component.getComponentId())) {
- String configurationName = usage.getConfigurationName();
- Set<ComponentArtifactMetaData> artifacts = component.getConfiguration(configurationName).getArtifacts();
- result.resolved(artifacts);
- return;
- }
- delegate.resolveModuleArtifacts(component, usage, result);
- }
-
- public void resolveArtifact(ComponentArtifactMetaData artifact, ModuleSource moduleSource, BuildableArtifactResolveResult result) {
- if (isProjectModule(artifact.getComponentId())) {
- LocalComponentArtifactIdentifier id = (LocalComponentArtifactIdentifier) artifact.getId();
- File localArtifactFile = id.getFile();
- if (localArtifactFile != null) {
- result.resolved(localArtifactFile);
- } else {
- result.notFound(artifact.getId());
- }
- } else {
- delegate.resolveArtifact(artifact, moduleSource, result);
- }
- }
-
- private boolean isProjectModule(ComponentIdentifier componentId) {
- return componentId instanceof ProjectComponentIdentifier;
- }
- private boolean isLibrary(ComponentIdentifier componentId) {
- return componentId instanceof LibraryComponentIdentifier;
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolver.java
index 8ccd888..d2cf35f 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolver.java
@@ -15,33 +15,31 @@
*/
package org.gradle.api.internal.artifacts.ivyservice.projectmodule;
-import org.gradle.api.artifacts.ResolveContext;
import org.gradle.api.artifacts.component.ComponentIdentifier;
import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
import org.gradle.api.artifacts.component.ProjectComponentSelector;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
+import org.gradle.api.internal.component.ArtifactType;
import org.gradle.internal.component.local.model.DefaultProjectComponentSelector;
+import org.gradle.internal.component.local.model.LocalComponentArtifactIdentifier;
import org.gradle.internal.component.local.model.LocalComponentMetaData;
-import org.gradle.internal.component.model.ComponentOverrideMetadata;
-import org.gradle.internal.component.model.DependencyMetaData;
+import org.gradle.internal.component.model.*;
import org.gradle.internal.resolve.ModuleVersionResolveException;
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
-import org.gradle.internal.resolve.resolver.ResolveContextToComponentResolver;
+import org.gradle.internal.resolve.result.BuildableArtifactResolveResult;
+import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
import org.gradle.internal.resolve.result.BuildableComponentIdResolveResult;
import org.gradle.internal.resolve.result.BuildableComponentResolveResult;
-public class ProjectDependencyResolver implements DependencyToComponentIdResolver, ResolveContextToComponentResolver, ComponentMetaDataResolver {
+import java.io.File;
+import java.util.Set;
+
+public class ProjectDependencyResolver implements ComponentMetaDataResolver, DependencyToComponentIdResolver, ArtifactResolver {
private final ProjectComponentRegistry projectComponentRegistry;
- private final DependencyToComponentIdResolver delegateIdResolver;
- private final ComponentMetaDataResolver delegateComponentResolver;
- private final LocalComponentFactory localComponentFactory;
- public ProjectDependencyResolver(ProjectComponentRegistry projectComponentRegistry, LocalComponentFactory localComponentFactory, DependencyToComponentIdResolver delegateIdResolver, ComponentMetaDataResolver delegateComponentResolver) {
+ public ProjectDependencyResolver(ProjectComponentRegistry projectComponentRegistry) {
this.projectComponentRegistry = projectComponentRegistry;
- this.delegateIdResolver = delegateIdResolver;
- this.delegateComponentResolver = delegateComponentResolver;
- this.localComponentFactory = localComponentFactory;
}
public void resolve(DependencyMetaData dependency, BuildableComponentIdResolveResult result) {
@@ -52,10 +50,8 @@ public class ProjectDependencyResolver implements DependencyToComponentIdResolve
if (componentMetaData == null) {
result.failed(new ModuleVersionResolveException(selector, "project '" + projectPath + "' not found."));
} else {
- result.resolved(componentMetaData.toResolveMetaData());
+ result.resolved(componentMetaData);
}
- } else {
- delegateIdResolver.resolve(dependency, result);
}
}
@@ -66,15 +62,38 @@ public class ProjectDependencyResolver implements DependencyToComponentIdResolve
if (componentMetaData == null) {
result.failed(new ModuleVersionResolveException(new DefaultProjectComponentSelector(projectPath), "project '" + projectPath + "' not found."));
} else {
- result.resolved(componentMetaData.toResolveMetaData());
+ result.resolved(componentMetaData);
+ }
+ }
+ }
+
+ public void resolveModuleArtifacts(ComponentResolveMetaData component, ArtifactType artifactType, BuildableArtifactSetResolveResult result) {
+ if (isProjectModule(component.getComponentId())) {
+ throw new UnsupportedOperationException("Resolving artifacts by type is not yet supported for project modules");
+ }
+ }
+
+ public void resolveModuleArtifacts(ComponentResolveMetaData component, ComponentUsage usage, BuildableArtifactSetResolveResult result) {
+ if (isProjectModule(component.getComponentId())) {
+ String configurationName = usage.getConfigurationName();
+ Set<ComponentArtifactMetaData> artifacts = component.getConfiguration(configurationName).getArtifacts();
+ result.resolved(artifacts);
+ }
+ }
+
+ public void resolveArtifact(ComponentArtifactMetaData component, ModuleSource moduleSource, BuildableArtifactResolveResult result) {
+ if (isProjectModule(component.getComponentId())) {
+ LocalComponentArtifactIdentifier id = (LocalComponentArtifactIdentifier) component.getId();
+ File localArtifactFile = id.getFile();
+ if (localArtifactFile != null) {
+ result.resolved(localArtifactFile);
+ } else {
+ result.notFound(component.getId());
}
- } else {
- delegateComponentResolver.resolve(identifier, componentOverrideMetadata, result);
}
}
- public void resolve(ResolveContext resolveContext, BuildableComponentResolveResult result) {
- LocalComponentMetaData componentMetaData = localComponentFactory.convert(resolveContext);
- result.resolved(componentMetaData.toResolveMetaData());
+ private boolean isProjectModule(ComponentIdentifier componentId) {
+ return componentId instanceof ProjectComponentIdentifier;
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/ComponentResolversChain.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/ComponentResolversChain.java
new file mode 100644
index 0000000..54add7e
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/ComponentResolversChain.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine;
+
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers;
+import org.gradle.api.internal.component.ArtifactType;
+import org.gradle.internal.component.model.*;
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
+import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
+import org.gradle.internal.resolve.result.BuildableArtifactResolveResult;
+import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
+import org.gradle.internal.resolve.result.BuildableComponentIdResolveResult;
+import org.gradle.internal.resolve.result.BuildableComponentResolveResult;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ComponentResolversChain implements ComponentResolvers {
+ private final DependencyToComponentIdResolverChain dependencyToComponentIdResolver;
+ private final ComponentMetaDataResolverChain componentMetaDataResolver;
+ private final ArtifactResolverChain artifactResolverChain;
+
+ public ComponentResolversChain(List<ComponentResolvers> providers) {
+ List<DependencyToComponentIdResolver> depToComponentIdResolvers = new ArrayList<DependencyToComponentIdResolver>(providers.size());
+ List<ComponentMetaDataResolver> componentMetaDataResolvers = new ArrayList<ComponentMetaDataResolver>(providers.size());
+ List<ArtifactResolver> artifactResolvers = new ArrayList<ArtifactResolver>(providers.size());
+ for (ComponentResolvers provider : providers) {
+ depToComponentIdResolvers.add(provider.getComponentIdResolver());
+ componentMetaDataResolvers.add(provider.getComponentResolver());
+ artifactResolvers.add(provider.getArtifactResolver());
+ }
+ dependencyToComponentIdResolver = new DependencyToComponentIdResolverChain(depToComponentIdResolvers);
+ componentMetaDataResolver = new ComponentMetaDataResolverChain(componentMetaDataResolvers);
+ artifactResolverChain = new ArtifactResolverChain(artifactResolvers);
+ }
+
+ @Override
+ public DependencyToComponentIdResolver getComponentIdResolver() {
+ return dependencyToComponentIdResolver;
+ }
+
+ @Override
+ public ComponentMetaDataResolver getComponentResolver() {
+ return componentMetaDataResolver;
+ }
+
+ @Override
+ public ArtifactResolver getArtifactResolver() {
+ return artifactResolverChain;
+ }
+
+ private static class ComponentMetaDataResolverChain implements ComponentMetaDataResolver {
+ private final List<ComponentMetaDataResolver> resolvers;
+
+ public ComponentMetaDataResolverChain(List<ComponentMetaDataResolver> resolvers) {
+ this.resolvers = resolvers;
+ }
+
+ @Override
+ public void resolve(ComponentIdentifier identifier, ComponentOverrideMetadata componentOverrideMetadata, BuildableComponentResolveResult result) {
+ for (ComponentMetaDataResolver resolver : resolvers) {
+ if (result.hasResult()) {
+ return;
+ }
+ resolver.resolve(identifier, componentOverrideMetadata, result);
+ }
+ }
+ }
+
+ private static class ArtifactResolverChain implements ArtifactResolver {
+ private final List<ArtifactResolver> resolvers;
+
+ private ArtifactResolverChain(List<ArtifactResolver> resolvers) {
+ this.resolvers = resolvers;
+ }
+
+ @Override
+ public void resolveArtifact(ComponentArtifactMetaData artifact, ModuleSource moduleSource, BuildableArtifactResolveResult result) {
+ for (ArtifactResolver resolver : resolvers) {
+ if (result.hasResult()) {
+ return;
+ }
+ resolver.resolveArtifact(artifact, moduleSource, result);
+ }
+ }
+
+ @Override
+ public void resolveModuleArtifacts(ComponentResolveMetaData component, ComponentUsage usage, BuildableArtifactSetResolveResult result) {
+ for (ArtifactResolver resolver : resolvers) {
+ if (result.hasResult()) {
+ return;
+ }
+ resolver.resolveModuleArtifacts(component, usage, result);
+ }
+ }
+
+ @Override
+ public void resolveModuleArtifacts(ComponentResolveMetaData component, ArtifactType artifactType, BuildableArtifactSetResolveResult result) {
+ for (ArtifactResolver resolver : resolvers) {
+ if (result.hasResult()) {
+ return;
+ }
+ resolver.resolveModuleArtifacts(component, artifactType, result);
+ }
+ }
+ }
+
+ private static class DependencyToComponentIdResolverChain implements DependencyToComponentIdResolver {
+ private final List<DependencyToComponentIdResolver> resolvers;
+
+ public DependencyToComponentIdResolverChain(List<DependencyToComponentIdResolver> resolvers) {
+ this.resolvers = resolvers;
+ }
+
+ @Override
+ public void resolve(DependencyMetaData dependency, BuildableComponentIdResolveResult result) {
+ for (DependencyToComponentIdResolver resolver : resolvers) {
+ if (result.hasResult()) {
+ return;
+ }
+ resolver.resolve(dependency, result);
+ }
+ }
+ }
+
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DefaultArtifactDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DefaultArtifactDependencyResolver.java
new file mode 100755
index 0000000..ff40639
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DefaultArtifactDependencyResolver.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine;
+
+import com.google.common.collect.Lists;
+import org.apache.ivy.Ivy;
+import org.gradle.api.Action;
+import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
+import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
+import org.gradle.api.internal.artifacts.ResolveContext;
+import org.gradle.api.internal.artifacts.configurations.ResolutionStrategyInternal;
+import org.gradle.api.internal.artifacts.ivyservice.CacheLockingManager;
+import org.gradle.api.internal.artifacts.ivyservice.ContextualArtifactResolver;
+import org.gradle.api.internal.artifacts.ivyservice.IvyContextManager;
+import org.gradle.api.internal.artifacts.ivyservice.LocalComponentConverter;
+import org.gradle.api.internal.artifacts.ivyservice.clientmodule.ClientModuleResolver;
+import org.gradle.api.internal.artifacts.ivyservice.dependencysubstitution.DependencySubstitutionResolver;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingArtifactResolver;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolveIvyFactory;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolverProviderFactory;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionComparator;
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependencyDescriptorFactory;
+import org.gradle.api.internal.artifacts.ivyservice.resolutionstrategy.StrictConflictResolution;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.CompositeDependencyGraphVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphBuilder;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.ConflictHandler;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.DefaultConflictHandler;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactsGraphVisitor;
+import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
+import org.gradle.internal.component.local.model.LocalComponentMetaData;
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
+import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
+import org.gradle.internal.resolve.resolver.ResolveContextToComponentResolver;
+import org.gradle.internal.resolve.result.BuildableComponentResolveResult;
+import org.gradle.internal.service.ServiceRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class DefaultArtifactDependencyResolver implements ArtifactDependencyResolver {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultArtifactDependencyResolver.class);
+ private final ServiceRegistry serviceRegistry;
+ private final DependencyDescriptorFactory dependencyDescriptorFactory;
+ private final ResolveIvyFactory ivyFactory;
+ private final CacheLockingManager cacheLockingManager;
+ private final IvyContextManager ivyContextManager;
+ private final VersionComparator versionComparator;
+
+ public DefaultArtifactDependencyResolver(ServiceRegistry serviceRegistry, ResolveIvyFactory ivyFactory, DependencyDescriptorFactory dependencyDescriptorFactory,
+ CacheLockingManager cacheLockingManager, IvyContextManager ivyContextManager, VersionComparator versionComparator) {
+ this.serviceRegistry = serviceRegistry;
+ this.ivyFactory = ivyFactory;
+ this.dependencyDescriptorFactory = dependencyDescriptorFactory;
+ this.cacheLockingManager = cacheLockingManager;
+ this.ivyContextManager = ivyContextManager;
+ this.versionComparator = versionComparator;
+ }
+
+ @Override
+ public void resolve(final ResolveContext resolveContext, final List<? extends ResolutionAwareRepository> repositories, final GlobalDependencyResolutionRules metadataHandler,
+ final DependencyGraphVisitor graphVisitor, final DependencyArtifactsVisitor artifactsVisitor) {
+ ivyContextManager.withIvy(new Action<Ivy>() {
+ public void execute(Ivy ivy) {
+ LOGGER.debug("Resolving {}", resolveContext);
+ ComponentResolvers componentSource = createComponentSource(resolveContext, repositories, metadataHandler);
+ DependencyGraphBuilder builder = createDependencyGraphBuilder(componentSource, resolveContext.getResolutionStrategy(), metadataHandler);
+
+ ArtifactResolver artifactResolver = new ErrorHandlingArtifactResolver(new ContextualArtifactResolver(cacheLockingManager, ivyContextManager, componentSource.getArtifactResolver()));
+ DependencyGraphVisitor artifactsGraphVisitor = new ResolvedArtifactsGraphVisitor(artifactsVisitor, artifactResolver);
+
+ // Resolve the dependency graph
+ builder.resolve(resolveContext, new CompositeDependencyGraphVisitor(graphVisitor, artifactsGraphVisitor));
+ }
+ });
+ }
+
+ private DependencyGraphBuilder createDependencyGraphBuilder(ComponentResolvers componentSource, ResolutionStrategyInternal resolutionStrategy, GlobalDependencyResolutionRules metadataHandler) {
+
+ DependencyToComponentIdResolver componentIdResolver = new DependencySubstitutionResolver(componentSource.getComponentIdResolver(), resolutionStrategy.getDependencySubstitutionRule());
+ ComponentMetaDataResolver componentMetaDataResolver = new ClientModuleResolver(componentSource.getComponentResolver(), dependencyDescriptorFactory);
+
+ DependencyToConfigurationResolver dependencyToConfigurationResolver = new DefaultDependencyToConfigurationResolver();
+ ResolveContextToComponentResolver requestResolver = createResolveContextConverter();
+ ConflictHandler conflictHandler = createConflictHandler(resolutionStrategy, metadataHandler);
+
+ return new DependencyGraphBuilder(componentIdResolver, componentMetaDataResolver, requestResolver, dependencyToConfigurationResolver, conflictHandler);
+ }
+
+ private ComponentResolversChain createComponentSource(ResolveContext resolveContext, List<? extends ResolutionAwareRepository> repositories, GlobalDependencyResolutionRules metadataHandler) {
+ List<ResolverProviderFactory> resolverFactories = allServices(ResolverProviderFactory.class);
+ List<ComponentResolvers> resolvers = Lists.newArrayList();
+ for (ResolverProviderFactory factory : resolverFactories) {
+ if (factory.canCreate(resolveContext)) {
+ resolvers.add(factory.create(resolveContext));
+ }
+ }
+ ResolutionStrategyInternal resolutionStrategy = resolveContext.getResolutionStrategy();
+ resolvers.add(ivyFactory.create(resolutionStrategy, repositories, metadataHandler.getComponentMetadataProcessor()));
+ return new ComponentResolversChain(resolvers);
+ }
+
+ private ResolveContextToComponentResolver createResolveContextConverter() {
+ List<LocalComponentConverter> localComponentFactories = allServices(LocalComponentConverter.class);
+ return new DefaultResolveContextToComponentResolver(new ChainedLocalComponentConverter(localComponentFactories));
+ }
+
+ private ConflictHandler createConflictHandler(ResolutionStrategyInternal resolutionStrategy, GlobalDependencyResolutionRules metadataHandler) {
+ ModuleConflictResolver conflictResolver;
+ if (resolutionStrategy.getConflictResolution() instanceof StrictConflictResolution) {
+ conflictResolver = new StrictConflictResolver();
+ } else {
+ conflictResolver = new LatestModuleConflictResolver(versionComparator);
+ }
+ conflictResolver = new VersionSelectionReasonResolver(conflictResolver);
+ return new DefaultConflictHandler(conflictResolver, metadataHandler.getModuleMetadataProcessor().getModuleReplacements());
+ }
+
+ private <T> List<T> allServices(Class<T> serviceType) {
+ return Lists.newArrayList(serviceRegistry.getAll(serviceType));
+ }
+
+ private static class ChainedLocalComponentConverter implements LocalComponentConverter {
+ private final List<LocalComponentConverter> factories;
+
+ public ChainedLocalComponentConverter(List<LocalComponentConverter> factories) {
+ this.factories = factories;
+ }
+
+ @Override
+ public boolean canConvert(Object source) {
+ for (LocalComponentConverter factory : factories) {
+ if (factory.canConvert(source)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public LocalComponentMetaData convert(Object context) {
+ for (LocalComponentConverter factory : factories) {
+ if (factory.canConvert(context)) {
+ return factory.convert(context);
+ }
+ }
+ throw new IllegalArgumentException("Unable to find a local converter factory for type " + context.getClass());
+ }
+ }
+
+ private static class DefaultResolveContextToComponentResolver implements ResolveContextToComponentResolver {
+ private final LocalComponentConverter localComponentFactory;
+
+ public DefaultResolveContextToComponentResolver(ChainedLocalComponentConverter localComponentFactory) {
+ this.localComponentFactory = localComponentFactory;
+ }
+
+ @Override
+ public void resolve(ResolveContext resolveContext, BuildableComponentResolveResult result) {
+ LocalComponentMetaData componentMetaData = localComponentFactory.convert(resolveContext);
+ result.resolved(componentMetaData);
+ }
+ }
+
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DefaultDependencyResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DefaultDependencyResolver.java
deleted file mode 100755
index 61e0fb9..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DefaultDependencyResolver.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine;
-
-import org.apache.ivy.Ivy;
-import org.gradle.api.Action;
-import org.gradle.api.artifacts.Configuration;
-import org.gradle.api.artifacts.ResolveContext;
-import org.gradle.api.artifacts.ResolveException;
-import org.gradle.api.artifacts.result.ResolvedComponentResult;
-import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
-import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
-import org.gradle.api.internal.artifacts.ResolveContextInternal;
-import org.gradle.api.internal.artifacts.ResolverResults;
-import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal;
-import org.gradle.api.internal.artifacts.configurations.ResolutionStrategyInternal;
-import org.gradle.api.internal.artifacts.ivyservice.*;
-import org.gradle.api.internal.artifacts.ivyservice.clientmodule.ClientModuleResolver;
-import org.gradle.api.internal.artifacts.ivyservice.dependencysubstitution.DependencySubstitutionResolver;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingArtifactResolver;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChain;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolveIvyFactory;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionComparator;
-import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependencyDescriptorFactory;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectArtifactResolver;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectComponentRegistry;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectDependencyResolver;
-import org.gradle.api.internal.artifacts.ivyservice.resolutionstrategy.DefaultResolutionStrategy;
-import org.gradle.api.internal.artifacts.ivyservice.resolutionstrategy.StrictConflictResolution;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.ConflictHandler;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.DefaultConflictHandler;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.*;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.DefaultResolvedProjectConfigurationResultBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResultBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ResolutionResultBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.StreamingResolutionResultBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.store.ResolutionResultsStoreFactory;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.store.StoreSet;
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
-import org.gradle.api.internal.cache.BinaryStore;
-import org.gradle.api.internal.cache.Store;
-import org.gradle.internal.Factory;
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
-import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
-import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-
-public class DefaultDependencyResolver implements ArtifactDependencyResolver {
- private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDependencyResolver.class);
- private final LocalComponentFactory localComponentFactory;
- private final DependencyDescriptorFactory dependencyDescriptorFactory;
- private final ResolveIvyFactory ivyFactory;
- private final ProjectComponentRegistry projectComponentRegistry;
- private final CacheLockingManager cacheLockingManager;
- private final IvyContextManager ivyContextManager;
- private final ResolutionResultsStoreFactory storeFactory;
- private final VersionComparator versionComparator;
- private final boolean buildProjectDependencies;
-
- public DefaultDependencyResolver(ResolveIvyFactory ivyFactory, LocalComponentFactory localComponentFactory, DependencyDescriptorFactory dependencyDescriptorFactory,
- ProjectComponentRegistry projectComponentRegistry, CacheLockingManager cacheLockingManager, IvyContextManager ivyContextManager,
- ResolutionResultsStoreFactory storeFactory, VersionComparator versionComparator, boolean buildProjectDependencies) {
- this.ivyFactory = ivyFactory;
- this.localComponentFactory = localComponentFactory;
- this.dependencyDescriptorFactory = dependencyDescriptorFactory;
- this.projectComponentRegistry = projectComponentRegistry;
- this.cacheLockingManager = cacheLockingManager;
- this.ivyContextManager = ivyContextManager;
- this.storeFactory = storeFactory;
- this.versionComparator = versionComparator;
- this.buildProjectDependencies = buildProjectDependencies;
- }
-
- public void resolve(final ResolveContext resolveContext,
- final List<? extends ResolutionAwareRepository> repositories,
- final GlobalDependencyResolutionRules metadataHandler,
- final ResolverResults results) throws ResolveException {
- LOGGER.debug("Resolving {}", resolveContext);
- ivyContextManager.withIvy(new Action<Ivy>() {
- public void execute(Ivy ivy) {
- ResolutionStrategyInternal resolutionStrategy;
- if (resolveContext instanceof ConfigurationInternal) {
- resolutionStrategy =((ConfigurationInternal) resolveContext).getResolutionStrategy();
- } else {
- resolutionStrategy = new DefaultResolutionStrategy();
- }
- RepositoryChain repositoryChain = ivyFactory.create(resolutionStrategy, repositories, metadataHandler.getComponentMetadataProcessor());
-
- ComponentMetaDataResolver metaDataResolver = new ClientModuleResolver(repositoryChain.getComponentResolver(), dependencyDescriptorFactory);
- ProjectDependencyResolver projectDependencyResolver;
- if (resolveContext instanceof ResolveContextInternal) {
- projectDependencyResolver = ((ResolveContextInternal) resolveContext).newProjectDependencyResolver(projectComponentRegistry, localComponentFactory, repositoryChain.getComponentIdResolver(), metaDataResolver);
- } else {
- projectDependencyResolver = new ProjectDependencyResolver(projectComponentRegistry, localComponentFactory, repositoryChain.getComponentIdResolver(), metaDataResolver);
- }
- DependencyToComponentIdResolver idResolver = new DependencySubstitutionResolver(projectDependencyResolver, resolutionStrategy.getDependencySubstitutionRule());
-
- ArtifactResolver artifactResolver = createArtifactResolver(repositoryChain);
-
- ModuleConflictResolver conflictResolver;
- if (resolutionStrategy.getConflictResolution() instanceof StrictConflictResolution) {
- conflictResolver = new StrictConflictResolver();
- } else {
- conflictResolver = new LatestModuleConflictResolver(versionComparator);
- }
- conflictResolver = new VersionSelectionReasonResolver(conflictResolver);
- ConflictHandler conflictHandler = new DefaultConflictHandler(conflictResolver, metadataHandler.getModuleMetadataProcessor().getModuleReplacements());
-
- DependencyGraphBuilder builder = new DependencyGraphBuilder(idResolver, projectDependencyResolver, projectDependencyResolver, artifactResolver, conflictHandler, new DefaultDependencyToConfigurationResolver());
-
- StoreSet stores = storeFactory.createStoreSet();
-
- BinaryStore newModelStore = stores.nextBinaryStore();
- Store<ResolvedComponentResult> newModelCache = stores.oldModelStore();
- ResolutionResultBuilder newModelBuilder = new StreamingResolutionResultBuilder(newModelStore, newModelCache);
-
- BinaryStore oldModelStore = stores.nextBinaryStore();
- Store<TransientConfigurationResults> oldModelCache = stores.newModelStore();
- TransientConfigurationResultsBuilder oldTransientModelBuilder = new TransientConfigurationResultsBuilder(oldModelStore, oldModelCache);
- DefaultResolvedConfigurationBuilder oldModelBuilder = new DefaultResolvedConfigurationBuilder(oldTransientModelBuilder);
- DefaultResolvedArtifactsBuilder artifactsBuilder = new DefaultResolvedArtifactsBuilder();
- ResolvedProjectConfigurationResultBuilder projectModelBuilder = new DefaultResolvedProjectConfigurationResultBuilder(buildProjectDependencies);
-
- // Resolve the dependency graph
- builder.resolve(resolveContext, newModelBuilder, oldModelBuilder, artifactsBuilder, projectModelBuilder);
- results.resolved(newModelBuilder.complete(), projectModelBuilder.complete());
-
- ResolvedGraphResults graphResults = oldModelBuilder.complete();
- results.retainState(graphResults, artifactsBuilder, oldTransientModelBuilder);
- }
- });
- }
-
- public void resolveArtifacts(final ResolveContext resolveContext,
- final List<? extends ResolutionAwareRepository> repositories,
- final GlobalDependencyResolutionRules metadataHandler,
- final ResolverResults results) throws ResolveException {
- // TODO:DAZ Should not be holding onto all of this state
- ResolvedGraphResults graphResults = results.getGraphResults();
-
- ResolvedArtifactResults artifactResults = results.getArtifactsBuilder().resolve();
-
- Factory<TransientConfigurationResults> transientConfigurationResultsFactory = new TransientConfigurationResultsLoader(results.getTransientConfigurationResultsBuilder(), graphResults, artifactResults);
-
- DefaultLenientConfiguration result = new DefaultLenientConfiguration(
- (Configuration) resolveContext, cacheLockingManager, graphResults, artifactResults, transientConfigurationResultsFactory);
- results.withResolvedConfiguration(new DefaultResolvedConfiguration(result));
- }
-
- private ArtifactResolver createArtifactResolver(RepositoryChain repositoryChain) {
- ArtifactResolver artifactResolver = repositoryChain.getArtifactResolver();
- artifactResolver = new ProjectArtifactResolver(artifactResolver);
- artifactResolver = new ContextualArtifactResolver(cacheLockingManager, ivyContextManager, artifactResolver);
- artifactResolver = new ErrorHandlingArtifactResolver(artifactResolver);
- return artifactResolver;
- }
-
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ArtifactSet.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ArtifactSet.java
new file mode 100644
index 0000000..6cc21c2
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ArtifactSet.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import org.gradle.api.artifacts.ResolvedArtifact;
+
+import java.util.Set;
+
+public interface ArtifactSet {
+
+ long getId();
+
+ Set<ResolvedArtifact> getArtifacts();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultArtifactSet.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultArtifactSet.java
new file mode 100644
index 0000000..aa39354
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultArtifactSet.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.ResolvedArtifact;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
+import org.gradle.api.internal.artifacts.DefaultResolvedArtifact;
+import org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.ModuleResolutionFilter;
+import org.gradle.internal.Factory;
+import org.gradle.internal.component.model.ComponentArtifactMetaData;
+import org.gradle.internal.component.model.IvyArtifactName;
+import org.gradle.internal.component.model.ModuleSource;
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.result.DefaultBuildableArtifactResolveResult;
+
+import java.io.File;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class DefaultArtifactSet implements ArtifactSet {
+ private final ModuleVersionIdentifier moduleVersionIdentifier;
+ private final ModuleSource moduleSource;
+ private final ModuleResolutionFilter selector;
+ private final ArtifactResolver artifactResolver;
+ private final Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts;
+ private final long id;
+ private final Set<ComponentArtifactMetaData> artifacts;
+
+ public DefaultArtifactSet(ModuleVersionIdentifier ownerId, ModuleSource moduleSource, ModuleResolutionFilter selector, Set<ComponentArtifactMetaData> artifacts,
+ ArtifactResolver artifactResolver, Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts, long id) {
+ this.moduleVersionIdentifier = ownerId;
+ this.moduleSource = moduleSource;
+ this.selector = selector;
+ this.artifacts = artifacts;
+ this.artifactResolver = artifactResolver;
+ this.allResolvedArtifacts = allResolvedArtifacts;
+ this.id = id;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public Set<ResolvedArtifact> getArtifacts() {
+ Set<ResolvedArtifact> resolvedArtifacts = new LinkedHashSet<ResolvedArtifact>(artifacts.size());
+ for (ComponentArtifactMetaData artifact : artifacts) {
+ IvyArtifactName artifactName = artifact.getName();
+ if (!selector.acceptArtifact(moduleVersionIdentifier.getModule(), artifactName)) {
+ continue;
+ }
+
+ ResolvedArtifact resolvedArtifact = allResolvedArtifacts.get(artifact.getId());
+ if (resolvedArtifact == null) {
+ Factory<File> artifactSource = new LazyArtifactSource(artifact, moduleSource, artifactResolver);
+ resolvedArtifact = new DefaultResolvedArtifact(new DefaultResolvedModuleVersion(moduleVersionIdentifier), artifactName, artifact.getId(), artifactSource);
+ allResolvedArtifacts.put(artifact.getId(), resolvedArtifact);
+ }
+ resolvedArtifacts.add(resolvedArtifact);
+ }
+ return resolvedArtifacts;
+ }
+
+ private static class LazyArtifactSource implements Factory<File> {
+ private final ArtifactResolver artifactResolver;
+ private final ModuleSource moduleSource;
+ private final ComponentArtifactMetaData artifact;
+
+ private LazyArtifactSource(ComponentArtifactMetaData artifact, ModuleSource moduleSource, ArtifactResolver artifactResolver) {
+ this.artifact = artifact;
+ this.artifactResolver = artifactResolver;
+ this.moduleSource = moduleSource;
+ }
+
+ public File create() {
+ DefaultBuildableArtifactResolveResult result = new DefaultBuildableArtifactResolveResult();
+ artifactResolver.resolveArtifact(artifact, moduleSource, result);
+ return result.getFile();
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultResolvedArtifactResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultResolvedArtifactResults.java
new file mode 100644
index 0000000..b767d35
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultResolvedArtifactResults.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import com.google.common.collect.Maps;
+import org.gradle.api.artifacts.ResolvedArtifact;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class DefaultResolvedArtifactResults implements ResolvedArtifactResults {
+ // Transient state: held between resolving graph and resolving actual artifacts
+ private Map<Long, ArtifactSet> artifactSets = Maps.newLinkedHashMap();
+
+ // Artifact State : held for the life of a build
+ private Set<ResolvedArtifact> artifacts;
+ private Map<Long, Set<ResolvedArtifact>> resolvedArtifactsById;
+
+ @Override
+ public Set<ResolvedArtifact> getArtifacts() {
+ assertArtifactsResolved();
+ return new LinkedHashSet<ResolvedArtifact>(artifacts);
+ }
+
+ @Override
+ public Set<ResolvedArtifact> getArtifacts(long id) {
+ assertArtifactsResolved();
+ Set<ResolvedArtifact> a = resolvedArtifactsById.get(id);
+ assert a != null : "Unable to find artifacts for id: " + id;
+ return a;
+ }
+
+ public void addArtifactSet(ArtifactSet artifactSet) {
+ artifactSets.put(artifactSet.getId(), artifactSet);
+ }
+
+ public void resolveNow() {
+ if (artifacts == null) {
+ artifacts = new LinkedHashSet<ResolvedArtifact>();
+ resolvedArtifactsById = new LinkedHashMap<Long, Set<ResolvedArtifact>>();
+ for (Map.Entry<Long, ArtifactSet> entry : artifactSets.entrySet()) {
+ Set<ResolvedArtifact> resolvedArtifacts = entry.getValue().getArtifacts();
+ artifacts.addAll(resolvedArtifacts);
+ resolvedArtifactsById.put(entry.getKey(), resolvedArtifacts);
+ }
+
+ // Release ResolvedArtifactSet instances so we're not holding onto state
+ artifactSets = null;
+ }
+ }
+
+ private void assertArtifactsResolved() {
+ if (artifacts == null) {
+ throw new IllegalStateException("Cannot access artifacts before they are explicitly resolved.");
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultResolvedArtifactsBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultResolvedArtifactsBuilder.java
new file mode 100644
index 0000000..f5217bb
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DefaultResolvedArtifactsBuilder.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+
+public class DefaultResolvedArtifactsBuilder implements ResolvedArtifactsBuilder {
+ private final DefaultResolvedArtifactResults artifactResults = new DefaultResolvedArtifactResults();
+
+ public void visitArtifacts(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, ArtifactSet artifactSet) {
+ artifactResults.addArtifactSet(artifactSet);
+ }
+
+ @Override
+ public void finishArtifacts() {
+
+ }
+
+ @Override
+ public ResolvedArtifactResults resolve() {
+ artifactResults.resolveNow();
+ return artifactResults;
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DependencyArtifactsVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DependencyArtifactsVisitor.java
new file mode 100644
index 0000000..2276fc6
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/DependencyArtifactsVisitor.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+
+public interface DependencyArtifactsVisitor {
+ void visitArtifacts(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, ArtifactSet artifacts);
+ void finishArtifacts();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactResults.java
new file mode 100644
index 0000000..5befe32
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactResults.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import org.gradle.api.artifacts.ResolvedArtifact;
+
+import java.util.Set;
+
+public interface ResolvedArtifactResults extends ResolvedArtifacts {
+ Set<ResolvedArtifact> getArtifacts(long id);
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifacts.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifacts.java
new file mode 100644
index 0000000..e759b40
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifacts.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import org.gradle.api.artifacts.ResolvedArtifact;
+
+import java.util.Set;
+
+public interface ResolvedArtifacts {
+ Set<ResolvedArtifact> getArtifacts();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactsBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactsBuilder.java
new file mode 100644
index 0000000..a809096
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactsBuilder.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+public interface ResolvedArtifactsBuilder extends DependencyArtifactsVisitor {
+ ResolvedArtifactResults resolve();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactsGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactsGraphVisitor.java
new file mode 100644
index 0000000..ca8cb6e
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/artifact/ResolvedArtifactsGraphVisitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact;
+
+import com.google.common.collect.Maps;
+import org.gradle.api.artifacts.ResolvedArtifact;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
+import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultModuleResolutionFilter;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphEdge;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphNode;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+import org.gradle.internal.component.model.ComponentArtifactMetaData;
+import org.gradle.internal.component.model.ComponentResolveMetaData;
+import org.gradle.internal.component.model.ConfigurationMetaData;
+import org.gradle.internal.component.model.DefaultComponentUsage;
+import org.gradle.internal.id.IdGenerator;
+import org.gradle.internal.id.LongIdGenerator;
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
+import org.gradle.internal.resolve.result.DefaultBuildableArtifactSetResolveResult;
+
+import java.util.Map;
+import java.util.Set;
+
+public class ResolvedArtifactsGraphVisitor implements DependencyGraphVisitor {
+ private final IdGenerator<Long> idGenerator = new LongIdGenerator();
+ private final Map<ResolvedConfigurationIdentifier, ArtifactSet> artifactSetsByConfiguration = Maps.newHashMap();
+ private final Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts = Maps.newHashMap();
+ private final ArtifactResolver artifactResolver;
+
+ private final DependencyArtifactsVisitor artifactResults;
+
+ public ResolvedArtifactsGraphVisitor(DependencyArtifactsVisitor artifactsBuilder, ArtifactResolver artifactResolver) {
+ this.artifactResults = artifactsBuilder;
+ this.artifactResolver = artifactResolver;
+ }
+
+ @Override
+ public void start(DependencyGraphNode root) {
+
+ }
+
+ @Override
+ public void visitNode(DependencyGraphNode resolvedConfiguration) {
+
+ }
+
+ public void visitEdge(DependencyGraphNode resolvedConfiguration) {
+ for (DependencyGraphEdge dependency : resolvedConfiguration.getIncomingEdges()) {
+ ResolvedConfigurationIdentifier parent = dependency.getFrom().getNodeId();
+ ResolvedConfigurationIdentifier child = resolvedConfiguration.getNodeId();
+
+ ArtifactSet artifacts = getArtifacts(dependency, resolvedConfiguration);
+ artifactResults.visitArtifacts(parent, child, artifacts);
+ }
+ }
+
+ public void finish(DependencyGraphNode root) {
+ artifactResults.finishArtifacts();
+ allResolvedArtifacts.clear();
+ artifactSetsByConfiguration.clear();
+ }
+
+ private ArtifactSet getArtifacts(DependencyGraphEdge dependency, DependencyGraphNode childConfiguration) {
+ long id = idGenerator.generateId();
+ ResolvedConfigurationIdentifier configurationIdentifier = childConfiguration.getNodeId();
+ ConfigurationMetaData metaData = childConfiguration.getMetaData();
+ ComponentResolveMetaData component = metaData.getComponent();
+
+ Set<ComponentArtifactMetaData> artifacts = dependency.getArtifacts(metaData);
+ if (!artifacts.isEmpty()) {
+ return new DefaultArtifactSet(component.getId(), component.getSource(), DefaultModuleResolutionFilter.all(), artifacts, artifactResolver, allResolvedArtifacts, id);
+ }
+
+ ArtifactSet configurationArtifactSet = artifactSetsByConfiguration.get(configurationIdentifier);
+ if (configurationArtifactSet == null) {
+ artifacts = doResolve(component, configurationIdentifier);
+
+ configurationArtifactSet = new DefaultArtifactSet(component.getId(), component.getSource(), dependency.getSelector(), artifacts, artifactResolver, allResolvedArtifacts, id);
+
+ // Only share an ArtifactSet if the artifacts are not filtered by the dependency
+ if (dependency.getSelector().acceptsAllArtifacts()) {
+ artifactSetsByConfiguration.put(configurationIdentifier, configurationArtifactSet);
+ }
+ }
+
+ return configurationArtifactSet;
+ }
+
+
+ private Set<ComponentArtifactMetaData> doResolve(ComponentResolveMetaData component, ResolvedConfigurationIdentifier configurationId) {
+ BuildableArtifactSetResolveResult result = new DefaultBuildableArtifactSetResolveResult();
+ artifactResolver.resolveModuleArtifacts(component, new DefaultComponentUsage(configurationId.getConfiguration()), result);
+ return result.getArtifacts();
+ }
+
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/AbstractArtifactSet.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/AbstractArtifactSet.java
deleted file mode 100644
index a428029..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/AbstractArtifactSet.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-
-import org.gradle.api.artifacts.ModuleVersionIdentifier;
-import org.gradle.api.artifacts.ResolvedArtifact;
-import org.gradle.api.internal.artifacts.DefaultResolvedArtifact;
-import org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.ModuleResolutionFilter;
-import org.gradle.internal.Factory;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
-import org.gradle.internal.component.model.ComponentArtifactMetaData;
-import org.gradle.internal.component.model.IvyArtifactName;
-import org.gradle.internal.component.model.ModuleSource;
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
-import org.gradle.internal.resolve.result.DefaultBuildableArtifactResolveResult;
-
-import java.io.File;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-public abstract class AbstractArtifactSet implements ArtifactSet {
- private final ModuleVersionIdentifier moduleVersionIdentifier;
- private final ModuleSource moduleSource;
- private final ModuleResolutionFilter selector;
- private final ArtifactResolver artifactResolver;
- private final Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts;
- private final long id;
-
- public AbstractArtifactSet(ModuleVersionIdentifier ownerId, ModuleSource moduleSource, ModuleResolutionFilter selector, ArtifactResolver artifactResolver,
- Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts, long id) {
- this.moduleVersionIdentifier = ownerId;
- this.moduleSource = moduleSource;
- this.selector = selector;
- this.artifactResolver = artifactResolver;
- this.allResolvedArtifacts = allResolvedArtifacts;
- this.id = id;
- }
-
- public long getId() {
- return id;
- }
-
- public Set<ResolvedArtifact> getArtifacts() {
- Set<ComponentArtifactMetaData> componentArtifacts = resolveComponentArtifacts();
- Set<ResolvedArtifact> resolvedArtifacts = new LinkedHashSet<ResolvedArtifact>(componentArtifacts.size());
- for (ComponentArtifactMetaData artifact : componentArtifacts) {
- IvyArtifactName artifactName = artifact.getName();
- if (!selector.acceptArtifact(moduleVersionIdentifier.getModule(), artifactName)) {
- continue;
- }
-
- ResolvedArtifact resolvedArtifact = allResolvedArtifacts.get(artifact.getId());
- if (resolvedArtifact == null) {
- Factory<File> artifactSource = new LazyArtifactSource(artifact, moduleSource, artifactResolver);
- resolvedArtifact = new DefaultResolvedArtifact(new DefaultResolvedModuleVersion(moduleVersionIdentifier), artifactName, artifactSource);
- allResolvedArtifacts.put(artifact.getId(), resolvedArtifact);
- }
- resolvedArtifacts.add(resolvedArtifact);
- }
- return resolvedArtifacts;
- }
-
- protected ArtifactResolver getArtifactResolver() {
- return artifactResolver;
- }
-
- protected abstract Set<ComponentArtifactMetaData> resolveComponentArtifacts();
-
- private static class LazyArtifactSource implements Factory<File> {
- private final ArtifactResolver artifactResolver;
- private final ModuleSource moduleSource;
- private final ComponentArtifactMetaData artifact;
-
- private LazyArtifactSource(ComponentArtifactMetaData artifact, ModuleSource moduleSource, ArtifactResolver artifactResolver) {
- this.artifact = artifact;
- this.artifactResolver = artifactResolver;
- this.moduleSource = moduleSource;
- }
-
- public File create() {
- DefaultBuildableArtifactResolveResult result = new DefaultBuildableArtifactResolveResult();
- artifactResolver.resolveArtifact(artifact, moduleSource, result);
- return result.getFile();
- }
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ArtifactSet.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ArtifactSet.java
deleted file mode 100644
index 63a7b95..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ArtifactSet.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-
-import org.gradle.api.artifacts.ResolvedArtifact;
-
-import java.util.Set;
-
-public interface ArtifactSet {
-
- long getId();
-
- Set<ResolvedArtifact> getArtifacts();
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/CompositeDependencyArtifactsVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/CompositeDependencyArtifactsVisitor.java
new file mode 100644
index 0000000..d82fabf
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/CompositeDependencyArtifactsVisitor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
+
+import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ArtifactSet;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class CompositeDependencyArtifactsVisitor implements DependencyArtifactsVisitor {
+ private final List<DependencyArtifactsVisitor> visitors;
+
+ public CompositeDependencyArtifactsVisitor(DependencyArtifactsVisitor... visitors) {
+ this.visitors = Arrays.asList(visitors);
+ }
+
+ @Override
+ public void visitArtifacts(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, ArtifactSet artifacts) {
+ for (DependencyArtifactsVisitor visitor : visitors) {
+ visitor.visitArtifacts(parent, child, artifacts);
+ }
+ }
+
+ @Override
+ public void finishArtifacts() {
+ for (DependencyArtifactsVisitor visitor : visitors) {
+ visitor.finishArtifacts();
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/CompositeDependencyGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/CompositeDependencyGraphVisitor.java
index 851041e..36a8f60 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/CompositeDependencyGraphVisitor.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/CompositeDependencyGraphVisitor.java
@@ -19,32 +19,32 @@ package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
import java.util.Arrays;
import java.util.List;
-class CompositeDependencyGraphVisitor implements DependencyGraphVisitor {
+public class CompositeDependencyGraphVisitor implements DependencyGraphVisitor {
private final List<DependencyGraphVisitor> visitors;
- CompositeDependencyGraphVisitor(DependencyGraphVisitor... visitors) {
+ public CompositeDependencyGraphVisitor(DependencyGraphVisitor... visitors) {
this.visitors = Arrays.asList(visitors);
}
- public void start(DependencyGraphBuilder.ConfigurationNode root) {
+ public void start(DependencyGraphNode root) {
for (DependencyGraphVisitor visitor : visitors) {
visitor.start(root);
}
}
- public void visitNode(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
+ public void visitNode(DependencyGraphNode resolvedConfiguration) {
for (DependencyGraphVisitor visitor : visitors) {
visitor.visitNode(resolvedConfiguration);
}
}
- public void visitEdge(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
+ public void visitEdge(DependencyGraphNode resolvedConfiguration) {
for (DependencyGraphVisitor visitor : visitors) {
visitor.visitEdge(resolvedConfiguration);
}
}
- public void finish(DependencyGraphBuilder.ConfigurationNode root) {
+ public void finish(DependencyGraphNode root) {
for (DependencyGraphVisitor visitor : visitors) {
visitor.finish(root);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ConfigurationArtifactSet.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ConfigurationArtifactSet.java
deleted file mode 100644
index 96371b6..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ConfigurationArtifactSet.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-
-import org.gradle.api.artifacts.ResolvedArtifact;
-import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.ModuleResolutionFilter;
-import org.gradle.internal.component.model.*;
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
-import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
-import org.gradle.internal.resolve.result.DefaultBuildableArtifactSetResolveResult;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * An ArtifactSet that resolves the artifacts for a configuration.
- */
-class ConfigurationArtifactSet extends AbstractArtifactSet {
- private final Set<ComponentArtifactMetaData> artifacts;
-
- public ConfigurationArtifactSet(ComponentResolveMetaData component, ResolvedConfigurationIdentifier configurationId, ModuleResolutionFilter selector,
- ArtifactResolver artifactResolver, Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts,
- long id) {
- super(component.getId(), component.getSource(), selector, artifactResolver, allResolvedArtifacts, id);
- this.artifacts = doResolve(component, configurationId);
- }
-
- private Set<ComponentArtifactMetaData> doResolve(ComponentResolveMetaData component, ResolvedConfigurationIdentifier configurationId) {
- BuildableArtifactSetResolveResult result = new DefaultBuildableArtifactSetResolveResult();
- getArtifactResolver().resolveModuleArtifacts(component, new DefaultComponentUsage(configurationId.getConfiguration()), result);
- return result.getArtifacts();
- }
-
- @Override
- protected Set<ComponentArtifactMetaData> resolveComponentArtifacts() {
- return artifacts;
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyArtifactSet.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyArtifactSet.java
deleted file mode 100644
index fffdd7d..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyArtifactSet.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-
-import org.gradle.api.artifacts.ModuleVersionIdentifier;
-import org.gradle.api.artifacts.ResolvedArtifact;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultModuleResolutionFilter;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
-import org.gradle.internal.component.model.ComponentArtifactMetaData;
-import org.gradle.internal.component.model.ModuleSource;
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A set of artifacts that is defined by a dependency declaration.
- */
-class DependencyArtifactSet extends AbstractArtifactSet {
- private final Set<ComponentArtifactMetaData> artifacts;
-
- public DependencyArtifactSet(ModuleVersionIdentifier ownerId, ModuleSource moduleSource, Set<ComponentArtifactMetaData> artifacts,
- ArtifactResolver artifactResolver, Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts,
- long id) {
- super(ownerId, moduleSource, DefaultModuleResolutionFilter.all(), artifactResolver, allResolvedArtifacts, id);
- this.artifacts = artifacts;
- }
-
- @Override
- protected Set<ComponentArtifactMetaData> resolveComponentArtifacts() {
- return artifacts;
- }
-
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphBuilder.java
index 27d7bfb..cb3a6db 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphBuilder.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphBuilder.java
@@ -17,28 +17,27 @@ package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
import com.google.common.base.Joiner;
import org.gradle.api.Action;
-import org.gradle.api.artifacts.*;
+import org.gradle.api.artifacts.ModuleDependency;
+import org.gradle.api.artifacts.ModuleIdentifier;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.ModuleVersionSelector;
import org.gradle.api.artifacts.component.ComponentIdentifier;
import org.gradle.api.artifacts.component.ComponentSelector;
import org.gradle.api.artifacts.result.ComponentSelectionReason;
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier;
+import org.gradle.api.internal.artifacts.ResolveContext;
import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.*;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.CandidateModule;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.ConflictHandler;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.ConflictResolutionResult;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.PotentialConflict;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedArtifactsBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedConfigurationBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResultBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.InternalDependencyResult;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ModuleVersionSelection;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ResolutionResultBuilder;
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.VersionSelectionReasons;
+import org.gradle.internal.Cast;
import org.gradle.internal.component.local.model.DslOriginDependencyMetaData;
import org.gradle.internal.component.model.*;
import org.gradle.internal.resolve.ModuleVersionResolveException;
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
import org.gradle.internal.resolve.resolver.ResolveContextToComponentResolver;
@@ -53,38 +52,20 @@ public class DependencyGraphBuilder {
private final DependencyToConfigurationResolver dependencyToConfigurationResolver;
private final ConflictHandler conflictHandler;
private final ResolveContextToComponentResolver moduleResolver;
- private final ArtifactResolver artifactResolver;
private final DependencyToComponentIdResolver idResolver;
private final ComponentMetaDataResolver metaDataResolver;
- public DependencyGraphBuilder(DependencyToComponentIdResolver idResolver,
- ComponentMetaDataResolver metaDataResolver,
- ResolveContextToComponentResolver moduleResolver,
- ArtifactResolver artifactResolver,
- ConflictHandler conflictHandler,
- DependencyToConfigurationResolver dependencyToConfigurationResolver) {
- this.idResolver = idResolver;
- this.metaDataResolver = metaDataResolver;
- this.moduleResolver = moduleResolver;
- this.artifactResolver = artifactResolver;
+ public DependencyGraphBuilder(DependencyToComponentIdResolver componentIdResolver, ComponentMetaDataResolver componentMetaDataResolver,
+ ResolveContextToComponentResolver resolveContextToComponentResolver, DependencyToConfigurationResolver dependencyToConfigurationResolver,
+ ConflictHandler conflictHandler) {
+ this.idResolver = componentIdResolver;
+ this.metaDataResolver = componentMetaDataResolver;
+ this.moduleResolver = resolveContextToComponentResolver;
this.conflictHandler = conflictHandler;
this.dependencyToConfigurationResolver = dependencyToConfigurationResolver;
}
- public void resolve(ResolveContext resolveContext,
- ResolutionResultBuilder newModelBuilder,
- ResolvedConfigurationBuilder oldModelBuilder,
- ResolvedArtifactsBuilder artifactsBuilder,
- ResolvedProjectConfigurationResultBuilder projectModelBuilder) throws ResolveException {
- DependencyGraphVisitor oldModelVisitor = new ResolvedConfigurationDependencyGraphVisitor(oldModelBuilder, artifactsBuilder, artifactResolver);
- DependencyGraphVisitor newModelVisitor = new ResolutionResultDependencyGraphVisitor(newModelBuilder);
- DependencyGraphVisitor projectModelVisitor = new ResolvedProjectConfigurationResultGraphVisitor(projectModelBuilder);
- DependencyGraphVisitor modelVisitor = new CompositeDependencyGraphVisitor(oldModelVisitor, newModelVisitor, projectModelVisitor);
-
- resolveDependencyGraph(resolveContext, modelVisitor);
- }
-
- private void resolveDependencyGraph(ResolveContext resolveContext, DependencyGraphVisitor modelVisitor) {
+ public void resolve(ResolveContext resolveContext, DependencyGraphVisitor modelVisitor) {
DefaultBuildableComponentResolveResult rootModule = new DefaultBuildableComponentResolveResult();
moduleResolver.resolve(resolveContext, rootModule);
@@ -199,7 +180,7 @@ public class DependencyGraphBuilder {
/**
* Represents the edges in the dependency graph.
*/
- static class DependencyEdge implements InternalDependencyResult {
+ private static class DependencyEdge implements DependencyGraphEdge {
public final ConfigurationNode from;
public final ModuleVersionSelectorResolveState selector;
@@ -222,6 +203,11 @@ public class DependencyGraphBuilder {
return String.format("%s -> %s(%s)", from.toString(), dependencyMetaData.getRequested(), Joiner.on(',').join(dependencyMetaData.getModuleConfigurations()));
}
+ @Override
+ public DependencyGraphNode getFrom() {
+ return from;
+ }
+
/**
* @return The resolved module version
*/
@@ -290,7 +276,6 @@ public class DependencyGraphBuilder {
return dependencyMetaData.getSelector();
}
- // TODO This should be replaced by getRequested()
public ModuleVersionSelector getRequestedModuleVersion() {
return dependencyMetaData.getRequested();
}
@@ -510,7 +495,7 @@ public class DependencyGraphBuilder {
/**
* Resolution state for a given module version.
*/
- static class ModuleVersionResolveState implements ComponentResolutionState, ModuleVersionSelection {
+ public static class ModuleVersionResolveState implements ComponentResolutionState, ModuleVersionSelection {
public final ModuleVersionIdentifier id;
private final ComponentMetaDataResolver resolver;
private final Set<ConfigurationNode> configurations = new LinkedHashSet<ConfigurationNode>();
@@ -622,7 +607,7 @@ public class DependencyGraphBuilder {
/**
* Represents a node in the dependency graph.
*/
- static class ConfigurationNode {
+ static class ConfigurationNode implements DependencyGraphNode {
public final ModuleVersionResolveState moduleRevision;
public final Set<DependencyEdge> incomingEdges = new LinkedHashSet<DependencyEdge>();
public final Set<DependencyEdge> outgoingEdges = new LinkedHashSet<DependencyEdge>();
@@ -640,15 +625,37 @@ public class DependencyGraphBuilder {
moduleRevision.addConfiguration(this);
}
+ @Override
+ public ResolvedConfigurationIdentifier getNodeId() {
+ return id;
+ }
+
+ @Override
public ModuleVersionIdentifier toId() {
return moduleRevision.id;
}
+ @Override
public ComponentIdentifier getComponentId() {
return moduleRevision.getComponentId();
}
- // TODO:DAZ Need to get rid of this
+ @Override
+ public ModuleVersionSelection getSelection() {
+ return moduleRevision;
+ }
+
+ @Override
+ public Set<DependencyGraphEdge> getIncomingEdges() {
+ return Cast.uncheckedCast(incomingEdges);
+ }
+
+ @Override
+ public Set<DependencyGraphEdge> getOutgoingEdges() {
+ return Cast.uncheckedCast(outgoingEdges);
+ }
+
+ @Override
public ConfigurationMetaData getMetaData() {
return metaData;
}
@@ -694,7 +701,7 @@ public class DependencyGraphBuilder {
return;
}
- ModuleResolutionFilter resolutionFilter = getSelector(transitiveIncoming);
+ ModuleResolutionFilter resolutionFilter = getModuleResolutionFilter(transitiveIncoming);
if (previousTraversal != null) {
if (previousTraversal.acceptsSameModulesAs(resolutionFilter)) {
LOGGER.debug("Changed edges for {} selects same versions as previous traversal. ignoring", this);
@@ -740,7 +747,7 @@ public class DependencyGraphBuilder {
return moduleRevision.state == ModuleState.Selected;
}
- private ModuleResolutionFilter getSelector(List<DependencyEdge> transitiveEdges) {
+ private ModuleResolutionFilter getModuleResolutionFilter(List<DependencyEdge> transitiveEdges) {
ModuleResolutionFilter resolutionFilter;
if (transitiveEdges.isEmpty()) {
resolutionFilter = DefaultModuleResolutionFilter.all();
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphEdge.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphEdge.java
new file mode 100644
index 0000000..fa61b4c
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphEdge.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
+
+import org.gradle.api.artifacts.ModuleDependency;
+import org.gradle.api.artifacts.ModuleVersionSelector;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.ModuleResolutionFilter;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.InternalDependencyResult;
+import org.gradle.internal.component.model.ComponentArtifactMetaData;
+import org.gradle.internal.component.model.ConfigurationMetaData;
+
+import java.util.Set;
+
+public interface DependencyGraphEdge extends InternalDependencyResult {
+ DependencyGraphNode getFrom();
+
+ // TODO This should be replaced by getRequested()
+ ModuleVersionSelector getRequestedModuleVersion();
+
+ ModuleResolutionFilter getSelector();
+
+ Set<ComponentArtifactMetaData> getArtifacts(ConfigurationMetaData metaData);
+
+ ModuleDependency getModuleDependency();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphNode.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphNode.java
new file mode 100644
index 0000000..e975dde
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphNode.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
+
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ModuleVersionSelection;
+import org.gradle.internal.component.model.ConfigurationMetaData;
+
+import java.util.Set;
+
+public interface DependencyGraphNode {
+ ResolvedConfigurationIdentifier getNodeId();
+
+ ModuleVersionIdentifier toId();
+
+ ComponentIdentifier getComponentId();
+
+ ModuleVersionSelection getSelection();
+
+ Set<DependencyGraphEdge> getIncomingEdges();
+
+ Set<DependencyGraphEdge> getOutgoingEdges();
+
+ ConfigurationMetaData getMetaData();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphPathResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphPathResolver.java
new file mode 100644
index 0000000..f0e807d
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphPathResolver.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
+
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ModuleVersionSelection;
+
+import java.util.*;
+
+public class DependencyGraphPathResolver {
+
+ public static Collection<List<ModuleVersionIdentifier>> calculatePaths(List<DependencyGraphNode> fromNodes, DependencyGraphNode toNode) {
+ // Include the shortest path from each version that has a direct dependency on the broken dependency, back to the root
+
+ Map<ModuleVersionSelection, List<ModuleVersionIdentifier>> shortestPaths = new LinkedHashMap<ModuleVersionSelection, List<ModuleVersionIdentifier>>();
+ List<ModuleVersionIdentifier> rootPath = new ArrayList<ModuleVersionIdentifier>();
+ rootPath.add(toNode.toId());
+ shortestPaths.put(toNode.getSelection(), rootPath);
+
+ Set<DependencyGraphBuilder.ModuleVersionResolveState> directDependees = new LinkedHashSet<DependencyGraphBuilder.ModuleVersionResolveState>();
+ for (DependencyGraphNode node : fromNodes) {
+ DependencyGraphBuilder.ConfigurationNode rawNode = (DependencyGraphBuilder.ConfigurationNode) node;
+ directDependees.add(rawNode.moduleRevision);
+ }
+
+ Set<DependencyGraphBuilder.ModuleVersionResolveState> seen = new HashSet<DependencyGraphBuilder.ModuleVersionResolveState>();
+ LinkedList<DependencyGraphBuilder.ModuleVersionResolveState> queue = new LinkedList<DependencyGraphBuilder.ModuleVersionResolveState>();
+ queue.addAll(directDependees);
+ while (!queue.isEmpty()) {
+ DependencyGraphBuilder.ModuleVersionResolveState version = queue.getFirst();
+ if (version == toNode.getSelection()) {
+ queue.removeFirst();
+ } else if (seen.add(version)) {
+ for (DependencyGraphBuilder.ModuleVersionResolveState incomingVersion : version.getIncoming()) {
+ queue.add(0, incomingVersion);
+ }
+ } else {
+ queue.remove();
+ List<ModuleVersionIdentifier> shortest = null;
+ for (DependencyGraphBuilder.ModuleVersionResolveState incomingVersion : version.getIncoming()) {
+ List<ModuleVersionIdentifier> candidate = shortestPaths.get(incomingVersion);
+ if (candidate == null) {
+ continue;
+ }
+ if (shortest == null) {
+ shortest = candidate;
+ } else if (shortest.size() > candidate.size()) {
+ shortest = candidate;
+ }
+
+ }
+ if (shortest == null) {
+ continue;
+ }
+ List<ModuleVersionIdentifier> path = new ArrayList<ModuleVersionIdentifier>();
+ path.addAll(shortest);
+ path.add(version.id);
+ shortestPaths.put(version, path);
+ }
+ }
+
+ List<List<ModuleVersionIdentifier>> paths = new ArrayList<List<ModuleVersionIdentifier>>();
+ for (DependencyGraphBuilder.ModuleVersionResolveState version : directDependees) {
+ List<ModuleVersionIdentifier> path = shortestPaths.get(version);
+ paths.add(path);
+ }
+ return paths;
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphVisitor.java
index 1c5e102..0aa573e 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphVisitor.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/DependencyGraphVisitor.java
@@ -16,9 +16,9 @@
package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-interface DependencyGraphVisitor {
- void start(DependencyGraphBuilder.ConfigurationNode root);
- void visitNode(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration);
- void visitEdge(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration);
- void finish(DependencyGraphBuilder.ConfigurationNode root);
+public interface DependencyGraphVisitor {
+ void start(DependencyGraphNode root);
+ void visitNode(DependencyGraphNode resolvedConfiguration);
+ void visitEdge(DependencyGraphNode resolvedConfiguration);
+ void finish(DependencyGraphNode root);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolutionResultDependencyGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolutionResultDependencyGraphVisitor.java
deleted file mode 100644
index 02dc4c3..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolutionResultDependencyGraphVisitor.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ResolutionResultBuilder;
-
-class ResolutionResultDependencyGraphVisitor implements DependencyGraphVisitor {
- private final ResolutionResultBuilder newModelBuilder;
-
- ResolutionResultDependencyGraphVisitor(ResolutionResultBuilder newModelBuilder) {
- this.newModelBuilder = newModelBuilder;
- }
-
- public void start(DependencyGraphBuilder.ConfigurationNode root) {
- newModelBuilder.start(root.toId(), root.getComponentId());
- }
-
- public void visitNode(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
- newModelBuilder.resolvedModuleVersion(resolvedConfiguration.moduleRevision);
- }
-
- public void visitEdge(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
- newModelBuilder.resolvedConfiguration(resolvedConfiguration.toId(), resolvedConfiguration.outgoingEdges);
- }
-
- public void finish(DependencyGraphBuilder.ConfigurationNode root) {
-
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolvedConfigurationDependencyGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolvedConfigurationDependencyGraphVisitor.java
deleted file mode 100644
index 9be9578..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolvedConfigurationDependencyGraphVisitor.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-
-import com.google.common.collect.Maps;
-import org.gradle.api.artifacts.ModuleDependency;
-import org.gradle.api.artifacts.ModuleVersionIdentifier;
-import org.gradle.api.artifacts.ModuleVersionSelector;
-import org.gradle.api.artifacts.ResolvedArtifact;
-import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
-import org.gradle.api.internal.artifacts.ivyservice.DefaultUnresolvedDependency;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedArtifactsBuilder;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.ResolvedConfigurationBuilder;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
-import org.gradle.internal.component.model.ComponentArtifactMetaData;
-import org.gradle.internal.component.model.ComponentResolveMetaData;
-import org.gradle.internal.component.model.ConfigurationMetaData;
-import org.gradle.internal.id.IdGenerator;
-import org.gradle.internal.id.LongIdGenerator;
-import org.gradle.internal.resolve.ModuleVersionResolveException;
-import org.gradle.internal.resolve.resolver.ArtifactResolver;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.*;
-
-class ResolvedConfigurationDependencyGraphVisitor implements DependencyGraphVisitor {
- private static final Logger LOGGER = LoggerFactory.getLogger(ResolvedConfigurationDependencyGraphVisitor.class);
-
- private final IdGenerator<Long> idGenerator = new LongIdGenerator();
- private final ResolvedConfigurationBuilder builder;
- private final ResolvedArtifactsBuilder artifactsBuilder;
- private final ArtifactResolver artifactResolver;
- private final Map<ModuleVersionSelector, BrokenDependency> failuresByRevisionId = new LinkedHashMap<ModuleVersionSelector, BrokenDependency>();
- private final Map<ComponentArtifactIdentifier, ResolvedArtifact> allResolvedArtifacts = Maps.newHashMap();
- private final Map<ResolvedConfigurationIdentifier, ArtifactSet> artifactSetsByConfiguration = Maps.newHashMap();
- private DependencyGraphBuilder.ConfigurationNode root;
-
- ResolvedConfigurationDependencyGraphVisitor(ResolvedConfigurationBuilder builder, ResolvedArtifactsBuilder artifactsBuilder, ArtifactResolver artifactResolver) {
- this.builder = builder;
- this.artifactsBuilder = artifactsBuilder;
- this.artifactResolver = artifactResolver;
- }
-
- public void start(DependencyGraphBuilder.ConfigurationNode root) {
- this.root = root;
- }
-
- public void visitNode(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
- builder.newResolvedDependency(resolvedConfiguration.id);
- for (DependencyGraphBuilder.DependencyEdge dependency : resolvedConfiguration.outgoingEdges) {
- ModuleVersionResolveException failure = dependency.getFailure();
- if (failure != null) {
- addUnresolvedDependency(dependency, dependency.getRequestedModuleVersion(), failure);
- }
- }
- }
-
- public void visitEdge(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
- LOGGER.debug("Attaching {} to its parents.", resolvedConfiguration);
- for (DependencyGraphBuilder.DependencyEdge dependency : resolvedConfiguration.incomingEdges) {
- attachToParents(dependency, resolvedConfiguration);
- }
- }
-
- private void attachToParents(DependencyGraphBuilder.DependencyEdge dependency, DependencyGraphBuilder.ConfigurationNode childConfiguration) {
- ResolvedConfigurationIdentifier parent = dependency.from.id;
- ResolvedConfigurationIdentifier child = childConfiguration.id;
- builder.addChild(parent, child);
-
- ArtifactSet artifacts = getArtifacts(dependency, childConfiguration);
- builder.addArtifacts(child, parent, artifacts.getId());
- artifactsBuilder.addArtifacts(artifacts.getId(), artifacts);
-
- if (parent == root.id) {
- ModuleDependency moduleDependency = dependency.getModuleDependency();
- builder.addFirstLevelDependency(moduleDependency, child);
- }
- }
-
- // TODO:DAZ This is functional, but need to refactor for clarity
- private ArtifactSet getArtifacts(DependencyGraphBuilder.DependencyEdge dependency, DependencyGraphBuilder.ConfigurationNode childConfiguration) {
- long id = idGenerator.generateId();
- ResolvedConfigurationIdentifier configurationIdentifier = childConfiguration.id;
- ConfigurationMetaData metaData = childConfiguration.getMetaData();
- ComponentResolveMetaData component = metaData.getComponent();
-
- Set<ComponentArtifactMetaData> artifacts = dependency.getArtifacts(metaData);
- if (!artifacts.isEmpty()) {
- return new DependencyArtifactSet(component.getId(), component.getSource(), artifacts, artifactResolver, allResolvedArtifacts, id);
- }
-
- ArtifactSet configurationArtifactSet = artifactSetsByConfiguration.get(configurationIdentifier);
- if (configurationArtifactSet == null) {
-
- configurationArtifactSet = new ConfigurationArtifactSet(component, configurationIdentifier, dependency.getSelector(), artifactResolver, allResolvedArtifacts, id);
-
- // Only share an ArtifactSet if the artifacts are not filtered by the dependency
- if (dependency.getSelector().acceptsAllArtifacts()) {
- artifactSetsByConfiguration.put(configurationIdentifier, configurationArtifactSet);
- }
- }
-
- return configurationArtifactSet;
- }
-
- public void finish(DependencyGraphBuilder.ConfigurationNode root) {
- allResolvedArtifacts.clear();
- artifactSetsByConfiguration.clear();
- attachFailures(builder);
- builder.done(root.id);
- }
-
- private void attachFailures(ResolvedConfigurationBuilder result) {
- for (Map.Entry<ModuleVersionSelector, BrokenDependency> entry : failuresByRevisionId.entrySet()) {
- Collection<List<ModuleVersionIdentifier>> paths = calculatePaths(entry.getValue());
- result.addUnresolvedDependency(new DefaultUnresolvedDependency(entry.getKey(), entry.getValue().failure.withIncomingPaths(paths)));
- }
- }
-
- private Collection<List<ModuleVersionIdentifier>> calculatePaths(BrokenDependency brokenDependency) {
- // Include the shortest path from each version that has a direct dependency on the broken dependency, back to the root
-
- Map<DependencyGraphBuilder.ModuleVersionResolveState, List<ModuleVersionIdentifier>> shortestPaths = new LinkedHashMap<DependencyGraphBuilder.ModuleVersionResolveState, List<ModuleVersionIdentifier>>();
- List<ModuleVersionIdentifier> rootPath = new ArrayList<ModuleVersionIdentifier>();
- rootPath.add(root.toId());
- shortestPaths.put(root.moduleRevision, rootPath);
-
- Set<DependencyGraphBuilder.ModuleVersionResolveState> directDependees = new LinkedHashSet<DependencyGraphBuilder.ModuleVersionResolveState>();
- for (DependencyGraphBuilder.ConfigurationNode node : brokenDependency.requiredBy) {
- directDependees.add(node.moduleRevision);
- }
-
- Set<DependencyGraphBuilder.ModuleVersionResolveState> seen = new HashSet<DependencyGraphBuilder.ModuleVersionResolveState>();
- LinkedList<DependencyGraphBuilder.ModuleVersionResolveState> queue = new LinkedList<DependencyGraphBuilder.ModuleVersionResolveState>();
- queue.addAll(directDependees);
- while (!queue.isEmpty()) {
- DependencyGraphBuilder.ModuleVersionResolveState version = queue.getFirst();
- if (version == root.moduleRevision) {
- queue.removeFirst();
- } else if (seen.add(version)) {
- for (DependencyGraphBuilder.ModuleVersionResolveState incomingVersion : version.getIncoming()) {
- queue.add(0, incomingVersion);
- }
- } else {
- queue.remove();
- List<ModuleVersionIdentifier> shortest = null;
- for (DependencyGraphBuilder.ModuleVersionResolveState incomingVersion : version.getIncoming()) {
- List<ModuleVersionIdentifier> candidate = shortestPaths.get(incomingVersion);
- if (candidate == null) {
- continue;
- }
- if (shortest == null) {
- shortest = candidate;
- } else if (shortest.size() > candidate.size()) {
- shortest = candidate;
- }
-
- }
- if (shortest == null) {
- continue;
- }
- List<ModuleVersionIdentifier> path = new ArrayList<ModuleVersionIdentifier>();
- path.addAll(shortest);
- path.add(version.id);
- shortestPaths.put(version, path);
- }
- }
-
- List<List<ModuleVersionIdentifier>> paths = new ArrayList<List<ModuleVersionIdentifier>>();
- for (DependencyGraphBuilder.ModuleVersionResolveState version : directDependees) {
- List<ModuleVersionIdentifier> path = shortestPaths.get(version);
- paths.add(path);
- }
- return paths;
- }
-
- private void addUnresolvedDependency(DependencyGraphBuilder.DependencyEdge dependency, ModuleVersionSelector requested, ModuleVersionResolveException failure) {
- BrokenDependency breakage = failuresByRevisionId.get(requested);
- if (breakage == null) {
- breakage = new BrokenDependency(failure);
- failuresByRevisionId.put(requested, breakage);
- }
- breakage.requiredBy.add(dependency.from);
- }
-
- private static class BrokenDependency {
- final ModuleVersionResolveException failure;
- final List<DependencyGraphBuilder.ConfigurationNode> requiredBy = new ArrayList<DependencyGraphBuilder.ConfigurationNode>();
-
- private BrokenDependency(ModuleVersionResolveException failure) {
- this.failure = failure;
- }
- }
-
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolvedProjectConfigurationResultGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolvedProjectConfigurationResultGraphVisitor.java
deleted file mode 100644
index b49fa9c..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/ResolvedProjectConfigurationResultGraphVisitor.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph;
-
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResultBuilder;
-
-public class ResolvedProjectConfigurationResultGraphVisitor implements DependencyGraphVisitor {
- private final ResolvedProjectConfigurationResultBuilder builder;
-
- public ResolvedProjectConfigurationResultGraphVisitor(ResolvedProjectConfigurationResultBuilder builder) {
- this.builder = builder;
- }
-
- @Override
- public void start(DependencyGraphBuilder.ConfigurationNode root) {
- builder.registerRoot(root.getComponentId());
- }
-
- @Override
- public void visitNode(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
- ComponentIdentifier componentId = resolvedConfiguration.getComponentId();
- if (componentId instanceof ProjectComponentIdentifier) {
- builder.addProjectComponentResult((ProjectComponentIdentifier) componentId, resolvedConfiguration.id.getConfiguration());
- }
- }
-
- @Override
- public void visitEdge(DependencyGraphBuilder.ConfigurationNode resolvedConfiguration) {
- }
-
- @Override
- public void finish(DependencyGraphBuilder.ConfigurationNode root) {
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedArtifactResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedArtifactResults.java
deleted file mode 100644
index c4f9f02..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedArtifactResults.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult;
-
-import com.google.common.collect.Maps;
-import org.gradle.api.artifacts.ResolvedArtifact;
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.ArtifactSet;
-
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class DefaultResolvedArtifactResults implements ResolvedArtifactResults {
- private Map<Long, ArtifactSet> artifactSets = Maps.newHashMap();
- private Set<ResolvedArtifact> artifacts;
- private Map<Long, Set<ResolvedArtifact>> resolvedArtifactsById;
-
- @Override
- public Set<ResolvedArtifact> getArtifacts() {
- assertArtifactsResolved();
- return new LinkedHashSet<ResolvedArtifact>(artifacts);
- }
-
- @Override
- public Set<ResolvedArtifact> getArtifacts(long id) {
- assertArtifactsResolved();
- Set<ResolvedArtifact> a = resolvedArtifactsById.get(id);
- assert a != null : "Unable to find artifacts for id: " + id;
- return a;
- }
-
- public void addArtifactSet(long id, ArtifactSet artifactSet) {
- artifactSets.put(id, artifactSet);
- }
-
- public void resolveNow() {
- if (artifacts == null) {
- artifacts = new LinkedHashSet<ResolvedArtifact>();
- resolvedArtifactsById = new LinkedHashMap<Long, Set<ResolvedArtifact>>();
- for (Map.Entry<Long, ArtifactSet> entry : artifactSets.entrySet()) {
- Set<ResolvedArtifact> resolvedArtifacts = entry.getValue().getArtifacts();
- artifacts.addAll(resolvedArtifacts);
- resolvedArtifactsById.put(entry.getKey(), resolvedArtifacts);
- }
-
- // Release ResolvedArtifactSet instances so we're not holding onto state
- artifactSets = null;
- }
- }
-
- private void assertArtifactsResolved() {
- if (artifacts == null) {
- throw new IllegalStateException("Cannot access artifacts before they are explicitly resolved.");
- }
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedArtifactsBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedArtifactsBuilder.java
deleted file mode 100644
index 3bfa26b..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedArtifactsBuilder.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult;
-
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.ArtifactSet;
-
-public class DefaultResolvedArtifactsBuilder implements ResolvedArtifactsBuilder {
- private final DefaultResolvedArtifactResults artifactResults = new DefaultResolvedArtifactResults();
-
- public void addArtifacts(long id, ArtifactSet artifactSet) {
- artifactResults.addArtifactSet(id, artifactSet);
- }
-
- @Override
- public ResolvedArtifactResults resolve() {
- artifactResults.resolveNow();
- return artifactResults;
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedConfigurationBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedConfigurationBuilder.java
index aca0c39..a082648 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedConfigurationBuilder.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/DefaultResolvedConfigurationBuilder.java
@@ -51,12 +51,8 @@ public class DefaultResolvedConfigurationBuilder implements ResolvedConfiguratio
builder.done(root);
}
- public void addChild(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child) {
- builder.parentChildMapping(parent, child);
- }
-
- public void addArtifacts(ResolvedConfigurationIdentifier child, ResolvedConfigurationIdentifier parent, long artifactSet) {
- builder.parentSpecificArtifacts(child, parent, artifactSet);
+ public void addChild(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, long artifactSet) {
+ builder.parentChildMapping(parent, child, artifactSet);
}
public void newResolvedDependency(ResolvedConfigurationIdentifier id) {
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedArtifactResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedArtifactResults.java
deleted file mode 100644
index f392d57..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedArtifactResults.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult;
-
-import org.gradle.api.artifacts.ResolvedArtifact;
-
-import java.util.Set;
-
-public interface ResolvedArtifactResults {
- void resolveNow();
-
- Set<ResolvedArtifact> getArtifacts();
-
- Set<ResolvedArtifact> getArtifacts(long id);
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedArtifactsBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedArtifactsBuilder.java
deleted file mode 100644
index bd2a8bd..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedArtifactsBuilder.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult;
-
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.ArtifactSet;
-
-public interface ResolvedArtifactsBuilder {
-
- // TODO:DAZ Should have a component id here, instead of relying on an internal id for syncing with graph
- void addArtifacts(long id, ArtifactSet artifacts);
-
- ResolvedArtifactResults resolve();
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedConfigurationBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedConfigurationBuilder.java
index 19007cb..66e6705 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedConfigurationBuilder.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedConfigurationBuilder.java
@@ -26,9 +26,7 @@ public interface ResolvedConfigurationBuilder {
void addUnresolvedDependency(UnresolvedDependency unresolvedDependency);
- void addChild(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child);
-
- void addArtifacts(ResolvedConfigurationIdentifier child, ResolvedConfigurationIdentifier parent, long artifactsId);
+ void addChild(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, long artifactsId);
void newResolvedDependency(ResolvedConfigurationIdentifier id);
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedConfigurationDependencyGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedConfigurationDependencyGraphVisitor.java
new file mode 100644
index 0000000..b215f33
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/ResolvedConfigurationDependencyGraphVisitor.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult;
+
+import org.gradle.api.artifacts.ModuleDependency;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.ModuleVersionSelector;
+import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.DefaultUnresolvedDependency;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ArtifactSet;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphEdge;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphNode;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphPathResolver;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+import org.gradle.internal.resolve.ModuleVersionResolveException;
+
+import java.util.*;
+
+public class ResolvedConfigurationDependencyGraphVisitor implements DependencyGraphVisitor, DependencyArtifactsVisitor {
+
+ private final ResolvedConfigurationBuilder builder;
+ private final Map<ModuleVersionSelector, BrokenDependency> failuresByRevisionId = new LinkedHashMap<ModuleVersionSelector, BrokenDependency>();
+ private DependencyGraphNode root;
+
+ public ResolvedConfigurationDependencyGraphVisitor(ResolvedConfigurationBuilder builder) {
+ this.builder = builder;
+ }
+
+ public void start(DependencyGraphNode root) {
+ this.root = root;
+ }
+
+ public void visitNode(DependencyGraphNode resolvedConfiguration) {
+ builder.newResolvedDependency(resolvedConfiguration.getNodeId());
+ for (DependencyGraphEdge dependency : resolvedConfiguration.getOutgoingEdges()) {
+ ModuleVersionResolveException failure = dependency.getFailure();
+ if (failure != null) {
+ addUnresolvedDependency(dependency, dependency.getRequestedModuleVersion(), failure);
+ }
+ }
+ }
+
+ public void visitEdge(DependencyGraphNode resolvedConfiguration) {
+ ResolvedConfigurationIdentifier targetNodeId = resolvedConfiguration.getNodeId();
+ for (DependencyGraphEdge dependency : resolvedConfiguration.getIncomingEdges()) {
+ if (dependency.getFrom().getNodeId() == root.getNodeId()) {
+ ModuleDependency moduleDependency = dependency.getModuleDependency();
+ builder.addFirstLevelDependency(moduleDependency, targetNodeId);
+ }
+ }
+ }
+
+ public void visitArtifacts(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, ArtifactSet artifacts) {
+ builder.addChild(parent, child, artifacts.getId());
+ }
+
+ public void finish(DependencyGraphNode root) {
+ attachFailures(builder);
+ builder.done(root.getNodeId());
+ }
+
+ public void finishArtifacts() {
+ }
+
+ private void attachFailures(ResolvedConfigurationBuilder result) {
+ for (Map.Entry<ModuleVersionSelector, BrokenDependency> entry : failuresByRevisionId.entrySet()) {
+ Collection<List<ModuleVersionIdentifier>> paths = DependencyGraphPathResolver.calculatePaths(entry.getValue().requiredBy, root);
+ result.addUnresolvedDependency(new DefaultUnresolvedDependency(entry.getKey(), entry.getValue().failure.withIncomingPaths(paths)));
+ }
+ }
+
+ private void addUnresolvedDependency(DependencyGraphEdge dependency, ModuleVersionSelector requested, ModuleVersionResolveException failure) {
+ BrokenDependency breakage = failuresByRevisionId.get(requested);
+ if (breakage == null) {
+ breakage = new BrokenDependency(failure);
+ failuresByRevisionId.put(requested, breakage);
+ }
+ breakage.requiredBy.add(dependency.getFrom());
+ }
+
+ private static class BrokenDependency {
+ final ModuleVersionResolveException failure;
+ final List<DependencyGraphNode> requiredBy = new ArrayList<DependencyGraphNode>();
+
+ private BrokenDependency(ModuleVersionResolveException failure) {
+ this.failure = failure;
+ }
+ }
+
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsBuilder.java
index bc50b38..1e068cd 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsBuilder.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsBuilder.java
@@ -45,7 +45,6 @@ public class TransientConfigurationResultsBuilder {
private static final byte ROOT = 2;
private static final byte FIRST_LVL = 3;
private static final byte PARENT_CHILD = 4;
- private static final byte PARENT_ARTIFACT = 5;
private final Object lock = new Object();
@@ -84,12 +83,8 @@ public class TransientConfigurationResultsBuilder {
writeId(FIRST_LVL, id);
}
- public void parentChildMapping(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child) {
+ public void parentChildMapping(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, final long artifactId) {
writeId(PARENT_CHILD, parent, child);
- }
-
- public void parentSpecificArtifacts(ResolvedConfigurationIdentifier child, ResolvedConfigurationIdentifier parent, final long artifactId) {
- writeId(PARENT_ARTIFACT, child, parent);
binaryStore.write(new BinaryStore.WriteAction() {
public void write(Encoder encoder) throws IOException {
encoder.writeLong(artifactId);
@@ -164,19 +159,7 @@ public class TransientConfigurationResultsBuilder {
throw new IllegalStateException(String.format("Unexpected child dependency id %s. Seen ids: %s", childId, allDependencies.keySet()));
}
parent.addChild(child);
- break;
- case PARENT_ARTIFACT:
- ResolvedConfigurationIdentifier artifactParentId = resolvedConfigurationIdentifierSerializer.read(decoder);
- ResolvedConfigurationIdentifier artifactChildId = resolvedConfigurationIdentifierSerializer.read(decoder);
- DefaultResolvedDependency artifactParent = allDependencies.get(artifactParentId);
- DefaultResolvedDependency artifactChild = allDependencies.get(artifactChildId);
- if (artifactParent == null) {
- throw new IllegalStateException(String.format("Unexpected parent dependency id %s. Seen ids: %s", artifactParentId, allDependencies.keySet()));
- }
- if (artifactChild == null) {
- throw new IllegalStateException(String.format("Unexpected child dependency id %s. Seen ids: %s", artifactChildId, allDependencies.keySet()));
- }
- artifactParent.addParentSpecificArtifacts(artifactChild, newHashSet(mapping.getArtifacts(decoder.readLong())));
+ child.addParentSpecificArtifacts(parent, newHashSet(mapping.getArtifacts(decoder.readLong())));
break;
default:
throw new IOException("Unknown value type read from stream: " + type);
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsLoader.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsLoader.java
index fe2b96a..4e62e24 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsLoader.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/oldresult/TransientConfigurationResultsLoader.java
@@ -19,6 +19,7 @@ package org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult;
import org.gradle.api.artifacts.ModuleDependency;
import org.gradle.api.artifacts.ResolvedArtifact;
import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactResults;
import org.gradle.internal.Factory;
import java.util.Set;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedLocalComponentsResult.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedLocalComponentsResult.java
new file mode 100644
index 0000000..2d4396d
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedLocalComponentsResult.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
+
+import org.gradle.api.tasks.TaskDependency;
+
+import java.util.Collection;
+import java.util.List;
+
+public class DefaultResolvedLocalComponentsResult implements ResolvedLocalComponentsResult {
+ private final Collection<ResolvedProjectConfiguration> resolvedProjectConfigurations;
+ private final TaskDependency componentBuildDependencies;
+
+ public DefaultResolvedLocalComponentsResult(List<ResolvedProjectConfiguration> resolvedProjectConfigurations, TaskDependency componentBuildDependencies) {
+ this.resolvedProjectConfigurations = resolvedProjectConfigurations;
+ this.componentBuildDependencies = componentBuildDependencies;
+ }
+
+ @Override
+ public TaskDependency getComponentBuildDependencies() {
+ return componentBuildDependencies;
+ }
+
+ @Override
+ public Iterable<ResolvedProjectConfiguration> getResolvedProjectConfigurations() {
+ return resolvedProjectConfigurations;
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedLocalComponentsResultBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedLocalComponentsResultBuilder.java
new file mode 100644
index 0000000..c5a6699
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedLocalComponentsResultBuilder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
+
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
+import org.gradle.api.internal.tasks.DefaultTaskDependency;
+import org.gradle.api.tasks.TaskDependency;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DefaultResolvedLocalComponentsResultBuilder implements ResolvedLocalComponentsResultBuilder {
+ private final List<ResolvedProjectConfiguration> resolvedProjectConfigurations = new ArrayList<ResolvedProjectConfiguration>();
+ private final DefaultTaskDependency componentBuildDependencies = new DefaultTaskDependency();
+ private final boolean buildProjectDependencies;
+
+ public DefaultResolvedLocalComponentsResultBuilder(boolean buildProjectDependencies) {
+ this.buildProjectDependencies = buildProjectDependencies;
+ }
+
+ @Override
+ public void localComponentResolved(ComponentIdentifier componentIdentifier, TaskDependency buildDependency) {
+ if (!buildProjectDependencies) {
+ return;
+ }
+ componentBuildDependencies.add(buildDependency);
+ }
+
+ @Override
+ public void projectConfigurationResolved(ProjectComponentIdentifier componentId, String configurationName) {
+ resolvedProjectConfigurations.add(new DefaultResolvedProjectConfiguration(componentId, configurationName));
+ }
+
+ @Override
+ public ResolvedLocalComponentsResult complete() {
+ return new DefaultResolvedLocalComponentsResult(resolvedProjectConfigurations, componentBuildDependencies);
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedProjectConfigurationResultBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedProjectConfigurationResultBuilder.java
deleted file mode 100644
index 6a95eda..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedProjectConfigurationResultBuilder.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
-
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class DefaultResolvedProjectConfigurationResultBuilder implements ResolvedProjectConfigurationResultBuilder {
- private final List<ResolvedProjectConfiguration> results = new ArrayList<ResolvedProjectConfiguration>();
- private final boolean buildProjectDependencies;
- private ComponentIdentifier rootId;
-
- public DefaultResolvedProjectConfigurationResultBuilder(boolean buildProjectDependencies) {
- this.buildProjectDependencies = buildProjectDependencies;
- }
-
- @Override
- public void registerRoot(ComponentIdentifier componentId) {
- this.rootId = componentId;
- }
-
- @Override
- public void addProjectComponentResult(ProjectComponentIdentifier componentId, String configurationName) {
- if (!buildProjectDependencies) {
- return;
- }
- if (rootId.equals(componentId)) {
- return;
- }
- results.add(new DefaultResolvedProjectConfiguration(componentId, configurationName));
- }
-
- @Override
- public ResolvedProjectConfigurationResults complete() {
- return new DefaultResolvedProjectConfigurationResults(results);
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedProjectConfigurationResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedProjectConfigurationResults.java
deleted file mode 100644
index 0c699c9..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/DefaultResolvedProjectConfigurationResults.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
-
-import java.util.Collection;
-
-public class DefaultResolvedProjectConfigurationResults implements ResolvedProjectConfigurationResults {
- private final Collection<ResolvedProjectConfiguration> results;
-
- public DefaultResolvedProjectConfigurationResults(Collection<ResolvedProjectConfiguration> results) {
- this.results = results;
- }
-
- @Override
- public Iterable<ResolvedProjectConfiguration> get() {
- return results;
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResult.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResult.java
new file mode 100644
index 0000000..c6cf1ac
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResult.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
+
+import org.gradle.api.tasks.TaskDependency;
+
+public interface ResolvedLocalComponentsResult {
+ TaskDependency getComponentBuildDependencies();
+ Iterable<ResolvedProjectConfiguration> getResolvedProjectConfigurations();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResultBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResultBuilder.java
new file mode 100644
index 0000000..e8b957c
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResultBuilder.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
+
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
+import org.gradle.api.tasks.TaskDependency;
+
+public interface ResolvedLocalComponentsResultBuilder {
+ void localComponentResolved(ComponentIdentifier componentIdentifier, TaskDependency buildDependency);
+ void projectConfigurationResolved(ProjectComponentIdentifier componentId, String configurationName);
+ ResolvedLocalComponentsResult complete();
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResultGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResultGraphVisitor.java
new file mode 100644
index 0000000..99c5490
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedLocalComponentsResultGraphVisitor.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
+
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphNode;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+import org.gradle.internal.component.local.model.LocalConfigurationMetaData;
+import org.gradle.internal.component.model.ConfigurationMetaData;
+
+public class ResolvedLocalComponentsResultGraphVisitor implements DependencyGraphVisitor {
+ private final ResolvedLocalComponentsResultBuilder builder;
+ private ComponentIdentifier rootId;
+
+ public ResolvedLocalComponentsResultGraphVisitor(ResolvedLocalComponentsResultBuilder builder) {
+ this.builder = builder;
+ }
+
+ @Override
+ public void start(DependencyGraphNode root) {
+ rootId = root.getComponentId();
+ }
+
+ @Override
+ public void visitNode(DependencyGraphNode resolvedConfiguration) {
+ if (rootId.equals(resolvedConfiguration.getComponentId())) {
+ return;
+ }
+
+ ComponentIdentifier componentId = resolvedConfiguration.getComponentId();
+ if (componentId instanceof ProjectComponentIdentifier) {
+ builder.projectConfigurationResolved((ProjectComponentIdentifier) componentId, resolvedConfiguration.getNodeId().getConfiguration());
+ }
+ ConfigurationMetaData configurationMetaData = resolvedConfiguration.getMetaData();
+ if (configurationMetaData instanceof LocalConfigurationMetaData) {
+ builder.localComponentResolved(componentId, ((LocalConfigurationMetaData) configurationMetaData).getDirectBuildDependencies());
+ }
+ }
+
+ @Override
+ public void visitEdge(DependencyGraphNode resolvedConfiguration) {
+ }
+
+ @Override
+ public void finish(DependencyGraphNode root) {
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedProjectConfigurationResultBuilder.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedProjectConfigurationResultBuilder.java
deleted file mode 100644
index 9d70bf6..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedProjectConfigurationResultBuilder.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
-
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
-
-public interface ResolvedProjectConfigurationResultBuilder {
- void registerRoot(ComponentIdentifier componentId);
- void addProjectComponentResult(ProjectComponentIdentifier componentId, String configurationName);
- ResolvedProjectConfigurationResults complete();
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedProjectConfigurationResults.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedProjectConfigurationResults.java
deleted file mode 100644
index b898c93..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/projectresult/ResolvedProjectConfigurationResults.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult;
-
-public interface ResolvedProjectConfigurationResults {
- Iterable<ResolvedProjectConfiguration> get();
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializer.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializer.java
index f0957a0..9068e84 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializer.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializer.java
@@ -17,11 +17,11 @@
package org.gradle.api.internal.artifacts.ivyservice.resolveengine.result;
import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier;
-import org.gradle.internal.component.local.model.DefaultLibraryComponentIdentifier;
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier;
import org.gradle.internal.component.local.model.DefaultProjectComponentIdentifier;
import org.gradle.internal.serialize.Decoder;
import org.gradle.internal.serialize.Encoder;
@@ -38,7 +38,7 @@ public class ComponentIdentifierSerializer implements Serializer<ComponentIdenti
} else if(Implementation.MODULE.getId() == id) {
return new DefaultModuleComponentIdentifier(decoder.readString(), decoder.readString(), decoder.readString());
} else if (Implementation.LIBRARY.getId() == id) {
- return new DefaultLibraryComponentIdentifier(decoder.readString(), decoder.readString());
+ return new DefaultLibraryBinaryIdentifier(decoder.readString(), decoder.readString(), decoder.readString());
}
throw new IllegalArgumentException("Unable to find component identifier with id: " + id);
@@ -59,11 +59,12 @@ public class ComponentIdentifierSerializer implements Serializer<ComponentIdenti
ProjectComponentIdentifier projectComponentIdentifier = (ProjectComponentIdentifier)value;
encoder.writeByte(Implementation.BUILD.getId());
encoder.writeString(projectComponentIdentifier.getProjectPath());
- } else if(value instanceof DefaultLibraryComponentIdentifier) {
- LibraryComponentIdentifier libraryIdentifier = (LibraryComponentIdentifier)value;
+ } else if(value instanceof DefaultLibraryBinaryIdentifier) {
+ LibraryBinaryIdentifier libraryIdentifier = (LibraryBinaryIdentifier)value;
encoder.writeByte(Implementation.LIBRARY.getId());
encoder.writeString(libraryIdentifier.getProjectPath());
encoder.writeString(libraryIdentifier.getLibraryName());
+ encoder.writeString(libraryIdentifier.getVariant());
} else {
throw new IllegalArgumentException("Unsupported component identifier class: " + value.getClass());
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializer.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializer.java
index 414208e..f5c98bf 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializer.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializer.java
@@ -38,7 +38,7 @@ public class ComponentSelectorSerializer implements Serializer<ComponentSelector
} else if (Implementation.MODULE.getId() == id) {
return new DefaultModuleComponentSelector(decoder.readString(), decoder.readString(), decoder.readString());
} else if (Implementation.LIBRARY.getId() == id) {
- return new DefaultLibraryComponentSelector(decoder.readString(), decoder.readString());
+ return new DefaultLibraryComponentSelector(decoder.readString(), decoder.readNullableString());
}
throw new IllegalArgumentException("Unable to find component selector with id: " + id);
@@ -63,7 +63,7 @@ public class ComponentSelectorSerializer implements Serializer<ComponentSelector
LibraryComponentSelector libraryComponentSelector = (LibraryComponentSelector) value;
encoder.writeByte(Implementation.LIBRARY.getId());
encoder.writeString(libraryComponentSelector.getProjectPath());
- encoder.writeString(libraryComponentSelector.getLibraryName());
+ encoder.writeNullableString(libraryComponentSelector.getLibraryName());
} else {
throw new IllegalArgumentException("Unsupported component selector class: " + value.getClass());
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ResolutionResultDependencyGraphVisitor.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ResolutionResultDependencyGraphVisitor.java
new file mode 100644
index 0000000..5904325
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ResolutionResultDependencyGraphVisitor.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.resolveengine.result;
+
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphNode;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+
+public class ResolutionResultDependencyGraphVisitor implements DependencyGraphVisitor {
+ private final ResolutionResultBuilder newModelBuilder;
+
+ public ResolutionResultDependencyGraphVisitor(ResolutionResultBuilder newModelBuilder) {
+ this.newModelBuilder = newModelBuilder;
+ }
+
+ public void start(DependencyGraphNode root) {
+ newModelBuilder.start(root.toId(), root.getComponentId());
+ }
+
+ public void visitNode(DependencyGraphNode resolvedConfiguration) {
+ newModelBuilder.resolvedModuleVersion(resolvedConfiguration.getSelection());
+ }
+
+ public void visitEdge(DependencyGraphNode resolvedConfiguration) {
+ newModelBuilder.resolvedConfiguration(resolvedConfiguration.toId(), resolvedConfiguration.getOutgoingEdges());
+ }
+
+ public void finish(DependencyGraphNode root) {
+
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactory.java
index 172489b..e58ae66 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactory.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactory.java
@@ -80,7 +80,7 @@ public class ResolutionResultsStoreFactory implements Closeable {
return createBinaryStore(storeKey);
}
- public Store<ResolvedComponentResult> oldModelStore() {
+ public Store<ResolvedComponentResult> newModelCache() {
if (oldModelCache == null) {
oldModelCache = new CachedStoreFactory("Resolution result");
cleanUpLater.add(oldModelCache);
@@ -88,7 +88,7 @@ public class ResolutionResultsStoreFactory implements Closeable {
return oldModelCache.createCachedStore(storeSetId);
}
- public Store<TransientConfigurationResults> newModelStore() {
+ public Store<TransientConfigurationResults> oldModelCache() {
if (newModelCache == null) {
newModelCache = new CachedStoreFactory("Resolved configuration");
cleanUpLater.add(newModelCache);
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/StoreSet.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/StoreSet.java
index bbe27de..73d262c 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/StoreSet.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/StoreSet.java
@@ -23,7 +23,7 @@ import org.gradle.api.internal.cache.Store;
public interface StoreSet {
BinaryStore nextBinaryStore();
- Store<ResolvedComponentResult> oldModelStore();
+ Store<ResolvedComponentResult> newModelCache();
- Store<TransientConfigurationResults> newModelStore();
+ Store<TransientConfigurationResults> oldModelCache();
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQuery.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQuery.java
index 4574d04..ed0959f 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQuery.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQuery.java
@@ -30,8 +30,8 @@ import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
import org.gradle.api.internal.artifacts.configurations.ConfigurationContainerInternal;
import org.gradle.api.internal.artifacts.configurations.ResolutionStrategyInternal;
import org.gradle.api.internal.artifacts.ivyservice.CacheLockingManager;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingArtifactResolver;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChain;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolveIvyFactory;
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
import org.gradle.api.internal.artifacts.result.*;
@@ -43,6 +43,7 @@ import org.gradle.internal.component.model.ComponentArtifactMetaData;
import org.gradle.internal.component.model.ComponentResolveMetaData;
import org.gradle.internal.component.model.DefaultComponentOverrideMetadata;
import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
import org.gradle.internal.resolve.result.*;
import org.gradle.util.CollectionUtils;
@@ -92,15 +93,15 @@ public class DefaultArtifactResolutionQuery implements ArtifactResolutionQuery {
return this;
}
- // TODO:DAZ This is ugly and needs a major cleanup and unit tests
public ArtifactResolutionResult execute() {
if (componentType == null) {
throw new IllegalStateException("Must specify component type and artifacts to query.");
}
List<ResolutionAwareRepository> repositories = CollectionUtils.collect(repositoryHandler, Transformers.cast(ResolutionAwareRepository.class));
ResolutionStrategyInternal resolutionStrategy = configurationContainer.detachedConfiguration().getResolutionStrategy();
- final RepositoryChain repositoryChain = ivyFactory.create(resolutionStrategy, repositories, metadataHandler.getComponentMetadataProcessor());
- final ArtifactResolver artifactResolver = new ErrorHandlingArtifactResolver(repositoryChain.getArtifactResolver());
+ final ComponentResolvers componentResolvers = ivyFactory.create(resolutionStrategy, repositories, metadataHandler.getComponentMetadataProcessor());
+ final ComponentMetaDataResolver componentMetaDataResolver = componentResolvers.getComponentResolver();
+ final ArtifactResolver artifactResolver = new ErrorHandlingArtifactResolver(componentResolvers.getArtifactResolver());
return lockingManager.useCache("resolve artifacts", new Factory<ArtifactResolutionResult>() {
public ArtifactResolutionResult create() {
@@ -109,7 +110,7 @@ public class DefaultArtifactResolutionQuery implements ArtifactResolutionQuery {
for (ComponentIdentifier componentId : componentIds) {
try {
ComponentIdentifier validId = validateComponentIdentifier(componentId);
- componentResults.add(buildComponentResult(validId, repositoryChain, artifactResolver));
+ componentResults.add(buildComponentResult(validId, componentMetaDataResolver, artifactResolver));
} catch (Throwable t) {
componentResults.add(new DefaultUnresolvedComponentResult(componentId, t));
}
@@ -131,9 +132,9 @@ public class DefaultArtifactResolutionQuery implements ArtifactResolutionQuery {
});
}
- private ComponentArtifactsResult buildComponentResult(ComponentIdentifier componentId, RepositoryChain repositoryChain, ArtifactResolver artifactResolver) {
+ private ComponentArtifactsResult buildComponentResult(ComponentIdentifier componentId, ComponentMetaDataResolver componentMetaDataResolver, ArtifactResolver artifactResolver) {
BuildableComponentResolveResult moduleResolveResult = new DefaultBuildableComponentResolveResult();
- repositoryChain.getComponentResolver().resolve(componentId, new DefaultComponentOverrideMetadata(), moduleResolveResult);
+ componentMetaDataResolver.resolve(componentId, new DefaultComponentOverrideMetadata(), moduleResolveResult);
ComponentResolveMetaData component = moduleResolveResult.getMetaData();
DefaultComponentArtifactsResult componentResult = new DefaultComponentArtifactsResult(component.getComponentId());
for (Class<? extends Artifact> artifactType : artifactTypes) {
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepository.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepository.java
index 4a8a866..8031e66 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepository.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepository.java
@@ -16,21 +16,30 @@
package org.gradle.api.internal.artifacts.repositories;
import org.gradle.api.Action;
+import org.gradle.api.artifacts.repositories.AuthenticationContainer;
import org.gradle.api.artifacts.repositories.PasswordCredentials;
+import org.gradle.authentication.Authentication;
import org.gradle.api.credentials.AwsCredentials;
import org.gradle.api.credentials.Credentials;
+import org.gradle.internal.authentication.AllSchemesAuthentication;
+import org.gradle.internal.authentication.AuthenticationInternal;
import org.gradle.internal.Cast;
import org.gradle.internal.artifacts.repositories.AuthenticationSupportedInternal;
import org.gradle.internal.credentials.DefaultAwsCredentials;
import org.gradle.internal.reflect.Instantiator;
+import java.util.Collection;
+import java.util.Collections;
+
public abstract class AbstractAuthenticationSupportedRepository extends AbstractArtifactRepository implements AuthenticationSupportedInternal {
private Credentials credentials;
private final Instantiator instantiator;
+ private AuthenticationContainer authenticationContainer;
- AbstractAuthenticationSupportedRepository(Instantiator instantiator) {
+ AbstractAuthenticationSupportedRepository(Instantiator instantiator, AuthenticationContainer authenticationContainer) {
this.instantiator = instantiator;
+ this.authenticationContainer = authenticationContainer;
}
@Override
@@ -40,7 +49,7 @@ public abstract class AbstractAuthenticationSupportedRepository extends Abstract
} else if (credentials instanceof PasswordCredentials) {
return Cast.uncheckedCast(credentials);
} else {
- throw new IllegalStateException("Can not use getCredentials() method when not using PasswordCredentals; please use getCredentials(Class)");
+ throw new IllegalStateException("Can not use getCredentials() method when not using PasswordCredentials; please use getCredentials(Class)");
}
}
@@ -51,13 +60,13 @@ public abstract class AbstractAuthenticationSupportedRepository extends Abstract
} else if (credentialsType.isInstance(credentials)) {
return Cast.uncheckedCast(credentials);
} else {
- throw new IllegalArgumentException(String.format("Given credentials type '%s' does not match actual type '%s'", credentialsType.getName(), getPublicType(credentials.getClass()).getName()));
+ throw new IllegalArgumentException(String.format("Given credentials type '%s' does not match actual type '%s'", credentialsType.getName(), getCredentialsPublicType(credentials.getClass()).getName()));
}
}
public void credentials(Action<? super PasswordCredentials> action) {
if (credentials != null && !(credentials instanceof PasswordCredentials)) {
- throw new IllegalStateException("Can not use credentials(Action) method when not using PasswordCredentals; please use credentials(Class, Action)");
+ throw new IllegalStateException("Can not use credentials(Action) method when not using PasswordCredentials; please use credentials(Class, Action)");
}
credentials(PasswordCredentials.class, action);
}
@@ -73,17 +82,44 @@ public abstract class AbstractAuthenticationSupportedRepository extends Abstract
}
private <T extends Credentials> T newCredentials(Class<T> clazz) {
- return instantiator.newInstance(getImplType(clazz));
+ return instantiator.newInstance(getCredentialsImplType(clazz));
}
public Credentials getConfiguredCredentials() {
return credentials;
}
+ @Override
+ public void authentication(Action<? super AuthenticationContainer> action) {
+ action.execute(getAuthentication());
+ }
+
+ @Override
+ public AuthenticationContainer getAuthentication() {
+ return authenticationContainer;
+ }
+
+ @Override
+ public Collection<Authentication> getConfiguredAuthentication() {
+ populateAuthenticationCredentials();
+ if (getConfiguredCredentials() != null & authenticationContainer.size() == 0) {
+ return Collections.<Authentication>singleton(new AllSchemesAuthentication(getConfiguredCredentials()));
+ } else {
+ return getAuthentication();
+ }
+ }
+
+ private void populateAuthenticationCredentials() {
+ // TODO: This will have to be changed when we support setting credentials directly on the authentication
+ for (Authentication authentication : authenticationContainer) {
+ ((AuthenticationInternal)authentication).setCredentials(getConfiguredCredentials());
+ }
+ }
+
// Mappings between public and impl types
// If the list of mappings grows we should move it to a data structure
- private static <T extends Credentials> Class<? extends T> getImplType(Class<T> publicType) {
+ private static <T extends Credentials> Class<? extends T> getCredentialsImplType(Class<T> publicType) {
if (publicType == PasswordCredentials.class) {
return Cast.uncheckedCast(DefaultPasswordCredentials.class);
} else if (publicType == AwsCredentials.class) {
@@ -93,7 +129,7 @@ public abstract class AbstractAuthenticationSupportedRepository extends Abstract
}
}
- private static <T extends Credentials> Class<? super T> getPublicType(Class<T> implType) {
+ private static <T extends Credentials> Class<? super T> getCredentialsPublicType(Class<T> implType) {
if (PasswordCredentials.class.isAssignableFrom(implType)) {
return Cast.uncheckedCast(PasswordCredentials.class);
} else if (AwsCredentials.class.isAssignableFrom(implType)) {
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactory.java
index cfacca1..921405e 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactory.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactory.java
@@ -17,16 +17,20 @@
package org.gradle.api.internal.artifacts.repositories;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
+import org.gradle.api.artifacts.repositories.AuthenticationContainer;
import org.gradle.api.artifacts.repositories.FlatDirectoryArtifactRepository;
import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
+import org.gradle.authentication.Authentication;
import org.gradle.api.internal.artifacts.BaseRepositoryFactory;
import org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.ResolverStrategy;
import org.gradle.api.internal.artifacts.mvnsettings.LocalMavenRepositoryLocator;
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransportFactory;
+import org.gradle.internal.authentication.DefaultAuthenticationContainer;
import org.gradle.api.internal.file.FileResolver;
+import org.gradle.internal.authentication.AuthenticationSchemeRegistry;
import org.gradle.internal.component.external.model.DefaultMavenModuleResolveMetaData;
import org.gradle.internal.component.external.model.ModuleComponentArtifactMetaData;
import org.gradle.internal.reflect.Instantiator;
@@ -34,6 +38,7 @@ import org.gradle.internal.resource.local.FileStore;
import org.gradle.internal.resource.local.LocallyAvailableResourceFinder;
import java.io.File;
+import java.util.Map;
public class DefaultBaseRepositoryFactory implements BaseRepositoryFactory {
private final LocalMavenRepositoryLocator localMavenRepositoryLocator;
@@ -44,6 +49,7 @@ public class DefaultBaseRepositoryFactory implements BaseRepositoryFactory {
private final ResolverStrategy resolverStrategy;
private final FileStore<ModuleComponentArtifactMetaData> artifactFileStore;
private final MetaDataParser<DefaultMavenModuleResolveMetaData> pomParser;
+ private final AuthenticationSchemeRegistry authenticationSchemeRegistry;
public DefaultBaseRepositoryFactory(LocalMavenRepositoryLocator localMavenRepositoryLocator,
FileResolver fileResolver,
@@ -51,7 +57,8 @@ public class DefaultBaseRepositoryFactory implements BaseRepositoryFactory {
RepositoryTransportFactory transportFactory,
LocallyAvailableResourceFinder<ModuleComponentArtifactMetaData> locallyAvailableResourceFinder,
ResolverStrategy resolverStrategy,
- FileStore<ModuleComponentArtifactMetaData> artifactFileStore, MetaDataParser<DefaultMavenModuleResolveMetaData> pomParser) {
+ FileStore<ModuleComponentArtifactMetaData> artifactFileStore, MetaDataParser<DefaultMavenModuleResolveMetaData> pomParser,
+ AuthenticationSchemeRegistry authenticationSchemeRegistry) {
this.localMavenRepositoryLocator = localMavenRepositoryLocator;
this.fileResolver = fileResolver;
this.instantiator = instantiator;
@@ -60,6 +67,7 @@ public class DefaultBaseRepositoryFactory implements BaseRepositoryFactory {
this.resolverStrategy = resolverStrategy;
this.artifactFileStore = artifactFileStore;
this.pomParser = pomParser;
+ this.authenticationSchemeRegistry = authenticationSchemeRegistry;
}
public FlatDirectoryArtifactRepository createFlatDirRepository() {
@@ -69,7 +77,7 @@ public class DefaultBaseRepositoryFactory implements BaseRepositoryFactory {
public MavenArtifactRepository createMavenLocalRepository() {
MavenArtifactRepository mavenRepository = instantiator.newInstance(DefaultMavenLocalArtifactRepository.class, fileResolver, transportFactory,
- locallyAvailableResourceFinder, instantiator, artifactFileStore, pomParser);
+ locallyAvailableResourceFinder, instantiator, artifactFileStore, pomParser, createAuthenticationContainer());
final File localMavenRepository = localMavenRepositoryLocator.getLocalMavenRepository();
mavenRepository.setUrl(localMavenRepository);
return mavenRepository;
@@ -89,11 +97,21 @@ public class DefaultBaseRepositoryFactory implements BaseRepositoryFactory {
public IvyArtifactRepository createIvyRepository() {
return instantiator.newInstance(DefaultIvyArtifactRepository.class, fileResolver, transportFactory,
- locallyAvailableResourceFinder, instantiator, resolverStrategy, artifactFileStore);
+ locallyAvailableResourceFinder, instantiator, resolverStrategy, artifactFileStore, createAuthenticationContainer());
}
public MavenArtifactRepository createMavenRepository() {
return instantiator.newInstance(DefaultMavenArtifactRepository.class, fileResolver, transportFactory,
- locallyAvailableResourceFinder, instantiator, artifactFileStore, pomParser);
+ locallyAvailableResourceFinder, instantiator, artifactFileStore, pomParser, createAuthenticationContainer());
+ }
+
+ protected AuthenticationContainer createAuthenticationContainer() {
+ DefaultAuthenticationContainer container = instantiator.newInstance(DefaultAuthenticationContainer.class, instantiator);
+
+ for (Map.Entry<Class<Authentication>, Class<? extends Authentication>> e : authenticationSchemeRegistry.getRegisteredSchemes().entrySet()) {
+ container.registerBinding(e.getKey(), e.getValue());
+ }
+
+ return container;
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepository.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepository.java
index a659689..7e10382 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepository.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepository.java
@@ -18,6 +18,7 @@ package org.gradle.api.internal.artifacts.repositories;
import com.google.common.collect.Lists;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.artifacts.repositories.FlatDirectoryArtifactRepository;
+import org.gradle.authentication.Authentication;
import org.gradle.api.internal.artifacts.ModuleVersionPublisher;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.ResolverStrategy;
@@ -29,10 +30,7 @@ import org.gradle.internal.resource.local.FileStore;
import org.gradle.internal.resource.local.LocallyAvailableResourceFinder;
import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
public class DefaultFlatDirArtifactRepository extends AbstractArtifactRepository implements FlatDirectoryArtifactRepository, ResolutionAwareRepository, PublicationAwareRepository {
private final FileResolver fileResolver;
@@ -84,7 +82,7 @@ public class DefaultFlatDirArtifactRepository extends AbstractArtifactRepository
throw new InvalidUserDataException("You must specify at least one directory for a flat directory repository.");
}
- IvyResolver resolver = new IvyResolver(getName(), transportFactory.createTransport("file", getName(), null), locallyAvailableResourceFinder, false, resolverStrategy, artifactFileStore);
+ IvyResolver resolver = new IvyResolver(getName(), transportFactory.createTransport("file", getName(), Collections.<Authentication>emptyList()), locallyAvailableResourceFinder, false, resolverStrategy, artifactFileStore);
for (File root : dirs) {
resolver.addArtifactLocation(root.toURI(), "/[artifact]-[revision](-[classifier]).[ext]");
resolver.addArtifactLocation(root.toURI(), "/[artifact](-[classifier]).[ext]");
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepository.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepository.java
index 5333273..4820e4f 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepository.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepository.java
@@ -21,6 +21,7 @@ import org.gradle.api.InvalidUserDataException;
import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
import org.gradle.api.artifacts.repositories.IvyArtifactRepositoryMetaDataProvider;
import org.gradle.api.artifacts.repositories.RepositoryLayout;
+import org.gradle.api.artifacts.repositories.AuthenticationContainer;
import org.gradle.api.internal.ClosureBackedAction;
import org.gradle.api.internal.artifacts.ModuleVersionPublisher;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository;
@@ -54,8 +55,8 @@ public class DefaultIvyArtifactRepository extends AbstractAuthenticationSupporte
public DefaultIvyArtifactRepository(FileResolver fileResolver, RepositoryTransportFactory transportFactory,
LocallyAvailableResourceFinder<ModuleComponentArtifactMetaData> locallyAvailableResourceFinder, Instantiator instantiator,
- ResolverStrategy resolverStrategy, FileStore<ModuleComponentArtifactMetaData> artifactFileStore) {
- super(instantiator);
+ ResolverStrategy resolverStrategy, FileStore<ModuleComponentArtifactMetaData> artifactFileStore, AuthenticationContainer authenticationContainer) {
+ super(instantiator, authenticationContainer);
this.fileResolver = fileResolver;
this.transportFactory = transportFactory;
this.locallyAvailableResourceFinder = locallyAvailableResourceFinder;
@@ -94,7 +95,7 @@ public class DefaultIvyArtifactRepository extends AbstractAuthenticationSupporte
if (schemes.isEmpty()) {
throw new InvalidUserDataException("You must specify a base url or at least one artifact pattern for an Ivy repository.");
}
- return createResolver(transportFactory.createTransport(schemes, getName(), getConfiguredCredentials()));
+ return createResolver(transportFactory.createTransport(schemes, getName(), getConfiguredAuthentication()));
}
private IvyResolver createResolver(RepositoryTransport transport) {
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepository.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepository.java
index 798a74c..e095b67 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepository.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepository.java
@@ -18,6 +18,7 @@ package org.gradle.api.internal.artifacts.repositories;
import com.google.common.collect.Lists;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
+import org.gradle.api.artifacts.repositories.AuthenticationContainer;
import org.gradle.api.internal.artifacts.ModuleVersionPublisher;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser;
@@ -50,8 +51,9 @@ public class DefaultMavenArtifactRepository extends AbstractAuthenticationSuppor
LocallyAvailableResourceFinder<ModuleComponentArtifactMetaData> locallyAvailableResourceFinder,
Instantiator instantiator,
FileStore<ModuleComponentArtifactMetaData> artifactFileStore,
- MetaDataParser<DefaultMavenModuleResolveMetaData> pomParser) {
- super(instantiator);
+ MetaDataParser<DefaultMavenModuleResolveMetaData> pomParser,
+ AuthenticationContainer authenticationContainer) {
+ super(instantiator, authenticationContainer);
this.fileResolver = fileResolver;
this.transportFactory = transportFactory;
this.locallyAvailableResourceFinder = locallyAvailableResourceFinder;
@@ -119,7 +121,7 @@ public class DefaultMavenArtifactRepository extends AbstractAuthenticationSuppor
}
protected RepositoryTransport getTransport(String scheme) {
- return transportFactory.createTransport(scheme, getName(), getConfiguredCredentials());
+ return transportFactory.createTransport(scheme, getName(), getConfiguredAuthentication());
}
protected LocallyAvailableResourceFinder<ModuleComponentArtifactMetaData> getLocallyAvailableResourceFinder() {
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalArtifactRepository.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalArtifactRepository.java
index c2fac9c..9dc06aa 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalArtifactRepository.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalArtifactRepository.java
@@ -17,6 +17,7 @@ package org.gradle.api.internal.artifacts.repositories;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
+import org.gradle.api.artifacts.repositories.AuthenticationContainer;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser;
import org.gradle.api.internal.artifacts.repositories.resolver.MavenLocalResolver;
import org.gradle.api.internal.artifacts.repositories.resolver.MavenResolver;
@@ -33,8 +34,9 @@ import java.net.URI;
public class DefaultMavenLocalArtifactRepository extends DefaultMavenArtifactRepository implements MavenArtifactRepository {
public DefaultMavenLocalArtifactRepository(FileResolver fileResolver, RepositoryTransportFactory transportFactory,
LocallyAvailableResourceFinder<ModuleComponentArtifactMetaData> locallyAvailableResourceFinder, Instantiator instantiator,
- FileStore<ModuleComponentArtifactMetaData> artifactFileStore, MetaDataParser<DefaultMavenModuleResolveMetaData> pomParser) {
- super(fileResolver, transportFactory, locallyAvailableResourceFinder, instantiator, artifactFileStore, pomParser);
+ FileStore<ModuleComponentArtifactMetaData> artifactFileStore, MetaDataParser<DefaultMavenModuleResolveMetaData> pomParser,
+ AuthenticationContainer authenticationContainer) {
+ super(fileResolver, transportFactory, locallyAvailableResourceFinder, instantiator, artifactFileStore, pomParser, authenticationContainer);
}
protected MavenResolver createRealResolver() {
@@ -49,4 +51,4 @@ public class DefaultMavenLocalArtifactRepository extends DefaultMavenArtifactRep
}
return resolver;
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/DefaultExternalResourceArtifactResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/DefaultExternalResourceArtifactResolver.java
index acd949b..668ca26 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/DefaultExternalResourceArtifactResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/DefaultExternalResourceArtifactResolver.java
@@ -16,6 +16,7 @@
package org.gradle.api.internal.artifacts.repositories.resolver;
import org.gradle.internal.component.external.model.ModuleComponentArtifactMetaData;
+import org.gradle.internal.component.model.ModuleDescriptorArtifactMetaData;
import org.gradle.internal.resolve.result.ResourceAwareResolveResult;
import org.gradle.internal.resource.ExternalResourceName;
import org.gradle.internal.resource.local.LocallyAvailableExternalResource;
@@ -52,11 +53,10 @@ class DefaultExternalResourceArtifactResolver implements ExternalResourceArtifac
this.resourceAccessor = resourceAccessor;
}
- public LocallyAvailableExternalResource resolveMetaDataArtifact(ModuleComponentArtifactMetaData artifact, ResourceAwareResolveResult result) {
- return downloadStaticResource(ivyPatterns, artifact, result);
- }
-
public LocallyAvailableExternalResource resolveArtifact(ModuleComponentArtifactMetaData artifact, ResourceAwareResolveResult result) {
+ if (artifact instanceof ModuleDescriptorArtifactMetaData) {
+ return downloadStaticResource(ivyPatterns, artifact, result);
+ }
return downloadStaticResource(artifactPatterns, artifact, result);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceArtifactResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceArtifactResolver.java
index 80cf839..178c9bc 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceArtifactResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceArtifactResolver.java
@@ -21,8 +21,6 @@ import org.gradle.internal.resolve.result.ResourceAwareResolveResult;
import org.gradle.internal.resource.local.LocallyAvailableExternalResource;
public interface ExternalResourceArtifactResolver {
- @Nullable
- LocallyAvailableExternalResource resolveMetaDataArtifact(ModuleComponentArtifactMetaData artifact, ResourceAwareResolveResult result);
@Nullable
LocallyAvailableExternalResource resolveArtifact(ModuleComponentArtifactMetaData artifact, ResourceAwareResolveResult result);
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolver.java
index a7bc9c0..d8b574f 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolver.java
@@ -25,10 +25,10 @@ import org.gradle.api.artifacts.ModuleIdentifier;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier;
import org.gradle.api.internal.artifacts.ModuleVersionPublisher;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.DependencyResolverIdentifier;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ModuleComponentRepositoryAccess;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChain;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.DescriptorParseContext;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParseException;
import org.gradle.api.internal.component.ArtifactType;
@@ -40,11 +40,7 @@ import org.gradle.internal.hash.HashUtil;
import org.gradle.internal.hash.HashValue;
import org.gradle.internal.resolve.ArtifactResolveException;
import org.gradle.internal.resolve.result.*;
-import org.gradle.internal.resource.local.LocallyAvailableExternalResource;
-import org.gradle.internal.resource.local.ByteArrayLocalResource;
-import org.gradle.internal.resource.local.FileLocalResource;
-import org.gradle.internal.resource.local.FileStore;
-import org.gradle.internal.resource.local.LocallyAvailableResourceFinder;
+import org.gradle.internal.resource.local.*;
import org.gradle.internal.resource.transfer.CacheAwareExternalResourceAccessor;
import org.gradle.internal.resource.transport.ExternalResourceRepository;
import org.gradle.util.CollectionUtils;
@@ -63,7 +59,7 @@ public abstract class ExternalResourceResolver implements ModuleVersionPublisher
private List<ResourcePattern> ivyPatterns = new ArrayList<ResourcePattern>();
private List<ResourcePattern> artifactPatterns = new ArrayList<ResourcePattern>();
private String name;
- private RepositoryChain repositoryChain;
+ private ComponentResolvers componentResolvers;
private final ExternalResourceRepository repository;
private final boolean local;
@@ -105,8 +101,8 @@ public abstract class ExternalResourceResolver implements ModuleVersionPublisher
return false;
}
- public void setRepositoryChain(RepositoryChain resolver) {
- this.repositoryChain = resolver;
+ public void setComponentResolvers(ComponentResolvers resolver) {
+ this.componentResolvers = resolver;
}
protected ExternalResourceRepository getRepository() {
@@ -165,12 +161,12 @@ public abstract class ExternalResourceResolver implements ModuleVersionPublisher
@Nullable
protected MutableModuleComponentResolveMetaData parseMetaDataFromArtifact(ModuleComponentIdentifier moduleComponentIdentifier, ExternalResourceArtifactResolver artifactResolver, ResourceAwareResolveResult result) {
ModuleComponentArtifactMetaData artifact = getMetaDataArtifactFor(moduleComponentIdentifier);
- LocallyAvailableExternalResource metaDataResource = artifactResolver.resolveMetaDataArtifact(artifact, result);
+ LocallyAvailableExternalResource metaDataResource = artifactResolver.resolveArtifact(artifact, result);
if (metaDataResource == null) {
return null;
}
- ExternalResourceResolverDescriptorParseContext context = new ExternalResourceResolverDescriptorParseContext(repositoryChain);
+ ExternalResourceResolverDescriptorParseContext context = new ExternalResourceResolverDescriptorParseContext(componentResolvers);
return parseMetaDataFromResource(moduleComponentIdentifier, metaDataResource, context);
}
@@ -226,9 +222,10 @@ public abstract class ExternalResourceResolver implements ModuleVersionPublisher
return Collections.emptySet();
}
- private ModuleComponentArtifactMetaData getMetaDataArtifactFor(ModuleComponentIdentifier moduleComponentIdentifier) {
+ private ModuleDescriptorArtifactMetaData getMetaDataArtifactFor(ModuleComponentIdentifier moduleComponentIdentifier) {
IvyArtifactName ivyArtifactName = getMetaDataArtifactName(moduleComponentIdentifier.getModule());
- return new DefaultModuleComponentArtifactMetaData(moduleComponentIdentifier, ivyArtifactName);
+ DefaultModuleComponentArtifactMetaData defaultModuleComponentArtifactMetaData = new DefaultModuleComponentArtifactMetaData(moduleComponentIdentifier, ivyArtifactName);
+ return new DefaultModuleDescriptorArtifactMetaData(defaultModuleComponentArtifactMetaData);
}
protected abstract IvyArtifactName getMetaDataArtifactName(String moduleName);
@@ -389,7 +386,7 @@ public abstract class ExternalResourceResolver implements ModuleVersionPublisher
}
protected final void resolveMetaDataArtifacts(ModuleComponentResolveMetaData module, BuildableArtifactSetResolveResult result) {
- ModuleComponentArtifactMetaData artifact = getMetaDataArtifactFor(module.getComponentId());
+ ModuleDescriptorArtifactMetaData artifact = getMetaDataArtifactFor(module.getComponentId());
result.resolved(Collections.singleton(artifact));
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolverDescriptorParseContext.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolverDescriptorParseContext.java
index ac4bc95..3371cc6 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolverDescriptorParseContext.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/ExternalResourceResolverDescriptorParseContext.java
@@ -16,7 +16,7 @@
package org.gradle.api.internal.artifacts.repositories.resolver;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChain;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.DescriptorParseContext;
import org.gradle.api.internal.component.ArtifactType;
import org.gradle.internal.component.model.ComponentArtifactMetaData;
@@ -37,9 +37,9 @@ import java.io.File;
* If the parser asks for a resolver for a different revision, the resolver scope is all repositories.
*/
public class ExternalResourceResolverDescriptorParseContext implements DescriptorParseContext {
- private final RepositoryChain mainResolvers;
+ private final ComponentResolvers mainResolvers;
- public ExternalResourceResolverDescriptorParseContext(RepositoryChain mainResolvers) {
+ public ExternalResourceResolverDescriptorParseContext(ComponentResolvers mainResolvers) {
this.mainResolvers = mainResolvers;
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolver.java
index 2dbe366..e1f3a96 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolver.java
@@ -37,10 +37,6 @@ class MavenUniqueSnapshotExternalResourceArtifactResolver implements ExternalRes
return delegate.resolveArtifact(timestamp(artifact), result);
}
- public LocallyAvailableExternalResource resolveMetaDataArtifact(ModuleComponentArtifactMetaData artifact, ResourceAwareResolveResult result) {
- return delegate.resolveMetaDataArtifact(timestamp(artifact), result);
- }
-
protected ModuleComponentArtifactMetaData timestamp(ModuleComponentArtifactMetaData artifact) {
MavenUniqueSnapshotComponentIdentifier snapshotComponentIdentifier =
new MavenUniqueSnapshotComponentIdentifier(artifact.getId().getComponentIdentifier(), timestamp);
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactory.java
index 878fc16..46ed2b5 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactory.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactory.java
@@ -15,13 +15,16 @@
*/
package org.gradle.api.internal.artifacts.repositories.transport;
+import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
+import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
import org.gradle.api.InvalidUserDataException;
-import org.gradle.api.artifacts.repositories.PasswordCredentials;
import org.gradle.api.credentials.Credentials;
import org.gradle.api.internal.artifacts.ivyservice.CacheLockingManager;
import org.gradle.api.internal.file.TemporaryFileProvider;
+import org.gradle.authentication.Authentication;
+import org.gradle.internal.authentication.AuthenticationInternal;
import org.gradle.internal.resource.cached.CachedExternalResourceIndex;
import org.gradle.internal.resource.connector.ResourceConnectorFactory;
import org.gradle.internal.resource.connector.ResourceConnectorSpecification;
@@ -68,37 +71,33 @@ public class RepositoryTransportFactory {
public Set<String> getRegisteredProtocols() {
Set<String> validSchemes = Sets.newLinkedHashSet();
- validSchemes.add("file");
for (ResourceConnectorFactory registeredProtocol : registeredProtocols) {
validSchemes.addAll(registeredProtocol.getSupportedProtocols());
}
return validSchemes;
}
- public RepositoryTransport createTransport(String scheme, String name, Credentials credentials) {
- return createTransport(Collections.singleton(scheme), name, credentials);
+ public RepositoryTransport createTransport(String scheme, String name, Collection<Authentication> authentications) {
+ return createTransport(Collections.singleton(scheme), name, authentications);
}
- /**
- * TODO René: why do we have two different PasswordCredentials
- * */
- private org.gradle.internal.resource.PasswordCredentials convertPasswordCredentials(Credentials credentials) {
- if (!(credentials instanceof PasswordCredentials)) {
- throw new IllegalArgumentException(String.format("Credentials must be an instance of: %s", PasswordCredentials.class.getCanonicalName()));
- }
- PasswordCredentials passwordCredentials = (PasswordCredentials) credentials;
- return new org.gradle.internal.resource.PasswordCredentials(passwordCredentials.getUsername(), passwordCredentials.getPassword());
- }
-
- public RepositoryTransport createTransport(Set<String> schemes, String name, Credentials credentials) {
+ public RepositoryTransport createTransport(Set<String> schemes, String name, Collection<Authentication> authentications) {
validateSchemes(schemes);
+ ResourceConnectorFactory connectorFactory = findConnectorFactory(schemes);
+
+ // Ensure resource transport protocol, authentication types and credentials are all compatible
+ validateConnectorFactoryCredentials(schemes, connectorFactory, authentications);
+
// File resources are handled slightly differently at present.
+ // file:// repos are treated differently
+ // 1) we don't cache their files
+ // 2) we don't do progress logging for "downloading"
if (Collections.singleton("file").containsAll(schemes)) {
return new FileTransport(name);
}
- ResourceConnectorSpecification connectionDetails = new DefaultResourceConnectorSpecification(credentials);
- ExternalResourceConnector resourceConnector = findConnectorFactory(schemes).createResourceConnector(connectionDetails);
+ ResourceConnectorSpecification connectionDetails = new DefaultResourceConnectorSpecification(authentications);
+ ExternalResourceConnector resourceConnector = connectorFactory.createResourceConnector(connectionDetails);
return new ResourceConnectorRepositoryTransport(name, progressLoggerFactory, temporaryFileProvider, cachedExternalResourceIndex, timeProvider, cacheLockingManager, resourceConnector);
}
@@ -111,6 +110,42 @@ public class RepositoryTransportFactory {
}
}
+ private void validateConnectorFactoryCredentials(Set<String> schemes, ResourceConnectorFactory factory, Collection<Authentication> authentications) {
+ Multiset duplicatedAuthentications = HashMultiset.create();
+
+ for (Authentication authentication : authentications) {
+ AuthenticationInternal authenticationInternal = (AuthenticationInternal)authentication;
+ boolean isAuthenticationSupported = false;
+ Credentials credentials = authenticationInternal.getCredentials();
+
+ for (Class<?> authenticationType : factory.getSupportedAuthentication()) {
+ if (authenticationType.isAssignableFrom(authentication.getClass())) {
+ isAuthenticationSupported = true;
+ break;
+ }
+ }
+
+ if (!isAuthenticationSupported) {
+ throw new InvalidUserDataException(String.format("Authentication scheme %s is not supported by protocol '%s'",
+ authentication, schemes.iterator().next()));
+ }
+
+ if (credentials != null) {
+ if (!((AuthenticationInternal) authentication).supports(credentials)) {
+ throw new InvalidUserDataException(String.format("Credentials type of '%s' is not supported by authentication scheme %s",
+ credentials.getClass().getSimpleName(), authentication));
+ }
+ } else {
+ throw new InvalidUserDataException("You cannot configure authentication schemes for a repository if no credentials are provided.");
+ }
+
+ int count = duplicatedAuthentications.add(authenticationInternal.getType(), 1);
+ if (count > 0) {
+ throw new InvalidUserDataException(String.format("You cannot configure multiple authentication schemes of the same type. The duplicate one is %s.", authentication));
+ }
+ }
+ }
+
private ResourceConnectorFactory findConnectorFactory(Set<String> schemes) {
for (ResourceConnectorFactory protocolRegistration : registeredProtocols) {
if (protocolRegistration.getSupportedProtocols().containsAll(schemes)) {
@@ -121,19 +156,22 @@ public class RepositoryTransportFactory {
}
private class DefaultResourceConnectorSpecification implements ResourceConnectorSpecification {
- private final Credentials credentials;
+ private final Collection<Authentication> authentications;
- private DefaultResourceConnectorSpecification(Credentials credentials) {
- this.credentials = credentials;
+ private DefaultResourceConnectorSpecification(Collection<Authentication> authentications) {
+ this.authentications = authentications;
}
@Override
public <T> T getCredentials(Class<T> type) {
- if(credentials == null){
+ if (authentications == null || authentications.size() < 1) {
return null;
}
- if (org.gradle.internal.resource.PasswordCredentials.class.isAssignableFrom(type)) {
- return type.cast(convertPasswordCredentials(credentials));
+
+ Credentials credentials = ((AuthenticationInternal)authentications.iterator().next()).getCredentials();
+
+ if(credentials == null) {
+ return null;
}
if (type.isAssignableFrom(credentials.getClass())) {
return type.cast(credentials);
@@ -141,5 +179,10 @@ public class RepositoryTransportFactory {
throw new IllegalArgumentException(String.format("Credentials must be an instance of '%s'.", type.getCanonicalName()));
}
}
+
+ @Override
+ public Collection<Authentication> getAuthentications() {
+ return authentications;
+ }
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/BuildableIvyModulePublishMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/BuildableIvyModulePublishMetaData.java
index ae35b03..95ab293 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/BuildableIvyModulePublishMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/BuildableIvyModulePublishMetaData.java
@@ -17,23 +17,10 @@
package org.gradle.internal.component.external.model;
import org.apache.ivy.core.module.descriptor.Artifact;
-import org.apache.ivy.core.module.descriptor.ExcludeRule;
-import org.gradle.api.artifacts.PublishArtifact;
-import org.gradle.internal.component.local.model.LocalConfigurationMetaData;
-import org.gradle.internal.component.model.DependencyMetaData;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
import java.io.File;
-public interface BuildableIvyModulePublishMetaData extends IvyModulePublishMetaData {
- void addConfiguration(LocalConfigurationMetaData configuration);
-
- void addExcludeRule(ExcludeRule excludeRule);
-
- void addDependency(DependencyMetaData dependency);
-
- void addArtifact(IvyModuleArtifactPublishMetaData artifact);
-
+public interface BuildableIvyModulePublishMetaData extends IvyModulePublishMetaData, BuildableLocalComponentMetaData {
void addArtifact(Artifact artifact, File file);
-
- void addArtifact(String configuration, PublishArtifact publishArtifact);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaData.java
index 3f3b849..0a3c3ae 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaData.java
@@ -22,7 +22,8 @@ import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
import org.gradle.api.artifacts.PublishArtifact;
import org.gradle.api.internal.artifacts.ivyservice.IvyUtil;
-import org.gradle.internal.component.local.model.LocalConfigurationMetaData;
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData;
import org.gradle.internal.component.model.DefaultIvyArtifactName;
import org.gradle.internal.component.model.DependencyMetaData;
import org.gradle.internal.component.model.IvyArtifactName;
@@ -31,7 +32,7 @@ import org.gradle.util.WrapUtil;
import java.io.File;
import java.util.*;
-public class DefaultIvyModulePublishMetaData implements BuildableIvyModulePublishMetaData {
+public class DefaultIvyModulePublishMetaData implements BuildableIvyModulePublishMetaData, BuildableLocalComponentMetaData {
private final ModuleVersionIdentifier id;
private final DefaultModuleDescriptor moduleDescriptor;
private final Map<ModuleComponentArtifactIdentifier, IvyModuleArtifactPublishMetaData> artifactsById = new LinkedHashMap<ModuleComponentArtifactIdentifier, IvyModuleArtifactPublishMetaData>();
@@ -56,12 +57,11 @@ public class DefaultIvyModulePublishMetaData implements BuildableIvyModulePublis
}
@Override
- public void addConfiguration(LocalConfigurationMetaData configuration) {
- Set<String> extendsFrom = configuration.getExtendsFrom();
+ public void addConfiguration(String name, String description, Set<String> extendsFrom, Set<String> hierarchy, boolean visible, boolean transitive, TaskDependency buildDependencies) {
String[] superConfigs = extendsFrom.toArray(new String[extendsFrom.size()]);
Arrays.sort(superConfigs);
- Configuration.Visibility visibility = configuration.isVisible() ? Configuration.Visibility.PUBLIC : Configuration.Visibility.PRIVATE;
- Configuration conf = new Configuration(configuration.getName(), visibility, configuration.getDescription(), superConfigs, configuration.isTransitive(), null);
+ Configuration.Visibility visibility = visible ? Configuration.Visibility.PUBLIC : Configuration.Visibility.PRIVATE;
+ Configuration conf = new Configuration(name, visibility, description, superConfigs, transitive, null);
moduleDescriptor.addConfiguration(conf);
}
@@ -96,6 +96,15 @@ public class DefaultIvyModulePublishMetaData implements BuildableIvyModulePublis
}
}
+ @Override
+ public void addArtifacts(String configuration, Iterable<? extends PublishArtifact> artifacts) {
+ for (PublishArtifact artifact : artifacts) {
+ MDArtifact ivyArtifact = getOrCreate(DefaultIvyArtifactName.forPublishArtifact(artifact));
+ ivyArtifact.addConfiguration(configuration);
+ addArtifact(ivyArtifact, artifact.getFile());
+ }
+ }
+
public void addArtifact(Artifact artifact, File file) {
DefaultIvyModuleArtifactPublishMetaData publishMetaData = new DefaultIvyModuleArtifactPublishMetaData(id, artifact, file);
artifactsById.put(publishMetaData.getId(), publishMetaData);
@@ -105,13 +114,6 @@ public class DefaultIvyModulePublishMetaData implements BuildableIvyModulePublis
artifactsById.put(artifact.getId(), artifact);
}
- @Override
- public void addArtifact(String configuration, PublishArtifact publishArtifact) {
- MDArtifact artifact = getOrCreate(DefaultIvyArtifactName.forPublishArtifact(publishArtifact, getId().getName()));
- artifact.addConfiguration(configuration);
- addArtifact(artifact, publishArtifact.getFile());
- }
-
private MDArtifact getOrCreate(IvyArtifactName ivyName) {
for (IvyModuleArtifactPublishMetaData artifactPublishMetaData : artifactsById.values()) {
if (artifactPublishMetaData.getArtifactName().equals(ivyName)) {
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/ModuleComponentArtifactIdentifier.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/ModuleComponentArtifactIdentifier.java
index 0ac5e5d..24b6904 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/ModuleComponentArtifactIdentifier.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/external/model/ModuleComponentArtifactIdentifier.java
@@ -16,8 +16,8 @@
package org.gradle.internal.component.external.model;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
/**
* An immutable identifier for an artifact that belongs to some module version.
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/BuildableLocalComponentMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/BuildableLocalComponentMetaData.java
new file mode 100644
index 0000000..cbf33bd
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/BuildableLocalComponentMetaData.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.component.local.model;
+
+import org.apache.ivy.core.module.descriptor.ExcludeRule;
+import org.gradle.api.artifacts.PublishArtifact;
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.model.DependencyMetaData;
+
+import java.util.Set;
+
+public interface BuildableLocalComponentMetaData {
+ void addArtifacts(String configuration, Iterable<? extends PublishArtifact> artifacts);
+
+ void addConfiguration(String name, String description, Set<String> extendsFrom, Set<String> hierarchy, boolean visible, boolean transitive, TaskDependency buildDependencies);
+
+ void addDependency(DependencyMetaData dependency);
+
+ void addExcludeRule(ExcludeRule excludeRule);
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryBinaryIdentifier.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryBinaryIdentifier.java
new file mode 100644
index 0000000..c91dd3b
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryBinaryIdentifier.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.internal.component.local.model;
+
+import com.google.common.base.Objects;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
+
+public class DefaultLibraryBinaryIdentifier implements LibraryBinaryIdentifier {
+ public static final String CONFIGURATION_NAME = "Component configuration";
+
+ private final String projectPath;
+ private final String libraryName;
+ private final String displayName;
+ private final String variant;
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public DefaultLibraryBinaryIdentifier(String projectPath, String libraryName, String variant) {
+ assert projectPath != null : "project path cannot be null";
+ assert libraryName != null : "library name cannot be null";
+ assert variant != null : "variant cannot be null";
+ this.projectPath = projectPath;
+ this.libraryName = libraryName;
+ this.variant = variant;
+ this.displayName = String.format("project '%s' library '%s' variant '%s'", projectPath, libraryName, variant);
+ }
+
+ @Override
+ public String getProjectPath() {
+ return projectPath;
+ }
+
+ @Override
+ public String getLibraryName() {
+ return libraryName;
+ }
+
+ @Override
+ public String getVariant() {
+ return variant;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DefaultLibraryBinaryIdentifier that = (DefaultLibraryBinaryIdentifier) o;
+ return Objects.equal(projectPath, that.projectPath)
+ && Objects.equal(libraryName, that.libraryName)
+ && Objects.equal(variant, that.variant);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(projectPath, libraryName, variant);
+ }
+
+ @Override
+ public String toString() {
+ return getDisplayName();
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryComponentIdentifier.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryComponentIdentifier.java
deleted file mode 100644
index 836d626..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryComponentIdentifier.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.internal.component.local.model;
-
-import com.google.common.base.Objects;
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier;
-
-public class DefaultLibraryComponentIdentifier implements LibraryComponentIdentifier {
- private final String projectPath;
- private final String libraryName;
- private final String displayName;
-
- public static String libraryToConfigurationName(String projectPath, String libraryName) {
- return String.format("project %s library %s", projectPath, libraryName);
- }
-
- public String getDisplayName() {
- return displayName;
- }
-
- public DefaultLibraryComponentIdentifier(String projectPath, String libraryName) {
- assert projectPath != null : "project path cannot be null";
- assert libraryName != null : "library name cannot be null";
- this.projectPath = projectPath;
- this.libraryName = libraryName;
- this.displayName = libraryToConfigurationName(projectPath, libraryName);
- }
-
- @Override
- public String getProjectPath() {
- return projectPath;
- }
-
- @Override
- public String getLibraryName() {
- return libraryName;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- DefaultLibraryComponentIdentifier that = (DefaultLibraryComponentIdentifier) o;
- return Objects.equal(projectPath, that.projectPath)
- && Objects.equal(libraryName, that.libraryName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(projectPath, libraryName);
- }
-
- @Override
- public String toString() {
- return getDisplayName();
- }
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryComponentSelector.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryComponentSelector.java
index 84e7543..b8b6355 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryComponentSelector.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLibraryComponentSelector.java
@@ -17,8 +17,9 @@
package org.gradle.internal.component.local.model;
import com.google.common.base.Objects;
+import com.google.common.base.Strings;
import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
import org.gradle.api.artifacts.component.LibraryComponentSelector;
public class DefaultLibraryComponentSelector implements LibraryComponentSelector {
@@ -26,15 +27,20 @@ public class DefaultLibraryComponentSelector implements LibraryComponentSelector
private final String libraryName;
public DefaultLibraryComponentSelector(String projectPath, String libraryName) {
- assert projectPath != null : "project path cannot be null";
- assert libraryName != null : "library name cannot be null";
+ assert !Strings.isNullOrEmpty(projectPath) : "project path cannot be null or empty";
this.projectPath = projectPath;
- this.libraryName = libraryName;
+ this.libraryName = Strings.emptyToNull(libraryName);
}
@Override
public String getDisplayName() {
- return DefaultLibraryComponentIdentifier.libraryToConfigurationName(getProjectPath(), getLibraryName());
+ String txt;
+ if (Strings.isNullOrEmpty(libraryName)) {
+ txt = String.format("project '%s'", projectPath);
+ } else {
+ txt = String.format("project '%s' library '%s'", projectPath, libraryName);
+ }
+ return txt;
}
@Override
@@ -50,9 +56,10 @@ public class DefaultLibraryComponentSelector implements LibraryComponentSelector
public boolean matchesStrictly(ComponentIdentifier identifier) {
assert identifier != null : "identifier cannot be null";
- if (identifier instanceof LibraryComponentIdentifier) {
- LibraryComponentIdentifier projectComponentIdentifier = (LibraryComponentIdentifier) identifier;
- return projectPath.equals(projectComponentIdentifier.getProjectPath()) && libraryName.equals(projectComponentIdentifier.getLibraryName());
+ if (identifier instanceof LibraryBinaryIdentifier) {
+ LibraryBinaryIdentifier projectComponentIdentifier = (LibraryBinaryIdentifier) identifier;
+ return projectPath.equals(projectComponentIdentifier.getProjectPath())
+ && projectComponentIdentifier.getLibraryName().equals(libraryName);
}
return false;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLocalComponentMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLocalComponentMetaData.java
index 7e5ddc9..31c4b45 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLocalComponentMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/DefaultLocalComponentMetaData.java
@@ -23,13 +23,12 @@ import org.apache.ivy.core.module.descriptor.ExcludeRule;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
import org.gradle.api.artifacts.PublishArtifact;
import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.internal.component.external.model.BuildableIvyModulePublishMetaData;
-import org.gradle.internal.component.external.model.DefaultIvyModulePublishMetaData;
+import org.gradle.api.tasks.TaskDependency;
import org.gradle.internal.component.model.*;
import java.util.*;
-public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaData {
+public class DefaultLocalComponentMetaData implements LocalComponentMetaData, BuildableLocalComponentMetaData {
private final Map<String, DefaultLocalConfigurationMetaData> allConfigurations = Maps.newHashMap();
private final Map<String, Iterable<? extends PublishArtifact>> allArtifacts = Maps.newHashMap();
private final List<DependencyMetaData> allDependencies = Lists.newArrayList();
@@ -52,8 +51,8 @@ public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaD
allArtifacts.put(configuration, artifacts);
}
- public void addConfiguration(String name, String description, Set<String> extendsFrom, Set<String> hierarchy, boolean visible, boolean transitive) {
- DefaultLocalConfigurationMetaData conf = new DefaultLocalConfigurationMetaData(name, description, visible, transitive, extendsFrom, hierarchy);
+ public void addConfiguration(String name, String description, Set<String> extendsFrom, Set<String> hierarchy, boolean visible, boolean transitive, TaskDependency buildDependencies) {
+ DefaultLocalConfigurationMetaData conf = new DefaultLocalConfigurationMetaData(name, description, visible, transitive, extendsFrom, hierarchy, buildDependencies);
allConfigurations.put(name, conf);
}
@@ -65,87 +64,50 @@ public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaD
allExcludeRules.add(excludeRule);
}
- public ComponentResolveMetaData toResolveMetaData() {
- return new DefaultLocalComponentResolveMetaData();
+ @Override
+ public String toString() {
+ return componentIdentifier.getDisplayName();
}
- public BuildableIvyModulePublishMetaData toPublishMetaData() {
- DefaultIvyModulePublishMetaData publishMetaData = new DefaultIvyModulePublishMetaData(id, status);
- for (DefaultLocalConfigurationMetaData configuration : allConfigurations.values()) {
- publishMetaData.addConfiguration(configuration);
- }
- for (ExcludeRule excludeRule : allExcludeRules) {
- publishMetaData.addExcludeRule(excludeRule);
- }
- for (DependencyMetaData dependency : allDependencies) {
- publishMetaData.addDependency(dependency);
- }
- for (String configuration : allArtifacts.keySet()) {
- Iterable<? extends PublishArtifact> publishArtifacts = allArtifacts.get(configuration);
- for (PublishArtifact publishArtifact : publishArtifacts) {
- publishMetaData.addArtifact(configuration, publishArtifact);
- }
- }
- return publishMetaData;
+ public ModuleSource getSource() {
+ return null;
}
- private class DefaultLocalComponentResolveMetaData implements ComponentResolveMetaData {
- private ModuleVersionIdentifier moduleVersionIdentifier;
-
- public DefaultLocalComponentResolveMetaData() {
- this.moduleVersionIdentifier = id;
- }
-
- @Override
- public String toString() {
- return componentIdentifier.getDisplayName();
- }
-
- public ModuleVersionIdentifier getId() {
- return moduleVersionIdentifier;
- }
-
- public ModuleSource getSource() {
- return null;
- }
-
- public ComponentResolveMetaData withSource(ModuleSource source) {
- throw new UnsupportedOperationException();
- }
-
- public boolean isGenerated() {
- return false;
- }
+ public ComponentResolveMetaData withSource(ModuleSource source) {
+ throw new UnsupportedOperationException();
+ }
- public boolean isChanging() {
- return false;
- }
+ public boolean isGenerated() {
+ return false;
+ }
- public String getStatus() {
- return status;
- }
+ public boolean isChanging() {
+ return false;
+ }
- public List<String> getStatusScheme() {
- return DEFAULT_STATUS_SCHEME;
- }
+ public String getStatus() {
+ return status;
+ }
- public ComponentIdentifier getComponentId() {
- return componentIdentifier;
- }
+ public List<String> getStatusScheme() {
+ return DEFAULT_STATUS_SCHEME;
+ }
- public List<DependencyMetaData> getDependencies() {
- return allDependencies;
- }
+ public ComponentIdentifier getComponentId() {
+ return componentIdentifier;
+ }
- @Override
- public Set<String> getConfigurationNames() {
- return allConfigurations.keySet();
- }
+ public List<DependencyMetaData> getDependencies() {
+ return allDependencies;
+ }
- public DefaultLocalConfigurationMetaData getConfiguration(final String name) {
- return allConfigurations.get(name);
- }
+ @Override
+ public Set<String> getConfigurationNames() {
+ return allConfigurations.keySet();
+ }
+ public DefaultLocalConfigurationMetaData getConfiguration(final String name) {
+ return allConfigurations.get(name);
}
private class DefaultLocalConfigurationMetaData implements LocalConfigurationMetaData {
@@ -155,17 +117,19 @@ public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaD
private final boolean visible;
private final Set<String> hierarchy;
private final Set<String> extendsFrom;
+ private final TaskDependency buildDependencies;
private List<DependencyMetaData> configurationDependencies;
private LinkedHashSet<ExcludeRule> configurationExcludeRules;
- private DefaultLocalConfigurationMetaData(String name, String description, boolean visible, boolean transitive, Set<String> extendsFrom, Set<String> hierarchy) {
+ private DefaultLocalConfigurationMetaData(String name, String description, boolean visible, boolean transitive, Set<String> extendsFrom, Set<String> hierarchy, TaskDependency buildDependencies) {
this.name = name;
this.description = description;
this.transitive = transitive;
this.visible = visible;
this.hierarchy = hierarchy;
this.extendsFrom = extendsFrom;
+ this.buildDependencies = buildDependencies;
}
@Override
@@ -174,7 +138,12 @@ public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaD
}
public ComponentResolveMetaData getComponent() {
- return new DefaultLocalComponentResolveMetaData();
+ return DefaultLocalComponentMetaData.this;
+ }
+
+ @Override
+ public TaskDependency getDirectBuildDependencies() {
+ return buildDependencies;
}
public String getDescription() {
@@ -252,7 +221,7 @@ public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaD
}
public Set<ComponentArtifactMetaData> getArtifacts() {
- return DefaultLocalComponentMetaData.getArtifacts(componentIdentifier, id, getHierarchy(), allArtifacts);
+ return DefaultLocalComponentMetaData.getArtifacts(componentIdentifier, getHierarchy(), allArtifacts);
}
public ComponentArtifactMetaData artifact(IvyArtifactName ivyArtifactName) {
@@ -266,8 +235,7 @@ public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaD
}
}
- static Set<ComponentArtifactMetaData> getArtifacts(ComponentIdentifier componentIdentifier, ModuleVersionIdentifier moduleVersionIdentifier,
- Set<String> configurationHierarchy, Map<String, Iterable<? extends PublishArtifact>> allArtifacts) {
+ static Set<ComponentArtifactMetaData> getArtifacts(ComponentIdentifier componentIdentifier, Set<String> configurationHierarchy, Map<String, Iterable<? extends PublishArtifact>> allArtifacts) {
Set<PublishArtifact> seen = Sets.newHashSet();
Set<ComponentArtifactMetaData> artifacts = Sets.newLinkedHashSet();
@@ -276,7 +244,7 @@ public class DefaultLocalComponentMetaData implements MutableLocalComponentMetaD
if (publishArtifacts != null) {
for (PublishArtifact publishArtifact : publishArtifacts) {
if (seen.add(publishArtifact)) {
- artifacts.add(new PublishArtifactLocalArtifactMetaData(componentIdentifier, componentIdentifier.getDisplayName(), moduleVersionIdentifier.getName(), publishArtifact));
+ artifacts.add(new PublishArtifactLocalArtifactMetaData(componentIdentifier, componentIdentifier.getDisplayName(), publishArtifact));
}
}
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentArtifactIdentifier.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentArtifactIdentifier.java
index d43c72c..2c94391 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentArtifactIdentifier.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentArtifactIdentifier.java
@@ -16,7 +16,7 @@
package org.gradle.internal.component.local.model;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import java.io.File;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentMetaData.java
index 7a4689e..5bd4ad0 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalComponentMetaData.java
@@ -16,21 +16,7 @@
package org.gradle.internal.component.local.model;
-import org.gradle.api.artifacts.ModuleVersionIdentifier;
-import org.gradle.internal.component.external.model.BuildableIvyModulePublishMetaData;
import org.gradle.internal.component.model.ComponentResolveMetaData;
-public interface LocalComponentMetaData {
- ModuleVersionIdentifier getId();
-
- /**
- * Converts this component to resolve meta-data.
- */
- ComponentResolveMetaData toResolveMetaData();
-
- /**
- * Converts this component to publication meta-data.
- */
- BuildableIvyModulePublishMetaData toPublishMetaData();
-
+public interface LocalComponentMetaData extends ComponentResolveMetaData {
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalConfigurationMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalConfigurationMetaData.java
index 0ce0b0d..7724185 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalConfigurationMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/LocalConfigurationMetaData.java
@@ -16,6 +16,7 @@
package org.gradle.internal.component.local.model;
+import org.gradle.api.tasks.TaskDependency;
import org.gradle.internal.component.model.ConfigurationMetaData;
import java.util.Set;
@@ -25,4 +26,9 @@ public interface LocalConfigurationMetaData extends ConfigurationMetaData {
String getDescription();
Set<String> getExtendsFrom();
+
+ /**
+ * The task dependencies required to build any artifacts and self-resolving dependencies for this configuration.
+ */
+ TaskDependency getDirectBuildDependencies();
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/MutableLocalComponentMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/MutableLocalComponentMetaData.java
deleted file mode 100644
index 0daeece..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/MutableLocalComponentMetaData.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.component.local.model;
-
-import org.apache.ivy.core.module.descriptor.ExcludeRule;
-import org.gradle.api.artifacts.PublishArtifact;
-import org.gradle.internal.component.model.DependencyMetaData;
-
-import java.util.Set;
-
-public interface MutableLocalComponentMetaData extends LocalComponentMetaData {
- void addArtifacts(String configuration, Iterable<? extends PublishArtifact> artifacts);
-
- void addConfiguration(String name, String description, Set<String> extendsFrom, Set<String> hierarchy, boolean visible, boolean transitive);
-
- void addDependency(DependencyMetaData dependency);
-
- void addExcludeRule(ExcludeRule excludeRule);
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/PublishArtifactLocalArtifactMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/PublishArtifactLocalArtifactMetaData.java
index c54e772..772179d 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/PublishArtifactLocalArtifactMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/local/model/PublishArtifactLocalArtifactMetaData.java
@@ -16,8 +16,10 @@
package org.gradle.internal.component.local.model;
+import org.gradle.api.Buildable;
import org.gradle.api.artifacts.PublishArtifact;
import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.tasks.TaskDependency;
import org.gradle.internal.component.model.ComponentArtifactMetaData;
import org.gradle.internal.component.model.DefaultIvyArtifactName;
import org.gradle.internal.component.model.IvyArtifactName;
@@ -25,16 +27,14 @@ import org.gradle.util.GUtil;
import java.io.File;
-public class PublishArtifactLocalArtifactMetaData implements LocalComponentArtifactIdentifier, ComponentArtifactMetaData {
+public class PublishArtifactLocalArtifactMetaData implements LocalComponentArtifactIdentifier, ComponentArtifactMetaData, Buildable {
private final ComponentIdentifier componentIdentifier;
- private final String moduleName;
private final String componentDisplayName;
private final PublishArtifact publishArtifact;
// The componentDisplayName parameter is temporary
- public PublishArtifactLocalArtifactMetaData(ComponentIdentifier componentIdentifier, String moduleName, String componentDisplayName, PublishArtifact publishArtifact) {
+ public PublishArtifactLocalArtifactMetaData(ComponentIdentifier componentIdentifier, String componentDisplayName, PublishArtifact publishArtifact) {
this.componentIdentifier = componentIdentifier;
- this.moduleName = moduleName;
this.componentDisplayName = componentDisplayName;
this.publishArtifact = publishArtifact;
}
@@ -84,7 +84,7 @@ public class PublishArtifactLocalArtifactMetaData implements LocalComponentArtif
@Override
public IvyArtifactName getName() {
- return DefaultIvyArtifactName.forPublishArtifact(publishArtifact, moduleName);
+ return DefaultIvyArtifactName.forPublishArtifact(publishArtifact);
}
@Override
@@ -103,4 +103,9 @@ public class PublishArtifactLocalArtifactMetaData implements LocalComponentArtif
PublishArtifactLocalArtifactMetaData other = (PublishArtifactLocalArtifactMetaData) obj;
return other.componentIdentifier.equals(componentIdentifier) && other.publishArtifact.equals(publishArtifact);
}
+
+ @Override
+ public TaskDependency getBuildDependencies() {
+ return publishArtifact.getBuildDependencies();
+ }
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentArtifactIdentifier.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentArtifactIdentifier.java
deleted file mode 100644
index 140f83f..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentArtifactIdentifier.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.component.model;
-
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-
-/**
- * An immutable identifier for an artifact that belongs to some component instance.
- */
-public interface ComponentArtifactIdentifier {
- /**
- * Returns the id of the component that this artifact belongs to.
- */
- ComponentIdentifier getComponentIdentifier();
-
- /**
- * Returns some human-consumable display name for this artifact.
- */
- String getDisplayName();
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentArtifactMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentArtifactMetaData.java
index 0c6a257..a9d0b47 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentArtifactMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentArtifactMetaData.java
@@ -16,6 +16,7 @@
package org.gradle.internal.component.model;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.api.artifacts.component.ComponentIdentifier;
/**
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentResolveMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentResolveMetaData.java
index 72d5e90..6f16099 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentResolveMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ComponentResolveMetaData.java
@@ -59,7 +59,6 @@ public interface ComponentResolveMetaData {
/**
* Returns the names of all of the configurations for this component.
*/
- // TODO:DAZ Maybe getConfigurations() would be better?
Set<String> getConfigurationNames();
/**
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/DefaultIvyArtifactName.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/DefaultIvyArtifactName.java
index 0734df7..2e6439a 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/DefaultIvyArtifactName.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/DefaultIvyArtifactName.java
@@ -42,8 +42,11 @@ public class DefaultIvyArtifactName implements IvyArtifactName {
return new DefaultIvyArtifactName(a.getName(), a.getType(), a.getExt(), a.getExtraAttributes());
}
- public static DefaultIvyArtifactName forPublishArtifact(PublishArtifact publishArtifact, String moduleName) {
- String name = GUtil.elvis(publishArtifact.getName(), moduleName);
+ public static DefaultIvyArtifactName forPublishArtifact(PublishArtifact publishArtifact) {
+ String name = publishArtifact.getName();
+ if (name == null) {
+ name = publishArtifact.getFile().getName();
+ }
String classifier = GUtil.elvis(publishArtifact.getClassifier(), null);
return new DefaultIvyArtifactName(name, publishArtifact.getType(), publishArtifact.getExtension(), classifier);
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/DefaultModuleDescriptorArtifactMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/DefaultModuleDescriptorArtifactMetaData.java
new file mode 100644
index 0000000..7266c03
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/DefaultModuleDescriptorArtifactMetaData.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.component.model;
+
+import org.gradle.api.artifacts.ArtifactIdentifier;
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.internal.component.external.model.DefaultModuleComponentArtifactMetaData;
+import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier;
+
+public class DefaultModuleDescriptorArtifactMetaData implements ModuleDescriptorArtifactMetaData {
+ private final DefaultModuleComponentArtifactMetaData delegate;
+
+ public DefaultModuleDescriptorArtifactMetaData(DefaultModuleComponentArtifactMetaData delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public ModuleComponentArtifactIdentifier getId() {
+ return delegate.getId();
+ }
+
+ @Override
+ public ArtifactIdentifier toArtifactIdentifier() {
+ return delegate.toArtifactIdentifier();
+ }
+
+ @Override
+ public ComponentIdentifier getComponentId() {
+ return delegate.getComponentId();
+ }
+
+ @Override
+ public IvyArtifactName getName() {
+ return delegate.getName();
+ }
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/LocalComponentDependencyMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/LocalComponentDependencyMetaData.java
index 8337560..17708d5 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/LocalComponentDependencyMetaData.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/LocalComponentDependencyMetaData.java
@@ -56,7 +56,6 @@ public class LocalComponentDependencyMetaData implements DependencyMetaData {
@Override
public String toString() {
- // TODO:DAZ Improve this copy from Ivy
return "dependency: " + requested + " " + moduleConfiguration;
}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ModuleComponentArtifactsMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ModuleComponentArtifactsMetaData.java
deleted file mode 100644
index ffc0622..0000000
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ModuleComponentArtifactsMetaData.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.component.model;
-
-public interface ModuleComponentArtifactsMetaData {
-}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ModuleDescriptorArtifactMetaData.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ModuleDescriptorArtifactMetaData.java
new file mode 100644
index 0000000..14179dd
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/component/model/ModuleDescriptorArtifactMetaData.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.component.model;
+
+import org.gradle.internal.component.external.model.ModuleComponentArtifactMetaData;
+
+public interface ModuleDescriptorArtifactMetaData extends ModuleComponentArtifactMetaData {
+}
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactNotFoundException.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactNotFoundException.java
index 55f443f..37a7428 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactNotFoundException.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactNotFoundException.java
@@ -15,7 +15,7 @@
*/
package org.gradle.internal.resolve;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import java.util.List;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactResolveException.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactResolveException.java
index 0e17031..2dfa4af 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactResolveException.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/ArtifactResolveException.java
@@ -16,8 +16,8 @@
package org.gradle.internal.resolve;
import org.gradle.api.GradleException;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
import org.gradle.internal.exceptions.Contextual;
import org.gradle.util.GUtil;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/ResolveContextToComponentResolver.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/ResolveContextToComponentResolver.java
index 138fc8f..5a5a27a 100755
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/ResolveContextToComponentResolver.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/resolver/ResolveContextToComponentResolver.java
@@ -16,7 +16,7 @@
package org.gradle.internal.resolve.resolver;
-import org.gradle.api.artifacts.ResolveContext;
+import org.gradle.api.internal.artifacts.ResolveContext;
import org.gradle.internal.resolve.result.BuildableComponentResolveResult;
/**
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/BuildableArtifactResolveResult.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/BuildableArtifactResolveResult.java
index 9774d6e..08200e6 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/BuildableArtifactResolveResult.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/BuildableArtifactResolveResult.java
@@ -16,8 +16,8 @@
package org.gradle.internal.resolve.result;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.internal.resolve.ArtifactResolveException;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
import java.io.File;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResult.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResult.java
index 4a9f7fb..4b1f828 100644
--- a/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResult.java
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResult.java
@@ -16,9 +16,9 @@
package org.gradle.internal.resolve.result;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.internal.resolve.ArtifactNotFoundException;
import org.gradle.internal.resolve.ArtifactResolveException;
-import org.gradle.internal.component.model.ComponentArtifactIdentifier;
import java.io.File;
diff --git a/subprojects/dependency-management/src/main/java/org/gradle/internal/resource/transport/file/FileConnectorFactory.java b/subprojects/dependency-management/src/main/java/org/gradle/internal/resource/transport/file/FileConnectorFactory.java
new file mode 100644
index 0000000..04c568f
--- /dev/null
+++ b/subprojects/dependency-management/src/main/java/org/gradle/internal/resource/transport/file/FileConnectorFactory.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.resource.transport.file;
+
+import com.google.common.collect.Sets;
+import org.gradle.authentication.Authentication;
+import org.gradle.internal.resource.connector.ResourceConnectorFactory;
+import org.gradle.internal.resource.connector.ResourceConnectorSpecification;
+import org.gradle.internal.resource.transfer.ExternalResourceConnector;
+
+import java.util.Set;
+
+public class FileConnectorFactory implements ResourceConnectorFactory {
+ @Override
+ public Set<String> getSupportedProtocols() {
+ return Sets.newHashSet("file");
+ }
+
+ @Override
+ public Set<Class<? extends Authentication>> getSupportedAuthentication() {
+ return Sets.newHashSet();
+ }
+
+ @Override
+ public ExternalResourceConnector createResourceConnector(ResourceConnectorSpecification connectionDetails) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedArtifactTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedArtifactTest.groovy
index 3f668ea..5849db7 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedArtifactTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedArtifactTest.groovy
@@ -16,8 +16,9 @@
package org.gradle.api.internal.artifacts
import org.gradle.api.artifacts.ResolvedModuleVersion
-import org.gradle.internal.component.model.IvyArtifactName
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier
import org.gradle.internal.Factory
+import org.gradle.internal.component.model.IvyArtifactName
import org.gradle.util.Matchers
import spock.lang.Specification
@@ -29,10 +30,11 @@ class DefaultResolvedArtifactTest extends Specification {
def dependencySameModule = dep("group", "module1", "1.2")
def dependency2 = dep("group", "module2", "1-beta")
def ivyArt = Stub(IvyArtifactName)
- def artifact = new DefaultResolvedArtifact(dependency, ivyArt, artifactSource)
- def equalArtifact = new DefaultResolvedArtifact(dependencySameModule, ivyArt, artifactSource)
- def differentModule = new DefaultResolvedArtifact(dependency2, ivyArt, artifactSource)
- def differentName = new DefaultResolvedArtifact(dependency, Stub(IvyArtifactName), artifactSource)
+ def artifactId = Mock(ComponentArtifactIdentifier)
+ def artifact = new DefaultResolvedArtifact(dependency, ivyArt, artifactId, artifactSource)
+ def equalArtifact = new DefaultResolvedArtifact(dependencySameModule, ivyArt, artifactId, artifactSource)
+ def differentModule = new DefaultResolvedArtifact(dependency2, ivyArt, artifactId, artifactSource)
+ def differentName = new DefaultResolvedArtifact(dependency, Stub(IvyArtifactName), artifactId, artifactSource)
expect:
artifact Matchers.strictlyEqual(equalArtifact)
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedDependencyTest.java b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedDependencyTest.java
index 439f3e1..521d1ee 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedDependencyTest.java
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolvedDependencyTest.java
@@ -19,8 +19,9 @@ import org.gradle.api.InvalidUserDataException;
import org.gradle.api.artifacts.ResolvedArtifact;
import org.gradle.api.artifacts.ResolvedDependency;
import org.gradle.api.artifacts.ResolvedModuleVersion;
-import org.gradle.internal.component.model.IvyArtifactName;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
import org.gradle.internal.Factory;
+import org.gradle.internal.component.model.IvyArtifactName;
import org.gradle.util.JUnit4GroovyMockery;
import org.jmock.Expectations;
import org.jmock.Mockery;
@@ -115,7 +116,7 @@ public class DefaultResolvedDependencyTest {
allowing(version).getId();
will(returnValue(new DefaultModuleVersionIdentifier("group", name, "1.2")));
}});
- return new DefaultResolvedArtifact(resolvedDependency.getModule(), artifactStub, artifactSource);
+ return new DefaultResolvedArtifact(resolvedDependency.getModule(), artifactStub, context.mock(ComponentArtifactIdentifier.class), artifactSource);
}
private DefaultResolvedDependency createResolvedDependency() {
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolverResultsSpec.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolverResultsSpec.groovy
new file mode 100644
index 0000000..65763ec
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/DefaultResolverResultsSpec.groovy
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts
+
+import org.gradle.api.artifacts.ResolveException
+import org.gradle.api.artifacts.ResolvedConfiguration
+import org.gradle.api.artifacts.result.ResolutionResult
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResult
+import spock.lang.Specification
+
+class DefaultResolverResultsSpec extends Specification {
+ private resolvedConfiguration = Mock(ResolvedConfiguration)
+ private resolutionResult = Mock(ResolutionResult)
+ private projectConfigurationResult = Mock(ResolvedLocalComponentsResult)
+ private fatalFailure = Mock(ResolveException)
+ private results = new DefaultResolverResults()
+
+ def "does not provide ResolutionResult in case of fatal failure"() {
+ when:
+ results.failed(fatalFailure)
+
+ and:
+ results.resolutionResult
+
+ then:
+ def ex = thrown(ResolveException)
+ ex == fatalFailure
+ }
+
+ def "provides resolve results"() {
+ when:
+ results.resolved(resolutionResult, projectConfigurationResult)
+ results.withResolvedConfiguration(resolvedConfiguration)
+
+ then:
+ results.resolvedConfiguration == resolvedConfiguration
+ results.resolutionResult == resolutionResult
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ResolverResultsSpec.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ResolverResultsSpec.groovy
deleted file mode 100644
index acaa092..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ResolverResultsSpec.groovy
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts
-
-import org.gradle.api.Action
-import org.gradle.api.artifacts.ResolveException
-import org.gradle.api.artifacts.ResolvedConfiguration
-import org.gradle.api.artifacts.result.ResolutionResult
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfiguration
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResults
-import spock.lang.Specification
-
-class ResolverResultsSpec extends Specification {
- private resolvedConfiguration = Mock(ResolvedConfiguration)
- private resolutionResult = Mock(ResolutionResult)
- private projectConfigurationResult = Mock(ResolvedProjectConfigurationResults)
- private fatalFailure = Mock(ResolveException)
- private results = new ResolverResults()
-
- def "does not provide ResolutionResult in case of fatal failure"() {
- when:
- results.failed(fatalFailure)
-
- and:
- results.resolutionResult
-
- then:
- def ex = thrown(ResolveException)
- ex == fatalFailure
- }
-
- def "provides resolve results"() {
- when:
- results.resolved(resolutionResult, projectConfigurationResult)
- results.withResolvedConfiguration(resolvedConfiguration)
-
- then:
- results.resolvedConfiguration == resolvedConfiguration
- results.resolutionResult == resolutionResult
- }
-
- def "performs action for each resolved project configuration"() {
- Action<ResolvedProjectConfiguration> action = Mock(Action)
- def projectConfiguration = Mock(ResolvedProjectConfiguration)
-
- projectConfigurationResult.get() >> [projectConfiguration]
-
- when:
- results.resolved(resolutionResult, projectConfigurationResult)
- results.eachResolvedProject(action)
-
- then:
- 1 * action.execute(projectConfiguration)
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy
index 60dcd50..98204c2 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy
@@ -24,11 +24,12 @@ import org.gradle.api.artifacts.result.ResolutionResult
import org.gradle.api.internal.artifacts.ConfigurationResolver
import org.gradle.api.internal.artifacts.DefaultExcludeRule
import org.gradle.api.internal.artifacts.DefaultPublishArtifactSet
-import org.gradle.api.internal.artifacts.ResolverResults
+import org.gradle.api.internal.artifacts.DefaultResolverResults
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
import org.gradle.api.internal.artifacts.dsl.dependencies.ProjectFinder
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResults
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResult
import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact
+import org.gradle.api.internal.tasks.DefaultTaskDependency
import org.gradle.api.specs.Spec
import org.gradle.api.tasks.TaskDependency
import org.gradle.initialization.ProjectAccessListener
@@ -301,10 +302,10 @@ class DefaultConfigurationSpec extends Specification {
def "state indicates failure resolving graph"() {
given:
def configuration = conf()
- def failure = new ResolveException(configuration, new RuntimeException())
+ def failure = new ResolveException("bad", new RuntimeException())
and:
- _ * resolver.resolve(_, _) >> { ConfigurationInternal config, ResolverResults resolverResults ->
+ _ * resolver.resolve(_, _) >> { ConfigurationInternal config, DefaultResolverResults resolverResults ->
resolverResults.failed(failure)
}
_ * resolutionStrategy.resolveGraphToDetermineTaskDependencies() >> true
@@ -428,11 +429,11 @@ class DefaultConfigurationSpec extends Specification {
private void expectResolved(ResolvedConfiguration resolvedConfiguration) {
def resolutionResults = Mock(ResolutionResult)
- def projectConfigurationResults = Mock(ResolvedProjectConfigurationResults)
+ def localComponentsResult = Mock(ResolvedLocalComponentsResult)
- _ * projectConfigurationResults.get() >> Collections.emptySet()
- _ * resolver.resolve(_, _) >> { ConfigurationInternal config, ResolverResults resolverResults ->
- resolverResults.resolved(resolutionResults, projectConfigurationResults)
+ _ * localComponentsResult.resolvedProjectConfigurations >> Collections.emptySet()
+ _ * resolver.resolve(_, _) >> { ConfigurationInternal config, DefaultResolverResults resolverResults ->
+ resolverResults.resolved(resolutionResults, localComponentsResult)
resolverResults.withResolvedConfiguration(resolvedConfiguration)
}
}
@@ -786,8 +787,8 @@ class DefaultConfigurationSpec extends Specification {
TaskDependency taskDep = Mock()
def config = conf("conf")
def resolvedConfiguration = Mock(ResolvedConfiguration)
- def resolverResults = new ResolverResults()
- def projectConfigurationResults = Mock(ResolvedProjectConfigurationResults)
+ def resolverResults = new DefaultResolverResults()
+ def projectConfigurationResults = Mock(ResolvedLocalComponentsResult)
given:
config.dependencies.add(dependency)
@@ -801,7 +802,7 @@ class DefaultConfigurationSpec extends Specification {
fileTaskDeps == [task] as Set
_ * resolutionStrategy.resolveGraphToDetermineTaskDependencies() >> false
_ * resolvedConfiguration.hasError() >> false
- _ * resolver.resolve(config, _) >> { ConfigurationInternal conf, ResolverResults res ->
+ _ * resolver.resolve(config, _) >> { ConfigurationInternal conf, DefaultResolverResults res ->
res.resolved(Mock(ResolutionResult), projectConfigurationResults)
}
_ * projectConfigurationResults.get() >> []
@@ -923,12 +924,13 @@ class DefaultConfigurationSpec extends Specification {
}
def resolves(ConfigurationInternal config, ResolutionResult resolutionResult, ResolvedConfiguration resolvedConfiguration) {
- def projectConfigurationResults = Mock(ResolvedProjectConfigurationResults)
- projectConfigurationResults.get() >> []
- resolver.resolve(config, _) >> { ConfigurationInternal conf, ResolverResults res ->
- res.resolved(resolutionResult, projectConfigurationResults)
+ def localComponentsResult = Mock(ResolvedLocalComponentsResult)
+ localComponentsResult.resolvedProjectConfigurations >> []
+ localComponentsResult.componentBuildDependencies >> new DefaultTaskDependency()
+ resolver.resolve(config, _) >> { ConfigurationInternal conf, DefaultResolverResults res ->
+ res.resolved(resolutionResult, localComponentsResult)
}
- resolver.resolveArtifacts(config, _) >> { ConfigurationInternal conf, ResolverResults res ->
+ resolver.resolveArtifacts(config, _) >> { ConfigurationInternal conf, DefaultResolverResults res ->
res.withResolvedConfiguration(resolvedConfiguration)
}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolverTest.groovy
index fb88c75..10e226b 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolverTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/CacheLockingArtifactDependencyResolverTest.groovy
@@ -14,32 +14,33 @@
* limitations under the License.
*/
package org.gradle.api.internal.artifacts.ivyservice
-
import org.gradle.api.internal.artifacts.ArtifactDependencyResolver
import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules
-import org.gradle.api.internal.artifacts.ResolverResults
import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor
import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
import spock.lang.Specification
class CacheLockingArtifactDependencyResolverTest extends Specification {
- final CacheLockingManager lockingManager = Mock()
- final ArtifactDependencyResolver target = Mock()
- final GlobalDependencyResolutionRules metadataHandler = Stub()
+ final lockingManager = Mock(CacheLockingManager )
+ final target = Mock(ArtifactDependencyResolver)
+ final metadataHandler = Stub(GlobalDependencyResolutionRules)
final List<ResolutionAwareRepository> repositories = [Mock(ResolutionAwareRepository)]
final CacheLockingArtifactDependencyResolver resolver = new CacheLockingArtifactDependencyResolver(lockingManager, target)
def "resolves while holding a lock on the cache"() {
ConfigurationInternal configuration = Mock()
- ResolverResults resolverResults = Mock()
+ def graphVisitor = Mock(DependencyGraphVisitor)
+ def artifactVisitor = Mock(DependencyArtifactsVisitor)
when:
- resolver.resolve(configuration, repositories, metadataHandler, resolverResults)
+ resolver.resolve(configuration, repositories, metadataHandler, graphVisitor, artifactVisitor)
then:
1 * lockingManager.useCache("resolve $configuration", !null) >> { String s, Runnable r ->
r.run()
}
- 1 * target.resolve(configuration, repositories, metadataHandler, resolverResults)
+ 1 * target.resolve(configuration, repositories, metadataHandler, graphVisitor, artifactVisitor)
}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingArtifactDependencyResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingArtifactDependencyResolverTest.groovy
deleted file mode 100644
index 8c2af8b..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingArtifactDependencyResolverTest.groovy
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2009 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice
-
-import org.gradle.api.artifacts.LenientConfiguration
-import org.gradle.api.artifacts.ResolveException
-import org.gradle.api.artifacts.ResolvedConfiguration
-import org.gradle.api.artifacts.result.ResolutionResult
-import org.gradle.api.internal.artifacts.ArtifactDependencyResolver
-import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules
-import org.gradle.api.internal.artifacts.ResolverResults
-import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResults
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
-import org.gradle.api.specs.Specs
-import spock.lang.Specification
-
-import static org.junit.Assert.fail
-
-class ErrorHandlingArtifactDependencyResolverTest extends Specification {
- private delegate = Mock(ArtifactDependencyResolver)
- private resolvedConfiguration = Mock(ResolvedConfiguration)
- private resolutionResult = Mock(ResolutionResult)
- private projectConfigResult = Mock(ResolvedProjectConfigurationResults)
- private configuration = Mock(ConfigurationInternal.class, name: 'coolConf')
- private repositories = [Mock(ResolutionAwareRepository)]
- private metadataHandler = Stub(GlobalDependencyResolutionRules)
- private results = new ResolverResults()
- private resolver = new ErrorHandlingArtifactDependencyResolver(delegate);
-
- void "delegates to backing service"() {
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
-
- then:
- 1 * delegate.resolve(configuration, repositories, metadataHandler, results) >> {
- results.resolved(resolvedConfiguration, resolutionResult, projectConfigResult)
- }
- }
-
- void "wraps operations with the failure"() {
- given:
- def failure = new RuntimeException()
- delegate.resolve(configuration, repositories, metadataHandler, results) >> { throw failure }
-
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
-
- then:
- results.resolvedConfiguration.hasError()
-
- failsWith(failure)
- .when { results.resolvedConfiguration.rethrowFailure(); }
- .when { results.resolvedConfiguration.getFiles(Specs.satisfyAll()); }
- .when { results.resolvedConfiguration.getFirstLevelModuleDependencies(); }
- .when { results.resolvedConfiguration.getResolvedArtifacts(); }
- }
-
- void "wraps exceptions thrown by resolved configuration"() {
- given:
- def failure = new RuntimeException()
-
- resolvedConfiguration.rethrowFailure() >> { throw failure }
- resolvedConfiguration.getFiles(Specs.satisfyAll()) >> { throw failure }
- resolvedConfiguration.getFirstLevelModuleDependencies() >> { throw failure }
- resolvedConfiguration.getFirstLevelModuleDependencies(_) >> { throw failure }
- resolvedConfiguration.getResolvedArtifacts() >> { throw failure }
- resolvedConfiguration.getLenientConfiguration() >> { throw failure }
-
- delegate.resolve(configuration, repositories, metadataHandler, results) >> { results.resolved(resolutionResult, projectConfigResult) }
- delegate.resolveArtifacts(configuration, repositories, metadataHandler, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
-
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
- resolver.resolveArtifacts(configuration, repositories, metadataHandler, results)
-
- then:
- def result = results.resolvedConfiguration
- failsWith(failure)
- .when { result.rethrowFailure() }
- .when { result.getFiles(Specs.satisfyAll()) }
- .when { result.firstLevelModuleDependencies }
- .when { result.getFirstLevelModuleDependencies(Specs.satisfyAll()) }
- .when { result.resolvedArtifacts }
- .when { result.lenientConfiguration }
- }
-
- void "wraps exceptions thrown by resolved lenient configuration"() {
- given:
- def failure = new RuntimeException()
- def lenientConfiguration = Stub(LenientConfiguration)
-
- resolvedConfiguration.getLenientConfiguration() >> lenientConfiguration
- lenientConfiguration.getFiles(_) >> { throw failure }
- lenientConfiguration.getFirstLevelModuleDependencies(_) >> { throw failure }
- lenientConfiguration.getArtifacts(_) >> { throw failure }
- lenientConfiguration.getUnresolvedModuleDependencies() >> { throw failure }
-
- delegate.resolve(configuration, repositories, metadataHandler, results) >> { results.resolved(resolutionResult, projectConfigResult) }
- delegate.resolveArtifacts(configuration, repositories, metadataHandler, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
-
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
- resolver.resolveArtifacts(configuration, repositories, metadataHandler, results)
-
- then:
- def result = results.resolvedConfiguration.lenientConfiguration
- failsWith(failure)
- .when { result.getFiles(Specs.satisfyAll()) }
- .when { result.getFirstLevelModuleDependencies(Specs.satisfyAll()) }
- .when { result.getArtifacts(Specs.satisfyAll()) }
- .when { result.unresolvedModuleDependencies }
- }
-
- void "wraps exceptions thrown by resolution result"() {
- given:
- def failure = new RuntimeException()
-
- resolutionResult.root >> { throw failure }
-
- delegate.resolve(configuration, repositories, metadataHandler, results) >> { results.resolved(resolutionResult, projectConfigResult) }
- delegate.resolveArtifacts(configuration, repositories, metadataHandler, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
-
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
- resolver.resolveArtifacts(configuration, repositories, metadataHandler, results)
-
- then:
- def result = results.resolutionResult
- failsWith(failure)
- .when { result.root }
- }
-
- ExceptionFixture failsWith(Throwable failure) {
- new ExceptionFixture(failure: failure)
- }
-
- class ExceptionFixture {
- Throwable failure
- ExceptionFixture when(Closure cl) {
- try {
- cl();
- fail();
- } catch (ResolveException e) {
- assert e.message == "Could not resolve all dependencies for Mock for type 'ConfigurationInternal' named 'coolConf'."
- assert e.cause.is(failure);
- }
- this
- }
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingConfigurationResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingConfigurationResolverTest.groovy
new file mode 100644
index 0000000..0eb4d95
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ErrorHandlingConfigurationResolverTest.groovy
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice
+
+import org.gradle.api.artifacts.LenientConfiguration
+import org.gradle.api.artifacts.ResolveException
+import org.gradle.api.artifacts.ResolvedConfiguration
+import org.gradle.api.artifacts.result.ResolutionResult
+import org.gradle.api.internal.artifacts.ConfigurationResolver
+import org.gradle.api.internal.artifacts.DefaultResolverResults
+import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResult
+import org.gradle.api.specs.Specs
+import spock.lang.Specification
+
+import static org.junit.Assert.fail
+
+class ErrorHandlingConfigurationResolverTest extends Specification {
+ private delegate = Mock(ConfigurationResolver)
+ private resolvedConfiguration = Mock(ResolvedConfiguration)
+ private resolutionResult = Mock(ResolutionResult)
+ private projectConfigResult = Mock(ResolvedLocalComponentsResult)
+ private context = Mock(ConfigurationInternal.class)
+ private results = new DefaultResolverResults()
+ private resolver = new ErrorHandlingConfigurationResolver(delegate);
+
+ def setup() {
+ context.displayName >> "resolve context 'foo'"
+ }
+
+ void "delegates to backing service"() {
+ when:
+ resolver.resolve(context, results)
+
+ then:
+ 1 * delegate.resolve(context, results) >> {
+ results.resolved(resolutionResult, projectConfigResult)
+ }
+ }
+
+ void "wraps operations with the failure"() {
+ given:
+ def failure = new RuntimeException()
+ delegate.resolve(context, results) >> { throw failure }
+
+ when:
+ resolver.resolve(context, results)
+
+ then:
+ results.resolvedConfiguration.hasError()
+
+ failsWith(failure)
+ .when { results.resolvedConfiguration.rethrowFailure(); }
+ .when { results.resolvedConfiguration.getFiles(Specs.satisfyAll()); }
+ .when { results.resolvedConfiguration.getFirstLevelModuleDependencies(); }
+ .when { results.resolvedConfiguration.getResolvedArtifacts(); }
+ }
+
+ void "wraps exceptions thrown by resolved configuration"() {
+ given:
+ def failure = new RuntimeException()
+
+ resolvedConfiguration.rethrowFailure() >> { throw failure }
+ resolvedConfiguration.getFiles(Specs.satisfyAll()) >> { throw failure }
+ resolvedConfiguration.getFirstLevelModuleDependencies() >> { throw failure }
+ resolvedConfiguration.getFirstLevelModuleDependencies(_) >> { throw failure }
+ resolvedConfiguration.getResolvedArtifacts() >> { throw failure }
+ resolvedConfiguration.getLenientConfiguration() >> { throw failure }
+
+ delegate.resolve(context, results) >> { results.resolved(resolutionResult, projectConfigResult) }
+ delegate.resolveArtifacts(context, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
+
+ when:
+ resolver.resolve(context, results)
+ resolver.resolveArtifacts(context, results)
+
+ then:
+ def result = results.resolvedConfiguration
+ failsWith(failure)
+ .when { result.rethrowFailure() }
+ .when { result.getFiles(Specs.satisfyAll()) }
+ .when { result.firstLevelModuleDependencies }
+ .when { result.getFirstLevelModuleDependencies(Specs.satisfyAll()) }
+ .when { result.resolvedArtifacts }
+ .when { result.lenientConfiguration }
+ }
+
+ void "wraps exceptions thrown by resolved lenient configuration"() {
+ given:
+ def failure = new RuntimeException()
+ def lenientConfiguration = Stub(LenientConfiguration)
+
+ resolvedConfiguration.getLenientConfiguration() >> lenientConfiguration
+ lenientConfiguration.getFiles(_) >> { throw failure }
+ lenientConfiguration.getFirstLevelModuleDependencies(_) >> { throw failure }
+ lenientConfiguration.getArtifacts(_) >> { throw failure }
+ lenientConfiguration.getUnresolvedModuleDependencies() >> { throw failure }
+
+ delegate.resolve(context, results) >> { results.resolved(resolutionResult, projectConfigResult) }
+ delegate.resolveArtifacts(context, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
+
+ when:
+ resolver.resolve(context, results)
+ resolver.resolveArtifacts(context, results)
+
+ then:
+ def result = results.resolvedConfiguration.lenientConfiguration
+ failsWith(failure)
+ .when { result.getFiles(Specs.satisfyAll()) }
+ .when { result.getFirstLevelModuleDependencies(Specs.satisfyAll()) }
+ .when { result.getArtifacts(Specs.satisfyAll()) }
+ .when { result.unresolvedModuleDependencies }
+ }
+
+ void "wraps exceptions thrown by resolution result"() {
+ given:
+ def failure = new RuntimeException()
+
+ resolutionResult.root >> { throw failure }
+
+ delegate.resolve(context, results) >> { results.resolved(resolutionResult, projectConfigResult) }
+ delegate.resolveArtifacts(context, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
+
+ when:
+ resolver.resolve(context, results)
+ resolver.resolveArtifacts(context, results)
+
+ then:
+ def result = results.resolutionResult
+ failsWith(failure)
+ .when { result.root }
+ }
+
+ ExceptionFixture failsWith(Throwable failure) {
+ new ExceptionFixture(failure: failure)
+ }
+
+ class ExceptionFixture {
+ Throwable failure
+ ExceptionFixture when(Closure cl) {
+ try {
+ cl();
+ fail();
+ } catch (ResolveException e) {
+ assert e.message == "Could not resolve all dependencies for resolve context 'foo'."
+ assert e.cause.is(failure);
+ }
+ this
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyConfigurationResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyConfigurationResolverTest.groovy
new file mode 100644
index 0000000..288348f
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyConfigurationResolverTest.groovy
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice
+
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.DependencySet
+import org.gradle.api.artifacts.ResolvedConfiguration
+import org.gradle.api.artifacts.result.ResolutionResult
+import org.gradle.api.file.FileCollection
+import org.gradle.api.internal.artifacts.CachingDependencyResolveContext
+import org.gradle.api.internal.artifacts.ConfigurationResolver
+import org.gradle.api.internal.artifacts.DefaultResolverResults
+import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
+import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResult
+import org.gradle.api.specs.Spec
+import org.gradle.api.specs.Specs
+import spock.lang.Specification
+
+public class SelfResolvingDependencyConfigurationResolverTest extends Specification {
+
+ private delegate = Mock(ConfigurationResolver)
+ private resolvedConfiguration = Mock(ResolvedConfiguration)
+ private configuration = Mock(ConfigurationInternal)
+ private dependencies = Mock(DependencySet)
+ private results = new DefaultResolverResults()
+ private resolver = new SelfResolvingDependencyConfigurationResolver(delegate);
+
+ void "returns correct resolved configuration"() {
+ given:
+ delegate.resolve(configuration, results) >> { results.resolved(Mock(ResolutionResult), Mock(ResolvedLocalComponentsResult)) }
+ delegate.resolveArtifacts(configuration, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
+ configuration.getAllDependencies() >> dependencies
+ configuration.isTransitive() >> true
+
+ when:
+ resolver.resolve(configuration, results)
+ resolver.resolveArtifacts(configuration, results)
+
+ then:
+ def conf = (SelfResolvingDependencyConfigurationResolver.FilesAggregatingResolvedConfiguration) results.resolvedConfiguration
+ conf.resolvedConfiguration == resolvedConfiguration
+ conf.selfResolvingFilesProvider
+ conf.selfResolvingFilesProvider.resolveContext.transitive
+ conf.selfResolvingFilesProvider.dependencies == dependencies
+ }
+
+ void "uses configuration transitive setting"() {
+ given:
+ delegate.resolve(configuration, results) >> { results.resolved(Mock(ResolutionResult), Mock(ResolvedLocalComponentsResult)) }
+ delegate.resolveArtifacts(configuration, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
+ configuration.getAllDependencies() >> dependencies
+ configuration.isTransitive() >> false
+
+ when:
+ resolver.resolve(configuration, results)
+ resolver.resolveArtifacts(configuration, results)
+
+ then:
+ def conf = (SelfResolvingDependencyConfigurationResolver.FilesAggregatingResolvedConfiguration) results.resolvedConfiguration
+ !conf.selfResolvingFilesProvider.resolveContext.transitive
+ }
+
+ void "delegates to provided resolved configuration"() {
+ given:
+ delegate.resolve(configuration, results) >> { results.resolved(Mock(ResolutionResult), Mock(ResolvedLocalComponentsResult)) }
+ delegate.resolveArtifacts(configuration, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
+ configuration.getAllDependencies() >> dependencies
+ configuration.isTransitive() >> true
+
+ when:
+ resolver.resolve(configuration, results)
+ resolver.resolveArtifacts(configuration, results)
+ results.resolvedConfiguration.getFirstLevelModuleDependencies(Specs.satisfyAll())
+ results.resolvedConfiguration.getResolvedArtifacts()
+ results.resolvedConfiguration.hasError()
+ results.resolvedConfiguration.rethrowFailure()
+ results.resolvedConfiguration.getLenientConfiguration()
+
+ then:
+ 1 * resolvedConfiguration.getFirstLevelModuleDependencies(Specs.satisfyAll())
+ 1 * resolvedConfiguration.getResolvedArtifacts()
+ 1 * resolvedConfiguration.hasError()
+ 1 * resolvedConfiguration.rethrowFailure()
+ 1 * resolvedConfiguration.getLenientConfiguration()
+ }
+
+ void "knows how to extract self resolving files"() {
+ given:
+ def resolvedFiles = Mock(FileCollection)
+ def resolveContext = Mock(CachingDependencyResolveContext)
+ def fooDep = new DefaultExternalModuleDependency("org", "foo", "1.0")
+ Set<Dependency> dependencies = [fooDep, new DefaultExternalModuleDependency("org", "bar", "1.0")]
+
+ def provider = new SelfResolvingDependencyConfigurationResolver.SelfResolvingFilesProvider(resolveContext, dependencies)
+
+ when:
+ def files = provider.getFiles({ it.name == 'foo' } as Spec)
+
+ then:
+ 1 * resolveContext.add(fooDep)
+ 1 * resolveContext.resolve() >> resolvedFiles
+ 1 * resolvedFiles.getFiles() >> [new File('foo.jar')]
+ 0 * _._
+
+ files*.name == ['foo.jar']
+ }
+
+ void "aggregates files with self resolving files first"() {
+ given:
+ def provider = Mock(SelfResolvingDependencyConfigurationResolver.SelfResolvingFilesProvider) {
+ getFiles(Specs.satisfyAll()) >> [new File("foo.jar")]
+ }
+ resolvedConfiguration.getFiles(Specs.satisfyAll()) >> new HashSet<File>([new File("bar.jar")])
+
+ def conf = new SelfResolvingDependencyConfigurationResolver.FilesAggregatingResolvedConfiguration(resolvedConfiguration, provider)
+
+ when:
+ def files = conf.getFiles(Specs.satisfyAll())
+
+ then:
+ files*.name == ['foo.jar', 'bar.jar']
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyResolverTest.groovy
deleted file mode 100644
index 1c71685..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/SelfResolvingDependencyResolverTest.groovy
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice;
-
-
-import org.gradle.api.artifacts.Dependency
-import org.gradle.api.artifacts.DependencySet
-import org.gradle.api.artifacts.ResolvedConfiguration
-import org.gradle.api.artifacts.result.ResolutionResult
-import org.gradle.api.file.FileCollection
-import org.gradle.api.internal.artifacts.ArtifactDependencyResolver
-import org.gradle.api.internal.artifacts.CachingDependencyResolveContext
-import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules
-import org.gradle.api.internal.artifacts.ResolverResults
-import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
-import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResults
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
-import org.gradle.api.specs.Spec
-import org.gradle.api.specs.Specs
-import spock.lang.Specification
-
-public class SelfResolvingDependencyResolverTest extends Specification {
-
- private delegate = Mock(ArtifactDependencyResolver)
- private resolvedConfiguration = Mock(ResolvedConfiguration)
- private configuration = Mock(ConfigurationInternal)
- private repositories = [Mock(ResolutionAwareRepository)]
- private dependencies = Mock(DependencySet)
- private metadataHandler = Stub(GlobalDependencyResolutionRules)
- private results = new ResolverResults()
- private resolver = new SelfResolvingDependencyResolver(delegate);
-
- void "returns correct resolved configuration"() {
- given:
- delegate.resolve(configuration, repositories, metadataHandler, results) >> { results.resolved(Mock(ResolutionResult), Mock(ResolvedProjectConfigurationResults)) }
- delegate.resolveArtifacts(configuration, repositories, metadataHandler, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
- configuration.getAllDependencies() >> dependencies
- configuration.isTransitive() >> true
-
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
- resolver.resolveArtifacts(configuration, repositories, metadataHandler, results)
-
- then:
- def conf = (SelfResolvingDependencyResolver.FilesAggregatingResolvedConfiguration) results.resolvedConfiguration
- conf.resolvedConfiguration == resolvedConfiguration
- conf.selfResolvingFilesProvider
- conf.selfResolvingFilesProvider.resolveContext.transitive
- conf.selfResolvingFilesProvider.dependencies == dependencies
- }
-
- void "uses configuration transitive setting"() {
- given:
- delegate.resolve(configuration, repositories, metadataHandler, results) >> { results.resolved(Mock(ResolutionResult), Mock(ResolvedProjectConfigurationResults)) }
- delegate.resolveArtifacts(configuration, repositories, metadataHandler, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
- configuration.getAllDependencies() >> dependencies
- configuration.isTransitive() >> false
-
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
- resolver.resolveArtifacts(configuration, repositories, metadataHandler, results)
-
- then:
- def conf = (SelfResolvingDependencyResolver.FilesAggregatingResolvedConfiguration) results.resolvedConfiguration
- !conf.selfResolvingFilesProvider.resolveContext.transitive
- }
-
- void "delegates to provided resolved configuration"() {
- given:
- delegate.resolve(configuration, repositories, metadataHandler, results) >> { results.resolved(Mock(ResolutionResult), Mock(ResolvedProjectConfigurationResults)) }
- delegate.resolveArtifacts(configuration, repositories, metadataHandler, results) >> { results.withResolvedConfiguration(resolvedConfiguration) }
- configuration.getAllDependencies() >> dependencies
- configuration.isTransitive() >> true
-
- when:
- resolver.resolve(configuration, repositories, metadataHandler, results)
- resolver.resolveArtifacts(configuration, repositories, metadataHandler, results)
- results.resolvedConfiguration.getFirstLevelModuleDependencies(Specs.satisfyAll())
- results.resolvedConfiguration.getResolvedArtifacts()
- results.resolvedConfiguration.hasError()
- results.resolvedConfiguration.rethrowFailure()
- results.resolvedConfiguration.getLenientConfiguration()
-
- then:
- 1 * resolvedConfiguration.getFirstLevelModuleDependencies(Specs.satisfyAll())
- 1 * resolvedConfiguration.getResolvedArtifacts()
- 1 * resolvedConfiguration.hasError()
- 1 * resolvedConfiguration.rethrowFailure()
- 1 * resolvedConfiguration.getLenientConfiguration()
- }
-
- void "knows how to extract self resolving files"() {
- given:
- def resolvedFiles = Mock(FileCollection)
- def resolveContext = Mock(CachingDependencyResolveContext)
- def fooDep = new DefaultExternalModuleDependency("org", "foo", "1.0")
- Set<Dependency> dependencies = [fooDep, new DefaultExternalModuleDependency("org", "bar", "1.0")]
-
- def provider = new SelfResolvingDependencyResolver.SelfResolvingFilesProvider(resolveContext, dependencies)
-
- when:
- def files = provider.getFiles({ it.name == 'foo' } as Spec)
-
- then:
- 1 * resolveContext.add(fooDep)
- 1 * resolveContext.resolve() >> resolvedFiles
- 1 * resolvedFiles.getFiles() >> [new File('foo.jar')]
- 0 * _._
-
- files*.name == ['foo.jar']
- }
-
- void "aggregates files with self resolving files first"() {
- given:
- def provider = Mock(SelfResolvingDependencyResolver.SelfResolvingFilesProvider) {
- getFiles(Specs.satisfyAll()) >> [new File("foo.jar")]
- }
- resolvedConfiguration.getFiles(Specs.satisfyAll()) >> new HashSet<File>([new File("bar.jar")])
-
- def conf = new SelfResolvingDependencyResolver.FilesAggregatingResolvedConfiguration(resolvedConfiguration, provider)
-
- when:
- def files = conf.getFiles(Specs.satisfyAll())
-
- then:
- files*.name == ['foo.jar', 'bar.jar']
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ShortCircuitEmptyConfigurationResolverSpec.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ShortCircuitEmptyConfigurationResolverSpec.groovy
new file mode 100644
index 0000000..600317f
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ShortCircuitEmptyConfigurationResolverSpec.groovy
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.artifacts.ivyservice
+
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.DependencySet
+import org.gradle.api.internal.artifacts.ConfigurationResolver
+import org.gradle.api.internal.artifacts.DefaultResolverResults
+import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory
+import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
+import org.gradle.api.specs.Specs
+import spock.lang.Specification
+
+class ShortCircuitEmptyConfigurationResolverSpec extends Specification {
+
+ def delegate = Mock(ConfigurationResolver)
+ def configuration = Stub(ConfigurationInternal)
+ def dependencies = Stub(DependencySet)
+ def componentIdentifierFactory = Mock(ComponentIdentifierFactory)
+ def results = new DefaultResolverResults()
+ def dependencyResolver = new ShortCircuitEmptyConfigurationResolver(delegate, componentIdentifierFactory);
+
+ def "returns empty result when no dependencies"() {
+ given:
+ dependencies.isEmpty() >> true
+ configuration.getAllDependencies() >> dependencies
+
+ when:
+ dependencyResolver.resolve(configuration, results)
+ dependencyResolver.resolveArtifacts(configuration, results)
+
+ then:
+ def resolvedConfig = results.resolvedConfiguration
+ !resolvedConfig.hasError()
+ resolvedConfig.rethrowFailure();
+
+ resolvedConfig.getFiles(Specs.<Dependency> satisfyAll()).isEmpty()
+ resolvedConfig.getFirstLevelModuleDependencies().isEmpty()
+ resolvedConfig.getResolvedArtifacts().isEmpty()
+
+ and:
+ def result = results.resolutionResult
+ result.allComponents.size() == 1
+ result.allDependencies.empty
+
+ and:
+ 0 * delegate._
+ }
+
+ def "delegates to backing service when there are one or more dependencies"() {
+ given:
+ dependencies.isEmpty() >> false
+ configuration.getAllDependencies() >> dependencies
+
+ when:
+ dependencyResolver.resolve(configuration, results)
+
+ then:
+ 1 * delegate.resolve(configuration, results)
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ShortcircuitEmptyConfigsArtifactDependencyResolverSpec.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ShortcircuitEmptyConfigsArtifactDependencyResolverSpec.groovy
deleted file mode 100644
index 52a04ff..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ShortcircuitEmptyConfigsArtifactDependencyResolverSpec.groovy
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2009 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.api.internal.artifacts.ivyservice
-
-import org.gradle.api.artifacts.Dependency
-import org.gradle.api.artifacts.DependencySet
-import org.gradle.api.internal.artifacts.ArtifactDependencyResolver
-import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules
-import org.gradle.api.internal.artifacts.ResolverResults
-import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory
-import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository
-import org.gradle.api.specs.Specs
-import spock.lang.Specification
-
-class ShortcircuitEmptyConfigsArtifactDependencyResolverSpec extends Specification {
-
- def delegate = Mock(ArtifactDependencyResolver)
- def configuration = Stub(ConfigurationInternal)
- def repositories = [Stub(ResolutionAwareRepository)]
- def metadataHandler = Stub(GlobalDependencyResolutionRules)
- def dependencies = Stub(DependencySet)
- def componentIdentifierFactory = Mock(ComponentIdentifierFactory)
- def results = new ResolverResults()
- def dependencyResolver = new ShortcircuitEmptyConfigsArtifactDependencyResolver(delegate, componentIdentifierFactory);
-
- def "returns empty result when no dependencies"() {
- given:
- dependencies.isEmpty() >> true
- configuration.getAllDependencies() >> dependencies
-
- when:
- dependencyResolver.resolve(configuration, repositories, metadataHandler, results)
- dependencyResolver.resolveArtifacts(configuration, repositories, metadataHandler, results)
-
- then:
- def resolvedConfig = results.resolvedConfiguration
- !resolvedConfig.hasError()
- resolvedConfig.rethrowFailure();
-
- resolvedConfig.getFiles(Specs.<Dependency> satisfyAll()).isEmpty()
- resolvedConfig.getFirstLevelModuleDependencies().isEmpty()
- resolvedConfig.getResolvedArtifacts().isEmpty()
-
- and:
- def result = results.resolutionResult
- result.allComponents.size() == 1
- result.allDependencies.empty
-
- and:
- 0 * delegate._
- }
-
- def "delegates to backing service when there are one or more dependencies"() {
- given:
- dependencies.isEmpty() >> false
- configuration.getAllDependencies() >> dependencies
-
- when:
- dependencyResolver.resolve(configuration, repositories, metadataHandler, results)
-
- then:
- 1 * delegate.resolve(configuration, repositories, metadataHandler, results)
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ErrorHandlingArtifactResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ErrorHandlingArtifactResolverTest.groovy
index f6bb45f..ff2cadf 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ErrorHandlingArtifactResolverTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ErrorHandlingArtifactResolverTest.groovy
@@ -16,12 +16,12 @@
package org.gradle.api.internal.artifacts.ivyservice.ivyresolve
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier
import org.gradle.api.artifacts.component.ComponentIdentifier
-import org.gradle.internal.component.model.ComponentArtifactIdentifier
+import org.gradle.api.internal.component.ArtifactType
import org.gradle.internal.component.model.ComponentArtifactMetaData
-import org.gradle.internal.component.model.ComponentUsage
import org.gradle.internal.component.model.ComponentResolveMetaData
-import org.gradle.api.internal.component.ArtifactType
+import org.gradle.internal.component.model.ComponentUsage
import org.gradle.internal.component.model.ModuleSource
import org.gradle.internal.resolve.ArtifactResolveException
import org.gradle.internal.resolve.resolver.ArtifactResolver
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChainArtifactResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChainArtifactResolverTest.groovy
deleted file mode 100644
index 08af31e..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChainArtifactResolverTest.groovy
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.ivyresolve
-
-import org.gradle.internal.component.model.ComponentUsage
-import org.gradle.internal.component.model.ModuleSource
-import org.gradle.internal.resolve.result.DefaultBuildableArtifactResolveResult
-import org.gradle.internal.resolve.result.DefaultBuildableArtifactSetResolveResult
-import org.gradle.internal.component.model.ComponentArtifactMetaData
-import org.gradle.internal.component.model.ComponentResolveMetaData
-import spock.lang.Specification
-
-class RepositoryChainArtifactResolverTest extends Specification {
- final artifact = Mock(ComponentArtifactMetaData)
- final component = Mock(ComponentResolveMetaData)
- final originalSource = Mock(ModuleSource)
- final result = new DefaultBuildableArtifactResolveResult()
- final artifactSetResult = new DefaultBuildableArtifactSetResolveResult()
-
- def repo1 = Stub(ModuleComponentRepository) {
- getId() >> "repo1"
- }
- def localAccess2 = Mock(ModuleComponentRepositoryAccess)
- def remoteAccess2 = Mock(ModuleComponentRepositoryAccess)
- def repo2 = Mock(ModuleComponentRepository) {
- getLocalAccess() >> localAccess2
- getRemoteAccess() >> remoteAccess2
- getId() >> "repo2"
- }
- def repo2Source = new RepositoryChainModuleSource("repo2", originalSource)
-
- final RepositoryChainArtifactResolver resolver = new RepositoryChainArtifactResolver()
-
- def setup() {
- resolver.add(repo1)
- resolver.add(repo2)
- }
-
- def "uses module artifacts from local access to repository defined by module source"() {
- def usage = Mock(ComponentUsage)
- def artifact = Mock(ComponentArtifactMetaData)
- when:
- resolver.resolveModuleArtifacts(component, usage, artifactSetResult)
-
- then:
- _ * component.getSource() >> repo2Source
- 1 * component.withSource(originalSource) >> component
- 1 * repo2.getLocalAccess() >> localAccess2
- 1 * localAccess2.resolveModuleArtifacts(component, usage, artifactSetResult) >> {
- it[2].resolved([artifact])
- }
- 0 * _._
-
- and:
- artifactSetResult.artifacts == [artifact] as Set
- }
-
- def "uses module artifacts from remote access to repository defined by module source"() {
- def usage = Mock(ComponentUsage)
- def artifact = Mock(ComponentArtifactMetaData)
- when:
- resolver.resolveModuleArtifacts(component, usage, artifactSetResult)
-
- then:
- _ * component.getSource() >> repo2Source
- 1 * component.withSource(originalSource) >> component
- 1 * repo2.getLocalAccess() >> localAccess2
- 1 * localAccess2.resolveModuleArtifacts(component, usage, artifactSetResult)
- 1 * repo2.getRemoteAccess() >> remoteAccess2
- 1 * remoteAccess2.resolveModuleArtifacts(component, usage, artifactSetResult) >> {
- it[2].resolved([artifact])
- }
- 0 * _._
-
- and:
- artifactSetResult.artifacts == [artifact] as Set
- }
-
- def "locates artifact with local access in repository defined by module source"() {
- def artifactFile = Mock(File)
- def artifact = Mock(ComponentArtifactMetaData)
- when:
- resolver.resolveArtifact(artifact, repo2Source, result)
-
- then:
- 1 * repo2.getLocalAccess() >> localAccess2
- 1 * localAccess2.resolveArtifact(artifact, originalSource, result) >> {
- it[2].resolved(artifactFile)
- }
- 0 * _._
-
- and:
- result.file == artifactFile
- }
-
- def "locates artifact with remote access in repository defined by module source"() {
- def artifactFile = Mock(File)
- def artifact = Mock(ComponentArtifactMetaData)
- when:
- resolver.resolveArtifact(artifact, repo2Source, result)
-
- then:
- 1 * repo2.getLocalAccess() >> localAccess2
- 1 * localAccess2.resolveArtifact(artifact, originalSource, result)
- 1 * repo2.getRemoteAccess() >> remoteAccess2
- 1 * remoteAccess2.resolveArtifact(artifact, originalSource, result) >> {
- it[2].resolved(artifactFile)
- }
- 0 * _._
-
- and:
- result.file == artifactFile
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChainComponentMetaDataResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChainComponentMetaDataResolverTest.groovy
deleted file mode 100644
index 29c183b..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/RepositoryChainComponentMetaDataResolverTest.groovy
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Copyright 2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.ivyresolve
-
-import org.apache.ivy.core.module.descriptor.ModuleDescriptor
-import org.gradle.api.Transformer
-import org.gradle.api.artifacts.ModuleVersionIdentifier
-import org.gradle.api.artifacts.ModuleVersionSelector
-import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier
-import org.gradle.api.internal.artifacts.DefaultModuleVersionSelector
-import org.gradle.api.internal.artifacts.ivyservice.IvyUtil
-import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
-import org.gradle.internal.component.external.model.ModuleComponentResolveMetaData
-import org.gradle.internal.component.external.model.MutableModuleComponentResolveMetaData
-import org.gradle.internal.component.model.ComponentOverrideMetadata
-import org.gradle.internal.component.model.DependencyMetaData
-import org.gradle.internal.resolve.ModuleVersionResolveException
-import org.gradle.internal.resolve.result.BuildableComponentResolveResult
-import spock.lang.Specification
-
-class RepositoryChainComponentMetaDataResolverTest extends Specification {
- final metaData = metaData("1.2")
- final moduleComponentId = DefaultModuleComponentIdentifier.newId("group", "project", "1.0")
- final dependency = Stub(DependencyMetaData)
- final componentRequestMetaData = Mock(ComponentOverrideMetadata)
- final selector = DefaultModuleVersionSelector.newSelector("group", "project", "1.0")
-
- final Transformer<ModuleComponentResolveMetaData, RepositoryChainModuleResolution> transformer = Mock(Transformer)
- final result = Mock(BuildableComponentResolveResult)
- def localAccess = Mock(ModuleComponentRepositoryAccess)
- def remoteAccess = Mock(ModuleComponentRepositoryAccess)
- def localAccess2 = Mock(ModuleComponentRepositoryAccess)
- def remoteAccess2 = Mock(ModuleComponentRepositoryAccess)
-
- final VersionedComponentChooser componentSelectionStrategy = Mock(VersionedComponentChooser)
- final RepositoryChainComponentMetaDataResolver resolver = new RepositoryChainComponentMetaDataResolver(componentSelectionStrategy, transformer)
-
- ModuleVersionIdentifier moduleVersionIdentifier(ModuleDescriptor moduleDescriptor) {
- def moduleRevId = moduleDescriptor.moduleRevisionId
- new DefaultModuleVersionIdentifier(moduleRevId.organisation, moduleRevId.name, moduleRevId.revision)
- }
-
- def setup() {
- _ * dependency.requested >> selector
- }
-
- def addRepo1() {
- addModuleComponentRepository("repo1", localAccess, remoteAccess)
- }
-
- def addRepo2() {
- addModuleComponentRepository("repo2", localAccess2, remoteAccess2)
- }
-
- def addModuleComponentRepository(def name, def repoLocalAccess, def repoRemoteAccess) {
- def repo = Stub(ModuleComponentRepository) {
- getLocalAccess() >> repoLocalAccess
- getRemoteAccess() >> repoRemoteAccess
- getName() >> name
- }
- resolver.add(repo)
- repo
- }
-
- def "uses local dependency when available"() {
- given:
- def repo = addRepo1()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * result._
- }
-
- def "attempts to find remote dependency when local dependency is unknown"() {
- given:
- def repo = addRepo1()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * result._
- }
-
- def "attempts to find remote dependency when local dependency is probably missing"() {
- given:
- def repo = addRepo1()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * result._
- }
-
- def "fails with not found when local static dependency is marked as missing"() {
- given:
- def repo = addRepo1()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.attempted("scheme:thing")
- result.missing()
- }
- 1 * result.attempted("scheme:thing")
- 1 * result.notFound(moduleComponentId)
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * result._
- }
-
- def "fails with not found when local and remote static dependency marked as missing"() {
- given:
- addRepo1()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- }
- 1 * result.notFound(moduleComponentId)
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * result._
- }
-
- def "stops on first available local dependency for static version"() {
- given:
- def repo1 = addRepo1()
- def repo2 = Mock(ModuleComponentRepository)
- resolver.add(repo2)
- def repo3 = Mock(ModuleComponentRepository)
- resolver.add(repo3)
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo1
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * repo2._
- 0 * repo3._
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * result._
- }
-
- def "uses local dependency when available in one repository and missing from all other repositories"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo2
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "uses local dependency when available in one repository and probably missing in all other repositories"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo2
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "uses remote dependency when local dependency is unknown for a given repository and probably missing in other repositories"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo2
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "attempts to find remote dependency when local dependency is probably missing in all repositories"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- }
- 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo2
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "does not attempt to resolve remote dependency when local dependency is missing"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo2
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "attempts to find remote dependency when local dependency is missing or unknown in all repositories"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- result.authoritative = false
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- }
- 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo1
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "ignores failure to resolve local dependency when available in another repository"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.failed(new ModuleVersionResolveException(id, "broken"))
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo2
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "ignores failure to resolve remote dependency when available in another repository"() {
- given:
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.failed(new ModuleVersionResolveException(id, "broken"))
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.resolved(metaData)
- }
- 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
- assert it.module == metaData
- assert it.repository == repo2
- metaData
- }
- 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
- assert metaData == this.metaData
- }
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "rethrows failure to resolve local dependency when not available in any repository"() {
- given:
- def failure = new ModuleVersionResolveException(Stub(ModuleVersionSelector), "broken")
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.failed(failure)
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- }
- 1 * result.failed({ it.cause == failure })
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def "rethrows failure to resolve remote dependency when not available in any repository"() {
- given:
- def failure = new ModuleVersionResolveException(Stub(ModuleVersionSelector), "broken")
- def repo1 = addRepo1()
- def repo2 = addRepo2()
-
- when:
- resolver.resolve(moduleComponentId, componentRequestMetaData, result)
-
- then:
- 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.failed(failure)
- }
- 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
- 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
- result.missing()
- }
- 1 * result.failed({ it.cause == failure })
-
- and:
- 0 * localAccess._
- 0 * remoteAccess._
- 0 * localAccess2._
- 0 * remoteAccess2._
- 0 * result._
- }
-
- def descriptor(String version) {
- def descriptor = Stub(ModuleDescriptor)
- descriptor.resolvedModuleRevisionId >> IvyUtil.createModuleRevisionId("org", "module", version)
- return descriptor
- }
-
- def metaData(String version) {
- return Stub(MutableModuleComponentResolveMetaData) {
- toString() >> version
- getId() >> DefaultModuleVersionIdentifier.newId("org", "module", version)
- getDescriptor() >> descriptor(version)
- }
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactoryTest.groovy
index 6903a1b..adbaf04 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolveIvyFactoryTest.groovy
@@ -100,7 +100,7 @@ class ResolveIvyFactoryTest extends Specification {
assert resolver instanceof UserResolverChain
resolver.componentSelectionRules == componentSelectionRules
- 1 * spyResolver.setRepositoryChain(_) >> { RepositoryChain parentResolver ->
+ 1 * spyResolver.setComponentResolvers(_) >> { ComponentResolvers parentResolver ->
assert parentResolver instanceof ResolveIvyFactory.ParentModuleLookupResolver
// Validate that the parent repository chain selection rules are different and empty
def parentComponentSelectionRules = parentResolver.delegate.componentSelectionRules
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderArtifactResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderArtifactResolverTest.groovy
new file mode 100644
index 0000000..41192e5
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderArtifactResolverTest.groovy
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.ivyresolve
+
+import org.gradle.internal.component.model.ComponentArtifactMetaData
+import org.gradle.internal.component.model.ComponentResolveMetaData
+import org.gradle.internal.component.model.ComponentUsage
+import org.gradle.internal.component.model.ModuleSource
+import org.gradle.internal.resolve.result.DefaultBuildableArtifactResolveResult
+import org.gradle.internal.resolve.result.DefaultBuildableArtifactSetResolveResult
+import spock.lang.Specification
+
+class ResolverProviderArtifactResolverTest extends Specification {
+ final artifact = Mock(ComponentArtifactMetaData)
+ final component = Mock(ComponentResolveMetaData)
+ final originalSource = Mock(ModuleSource)
+ final result = new DefaultBuildableArtifactResolveResult()
+ final artifactSetResult = new DefaultBuildableArtifactSetResolveResult()
+
+ def repo1 = Stub(ModuleComponentRepository) {
+ getId() >> "repo1"
+ }
+ def localAccess2 = Mock(ModuleComponentRepositoryAccess)
+ def remoteAccess2 = Mock(ModuleComponentRepositoryAccess)
+ def repo2 = Mock(ModuleComponentRepository) {
+ getLocalAccess() >> localAccess2
+ getRemoteAccess() >> remoteAccess2
+ getId() >> "repo2"
+ }
+ def repo2Source = new RepositoryChainModuleSource("repo2", originalSource)
+
+ final RepositoryChainArtifactResolver resolver = new RepositoryChainArtifactResolver()
+
+ def setup() {
+ resolver.add(repo1)
+ resolver.add(repo2)
+ }
+
+ def "uses module artifacts from local access to repository defined by module source"() {
+ def usage = Mock(ComponentUsage)
+ def artifact = Mock(ComponentArtifactMetaData)
+ when:
+ resolver.resolveModuleArtifacts(component, usage, artifactSetResult)
+
+ then:
+ _ * component.getSource() >> repo2Source
+ 1 * component.withSource(originalSource) >> component
+ 1 * repo2.getLocalAccess() >> localAccess2
+ 1 * localAccess2.resolveModuleArtifacts(component, usage, artifactSetResult) >> {
+ it[2].resolved([artifact])
+ }
+ 0 * _._
+
+ and:
+ artifactSetResult.artifacts == [artifact] as Set
+ }
+
+ def "uses module artifacts from remote access to repository defined by module source"() {
+ def usage = Mock(ComponentUsage)
+ def artifact = Mock(ComponentArtifactMetaData)
+ when:
+ resolver.resolveModuleArtifacts(component, usage, artifactSetResult)
+
+ then:
+ _ * component.getSource() >> repo2Source
+ 1 * component.withSource(originalSource) >> component
+ 1 * repo2.getLocalAccess() >> localAccess2
+ 1 * localAccess2.resolveModuleArtifacts(component, usage, artifactSetResult)
+ 1 * repo2.getRemoteAccess() >> remoteAccess2
+ 1 * remoteAccess2.resolveModuleArtifacts(component, usage, artifactSetResult) >> {
+ it[2].resolved([artifact])
+ }
+ 0 * _._
+
+ and:
+ artifactSetResult.artifacts == [artifact] as Set
+ }
+
+ def "locates artifact with local access in repository defined by module source"() {
+ def artifactFile = Mock(File)
+ def artifact = Mock(ComponentArtifactMetaData)
+ when:
+ resolver.resolveArtifact(artifact, repo2Source, result)
+
+ then:
+ 1 * repo2.getLocalAccess() >> localAccess2
+ 1 * localAccess2.resolveArtifact(artifact, originalSource, result) >> {
+ it[2].resolved(artifactFile)
+ }
+ 0 * _._
+
+ and:
+ result.file == artifactFile
+ }
+
+ def "locates artifact with remote access in repository defined by module source"() {
+ def artifactFile = Mock(File)
+ def artifact = Mock(ComponentArtifactMetaData)
+ when:
+ resolver.resolveArtifact(artifact, repo2Source, result)
+
+ then:
+ 1 * repo2.getLocalAccess() >> localAccess2
+ 1 * localAccess2.resolveArtifact(artifact, originalSource, result)
+ 1 * repo2.getRemoteAccess() >> remoteAccess2
+ 1 * remoteAccess2.resolveArtifact(artifact, originalSource, result) >> {
+ it[2].resolved(artifactFile)
+ }
+ 0 * _._
+
+ and:
+ result.file == artifactFile
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderComponentMetaDataResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderComponentMetaDataResolverTest.groovy
new file mode 100644
index 0000000..f18c808
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/ResolverProviderComponentMetaDataResolverTest.groovy
@@ -0,0 +1,580 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.ivyresolve
+
+import org.apache.ivy.core.module.descriptor.ModuleDescriptor
+import org.gradle.api.Transformer
+import org.gradle.api.artifacts.ModuleVersionIdentifier
+import org.gradle.api.artifacts.ModuleVersionSelector
+import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier
+import org.gradle.api.internal.artifacts.DefaultModuleVersionSelector
+import org.gradle.api.internal.artifacts.ivyservice.IvyUtil
+import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
+import org.gradle.internal.component.external.model.ModuleComponentResolveMetaData
+import org.gradle.internal.component.external.model.MutableModuleComponentResolveMetaData
+import org.gradle.internal.component.model.ComponentOverrideMetadata
+import org.gradle.internal.component.model.DependencyMetaData
+import org.gradle.internal.resolve.ModuleVersionResolveException
+import org.gradle.internal.resolve.result.BuildableComponentResolveResult
+import spock.lang.Specification
+
+class ResolverProviderComponentMetaDataResolverTest extends Specification {
+ final metaData = metaData("1.2")
+ final moduleComponentId = DefaultModuleComponentIdentifier.newId("group", "project", "1.0")
+ final dependency = Stub(DependencyMetaData)
+ final componentRequestMetaData = Mock(ComponentOverrideMetadata)
+ final selector = DefaultModuleVersionSelector.newSelector("group", "project", "1.0")
+
+ final Transformer<ModuleComponentResolveMetaData, RepositoryChainModuleResolution> transformer = Mock(Transformer)
+ final result = Mock(BuildableComponentResolveResult)
+ def localAccess = Mock(ModuleComponentRepositoryAccess)
+ def remoteAccess = Mock(ModuleComponentRepositoryAccess)
+ def localAccess2 = Mock(ModuleComponentRepositoryAccess)
+ def remoteAccess2 = Mock(ModuleComponentRepositoryAccess)
+
+ final VersionedComponentChooser componentSelectionStrategy = Mock(VersionedComponentChooser)
+ final RepositoryChainComponentMetaDataResolver resolver = new RepositoryChainComponentMetaDataResolver(componentSelectionStrategy, transformer)
+
+ ModuleVersionIdentifier moduleVersionIdentifier(ModuleDescriptor moduleDescriptor) {
+ def moduleRevId = moduleDescriptor.moduleRevisionId
+ new DefaultModuleVersionIdentifier(moduleRevId.organisation, moduleRevId.name, moduleRevId.revision)
+ }
+
+ def setup() {
+ _ * dependency.requested >> selector
+ }
+
+ def addRepo1() {
+ addModuleComponentRepository("repo1", localAccess, remoteAccess)
+ }
+
+ def addRepo2() {
+ addModuleComponentRepository("repo2", localAccess2, remoteAccess2)
+ }
+
+ def addModuleComponentRepository(def name, def repoLocalAccess, def repoRemoteAccess) {
+ def repo = Stub(ModuleComponentRepository) {
+ getLocalAccess() >> repoLocalAccess
+ getRemoteAccess() >> repoRemoteAccess
+ getName() >> name
+ }
+ resolver.add(repo)
+ repo
+ }
+
+ def "uses local dependency when available"() {
+ given:
+ def repo = addRepo1()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * result._
+ }
+
+ def "attempts to find remote dependency when local dependency is unknown"() {
+ given:
+ def repo = addRepo1()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * result._
+ }
+
+ def "attempts to find remote dependency when local dependency is probably missing"() {
+ given:
+ def repo = addRepo1()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * result._
+ }
+
+ def "fails with not found when local static dependency is marked as missing"() {
+ given:
+ def repo = addRepo1()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.attempted("scheme:thing")
+ result.missing()
+ }
+ 1 * result.attempted("scheme:thing")
+ 1 * result.notFound(moduleComponentId)
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * result._
+ }
+
+ def "fails with not found when local and remote static dependency marked as missing"() {
+ given:
+ addRepo1()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ }
+ 1 * result.notFound(moduleComponentId)
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * result._
+ }
+
+ def "stops on first available local dependency for static version"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = Mock(ModuleComponentRepository)
+ resolver.add(repo2)
+ def repo3 = Mock(ModuleComponentRepository)
+ resolver.add(repo3)
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo1
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * repo2._
+ 0 * repo3._
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * result._
+ }
+
+ def "uses local dependency when available in one repository and missing from all other repositories"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo2
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "uses local dependency when available in one repository and probably missing in all other repositories"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo2
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "uses remote dependency when local dependency is unknown for a given repository and probably missing in other repositories"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo2
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "attempts to find remote dependency when local dependency is probably missing in all repositories"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ }
+ 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo2
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "does not attempt to resolve remote dependency when local dependency is missing"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo2
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "attempts to find remote dependency when local dependency is missing or unknown in all repositories"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ result.authoritative = false
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ }
+ 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo1
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "ignores failure to resolve local dependency when available in another repository"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.failed(new ModuleVersionResolveException(id, "broken"))
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo2
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "ignores failure to resolve remote dependency when available in another repository"() {
+ given:
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.failed(new ModuleVersionResolveException(id, "broken"))
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.resolved(metaData)
+ }
+ 1 * transformer.transform(_) >> { RepositoryChainModuleResolution it ->
+ assert it.module == metaData
+ assert it.repository == repo2
+ metaData
+ }
+ 1 * result.resolved(_) >> { ModuleComponentResolveMetaData metaData ->
+ assert metaData == this.metaData
+ }
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "rethrows failure to resolve local dependency when not available in any repository"() {
+ given:
+ def failure = new ModuleVersionResolveException(Stub(ModuleVersionSelector), "broken")
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.failed(failure)
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ }
+ 1 * result.failed({ it.cause == failure })
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def "rethrows failure to resolve remote dependency when not available in any repository"() {
+ given:
+ def failure = new ModuleVersionResolveException(Stub(ModuleVersionSelector), "broken")
+ def repo1 = addRepo1()
+ def repo2 = addRepo2()
+
+ when:
+ resolver.resolve(moduleComponentId, componentRequestMetaData, result)
+
+ then:
+ 1 * localAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.failed(failure)
+ }
+ 1 * localAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _)
+ 1 * remoteAccess2.resolveComponentMetaData(moduleComponentId, componentRequestMetaData, _) >> { id, meta, result ->
+ result.missing()
+ }
+ 1 * result.failed({ it.cause == failure })
+
+ and:
+ 0 * localAccess._
+ 0 * remoteAccess._
+ 0 * localAccess2._
+ 0 * remoteAccess2._
+ 0 * result._
+ }
+
+ def descriptor(String version) {
+ def descriptor = Stub(ModuleDescriptor)
+ descriptor.resolvedModuleRevisionId >> IvyUtil.createModuleRevisionId("org", "module", version)
+ return descriptor
+ }
+
+ def metaData(String version) {
+ return Stub(MutableModuleComponentResolveMetaData) {
+ toString() >> version
+ getId() >> DefaultModuleVersionIdentifier.newId("org", "module", version)
+ getDescriptor() >> descriptor(version)
+ }
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorParserTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorParserTest.groovy
index 54e0ba7..4f50b54 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorParserTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/GradlePomModuleDescriptorParserTest.groovy
@@ -2247,4 +2247,54 @@ class GradlePomModuleDescriptorParserTest extends AbstractGradlePomModuleDescrip
'bundle' | 'jar' | null
'custom-type' | 'custom-type' | null
}
+
+ @Issue("GRADLE-3299")
+ def "correctly resolve references to parent GAV properties"() {
+ given:
+ def parent = tmpDir.file("parent.xml") << """
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>group-one</groupId>
+ <artifactId>artifact-one</artifactId>
+ <version>version-one</version>
+</project>
+"""
+
+ pomFile << """
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>\${project.parent.groupId}</groupId>
+ <artifactId>\${project.parent.artifactId}-ext</artifactId>
+ <version>\${project.parent.version}</version>
+
+ <parent>
+ <groupId>group-one</groupId>
+ <artifactId>artifact-one</artifactId>
+ <version>version-one</version>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>\${parent.groupId}</groupId>
+ <artifactId>\${parent.artifactId}-xxx</artifactId>
+ <version>\${parent.version}</version>
+ </dependency>
+ </dependencies>
+</project>
+"""
+ and:
+ parseContext.getMetaDataArtifact(_, MAVEN_POM) >> { new DefaultLocallyAvailableExternalResource(parent.toURI(), new DefaultLocallyAvailableResource(parent)) }
+
+ when:
+ def descriptor = parsePom()
+
+ then:
+ descriptor.moduleRevisionId == moduleId('group-one', 'artifact-one-ext', 'version-one')
+
+ descriptor.dependencies.length == 1
+ def depGroupOne = descriptor.dependencies[0]
+ depGroupOne.dependencyRevisionId == moduleId('group-one', 'artifact-one-xxx', 'version-one')
+ depGroupOne.moduleConfigurations as List == ['compile', 'runtime']
+ hasDefaultDependencyArtifact(depGroupOne)
+ }
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderProfileTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderProfileTest.groovy
index d220d08..b0196a5 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderProfileTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderProfileTest.groovy
@@ -169,7 +169,7 @@ class PomReaderProfileTest extends AbstractPomReaderTest {
then:
pomReader.parseActivePomProfiles().size() == 1
- pomReader.properties.size() == 5
+ pomReader.properties.size() == 7
!pomReader.properties.containsKey('prop1')
!pomReader.properties.containsKey('prop3')
pomReader.properties['prop2'] == 'myproperty2'
@@ -286,7 +286,7 @@ class PomReaderProfileTest extends AbstractPomReaderTest {
pomProfile.properties['groupId.prop'] == 'group-two'
pomProfile.properties['artifactId.prop'] == 'artifact-two'
pomProfile.properties['version.prop'] == 'version-two'
- pomReader.properties.size() == 7
+ pomReader.properties.size() == 9
pomReader.properties['groupId.prop'] == 'group-two'
pomReader.properties['artifactId.prop'] == 'artifact-two'
pomReader.properties['version.prop'] == 'version-two'
@@ -331,7 +331,7 @@ class PomReaderProfileTest extends AbstractPomReaderTest {
then:
pomReader.parseActivePomProfiles().size() == 2
- pomReader.properties.size() == 7
+ pomReader.properties.size() == 9
pomReader.properties['groupId.prop'] == 'group-two'
pomReader.properties['artifactId.prop'] == 'artifact-two'
pomReader.properties['version.prop'] == 'version-two'
@@ -2243,7 +2243,7 @@ class PomReaderProfileTest extends AbstractPomReaderTest {
then:
pomReader.parseActivePomProfiles().size() == 2
- pomReader.properties.size() == 7
+ pomReader.properties.size() == 9
pomReader.properties['groupId.prop'] == 'group-two'
pomReader.properties['artifactId.prop'] == 'artifact-two'
pomReader.properties['version.prop'] == 'version-two'
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderTest.groovy
index 65e045b..bcb0d1d 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/parser/PomReaderTest.groovy
@@ -95,11 +95,13 @@ class PomReaderTest extends AbstractPomReaderTest {
pomReader.licenses[0].url == 'http://www.apache.org/licenses/LICENSE-2.0.txt'
!pomReader.hasParent()
pomReader.pomProperties.size() == 0
- pomReader.properties.size() == 4
+ pomReader.properties.size() == 6
pomReader.properties['parent.version'] == 'version-one'
pomReader.properties['parent.groupId'] == 'group-one'
+ pomReader.properties['parent.artifactId'] == 'artifact-one'
pomReader.properties['project.parent.version'] == 'version-one'
pomReader.properties['project.parent.groupId'] == 'group-one'
+ pomReader.properties['project.parent.artifactId'] == 'artifact-one'
pomReader.relocation == null
}
@@ -134,7 +136,7 @@ class PomReaderTest extends AbstractPomReaderTest {
pomReader.pomProperties.size() == 5
pomReader.pomProperties.containsKey('some.prop1')
pomReader.pomProperties.containsKey('some.prop2')
- pomReader.properties.size() == 9
+ pomReader.properties.size() == 11
pomReader.properties.containsKey('some.prop1')
pomReader.properties.containsKey('some.prop2')
}
@@ -487,11 +489,13 @@ class PomReaderTest extends AbstractPomReaderTest {
pomReader.licenses == new License[0]
!pomReader.hasParent()
pomReader.pomProperties.size() == 0
- pomReader.properties.size() == 13
+ pomReader.properties.size() == 15
pomReader.properties['parent.version'] == 'version-one'
pomReader.properties['parent.groupId'] == 'group-one'
+ pomReader.properties['parent.artifactId'] == 'artifact-one'
pomReader.properties['project.parent.version'] == 'version-one'
pomReader.properties['project.parent.groupId'] == 'group-one'
+ pomReader.properties['project.parent.artifactId'] == 'artifact-one'
pomReader.properties['project.groupId'] == 'group-one'
pomReader.properties['pom.groupId'] == 'group-one'
pomReader.properties['groupId'] == 'group-one'
@@ -848,4 +852,32 @@ class PomReaderTest extends AbstractPomReaderTest {
where:
packaging << ['pom', 'jar', 'ejb', 'war', 'ear', 'rar', 'par']
}
+
+ @Issue("GRADLE-3299")
+ def "can define GAV with reference to parent.GAV"() {
+ when:
+ pomFile << """
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>\${parent.groupId}</groupId>
+ <artifactId>\${parent.artifactId}</artifactId>
+ <version>\${parent.version}</version>
+
+ <parent>
+ <groupId>parent-group</groupId>
+ <artifactId>parent-artifact</artifactId>
+ <version>parent-version</version>
+ </parent>
+</project>
+"""
+ pomReader = new PomReader(locallyAvailableExternalResource)
+
+ then:
+ pomReader.parentGroupId == 'parent-group'
+ pomReader.parentArtifactId == 'parent-artifact'
+ pomReader.parentVersion == 'parent-version'
+ pomReader.groupId == pomReader.parentGroupId
+ pomReader.artifactId == pomReader.parentArtifactId
+ pomReader.version == pomReader.parentVersion
+ }
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/DefaultVersionSelectorSchemeTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/DefaultVersionSelectorSchemeTest.groovy
index e1f269e..5c49911 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/DefaultVersionSelectorSchemeTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/DefaultVersionSelectorSchemeTest.groovy
@@ -35,6 +35,8 @@ class DefaultVersionSelectorSchemeTest extends Specification {
"]1.0,)",
"(,2.0]",
"(,2.0[",
+ "[3]",
+ "[1.0]",
]
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelectorTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelectorTest.groovy
index ecfee14..234a865 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelectorTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/ivyresolve/strategy/VersionRangeSelectorTest.groovy
@@ -23,12 +23,14 @@ public class VersionRangeSelectorTest extends AbstractVersionSelectorTest {
expect:
isDynamic("[1.0,2.0]")
isDynamic("[1.0,)")
+ isDynamic("[1.0]")
}
def "never needs metadata"() {
expect:
!requiresMetadata("[1.0,2.0]")
!requiresMetadata("[1.0,)")
+ !requiresMetadata("[1.0]")
}
def "accepts candidate versions that fall into the selector's range"() {
@@ -148,6 +150,17 @@ public class VersionRangeSelectorTest extends AbstractVersionSelectorTest {
"2.5" | false
}
+ def "single-value range accepts only exact match"() {
+ expect:
+ accept("[1.0]", "1.0")
+
+ !accept("[1.0]", "1.1")
+ !accept("[1.0]", "1")
+ !accept("[1.0]", "1.01")
+ !accept("[1.0]", "0.9")
+ !accept("[1.0]", "1.0-beta1")
+ }
+
@Override
VersionSelector getSelector(String selector) {
return new VersionRangeSelector(selector, new DefaultVersionComparator().asStringComparator())
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationLocalComponentConverterTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationLocalComponentConverterTest.groovy
new file mode 100644
index 0000000..e428543
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ConfigurationLocalComponentConverterTest.groovy
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.artifacts.ivyservice.moduleconverter
+
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.internal.artifacts.DefaultModule
+import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory
+import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependenciesToModuleDescriptorConverter
+import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
+import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData
+import spock.lang.Specification
+
+public class ConfigurationLocalComponentConverterTest extends Specification {
+ def configurationsConverter = Mock(ConfigurationsToModuleDescriptorConverter)
+ def dependenciesConverter = Mock(DependenciesToModuleDescriptorConverter)
+ def componentIdentifierFactory = Mock(ComponentIdentifierFactory)
+ def configurationsToArtifactsConverter = Mock(ConfigurationsToArtifactsConverter)
+
+ ConfigurationLocalComponentConverter resolveModuleDescriptorConverter = new ConfigurationLocalComponentConverter(
+ configurationsConverter,
+ dependenciesConverter,
+ componentIdentifierFactory,
+ configurationsToArtifactsConverter)
+
+ def "converts for provided default module"() {
+ given:
+ def configurations = [Mock(Configuration), Mock(Configuration)] as Set
+ def module = new DefaultModule('group-one', 'name-one', 'version-one')
+
+ when:
+ def componentMetaData = resolveModuleDescriptorConverter.convert(new ConfigurationBackedComponent(module, configurations))
+
+ then:
+ 1 * configurationsConverter.addConfigurations(!null, configurations)
+ 1 * dependenciesConverter.addDependencyDescriptors(!null, configurations)
+ 1 * componentIdentifierFactory.createComponentIdentifier(module) >> new DefaultModuleComponentIdentifier('group-one', 'name-one', 'version-one')
+
+ and:
+ componentMetaData instanceof DefaultLocalComponentMetaData
+ componentMetaData.componentId == new DefaultModuleComponentIdentifier('group-one', 'name-one', 'version-one')
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverterTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverterTest.groovy
index 2576a88..6784cd8 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverterTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToArtifactsConverterTest.groovy
@@ -17,14 +17,14 @@
package org.gradle.api.internal.artifacts.ivyservice.moduleconverter
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.PublishArtifactSet
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData
import spock.lang.Specification
class DefaultConfigurationsToArtifactsConverterTest extends Specification {
def converter = new DefaultConfigurationsToArtifactsConverter()
def "adds artifacts from each configuration"() {
- def metaData = Mock(MutableLocalComponentMetaData)
+ def metaData = Mock(BuildableLocalComponentMetaData)
def config1 = Stub(Configuration)
def config2 = Stub(Configuration)
def artifacts1 = Stub(PublishArtifactSet)
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverterTest.java b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverterTest.java
index fe44ae4..b03f6e1 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverterTest.java
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/DefaultConfigurationsToModuleDescriptorConverterTest.java
@@ -17,13 +17,16 @@ package org.gradle.api.internal.artifacts.ivyservice.moduleconverter;
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.PublishArtifact;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
+import org.gradle.api.internal.artifacts.DefaultDependencySet;
import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier;
+import org.gradle.api.internal.artifacts.DefaultPublishArtifactSet;
import org.gradle.api.internal.artifacts.configurations.Configurations;
+import org.gradle.internal.component.external.model.DefaultIvyModulePublishMetaData;
import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier;
-import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData;
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData;
import org.gradle.util.TestUtil;
import org.gradle.util.WrapUtil;
import org.jmock.Expectations;
@@ -47,11 +50,11 @@ public class DefaultConfigurationsToModuleDescriptorConverterTest {
public void testAddConfigurations() {
Configuration configurationStub1 = createNamesAndExtendedConfigurationStub("conf1");
Configuration configurationStub2 = createNamesAndExtendedConfigurationStub("conf2", configurationStub1);
- MutableLocalComponentMetaData metaData = new DefaultLocalComponentMetaData(id, componentId, "status");
+ DefaultIvyModulePublishMetaData metaData = new DefaultIvyModulePublishMetaData(id, "status");
configurationsToModuleDescriptorConverter.addConfigurations(metaData, WrapUtil.toSet(configurationStub1, configurationStub2));
- ModuleDescriptor moduleDescriptor = metaData.toPublishMetaData().getModuleDescriptor();
+ ModuleDescriptor moduleDescriptor = metaData.getModuleDescriptor();
assertIvyConfigurationIsCorrect(moduleDescriptor.getConfiguration(configurationStub1.getName()),
expectedIvyConfiguration(configurationStub1));
assertIvyConfigurationIsCorrect(moduleDescriptor.getConfiguration(configurationStub2.getName()),
@@ -95,6 +98,12 @@ public class DefaultConfigurationsToModuleDescriptorConverterTest {
allowing(configurationStub).getHierarchy();
will(returnValue(WrapUtil.toSet(extendsFromConfigurations)));
+
+ allowing(configurationStub).getAllDependencies();
+ will(returnValue(new DefaultDependencySet("foo", WrapUtil.toDomainObjectSet(Dependency.class))));
+
+ allowing(configurationStub).getAllArtifacts();
+ will(returnValue(new DefaultPublishArtifactSet("foo", WrapUtil.toDomainObjectSet(PublishArtifact.class))));
}});
return configurationStub;
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ResolveLocalComponentFactoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ResolveLocalComponentFactoryTest.groovy
deleted file mode 100644
index 0dfa450..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/ResolveLocalComponentFactoryTest.groovy
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2007 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.internal.artifacts.ivyservice.moduleconverter
-
-import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor
-import org.gradle.api.artifacts.Configuration
-import org.gradle.api.internal.artifacts.DefaultModule
-import org.gradle.api.internal.artifacts.component.ComponentIdentifierFactory
-import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.dependencies.DependenciesToModuleDescriptorConverter
-import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
-import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData
-import spock.lang.Specification
-
-public class ResolveLocalComponentFactoryTest extends Specification {
- def configurationsConverter = Mock(ConfigurationsToModuleDescriptorConverter)
- def dependenciesConverter = Mock(DependenciesToModuleDescriptorConverter)
- def componentIdentifierFactory = Mock(ComponentIdentifierFactory)
- def configurationsToArtifactsConverter = Mock(ConfigurationsToArtifactsConverter)
-
- ResolveLocalComponentFactory resolveModuleDescriptorConverter = new ResolveLocalComponentFactory(
- configurationsConverter,
- dependenciesConverter,
- componentIdentifierFactory,
- configurationsToArtifactsConverter)
-
- def "converts for provided default module"() {
- given:
- def configurations = [Mock(Configuration), Mock(Configuration)] as Set
- def module = new DefaultModule('group-one', 'name-one', 'version-one')
-
- when:
- def componentMetaData = resolveModuleDescriptorConverter.convert(new ComponentConverterSource(configurations, module))
-
- then:
- 1 * configurationsConverter.addConfigurations(!null, configurations)
- 1 * dependenciesConverter.addDependencyDescriptors(!null, configurations)
- 1 * componentIdentifierFactory.createComponentIdentifier(module) >> new DefaultModuleComponentIdentifier('group-one', 'name-one', 'version-one')
-
- and:
- componentMetaData instanceof DefaultLocalComponentMetaData
- componentMetaData.toResolveMetaData().componentId == new DefaultModuleComponentIdentifier('group-one', 'name-one', 'version-one')
- componentMetaData.toPublishMetaData().moduleDescriptor instanceof DefaultModuleDescriptor
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverterTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverterTest.groovy
index be117a6..d033d08 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverterTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/moduleconverter/dependencies/DefaultDependenciesToModuleDescriptorConverterTest.groovy
@@ -22,7 +22,7 @@ import org.gradle.api.artifacts.ExcludeRule
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.ExcludeRuleConverter
import org.gradle.internal.component.model.DependencyMetaData
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData
+import org.gradle.internal.component.local.model.BuildableLocalComponentMetaData
import spock.lang.Specification
import static org.gradle.util.WrapUtil.toDomainObjectSet
@@ -34,7 +34,7 @@ public class DefaultDependenciesToModuleDescriptorConverterTest extends Specific
def converter = new DefaultDependenciesToModuleDescriptorConverter(dependencyDescriptorFactory, excludeRuleConverter)
def descriptor = Mock(DefaultModuleDescriptor)
- def metaData = Mock(MutableLocalComponentMetaData)
+ def metaData = Mock(BuildableLocalComponentMetaData)
def configuration = Mock(Configuration)
def dependencySet = Mock(DependencySet.class);
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolverTest.groovy
index 85c5cce..cff3298 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolverTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/projectmodule/ProjectDependencyResolverTest.groovy
@@ -16,34 +16,24 @@
package org.gradle.api.internal.artifacts.ivyservice.projectmodule
import org.apache.ivy.core.module.descriptor.DependencyDescriptor
import org.gradle.api.artifacts.component.ComponentIdentifier
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory
-import org.gradle.internal.component.external.model.ModuleComponentResolveMetaData
import org.gradle.internal.component.local.model.DefaultProjectComponentIdentifier
import org.gradle.internal.component.local.model.DefaultProjectComponentSelector
-import org.gradle.internal.component.local.model.MutableLocalComponentMetaData
+import org.gradle.internal.component.local.model.LocalComponentMetaData
import org.gradle.internal.component.model.ComponentOverrideMetadata
import org.gradle.internal.component.model.DefaultComponentOverrideMetadata
import org.gradle.internal.component.model.DependencyMetaData
import org.gradle.internal.resolve.ModuleVersionResolveException
-import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver
-import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver
import org.gradle.internal.resolve.result.BuildableComponentIdResolveResult
import org.gradle.internal.resolve.result.BuildableComponentResolveResult
import spock.lang.Specification
class ProjectDependencyResolverTest extends Specification {
final ProjectComponentRegistry registry = Mock()
- final DependencyToComponentIdResolver target = Mock()
- final ComponentMetaDataResolver componentResolver = Mock()
- final LocalComponentFactory converter = Mock()
- final ProjectDependencyResolver resolver = new ProjectDependencyResolver(registry, converter, target, componentResolver)
+ final ProjectDependencyResolver resolver = new ProjectDependencyResolver(registry)
def "resolves project dependency"() {
setup:
- def resolveMetaData = Stub(ModuleComponentResolveMetaData)
- def componentMetaData = Stub(MutableLocalComponentMetaData) {
- toResolveMetaData() >> resolveMetaData
- }
+ def componentMetaData = Mock(LocalComponentMetaData)
def result = Mock(BuildableComponentIdResolveResult)
def dependencyMetaData = Stub(DependencyMetaData) {
getSelector() >> DefaultProjectComponentSelector.newSelector(":project")
@@ -54,16 +44,13 @@ class ProjectDependencyResolverTest extends Specification {
then:
1 * registry.getProject(":project") >> componentMetaData
- 1 * result.resolved(resolveMetaData)
+ 1 * result.resolved(componentMetaData)
0 * result._
}
def "resolves project component"() {
setup:
- def resolveMetaData = Stub(ModuleComponentResolveMetaData)
- def componentMetaData = Stub(MutableLocalComponentMetaData) {
- toResolveMetaData() >> resolveMetaData
- }
+ def componentMetaData = Mock(LocalComponentMetaData)
def result = Mock(BuildableComponentResolveResult)
def projectComponentId = new DefaultProjectComponentIdentifier(":projectPath")
@@ -72,11 +59,11 @@ class ProjectDependencyResolverTest extends Specification {
then:
1 * registry.getProject(":projectPath") >> componentMetaData
- 1 * result.resolved(resolveMetaData)
+ 1 * result.resolved(componentMetaData)
0 * result._
}
- def "delegates to backing resolver for non-project dependency"() {
+ def "doesn't try to resolve non-project dependency"() {
def result = Mock(BuildableComponentIdResolveResult)
def dependencyDescriptor = Stub(DependencyDescriptor)
def dependencyMetaData = Stub(DependencyMetaData) {
@@ -87,11 +74,11 @@ class ProjectDependencyResolverTest extends Specification {
resolver.resolve(dependencyMetaData, result)
then:
- 1 * target.resolve(dependencyMetaData, result)
+ 0 * registry.getProject(_)
0 * _
}
- def "delegates to backing resolver for non-project identifier"() {
+ def "doesn't try to resolve non-project identifier"() {
def result = Mock(BuildableComponentResolveResult)
def componentIdentifier = Mock(ComponentIdentifier)
def overrideMetaData = Mock(ComponentOverrideMetadata)
@@ -100,7 +87,7 @@ class ProjectDependencyResolverTest extends Specification {
resolver.resolve(componentIdentifier, overrideMetaData, result)
then:
- 1 * componentResolver.resolve(componentIdentifier, overrideMetaData, result)
+ 0 * registry.getProject(_)
0 * _
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DependencyGraphBuilderTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DependencyGraphBuilderTest.groovy
index e85bf2c..88684cd 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DependencyGraphBuilderTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/DependencyGraphBuilderTest.groovy
@@ -14,33 +14,40 @@
* limitations under the License.
*/
package org.gradle.api.internal.artifacts.ivyservice.resolveengine
-
-import org.apache.ivy.core.module.descriptor.*
+import org.apache.ivy.core.module.descriptor.DefaultExcludeRule
import org.apache.ivy.core.module.id.ArtifactId
+import org.apache.ivy.core.module.id.ModuleId
import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.ivy.plugins.matcher.ExactPatternMatcher
import org.apache.ivy.plugins.matcher.PatternMatcher
import org.gradle.api.artifacts.*
import org.gradle.api.artifacts.component.ComponentIdentifier
+import org.gradle.api.artifacts.component.ComponentSelector
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier
import org.gradle.api.internal.artifacts.DefaultModuleVersionSelector
import org.gradle.api.internal.artifacts.configurations.ConfigurationInternal
import org.gradle.api.internal.artifacts.dsl.ModuleReplacementsData
import org.gradle.api.internal.artifacts.ivyservice.CacheLockingManager
import org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DefaultResolvedArtifactsBuilder
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactsGraphVisitor
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.CompositeDependencyArtifactsVisitor
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.CompositeDependencyGraphVisitor
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphBuilder
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.conflicts.DefaultConflictHandler
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.DefaultResolvedArtifactsBuilder
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.DefaultResolvedConfigurationBuilder
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.TransientConfigurationResultsBuilder
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.TransientConfigurationResultsLoader
-import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedProjectConfigurationResultBuilder
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.oldresult.*
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResultBuilder
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.projectresult.ResolvedLocalComponentsResultGraphVisitor
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.DummyBinaryStore
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.DummyStore
import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ResolutionResultBuilder
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.result.ResolutionResultDependencyGraphVisitor
+import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact
+import org.gradle.api.internal.tasks.DefaultTaskDependency
import org.gradle.api.specs.Spec
-import org.gradle.internal.component.external.model.BuildableIvyModuleResolveMetaData
-import org.gradle.internal.component.external.model.ModuleComponentResolveMetaData
+import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
+import org.gradle.internal.component.external.model.DefaultModuleComponentSelector
+import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData
import org.gradle.internal.component.local.model.DefaultProjectComponentIdentifier
import org.gradle.internal.component.local.model.DslOriginDependencyMetaDataWrapper
import org.gradle.internal.component.model.*
@@ -57,7 +64,6 @@ import spock.lang.Specification
import static org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier.newId
import static org.gradle.api.internal.artifacts.DefaultModuleVersionSelector.newSelector
-import static org.gradle.api.internal.artifacts.ivyservice.IvyUtil.createModuleRevisionId
class DependencyGraphBuilderTest extends Specification {
def configuration = Mock(ConfigurationInternal)
@@ -66,35 +72,44 @@ class DependencyGraphBuilderTest extends Specification {
def metaDataResolver = Mock(ComponentMetaDataResolver)
def artifactResolver = Mock(ArtifactResolver)
def resolutionResultBuilder = Mock(ResolutionResultBuilder)
- def projectModelBuilder = Mock(ResolvedProjectConfigurationResultBuilder)
- def TestMetaData root = project('root')
+ def projectModelBuilder = Mock(ResolvedLocalComponentsResultBuilder)
+ def root = project('root', '1.0', ['root'])
def moduleResolver = Mock(ResolveContextToComponentResolver)
def dependencyToConfigurationResolver = new DefaultDependencyToConfigurationResolver()
def moduleReplacements = Mock(ModuleReplacementsData)
- def builder = new DependencyGraphBuilder(idResolver, metaDataResolver, moduleResolver, artifactResolver, new DefaultConflictHandler(conflictResolver, moduleReplacements), dependencyToConfigurationResolver)
+ DependencyGraphBuilder builder
def setup() {
- config(root, 'root', 'default')
_ * configuration.name >> 'root'
_ * configuration.path >> 'root'
_ * moduleResolver.resolve(_, _) >> { it[1].resolved(root) }
-
_ * artifactResolver.resolveModuleArtifacts(_, _, _,) >> { ComponentResolveMetaData module, ComponentUsage context, BuildableArtifactSetResolveResult result ->
result.resolved(module.getConfiguration(context.configurationName).artifacts)
}
+
+ builder = new DependencyGraphBuilder(idResolver, metaDataResolver, moduleResolver, dependencyToConfigurationResolver, new DefaultConflictHandler(conflictResolver, moduleReplacements))
}
private DefaultLenientConfiguration resolve() {
def transientConfigurationResultsBuilder = new TransientConfigurationResultsBuilder(new DummyBinaryStore(), new DummyStore())
def modelBuilder = new DefaultResolvedConfigurationBuilder(transientConfigurationResultsBuilder)
+ def configurationResultVisitor = new ResolvedConfigurationDependencyGraphVisitor(modelBuilder)
+
+ def resolutionResultVisitor = new ResolutionResultDependencyGraphVisitor(resolutionResultBuilder)
+ def projectComponentsVisitor = new ResolvedLocalComponentsResultGraphVisitor(projectModelBuilder)
+
def artifactsBuilder = new DefaultResolvedArtifactsBuilder()
+ def artifactsGraphVisitor = new ResolvedArtifactsGraphVisitor(new CompositeDependencyArtifactsVisitor(artifactsBuilder, configurationResultVisitor), artifactResolver)
+
+ def graphVisitor = new CompositeDependencyGraphVisitor(configurationResultVisitor, resolutionResultVisitor, projectComponentsVisitor, artifactsGraphVisitor)
- builder.resolve(configuration, resolutionResultBuilder, modelBuilder, artifactsBuilder, projectModelBuilder)
+ builder.resolve(configuration, graphVisitor)
def graphResults = modelBuilder.complete()
def artifactResults = artifactsBuilder.resolve()
- new DefaultLenientConfiguration(configuration, Stub(CacheLockingManager), graphResults, artifactResults, new TransientConfigurationResultsLoader(transientConfigurationResultsBuilder, graphResults, artifactResults))
+ new DefaultLenientConfiguration(configuration, Stub(CacheLockingManager), graphResults.getUnresolvedDependencies(),
+ artifactResults, new TransientConfigurationResultsLoader(transientConfigurationResultsBuilder, graphResults, artifactResults))
}
def "does not resolve a given module selector more than once"() {
@@ -152,11 +167,12 @@ class DependencyGraphBuilderTest extends Specification {
resolve()
then:
- 1 * projectModelBuilder.registerRoot({ it.projectPath == ':root'})
- 1 * projectModelBuilder.addProjectComponentResult({ it.projectPath == ':root'}, { it == 'root' })
- 1 * projectModelBuilder.addProjectComponentResult({ it.projectPath == ':a'}, { it == 'default' })
- 1 * projectModelBuilder.addProjectComponentResult({ it.projectPath == ':b'}, { it == 'default' })
- 1 * projectModelBuilder.addProjectComponentResult({ it.projectPath == ':c'}, { it == 'default' })
+ 1 * projectModelBuilder.projectConfigurationResolved({ it.projectPath == ':a'}, { it == 'default' })
+ 1 * projectModelBuilder.localComponentResolved({ it.projectPath == ':a'}, _)
+ 1 * projectModelBuilder.projectConfigurationResolved({ it.projectPath == ':b'}, { it == 'default' })
+ 1 * projectModelBuilder.localComponentResolved({ it.projectPath == ':b'}, _)
+ 1 * projectModelBuilder.projectConfigurationResolved({ it.projectPath == ':c'}, { it == 'default' })
+ 1 * projectModelBuilder.localComponentResolved({ it.projectPath == ':c'}, _)
0 * projectModelBuilder._
}
@@ -925,30 +941,30 @@ class DependencyGraphBuilderTest extends Specification {
}
def revision(String name, String revision = '1.0') {
- def descriptor = new DefaultModuleDescriptor(createModuleRevisionId("group", name, revision), "release", new Date())
- def metaData = new TestModuleMetaData(descriptor)
- config(metaData, 'default')
- descriptor.addArtifact('default', new DefaultArtifact(descriptor.moduleRevisionId, new Date(), "art1", "art", "zip"))
+ // TODO Shouldn't really be using the local component implementation here
+ def id = newId("group", name, revision)
+ def metaData = new DefaultLocalComponentMetaData(id, DefaultModuleComponentIdentifier.newId(id), "release")
+ metaData.addConfiguration("default", "defaultConfig", [] as Set<String>, ["default"] as Set<String>, true, true, new DefaultTaskDependency())
+ metaData.addArtifacts("default", [new DefaultPublishArtifact("art1", "zip", "art", null, new Date(), new File("art1.zip"))])
+// def descriptor = new DefaultModuleDescriptor(createModuleRevisionId("group", name, revision), "release", new Date())
+// def metaData = new MutableModuleMetaData(descriptor)
+// metaData.descriptor.addConfiguration(new org.apache.ivy.core.module.descriptor.Configuration('default', org.apache.ivy.core.module.descriptor.Configuration.Visibility.PUBLIC, null, [] as String[], true, null))
+// descriptor.addArtifact('default', new DefaultArtifact(descriptor.moduleRevisionId, new Date(), "art1", "art", "zip"))
return metaData
}
- def project(String name, String revision = '1.0') {
- def revisionId = createModuleRevisionId("group", name, revision)
- def descriptor = new DefaultModuleDescriptor(revisionId, "release", new Date())
- def metaData = new TestProjectMetaData(newId(revisionId), descriptor, DefaultProjectComponentIdentifier.newId(":${name}"))
- config(metaData, 'default')
- descriptor.addArtifact('default', new DefaultArtifact(descriptor.moduleRevisionId, new Date(), "art1", "art", "zip"))
+ def project(String name, String revision = '1.0', List<String> extraConfigs = []) {
+ def metaData = new DefaultLocalComponentMetaData(newId("group", name, revision), DefaultProjectComponentIdentifier.newId(":${name}"), "release")
+ metaData.addConfiguration("default", "defaultConfig", [] as Set<String>, ["default"] as Set<String>, true, true, new DefaultTaskDependency())
+ extraConfigs.each { String config ->
+ metaData.addConfiguration(config, "${config}Config", ["default"] as Set<String>, ["default", config] as Set<String>, true, true, new DefaultTaskDependency())
+ }
+ metaData.addArtifacts("default", [new DefaultPublishArtifact("art1", "zip", "art", null, new Date(), new File("art1.zip"))])
return metaData
}
- def config(ComponentResolveMetaData metaData, String name, String... extendsFrom) {
- def configuration = new org.apache.ivy.core.module.descriptor.Configuration(name, org.apache.ivy.core.module.descriptor.Configuration.Visibility.PUBLIC, null, extendsFrom, true, null)
- metaData.descriptor.addConfiguration(configuration)
- return configuration
- }
-
- def traverses(Map<String, ?> args = [:], TestMetaData from, ComponentResolveMetaData to) {
- def dependencyMetaData = dependsOn(args, from, to.descriptor.moduleRevisionId)
+ def traverses(Map<String, ?> args = [:], def from, ComponentResolveMetaData to) {
+ def dependencyMetaData = dependsOn(args, from, to.id)
selectorResolvesTo(dependencyMetaData, to.componentId, to.id)
1 * metaDataResolver.resolve(to.componentId, _, _) >> { ComponentIdentifier id, ComponentOverrideMetadata requestMetaData, BuildableComponentResolveResult result ->
@@ -956,28 +972,28 @@ class DependencyGraphBuilderTest extends Specification {
}
}
- def doesNotTraverse(Map<String, ?> args = [:], TestMetaData from, ComponentResolveMetaData to) {
- def dependencyMetaData = dependsOn(args, from, to.descriptor.moduleRevisionId)
+ def doesNotTraverse(Map<String, ?> args = [:], def from, ComponentResolveMetaData to) {
+ def dependencyMetaData = dependsOn(args, from, to.id)
selectorResolvesTo(dependencyMetaData, to.componentId, to.id)
0 * metaDataResolver.resolve(to.componentId, _, _)
}
- def doesNotResolve(Map<String, ?> args = [:], TestMetaData from, ComponentResolveMetaData to) {
- def dependencyMetaData = dependsOn(args, from, to.descriptor.moduleRevisionId)
+ def doesNotResolve(Map<String, ?> args = [:], def from, ComponentResolveMetaData to) {
+ def dependencyMetaData = dependsOn(args, from, to.id)
0 * idResolver.resolve(dependencyMetaData, _)
0 * metaDataResolver.resolve(to.componentId, _, _)
}
- def traversesMissing(Map<String, ?> args = [:], TestMetaData from, ComponentResolveMetaData to) {
- def dependencyMetaData = dependsOn(args, from, to.descriptor.moduleRevisionId)
+ def traversesMissing(Map<String, ?> args = [:], def from, ComponentResolveMetaData to) {
+ def dependencyMetaData = dependsOn(args, from, to.id)
selectorResolvesTo(dependencyMetaData, to.componentId, to.id)
1 * metaDataResolver.resolve(to.componentId, _, _) >> { ComponentIdentifier id, ComponentOverrideMetadata requestMetaData, BuildableComponentResolveResult result ->
result.notFound(to.componentId)
}
}
- def traversesBroken(Map<String, ?> args = [:], TestMetaData from, ComponentResolveMetaData to) {
- def dependencyMetaData = dependsOn(args, from, to.descriptor.moduleRevisionId)
+ def traversesBroken(Map<String, ?> args = [:], def from, ComponentResolveMetaData to) {
+ def dependencyMetaData = dependsOn(args, from, to.id)
selectorResolvesTo(dependencyMetaData, to.componentId, to.id)
1 * metaDataResolver.resolve(to.componentId, _, _) >> { ComponentIdentifier id, ComponentOverrideMetadata requestMetaData, BuildableComponentResolveResult result ->
result.failed(new ModuleVersionResolveException(newSelector("a", "b", "c"), "broken"))
@@ -992,28 +1008,32 @@ class DependencyGraphBuilderTest extends Specification {
moduleVersionIdentifier
}
- def brokenSelector(Map<String, ?> args = [:], TestMetaData from, String to) {
- def dependencyMetaData = dependsOn(args, from, createModuleRevisionId("group", to, "1.0"))
+ def brokenSelector(Map<String, ?> args = [:], def from, String to) {
+ def dependencyMetaData = dependsOn(args, from, newId("group", to, "1.0"))
1 * idResolver.resolve(dependencyMetaData, _) >> { DependencyMetaData dep, BuildableComponentIdResolveResult result ->
result.failed(new ModuleVersionResolveException(newSelector("a", "b", "c"), "broken"))
}
}
- def dependsOn(Map<String, ?> args = [:], TestMetaData from, ModuleRevisionId to) {
- def dependencyId = args.revision ? createModuleRevisionId(to.moduleId.organisation, to.moduleId.name, args.revision) : to
+ def dependsOn(Map<String, ?> args = [:], ComponentResolveMetaData from, ModuleVersionIdentifier to) {
+ ModuleVersionIdentifier dependencyId = args.revision ? newId(to.group, to.name, args.revision) : to
boolean transitive = args.transitive == null || args.transitive
boolean force = args.force
- def descriptor = new DefaultDependencyDescriptor(from.descriptor, dependencyId, force, false, transitive)
- descriptor.addDependencyConfiguration("default", "default")
+ ModuleVersionSelector selector = newSelector(dependencyId.group, dependencyId.name, dependencyId.version)
+ ComponentSelector componentSelector = DefaultModuleComponentSelector.newSelector(selector)
+ def excludeRules = []
if (args.exclude) {
- descriptor.addExcludeRule("default", new DefaultExcludeRule(new ArtifactId(
- args.exclude.descriptor.moduleRevisionId.moduleId, PatternMatcher.ANY_EXPRESSION,
+ ComponentResolveMetaData excluded = args.exclude
+ excludeRules << new DefaultExcludeRule(new ArtifactId(new ModuleId(excluded.id.group, excluded.id.name),
+ PatternMatcher.ANY_EXPRESSION,
PatternMatcher.ANY_EXPRESSION,
PatternMatcher.ANY_EXPRESSION),
- ExactPatternMatcher.INSTANCE, null))
+ ExactPatternMatcher.INSTANCE, null)
}
- def dependencyMetaData = new DslOriginDependencyMetaDataWrapper(new DefaultDependencyMetaData(descriptor), Stub(ModuleDependency))
- from.addDependency(dependencyMetaData)
+ def dependencyMetaData = new LocalComponentDependencyMetaData(componentSelector, selector, "default", "default", [] as Set<IvyArtifactName>,
+ excludeRules as org.apache.ivy.core.module.descriptor.ExcludeRule[], force, false, transitive)
+ dependencyMetaData = new DslOriginDependencyMetaDataWrapper(dependencyMetaData, Stub(ModuleDependency))
+ from.getDependencies().add(dependencyMetaData)
return dependencyMetaData
}
@@ -1023,7 +1043,7 @@ class DependencyGraphBuilderTest extends Specification {
}
}
- def ids(ModuleComponentResolveMetaData... descriptors) {
+ def ids(ComponentResolveMetaData... descriptors) {
return descriptors.collect { it.id } as Set
}
@@ -1042,54 +1062,4 @@ class DependencyGraphBuilderTest extends Specification {
def artifacts(LenientConfiguration config) {
return config.resolvedArtifacts.collect { it.moduleVersion.id } as Set
}
-
- private interface TestMetaData extends ComponentResolveMetaData {
- void addDependency(DependencyMetaData dependencyMetaData)
- }
-
- private static class TestModuleMetaData extends BuildableIvyModuleResolveMetaData implements TestMetaData {
- def deps = []
-
- TestModuleMetaData(DefaultModuleDescriptor module) {
- super(module)
- }
-
- @Override
- void addDependency(DependencyMetaData dependencyMetaData) {
- deps.add(dependencyMetaData)
- }
-
- @Override
- protected List<DependencyMetaData> populateDependenciesFromDescriptor() {
- return deps
- }
- }
-
- private static class TestProjectMetaData extends AbstractModuleDescriptorBackedMetaData implements TestMetaData {
- def deps = []
-
- TestProjectMetaData(ModuleVersionIdentifier moduleVersionIdentifier, ModuleDescriptor module, ComponentIdentifier componentIdentifier) {
- super(moduleVersionIdentifier, module, componentIdentifier)
- }
-
- @Override
- void addDependency(DependencyMetaData dependencyMetaData) {
- deps.add(dependencyMetaData)
- }
-
- @Override
- protected List<DependencyMetaData> populateDependenciesFromDescriptor() {
- return deps
- }
-
- @Override
- protected Set<ComponentArtifactMetaData> getArtifactsForConfiguration(ConfigurationMetaData configuration) {
- return []
- }
-
- @Override
- ComponentResolveMetaData withSource(ModuleSource source) {
- return null
- }
- }
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializerTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializerTest.groovy
index 8403cd8..58e9d8c 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializerTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentIdentifierSerializerTest.groovy
@@ -16,11 +16,11 @@
package org.gradle.api.internal.artifacts.ivyservice.resolveengine.result
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
-import org.gradle.internal.component.local.model.DefaultLibraryComponentIdentifier
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier
import org.gradle.internal.component.local.model.DefaultProjectComponentIdentifier
import org.gradle.internal.serialize.SerializerSpec
@@ -51,10 +51,10 @@ class ComponentIdentifierSerializerTest extends SerializerSpec {
def "serializes LibraryIdentifier"() {
given:
- LibraryComponentIdentifier selection = new DefaultLibraryComponentIdentifier(':project', 'lib')
+ LibraryBinaryIdentifier selection = new DefaultLibraryBinaryIdentifier(':project', 'lib', 'variant')
when:
- LibraryComponentIdentifier result = serialize(selection, serializer)
+ LibraryBinaryIdentifier result = serialize(selection, serializer)
then:
result.projectPath == ':project'
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializerTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializerTest.groovy
index f50ee77..dd18c10 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializerTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/result/ComponentSelectorSerializerTest.groovy
@@ -23,6 +23,7 @@ import org.gradle.internal.component.external.model.DefaultModuleComponentSelect
import org.gradle.internal.component.local.model.DefaultLibraryComponentSelector
import org.gradle.internal.component.local.model.DefaultProjectComponentSelector
import org.gradle.internal.serialize.SerializerSpec
+import spock.lang.Unroll
public class ComponentSelectorSerializerTest extends SerializerSpec {
ComponentSelectorSerializer serializer = new ComponentSelectorSerializer()
@@ -60,15 +61,23 @@ public class ComponentSelectorSerializerTest extends SerializerSpec {
result.projectPath == ':myPath'
}
- def "serializes LibraryComponentSelector"() {
+ @Unroll
+ def "serializes LibraryComponentSelector project #projectPath library #libraryName variant #variant"() {
given:
- LibraryComponentSelector selection = new DefaultLibraryComponentSelector(':myPath', 'myLib')
+ LibraryComponentSelector selection = new DefaultLibraryComponentSelector(projectPath, libraryName)
when:
LibraryComponentSelector result = serialize(selection, serializer)
then:
- result.projectPath == ':myPath'
- result.libraryName == 'myLib'
+ result.projectPath == projectPath
+ result.libraryName == libraryName
+
+ where:
+ projectPath | libraryName
+ ':myPath' | null
+ ':myPath' | 'myLib'
+ ':myPath' | null
+ ':myPath' | 'myLib'
}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactoryTest.groovy
index d6e513a..7432bcc 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/resolveengine/store/ResolutionResultsStoreFactoryTest.groovy
@@ -82,12 +82,12 @@ class ResolutionResultsStoreFactoryTest extends Specification {
def set2 = f.createStoreSet()
expect:
- set1.newModelStore().load({"1"} as org.gradle.internal.Factory) == "1"
- set1.newModelStore().load({"2"} as org.gradle.internal.Factory) == "1"
- set2.newModelStore().load({"3"} as org.gradle.internal.Factory) == "3"
+ set1.oldModelCache().load({"1"} as org.gradle.internal.Factory) == "1"
+ set1.oldModelCache().load({"2"} as org.gradle.internal.Factory) == "1"
+ set2.oldModelCache().load({"3"} as org.gradle.internal.Factory) == "3"
- set1.oldModelStore().load({"1"} as org.gradle.internal.Factory) == "1"
- set1.oldModelStore().load({"2"} as org.gradle.internal.Factory) == "1"
- set2.oldModelStore().load({"3"} as org.gradle.internal.Factory) == "3"
+ set1.newModelCache().load({"1"} as org.gradle.internal.Factory) == "1"
+ set1.newModelCache().load({"2"} as org.gradle.internal.Factory) == "1"
+ set2.newModelCache().load({"3"} as org.gradle.internal.Factory) == "3"
}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQueryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQueryTest.groovy
index 684d683..7567a0d 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQueryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/query/DefaultArtifactResolutionQueryTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.api.internal.artifacts.query
+
import org.gradle.api.artifacts.component.ComponentIdentifier
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.artifacts.dsl.RepositoryHandler
@@ -25,8 +26,8 @@ import org.gradle.api.component.Component
import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules
import org.gradle.api.internal.artifacts.configurations.ConfigurationContainerInternal
import org.gradle.api.internal.artifacts.ivyservice.CacheLockingManager
-import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChain
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolveIvyFactory
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers
import org.gradle.api.internal.component.ComponentTypeRegistration
import org.gradle.api.internal.component.ComponentTypeRegistry
import org.gradle.internal.Factory
@@ -48,7 +49,7 @@ class DefaultArtifactResolutionQueryTest extends Specification {
def cacheLockingManager = Mock(CacheLockingManager)
def componentTypeRegistry = Mock(ComponentTypeRegistry)
def artifactResolver = Mock(ArtifactResolver)
- def repositoryChain = Mock(RepositoryChain)
+ def repositoryChain = Mock(ComponentResolvers)
def componentMetaDataResolver = Mock(ComponentMetaDataResolver)
def componentResolveMetaData = Mock(ComponentResolveMetaData)
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepositoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepositoryTest.groovy
index d637e93..143591a 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepositoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/AbstractAuthenticationSupportedRepositoryTest.groovy
@@ -17,10 +17,14 @@
package org.gradle.api.internal.artifacts.repositories
import org.gradle.api.Action
+import org.gradle.api.InvalidUserDataException
+import org.gradle.api.artifacts.repositories.AuthenticationContainer
import org.gradle.api.artifacts.repositories.PasswordCredentials
+import org.gradle.authentication.Authentication
import org.gradle.api.credentials.AwsCredentials
import org.gradle.api.credentials.Credentials
import org.gradle.api.internal.ClosureBackedAction
+import org.gradle.internal.authentication.DefaultAuthenticationContainer
import org.gradle.internal.credentials.DefaultAwsCredentials
import org.gradle.internal.reflect.DirectInstantiator
import org.gradle.internal.reflect.Instantiator
@@ -30,7 +34,7 @@ import spock.lang.Unroll
class AbstractAuthenticationSupportedRepositoryTest extends Specification {
AuthSupportedRepository repo() {
- new AuthSupportedRepository(DirectInstantiator.INSTANCE)
+ new AuthSupportedRepository(DirectInstantiator.INSTANCE, new DefaultAuthenticationContainer(DirectInstantiator.INSTANCE))
}
def "should configure default password credentials using an action only"() {
@@ -39,9 +43,10 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
enhanceCredentials(passwordCredentials, 'username', 'password')
Instantiator instantiator = Mock()
+ AuthenticationContainer authenticationContainer = Stub()
instantiator.newInstance(DefaultPasswordCredentials) >> passwordCredentials
- AuthSupportedRepository repo = new AuthSupportedRepository(instantiator)
+ AuthSupportedRepository repo = new AuthSupportedRepository(instantiator, authenticationContainer)
def configAction = new Action<PasswordCredentials>() {
@Override
@@ -66,9 +71,10 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
enhanceCredentials(enhancedCredentials, 'accessKey', 'secretKey')
Instantiator instantiator = Mock()
+ AuthenticationContainer authenticationContainer = Mock()
instantiator.newInstance(DefaultAwsCredentials) >> enhancedCredentials
- AuthSupportedRepository repo = new AuthSupportedRepository(instantiator)
+ AuthSupportedRepository repo = new AuthSupportedRepository(instantiator, authenticationContainer)
def action = new ClosureBackedAction<DefaultAwsCredentials>({
accessKey = 'key'
@@ -84,7 +90,8 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
@Unroll
def "getCredentials(Class) instantiates the correct credential types "() {
Instantiator instantiator = Mock()
- AuthSupportedRepository repo = new AuthSupportedRepository(instantiator)
+ AuthenticationContainer authenticationContainer = Mock()
+ AuthSupportedRepository repo = new AuthSupportedRepository(instantiator, authenticationContainer)
when:
repo.getCredentials(credentialType) == credentials
@@ -100,7 +107,8 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
def "getCredentials(Class) throws IllegalArgumentException when setting credentials with different type than already set"() {
Instantiator instantiator = Mock()
- AuthSupportedRepository repo = new AuthSupportedRepository(instantiator)
+ AuthenticationContainer authenticationContainer = Mock()
+ AuthSupportedRepository repo = new AuthSupportedRepository(instantiator, authenticationContainer)
1 * instantiator.newInstance(_) >> credentials
when:
@@ -117,7 +125,7 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
}
def "getCredentials(Class) throws IllegalArgumentException when setting credentials with unknown type"() {
- AuthSupportedRepository repo = new AuthSupportedRepository(Mock(Instantiator))
+ AuthSupportedRepository repo = new AuthSupportedRepository(Mock(Instantiator), Mock(AuthenticationContainer))
when:
repo.getCredentials(UnsupportedCredentials)
then:
@@ -127,9 +135,10 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
def "credentials(Class, Action) creates credentials on demand if required"() {
Instantiator instantiator = Mock()
+ AuthenticationContainer authenticationContainer = Stub()
Action action = Mock()
- AuthSupportedRepository repo = new AuthSupportedRepository(instantiator)
+ AuthSupportedRepository repo = new AuthSupportedRepository(instantiator, authenticationContainer)
when:
repo.credentials(credentialType, action)
@@ -148,17 +157,18 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
def "can reference alternative credentials"() {
given:
Instantiator instantiator = Mock()
+ AuthenticationContainer authenticationContainer = Stub()
Action action = Mock()
def credentials = Mock(AwsCredentials)
1 * instantiator.newInstance(_) >> credentials
1 * action.execute(credentials)
- AuthSupportedRepository repo = new AuthSupportedRepository(instantiator)
+ AuthSupportedRepository repo = new AuthSupportedRepository(instantiator, authenticationContainer)
when:
repo.credentials(AwsCredentials, action)
then:
- repo.configuredCredentials instanceof AwsCredentials
+ repo.getCredentials(AwsCredentials) instanceof AwsCredentials
}
def "get credentials throws ISE if not using password credentials"() {
@@ -183,6 +193,23 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
thrown IllegalStateException
}
+ def "authentication container throws IUD with authentication of unknown type"() {
+ def action = new Action<AuthenticationContainer>() {
+ @Override
+ void execute(AuthenticationContainer authentications) {
+ authentications.create('basic', UnsupportedAuthentication)
+ }
+ }
+
+ when:
+ repo().with {
+ authentication(action)
+ }
+
+ then:
+ thrown InvalidUserDataException
+ }
+
private void enhanceCredentials(Credentials credentials, String... props) {
props.each { prop ->
credentials.metaClass."$prop" = { String val ->
@@ -192,10 +219,12 @@ class AbstractAuthenticationSupportedRepositoryTest extends Specification {
}
class AuthSupportedRepository extends AbstractAuthenticationSupportedRepository {
- AuthSupportedRepository(Instantiator instantiator) {
- super(instantiator)
+ AuthSupportedRepository(Instantiator instantiator, AuthenticationContainer authenticationContainer) {
+ super(instantiator, authenticationContainer)
}
}
interface UnsupportedCredentials extends Credentials {}
+
+ interface UnsupportedAuthentication extends Authentication {}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactoryTest.groovy
index 1566abb..ebe2135 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultBaseRepositoryFactoryTest.groovy
@@ -15,7 +15,6 @@
*/
package org.gradle.api.internal.artifacts.repositories
-
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.internal.artifacts.dsl.DefaultRepositoryHandler
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser
@@ -24,6 +23,8 @@ import org.gradle.api.internal.artifacts.mvnsettings.LocalMavenRepositoryLocator
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransportFactory
import org.gradle.api.internal.file.FileResolver
import org.gradle.api.internal.filestore.ivy.ArtifactIdentifierFileStore
+import org.gradle.internal.authentication.AuthenticationSchemeRegistry
+import org.gradle.internal.authentication.DefaultAuthenticationSchemeRegistry
import org.gradle.internal.reflect.DirectInstantiator
import org.gradle.internal.resource.local.LocallyAvailableResourceFinder
import org.gradle.logging.ProgressLoggerFactory
@@ -38,10 +39,11 @@ class DefaultBaseRepositoryFactoryTest extends Specification {
final ArtifactIdentifierFileStore artifactIdentifierFileStore = Stub()
final ResolverStrategy resolverStrategy = Mock()
final MetaDataParser pomParser = Mock()
+ final AuthenticationSchemeRegistry authenticationSchemeRegistry = new DefaultAuthenticationSchemeRegistry()
final DefaultBaseRepositoryFactory factory = new DefaultBaseRepositoryFactory(
localMavenRepoLocator, fileResolver, DirectInstantiator.INSTANCE, transportFactory, locallyAvailableResourceFinder,
- resolverStrategy, artifactIdentifierFileStore, pomParser
+ resolverStrategy, artifactIdentifierFileStore, pomParser, authenticationSchemeRegistry
)
def testCreateFlatDirResolver() {
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepositoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepositoryTest.groovy
index e776710..572bf53 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepositoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultFlatDirArtifactRepositoryTest.groovy
@@ -54,7 +54,7 @@ class DefaultFlatDirArtifactRepositoryTest extends Specification {
def repo = repository.createResolver()
then:
- 1 * transportFactory.createTransport("file", "repo-name", null) >> repositoryTransport
+ 1 * transportFactory.createTransport("file", "repo-name", []) >> repositoryTransport
and:
repo instanceof IvyResolver
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepositoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepositoryTest.groovy
index f3657ea..b0fac19 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepositoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultIvyArtifactRepositoryTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.api.internal.artifacts.repositories
import org.gradle.api.InvalidUserDataException
+import org.gradle.api.artifacts.repositories.AuthenticationContainer
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.ResolverStrategy
import org.gradle.api.internal.artifacts.repositories.resolver.IvyResolver
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransport
@@ -35,10 +36,11 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
final ProgressLoggerFactory progressLoggerFactory = Mock()
final ResolverStrategy resolverStrategy = Stub()
final ArtifactIdentifierFileStore artifactIdentifierFileStore = Stub()
+ final AuthenticationContainer authenticationContainer = Stub()
final DefaultIvyArtifactRepository repository = new DefaultIvyArtifactRepository(
fileResolver, transportFactory, locallyAvailableResourceFinder,
- DirectInstantiator.INSTANCE, resolverStrategy, artifactIdentifierFileStore
+ DirectInstantiator.INSTANCE, resolverStrategy, artifactIdentifierFileStore, authenticationContainer
)
def "default values"() {
@@ -56,7 +58,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('http://host/') >> new URI('http://host/')
fileResolver.resolveUri('http://other/') >> new URI('http://other/')
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
when:
@@ -82,7 +84,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('repo/') >> fileUri
- transportFactory.createTransport({ it == ['file'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['file'] as Set}, 'name', _) >> transport()
when:
def resolver = repository.createResolver()
@@ -104,7 +106,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('http://host') >> new URI('http://host/')
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
when:
def resolver = repository.createResolver()
@@ -125,7 +127,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('http://host') >> new URI('http://host/')
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
when:
def resolver = repository.createResolver()
@@ -147,7 +149,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('http://host') >> new URI('http://host/')
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
when:
def resolver = repository.createResolver()
@@ -173,7 +175,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('http://host') >> new URI('http://host/')
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
when:
def resolver = repository.createResolver()
@@ -200,7 +202,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('http://host') >> new URI('http://host/')
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
when:
def resolver = repository.createResolver()
@@ -224,7 +226,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
given:
fileResolver.resolveUri('http://host/') >> new URI('http://host/')
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
when:
def resolver = repository.createResolver()
@@ -246,7 +248,7 @@ class DefaultIvyArtifactRepositoryTest extends Specification {
artifact '[layoutPattern]'
}
repository.artifactPattern 'http://other/[additionalPattern]'
- transportFactory.createTransport({ it == ['http'] as Set}, 'name', null) >> transport()
+ transportFactory.createTransport({ it == ['http'] as Set}, 'name', _) >> transport()
given:
fileResolver.resolveUri('http://host') >> new URI('http://host')
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepositoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepositoryTest.groovy
index e30a765..961a14a 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepositoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenArtifactRepositoryTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.api.internal.artifacts.repositories
import org.gradle.api.InvalidUserDataException
+import org.gradle.api.artifacts.repositories.AuthenticationContainer
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser
import org.gradle.api.internal.artifacts.repositories.resolver.MavenResolver
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransport
@@ -33,16 +34,17 @@ class DefaultMavenArtifactRepositoryTest extends Specification {
final ExternalResourceRepository resourceRepository = Mock()
final ArtifactIdentifierFileStore artifactIdentifierFileStore = Stub()
final MetaDataParser pomParser = Stub()
+ final AuthenticationContainer authenticationContainer = Stub()
final DefaultMavenArtifactRepository repository = new DefaultMavenArtifactRepository(
- resolver, transportFactory, locallyAvailableResourceFinder, DirectInstantiator.INSTANCE, artifactIdentifierFileStore, pomParser)
+ resolver, transportFactory, locallyAvailableResourceFinder, DirectInstantiator.INSTANCE, artifactIdentifierFileStore, pomParser, authenticationContainer)
def "creates local repository"() {
given:
def file = new File('repo')
def uri = file.toURI()
_ * resolver.resolveUri('repo-dir') >> uri
- transportFactory.createTransport('file', 'repo', null) >> transport()
+ transportFactory.createTransport('file', 'repo', _) >> transport()
and:
repository.name = 'repo'
@@ -60,7 +62,7 @@ class DefaultMavenArtifactRepositoryTest extends Specification {
given:
def uri = new URI("http://localhost:9090/repo")
_ * resolver.resolveUri('repo-dir') >> uri
- transportFactory.createTransport('http', 'repo', null) >> transport()
+ transportFactory.createTransport('http', 'repo', _) >> transport()
and:
repository.name = 'repo'
@@ -82,7 +84,7 @@ class DefaultMavenArtifactRepositoryTest extends Specification {
_ * resolver.resolveUri('repo-dir') >> uri
_ * resolver.resolveUri('repo1') >> uri1
_ * resolver.resolveUri('repo2') >> uri2
- transportFactory.createTransport('http', 'repo', null) >> transport()
+ transportFactory.createTransport('http', 'repo', _) >> transport()
and:
repository.name = 'repo'
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalRepositoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalRepositoryTest.groovy
index 101f449..2845491 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalRepositoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/DefaultMavenLocalRepositoryTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.api.internal.artifacts.repositories
+import org.gradle.api.artifacts.repositories.AuthenticationContainer
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser
import org.gradle.api.internal.artifacts.repositories.resolver.MavenLocalResolver
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransport
@@ -34,9 +35,10 @@ class DefaultMavenLocalRepositoryTest extends Specification {
final ExternalResourceRepository resourceRepository = Mock()
final ArtifactIdentifierFileStore artifactIdentifierFileStore = Stub()
final MetaDataParser pomParser = Stub()
+ final AuthenticationContainer authenticationContainer = Stub()
final DefaultMavenArtifactRepository repository = new DefaultMavenLocalArtifactRepository(
- resolver, transportFactory, locallyAvailableResourceFinder, DirectInstantiator.INSTANCE, artifactIdentifierFileStore, pomParser)
+ resolver, transportFactory, locallyAvailableResourceFinder, DirectInstantiator.INSTANCE, artifactIdentifierFileStore, pomParser, authenticationContainer)
final ProgressLoggerFactory progressLoggerFactory = Mock()
def "creates local repository"() {
@@ -44,7 +46,7 @@ class DefaultMavenLocalRepositoryTest extends Specification {
def file = new File('repo')
def uri = file.toURI()
_ * resolver.resolveUri('repo-dir') >> uri
- transportFactory.createTransport('file', 'repo', null) >> transport()
+ transportFactory.createTransport('file', 'repo', _) >> transport()
and:
repository.name = 'repo'
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolverTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolverTest.groovy
index 684e15f..728c099 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolverTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/resolver/MavenUniqueSnapshotExternalResourceArtifactResolverTest.groovy
@@ -53,16 +53,13 @@ class MavenUniqueSnapshotExternalResourceArtifactResolverTest extends Specificat
def originalArtifact = new DefaultModuleComponentArtifactMetaData(originalComponentId, originalIvyName)
def artifact = resolver.timestamp(originalArtifact)
def result = Mock(ResourceAwareResolveResult)
- def resource1 = Mock(LocallyAvailableExternalResource)
def resource2 = Mock(LocallyAvailableExternalResource)
when:
- 1 * delegate.resolveMetaDataArtifact({ it.id == artifact.id }, result) >> resource1
1 * delegate.resolveArtifact({ it.id == artifact.id }, result) >> resource2
1 * delegate.artifactExists({ it.id == artifact.id }, result) >> true
then:
- resolver.resolveMetaDataArtifact(originalArtifact, result) == resource1
resolver.resolveArtifact(originalArtifact, result) == resource2
resolver.artifactExists(originalArtifact, result)
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactoryTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactoryTest.groovy
index ffafd6f..43675dc 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactoryTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/repositories/transport/RepositoryTransportFactoryTest.groovy
@@ -15,14 +15,16 @@
*/
package org.gradle.api.internal.artifacts.repositories.transport
+
import com.google.common.collect.Lists
import org.gradle.api.InvalidUserDataException
-import org.gradle.api.artifacts.repositories.PasswordCredentials
-import org.gradle.api.internal.artifacts.repositories.DefaultPasswordCredentials
-import org.gradle.internal.credentials.DefaultAwsCredentials
+import org.gradle.api.credentials.Credentials
+import org.gradle.authentication.Authentication
+import org.gradle.internal.authentication.AbstractAuthentication
import org.gradle.internal.resource.connector.ResourceConnectorFactory
import org.gradle.internal.resource.transport.ResourceConnectorRepositoryTransport
import spock.lang.Specification
+import spock.lang.Unroll
class RepositoryTransportFactoryTest extends Specification {
@@ -32,23 +34,25 @@ class RepositoryTransportFactoryTest extends Specification {
def setup() {
connectorFactory1.getSupportedProtocols() >> (["protocol1"] as Set)
+ connectorFactory1.getSupportedAuthentication() >> ([GoodCredentialsAuthentication, BadCredentialsAuthentication] as Set)
connectorFactory2.getSupportedProtocols() >> (["protocol2a", "protocol2b"] as Set)
+ connectorFactory2.getSupportedAuthentication() >> ([] as Set)
List<ResourceConnectorFactory> resourceConnectorFactories = Lists.newArrayList(connectorFactory1, connectorFactory2)
repositoryTransportFactory = new RepositoryTransportFactory(resourceConnectorFactories, null, null, null, null, null)
}
def "cannot create a transport for url with unsupported scheme"() {
when:
- repositoryTransportFactory.createTransport(['unsupported'] as Set, null, null)
+ repositoryTransportFactory.createTransport(['unsupported'] as Set, null, [])
then:
InvalidUserDataException e = thrown()
- e.message == "Not a supported repository protocol 'unsupported': valid protocols are [file, protocol1, protocol2a, protocol2b]"
+ e.message == "Not a supported repository protocol 'unsupported': valid protocols are [protocol1, protocol2a, protocol2b]"
}
def "cannot creates a transport for mixed url scheme"() {
when:
- repositoryTransportFactory.createTransport(['protocol1', 'protocol2b'] as Set, null, null)
+ repositoryTransportFactory.createTransport(['protocol1', 'protocol2b'] as Set, null, [])
then:
InvalidUserDataException e = thrown()
@@ -56,21 +60,101 @@ class RepositoryTransportFactoryTest extends Specification {
}
def "should create a transport for known scheme"() {
- def credentials = Mock(DefaultPasswordCredentials)
+ def authentication = new GoodCredentialsAuthentication('good')
+ authentication.credentials = Mock(GoodCredentials)
when:
- def transport = repositoryTransportFactory.createTransport(['protocol1'] as Set, null, credentials)
+ def transport = repositoryTransportFactory.createTransport(['protocol1'] as Set, null, [authentication])
then:
transport.class == ResourceConnectorRepositoryTransport
}
- def "should throw when credentials types is invalid"(){
+ def "should create transport for known scheme, authentication and credentials"() {
+ def authentication = new GoodCredentialsAuthentication('good')
+ authentication.credentials = Mock(GoodCredentials)
+
+ when:
+ def transport = repositoryTransportFactory.createTransport(['protocol1'] as Set, null, [authentication])
+
+ then:
+ transport.class == ResourceConnectorRepositoryTransport
+ }
+
+ def "should throw when using invalid authentication type"() {
+ def credentials = Mock(GoodCredentials)
+ authentication.credentials = credentials
+
+ when:
+ repositoryTransportFactory.createTransport(protocols as Set, null, [authentication])
+
+ then:
+ def ex = thrown(InvalidUserDataException)
+ ex.message == "Authentication scheme ${authentication} is not supported by protocol '${protocols[0]}'"
+
+ where:
+ authentication | protocols
+ new NoCredentialsAuthentication('none') | ['protocol1']
+ new GoodCredentialsAuthentication('good') | ['protocol2a', 'protocol2b']
+ }
+
+ @Unroll
+ def "should throw when using invalid credentials type"() {
+ authentication*.credentials = credentials
+
+ when:
+ repositoryTransportFactory.createTransport(['protocol1'] as Set, null, authentication)
+
+ then:
+ def ex = thrown(InvalidUserDataException)
+ ex.message == "Credentials type of '${credentials.class.simpleName}' is not supported by authentication scheme ${failingAuthentication}"
+
+ where:
+ credentials | authentication | failingAuthentication
+ Mock(BadCredentials) | [new GoodCredentialsAuthentication('good')] | "'good'(Authentication)"
+ Mock(GoodCredentials) | [new GoodCredentialsAuthentication('good'), new BadCredentialsAuthentication('bad')] | "'bad'(Authentication)"
+ }
+
+ def "should throw when specifying authentication types with null credentials"() {
+ when:
+ repositoryTransportFactory.createTransport(['protocol1'] as Set, null, [new GoodCredentialsAuthentication('good')])
+
+ then:
+ def ex = thrown(InvalidUserDataException)
+ ex.message == "You cannot configure authentication schemes for a repository if no credentials are provided."
+ }
+
+ def "should throw when specifying multiple authentication schemes of the same type"() {
+ def authentication = new GoodCredentialsAuthentication('good')
+ authentication.credentials = Mock(GoodCredentials)
+
when:
- repositoryTransportFactory.convertPasswordCredentials(new DefaultAwsCredentials())
+ repositoryTransportFactory.createTransport(['protocol1'] as Set, null, [authentication, authentication])
then:
- def ex = thrown(IllegalArgumentException)
- ex.message == "Credentials must be an instance of: ${PasswordCredentials.class.getCanonicalName()}"
+ def ex = thrown(InvalidUserDataException)
+ ex.message == "You cannot configure multiple authentication schemes of the same type. The duplicate one is 'good'(Authentication)."
+ }
+
+ private class GoodCredentialsAuthentication extends AbstractAuthentication {
+ GoodCredentialsAuthentication(String name) {
+ super(name, Authentication, GoodCredentials)
+ }
+ }
+
+ private class BadCredentialsAuthentication extends AbstractAuthentication {
+ BadCredentialsAuthentication(String name) {
+ super(name, Authentication, BadCredentials)
+ }
}
+
+ private class NoCredentialsAuthentication extends AbstractAuthentication {
+ NoCredentialsAuthentication(String name) {
+ super(name, Authentication)
+ }
+ }
+
+ private interface GoodCredentials extends Credentials {}
+
+ private interface BadCredentials extends Credentials {}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaDataTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaDataTest.groovy
index f0d92f7..2062e3a 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaDataTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/external/model/DefaultIvyModulePublishMetaDataTest.groovy
@@ -41,10 +41,8 @@ class DefaultIvyModulePublishMetaDataTest extends Specification {
}
def "can add configuration"() {
- def configuration = mockConfiguration()
-
when:
- metaData.addConfiguration(configuration)
+ metaData.addConfiguration("configName", "configDescription", ["one", "two", "three"] as Set, ["one", "two", "three", "configName"] as Set, true, true, null)
then:
metaData.moduleDescriptor.configurations.length == 1
@@ -70,7 +68,7 @@ class DefaultIvyModulePublishMetaDataTest extends Specification {
def dependency = Mock(DependencyMetaData)
given:
- metaData.addConfiguration(mockConfiguration())
+ metaData.addConfiguration("configName", "configDescription", ["one", "two", "three"] as Set, ["one", "two", "three", "configName"] as Set, true, true, null)
and:
dependency.requested >> DefaultModuleVersionSelector.newSelector("group", "module", "version")
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryBinaryIdentifierTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryBinaryIdentifierTest.groovy
new file mode 100644
index 0000000..c890f52
--- /dev/null
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryBinaryIdentifierTest.groovy
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.internal.component.local.model
+
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier
+import spock.lang.Specification
+import spock.lang.Unroll
+
+import static org.gradle.util.Matchers.strictlyEquals
+
+class DefaultLibraryBinaryIdentifierTest extends Specification {
+ def "is instantiated with non-null constructor parameter values"() {
+ when:
+ LibraryBinaryIdentifier defaultBuildComponentIdentifier = new DefaultLibraryBinaryIdentifier(':myPath', 'myLib', 'api')
+
+ then:
+ defaultBuildComponentIdentifier.projectPath == ':myPath'
+ defaultBuildComponentIdentifier.libraryName == 'myLib'
+ defaultBuildComponentIdentifier.variant == 'api'
+ defaultBuildComponentIdentifier.displayName == /project ':myPath' library 'myLib' variant 'api'/
+ defaultBuildComponentIdentifier.toString() == /project ':myPath' library 'myLib' variant 'api'/
+ }
+
+ def "is instantiated with null project constructor parameter value"() {
+ when:
+ new DefaultLibraryBinaryIdentifier(null, 'foo', 'api')
+
+ then:
+ Throwable t = thrown(AssertionError)
+ t.message == 'project path cannot be null'
+ }
+
+ def "is instantiated with null library constructor parameter value"() {
+ when:
+ new DefaultLibraryBinaryIdentifier('foo', null, 'api')
+
+ then:
+ Throwable t = thrown(AssertionError)
+ t.message == 'library name cannot be null'
+ }
+
+ def "is instantiated with null variant constructor parameter value"() {
+ when:
+ new DefaultLibraryBinaryIdentifier('foo', 'bar', null)
+
+ then:
+ Throwable t = thrown(AssertionError)
+ t.message == 'variant cannot be null'
+ }
+
+ @Unroll
+ def "can compare with other instance (#projectPath,#libraryName,#variant)"() {
+ expect:
+ LibraryBinaryIdentifier defaultBuildComponentIdentifier1 = new DefaultLibraryBinaryIdentifier(':myProjectPath1', 'myLib', 'api')
+ LibraryBinaryIdentifier defaultBuildComponentIdentifier2 = new DefaultLibraryBinaryIdentifier(projectPath, libraryName, variant)
+ strictlyEquals(defaultBuildComponentIdentifier1, defaultBuildComponentIdentifier2) == equality
+ (defaultBuildComponentIdentifier1.hashCode() == defaultBuildComponentIdentifier2.hashCode()) == hashCode
+ (defaultBuildComponentIdentifier1.toString() == defaultBuildComponentIdentifier2.toString()) == stringRepresentation
+
+ where:
+ projectPath | libraryName | variant | equality | hashCode | stringRepresentation
+ ':myProjectPath1' | 'myLib' | 'api' | true | true | true
+ ':myProjectPath2' | 'myLib' | 'api' | false | false | false
+ ':myProjectPath1' | 'myLib2' | 'api' | false | false | false
+ ':myProjectPath1' | 'myLib' | 'impl' | false | false | false
+ }
+}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryComponentIdentifierTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryComponentIdentifierTest.groovy
deleted file mode 100644
index c90b34e..0000000
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryComponentIdentifierTest.groovy
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.internal.component.local.model
-
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier
-import spock.lang.Specification
-import spock.lang.Unroll
-
-import static org.gradle.util.Matchers.strictlyEquals
-
-class DefaultLibraryComponentIdentifierTest extends Specification {
- def "is instantiated with non-null constructor parameter values"() {
- when:
- LibraryComponentIdentifier defaultBuildComponentIdentifier = new DefaultLibraryComponentIdentifier(':myPath', 'myLib')
-
- then:
- defaultBuildComponentIdentifier.projectPath == ':myPath'
- defaultBuildComponentIdentifier.libraryName == 'myLib'
- defaultBuildComponentIdentifier.displayName == 'project :myPath library myLib'
- defaultBuildComponentIdentifier.toString() == 'project :myPath library myLib'
- }
-
- def "is instantiated with null project constructor parameter value"() {
- when:
- new DefaultLibraryComponentIdentifier(null, 'foo')
-
- then:
- Throwable t = thrown(AssertionError)
- t.message == 'project path cannot be null'
- }
-
- def "is instantiated with null library constructor parameter value"() {
- when:
- new DefaultLibraryComponentIdentifier('foo', null)
-
- then:
- Throwable t = thrown(AssertionError)
- t.message == 'library name cannot be null'
- }
-
- @Unroll
- def "can compare with other instance (#projectPath,#libraryName)"() {
- expect:
- LibraryComponentIdentifier defaultBuildComponentIdentifier1 = new DefaultLibraryComponentIdentifier(':myProjectPath1', 'myLib')
- LibraryComponentIdentifier defaultBuildComponentIdentifier2 = new DefaultLibraryComponentIdentifier(projectPath, libraryName)
- strictlyEquals(defaultBuildComponentIdentifier1, defaultBuildComponentIdentifier2) == equality
- (defaultBuildComponentIdentifier1.hashCode() == defaultBuildComponentIdentifier2.hashCode()) == hashCode
- (defaultBuildComponentIdentifier1.toString() == defaultBuildComponentIdentifier2.toString()) == stringRepresentation
-
- where:
- projectPath | libraryName | equality | hashCode | stringRepresentation
- ':myProjectPath1' | 'myLib' | true | true | true
- ':myProjectPath2' | 'myLib' | false | false | false
- ':myProjectPath1' | 'myLib2' | false | false | false
- }
-}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryComponentSelectorTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryComponentSelectorTest.groovy
index a9a0971..a6f52c7 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryComponentSelectorTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLibraryComponentSelectorTest.groovy
@@ -15,7 +15,7 @@
*/
package org.gradle.internal.component.local.model
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier
import org.gradle.api.artifacts.component.LibraryComponentSelector
import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
import spock.lang.Specification
@@ -31,42 +31,70 @@ class DefaultLibraryComponentSelectorTest extends Specification {
then:
defaultBuildComponentSelector.projectPath == ':myPath'
defaultBuildComponentSelector.libraryName == 'myLib'
- defaultBuildComponentSelector.displayName == 'project :myPath library myLib'
- defaultBuildComponentSelector.toString() == 'project :myPath library myLib'
+ defaultBuildComponentSelector.displayName == /project ':myPath' library 'myLib'/
+ defaultBuildComponentSelector.toString() == /project ':myPath' library 'myLib'/
}
- def "is instantiated with null project constructor parameter value"() {
+ def "can be instantiated with null constructor library name value"() {
when:
- new DefaultLibraryComponentSelector(null, 'foo')
+ LibraryComponentSelector defaultBuildComponentSelector = new DefaultLibraryComponentSelector(':myPath', null)
+
+ then:
+ defaultBuildComponentSelector.projectPath == ':myPath'
+ defaultBuildComponentSelector.libraryName == null
+ defaultBuildComponentSelector.displayName == /project ':myPath'/
+ defaultBuildComponentSelector.toString() == /project ':myPath'/
+ }
+
+ def "can be instantiated with null constructor variant value"() {
+ when:
+ LibraryComponentSelector defaultBuildComponentSelector = new DefaultLibraryComponentSelector(':myPath', 'myLib')
+
+ then:
+ defaultBuildComponentSelector.projectPath == ':myPath'
+ defaultBuildComponentSelector.libraryName == 'myLib'
+ defaultBuildComponentSelector.displayName == /project ':myPath' library 'myLib'/
+ defaultBuildComponentSelector.toString() == /project ':myPath' library 'myLib'/
+ }
+
+ def "cannot be instantiated with null project constructor parameter value"() {
+ when:
+ new DefaultLibraryComponentSelector(null, 'myLib')
then:
Throwable t = thrown(AssertionError)
- t.message == 'project path cannot be null'
+ t.message == 'project path cannot be null or empty'
}
- def "is instantiated with null library constructor parameter value"() {
+ def "cannot be instantiated with empty project constructor parameter value"() {
when:
- new DefaultLibraryComponentSelector(':foo', null)
+ new DefaultLibraryComponentSelector('', 'myLib')
then:
Throwable t = thrown(AssertionError)
- t.message == 'library name cannot be null'
+ t.message == 'project path cannot be null or empty'
}
@Unroll
- def "can compare with other instance (#projectPath,#libraryName)"() {
+ def "can compare (#projectPath1,#libraryName1,#variant1) with other instance (#projectPath2,#libraryName2, #variant2)"() {
expect:
- LibraryComponentSelector defaultBuildComponentSelector1 = new DefaultLibraryComponentSelector(':myProjectPath1', 'myLib1')
- LibraryComponentSelector defaultBuildComponentSelector2 = new DefaultLibraryComponentSelector(projectPath, libraryName)
+ LibraryComponentSelector defaultBuildComponentSelector1 = new DefaultLibraryComponentSelector(projectPath1, libraryName1)
+ LibraryComponentSelector defaultBuildComponentSelector2 = new DefaultLibraryComponentSelector(projectPath2, libraryName2)
strictlyEquals(defaultBuildComponentSelector1, defaultBuildComponentSelector2) == equality
(defaultBuildComponentSelector1.hashCode() == defaultBuildComponentSelector2.hashCode()) == hashCode
(defaultBuildComponentSelector1.toString() == defaultBuildComponentSelector2.toString()) == stringRepresentation
where:
- projectPath | libraryName | equality | hashCode | stringRepresentation
- ':myProjectPath1' | 'myLib1' | true | true | true
- ':myProjectPath1' | 'myLib2' | false | false | false
- ':myProjectPath2' | 'myLib1' | false | false | false
+ projectPath1 | libraryName1 | projectPath2 | libraryName2 | equality | hashCode | stringRepresentation
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath1' | 'myLib1' | true | true | true
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath1' | 'myLib2' | false | false | false
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath2' | 'myLib1' | false | false | false
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath2' | null | false | false | false
+ ':myProjectPath1' | null | ':myProjectPath1' | 'myLib1' | false | false | false
+ ':myProjectPath1' | null | ':myProjectPath1' | 'myLib2' | false | false | false
+ ':myProjectPath1' | null | ':myProjectPath2' | 'myLib1' | false | false | false
+ ':myProjectPath1' | null | ':myProjectPath2' | null | false | false | false
+ ':myProjectPath1' | null | ':myProjectPath1' | null | true | true | true
}
def "prevents matching of null id"() {
@@ -91,14 +119,21 @@ class DefaultLibraryComponentSelectorTest extends Specification {
@Unroll
def "matches id (#projectPath,#libraryName)"() {
expect:
- LibraryComponentSelector defaultBuildComponentSelector = new DefaultLibraryComponentSelector(':myProjectPath1', 'myLib')
- LibraryComponentIdentifier defaultBuildComponentIdentifier = new DefaultLibraryComponentIdentifier(projectPath, libraryName)
+ LibraryComponentSelector defaultBuildComponentSelector = new DefaultLibraryComponentSelector(projectPath1, libraryName1)
+ LibraryBinaryIdentifier defaultBuildComponentIdentifier = new DefaultLibraryBinaryIdentifier(projectPath2, libraryName2, variant)
defaultBuildComponentSelector.matchesStrictly(defaultBuildComponentIdentifier) == matchesId
where:
- projectPath | libraryName | matchesId
- ':myProjectPath1' | 'myLib' | true
- ':myProjectPath2' | 'myLib' | false
- ':myProjectPath1' | 'myLib2' | false
+ projectPath1 | libraryName1 | projectPath2 | libraryName2 | variant | matchesId
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath1' | 'myLib1' | 'api' | true
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath2' | 'myLib1' | 'impl' | false
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath2' | 'myLib1' | 'api' | false
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath1' | 'myLib2' | 'api' | false
+ ':myProjectPath1' | null | ':myProjectPath1' | 'foo' | 'api' | false
+ ':myProjectPath1' | null | ':myProjectPath2' | 'foo' | 'api' | false
+ ':myProjectPath1' | null | ':myProjectPath1' | 'foo' | 'api' | false
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath2' | 'myLib1' | 'api' | false
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath2' | 'myLib1' | 'api' | false
+ ':myProjectPath1' | 'myLib1' | ':myProjectPath1' | 'myLib2' | 'api' | false
}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLocalComponentMetaDataTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLocalComponentMetaDataTest.groovy
index 81f2d75..30366ff 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLocalComponentMetaDataTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/local/model/DefaultLocalComponentMetaDataTest.groovy
@@ -15,11 +15,12 @@
*/
package org.gradle.internal.component.local.model
-import org.apache.ivy.core.module.descriptor.Configuration
+
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier
import org.gradle.api.internal.artifacts.DefaultPublishArtifactSet
import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact
+import org.gradle.api.internal.tasks.DefaultTaskDependency
import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier
import org.gradle.internal.component.model.DefaultIvyArtifactName
import org.gradle.internal.component.model.DependencyMetaData
@@ -31,35 +32,25 @@ class DefaultLocalComponentMetaDataTest extends Specification {
def id = DefaultModuleVersionIdentifier.newId("group", "module", "version")
def componentIdentifier = DefaultModuleComponentIdentifier.newId(id)
def metaData = new DefaultLocalComponentMetaData(id, componentIdentifier, "status")
+ def taskDep = new DefaultTaskDependency()
def "can lookup configuration after it has been added"() {
when:
- metaData.addConfiguration("super", "description", [] as Set, ["super"] as Set, false, false)
- metaData.addConfiguration("conf", "description", ["super"] as Set, ["super", "conf"] as Set, true, true)
+ metaData.addConfiguration("super", "description", [] as Set, ["super"] as Set, false, false, taskDep)
+ metaData.addConfiguration("conf", "description", ["super"] as Set, ["super", "conf"] as Set, true, true, taskDep)
then:
- def resolveMetaData = metaData.toResolveMetaData()
- resolveMetaData.configurationNames == ['conf', 'super'] as Set
+ metaData.configurationNames == ['conf', 'super'] as Set
- def conf = resolveMetaData.getConfiguration('conf')
+ def conf = metaData.getConfiguration('conf')
conf != null
conf.visible
conf.transitive
- def superConf = resolveMetaData.getConfiguration('super')
+ def superConf = metaData.getConfiguration('super')
superConf != null
!superConf.visible
!superConf.transitive
-
- and:
- def publishMetaData = metaData.toPublishMetaData()
- publishMetaData.getModuleDescriptor().configurations.length == 2
- publishMetaData.getModuleDescriptor().getConfiguration('conf') != null
-
- def ivyConf = publishMetaData.getModuleDescriptor().getConfiguration('conf')
- ivyConf != null
- ivyConf.transitive
- ivyConf.visibility == Configuration.Visibility.PUBLIC
}
def "can lookup artifact in various ways after it has been added"() {
@@ -73,31 +64,19 @@ class DefaultLocalComponentMetaDataTest extends Specification {
addArtifact("conf", artifact, file)
then:
- def resolveMetaData = metaData.toResolveMetaData()
- resolveMetaData.getConfiguration("conf").artifacts.size() == 1
+ metaData.getConfiguration("conf").artifacts.size() == 1
- def publishArtifact = resolveMetaData.getConfiguration("conf").artifacts.first()
+ def publishArtifact = metaData.getConfiguration("conf").artifacts.first()
publishArtifact.id
publishArtifact.name.name == artifact.name
publishArtifact.name.type == artifact.type
publishArtifact.name.extension == artifact.extension
publishArtifact.file == file
- publishArtifact == resolveMetaData.getConfiguration("conf").artifact(artifact)
-
- and:
- def publishMetaData = metaData.toPublishMetaData()
- publishMetaData.artifacts.size() == 1
-
- def publishMetaDataArtifact = (publishMetaData.artifacts as List).first()
- publishMetaDataArtifact.id
- publishMetaDataArtifact.id.componentIdentifier == componentIdentifier
- publishMetaDataArtifact.artifactName.name == artifact.name
- publishMetaDataArtifact.artifactName.type == artifact.type
- publishMetaDataArtifact.artifactName.extension == artifact.extension
+ publishArtifact == metaData.getConfiguration("conf").artifact(artifact)
}
private addConfiguration(String name) {
- metaData.addConfiguration(name, "", [] as Set, [name] as Set, true, true)
+ metaData.addConfiguration(name, "", [] as Set, [name] as Set, true, true, taskDep)
}
def addArtifact(String configuration, IvyArtifactName name, File file) {
@@ -123,9 +102,8 @@ class DefaultLocalComponentMetaDataTest extends Specification {
addArtifact("conf2", publishArtifact)
then:
- def resolveMetaData = metaData.toResolveMetaData()
- resolveMetaData.getConfiguration("conf1").artifacts.size() == 1
- resolveMetaData.getConfiguration("conf1").artifacts == resolveMetaData.getConfiguration("conf2").artifacts
+ metaData.getConfiguration("conf1").artifacts.size() == 1
+ metaData.getConfiguration("conf1").artifacts == metaData.getConfiguration("conf2").artifacts
}
def "can lookup an artifact given an Ivy artifact"() {
@@ -142,7 +120,7 @@ class DefaultLocalComponentMetaDataTest extends Specification {
def ivyArtifact = artifactName()
expect:
- def resolveArtifact = metaData.toResolveMetaData().getConfiguration("conf").artifact(ivyArtifact)
+ def resolveArtifact = metaData.getConfiguration("conf").artifact(ivyArtifact)
resolveArtifact.file == file
}
@@ -152,7 +130,7 @@ class DefaultLocalComponentMetaDataTest extends Specification {
addConfiguration("conf")
expect:
- def resolveArtifact = metaData.toResolveMetaData().getConfiguration("conf").artifact(artifact)
+ def resolveArtifact = metaData.getConfiguration("conf").artifact(artifact)
resolveArtifact != null
resolveArtifact.file == null
}
@@ -163,21 +141,18 @@ class DefaultLocalComponentMetaDataTest extends Specification {
def file1 = new File("artifact-1.zip")
def file2 = new File("artifact-2.zip")
- given:
+ when:
addConfiguration("conf1")
addConfiguration("conf2")
addArtifact("conf1", artifact1, file1)
addArtifact("conf2", artifact2, file2)
- when:
- def resolveMetaData = metaData.toResolveMetaData()
-
then:
- def conf1Artifacts = resolveMetaData.getConfiguration("conf1").artifacts as List
+ def conf1Artifacts = metaData.getConfiguration("conf1").artifacts as List
conf1Artifacts.size() == 1
def artifactMetadata1 = conf1Artifacts[0]
- def conf2Artifacts = resolveMetaData.getConfiguration("conf2").artifacts as List
+ def conf2Artifacts = metaData.getConfiguration("conf2").artifacts as List
conf2Artifacts.size() == 1
def artifactMetadata2 = conf2Artifacts[0]
@@ -185,8 +160,8 @@ class DefaultLocalComponentMetaDataTest extends Specification {
artifactMetadata1.id != artifactMetadata2.id
and:
- resolveMetaData.getConfiguration("conf1").artifacts == [artifactMetadata1] as Set
- resolveMetaData.getConfiguration("conf2").artifacts == [artifactMetadata2] as Set
+ metaData.getConfiguration("conf1").artifacts == [artifactMetadata1] as Set
+ metaData.getConfiguration("conf2").artifacts == [artifactMetadata2] as Set
}
def "can add dependencies"() {
@@ -196,12 +171,7 @@ class DefaultLocalComponentMetaDataTest extends Specification {
metaData.addDependency(dependency)
then:
- metaData.toResolveMetaData().dependencies == [dependency]
-
- // TODO:DAZ Test conversion of dependency meta data for publishing
-// and:
-// def ivyDependencies = metaData.toPublishMetaData().getModuleDescriptor().dependencies
-// ivyDependencies.length == 1
+ metaData.dependencies == [dependency]
}
def artifactName() {
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/model/DefaultIvyArtifactNameTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/model/DefaultIvyArtifactNameTest.groovy
index 54324eb..ec3ef58 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/model/DefaultIvyArtifactNameTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/component/model/DefaultIvyArtifactNameTest.groovy
@@ -75,7 +75,7 @@ class DefaultIvyArtifactNameTest extends Specification {
1 * publishArtifact.getName() >> "art-name"
then:
- def name = DefaultIvyArtifactName.forPublishArtifact(publishArtifact, "default-name")
+ def name = DefaultIvyArtifactName.forPublishArtifact(publishArtifact)
name.name == "art-name"
name.extension == "art-ext"
name.type == "art-type"
@@ -84,9 +84,10 @@ class DefaultIvyArtifactNameTest extends Specification {
when:
1 * publishArtifact.getName() >> null
+ 1 * publishArtifact.getFile() >> new File("file-name")
then:
- def nameWithDefault = DefaultIvyArtifactName.forPublishArtifact(publishArtifact, "default-name")
- nameWithDefault.name == "default-name"
+ def missingName = DefaultIvyArtifactName.forPublishArtifact(publishArtifact)
+ missingName.name == "file-name"
}
}
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/ArtifactNotFoundExceptionTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/ArtifactNotFoundExceptionTest.groovy
index 43e1cce..477f3f9 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/ArtifactNotFoundExceptionTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/ArtifactNotFoundExceptionTest.groovy
@@ -16,7 +16,7 @@
package org.gradle.internal.resolve
-import org.gradle.internal.component.model.ComponentArtifactIdentifier
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier
import org.gradle.util.TextUtil
import spock.lang.Specification
diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResultTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResultTest.groovy
index 1e56de1..efcf158 100644
--- a/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResultTest.groovy
+++ b/subprojects/dependency-management/src/test/groovy/org/gradle/internal/resolve/result/DefaultBuildableArtifactResolveResultTest.groovy
@@ -15,9 +15,10 @@
*/
package org.gradle.internal.resolve.result
+
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier
import org.gradle.internal.resolve.ArtifactNotFoundException
import org.gradle.internal.resolve.ArtifactResolveException
-import org.gradle.internal.component.model.ComponentArtifactIdentifier
import spock.lang.Specification
class DefaultBuildableArtifactResolveResultTest extends Specification {
diff --git a/subprojects/dependency-management/src/testFixtures/groovy/org/gradle/integtests/resolve/ivy/AbstractIvyRemoteRepoResolveIntegrationTest.groovy b/subprojects/dependency-management/src/testFixtures/groovy/org/gradle/integtests/resolve/ivy/AbstractIvyRemoteRepoResolveIntegrationTest.groovy
index 22feca3..a577ba1 100644
--- a/subprojects/dependency-management/src/testFixtures/groovy/org/gradle/integtests/resolve/ivy/AbstractIvyRemoteRepoResolveIntegrationTest.groovy
+++ b/subprojects/dependency-management/src/testFixtures/groovy/org/gradle/integtests/resolve/ivy/AbstractIvyRemoteRepoResolveIntegrationTest.groovy
@@ -18,11 +18,13 @@ package org.gradle.integtests.resolve.ivy
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.executer.ProgressLoggingFixture
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.server.RepositoryServer
import org.junit.Rule
import spock.lang.Unroll
@Unroll
+ at LeaksFileHandles
abstract class AbstractIvyRemoteRepoResolveIntegrationTest extends AbstractIntegrationSpec {
abstract RepositoryServer getServer()
diff --git a/subprojects/diagnostics/src/integTest/groovy/org/gradle/api/reporting/model/DetailedModelReportIntegrationTest.groovy b/subprojects/diagnostics/src/integTest/groovy/org/gradle/api/reporting/model/DetailedModelReportIntegrationTest.groovy
new file mode 100644
index 0000000..6161c41
--- /dev/null
+++ b/subprojects/diagnostics/src/integTest/groovy/org/gradle/api/reporting/model/DetailedModelReportIntegrationTest.groovy
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.EnableModelDsl
+import org.gradle.test.fixtures.server.http.HttpServer
+import org.junit.Rule
+
+import static org.gradle.util.TextUtil.normaliseFileSeparators
+
+/**
+ * Tests for more detailed output i.e. with the `org.gradle.model.dsl` flag enabled.
+ */
+class DetailedModelReportIntegrationTest extends AbstractIntegrationSpec {
+
+ @Rule
+ public final HttpServer server = new HttpServer()
+
+ void setup() {
+ EnableModelDsl.enable(executer)
+ }
+
+ def "includes a relative path to the build script"() {
+ given:
+ buildFile << """
+${managedNumbers()}
+
+model {
+ numbers(Numbers){
+ value = 5
+ }
+}
+"""
+ buildFile
+ when:
+ run "model"
+
+ then:
+ def modelNode = ModelReportOutput.from(output).modelNode
+ normaliseFileSeparators(modelNode.numbers. at creator[0]) == "model.numbers @ build.gradle line 9, column 5"
+ }
+
+ def "can find the relative path to a custom named build script"() {
+ given:
+ def renamed = testDirectory.file("why.gradle")
+ settingsFile << """
+ rootProject.buildFileName = "why.gradle"
+ """
+ renamed << """
+${managedNumbers()}
+
+model {
+ numbers(Numbers){
+ value = 5
+ }
+}
+
+"""
+ when:
+ run "model"
+
+ then:
+ def modelNode = ModelReportOutput.from(output).modelNode
+ normaliseFileSeparators(modelNode.numbers. at creator[0]) == "model.numbers @ why.gradle line 9, column 5"
+ }
+
+ def "can find the relative path when model configuration is applied from a local script inside the root dir"() {
+ given:
+ def modelFile = testDirectory.file(inputFile)
+ modelFile << """
+ ${managedNumbers()}
+
+ model {
+ numbers(Numbers){
+ value = 5
+ }
+ }
+"""
+
+ buildFile << "apply from: '${inputFile}'"
+ when:
+ run "model"
+
+ then:
+ def modelNode = ModelReportOutput.from(output).modelNode
+ normaliseFileSeparators(modelNode.numbers. at creator[0]) == "model.numbers @ ${inputFile} line 9, column 13"
+
+ where:
+ inputFile << ["my-model.gradle", "level1/level2/my-model.gradle"]
+ }
+
+ def "can find the relative path when model configuration is applied from a local script outside the root dir"() {
+ given:
+ def modelFile = testDirectory.getParentFile().file("my-model.gradle")
+
+ modelFile.text = """
+ ${managedNumbers()}
+
+ model {
+ numbers(Numbers){
+ value = 5
+ }
+ }
+"""
+
+ buildFile << "apply from: '${normaliseFileSeparators(modelFile.getAbsolutePath())}'"
+ when:
+ run "model"
+
+ then:
+ def modelNode = ModelReportOutput.from(output).modelNode
+ normaliseFileSeparators(modelNode.numbers. at creator[0]) == "model.numbers @ ../my-model.gradle line 9, column 13"
+ }
+
+ def "can find the relative path when model configuration is applied from a remote http url"() {
+ given:
+ server.start()
+ server.logRequests = false
+
+ def modelFile = testDirectory.file("local-my-model.gradle")
+ modelFile.text = """
+ ${managedNumbers()}
+
+ model {
+ numbers(Numbers){
+ value = 5
+ }
+ }
+"""
+
+ server.allowGetOrHead("/stub/my-model.gradle", modelFile)
+ buildFile << "apply from: '${server.getAddress()}/stub/my-model.gradle'"
+ when:
+ run "model"
+
+ then:
+ def modelNode = ModelReportOutput.from(output).modelNode
+ normaliseFileSeparators(modelNode.numbers. at creator[0]) == "model.numbers @ ${server.getAddress()}/stub/my-model.gradle line 9, column 13"
+ }
+
+ def "can find the relative path to model rules defined in different scripts"() {
+ given:
+ def model1File = testDirectory.file("model1.gradle")
+ def model2File = testDirectory.file("sub-dir", "model2.gradle")
+
+ model1File << """
+ ${managedNumbers()}
+ model {
+ numbers(Numbers){
+ value = 5
+ }
+ }
+"""
+
+ model2File << """
+ ${managedNumbers()}
+ model {
+ otherNumbers(Numbers){
+ value = 5
+ }
+ }
+"""
+
+ buildFile << """
+apply from: '${normaliseFileSeparators(model1File.absolutePath)}'
+apply from: '${normaliseFileSeparators(model2File.absolutePath)}'
+"""
+ when:
+ run "model"
+
+ then:
+ def modelNode = ModelReportOutput.from(output).modelNode
+ normaliseFileSeparators(modelNode.numbers. at creator[0]) == "model.numbers @ model1.gradle line 8, column 13"
+ normaliseFileSeparators(modelNode.otherNumbers. at creator[0]) == "model.otherNumbers @ sub-dir/model2.gradle line 8, column 13"
+ }
+
+ private String managedNumbers() {
+ return """@Managed
+ public interface Numbers {
+ Integer getValue()
+ void setValue(Integer i)
+ }"""
+ }
+}
+
+
diff --git a/subprojects/diagnostics/src/integTest/groovy/org/gradle/api/reporting/model/ModelReportIntegrationTest.groovy b/subprojects/diagnostics/src/integTest/groovy/org/gradle/api/reporting/model/ModelReportIntegrationTest.groovy
index fbd7cef..c9b61b2 100644
--- a/subprojects/diagnostics/src/integTest/groovy/org/gradle/api/reporting/model/ModelReportIntegrationTest.groovy
+++ b/subprojects/diagnostics/src/integTest/groovy/org/gradle/api/reporting/model/ModelReportIntegrationTest.groovy
@@ -15,11 +15,8 @@
*/
package org.gradle.api.reporting.model
-
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import static org.gradle.util.TextUtil.toPlatformLineSeparators
-
class ModelReportIntegrationTest extends AbstractIntegrationSpec {
def "displays basic structure of an empty project"() {
@@ -30,111 +27,93 @@ class ModelReportIntegrationTest extends AbstractIntegrationSpec {
run "model"
then:
- output.contains(toPlatformLineSeparators(
- """model
- tasks
- components = task ':components'
- dependencies = task ':dependencies'
- dependencyInsight = task ':dependencyInsight'
- help = task ':help'
- init = task ':init'
- model = task ':model'
- projects = task ':projects'
- properties = task ':properties'
- tasks = task ':tasks'
-"""))
+ def modelReportOutput = ModelReportOutput.from(output)
+ modelReportOutput.hasNodeStructure({
+ model() {
+ tasks {
+ components(nodeValue: "task ':components'", type: 'org.gradle.api.reporting.components.ComponentReport')
+ dependencies()
+ dependencyInsight()
+ help()
+ init()
+ model()
+ projects()
+ properties()
+ tasks()
+ wrapper()
+ }
+ }
+ })
}
- def "displays basic structure of a polyglot project"() {
+ def "displays basic values of a simple model graph with values"() {
given:
buildFile << """
-plugins {
- id 'jvm-component'
- id 'java-lang'
- id 'cpp'
- id 'c'
+
+ at Managed
+public interface PasswordCredentials {
+ String getUsername()
+ String getPassword()
+ void setUsername(String s)
+ void setPassword(String s)
}
+
+${managedNumbers()}
+
model {
- components {
- jvmLib(JvmLibrarySpec)
- nativeLib(NativeLibrarySpec)
+ primaryCredentials(PasswordCredentials){
+ username = 'uname'
+ password = 'hunter2'
+ }
+
+ nullCredentials(PasswordCredentials) { }
+ numbers(Numbers){
+ value = 5
+ threshold = 0.8
}
}
+
"""
buildFile
when:
run "model"
then:
- def report = new ConsoleReportOutput(output)
- report.hasTitle('Root project')
- report.hasRootNode('model')
- report.hasNodeStructure(
- """model
- binaries
- jvmLibJar
- tasks
- nativeLibSharedLibrary
- tasks
- nativeLibStaticLibrary
- tasks
- binaryNamingSchemeBuilder
- binarySpecFactory
- buildTypes
- componentSpecFactory
- components
- jvmLib
- binaries
- jvmLibJar
- tasks
- sources
- java
- resources
- nativeLib
- binaries
- nativeLibSharedLibrary
- tasks
- nativeLibStaticLibrary
- tasks
- sources
- c
- cpp
- flavors
- javaToolChain
- jvm
- languageTransforms
- languages
- platformResolver
- platforms
- repositories
- sources
- tasks
- assemble
- build
- check
- clean
- components
- createJvmLibJar
- createNativeLibStaticLibrary
- dependencies
- dependencyInsight
- help
- init
- jvmLibJar
- linkNativeLibSharedLibrary
- model
- nativeLibSharedLibrary
- nativeLibStaticLibrary
- projects
- properties
- tasks
- wrapper
- toolChains"""
- )
+ ModelReportOutput.from(output).hasNodeStructure({
+ model {
+ nullCredentials {
+ password(type: 'java.lang.String', creator: 'model.nullCredentials')
+ username(type: 'java.lang.String', creator: 'model.nullCredentials')
+ }
+
+ numbers {
+ threshold(nodeValue: "0.8")
+ value(nodeValue: "5")
+ }
+ primaryCredentials {
+ password(nodeValue: 'hunter2', type: 'java.lang.String', creator: 'model.primaryCredentials')
+ username(nodeValue: 'uname', type: 'java.lang.String', creator: 'model.primaryCredentials')
+ }
+ tasks {
+ components(nodeValue: "task ':components'")
+ dependencies(nodeValue: "task ':dependencies'")
+ dependencyInsight(nodeValue: "task ':dependencyInsight'")
+ help(nodeValue: "task ':help'")
+ init(nodeValue: "task ':init'")
+ model(nodeValue: "task ':model'")
+ projects(nodeValue: "task ':projects'")
+ properties(nodeValue: "task ':properties'")
+ tasks(nodeValue: "task ':tasks'")
+ wrapper()
+ }
+ }
+ })
}
- def "displays basic values of a simple model graph with values"() {
+ // nb: specifically doesn't use the parsing fixture, so that the output is visualised
+ //If you're changing this you will also need to change: src/samples/userguideOutput/basicRuleSourcePlugin-model-task.out
+ def "displays a report in the correct format"() {
given:
buildFile << """
@@ -147,11 +126,7 @@ public interface PasswordCredentials {
}
- at Managed
-public interface Numbers {
- Integer getValue()
- void setValue(Integer i)
-}
+${managedNumbers()}
model {
primaryCredentials(PasswordCredentials){
@@ -162,6 +137,7 @@ model {
nullCredentials(PasswordCredentials) { }
numbers(Numbers){
value = 5
+ threshold = 0.8
}
}
@@ -171,28 +147,161 @@ model {
run "model"
then:
+ def modelReportOutput = ModelReportOutput.from(output)
+ modelReportOutput.hasTitle("Root project")
- output.contains(toPlatformLineSeparators(
- """model
- nullCredentials
- password
- username
- numbers
- value = 5
- primaryCredentials
- password = hunter2
- username = uname
- tasks
- components = task ':components'
- dependencies = task ':dependencies'
- dependencyInsight = task ':dependencyInsight'
- help = task ':help'
- init = task ':init'
- model = task ':model'
- projects = task ':projects'
- properties = task ':properties'
- tasks = task ':tasks'
-"""))
+ and:
+ modelReportOutput.nodeContentEquals('''
++ model
+ + nullCredentials
+ | Type: \tPasswordCredentials
+ | Creator: \tmodel.nullCredentials
+ + password
+ | Type: \tjava.lang.String
+ | Creator: \tmodel.nullCredentials
+ + username
+ | Type: \tjava.lang.String
+ | Creator: \tmodel.nullCredentials
+ + numbers
+ | Type: \tNumbers
+ | Creator: \tmodel.numbers
+ + threshold
+ | Type: \tdouble
+ | Value: \t0.8
+ | Creator: \tmodel.numbers
+ + value
+ | Type: \tjava.lang.Integer
+ | Value: \t5
+ | Creator: \tmodel.numbers
+ + primaryCredentials
+ | Type: \tPasswordCredentials
+ | Creator: \tmodel.primaryCredentials
+ + password
+ | Type: \tjava.lang.String
+ | Value: \thunter2
+ | Creator: \tmodel.primaryCredentials
+ + username
+ | Type: \tjava.lang.String
+ | Value: \tuname
+ | Creator: \tmodel.primaryCredentials
+ + tasks
+ | Type: \torg.gradle.model.ModelMap<org.gradle.api.Task>
+ | Creator: \tProject.<init>.tasks()
+ + components
+ | Type: \torg.gradle.api.reporting.components.ComponentReport
+ | Value: \ttask ':components'
+ | Creator: \ttasks.addPlaceholderAction(components)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + dependencies
+ | Type: \torg.gradle.api.tasks.diagnostics.DependencyReportTask
+ | Value: \ttask ':dependencies'
+ | Creator: \ttasks.addPlaceholderAction(dependencies)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + dependencyInsight
+ | Type: \torg.gradle.api.tasks.diagnostics.DependencyInsightReportTask
+ | Value: \ttask ':dependencyInsight'
+ | Creator: \ttasks.addPlaceholderAction(dependencyInsight)
+ | Rules:
+ ⤷ HelpTasksPlugin.Rules#addDefaultDependenciesReportConfiguration
+ ⤷ copyToTaskContainer
+ + help
+ | Type: \torg.gradle.configuration.Help
+ | Value: \ttask ':help'
+ | Creator: \ttasks.addPlaceholderAction(help)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + init
+ | Type: \torg.gradle.buildinit.tasks.InitBuild
+ | Value: \ttask ':init'
+ | Creator: \ttasks.addPlaceholderAction(init)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + model
+ | Type: \torg.gradle.api.reporting.model.ModelReport
+ | Value: \ttask ':model'
+ | Creator: \ttasks.addPlaceholderAction(model)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + projects
+ | Type: \torg.gradle.api.tasks.diagnostics.ProjectReportTask
+ | Value: \ttask ':projects'
+ | Creator: \ttasks.addPlaceholderAction(projects)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + properties
+ | Type: \torg.gradle.api.tasks.diagnostics.PropertyReportTask
+ | Value: \ttask ':properties'
+ | Creator: \ttasks.addPlaceholderAction(properties)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + tasks
+ | Type: \torg.gradle.api.tasks.diagnostics.TaskReportTask
+ | Value: \ttask ':tasks'
+ | Creator: \ttasks.addPlaceholderAction(tasks)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + wrapper
+ | Type: \torg.gradle.api.tasks.wrapper.Wrapper
+ | Value: \ttask ':wrapper'
+ | Creator: \ttasks.addPlaceholderAction(wrapper)
+ | Rules:
+ ⤷ copyToTaskContainer
+''')
+ }
+
+ def "method rule sources have simple type names and correct order"() {
+ given:
+ buildFile << """
+${managedNumbers()}
+
+class NumberRules extends RuleSource {
+ @Model("myNumbers")
+ void createRule(Numbers n) {
+ n.setValue(5)
+ n.setThreshold(0.8)
+ }
+ @Defaults void defaultsRule(Numbers n) {}
+ @Mutate void mutateRule(Numbers n) {}
+ @Finalize void finalizeRule(Numbers n) {}
+ @Validate void validateRule(Numbers n) {}
+}
+
+class ClassHolder {
+ static class InnerRules extends RuleSource {
+ @Mutate void mutateRule(Numbers n) {}
+ }
+}
+
+apply plugin: NumberRules
+apply plugin: ClassHolder.InnerRules
+"""
+ buildFile
+ when:
+ run "model"
+
+ then:
+ def modelNode = ModelReportOutput.from(output).modelNode
+ modelNode.myNumbers. at creator[0] == 'NumberRules#createRule'
+
+ int i = 0
+ def rules = modelNode.myNumbers. at rules[0]
+ rules[i++] == 'NumberRules#defaultsRule'
+ rules[i++] == 'NumberRules#mutateRule'
+ rules[i++] == 'ClassHolder.InnerRules#mutateRule'
+ rules[i++] == 'NumberRules#finalizeRule'
+ rules[i] == 'NumberRules#validateRule'
+ }
+
+ private String managedNumbers() {
+ return """@Managed
+ public interface Numbers {
+ Integer getValue()
+ void setValue(Integer i)
+ double getThreshold()
+ void setThreshold(double d)
+ }"""
}
}
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/AbstractBinaryRenderer.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/AbstractBinaryRenderer.java
index d220831..c992e76 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/AbstractBinaryRenderer.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/AbstractBinaryRenderer.java
@@ -19,7 +19,9 @@ package org.gradle.api.reporting.components.internal;
import org.apache.commons.lang.StringUtils;
import org.gradle.api.tasks.diagnostics.internal.text.TextReportBuilder;
import org.gradle.internal.text.TreeFormatter;
+import org.gradle.language.base.LanguageSourceSet;
import org.gradle.logging.StyledTextOutput;
+import org.gradle.model.ModelMap;
import org.gradle.platform.base.BinarySpec;
import org.gradle.platform.base.internal.BinaryBuildAbility;
import org.gradle.platform.base.internal.BinarySpecInternal;
@@ -47,6 +49,8 @@ public abstract class AbstractBinaryRenderer<T extends BinarySpec> extends Repor
renderOutputs(specialized, builder);
renderBuildAbility(specialized, builder);
+
+ renderOwnedSourceSets(specialized, builder);
}
public abstract Class<T> getTargetType();
@@ -68,4 +72,15 @@ public abstract class AbstractBinaryRenderer<T extends BinarySpec> extends Repor
builder.item(formatter.toString());
}
}
+
+ protected void renderOwnedSourceSets(T binary, TextReportBuilder builder) {
+ if (((BinarySpecInternal) binary).isLegacyBinary()) {
+ return;
+ }
+ ModelMap<LanguageSourceSet> sources = binary.getSources();
+ if (!sources.isEmpty()) {
+ SourceSetRenderer sourceSetRenderer = new SourceSetRenderer();
+ builder.itemCollection("source sets", sources.values(), sourceSetRenderer, "source sets");
+ }
+ }
}
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentRenderer.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentRenderer.java
index a1b3eb9..2f9ba38 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentRenderer.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentRenderer.java
@@ -37,7 +37,7 @@ public class ComponentRenderer extends ReportRenderer<ComponentSpec, TextReportB
public void render(ComponentSpec component, TextReportBuilder builder) {
builder.subheading(StringUtils.capitalize(component.getDisplayName()));
builder.getOutput().println();
- builder.collection("Source sets", CollectionUtils.sort(component.getSource().values(), SourceSetRenderer.SORT_ORDER), sourceSetRenderer, "source sets");
+ builder.collection("Source sets", CollectionUtils.sort(component.getSources().values(), SourceSetRenderer.SORT_ORDER), sourceSetRenderer, "source sets");
builder.getOutput().println();
builder.collection("Binaries", CollectionUtils.sort(component.getBinaries().values(), TypeAwareBinaryRenderer.SORT_ORDER), binaryRenderer, "binaries");
}
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentReportRenderer.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentReportRenderer.java
index 547b95e..f872eb4 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentReportRenderer.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/ComponentReportRenderer.java
@@ -63,7 +63,7 @@ public class ComponentReportRenderer extends TextReportRenderer {
seen = true;
}
componentRenderer.render(component, getBuilder());
- componentSourceSets.addAll(component.getSource().values());
+ componentSourceSets.addAll(component.getSources().values());
componentBinaries.addAll(component.getBinaries().values());
}
}
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/DiagnosticsServices.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/DiagnosticsServices.java
index d81a773..cd7bd95 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/DiagnosticsServices.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/DiagnosticsServices.java
@@ -34,6 +34,9 @@ public class DiagnosticsServices implements PluginServiceRegistry {
});
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/SourceSetRenderer.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/SourceSetRenderer.java
index ee60093..739f42c 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/SourceSetRenderer.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/components/internal/SourceSetRenderer.java
@@ -76,7 +76,7 @@ class SourceSetRenderer extends ReportRenderer<LanguageSourceSet, TextReportBuil
DependencySpecContainer dependencies = ((DependentSourceSetInternal) sourceSet).getDependencies();
if (!dependencies.isEmpty()) {
builder.item("dependencies");
- builder.collection(dependencies, new ReportRenderer<DependencySpec, TextReportBuilder>() {
+ builder.collection(dependencies.getDependencies(), new ReportRenderer<DependencySpec, TextReportBuilder>() {
@Override
public void render(DependencySpec model, TextReportBuilder output) throws IOException {
List<String> parts = Lists.newArrayList();
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/ModelReport.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/ModelReport.java
index bf9d18b..0c41f59 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/ModelReport.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/ModelReport.java
@@ -50,10 +50,14 @@ public class ModelReport extends DefaultTask {
Project project = getProject();
StyledTextOutput textOutput = getTextOutputFactory().create(ModelReport.class);
ModelNodeRenderer renderer = new ModelNodeRenderer();
+
TextModelReportRenderer textModelReportRenderer = new TextModelReportRenderer(renderer);
+
textModelReportRenderer.setOutput(textOutput);
textModelReportRenderer.startProject(project);
+
textModelReportRenderer.render(getModelRegistry().realizeNode(ModelPath.ROOT));
+
textModelReportRenderer.completeProject(project);
textModelReportRenderer.complete();
}
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/internal/ModelNodeRenderer.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/internal/ModelNodeRenderer.java
index a2ab3fb..7a9ceba 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/internal/ModelNodeRenderer.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/reporting/model/internal/ModelNodeRenderer.java
@@ -17,21 +17,27 @@
package org.gradle.api.reporting.model.internal;
import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import org.gradle.api.tasks.diagnostics.internal.text.TextReportBuilder;
import org.gradle.logging.StyledTextOutput;
import org.gradle.model.internal.core.ModelNode;
import org.gradle.model.internal.core.ModelPath;
+import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.type.ModelType;
import org.gradle.reporting.ReportRenderer;
import java.util.Map;
import java.util.TreeMap;
-import static org.gradle.logging.StyledTextOutput.Style.Description;
-import static org.gradle.logging.StyledTextOutput.Style.Identifier;
+import static org.gradle.logging.StyledTextOutput.Style.*;
public class ModelNodeRenderer extends ReportRenderer<ModelNode, TextReportBuilder> {
+ private static final int LABEL_LENGTH = 7;
+
@Override
public void render(ModelNode model, TextReportBuilder output) {
if (model.isHidden()) {
@@ -39,17 +45,16 @@ public class ModelNodeRenderer extends ReportRenderer<ModelNode, TextReportBuild
}
StyledTextOutput styledTextoutput = output.getOutput();
+
if (model.getPath().equals(ModelPath.ROOT)) {
- styledTextoutput.println("model");
- } else {
- styledTextoutput.withStyle(Identifier).format("%s", model.getPath().getName());
- if (model.getLinkCount() == 0) {
- Optional<String> value = model.getValueDescription();
- if (value.isPresent()) {
- styledTextoutput.withStyle(Description).format(" = %s", value.get());
- }
- }
+ styledTextoutput.withStyle(Identifier).format("+ %s", "model");
styledTextoutput.println();
+ } else {
+ printNodeName(model, styledTextoutput);
+ maybePrintType(model, styledTextoutput);
+ maybePrintValue(model, styledTextoutput);
+ printCreator(model, styledTextoutput);
+ maybePrintRules(model, styledTextoutput);
}
Map<String, ModelNode> links = new TreeMap<String, ModelNode>();
@@ -58,4 +63,73 @@ public class ModelNodeRenderer extends ReportRenderer<ModelNode, TextReportBuild
}
output.collection(links.values(), this);
}
+
+ public void printNodeName(ModelNode model, StyledTextOutput styledTextoutput) {
+ styledTextoutput.withStyle(Identifier).format("+ %s", model.getPath().getName());
+ styledTextoutput.println();
+ }
+
+ public void printCreator(ModelNode model, StyledTextOutput styledTextoutput) {
+ ModelRuleDescriptor descriptor = model.getDescriptor();
+ StringBuffer buffer = new StringBuffer();
+ descriptor.describeTo(buffer);
+ printNodeAttribute(styledTextoutput, "Creator:", buffer.toString());
+ }
+
+ public void maybePrintType(ModelNode model, StyledTextOutput styledTextoutput) {
+ Optional<String> typeDescription = model.getTypeDescription();
+ if (typeDescription.isPresent()) {
+ printNodeAttribute(styledTextoutput, "Type:", typeDescription.get());
+ }
+ }
+
+ public void maybePrintValue(ModelNode model, StyledTextOutput styledTextoutput) {
+ if (model.getLinkCount() == 0) {
+ Optional<String> value = model.getValueDescription();
+ if (value.isPresent()) {
+ printNodeAttribute(styledTextoutput, "Value:", value.get());
+ }
+ }
+ }
+
+ private void maybePrintRules(ModelNode model, StyledTextOutput styledTextoutput) {
+ Iterable<ModelRuleDescriptor> executedRules = uniqueExecutedRulesExcludingCreator(model);
+ if (!Iterables.isEmpty(executedRules)) {
+ printNestedAttributeTitle(styledTextoutput, "Rules:");
+ for (ModelRuleDescriptor ruleDescriptor : executedRules) {
+ printNestedAttribute(styledTextoutput, "⤷ " + ruleDescriptor.toString());
+ }
+ }
+ }
+
+ private void printNestedAttribute(StyledTextOutput styledTextoutput, String value) {
+ styledTextoutput.withStyle(Normal).format(" %s", value);
+ styledTextoutput.println();
+ }
+
+ private void printNestedAttributeTitle(StyledTextOutput styledTextoutput, String title) {
+ styledTextoutput.withStyle(Identifier).format(" | %s", title);
+ styledTextoutput.println();
+ }
+
+ public void printNodeAttribute(StyledTextOutput styledTextoutput, String label, String value) {
+ styledTextoutput.withStyle(Identifier).format(" | %s", attributeLabel(label));
+ styledTextoutput.withStyle(Description).format(" \t%s", value);
+ styledTextoutput.println();
+ }
+
+
+ private String attributeLabel(String label) {
+ return Strings.padEnd(label, LABEL_LENGTH, ' ');
+ }
+
+ static Iterable<ModelRuleDescriptor> uniqueExecutedRulesExcludingCreator(final ModelNode model) {
+ Iterable filtered = Iterables.filter(model.getExecutedRules(), new Predicate<ModelRuleDescriptor>() {
+ @Override
+ public boolean apply(ModelRuleDescriptor input) {
+ return !input.equals(model.getDescriptor());
+ }
+ });
+ return ImmutableSet.copyOf(filtered);
+ }
}
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/DefaultTextReportBuilder.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/DefaultTextReportBuilder.java
index 4a30081..52e2ffa 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/DefaultTextReportBuilder.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/DefaultTextReportBuilder.java
@@ -75,6 +75,16 @@ public class DefaultTextReportBuilder implements TextReportBuilder {
textOutput.style(Normal).println();
}
+ public <T> void itemCollection(String title, Collection<? extends T> items, ReportRenderer<T, TextReportBuilder> renderer, String elementsPlural) {
+ StyledTextOutput original = textOutput;
+ try {
+ textOutput = new LinePrefixingStyledTextOutput(original, " ");
+ collection(title + ":", items, renderer, elementsPlural);
+ } finally {
+ textOutput = original;
+ }
+ }
+
public <T> void collection(String title, Collection<? extends T> items, ReportRenderer<T, TextReportBuilder> renderer, String elementsPlural) {
textOutput.println(title);
if (items.isEmpty()) {
diff --git a/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/TextReportBuilder.java b/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/TextReportBuilder.java
index 10b9831..79f8a9c 100644
--- a/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/TextReportBuilder.java
+++ b/subprojects/diagnostics/src/main/groovy/org/gradle/api/tasks/diagnostics/internal/text/TextReportBuilder.java
@@ -27,6 +27,8 @@ public interface TextReportBuilder {
void subheading(String heading);
+ <T> void itemCollection(String title, Collection<? extends T> items, ReportRenderer<T, TextReportBuilder> renderer, String elementsPlural);
+
<T> void collection(String title, Collection<? extends T> items, ReportRenderer<T, TextReportBuilder> renderer, String elementsPlural);
<T> void collection(Iterable<? extends T> items, ReportRenderer<T, TextReportBuilder> renderer);
diff --git a/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/components/internal/ComponentReportRendererTest.groovy b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/components/internal/ComponentReportRendererTest.groovy
index 7eca1f0..64f59db 100644
--- a/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/components/internal/ComponentReportRendererTest.groovy
+++ b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/components/internal/ComponentReportRendererTest.groovy
@@ -94,7 +94,7 @@ class ComponentReportRendererTest extends Specification {
getDisplayName() >> "<source set>"
}
def component = Stub(ComponentSpec) {
- getSource() >> Stub(ModelMap) {
+ getSources() >> Stub(ModelMap) {
values() >> [sourceSet1]
}
}
diff --git a/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ModelReportNodeBuilderTest.groovy b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ModelReportNodeBuilderTest.groovy
new file mode 100644
index 0000000..7326382
--- /dev/null
+++ b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ModelReportNodeBuilderTest.groovy
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+import spock.lang.Specification
+
+class ModelReportNodeBuilderTest extends Specification {
+
+ def "builds a report node structure from a DSL"() {
+ ReportNode node = ModelReportNodeBuilder.fromDsl({
+ model {
+ childOne()
+ childTwo(aValue: 'someThing', anotherValue: 'somethingElse')
+ }
+ }).get()
+
+ expect:
+ node.'**'.childOne
+ node.'**'.childTwo. at aValue[0] == 'someThing'
+ node.'**'.childTwo. at anotherValue[0] == 'somethingElse'
+ }
+
+ def "can accept an empty closue"() {
+ def node = ModelReportNodeBuilder.fromDsl {}.get()
+ expect:
+ node == null
+ }
+}
diff --git a/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ModelReportParserTest.groovy b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ModelReportParserTest.groovy
new file mode 100644
index 0000000..c49a9a3
--- /dev/null
+++ b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ModelReportParserTest.groovy
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class ModelReportParserTest extends Specification {
+
+ @Unroll
+ def "fails with invalid text"() {
+ when:
+ ModelReportParser.parse(text)
+
+ then:
+ def ex = thrown(AssertionError)
+ ex.message.startsWith message
+
+ where:
+ text | message
+ '' | 'Report text must not be blank'
+ null | 'Report text must not be blank'
+ 's' | 'Should have at least 7 lines'
+ }
+
+ def "fails when missing the success marker"() {
+ when:
+ ModelReportParser.parse("""1
+2
+3
+4
+5
+6
++ model
+BUILD SUCCESSFUsL
+""")
+ then:
+ def ex = thrown(AssertionError)
+ ex.message.startsWith "Expected to find an end of report marker '${ModelReportParser.END_OF_REPORT_MARKER}'"
+ }
+
+ def "fails when missing a root node"() {
+ when:
+ ModelReportParser.parse("""1
+2
+3
+4
+5
+6
++ incorrect
+BUILD SUCCESSFUL
+""")
+ then:
+ def ex = thrown(AssertionError)
+ ex.message.startsWith "Expected to find the root node '${ModelReportParser.ROOT_NODE_MARKER}'"
+ }
+
+ def "should parse a report with no children"() {
+ def modelReport = ModelReportParser.parse(""":model
+
+
+My Report
+
+
++ model
+BUILD SUCCESSFUL
+""")
+ expect:
+ modelReport.title == 'My Report'
+ modelReport.reportNode.name() == 'model'
+ modelReport.reportNode.children() == []
+ }
+
+ def "should parse a model report with child nodes and values"() {
+ setup:
+ def modelReport = ModelReportParser.parse(""":model
+
+
+My Report
+
+
++ model
+ + nullCredentials
+ | Type: \t PasswordCredentials
+ + password
+ | Type: \t java.lang.String
+ + username
+ | Type: \t java.lang.String
+ + numbers
+ | Type: \t Numbers
+ + value
+ | Value: \t 5
+ | Type: \t java.lang.Integer
+ + primaryCredentials
+ | Type: \t PasswordCredentials
+ | Rules:
+ ⤷ Rule1
+ ⤷ Rule2
+ + password
+ | Value: \t hunter2
+ | Type: \t java.lang.String
+ + username
+ | Value: \t uname
+ | Type: \t java.lang.String
+
+BUILD SUCCESSFUL
+""")
+
+ expect:
+ modelReport.reportNode.'**'.primaryCredentials.username. at nodeValue[0] == 'uname'
+ modelReport.reportNode.'**'.primaryCredentials.username. at type[0] == 'java.lang.String'
+ modelReport.reportNode.'**'.primaryCredentials. at rules[0][0]== 'Rule1'
+ modelReport.reportNode.'**'.primaryCredentials. at rules[0][1]== 'Rule2'
+ }
+
+ def "should find a node attributes"() {
+ ReportNode reportNode = new ReportNode('test')
+ when:
+ ModelReportParser.setNodeProperties(line, reportNode)
+
+ then:
+ reportNode.attribute(expectedAttribute) == expectedValue
+ where:
+ line | expectedAttribute | expectedValue
+ '| Value: \t some value' | 'nodeValue' | 'some value'
+ '| Type: \t some type' | 'type' | 'some type'
+ }
+}
diff --git a/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ReportNodeTest.groovy b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ReportNodeTest.groovy
new file mode 100644
index 0000000..273ca21
--- /dev/null
+++ b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/ReportNodeTest.groovy
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+import spock.lang.Specification
+
+class ReportNodeTest extends Specification {
+
+ def "should create a report node with a child"() {
+ setup:
+ ReportNode reportNode = new ReportNode('myName')
+ def child = new ReportNode('child')
+ reportNode.append(child)
+
+ expect:
+ reportNode.children().size() == 1
+ }
+
+ def "should find the first matching child node"() {
+ setup:
+ ReportNode parent = new ReportNode('parent')
+ new ReportNode(parent, 'child', [aVal: 2])
+ new ReportNode(parent, 'child', [aVal: 1])
+
+ expect:
+ parent.findFirstByName('child').attribute('aVal') == 2
+ }
+}
diff --git a/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/internal/ModelNodeRendererTest.groovy b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/internal/ModelNodeRendererTest.groovy
new file mode 100644
index 0000000..54eaa64
--- /dev/null
+++ b/subprojects/diagnostics/src/test/groovy/org/gradle/api/reporting/model/internal/ModelNodeRendererTest.groovy
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model.internal
+
+import org.gradle.model.internal.core.ModelNode
+import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor
+import spock.lang.Specification
+
+
+class ModelNodeRendererTest extends Specification {
+
+ def "should filter rules removeing duplicates and excluding creators"() {
+ ModelRuleDescriptor creator = Mock()
+ creator.describeTo(_) >> { Appendable a ->
+ a.append("creator")
+ }
+
+ ModelRuleDescriptor mutator = Mock()
+ mutator.describeTo(_) >> { Appendable a ->
+ a.append("mutator")
+ }
+
+ ModelNode modelNode = Mock()
+ modelNode.getDescriptor() >> creator
+ modelNode.getExecutedRules() >> [creator, mutator, creator, mutator]
+
+ expect:
+ ModelNodeRenderer.uniqueExecutedRulesExcludingCreator(modelNode).asList() == [mutator]
+ }
+}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/components/JvmComponentReportOutputFormatter.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/components/JvmComponentReportOutputFormatter.groovy
new file mode 100644
index 0000000..0511e64
--- /dev/null
+++ b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/components/JvmComponentReportOutputFormatter.groovy
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.components
+
+import org.gradle.api.JavaVersion
+
+
+class JvmComponentReportOutputFormatter extends ComponentReportOutputFormatter {
+ @Override
+ String transform(String original) {
+ def java = JavaVersion.current()
+ return super.transform(
+ original
+ .replace("java7", "java" + java.majorVersion)
+ .replace("JDK 7 (1.7)", "JDK " + java.majorVersion + " (" + java + ")")
+ )
+ }
+}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/components/PlayComponentReportOutputFormatter.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/components/PlayComponentReportOutputFormatter.groovy
new file mode 100644
index 0000000..77cc63b
--- /dev/null
+++ b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/components/PlayComponentReportOutputFormatter.groovy
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.components
+
+import org.gradle.api.JavaVersion
+
+class PlayComponentReportOutputFormatter extends ComponentReportOutputFormatter {
+ @Override
+ String transform(String original) {
+
+ return super.transform(
+ original.replace("Java SE 8", "Java SE " + JavaVersion.current().majorVersion)
+ )
+ }
+}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ConsoleReportOutput.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ConsoleReportOutput.groovy
deleted file mode 100644
index 1ee788f..0000000
--- a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ConsoleReportOutput.groovy
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.api.reporting.model
-
-import org.gradle.util.TextUtil
-
-import static org.gradle.util.TextUtil.toPlatformLineSeparators
-
-class ConsoleReportOutput {
- public static final String LINE_SEPARATOR = TextUtil.getPlatformLineSeparator()
- public static final int HEADING_LINE_NUMBER = 2
- public static final int FIRST_NODE_LINE_NUMBER = 6
- public static final int PADDING_SIZE = 4
- private String consoleOutput
- def lines
-
- ConsoleReportOutput(String consoleOutput) {
- this.consoleOutput = toPlatformLineSeparators(consoleOutput)
- lines = consoleOutput?.split(LINE_SEPARATOR)
- }
-
- void hasTitle(String text) {
- lineIs(HEADING_LINE_NUMBER, '------------------------------------------------------------')
- lineIs(HEADING_LINE_NUMBER + 1, text)
- lineIs(HEADING_LINE_NUMBER + 2, '------------------------------------------------------------')
- }
-
- void hasNodeStructure(String text) {
- List<String> nodeLines = lines[FIRST_NODE_LINE_NUMBER..-1]
- def subject = toPlatformLineSeparators(text).split(LINE_SEPARATOR)
- String firstToken = subject[0]
- int startPosition = nodeLines.findIndexOf { name -> name == firstToken }
- assert startPosition >= 0: "Failed to find the first node:$firstToken"
- int endPosition = startPosition + (subject.size() - 1)
- nodeLines[startPosition..endPosition].eachWithIndex { String line, i ->
- assert line.startsWith(subject[i]): "\n\n Expected Line:|${line}| to start with:|${subject[i]}| \n\n"
- }
- }
-
- void hasRootNode(String text) {
- assert lines[FIRST_NODE_LINE_NUMBER] == text
- }
-
- void lineIs(int num, String text) {
- assert lines[num] == text
- }
-
- void hasNodeAtDepth(String node, int depth) {
- String paddedNode = ((" " * PADDING_SIZE) * (depth - 1)) + node
- assert lines.findAll { it.startsWith(paddedNode) }
- }
-
- void debug() {
- println("Total report lines: ${lines.size()}")
- println("Original output: ${consoleOutput}")
- println("Numbered Lines: ")
- lines.eachWithIndex { l, i ->
- println "$i. $l"
- }
-
- }
-}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportNodeBuilder.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportNodeBuilder.groovy
new file mode 100644
index 0000000..dd8c336
--- /dev/null
+++ b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportNodeBuilder.groovy
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+class ModelReportNodeBuilder extends BuilderSupport {
+ private ReportNode rootNode
+
+ @Override
+ protected void setParent(Object parent, Object child) {
+ parent.append(child)
+ }
+
+ @Override
+ protected Object createNode(Object name) {
+ def node = new ReportNode(name)
+ if (name == 'root') {
+ this.rootNode = node
+ }
+ return node
+ }
+
+ @Override
+ protected Object createNode(Object name, Object value) {
+ return new ReportNode(name)
+ }
+
+ @Override
+ protected Object createNode(Object name, Map attributes) {
+ def node = new ReportNode(name, attributes)
+ return node
+ }
+
+ @Override
+ protected Object createNode(Object name, Map attributes, Object value) {
+ return null
+ }
+
+ public ReportNode get() {
+ return rootNode.children()?.find()
+ }
+
+ static ModelReportNodeBuilder fromDsl(Closure<?> closure) {
+ def report = new ModelReportNodeBuilder()
+ report.root(closure)
+ return report
+ }
+}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportOutput.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportOutput.groovy
new file mode 100644
index 0000000..3442198
--- /dev/null
+++ b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportOutput.groovy
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+class ModelReportOutput {
+ private final ParsedModelReport parsedModelReport
+
+ static ModelReportOutput from(String text) {
+ new ModelReportOutput(ModelReportParser.parse(text))
+ }
+
+ public ModelReportOutput(ParsedModelReport parsedModelReport) {
+ this.parsedModelReport = parsedModelReport
+ }
+
+ void hasTitle(String text) {
+ assert parsedModelReport.title == text
+ }
+
+ void nodeContentEquals(String text) {
+ assert text
+ List<String> subject = text.trim().readLines()
+ assert subject.size() == parsedModelReport.nodeOnlyLines.size()
+ parsedModelReport.nodeOnlyLines.eachWithIndex { String line, i ->
+ assert line == subject[i]: "\n\n Expected Line:${line} to start with:${subject[i]} line#($i)\n\n"
+ }
+ }
+
+ /**
+ * Finds the first occurrence of the root node of the {@code closure} representing a {@link ModelReportNodeBuilder} from within the entire report. i.e. a subtree
+ * @see {@link ModelReportOutput#hasNodeStructure(groovy.lang.Closure)}
+ */
+ void hasNodeStructure(@DelegatesTo(ModelReportNodeBuilder) Closure<?> closure) {
+ hasNodeStructure(ModelReportNodeBuilder.fromDsl(closure).get())
+ }
+
+ /**
+ * Finds the first occurrence of the root node of {@code modelReportBuilder} from within the entire report. i.e. a subtree
+ * Each node of the subtree is then verified against the expected structure.
+ */
+ void hasNodeStructure(ReportNode expectedNode) {
+ def parsedNodes = parsedModelReport.reportNode
+ def actualNode = parsedNodes.findFirstByName(expectedNode.name())
+ assert actualNode: "Could not find the first node to begin comparison"
+ checkNodes(actualNode, expectedNode)
+ }
+
+ /**
+ * A fuzzy assertion which recursively asserts that:
+ * - {@code excepted} has, at a minimum, has the same number of and node names as {@actual}
+ * - Where an {@code excepted} node has properties (nodeValue, types, etc.) the vales of those properties will be asserted with {@actual}
+ *
+ * @param actual Some or all of the model report used as the reference to verify {@code excepted}
+ * @param expected A representation of some or all of the model report to be checked against {@code actual}
+ */
+ void checkNodes(ReportNode actual, ReportNode expected) {
+ assert actual.children().size() == expected.children().size()
+ assert actual.name == expected.name
+ ModelReportParser.NODE_ATTRIBUTES.each { String display, String property ->
+ if (expected.attribute(property)) {
+ assert actual.attribute(property) == expected.attribute(property)
+ }
+ }
+ expected.children().eachWithIndex { ReportNode node, int index ->
+ checkNodes(actual.children()[index], node)
+ }
+ }
+
+ def getModelNode() {
+ parsedModelReport.reportNode
+ }
+}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportParser.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportParser.groovy
new file mode 100644
index 0000000..5014631
--- /dev/null
+++ b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ModelReportParser.groovy
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+import com.google.common.annotations.VisibleForTesting
+
+import java.util.regex.Matcher
+
+class ModelReportParser {
+
+ public static final int HEADING_LINE_NUMBER = 3
+ public static final int FIRST_NODE_LINE_NUMBER = 6
+ public static final String NODE_LEFT_PADDING = ' '
+ public static final String NODE_SYMBOL = '+'
+ public static final String END_OF_REPORT_MARKER = 'BUILD SUCCESSFUL'
+ public static final String ROOT_NODE_MARKER = '+ model'
+ public static final LinkedHashMap<String, String> NODE_ATTRIBUTES = ['Value': 'nodeValue', 'Type': 'type', 'Creator': 'creator']
+
+ static ParsedModelReport parse(String text) {
+ validate(text)
+ def reportLines = text.readLines()
+ def nodeLines = reportLines[FIRST_NODE_LINE_NUMBER..-1]
+
+ return new ParsedModelReport(
+ getTitle(reportLines),
+ reportLines,
+ nodeOnlyLines(nodeLines),
+ parseNodes(nodeLines)
+ )
+ }
+
+ private static void validate(String text) {
+ assert text: 'Report text must not be blank'
+ def reportLines = text.readLines()
+ assert reportLines.size() > FIRST_NODE_LINE_NUMBER: "Should have at least ${FIRST_NODE_LINE_NUMBER + 1} lines"
+ assert text.contains(END_OF_REPORT_MARKER): "Expected to find an end of report marker '${END_OF_REPORT_MARKER}'"
+ assert text.contains(ROOT_NODE_MARKER): "Expected to find the root node '${ROOT_NODE_MARKER}'"
+ }
+
+ private static String getTitle(List<String> reportLines) {
+ return reportLines[HEADING_LINE_NUMBER]
+ }
+
+ private static ReportNode parseNodes(List<String> nodeLines) {
+ ReportNode prev = null
+ ReportNode root = null
+ nodeLines.each { line ->
+ if (prev == null) {
+ assert line == ROOT_NODE_MARKER
+ root = new ReportNode(getNodeName(line))
+ root.setDepth(0)
+ prev = root
+ } else if (lineIsANode(line)) {
+ int depth = getNodeDepth(line)
+ if (depth > prev.getDepth()) {
+ ReportNode node = new ReportNode(prev, getNodeName(line))
+ node.setDepth(depth)
+ prev = node
+ } else if (depth == prev.getDepth()) {
+ ReportNode node = new ReportNode(prev.parent(), getNodeName(line))
+ node.setDepth(depth)
+ prev = node
+ } else {
+ while (depth < prev.getDepth()) {
+ prev = prev.parent()
+ }
+ ReportNode node = new ReportNode(prev.parent(), getNodeName(line))
+ node.setDepth(depth)
+ prev = node
+ }
+ } else {
+ if (isARuleLabel(line)) {
+ prev.attributes()['rules'] = []
+ } else if (isARule(line)) {
+ prev.attributes()['rules'] << rule(line)
+ } else {
+ setNodeProperties(line, prev)
+ }
+ }
+ }
+ return root
+ }
+
+ private static String rule(String line) {
+ return line.replaceAll('⤷', '').trim()
+ }
+
+ private static boolean isARule(String line) {
+ return line =~ /⤷ /
+ }
+
+ private static boolean isARuleLabel(String line) {
+ return line =~ /$( +)| Rules:/
+ }
+
+ private static String getNodeName(String line) {
+ def matcher = lineIsANode(line)
+ return matcher[0][1]
+ }
+
+ private static int getNodeDepth(String line) {
+ return (line =~ /$NODE_LEFT_PADDING/).getCount()
+ }
+
+ @VisibleForTesting
+ static void setNodeProperties(String line, ReportNode reportNode) {
+ NODE_ATTRIBUTES.each { String pattern, String prop ->
+ def matcher = (line =~ /\| ${pattern}: (.+)$/)
+ if (matcher) {
+ String val = matcher[0][1]
+ if (val) {
+ reportNode.attributes()[prop] = val.trim()
+ }
+ }
+ }
+ }
+
+ private static Matcher lineIsANode(String line) {
+ return line =~ /\$NODE_SYMBOL (.+)$/
+ }
+
+ private static List<String> nodeOnlyLines(List<String> nodeLines) {
+ int successMarker = nodeLines.findIndexOf { line -> line == END_OF_REPORT_MARKER }
+ nodeLines.subList(0, successMarker - 1)
+ }
+}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ParsedModelReport.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ParsedModelReport.groovy
new file mode 100644
index 0000000..db43e89
--- /dev/null
+++ b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ParsedModelReport.groovy
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+
+class ParsedModelReport {
+ final String title
+ final List<String> reportLines
+ final List<String> nodeOnlyLines
+ final ReportNode reportNode
+
+ ParsedModelReport(String title, List<String> reportLines, List<String> nodeOnlyLines, ReportNode reportNode) {
+ this.title = title
+ this.reportLines = reportLines.asImmutable()
+ this.nodeOnlyLines = nodeOnlyLines.asImmutable()
+ this.reportNode = reportNode
+ }
+}
diff --git a/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ReportNode.groovy b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ReportNode.groovy
new file mode 100644
index 0000000..be01e06
--- /dev/null
+++ b/subprojects/diagnostics/src/testFixtures/groovy/org/gradle/api/reporting/model/ReportNode.groovy
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.reporting.model
+/**
+ *
+ * Represents a node of a hierarchical report
+ * Extends from groovy's {@code groovy.util.Node} and hence GPath expressions can be used to search and identify report nodes and values.
+ *
+ * See http://www.groovy-lang.org/processing-xml.html#_gpath
+ *
+ * E.g:
+ * <pre>
+ * modelReport.reportNode.'**'.primaryCredentials.username. at nodeValue[0] == 'uname'
+ * modelReport.reportNode.'**'.primaryCredentials.username. at type[0] == 'java.lang.String'
+ * </pre>
+ *
+ */
+class ReportNode extends Node {
+ Integer depth
+
+ ReportNode(name) {
+ super(null, name)
+ }
+
+ ReportNode(ReportNode parent, name) {
+ super(parent, name)
+ }
+
+ ReportNode(name, Map attributes) {
+ super(null, name, attributes)
+ }
+
+ ReportNode(ReportNode parent, name, Map attributes) {
+ super(parent, name, attributes)
+ }
+
+ ReportNode findFirstByName(String aName) {
+ return this.depthFirst().find { ReportNode node -> node.name() == aName }
+ }
+
+ String getType() {
+ return attribute('type')
+ }
+
+ String getNodeValue() {
+ return attribute('nodeValue')
+ }
+
+ Integer getDepth() {
+ return depth
+ }
+}
diff --git a/subprojects/distributions/src/integTest/groovy/org/gradle/AllDistributionIntegrationSpec.groovy b/subprojects/distributions/src/integTest/groovy/org/gradle/AllDistributionIntegrationSpec.groovy
index dd6df8e..f70d38d 100644
--- a/subprojects/distributions/src/integTest/groovy/org/gradle/AllDistributionIntegrationSpec.groovy
+++ b/subprojects/distributions/src/integTest/groovy/org/gradle/AllDistributionIntegrationSpec.groovy
@@ -30,7 +30,7 @@ class AllDistributionIntegrationSpec extends DistributionIntegrationSpec {
@Override
int getLibJarsCount() {
- 157
+ 158
}
def allZipContents() {
diff --git a/subprojects/distributions/src/integTest/groovy/org/gradle/BinDistributionIntegrationSpec.groovy b/subprojects/distributions/src/integTest/groovy/org/gradle/BinDistributionIntegrationSpec.groovy
index 707af73..1eb106d 100644
--- a/subprojects/distributions/src/integTest/groovy/org/gradle/BinDistributionIntegrationSpec.groovy
+++ b/subprojects/distributions/src/integTest/groovy/org/gradle/BinDistributionIntegrationSpec.groovy
@@ -27,7 +27,7 @@ class BinDistributionIntegrationSpec extends DistributionIntegrationSpec {
@Override
int getLibJarsCount() {
- 157
+ 158
}
def binZipContents() {
diff --git a/subprojects/docs/docs.gradle b/subprojects/docs/docs.gradle
index 933c787..152c4ef 100755
--- a/subprojects/docs/docs.gradle
+++ b/subprojects/docs/docs.gradle
@@ -334,6 +334,7 @@ task javadocAll(type: Javadoc) {
classpath = files(publicGroovyProjects.collect {project -> [project.sourceSets.main.compileClasspath, project.sourceSets.main.output] })
include 'org/gradle/*'
include 'org/gradle/api/**'
+ include 'org/gradle/authentication/**'
include 'org/gradle/buildinit/**'
include 'org/gradle/external/javadoc/**'
include 'org/gradle/ide/**'
@@ -352,6 +353,7 @@ task javadocAll(type: Javadoc) {
include 'org/gradle/sonar/runner/**'
include 'org/gradle/tooling/**'
include 'org/gradle/model/**'
+ include 'org/gradle/testkit/**'
exclude '**/internal/**'
options.links(javaApiUrl, groovyApiUrl, "http://maven.apache.org/ref/2.2.1/maven-core/apidocs",
"http://maven.apache.org/ref/2.2.1/maven-model/apidocs")
diff --git a/subprojects/docs/src/docs/css/dsl.css b/subprojects/docs/src/docs/css/dsl.css
index 31068aa..e6de7ff 100644
--- a/subprojects/docs/src/docs/css/dsl.css
+++ b/subprojects/docs/src/docs/css/dsl.css
@@ -3,7 +3,6 @@
font-size: 15px;
color: #AF5252;
background-color: pink;
- text-transform: lowercase;
font-style: italic;
border-radius: 3px;
display: inline-block;
@@ -142,4 +141,4 @@ table .caution {
div.chapter h5 {
margin-left: 0px;
-}
\ No newline at end of file
+}
diff --git a/subprojects/docs/src/docs/css/javadoc.css b/subprojects/docs/src/docs/css/javadoc.css
index 8ab8dfb..4275275 100644
--- a/subprojects/docs/src/docs/css/javadoc.css
+++ b/subprojects/docs/src/docs/css/javadoc.css
@@ -577,7 +577,7 @@ Table styles
background-image: none;
}
/** Don't show superfluous table headers */
-.overviewSummary th, .packageSummary th, .contentContainer ul.blockList li.blockList th, .summary th, .classUseContainer th, .constantValuesContainer th {
+.overviewSummary th, .packageSummary th, .summary th, .classUseContainer th, .constantValuesContainer th {
display: none;
}
diff --git a/subprojects/docs/src/docs/css/userguide.css b/subprojects/docs/src/docs/css/userguide.css
index f45f025..c792d4b 100644
--- a/subprojects/docs/src/docs/css/userguide.css
+++ b/subprojects/docs/src/docs/css/userguide.css
@@ -83,6 +83,10 @@ div.toc p b {
margin-top: 4em;
}
+.toc .chapter {
+ padding-top: 0;
+}
+
div.example code.filename {
font-weight: bold;
-}
\ No newline at end of file
+}
diff --git a/subprojects/docs/src/docs/dsl/dsl.xml b/subprojects/docs/src/docs/dsl/dsl.xml
index 9614d5a..71679a1 100644
--- a/subprojects/docs/src/docs/dsl/dsl.xml
+++ b/subprojects/docs/src/docs/dsl/dsl.xml
@@ -79,6 +79,8 @@
-
- 2. Adding new sections:
- The section title should end with 'types' (see AssembleDslDocTask.mergeContent)
+ -
+ - Add attribute condition='noNavBar' to the section element if the section should not appear in the nav bar.
-->
<section>
@@ -252,6 +254,38 @@
</table>
</section>
+ <section condition="noNavBar">
+ <title>Authentication types</title>
+ <para>Credentials and Authentication types for connecting to repositories:</para>
+ <table>
+ <title>Credential and Authentication types</title>
+ <tr>
+ <td>org.gradle.api.artifacts.repositories.AuthenticationSupported</td>
+ </tr>
+ <tr>
+ <td>org.gradle.api.credentials.Credentials</td>
+ </tr>
+ <tr>
+ <td>org.gradle.api.artifacts.repositories.PasswordCredentials</td>
+ </tr>
+ <tr>
+ <td>org.gradle.api.credentials.AwsCredentials</td>
+ </tr>
+ <tr>
+ <td>org.gradle.api.artifacts.repositories.AuthenticationContainer</td>
+ </tr>
+ <tr>
+ <td>org.gradle.authentication.Authentication</td>
+ </tr>
+ <tr>
+ <td>org.gradle.authentication.http.BasicAuthentication</td>
+ </tr>
+ <tr>
+ <td>org.gradle.authentication.http.DigestAuthentication</td>
+ </tr>
+ </table>
+ </section>
+
<section>
<title>Help Task types</title>
<para>Below are the task types that are available for every Gradle project.
@@ -503,10 +537,10 @@
</section>
<section>
- <title>Native binary core types</title>
- <para>Used to configure components developed with native code.</para>
+ <title>Native software model types</title>
+ <para>Used to configure software components developed with native code.</para>
<table>
- <title>Native component core types</title>
+ <title>Native software types</title>
<tr>
<td>org.gradle.nativeplatform.NativeExecutable</td>
</tr>
@@ -550,6 +584,9 @@
<td>org.gradle.nativeplatform.NativeExecutableBinarySpec</td>
</tr>
<tr>
+ <td>org.gradle.nativeplatform.NativeLibraryBinarySpec</td>
+ </tr>
+ <tr>
<td>org.gradle.nativeplatform.SharedLibraryBinarySpec</td>
</tr>
<tr>
@@ -610,7 +647,7 @@
</section>
<section>
<title>Native binary task types</title>
- <para>Tasks used to build native binary components.</para>
+ <para>Tasks used to build native binaries.</para>
<table>
<title>Native component task types</title>
<tr>
@@ -648,4 +685,52 @@
</tr>
</table>
</section>
+
+ <section condition="noNavBar">
+ <title>Play Framework model types</title>
+ <para>Used to configure software components developed with the Play Framework.</para>
+ <table>
+ <title>Play Framework model types</title>
+ <tr>
+ <td>org.gradle.play.PlayApplicationBinarySpec</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.PlayApplicationSpec</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.platform.PlayPlatform</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.JvmClasses</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.PublicAssets</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.distribution.PlayDistributionContainer</td>
+ </tr>
+ </table>
+ </section>
+
+ <section condition="noNavBar">
+ <title>Play Framework task types</title>
+ <para>Tasks used to build applications using the Play Framework.</para>
+ <table>
+ <title>Play Framework task types</title>
+ <tr>
+ <td>org.gradle.play.tasks.JavaScriptMinify</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.tasks.PlayRun</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.tasks.RoutesCompile</td>
+ </tr>
+ <tr>
+ <td>org.gradle.play.tasks.TwirlCompile</td>
+ </tr>
+ <!-- add PlatformScalaCompile -->
+ </table>
+ </section>
+
</book>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.Buildable.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.Buildable.xml
new file mode 100644
index 0000000..1695407
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.Buildable.xml
@@ -0,0 +1,41 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>buildDependencies</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.BuildableModelElement.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.BuildableModelElement.xml
new file mode 100644
index 0000000..0668714
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.BuildableModelElement.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>buildTask</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>builtBy</td>
+ </tr>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.PolymorphicDomainObjectContainer.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.PolymorphicDomainObjectContainer.xml
new file mode 100644
index 0000000..e2760e6
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.PolymorphicDomainObjectContainer.xml
@@ -0,0 +1,47 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>create</td>
+ </tr>
+ <tr>
+ <td>maybeCreate</td>
+ </tr>
+ <tr>
+ <td>containerWithType</td>
+ </tr>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.AuthenticationContainer.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.AuthenticationContainer.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.AuthenticationContainer.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.AuthenticationSupported.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.AuthenticationSupported.xml
index ec8541f..92d9244 100644
--- a/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.AuthenticationSupported.xml
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.AuthenticationSupported.xml
@@ -26,6 +26,9 @@
<tr>
<td>credentials</td>
</tr>
+ <tr>
+ <td>authentication</td>
+ </tr>
</table>
</section>
<section>
@@ -39,6 +42,9 @@
<tr>
<td>credentials</td>
</tr>
+ <tr>
+ <td>authentication</td>
+ </tr>
</table>
</section>
-</section>
\ No newline at end of file
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.PasswordCredentials.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.PasswordCredentials.xml
new file mode 100644
index 0000000..db75fda
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.artifacts.repositories.PasswordCredentials.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>username</td>
+ </tr>
+ <tr>
+ <td>password</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.credentials.AwsCredentials.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.credentials.AwsCredentials.xml
new file mode 100644
index 0000000..2116b10
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.credentials.AwsCredentials.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>accessKey</td>
+ </tr>
+ <tr>
+ <td>secretKey</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.credentials.Credentials.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.credentials.Credentials.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.credentials.Credentials.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.compile.JavaCompile.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.compile.JavaCompile.xml
index 2359356..464fca8 100644
--- a/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.compile.JavaCompile.xml
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.compile.JavaCompile.xml
@@ -13,7 +13,7 @@
<td/>
</tr>
<tr>
- <td>toolResolver</td>
+ <td>toolChain</td>
<td/>
</tr>
<tr>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Javadoc.xml b/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Javadoc.xml
index a2508a7..e49fc05 100644
--- a/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Javadoc.xml
+++ b/subprojects/docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Javadoc.xml
@@ -49,7 +49,7 @@
<td><literal>[]</literal></td>
</tr>
<tr>
- <td>toolResolver</td>
+ <td>toolChain</td>
<td></td>
</tr>
</table>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.authentication.Authentication.xml b/subprojects/docs/src/docs/dsl/org.gradle.authentication.Authentication.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.authentication.Authentication.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.authentication.http.BasicAuthentication.xml b/subprojects/docs/src/docs/dsl/org.gradle.authentication.http.BasicAuthentication.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.authentication.http.BasicAuthentication.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.authentication.http.DigestAuthentication.xml b/subprojects/docs/src/docs/dsl/org.gradle.authentication.http.DigestAuthentication.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.authentication.http.DigestAuthentication.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.nativeplatform.NativeLibraryBinarySpec.xml b/subprojects/docs/src/docs/dsl/org.gradle.nativeplatform.NativeLibraryBinarySpec.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.nativeplatform.NativeLibraryBinarySpec.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.platform.base.BinarySpec.xml b/subprojects/docs/src/docs/dsl/org.gradle.platform.base.BinarySpec.xml
index 96f5c37..2bef61b 100644
--- a/subprojects/docs/src/docs/dsl/org.gradle.platform.base.BinarySpec.xml
+++ b/subprojects/docs/src/docs/dsl/org.gradle.platform.base.BinarySpec.xml
@@ -43,8 +43,8 @@
</tr>
</thead>
<tr>
- <td>source</td>
+ <td>sources</td>
</tr>
</table>
</section>
-</section>
\ No newline at end of file
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.platform.base.ToolChain.xml b/subprojects/docs/src/docs/dsl/org.gradle.platform.base.ToolChain.xml
new file mode 100644
index 0000000..157ecf7
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.platform.base.ToolChain.xml
@@ -0,0 +1,41 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>displayName</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.JvmClasses.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.JvmClasses.xml
new file mode 100644
index 0000000..23dfea3
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.JvmClasses.xml
@@ -0,0 +1,47 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>classesDir</td>
+ </tr>
+ <tr>
+ <td>resourceDirs</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>addResourceDir</td>
+ </tr>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.PlayApplicationBinarySpec.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.PlayApplicationBinarySpec.xml
new file mode 100644
index 0000000..83d04e2
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.PlayApplicationBinarySpec.xml
@@ -0,0 +1,53 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>targetPlatform</td>
+ </tr>
+ <tr>
+ <td>jarFile</td>
+ </tr>
+ <tr>
+ <td>assetsJarFile</td>
+ </tr>
+ <tr>
+ <td>classes</td>
+ </tr>
+ <tr>
+ <td>assets</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.PlayApplicationSpec.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.PlayApplicationSpec.xml
new file mode 100644
index 0000000..5ded8da
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.PlayApplicationSpec.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>injectedRoutesGenerator</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>platform</td>
+ </tr>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.PublicAssets.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.PublicAssets.xml
new file mode 100644
index 0000000..12c6b75
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.PublicAssets.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>assetDirs</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>addAssetDir</td>
+ </tr>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.distribution.PlayDistributionContainer.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.distribution.PlayDistributionContainer.xml
new file mode 100644
index 0000000..5d063ff
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.distribution.PlayDistributionContainer.xml
@@ -0,0 +1,22 @@
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.platform.PlayPlatform.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.platform.PlayPlatform.xml
new file mode 100644
index 0000000..a49e973
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.platform.PlayPlatform.xml
@@ -0,0 +1,47 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>playVersion</td>
+ </tr>
+ <tr>
+ <td>scalaPlatform</td>
+ </tr>
+ <tr>
+ <td>javaPlatform</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.JavaScriptMinify.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.JavaScriptMinify.xml
new file mode 100644
index 0000000..29abb6c
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.JavaScriptMinify.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>destinationDir</td>
+ </tr>
+ <tr>
+ <td>forkOptions</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.PlayCoffeeScriptCompile.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.PlayCoffeeScriptCompile.xml
new file mode 100644
index 0000000..4b0fe6a
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.PlayCoffeeScriptCompile.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.PlayRun.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.PlayRun.xml
new file mode 100644
index 0000000..f70bf1d
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.PlayRun.xml
@@ -0,0 +1,53 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>forkOptions</td>
+ </tr>
+ <tr>
+ <td>httpPort</td>
+ </tr>
+ <tr>
+ <td>applicationJar</td>
+ </tr>
+ <tr>
+ <td>assetsJar</td>
+ </tr>
+ <tr>
+ <td>assetsDirs</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.RoutesCompile.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.RoutesCompile.xml
new file mode 100644
index 0000000..48ed67d
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.RoutesCompile.xml
@@ -0,0 +1,56 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>outputDirectory</td>
+ </tr>
+ <tr>
+ <td>forkOptions</td>
+ </tr>
+ <tr>
+ <td>additionalImports</td>
+ </tr>
+ <tr>
+ <td>generateReverseRoutes</td>
+ </tr>
+ <tr>
+ <td>namespaceReverseRouter</td>
+ </tr>
+ <tr>
+ <td>injectedRoutesGenerator</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.TwirlCompile.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.TwirlCompile.xml
new file mode 100644
index 0000000..d6ae8de
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.tasks.TwirlCompile.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>outputDirectory</td>
+ </tr>
+ <tr>
+ <td>forkOptions</td>
+ </tr>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.play.toolchain.PlayToolChain.xml b/subprojects/docs/src/docs/dsl/org.gradle.play.toolchain.PlayToolChain.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.play.toolchain.PlayToolChain.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/org.gradle.plugins.javascript.coffeescript.CoffeeScriptCompile.xml b/subprojects/docs/src/docs/dsl/org.gradle.plugins.javascript.coffeescript.CoffeeScriptCompile.xml
new file mode 100644
index 0000000..659d719
--- /dev/null
+++ b/subprojects/docs/src/docs/dsl/org.gradle.plugins.javascript.coffeescript.CoffeeScriptCompile.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright 2013 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<section>
+ <section>
+ <title>Properties</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+ <section>
+ <title>Methods</title>
+ <table>
+ <thead>
+ <tr>
+ <td>Name</td>
+ </tr>
+ </thead>
+ </table>
+ </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/docs/src/docs/dsl/plugins.xml b/subprojects/docs/src/docs/dsl/plugins.xml
index 613587c..05dca80 100755
--- a/subprojects/docs/src/docs/dsl/plugins.xml
+++ b/subprojects/docs/src/docs/dsl/plugins.xml
@@ -77,7 +77,7 @@
<extends targetClass="org.gradle.api.Project" id="binaries" extensionClass="org.gradle.platform.base.BinaryContainer"/>
<extends targetClass="org.gradle.api.Project" id="sources" extensionClass="org.gradle.language.base.ProjectSourceSet"/>
</plugin>
- <plugin id="native-component" description="Native Component Model Plugin"></plugin>
+ <plugin id="native-component" description="Native Software Model Plugin"></plugin>
<plugin id="cpp" description="C++ Plugin">
<extends targetClass="org.gradle.nativeplatform.NativeBinary" id="cppCompiler" extensionClass="org.gradle.language.PreprocessingTool"/>
</plugin>
@@ -103,4 +103,9 @@
<extends targetClass="org.gradle.api.Project" id="sonarRunner" extensionClass="org.gradle.sonar.runner.SonarRunnerExtension"/>
<extends targetClass="org.gradle.api.Project" id="sonarRunner" extensionClass="org.gradle.sonar.runner.SonarRunnerRootExtension"/>
</plugin>
+
+ <plugin id="play" description="Play Plugin">
+ </plugin>
+ <plugin id="play-coffeescript" description="Play Coffeescript Plugin">
+ </plugin>
</plugins>
diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md
index 95d64a9..e26d414 100644
--- a/subprojects/docs/src/docs/release/notes.md
+++ b/subprojects/docs/src/docs/release/notes.md
@@ -1,349 +1,191 @@
-Gradle 2.5 delivers some big features and plenty of internal improvements and optimizations.
+With this release, the Gradle team moves into a more rapid release cycle, with a goal to release a new version of Gradle every 4-6 weeks.
+By increasing our release frequency, we aim to reduce the wait time for important bug fixes, as well as get new features out sooner.
-The new “Continuous build” support brings capability to have Gradle automatically initiate a build in response to file system changes.
-This works with any build and has many applications. For example, it can be used to get continuous compile and test, giving more immediate feedback.
-As it works with _any_ Gradle task, it is equally applicable to documentation generation tasks and more.
-Upcoming versions of Gradle will build on this capability to facilitate reloading applications and the like under development in response to changes,
-providing a fast feedback local development loop.
+Even with a short development cycle, this release still contains some important features and improvements.
+As well as [fixing quite a few bugs](#fixed-issues), we've made incremental improvements to the new "Gradle TestKit"
+and enhanced the experience of developing Play applications using Gradle with continuous build.
-“Dependency substitution rules” make it possible to develop multiple related projects builds with more flexibility.
-It is now possible to dynamically substitute source dependencies with pre-built versions, and vice-versa, with greater ease.
-Dependency substitution rules are a powerful new addition to Gradle's arsenal for Dependency Management.
+In addition to this, this version of Gradle now makes it easier use GitHub or BitBucket to back an authenticated Maven repository,
+by adding support for [preemptive HTTP authentication](#support-for-preemptive-http-authentication).
-The Tooling API (i.e. the mechanism for [embedding Gradle](userguide/embedding.html)) now provides rich event information during the execution of the build to specified listeners.
-This mechanism can be used by IDEs and other tools wanting to provide visualisations or extra progress information during build execution.
+## Important: Performance regression with any wrapper generated by Gradle 2.6
-There are also notable improvements to Gradle's support for native code, including support for [GoogleTest](https://code.google.com/p/googletest/) and precompiled headers.
+If you generated your Gradle wrapper with Gradle 2.6, we strongly recommend you regenerate your `gradle-wrapper.jar` with Gradle 2.7.
+The new checksum validation feature added in 2.6 introduced a serious performance degradation in the Gradle wrapper. This issue affects the startup time
+for any gradle execution via this wrapper. This issue has been fixed in 2.7.
-## New and noteworthy
+**NOTE**: This only affects wrappers _generated by_ Gradle 2.6.
+ If you generated your wrapper with a older version, you can still configure that wrapper to point to Gradle 2.6 without issue.
-Here are the new features introduced in this Gradle release.
+## New and noteworthy in Gradle 2.7
-### Continuous build (i)
+### Selection of HTTP authentication schemes (i)
-The new continuous build support allows Gradle to automatically start building in response to file system changes.
-When you run with the `--continuous` or `-t` command line options, Gradle will not exit at the end of a build.
-Instead, Gradle will wait for files that are processed by the build to change.
-When changes are detected, Gradle will re-run the previous build with the same task selection.
+When authenticating to Maven or Ivy repositories over HTTP/HTTPS, Gradle will attempt to use all supported authentication schemes to connect (NTLM, Kerberos, Digest, Basic).
+This release allows for the explicit selection of authentication schemes that should be used, allowing a build author to prevent the use of an unwanted authentication scheme.
-For instance, if you run `gradle -t build` in a typical Java project, main and test sources will be built and tests will be run.
-If changes are made to the project's main sources, Gradle will rebuild the main Java sources and re-run the project's tests.
-If changes are made to the project's test sources, Gradle will only rebuild the test Java sources and re-run the project's tests.
+The authentication schemes to use are specified by adding them to the new
+<a href="dsl/org.gradle.api.artifacts.repositories.MavenArtifactRepository.html#org.gradle.api.artifacts.repositories.MavenArtifactRepository:authentication(org.gradle.api.Action)">authentication</a>
+element for a repository.
-This is just the initial iteration of this feature, which will improve in coming releases.
-Future releases will increase the scope of “changes” to include more than just local input files.
-For example, the scope of considered “changes” may expand in the future to encompass dependencies in remote repositories along with other types of inputs that affect the build result.
+For example, to configure a repository to use only digest authentication:
-For more information, please see the [new User Guide chapter](userguide/continuous_build.html).
+ repositories {
+ maven {
+ url 'https://repo.mycompany.com/maven2'
+ credentials {
+ username 'user'
+ password 'password'
+ }
+ authentication {
+ digest(DigestAuthentication)
+ }
+ }
+ }
-### Dependency substitution rules (i)
+Currently, only `BasicAuthentication` and `DigestAuthentication` schemes can be explicitly configured, and only for HTTP transport.
+More details can be found in the Gradle [User Guide](userguide/dependency_management.html#sub:authentication_schemes).
-Previous versions of Gradle allowed an external dependency to be replaced with another using a ['Dependency Resolve Rule'](https://docs.gradle.org/1.4/release-notes#dependency-resolve-rules).
-With the introduction of 'Dependency substitution rules' this behaviour has been enhanced and extended to allow external dependencies and project dependencies to be replaced interchangeably.
+### Support for preemptive HTTP authentication (i)
-When combined with a configurable Gradle settings file, these dependency substitution rules permit some powerful new ways of working with Gradle:
+Building on the [new support for selecting authentication schemes](#selection-of-http-authentication-schemes), Gradle will now send preemptive HTTP authentication
+for repositories configured to use `BasicAuthentication`.
-* While developing a patch for an external library, use a local project dependency instead of a module dependency.
-* For a large multi-project build, only develop with a subset of the projects locally, downloading the rest from an external repository.
-* Extensions to Gradle such as [Prezi Pride](https://github.com/prezi/pride) no longer require a custom dependency syntax.
+Gradle will normally submit HTTP credentials only when a server responds with an authentication challenge (401-UNAUTHORIZED). This avoids sending unencrypted credentials when not required.
+However, in some cases a server will respond with a different response for resources requiring authentication (e.g. GitHub will return a 404-NOT-FOUND).
+This causes dependency resolution to fail.
-Substitute a project dependency with an external module dependency like this:
+To get around this behavior, credentials may be sent to the server preemptively.
+Where a repository is explicitly configured to use the [`BasicAuthentication`](dsl/org.gradle.authentication.http.BasicAuthentication.html) scheme, Gradle
+will send credentials preemptively for every request:
- resolutionStrategy {
- dependencySubstitution {
- substitute project(":api") with module("org.utils:api:1.3")
- }
+ authentication {
+ basic(BasicAuthentication) // enable preemptive authentication
}
-Alternatively, an external dependency can be replaced with a project dependency like this:
+### Gradle TestKit executes tests within an isolated environment (i)
- resolutionStrategy {
- dependencySubstitution {
- substitute module("org.utils:api") with project(":api")
- }
- }
-
-It is also possible to substitute a project dependency with another, or a module dependency with another.
-(The latter provides the same functionality as `eachDependency`, with a more convenient syntax).
+The previous release of Gradle introduced the [Gradle TestKit](userguide/test_kit.html) for functionally testing Gradle plugins.
-Note: adding a dependency substitution rule to a `Configuration` used as a task input changes the timing of when that configuration is resolved.
-Instead of being resolved on first use, the `Configuration` is instead resolved when the task graph is being constructed.
-This can have unexpected consequences if the configuration is being further modified during task execution,
-or if the configuration relies on modules that are published during execution of another task.
+This release extends the existing TestKit feature set by adding **Test execution isolation**.
+Test execution is now performed in an isolated "working space" in order to prevent builds under test inheriting any environmental configuration from the current user.
-For more information consult the [User Guide](userguide/dependency_management.html#dependency_substitution_rules)
-and the [DSL Reference](dsl/org.gradle.api.artifacts.DependencySubstitutions.html).
+The TestKit uses dedicated, reusable Gradle daemon processes; after executing all functional tests for a build, these daemon processes are stopped.
-This feature was contributed by [Lóránt Pintér](https://github.com/lptr) and the team at [Prezi](https://prezi.com).
+### Play application displays build failures when running with `--continuous` (i)
-### Progress events via the Tooling API (i)
+The initial release of the [Gradle Play plugin](userguide/play_plugin.html) allowed Play applications to be developed
+ in a continuous build, automatically reloading resources and application classes on rebuild. However, when a build failure occurred, Gradle would simply leave the
+ existing application running.
-It is now possible to receive progress events for various build operations.
-Listeners can be provided to the [`BuildLauncher`](javadoc/org/gradle/tooling/BuildLauncher.html) via the
-[`addProgressListener(ProgressListener)`](javadoc/org/gradle/tooling/LongRunningOperation.html#addProgressListener\(org.gradle.tooling.events.ProgressListener\)) method.
-Events are fired when the task graph is being populated, when each task is executed, when tests are executed, etc.
+When running with Gradle 2.7, the running Play application will reload on build failure, showing any build failure message in the browser.
-All operations are part of a single-root hierarchy that can be traversed through the operation descriptors via
-[`ProgressEvent.getDescriptor()`](javadoc/org/gradle/tooling/events/ProgressEvent.html#getDescriptor\(\)) and
-[`OperationDescriptor.getParent()`](javadoc/org/gradle/tooling/events/OperationDescriptor.html#getParent\(\)).
+### Support for Play 2.4 (i)
-If you are only interested in the progress events for a sub-set of all available operations, you can use
-[`LongRunningOperation.addProgressListener(ProgressListener, Set<OperationType>)`](javadoc/org/gradle/tooling/LongRunningOperation.html#addProgressListener\(org.gradle.tooling.events.ProgressListener,%20java.util.Set\)).
-For example, you may elect to only receive events for the execution of tasks.
+In this release, the 'play' plugin has been updated to support Play 2.4, and includes support for the new injected routes generator.
-One potential use of this new capability would be to provide interesting visualisations of the build execution.
+You can configure the routes compiler to use the [injected routes generator](https://www.playframework.com/documentation/2.4.x/Migration24#Routing),
+by using a new configuration option on the [`play` component](dsl/org.gradle.play.PlayApplicationSpec.html):
-### Simpler default dependencies (i)
+ model {
+ components {
+ play {
+ injectedRoutesGenerator = true
+ }
+ }
+ }
-Many Gradle plugins allow the user to specify a dependency for a particular tool, supplying a default version only if none is provided by the user.
-A common implementation of this involves using a `beforeResolve()` hook to check if the configuration has any dependencies, adding the default dependency if not.
-The new [`defaultDependencies()`](dsl/org.gradle.api.artifacts.Configuration.html#org.gradle.api.artifacts.Configuration:defaultDependencies\(org.gradle.api.Action\))
-method has been introduced to make this simpler and more robust.
+By default, Gradle will use the static routes generator.
-The use of `beforeResolve()` to specify default dependencies will continue to work,
-but will emit a deprecation warning if the configuration has already participated in dependency resolution when it is first resolved (see below).
+### Managed model improvements (i)
-Specifying a default dependency with `beforeResolve` (deprecated):
+Managed types now support properties of any primitive type (`boolean`, `byte`, `char`, `short`, `int`, `long`, `float` and `double`), as well as any of their boxed types
+(respectively `Boolean`, `Byte`, `Character`, `Short`, `Integer`, `Long`, `Float` and `Double`).
+Primitive `boolean` properties can be declared with either a classic getter or an `is`-style getter. e.g.
- def util = dependencies.create("org.gradle:my-util:1.0")
- conf.incoming.beforeResolve {
- if (conf.dependencies.empty) {
- conf.dependencies.add(util)
- }
- }
+ @Managed
+ interface ManagedType {
+ boolean getEnabled()
+ void setEnabled(boolean enabled)
-Specifying a default dependency with `defaultDependencies` (recommended):
+ boolean isActive()
+ void setActive(boolean active)
- def util = dependencies.create("org.gradle:my-util:1.0")
- conf.defaultDependencies { dependencies ->
- dependencies.add(util)
+ int getCount()
+ void setCount(int value)
}
-See the <a href="dsl/org.gradle.api.artifacts.Configuration.html#org.gradle.api.artifacts.Configuration:defaultDependencies(org.gradle.api.Action)">DSL reference</a> for more details.
+It is possible for a single `boolean` property to have both a `get` and `is` getter.
-### Precompiled header support (i)
+### Dependency management for JVM components (i)
-Precompiled headers are a performance optimization for native builds that allows commonly used headers to be parsed only once rather than for each file that includes the headers.
-Precompiled headers are now supported for C, C++, Objective-C and Objective-C++ projects.
+This release introduces new dependency management features for JVM components, an important step toward full variant-aware dependency resolution.
+This feature is built upon the [new rule based model configuration](userguide/new_model.html) and requires you to use the new `jvm-component` plugin:
-To use a precompiled header, a header file needs to created containing all of the headers that should be precompiled.
-This header file is then declared in the build script as a precompiled header.
+ plugins {
+ id 'jvm-component'
+ id 'java-lang'
+ }
+
+A defined `JvmLibrarySpec` can declare API dependencies on any other locally-produced libraries. This includes other `JvmLibrarySpec` instances in the same
+Gradle project, and `JvmLibrarySpec` components declared in other projects of a multi-project build.
model {
components {
- hello(NativeLibrarySpec) {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ targetPlatform 'java8'
sources {
- cpp {
- preCompiledHeader "pch.h"
+ java {
+ dependencies {
+ library 'commons'
+ }
}
}
}
+ commons(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ }
}
}
-Each source set can have a single precompiled header defined.
-Any source file that includes this header file as the first header will be compiled using the precompiled header.
-Otherwise, the precompiled header will be ignored and the source file will be compiled in the normal manner.
-
-Please see the [User Guide](userguide/nativeBinaries.html#native_binaries:preCompiledHeaders) for further information.
+For a `JvmLibrarySpec` that is configured to produce multiple variants for different platforms, Gradle will generate and resolve a compatible binary variant of the depended-on library.
+In the example above, Gradle will produce 2 JAR variants of the 'main' library component, one each for JDK 1.7 and JDK 1.8. Both of these will be compiled against the
+JDK 1.7 Jar variant of the 'commons' library.
-### Google Test support (i)
-
-The new Gradle `google-test` plugin provides support for compiling and executing [GoogleTest](https://code.google.com/p/googletest/) tests in your native binary project.
-You simply need to include your Google Test test sources in a conventional location (i.e. `src/«component name»Test/cpp`).
-
-Gradle will build a test executable and run your tests.
-
-<pre><tt>> gradle -q runFailingOperatorsTest
-
-[==========] Running 2 tests from 1 test case.
-[----------] Global test environment set-up.
-[----------] 2 tests from OperatorTests
-[ RUN ] OperatorTests.test_plus
-src/operatorsTest/cpp/test_plus.cpp:8: Failure
-Value of: plus(0, -2) == -2
- Actual: false
-Expected: true
-[ FAILED ] OperatorTests.test_plus (0 ms)
-[ RUN ] OperatorTests.test_minus
-[ OK ] OperatorTests.test_minus (0 ms)
-[----------] 2 tests from OperatorTests (0 ms total)
-
-[----------] Global test environment tear-down
-[==========] 2 tests from 1 test case ran. (0 ms total)
-[ PASSED ] 1 test.
-[ FAILED ] 1 test, listed below:
-[ FAILED ] OperatorTests.test_plus
-
-1 FAILED TEST</tt></pre>
-
-See the [User Guide](userguide/nativeBinaries.html#native_binaries:google_test) to learn more.
-Expect deeper integration with Google Test (and other native testing tools) in the future.
-
-This feature was contributed by [Daniel Lacasse](https://github.com/Shad0w1nk).
-
-### Obtaining a task's group via the Tooling API
-
-It is now possible to obtain the “group” of a task via [`org.gradle.tooling.model.Task.getGroup()`](javadoc/org/gradle/tooling/model/GradleTask.html#getGroup\(\)).
-
-### New managed model improvements
-
-A number of improvements have been made to the experimental managed model feature. This feature is currently used by the native plugins and will evolve into
-a general purpose feature for describing Gradle builds:
-
-The model report for [Rule based model configuration](userguide/new_model.html) has been enhanced to display string representations of some values.
-This allows the effective values of the build model to be visualised, not just the structure as was the case previously.
-
-More of the new software model is now visible to the model report and to configuration rules.
-
-[`@Managed`](javadoc/org/gradle/model/Managed.html) models can now have managed model properties of type `java.io.File`.
-
-[`@Managed`](javadoc/org/gradle/model/Managed.html) types can now implement the [`Named`](javadoc/org/gradle/api/Named.html) interface.
-The `name` property will be automatically populated based on the objects location in the model graph.
-
-It is now possible for [`@Managed`](javadoc/org/gradle/model/Managed.html) types to declare properties of type [`ModelMap<T>`](javadoc/org/gradle/model/ModelMap.html).
+More information about this incubating feature can be found in the [User Guide](userguide/new_java_plugin.html).
## Fixed issues
-## Deprecations
-
-Features that have become superseded or irrelevant due to the natural evolution of Gradle become *deprecated*, and scheduled to be removed
-in the next major Gradle version (Gradle 3.0). See the User guide section on the “[Feature Lifecycle](userguide/feature_lifecycle.html)” for more information.
-
-The following are the newly deprecated items in this Gradle release. If you have concerns about a deprecation, please raise it via the [Gradle Forums](http://discuss.gradle.org).
-
-### Changing a configuration after it has participated in dependency resolution
-
-Unexpected behaviour can result from changing a configuration after it has participated in dependency resolution. Examples include:
-
-* Change the dependencies of a parent of a configuration: the child configuration will get different dependencies depending on when
- it is resolved.
-* Changing the artifacts of a configuration referenced as a project dependency: whether the referencing project gets those artifacts
- depends on the order that configurations are resolved.
-
-Previous versions of Gradle prevented the resolved configuration itself from being modified, but did nothing to
-prevent modifications to related configurations after they have participated in dependency resolution. This version of Gradle extends
-the checks, emitting a deprecation warning when a modification is made to a configuration that has been referenced in dependency
-resolution.
-
-One exception is that changes to the `ResolutionStrategy` of a configuration can be made at any time until that configuration is
-itself resolved. Changes to the strategy do not impact the resolution of child configurations, or configurations referenced as
-project dependencies. Thus, these changes are safe to make.
-
-### Distribution Plugin changes
-
-Due to a bug in the distribution plugin (see GRADLE-3278), earlier Gradle versions didn't follow the general naming convention for the assemble task of the main distribution.
-This has been fixed and assemble task name for the main distribution has changed from `assembleMainDist` to `assembleDist`.
-
-### Deprecation of `CollectionBuilder` and `ManagedSet`.
-
-The types `org.gradle.model.collection.CollectionBuilder` and `org.gradle.model.collection.ManagedSet` have been deprecated and replaced by
-[`org.gradle.model.ModelMap`](javadoc/org/gradle/model/ModelMap.html) and [`org.gradle.model.ModelSet`](javadoc/org/gradle/model/ModelSet.html) respectively.
-
-As these types were incubating, they will be removed before Gradle 3.0.
-Please change your usage to the new `ModelMap` and `ModelSet` types.
-
-### Deprecations in Eclipse model
-As part of the changes in the IDE classpath generation, the following properties have been deprecated:
-
-- `EclipseClasspath#noExportConfigurations`
-- `ProjectDependency#declaredConfigurationName`
-- `AbstractLibrary#declaredConfigurationName`
-
## Potential breaking changes
-### Changes to the new software model
-
-As work continues on the new software model for Gradle, many changes to the new incubating plugins and types
-are required. These changes should have no impact on builds that do not leverage these new features.
-
-#### Removal of `componentSpec` project extension
-
-As part of work on exposing more of the component model as managed types, the `componentSpec` project extension previously added by all language plugins via `ComponentModelBasePlugin` has been removed.
-The `components` container can now only be accessed using configuration rules.
-
-#### Changes to `ComponentSpecContainer`
+### Changes to `ANTLR` generated sources and package structure
-- `ComponentSpecContainer` no longer implements `ExtensiblePolymorphicDomainObjectContainer<ComponentSpec>`.
-- `ComponentSpecContainer` now implements `ModelMap<ComponentSpec>`.
-- All configuration done using subject of type `ComponentSpecContainer` is now deferred. In earlier versions of Gradle this configuration was eager.
+- The output directory for `ANTLR` generated sources is now calculated from package information in the grammar files. (This fixes a regression introduced in Gradle 2.2).
+- The output directory for `ANTLR3` and `ANTLR4` generated sources is now relative to the path of the grammar in the ANTLR grammar folder.
-#### Changes to `ComponentSpec`
-- `getSource()` now returns a `ModelMap<LanguageSourceSet>` instead of `DomainObjectSet<LanguageSourceSet>`.
-- `sources()` now takes a `Action<? super ModelMap<LanguageSourceSet>>` instead of `Action<? super PolymorphicDomainObjectContainer<LanguageSourceSet>>`.
-- `getBinaries()` now returns a `ModelMap<BinarySpec>` instead of `DomainObjectSet<BinarySpec>`.
-- `binaries()` now takes a `Action<? super ModelMap<BinarySpec>>` instead of `Action<? super DomainObjectSet<BinarySpec>>`.
-- Source sets and binaries cannot be removed from these collections.
+### Filtering source directory with overlapping source and resource directories in Eclipse
-#### Changes in `TestSuiteContainer`
+This release fixes a bug where generating the Eclipse classpath for projects with a shared directory for source and resource files using _includes_ and _excludes_
+declarations could cause problems (see [GRADLE-3335](https://issues.gradle.org/browse/GRADLE-3335) for details). This fix changes the behaviour of applying exclude/include
+filters to the source directory, which may result in a different set of directories in the generated Eclipse classpath.
-- `TestSuiteContainer` no longer implements `ExtensiblePolymorphicDomainObjectContainer<TestSuiteSpec>`.
-- `TestSuiteContainer` now implements `ModelMap<TestSuiteSpec>`.
-- All configuration done using subject of type `TestSuiteContainer` is now deferred. In earlier versions of Gradle this configuration was eager.
-
-### Maven publishing
-
-The [maven-publish](userguide/publishing_maven.html) and [maven](userguide/maven_plugin.html) plugins
-no longer use the Maven 2 based [Maven ant tasks](https://maven.apache.org/ant-tasks/) libraries to publish artifacts.
-Both plugins now use the newer Maven 3 and Aether libraries.
-Whilst the API's exposed by both plugins remain unchanged, the underlying publishing libraries have been upgraded.
-
-This upgrade was contributed by [Mikolaj Izdebski](https://github.com/mizdebsk).
-
-### Java annotation processing of Groovy code is now disabled by default
-
-[Gradle 2.4 introduced the ability to use Java annotation processors on Groovy sources](https://docs.gradle.org/2.4/release-notes#support-for-“annotation-processing”-of-groovy-code).
-If annotation processors were present on the classpath, they were implicitly applied to Groovy source.
-This caused problems in situations where a separate “processing” strategy was required for joint compiled Groovy source (GRADLE-3300).
-
-Java annotation processing of Groovy source is now disabled by default.
-It can be enabled by setting the
-[`javaAnnotationProcessing` property of `GroovyCompileOptions`](dsl/org.gradle.api.tasks.compile.GroovyCompileOptions.html#org.gradle.api.tasks.compile.GroovyCompileOptions:javaAnnotationProcessing)
-
- compileGroovy {
- groovyOptions.javaAnnotationProcessing = true
- }
-
-### Registering test progress listeners through the Tooling API
-
-The incubating API `BuildLauncher.addTestProgressListener()` and the associated listener type have been removed.
-This API has been superseded by the new [progress listener API](#progress-events-via-the-tooling-api).
-
-### Changes in IDE classpath generation
-
-Project files generated by the Gradle Idea and Eclipse plugins are responsible for deriving the classpath from the declared list of dependencies in the build file.
-Some incorrect behavior, resulting in incorrect classpaths in the IDE, has been rectified in this Gradle version.
-
-Let's assume project A and B are part of a multi-project build.
-Project B declares a project dependency on project A.
-The generated classpath of project B is a union of the classpath of project A (the generated JAR file plus its dependencies) and its own declared top-level dependencies and transitive dependencies.
-In practice, this means that when project A and B depend on a specific library with different versions, the "exported" dependency version wins as it happens to be listed first in the classpath of project B.
-This behaviour might lead to compilation and runtime issues in the IDE as no conflict-resolution takes place across projects.
-
-To avoid the situation just described, the IDE classpath generation now more closely reflects the classpath as it is used by Gradle:
-
-- All transitive external and project dependencies of a project are listed as direct dependencies in the project.
- - Different versions of a library are resolved by Gradle conflict resolution.
-- All dependencies in projects are marked as `exported = false`.
-
-### Dependency Substitution
-
-Gradle 2.4 included some of the new dependency substitution interfaces and classes, but they were unannounced. Build scripts written to use these interfaces in 2.4 will likely not work in 2.5.
-Please take a look at the dependency substitution sample and [User Guide chapter](userguide/dependency_management.html#dependency_substitution_rules) to understand the changes that were made
-while getting dependency substitution ready for the Gradle 2.5 release.
+For an exclude to be applied to the source folder in the Eclipse classpath, that exclude must be declared for both the java and resources sourceSets.
+This is only important in the case of _overlapping_ source and resource directories.
## External contributions
We would like to thank the following community members for making contributions to this release of Gradle.
-* [Daniel Lacasse](https://github.com/Shad0w1nk) - Support Google Test for testing C++ binaries
-* [Lóránt Pintér](https://github.com/lptr), [Daniel Vigovszky](https://github.com/vigoo) and [Mark Vujevits](https://github.com/vujevits) - implement dependency substitution for projects
-* [Larry North](https://github.com/LarryNorth) - Build improvements.
-* [Tobias Schulte](https://github.com/tschulte) - Documentation improvements.
-* [Stefan Oehme](https://github.com/oehme) - Addition of `Project.copy(Action)` and `Project.copySpec(Action)`.
-* [Mikolaj Izdebski](https://github.com/mizdebsk) - Upgrade of the Maven publishing mechanisms to use Aether libraries.
-* [Lorin Hochstein](https://github.com/lorin) - Improvements to the ANTLR plugin documentation.
-* [Amit Portnoy](https://github.com/amitport) - Minor fix in LifecycleBasePlugin
+* [Tony Abbott](https://github.com/tonyabbott) - Performance test improvements
+* [Emmanuel Bourg](https://github.com/ebourg) - Use correct import for `Sets` in `ProjectDependencyArtifactIdExtractorHack`
+* [Bruno Bowden](https://github.com/brunobowden) - Documentation improvements
+* [Ethan Hall](https://github.com/ethankhall) - Support for Checkstyle 6.8
+* [Chris Purcell](https://github.com/cjp39) - Documentation improvements
+* [Sebastian Schuberth](https://github.com/sschuberth) - Documentation improvements
+* [Hao Xia](https://github.com/jasonxh) - GRADLE-3338 Bump up joda-time version to resolve issue with JDK 8u60
+
+We love getting contributions from the Gradle community. For information on contributing, please see [gradle.org/contribute](http://gradle.org/contribute).
## Known issues
diff --git a/subprojects/docs/src/docs/stylesheets/dslHtml.xsl b/subprojects/docs/src/docs/stylesheets/dslHtml.xsl
index c0ac085..c63d675 100644
--- a/subprojects/docs/src/docs/stylesheets/dslHtml.xsl
+++ b/subprojects/docs/src/docs/stylesheets/dslHtml.xsl
@@ -74,7 +74,8 @@
<div class="sidebar">
<ul>
<xsl:apply-templates select="." mode="sidebar"/>
- <xsl:apply-templates select="/book/section/table[@role = 'dslTypes']" mode="sidebar"/>
+ <!-- only apply navbar to sections that are not marked with 'noNavBar' -->
+ <xsl:apply-templates select="/book/section[not(@condition) or @condition != 'noNavBar']/table[@role = 'dslTypes']" mode="sidebar"/>
</ul>
</div>
<div class="content">
@@ -209,4 +210,4 @@
<dt><xsl:apply-templates select="$segtitles[$segnum=position()]" mode="segtitle-in-seg"/>:</dt>
<dd><xsl:apply-templates/></dd>
</xsl:template>
-</xsl:stylesheet>
\ No newline at end of file
+</xsl:stylesheet>
diff --git a/subprojects/docs/src/docs/userguide/antlrPlugin.xml b/subprojects/docs/src/docs/userguide/antlrPlugin.xml
index 28554ae..c71565b 100644
--- a/subprojects/docs/src/docs/userguide/antlrPlugin.xml
+++ b/subprojects/docs/src/docs/userguide/antlrPlugin.xml
@@ -108,7 +108,8 @@
<td>
<filename>src/main/antlr</filename>
</td>
- <td>Production ANTLR grammar files.</td>
+ <td>Production ANTLR grammar files. If the ANTLR grammar is organized in packages, the structure in the antlr folder should reflect
+ the package structure. This ensures that the generated sources end up in the correct target subfolder.</td>
</tr>
<tr>
<td>
diff --git a/subprojects/docs/src/docs/userguide/buildScriptsTutorial.xml b/subprojects/docs/src/docs/userguide/buildScriptsTutorial.xml
index a77018f..ede5f23 100644
--- a/subprojects/docs/src/docs/userguide/buildScriptsTutorial.xml
+++ b/subprojects/docs/src/docs/userguide/buildScriptsTutorial.xml
@@ -202,7 +202,7 @@
</section>
<section id='sec:default_tasks'>
<title>Default tasks</title>
- <para>Gradle allows you to define one or more default tasks for your build.
+ <para>Gradle allows you to define one or more default tasks that are executed if no other tasks are specified.
</para>
<sample id="defaultTasks" dir="userguide/tutorial/defaultTasks" title="Defining a default tasks">
<sourcefile file="build.gradle"/>
diff --git a/subprojects/docs/src/docs/userguide/continuousBuild.xml b/subprojects/docs/src/docs/userguide/continuousBuild.xml
index d032c19..af0cd49 100644
--- a/subprojects/docs/src/docs/userguide/continuousBuild.xml
+++ b/subprojects/docs/src/docs/userguide/continuousBuild.xml
@@ -56,8 +56,7 @@
</para>
</tip>
<para>
- At this time, <emphasis>only</emphasis> changes to input files to the previously executed tasks will initiate a build.
- Furthermore, only changes that occur after the build has completed (and Gradle has prompted that it is waiting for changes) are noticed.
+ At this time, only changes that occur after the build has completed (and Gradle has prompted that it is waiting for changes) are noticed.
No other changes will initiate a build.
For example, changes to build scripts and build logic will not initiate build.
Likewise, changes to files that are read during the configuration of the build, not the execution, will not initiate a build.
diff --git a/subprojects/docs/src/docs/userguide/customPlugins.xml b/subprojects/docs/src/docs/userguide/customPlugins.xml
index c15a0e1..cd4057a 100644
--- a/subprojects/docs/src/docs/userguide/customPlugins.xml
+++ b/subprojects/docs/src/docs/userguide/customPlugins.xml
@@ -75,7 +75,7 @@
<para>
One thing to note is that a new instance of a given plugin is created for each project it is applied to. Also
note that the <apilink class="org.gradle.api.Plugin"/> class is a generic type. This example has it receiving the
- <apilink class="org.gradle.api.Plugin"/> type as a type parameter. It's possible to write unusual custom
+ <apilink class="org.gradle.api.Project"/> type as a type parameter. It's possible to write unusual custom
plugins that take different type parameters, but this will be unlikely (until someone figures out more
creative things to do here).
</para>
diff --git a/subprojects/docs/src/docs/userguide/depMngmt.xml b/subprojects/docs/src/docs/userguide/depMngmt.xml
index 289ed80..efd293f 100644
--- a/subprojects/docs/src/docs/userguide/depMngmt.xml
+++ b/subprojects/docs/src/docs/userguide/depMngmt.xml
@@ -840,7 +840,7 @@
<thead>
<tr>
<td>Type</td>
- <td>Authentication schemes</td>
+ <td>Credential types</td>
</tr>
</thead>
<tr>
@@ -982,6 +982,54 @@
</itemizedlist>
</note>
</section>
+
+ <section id="sub:authentication_schemes">
+ <title>Configuring HTTP authentication schemes</title>
+ <para>
+ When configuring a repository using HTTP or HTTPS transport protocols, multiple authentication schemes are available. By default, Gradle will attempt to use all schemes that
+ are supported by the Apache HttpClient library, <ulink url="http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html#d5e625">documented here</ulink>.
+ In some cases, it may be preferable to explicitly specify which authentication schemes should be used when exchanging credentials with a remote server. When explicitly
+ declared, only those schemes are used when authenticating to a remote repository. The following example show how to configure a repository to use only digest authentication:
+ </para>
+ <sample id="digestAuthentication" dir="userguide/artifacts/defineRepository" title="Configure repository to use only digest authentication">
+ <sourcefile file="build.gradle" snippet="digest-authentication"/>
+ </sample>
+ <para>
+ Currently supported authentication schemes are:
+ </para>
+ <table>
+ <title>Authentication schemes</title>
+ <thead>
+ <tr>
+ <th>Type</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><apilink class="org.gradle.authentication.http.BasicAuthentication"/></td>
+ <td>Basic access authentication over HTTP. When using this scheme, credentials are sent preemptively.</td>
+ </tr>
+ <tr>
+ <td><apilink class="org.gradle.authentication.http.DigestAuthentication"/></td>
+ <td>Digest access authentication over HTTP.</td>
+ </tr>
+ </tbody>
+ </table>
+ </section>
+
+ <section id="sub:preemptive_authentication">
+ <title>Using preemptive authentication</title>
+ <para>
+ Gradle's default behavior is to only submit credentials when a server responds with an authentication challenge in the form of a HTTP 401 response. In some cases,
+ the server will respond with a different code (ex. for repositories hosted on GitHub a 404 is returned) causing dependency resolution to fail. To get around this
+ behavior, credentials may be sent to the server preemptively. To enable preemptive authentication simply configure your repository to explicitly use the
+ <apilink class="org.gradle.authentication.http.BasicAuthentication"/> scheme:
+ </para>
+ <sample id="preemptiveAuthentication" dir="userguide/artifacts/defineRepository" title="Configure repository to use preemptive authentication">
+ <sourcefile file="build.gradle" snippet="preemptive-authentication"/>
+ </sample>
+ </section>
</section>
<section>
diff --git a/subprojects/docs/src/docs/userguide/gradleDaemon.xml b/subprojects/docs/src/docs/userguide/gradleDaemon.xml
index 61aaded..b9bc118 100644
--- a/subprojects/docs/src/docs/userguide/gradleDaemon.xml
+++ b/subprojects/docs/src/docs/userguide/gradleDaemon.xml
@@ -44,10 +44,6 @@
<section>
<title>How do I enable the Gradle Daemon?</title>
<para>
- The <literal>--daemon</literal> and <literal>--no-daemon</literal> command line switches enable and disable usage of the Daemon for individual build invocations when using the Gradle command line interface.
- Typically, it is more convenient to enable the Daemon for an environment (e.g. a user account) so that all builds use the Daemon without requiring to remember to supply the <literal>--daemon</literal> switch.
- </para>
- <para>
There are two recommended ways to enable the Daemon persistently for an environment:
</para>
<itemizedlist>
@@ -71,7 +67,7 @@
<para>
On Windows, this command will enable the Daemon for the current user:
<programlisting>
- (if not exist "%HOMEPATH%/.gradle" mkdir "%HOMEPATH%/.gradle") && (echo foo >> "%HOMEPATH%/.gradle/gradle.properties")
+ (if not exist "%HOMEPATH%/.gradle" mkdir "%HOMEPATH%/.gradle") && (echo org.gradle.daemon=true >> "%HOMEPATH%/.gradle/gradle.properties")
</programlisting>
On UNIX-like operating systems, the following Bash shell command will enable the Daemon for the current user:
<programlisting>
@@ -79,6 +75,10 @@
</programlisting>
Once the Daemon is enabled for a build environment in this way, all builds will implicitly use a Daemon.
</para>
+ <para>
+ The <literal>--daemon</literal> and <literal>--no-daemon</literal> command line switches enable and disable usage of the Daemon for individual build invocations when using the Gradle command line interface.
+ Typically, it is more convenient to enable the Daemon for an environment (e.g. a user account) so that all builds use the Daemon without requiring to remember to supply the <literal>--daemon</literal> switch.
+ </para>
</section>
<section>
<title>How do I disable the Gradle Daemon?</title>
diff --git a/subprojects/docs/src/docs/userguide/gradleWrapper.xml b/subprojects/docs/src/docs/userguide/gradleWrapper.xml
index 1ac59dc..77a9082 100644
--- a/subprojects/docs/src/docs/userguide/gradleWrapper.xml
+++ b/subprojects/docs/src/docs/userguide/gradleWrapper.xml
@@ -18,12 +18,12 @@
<para>
The Gradle Wrapper (henceforth referred to as the “wrapper”) is the preferred way of starting a Gradle build. The wrapper
is a batch script on Windows, and a shell script for other operating systems. When you start a Gradle build via the wrapper,
- Gradle will be automatically downloaded and used to run the build.
+ Gradle will be automatically downloaded and used to run the build.
</para>
<para>
The wrapper is something you <emphasis>should</emphasis> check into version control. By distributing the wrapper with your project,
- anyone can work with it without needing to install Gradle beforehand. Even better, users of the build are guaranteed to use the
- version of Gradle that the build was designed to work with. Of course, this is also great for
+ anyone can work with it without needing to install Gradle beforehand. Even better, users of the build are guaranteed to use the
+ version of Gradle that the build was designed to work with. Of course, this is also great for
<ulink url="http://en.wikipedia.org/wiki/Continuous_integration">continuous integration</ulink> servers (i.e. servers that regularly
build your project) as it requires no configuration on the server.
</para>
@@ -45,7 +45,7 @@
<sourcefile file="build.gradle"/>
</sample>
<para>
- After such an execution you find the following new or updated files in your project directory
+ After such an execution you find the following new or updated files in your project directory
(in case the default configuration of the wrapper task is used).
</para>
<sample id="wrapperSimple" dir="userguide/wrapper/simple" title="Wrapper generated files">
@@ -89,6 +89,33 @@
<para>If you build via the wrapper, any existing Gradle distribution installed on the machine is ignored.
</para>
</section>
+ <section id='sec:verification'>
+ <title>Verification of downloaded Gradle distributions</title>
+ <para>The Gradle Wrapper allows for verification of the downloaded Gradle distribution via SHA-256 hash sum comparison.
+ This increases security against targeted attacks by preventing a man-in-the-middle attacker from tampering with the downloaded Gradle distribution.
+ </para>
+ <para>
+ To enable this feature you'll want to first calculate the SHA-256 hash of a known Gradle distribution. You can generate a SHA-256 hash from Linux and
+ OSX or Windows (via <ulink url="https://www.cygwin.com/">Cygwin</ulink>) with the <command>shasum</command> command.
+ </para>
+ <example>
+ <title>Generating a SHA-256 hash</title>
+ <programlisting><![CDATA[
+> shasum -a 256 gradle-2.4-all.zip
+371cb9fbebbe9880d147f59bab36d61eee122854ef8c9ee1ecf12b82368bcf10 gradle-2.4-all.zip
+]]></programlisting>
+ </example>
+ <para>
+ Add the returned hash sum to the <literal>gradle-wrapper.properties</literal> using the <literal>distributionSha256Sum</literal> property.
+ </para>
+ <example>
+ <title>Configuring SHA-256 checksum verification</title>
+ <para><filename>gradle-wrapper.properties</filename></para>
+ <programlisting><![CDATA[
+distributionSha256Sum=371cb9fbebbe9880d147f59bab36d61eee122854ef8c9ee1ecf12b82368bcf10
+]]></programlisting>
+ </example>
+ </section>
<section id='sec:unix_file_permissions'>
<title>Unix file permissions</title>
<para>The Wrapper task adds appropriate file permissions to allow the execution of the <literal>gradlew</literal> *NIX command.
diff --git a/subprojects/docs/src/docs/userguide/img/playPluginModel.graphml b/subprojects/docs/src/docs/userguide/img/playPluginModel.graphml
new file mode 100644
index 0000000..5227d28
--- /dev/null
+++ b/subprojects/docs/src/docs/userguide/img/playPluginModel.graphml
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml [...]
+ <!--Created by yEd 3.14.2-->
+ <key attr.name="Description" attr.type="string" for="graph" id="d0"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key for="graphml" id="d7" yfiles.type="resources"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d0"/>
+ <node id="n0">
+ <data key="d6">
+ <y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
+ <y:Geometry height="87.3866666666667" width="140.4" x="-281.4" y="-149.4666666666667"/>
+ <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B7C9E3" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="119.716796875" x="10.341601562499989" y="4.0">PlayApplicationSpec</y:NodeLabel>
+ <y:NodeLabel alignment="left" autoSizePolicy="content" configuration="com.yworks.entityRelationship.label.attributes" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="46.3984375" modelName="custom" textColor="#000000" visible="true" width="94.69140625" x="2.0" y="30.1328125">Target Platform
+binaries
+sources<y:LabelModel>
+ <y:ErdAttributesNodeLabelModel/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:ErdAttributesNodeLabelModelParameter/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:StyleProperties>
+ <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/>
+ </y:StyleProperties>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:GenericNode configuration="com.yworks.entityRelationship.small_entity">
+ <y:Geometry height="30.0" width="140.4" x="96.0" y="-120.77333333333334"/>
+ <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="97.5859375" x="21.407031250000003" y="5.93359375">Scala Source Set<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:StyleProperties>
+ <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/>
+ </y:StyleProperties>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:GenericNode configuration="com.yworks.entityRelationship.small_entity">
+ <y:Geometry height="30.0" width="140.4" x="96.0" y="-70.30666666666664"/>
+ <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="91.451171875" x="24.474414062500003" y="5.93359375">Java Source Set<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:StyleProperties>
+ <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/>
+ </y:StyleProperties>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:GenericNode configuration="com.yworks.entityRelationship.small_entity">
+ <y:Geometry height="30.0" width="140.4" x="96.0" y="-18.34666666666665"/>
+ <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="127.322265625" x="6.538867187500003" y="5.93359375">Resources Source Set<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:StyleProperties>
+ <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/>
+ </y:StyleProperties>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:GenericNode configuration="com.yworks.entityRelationship.big_entity">
+ <y:Geometry height="77.0" width="140.4" x="-281.4" y="-13.386666666666656"/>
+ <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" backgroundColor="#B7C9E3" configuration="com.yworks.entityRelationship.label.name" fontFamily="Dialog" fontSize="10" fontStyle="plain" hasLineColor="false" height="15.77734375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="130.1181640625" x="5.140917968749989" y="4.0">PlayApplicationBinarySpec</y:NodeLabel>
+ <y:NodeLabel alignment="left" autoSizePolicy="content" configuration="com.yworks.entityRelationship.label.attributes" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="46.3984375" modelName="custom" textColor="#000000" visible="true" width="102.42578125" x="2.0" y="27.77734375">Compiled Assets
+Compiled Source
+Target Platform<y:LabelModel>
+ <y:ErdAttributesNodeLabelModel/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:ErdAttributesNodeLabelModelParameter/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:StyleProperties>
+ <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/>
+ </y:StyleProperties>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:GenericNode configuration="com.yworks.entityRelationship.small_entity">
+ <y:Geometry height="30.0" width="140.4" x="96.0" y="33.613333333333344"/>
+ <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
+ <y:BorderStyle color="#000000" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="124.48046875" x="7.959765625000003" y="5.93359375">JavaScript Source Set<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ <y:StyleProperties>
+ <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/>
+ </y:StyleProperties>
+ </y:GenericNode>
+ </data>
+ </node>
+ <edge id="e0" source="n0" target="n4">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="crows_foot_one_mandatory" target="crows_foot_one_mandatory"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e1" source="n0" target="n1">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="crows_foot_one_mandatory" target="crows_foot_many_mandatory"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e2" source="n0" target="n3">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="-22.499999999999986" y="-105.77333333333334"/>
+ <y:Point x="-22.499999999999986" y="-3.34666666666665"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="crows_foot_one_mandatory" target="crows_foot_many_mandatory"/>
+ <y:BendStyle smoothed="true"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e3" source="n0" target="n2">
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="-22.499999999999986" y="-105.77333333333334"/>
+ <y:Point x="-22.499999999999986" y="-55.30666666666664"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="crows_foot_one_mandatory" target="crows_foot_many_mandatory"/>
+ <y:BendStyle smoothed="true"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e4" source="n5" target="n0">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="70.21416015625002" ty="0.0">
+ <y:Point x="-22.499999999999986" y="48.613333333333344"/>
+ <y:Point x="-22.499999999999986" y="-105.77333333333334"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="crows_foot_many" target="none"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="-61.28639984130859" y="-32.000001322428375">
+ <y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
+ <y:BendStyle smoothed="true"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ </graph>
+ <data key="d7">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/subprojects/docs/src/docs/userguide/img/playPluginModel.png b/subprojects/docs/src/docs/userguide/img/playPluginModel.png
new file mode 100644
index 0000000..4ae4aba
Binary files /dev/null and b/subprojects/docs/src/docs/userguide/img/playPluginModel.png differ
diff --git a/subprojects/docs/src/docs/userguide/mavenPlugin.xml b/subprojects/docs/src/docs/userguide/mavenPlugin.xml
index 3d0f705..e1ecdda 100644
--- a/subprojects/docs/src/docs/userguide/mavenPlugin.xml
+++ b/subprojects/docs/src/docs/userguide/mavenPlugin.xml
@@ -77,27 +77,13 @@
</thead>
<tr>
<td>
- <literal>pomDirName</literal>
+ <literal>mavenPomDir</literal>
</td>
<td>
- <classname>String</classname>
+ <classname>File</classname>
</td>
<td>
- <literal>poms</literal>
- </td>
- <td>
- The path of the directory to write the generated POMs, relative to the build directory.
- </td>
- </tr>
- <tr>
- <td>
- <literal>pomDir</literal>
- </td>
- <td>
- <classname>File (read-only)</classname>
- </td>
- <td>
- <literal><replaceable>buildDir</replaceable>/<replaceable>pomDirName</replaceable></literal>
+ <literal><replaceable>${project.buildDir}</replaceable>/poms</literal>
</td>
<td>
The directory where the generated POMs are written to.
diff --git a/subprojects/docs/src/docs/userguide/multiproject.xml b/subprojects/docs/src/docs/userguide/multiproject.xml
index bff3456..07da1f4 100644
--- a/subprojects/docs/src/docs/userguide/multiproject.xml
+++ b/subprojects/docs/src/docs/userguide/multiproject.xml
@@ -162,7 +162,7 @@
You may notice that there are two code snippets referencing the “<literal>hello</literal>” task.
The first one, which uses the “<literal>task</literal>” keyword, constructs the task and provides it's base configuration.
The second piece doesn't use the “<literal>task</literal>” keyword, as it is further configuring the existing “<literal>hello</literal>” task.
- You may only construct a task once in a project, but you may any number of code blocks providing additional configuration.
+ You may only construct a task once in a project, but you may add any number of code blocks providing additional configuration.
</para>
</section>
<section id='sub:adding_specific_behavior'>
diff --git a/subprojects/docs/src/docs/userguide/nativeBinaries.xml b/subprojects/docs/src/docs/userguide/nativeBinaries.xml
index 897f3c6..c6f4dc2 100755
--- a/subprojects/docs/src/docs/userguide/nativeBinaries.xml
+++ b/subprojects/docs/src/docs/userguide/nativeBinaries.xml
@@ -3,7 +3,7 @@
<note>
<para>
- The Gradle support for building native binaries is currently <link linkend="feature_lifecycle">incubating</link>. Please be aware that the DSL and other configuration may change in later Gradle versions.
+ Support for building native binaries is currently <link linkend="feature_lifecycle">incubating</link>. Please be aware that the DSL, APIs and other configuration may change in later Gradle versions.
</para>
</note>
@@ -120,7 +120,7 @@
</section>
<section>
- <title>Component model</title>
+ <title>Native software model</title>
<para>
To build native binaries using Gradle, your project should define one or more <firstterm>native components</firstterm>. Each component represents either an
executable or a library that Gradle should build. A project can define any number of components. Gradle does not define any components by default.
diff --git a/subprojects/docs/src/docs/userguide/newJavaPlugin.xml b/subprojects/docs/src/docs/userguide/newJavaPlugin.xml
new file mode 100644
index 0000000..1c50a12
--- /dev/null
+++ b/subprojects/docs/src/docs/userguide/newJavaPlugin.xml
@@ -0,0 +1,313 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<chapter id='new_java_plugin'>
+ <title>The New Java Plugin</title>
+
+ <note>
+ <para>
+ Support for building Java libraries using the new software model is currently <link linkend="feature_lifecycle">incubating</link>. Please be aware that the DSL, APIs and other configuration may change in later Gradle versions.
+ </para>
+ </note>
+
+ <para>The New Java plugin is intended to replace the <link linkend="java_plugin">Java plugin</link>, and
+ leverages the <link linkend="new_model">new rule based model configuration</link>
+ to achieve the best performance, improved expressiveness
+ and support for variant-aware dependency management.
+ </para>
+
+ <section>
+ <title>The Software Model</title>
+ <para>The plugin relies on a software model which describes how an application is built, and how components
+ of the model relate to each other. The software model is organized around key concepts:
+ </para>
+ <para>
+ <itemizedlist>
+ <listitem>A
+ <firstterm>component</firstterm>
+ is a general concept for a piece of software, that might be deliverable. Examples of components are a standalone
+ application, a web application, a library, etc. A component is often composed of other components.
+ </listitem>
+ <listitem>A
+ <firstterm>library</firstterm>
+ is a buildable component. In the Java world, a library is often assimilated to a Jar file, but while a Jar file
+ represents an output, a library is the description of how the output is built. A library is defined by the combination of its source sets and variants.
+ </listitem>
+ <listitem>A
+ <firstterm>source set</firstterm>
+ represents a logical group of source files in a component. As such, a source set is often an input to a single
+ compilation task, which will produce an output (classes, compiled CSS, etc). A library may consist of multiple <firstterm>source sets</firstterm>.
+ </listitem>
+ <listitem>A
+ <firstterm>variant</firstterm>
+ represents a modulation of a component. A library, for example, might target Java 6 and Java 7, effectively producing two
+ distinct outputs: a Java 6 jar and a Java 7 jar. In this case, the target platform is an example of a <firstterm>variant dimension</firstterm>.
+ Custom library types may define their own <firstterm>variant dimensions</firstterm>, which will participate in dependency resolution.
+ </listitem>
+ <listitem>A <firstterm>binary</firstterm>
+ represents the output of a library. Given a combination of variants, a library may produce multiple binaries. A binary is often
+ a consumable artifact of other components.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Usage</title>
+ <para>To use the new Java plugin, include the following in your build script:</para>
+ <sample id="newJavaQuickstart" dir="newJavaPlugin/quickstart" title="Using the new Java plugin">
+ <sourcefile file="build.gradle" snippet="use-plugin"/>
+ </sample>
+ </section>
+
+ <section>
+ <title>Creating a library</title>
+ <para>A library is created by declaring a <apilink class="org.gradle.jvm.JvmLibrarySpec"/> under the <literal>components</literal>
+ element of the <literal>model</literal>:
+ </para>
+ <sample id="newJavaQuickstart" dir="newJavaPlugin/quickstart" title="Creating a source set">
+ <sourcefile file="build.gradle" snippet="single-lib"/>
+ <output args='build' ignoreExtraLines="true"/>
+ </sample>
+ <para>This example creates a library named <literal>main</literal>, which will implicitly create a <apilink class="org.gradle.language.java.JavaSourceSet"/>
+ named <literal>java</literal>.
+ Therefore the new Java plugin follows the conventions of the <link linkend="java_plugin">legacy Java plugin</link>, and Java sources
+ are expected to be found in <filename>src/main/java</filename>,
+ while resources are expected to be found in <filename>src/main/resources</filename>.
+ </para>
+ </section>
+
+ <section>
+ <title>Source Sets</title>
+ <para>Source sets represent logical groupings of source files in a library. A library can define multiple source sets and all
+ sources will be compiled and included in the resulting binaries. When a library is added to a build, the following
+ source sets are added by default.</para>
+ <table>
+ <title>Java plugin - default source sets</title>
+ <thead>
+ <tr>
+ <td>Source Set</td>
+ <td>Type</td>
+ <td>Directory</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>java</td>
+ <td><apilink class="org.gradle.language.java.JavaSourceSet"/></td>
+ <td>src/${library.name}/java</td>
+ </tr>
+ <tr>
+ <td>resources</td>
+ <td><apilink class="org.gradle.language.jvm.JvmResourceSet"/></td>
+ <td>src/${library.name}/resources</td>
+ </tr>
+ </table>
+ <para>It is possible to configure an existing <firstterm>source set</firstterm>
+ through the <literal>sources</literal> container:
+ </para>
+ <sample id="newJavaQuickstart" dir="newJavaPlugin/quickstart" title="Configuring a source set">
+ <sourcefile file="build.gradle" snippet="configure-sourceset"/>
+ </sample>
+ <para>It is also possible to create an additional source set, using the
+ <apilink class="org.gradle.language.java.JavaSourceSet"/>
+ type:
+ </para>
+ <sample id="newJavaQuickstart" dir="newJavaPlugin/quickstart" title="Creating a new source set">
+ <sourcefile file="build.gradle" snippet="new-sourceset"/>
+ </sample>
+ </section>
+
+ <section>
+ <title>Tasks</title>
+ <para>By default, when the plugins above are applied, no new tasks are added to the build. However, when libraries are defined,
+ conventional tasks are added which build and package each binary of the library.</para>
+
+ <para>For each binary of a library, a single lifecycle task is created which executes all tasks associated with building the binary.
+ To build all binaries, the standard <userinput>build</userinput> lifecycle task can be used.</para>
+ <table id="java_lifecycle_tasks">
+ <title>Java plugin - lifecycle tasks</title>
+ <thead>
+ <tr>
+ <td>Component Type</td>
+ <td>Binary Type</td>
+ <td>Lifecycle Task</td>
+ </tr>
+ </thead>
+ <tr>
+ <td><apilink class="org.gradle.jvm.JvmLibrarySpec"/></td>
+ <td><apilink class="org.gradle.jvm.JvmBinarySpec"/></td>
+ <td>${binary.name}</td>
+ </tr>
+ </table>
+
+ <para>For each source set added to a library, tasks are added to compile or process the source files for each binary.</para>
+ <table id="java_sourceset_tasks">
+ <title>Java plugin - source set tasks</title>
+ <thead>
+ <tr>
+ <td>Source Set Type</td>
+ <td>Task name</td>
+ <td>Type</td>
+ <td>Description</td>
+ </tr>
+ </thead>
+ <tr>
+ <td><apilink class="org.gradle.language.java.JavaSourceSet"/></td>
+ <td>compile${binary.name}${library.name}${sourceset.name}</td>
+ <td><apilink class="org.gradle.language.java.tasks.PlatformJavaCompile" /></td>
+ <td>Compiles the sources of a given source set.</td>
+ </tr>
+ <tr>
+ <td><apilink class="org.gradle.language.jvm.JvmResourceSet"/></td>
+ <td>process${binary.name}${library.name}${sourceset.name}</td>
+ <td><apilink class="org.gradle.language.jvm.tasks.ProcessResources" /></td>
+ <td>Copies the resources in the given source set to the classes output directory.</td>
+ </tr>
+ </table>
+
+ <para>For each binary in a library, a packaging task is added to create the jar for that binary.</para>
+ <table id="java_packaging_tasks">
+ <title>Java plugin - packaging tasks</title>
+ <thead>
+ <tr>
+ <td>Binary Type</td>
+ <td>Task name</td>
+ <td>Depends on</td>
+ <td>Type</td>
+ <td>Description</td>
+ </tr>
+ </thead>
+ <tr>
+ <td><apilink class="org.gradle.jvm.JvmBinarySpec"/></td>
+ <td>create${binary.name}</td>
+ <td>all <apilink class="org.gradle.language.java.tasks.PlatformJavaCompile" /> and <apilink class="org.gradle.language.jvm.tasks.ProcessResources" />
+ tasks associated with the binary</td>
+ <td><apilink class="org.gradle.jvm.tasks.Jar" /></td>
+ <td>Packages the compiled classes and processed resources of the binary.</td>
+ </tr>
+ </table>
+ </section>
+
+ <section>
+ <title>Finding out more about your project</title>
+ <para>
+ Gradle provides a report that you can run from the command-line that shows details about the components and binaries that your
+ project produces. To use this report, just run <userinput>gradle components</userinput>. Below is an example of running this report for
+ one of the sample projects:
+ </para>
+ <sample id="newJavaComponentReport" dir="newJavaPlugin/quickstart" title="The components report">
+ <output args='components'/>
+ </sample>
+ </section>
+
+ <section>
+ <title>Dependencies between components</title>
+ <para>The new Java plugin supports API dependencies between components. Having an API dependency means that if
+ <literal>A</literal> depends on <literal>B</literal>, then the API of <literal>B</literal>
+ is required to compile <literal>A</literal>. Gradle will then
+ make sure that the dependency is built before the dependent component, and that the dependency
+ appears on the <firstterm>compile classpath</firstterm>.
+ API dependencies are (by nature) not transitive. Runtime (transitive) dependency management is not implemented yet.
+ </para>
+ <para>Currently the plugin supports two kinds of dependencies:
+ <itemizedlist>
+ <listitem>API dependencies onto a local project</listitem>
+ <listitem>API dependencies onto a local library</listitem>
+ </itemizedlist>
+ Dependencies onto external components are not yet supported.
+ </para>
+ <para>Dependencies are declared on a <apilink class="org.gradle.api.tasks.SourceSet">source set</apilink>:</para>
+ <sample id="newJavaMultiComponents" dir="newJavaPlugin/multiplecomponents" title="Declaring a dependency onto a library">
+ <sourcefile file="build.gradle" snippet="simple-dependency"/>
+ <output args="serverJar" outputFile="newJavaMultiComponents-serverJar.out" ignoreExtraLines="true"/>
+ </sample>
+ <para>This example declares an API dependency for the <literal>java</literal> source set of the <literal>server</literal> library
+ onto the <literal>core</literal> library of the same project. However, it is possible for a library to depend on a library in a different
+ project as well:</para>
+ <sample id="newJavaMultiComponents" dir="newJavaPlugin/multiplecomponents" title="Declaring a dependency onto a project with an explicit library">
+ <sourcefile file="build.gradle" snippet="dependency-other-project"/>
+ <output args="clientJar" outputFile="newJavaMultiComponents-clientJar.out" ignoreExtraLines="true"/>
+ </sample>
+ <para>When the target project only defines a single library, the <literal>library</literal> selector can be omitted
+ altogether:</para>
+ <sample id="newJavaMultiComponents" dir="newJavaPlugin/multiplecomponents" title="Declaring a dependency onto a project with an implicit library">
+ <sourcefile file="build.gradle" snippet="dependency-other-project-implicit-lib"/>
+ </sample>
+ <para>The <apilink class="org.gradle.platform.base.DependencySpecContainer"/> class provides a complete reference of the dependencies DSL.</para>
+ </section>
+
+ <section>
+ <title>Platform aware dependency management</title>
+ <section>
+ <title>Specifying the target platform</title>
+ <para>The software model extracts the target platform as a core concept. In the Java world, this means that a library can be built, or resolved,
+ against a specific version of Java. For example, if you compile a library for Java 5, we know that such a library can be consumed by a library
+ built for Java 6, but the opposite is not true. Gradle lets you define which platforms a library targets, and will take care of:</para>
+ <para>
+ <itemizedlist>
+ <listitem>generating a binary for each target platform (eg, a Java 5 jar as well as a Java 6 jar)</listitem>
+ <listitem>resolving dependencies against a matching platform</listitem>
+ </itemizedlist>
+ </para>
+ <para>The <literal>targetPlatform</literal> DSL defines which platforms a library should be built against:</para>
+ <sample id="newJavaTargetPlatforms" dir="newJavaPlugin/targetplatforms" title="Declaring target platforms">
+ <sourcefile file="core/build.gradle" snippet="declare-target-platforms"/>
+ <output args=":core:build" ignoreExtraLines="true"/>
+ </sample>
+ <para>When building the application, Gradle generates two binaries: <literal>java5MainJar</literal> and <literal>java6MainJar</literal>
+ corresponding to the target versions of Java. These artifacts will participate in dependency resolution as described
+ <link linkend="java_dependency_resolution">here</link>.</para>
+ </section>
+ <section>
+ <title>Binary specific source sets</title>
+ <para>For each <apilink class="org.gradle.jvm.JvmLibrarySpec"/> it is possible to define additional source sets for each binary. A common use case for this
+ is having specific dependencies for each variant and source sets that conform to those dependencies. The example below configures a <literal>java6</literal> source set on the <literal>java6MainJar</literal>
+ binary:</para>
+ <sample id="newJavaTargetPlatforms" dir="newJavaPlugin/targetplatforms" title="Declaring binary specific sources">
+ <sourcefile file="core/build.gradle" snippet="binary-specific-sourceset"/>
+ <output args=":core:java6MainJar" ignoreExtraLines="true" outputFile="newJavaTargetPlatforms-java6MainJar.out"/>
+ </sample>
+ </section>
+ <section id="java_dependency_resolution">
+ <title>Dependency resolution</title>
+ <para>When a library targets multiple versions of Java and depends on another library, Gradle will make its best effort to
+ resolve the dependency to the most appropriate version of the dependency library. In practice, this means that Gradle chooses
+ the <emphasis>highest compatible</emphasis> version:</para>
+ <para>
+ <itemizedlist>
+ <listitem>for a binary <literal>B</literal> built for Java <literal>n</literal></listitem>
+ <listitem>for a dependency binary <literal>D</literal> built for Java <literal>m</literal></listitem>
+ <listitem><literal>D</literal> is compatible with <literal>B</literal> if <literal>m<=n</literal></listitem>
+ <listitem>for multiple compatible binaries <literal>D(java 5), D(java 6), ...D(java m)</literal>, choose the compatible D binary with the highest Java version</listitem>
+ </itemizedlist>
+ </para>
+ <sample id="newJavaTargetPlatforms" dir="newJavaPlugin/targetplatforms" title="Declaring target platforms">
+ <sourcefile file="server/build.gradle" snippet="dependency-with-platform"/>
+ <output args=":server:build" ignoreExtraLines="true" outputFile="newJavaTargetPlatforms-server.out"/>
+ </sample>
+ <para>In the example above, Gradle automatically chooses the Java 6 variant of the dependency for the Java 6 variant of the <literal>server</literal> component,
+ and chooses the Java 5 version of the dependency for the Java 5 variant of the <literal>server</literal> component.
+ </para>
+ </section>
+ </section>
+ <section>
+ <title>Custom variant resolution</title>
+ <para>The Java plugin, in addition to the target platform resolution, supports resolution of custom variants. Custom variants
+ can be defined on custom binary types, as long as they extends <apilink class="org.gradle.jvm.JarBinarySpec"/>. Users interested
+ in testing this incubating feature can check out the documentation of the <apilink class="org.gradle.platform.base.Variant"/>
+ annotation.</para>
+ </section>
+</chapter>
diff --git a/subprojects/docs/src/docs/userguide/newModel.xml b/subprojects/docs/src/docs/userguide/newModel.xml
index 1d28290..1196c1f 100644
--- a/subprojects/docs/src/docs/userguide/newModel.xml
+++ b/subprojects/docs/src/docs/userguide/newModel.xml
@@ -15,19 +15,26 @@
-->
<chapter id='new_model'>
<title>Rule based model configuration</title>
+ <note>
+ <para>
+ Support for rule based configuration is currently <link linkend="feature_lifecycle">incubating</link>. Please be aware that the DSL, APIs and other configuration may change in later Gradle versions.
+ </para>
+ </note>
<para>
- This chapter describes and documents what is essentially the foundation for the Gradle 3.0 and the next generation of Gradle builds.
- It is being incrementally developed during the Gradle 2.x stream and is in use for <link linkend="nativeBinaries">Gradle's support for building native binaries</link>.
+ This chapter describes and documents what is essentially the foundation for Gradle 3.0 and the next generation of Gradle builds.
+ It is being incrementally developed during the Gradle 2.x stream. Gradle's support for building <link linkend="nativeBinaries">native applications</link> and
+ <link linkend="play_plugin">Play Framework applications</link> already uses this configuration model.
+ Gradle also includes some initial support for building <link linkend="new_java_plugin">Java libraries</link> using this configuration model.
</para>
<para>
- All of the mechanisms, DSL, API, and techniques discussed here are <emphasis>incubating</emphasis> (i.e. not considered stable and subject to change - see <xref linkend="feature_lifecycle"/>).
+ All of the mechanisms, DSL, API, and techniques discussed here are <emphasis>incubating</emphasis> and are not considered stable and subject to change - see <xref linkend="feature_lifecycle"/>).
Exposing new features early, during incubation, allows early testing and the incorporation of real world feedback ultimately resulting in a better Gradle.
</para>
<para>
The following build script is an example of a rule based build.
</para>
<sample id='basicRuleSourcePlugin-all' dir='modelRules/basicRuleSourcePlugin' includeLocation="true" title='an example of a simple rule based build'>
- <sourcefile file='build.gradle' />
+ <sourcefile file='build.gradle' snippet="managed-type-plugin-and-dsl"/>
<output args='hello'/>
</sample>
<para>
@@ -56,7 +63,7 @@
<para>
Domain modelling in Gradle is not new.
The Java plugin's <apilink class="org.gradle.api.tasks.SourceSet" /> concept is an example of domain modelling,
- as is the modelling of <apilink class="org.gradle.nativeplatform.NativeBinary"/> in the Native plugin suite.
+ as is the modelling of <apilink class="org.gradle.nativeplatform.NativeBinary"/> in the native plugin suite.
</para>
<para>
One distinguishing characteristic of Gradle compared to other build tools that also embrace modelling is that Gradle's model is open and collaborative.
@@ -158,12 +165,118 @@
<para>
A “managed” object is transparent and enforces immutability once realized.
Being transparent means that its structure is understood by the rule infrastructure and as such each of its properties are also individual elements in the model space.
- Please see the <apilink class="org.gradle.model.Managed" /> annotation for more information on creating managed model objects.
</para>
<para>
An “unmanaged” object is opaque to the the model space and does not enforce immutability.
Over time, more mechanisms will be available for defining managed model elements culminating in all model elements being managed in some way.
</para>
+ <para>Managed models can be defined by attaching the <literal>@Managed</literal> annotation to an interface:</para>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="a managed type">
+ <sourcefile file='build.gradle' snippet='managed-type'/>
+ </sample>
+ <para>By defining a couple of getter/setter, you are effectively declaring a managed property. A managed property is a property for which Gradle
+ will enforce semantics such as immutability when a node of the model is not the subject of a rule. Therefore, this example declares a property
+ named <emphasis>name</emphasis> on the managed type <emphasis>Person</emphasis>. This property will only be writeable when the view is mutable,
+ that is to say when the <emphasis>Person</emphasis> is the subject of a <literal>Rule</literal> (see below the explanation for rules).</para>
+ <para>Properties can be of any primitive type (e.g. <literal>int</literal>), boxed type (e.g <literal>Integer</literal>), <literal>String</literal>,
+ <literal>File</literal> or enumeration. In addition, properties can also be of any type which is itself managed:</para>
+ <table>
+ <thead>
+ <td>Property type</td><td>Nullable</td><td>Example</td>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <literal>String</literal>
+ </td>
+ <td>Yes</td>
+ <td>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="a String property" >
+ <sourcefile file='build.gradle' snippet='property-type-string'/>
+ </sample>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <literal>File</literal>
+ </td>
+ <td>Yes</td>
+ <td>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="a File property" >
+ <sourcefile file='build.gradle' snippet='property-type-file'/>
+ </sample>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <literal>Integer</literal>, <literal>Boolean</literal>, <literal>Byte</literal>, <literal>Short</literal>,
+ <literal>Float</literal>, <literal>Long</literal>, <literal>Double</literal>
+ </td>
+ <td>Yes</td>
+ <td>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="a Long property" >
+ <sourcefile file='build.gradle' snippet='property-type-long'/>
+ </sample>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <literal>int</literal>, <literal>boolean</literal>, <literal>byte</literal>, <literal>short</literal>,
+ <literal>float</literal>, <literal>long</literal>, <literal>double</literal>
+ </td>
+ <td>No</td>
+ <td>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="a boolean property">
+ <sourcefile file='build.gradle' snippet='property-type-boolean'/>
+ </sample>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="an int property" >
+ <sourcefile file='build.gradle' snippet='property-type-int'/>
+ </sample>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Another <emphasis>managed</emphasis> type.
+ </td>
+ <td>Only if read/write</td>
+ <td>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="a managed property">
+ <sourcefile file='build.gradle' snippet='property-type-managed'/>
+ </sample>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ An <emphasis>enumeration</emphasis> type.
+ </td>
+ <td>Yes</td>
+ <td>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="an enumeration type property">
+ <sourcefile file='build.gradle' snippet='property-type-enum'/>
+ </sample>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ A <literal>ManagedSet</literal>.
+ </td>
+ <td>Only if read/write</td>
+ <td>
+ <sample id='basicRuleSourcePlugin' dir='modelRules/basicRuleSourcePlugin' title="a managed set">
+ <sourcefile file='build.gradle' snippet='property-type-managedset'/>
+ </sample>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <para>If the type of a property is itself a managed type, it is possible to declare only a getter, in which case you are declaring a
+ read-only property. A read-only property must not be mistaken with an immutable property. A read-only property will be instantiated by Gradle,
+ and cannot be replaced with another object of the same type (for example calling a setter). However, the properties of that property can potentially
+ be changed, if, and only if, the property is the subject of a rule. If it's not the case, the property is immutable, like any classic
+ read/write managed property.</para>
+ <para>Managed types can be defined out of interfaces or abstract classes and are usually defined in plugins, which are written either in Java or Groovy.
+ Please see the <apilink class="org.gradle.model.Managed" /> annotation
+ for more information on creating managed model objects.</para>
</section>
<section>
<title>References, binding and scopes</title>
@@ -327,17 +440,42 @@ model {
<section>
<title>The model report</title>
<para>
- The built-in <link>model</link> task displays the model space as a tree.
- It can be used to see what the potential elements to bind to are.
+ The built-in <apilink class="org.gradle.api.reporting.model.ModelReport"/> task displays a hierarchical view of the elements in the model space.
+ Each item prefixed with a `+`, excluding the topmost `+ model`, on the model report is a model element and the visual nesting of these elements correlates to the model
+ path (e.g. `tasks.help`). The model report displays the following details about each model element:
</para>
+
+ <table>
+ <title>Model report - model element details</title>
+ <thead>
+ <td>Detail</td>
+ <td>Description</td>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Type</td>
+ <td>This is the underlying type of the model element and is typically a fully qualified class name.</td>
+ </tr>
+ <tr>
+ <td>Value</td>
+ <td>Is conditionally displayed on the report when a model element can be represented as a string.</td>
+ </tr>
+ <tr>
+ <td>Creator</td>
+ <td>Every model element has a creator. A creator signifies the origin of the model element (i.e. what created the model element).</td>
+ </tr>
+ <tr>
+ <td>Rules</td>
+ <td>Is a listing of the rules, excluding the creator rule, which are executed for a given model element. The order in which the rules are displayed reflects
+ the order in which they are executed.
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
<sample id='basicRuleSourcePlugin-model-task' dir='modelRules/basicRuleSourcePlugin' title='model task output'>
<output args='model' ignoreExtraLines="true"/>
</sample>
- <para>
- Currently the report only shows the structure of the model space.
- In future Gradle versions it will also display the types and values of the nodes.
- Future versions will also provide richer and more interactive ways of exploring the model space.
- </para>
</section>
<section>
<title>Limitations and future direction</title>
diff --git a/subprojects/docs/src/docs/userguide/organizeBuildLogic.xml b/subprojects/docs/src/docs/userguide/organizeBuildLogic.xml
index bd85722..204b94f 100644
--- a/subprojects/docs/src/docs/userguide/organizeBuildLogic.xml
+++ b/subprojects/docs/src/docs/userguide/organizeBuildLogic.xml
@@ -189,8 +189,8 @@
<output args="-q encode"/>
</sample>
<para>
- For multi-project builds, the dependencies declared in the a project's build script, are available to the
- build scripts of all sub-projects.
+ For multi-project builds, the dependencies declared with a project's <literal>buildscript()</literal> method
+ are available to the build scripts of all its sub-projects.
</para>
</section>
diff --git a/subprojects/docs/src/docs/userguide/playPlugin.xml b/subprojects/docs/src/docs/userguide/playPlugin.xml
new file mode 100644
index 0000000..58a10c2
--- /dev/null
+++ b/subprojects/docs/src/docs/userguide/playPlugin.xml
@@ -0,0 +1,560 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<chapter id='play_plugin' xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>The Play Plugin</title>
+ <note>
+ <para>
+ Support for building Play applications is currently <link linkend="feature_lifecycle">incubating</link>. Please be aware that the DSL, APIs and other configuration may change in later Gradle versions.
+ </para>
+ </note>
+
+ <para>
+ <ulink url="https://www.playframework.com/">Play</ulink> is a modern web application framework.
+ The Play plugin adds support for building, testing and running Play applications with Gradle.
+ </para>
+
+ <section>
+ <title>Usage</title>
+ <para>To use the Play plugin, include the following in your build script to apply the <literal>play</literal> plugin and add the Typesafe repositories:</para>
+ <sample id="usePlayPlugin" dir="play/basic" title="Using the Play plugin">
+ <sourcefile file="build.gradle" snippet="use-plugin"/>
+ </sample>
+ <para>Note that defining the Typesafe repositories is necessary. In future versions of Gradle, this will be replaced with a more convenient syntax.</para>
+ </section>
+
+ <section>
+ <title>Limitations</title>
+ <para>The Play plugin currently has a few limitations.</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Full support is limited to Play 2.3.x applications.
+ Limited support is available for Play 2.4.x applications. Gradle does not include support for a few new build-related features in 2.4.
+ Specifically, Gradle does not yet support aggregate reverse routes.
+ Future Gradle versions will add more support for Play 2.4.x and 3.0.x.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A given project may only define a single Play application. This means that a single project cannot build more than one Play application.
+ However, a multi-project build can have many projects that each define their own Play application.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Play applications can only target a single “platform” (combination of Play, Scala and Java version) at a time. This means that it is
+ currently not possible to define multiple variants of a Play application that, for example, produce jars for both Scala 2.10 and 2.11.
+ This limitation may be lifted in future Gradle versions.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Software Model</title>
+
+ <para>
+ The Play plugin uses a <emphasis>software model</emphasis> to describe a Play application. The software model is comprised of
+ "components" and "binaries". Components are abstract software elements that are built to produce binaries and
+ a Play application is represented by a <apilink class="org.gradle.play.PlayApplicationSpec"/> component type. The plugin automatically
+ creates a single <apilink class="org.gradle.play.PlayApplicationBinarySpec"/> when it is applied. Additional Play components
+ cannot be added.
+ </para>
+
+ <figure>
+ <title>Play plugin - software model</title>
+ <imageobject>
+ <imagedata fileref="img/playPluginModel.png"/>
+ </imageobject>
+ </figure>
+
+ <section>
+ <title>The Play application component</title>
+ <para>
+ A Play application component describes the application to be built and consists of several configuration elements. One type of element that
+ describes the application are the source sets that define where the application controller, route, template and model class source
+ files should be found. These source sets are logical groupings of files of a particular type and a default source set for each type is
+ created when the <literal>play</literal> plugin is applied.
+ </para>
+ <table>
+ <title>Default Play source sets</title>
+ <thead>
+ <tr>
+ <td>Source Set</td>
+ <td>Type</td>
+ <td>Directory</td>
+ <td>Filters</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>java</td>
+ <td><apilink class="org.gradle.language.java.JavaSourceSet"/></td>
+ <td>app</td>
+ <td>**/*.java</td>
+ </tr>
+ <tr>
+ <td>scala</td>
+ <td><apilink class="org.gradle.language.scala.ScalaLanguageSourceSet"/></td>
+ <td>app</td>
+ <td>**/*.scala</td>
+ </tr>
+ <tr>
+ <td>routes</td>
+ <td><apilink class="org.gradle.language.routes.RoutesSourceSet"/></td>
+ <td>conf</td>
+ <td>routes, *.routes</td>
+ </tr>
+ <tr>
+ <td>twirlTemplates</td>
+ <td><apilink class="org.gradle.language.twirl.TwirlSourceSet"/></td>
+ <td>app</td>
+ <td>**/*.html</td>
+ </tr>
+ <tr>
+ <td>javaScript</td>
+ <td><apilink class="org.gradle.language.javascript.JavaScriptSourceSet"/></td>
+ <td>app/assets</td>
+ <td>**/*.js</td>
+ </tr>
+ </table>
+ <para>
+ These source sets can be configured or additional source sets can be added to the Play component. See <link linkend="configuring_play">Configuring Play</link> for further information.
+ </para>
+ <para>
+ Another element of configuring a Play application is the <literal>platform</literal>. To build a Play application, Gradle needs to understand which versions of Play, Scala and Java to use.
+ The Play component specifies this requirement as a <apilink class="org.gradle.play.platform.PlayPlatform"/>. If these values are not configured, a default version of Play, Scala and Java
+ will be used. See <link linkend="configuring_play_platform">Targeting a certain version of Play</link> for information on configuring the Play platform.
+ </para>
+ <para>
+ Note that only a single platform can be specified for a given Play component. This means that only a single version of
+ Play, Scala and Java can be used to build a Play component. In other words, a Play component can only produce one set of outputs, and
+ those outputs will be built using the versions specified by the platform configured on the component.
+ </para>
+ </section>
+ <section>
+ <title>The Play application binary</title>
+ <para>
+ A Play application component is compiled and packaged to produce a set of outputs which are represented by a <apilink class="org.gradle.play.PlayApplicationBinarySpec"/>.
+ The Play binary specifies the jar files produced by building the component as well as providing elements by which additional content can be added to those jar files.
+ It also exposes the tasks involved in building the component and creating the binary.
+ </para>
+ <para>
+ See <link linkend="configuring_play">Configuring Play</link> for examples of configuring the Play binary.
+ </para>
+ </section>
+ </section>
+
+ <section>
+ <title>Project Layout</title>
+ <para>The Play plugin follows the typical Play application layout. You can <link linkend="configuring_play_sourcesets">configure source sets</link> to include additional directories or change the defaults.</para>
+ <screen>
+ ├── app <lineannotation>→ Application source code.</lineannotation>
+ │ ├── assets <lineannotation>→ Assets that require compilation.</lineannotation>
+ │ │ └── javascripts <lineannotation>→ JavaScript source code to be minified.</lineannotation>
+ │ ├── controllers <lineannotation>→ Application controller source code.</lineannotation>
+ │ ├── models <lineannotation>→ Application business source code.</lineannotation>
+ │ └── views <lineannotation>→ Application UI templates.</lineannotation>
+ ├── build.gradle <lineannotation>→ Your project's build script.</lineannotation>
+ ├── conf <lineannotation>→ Main application configuration file and routes files.</lineannotation>
+ ├── public <lineannotation>→ Public assets.</lineannotation>
+ │ ├── images <lineannotation>→ Application image files.</lineannotation>
+ │ ├── javascripts <lineannotation>→ Typically JavaScript source code.</lineannotation>
+ │ └── stylesheets <lineannotation>→ Typically CSS source code.</lineannotation>
+ └── test <lineannotation>→ Test source code.</lineannotation>
+ </screen>
+ </section>
+
+ <section>
+ <title>Tasks</title>
+
+ <para>The Play plugin hooks into the normal Gradle lifecycle tasks such as <literal>assemble</literal>, <literal>check</literal> and <literal>build</literal>,
+ but it also adds several additional tasks which form the lifecycle of a Play project:</para>
+
+ <table id="play_lifecycle_tasks">
+ <title>Play plugin - lifecycle tasks</title>
+ <thead>
+ <tr>
+ <td>Task name</td>
+ <td>Depends on</td>
+ <td>Type</td>
+ <td>Description</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>
+ <literal>playBinary</literal>
+ </td>
+ <td>
+ All compile tasks for source sets added to the Play application.
+ </td>
+ <td><apilink class="org.gradle.api.Task"/></td>
+ <td>Performs a build of just the Play application.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>dist</literal>
+ </td>
+ <td>
+ <literal>createPlayBinaryDist</literal>
+ </td>
+ <td><apilink class="org.gradle.api.Task"/></td>
+ <td>Assembles the Play distribution.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>stage</literal>
+ </td>
+ <td>
+ <literal>stagePlayBinaryDist</literal>
+ </td>
+ <td><apilink class="org.gradle.api.Task"/></td>
+ <td>Stages the Play distribution.</td>
+ </tr>
+ </table>
+ <para>The plugin also provides tasks for running, testing and packaging your Play application:</para>
+ <table>
+ <title>Play plugin - running and testing tasks</title>
+ <thead>
+ <tr>
+ <td>Task name</td>
+ <td>Depends on</td>
+ <td>Type</td>
+ <td>Description</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>
+ <literal>runPlayBinary</literal>
+ </td>
+ <td>
+ <literal>playBinary</literal> to build Play application.
+ </td>
+ <td><apilink class="org.gradle.play.tasks.PlayRun"/></td>
+ <td>Runs the Play application for local development. See <link linkend="play_continuous_build">how this works with continuous build.</link></td>
+ </tr>
+ <tr>
+ <td>
+ <literal>testPlayBinary</literal>
+ </td>
+ <td>
+ <literal>playBinary</literal> to build Play application and <literal>compilePlayBinaryTests</literal>.
+ </td>
+ <td><apilink class="org.gradle.api.tasks.testing.Test"/></td>
+ <td>Runs JUnit/TestNG tests for the Play application.</td>
+ </tr>
+ </table>
+ <para>For the different types of sources in a Play application, the plugin adds the following compilation tasks:</para>
+ <table id="play_source_set_tasks">
+ <title>Play plugin - source set tasks</title>
+ <thead>
+ <tr>
+ <td>Task name</td>
+ <td>Source Type</td>
+ <td>Type</td>
+ <td>Description</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>
+ <literal>compilePlayBinaryScala</literal>
+ </td>
+ <td>
+ Scala and Java
+ </td>
+ <td><apilink class="org.gradle.language.scala.tasks.PlatformScalaCompile"/></td>
+ <td>Compiles all Scala and Java sources defined by the Play application.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>compilePlayBinaryTwirlTemplates</literal>
+ </td>
+ <td>
+ Twirl HTML templates
+ </td>
+ <td><apilink class="org.gradle.play.tasks.TwirlCompile"/></td>
+ <td>Compiles HTML templates with the Twirl compiler.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>compilePlayBinaryRoutes</literal>
+ </td>
+ <td>
+ Play Route files
+ </td>
+ <td><apilink class="org.gradle.play.tasks.RoutesCompile"/></td>
+ <td>Compiles routes files into Scala sources.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>minifyPlayBinaryJavaScript</literal>
+ </td>
+ <td>
+ JavaScript files
+ </td>
+ <td><apilink class="org.gradle.play.tasks.JavaScriptMinify"/></td>
+ <td>Minifies JavaScript files with the Google Closure compiler.</td>
+ </tr>
+ </table>
+ </section>
+
+ <section>
+ <title>Finding out more about your project</title>
+ <para>
+ Gradle provides a report that you can run from the command-line that shows some details about the components and binaries that your
+ project produces. To use this report, just run <userinput>gradle components</userinput>. Below is an example of running this report for
+ one of the sample projects:
+ </para>
+ <sample id="playComponentReport" dir="play/basic" title="The components report">
+ <output args='components'/>
+ </sample>
+ </section>
+
+ <section id="play_continuous_build">
+ <title>Running a Play application</title>
+ <para>
+ The <literal>runPlayBinary</literal> task starts the Play application under development.
+ During development it is beneficial to execute this task as a <link linkend="continuous_build">continuous build</link>.
+ Continuous build is a generic feature that supports automatically re-running a build when inputs change.
+ The <literal>runPlayBinary</literal> task is “continuous build aware” in that it behaves differently when run as part of a continuous build.
+ </para>
+ <para>
+ When not run as part of a continuous build, the <literal>runPlayBinary</literal> task will <emphasis>block</emphasis> the build.
+ That is, the task will not complete as long as the application is running.
+ When running as part of a continuous build, the task will start the application if not running and otherwise propagate any changes to the code of the application to the running instance.
+ This is useful for quickly iterating on your Play application with an edit->rebuild->refresh cycle. Changes to your application will not take affect until the end of the overall build.
+ </para>
+ <para>
+ To enable continuous build, run Gradle with <userinput>-t runPlayBinary</userinput> or <userinput>--continuous runPlayBinary</userinput>.
+ </para>
+ <para>
+ Users of Play used to such a workflow with Play's default build system should note that compile errors are handled differently.
+ If a build failure occurs during a continuous build, the Play application will not be reloaded. Instead, you will be presented with an exception
+ message. The exception message will only contain the overall cause of the build failure.
+ More detailed information will only be available from the console.
+ </para>
+ </section>
+
+ <section id="configuring_play">
+ <title>Configuring a Play application</title>
+ <section id="configuring_play_platform">
+ <title>Targeting a certain version of Play</title>
+ <para>
+ By default, Gradle uses Play 2.3.9, Scala 2.11 and the version of Java used to start the build.
+ A Play application can select a different version by specifying a target <apilink class="org.gradle.play.PlayApplicationSpec" method="platform">platform</apilink> on the Play application component.
+ </para>
+ <sample id="specifyPlayVersion" dir="play/advanced" title="Selecting a version of the Play Framework">
+ <sourcefile file="build.gradle" snippet="play-platform"/>
+ </sample>
+ </section>
+ <section>
+ <title>Adding dependencies</title>
+ <para>
+ You can add compile, test and runtime dependencies to a Play application through <apilink class="org.gradle.api.artifacts.Configuration">Configurations</apilink> created by the Play plugin.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>play</literal> is used for compile time dependencies.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>playTest</literal> is used for test compile time dependencies.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>playRun</literal> is used for run time dependencies.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <sample id="addPlayDependencies" dir="play/advanced" title="Adding dependencies to a Play application">
+ <sourcefile file="build.gradle" snippet="play-dependencies"/>
+ </sample>
+ </section>
+
+ <section id="configuring_play_sourcesets">
+ <title>Configuring the default source sets</title>
+ <para>You can further configure the default source sets to do things like add new directories, add filters, etc.</para>
+ <sample id="addExtraPlaySourcesets" dir="play/sourcesets" title="Adding extra source sets to a Play application">
+ <sourcefile file="build.gradle" snippet="default-sourcesets"/>
+ </sample>
+ </section>
+ <section>
+ <title>Adding extra source sets</title>
+ <para>
+ If your Play application has additional sources that exist in non-standard directories, you can add extra source sets that Gradle will automatically add to the appropriate compile tasks.
+ </para>
+ <sample id="addExtraPlaySourcesets" dir="play/sourcesets" title="Adding extra source sets to a Play application">
+ <sourcefile file="build.gradle" snippet="play-extra-sourcesets"/>
+ </sample>
+ </section>
+ <section>
+ <title>Configuring compiler options</title>
+ <para>
+ If your Play application requires additional Scala compiler flags, you can add these arguments directly to the Scala compiler task.
+ </para>
+ <sample id="configureScalaCompiler" dir="play/configure-compiler" title="Configuring Scala compiler options">
+ <sourcefile file="build.gradle" snippet="play-configure-compiler"/>
+ </sample>
+ </section>
+ <section>
+ <title>Configuring routes style</title>
+ <note>
+ The injected router is only supported in Play Framework 2.4 or better.
+ </note>
+ <para>
+ If your Play application's router uses dependency injection to access your controllers, you'll need to configure your application to <emphasis>not</emphasis> use the default static router.
+
+ Under the covers, the Play plugin is using the <literal>InjectedRoutesGenerator</literal> instead of the default <literal>StaticRoutesGenerator</literal> to generate the router classes.
+ </para>
+ <sample id="configureRoutesCompiler" dir="play/play-2.4" title="Configuring routes style">
+ <sourcefile file="build.gradle" snippet="play-injected-routes-compiler"/>
+ </sample>
+ </section>
+ <section>
+ <title>Injecting a custom asset pipeline</title>
+ <para>
+ Gradle Play support comes with a simplistic asset processing pipeline that minifies JavaScript assets. However, many organizations have their own
+ custom pipeline for processing assets. You can easily hook the results of your pipeline into the Play binary by utilizing the <apilink class="org.gradle.play.PublicAssets"/>
+ property on the binary.
+ </para>
+ <sample id="customAssetsPipeline" dir="play/custom-assets" title="Configuring a custom asset pipeline">
+ <sourcefile file="build.gradle" snippet="custom-assets"/>
+ </sample>
+ </section>
+ </section>
+
+ <section>
+ <title>Multi-project Play applications</title>
+ <para>
+ Play applications can be built in multi-project builds as well. Simply apply the <literal>play</literal> plugin in the appropriate subprojects and create any
+ project dependencies on the <literal>play</literal> configuration.
+ </para>
+ <sample id="playMultiProjectDependencies" dir="play/multiproject" title="Configuring dependencies on Play subprojects">
+ <sourcefile file="build.gradle" snippet="play-multiproject-dependencies"/>
+ </sample>
+ <para>
+ See the <filename>play/multiproject</filename> sample provided in the Gradle distribution for a working example.
+ </para>
+ </section>
+ <section>
+ <title>Packaging a Play application for distribution</title>
+ <para>
+ Gradle provides the capability to package your Play application so that it can easily be distributed and run in a target environment.
+ The distribution package (zip file) contains the Play binary jars, all dependencies, and generated scripts that set up the classpath and run
+ the application in a Play-specific <ulink url="http://netty.io">Netty</ulink> container.
+ </para>
+ <para>
+ The distribution can be created by running the <literal>dist</literal> lifecycle task and places the distribution in the <literal>$buildDir/distributions</literal> directory. Alternatively,
+ one can validate the contents by running the <literal>stage</literal> lifecycle task which copies the files to the <literal>$buildDir/stage</literal> directory using the layout of the distribution package.
+ </para>
+ <table>
+ <title>Play distribution tasks</title>
+ <thead>
+ <tr>
+ <td>Task name</td>
+ <td>Depends on</td>
+ <td>Type</td>
+ <td>Description</td>
+ </tr>
+ </thead>
+ <tr>
+ <td>
+ <literal>createPlayBinaryStartScripts</literal>
+ </td>
+ <td>-</td>
+ <td><apilink class="org.gradle.api.tasks.application.CreateStartScripts"/></td>
+ <td>Generates scripts to run the Play application distribution.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>stagePlayBinaryDist</literal>
+ </td>
+ <td>
+ <literal>playBinary</literal>, <literal>createPlayBinaryStartScripts</literal>
+ </td>
+ <td><apilink class="org.gradle.api.tasks.Copy"/></td>
+ <td>Copies all jar files, dependencies and scripts into a staging directory.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>createPlayBinaryDist</literal>
+ </td>
+ <td><literal>stagePlayBinaryDist</literal></td>
+ <td><apilink class="org.gradle.api.tasks.bundling.Zip"/></td>
+ <td>Bundles the Play application as a distribution.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>stage</literal>
+ </td>
+ <td><literal>stagePlayBinaryDist</literal></td>
+ <td><apilink class="org.gradle.api.Task"/></td>
+ <td>Lifecycle task for staging a Play distribution.</td>
+ </tr>
+ <tr>
+ <td>
+ <literal>dist</literal>
+ </td>
+ <td><literal>createPlayBinaryDist</literal></td>
+ <td><apilink class="org.gradle.api.Task"/></td>
+ <td>Lifecycle task for creating a Play distribution.</td>
+ </tr>
+ </table>
+ <section>
+ <title>Adding additional files to your Play application distribution</title>
+ <para>
+ You can add additional files to the distribution package using the <apilink class="org.gradle.api.distribution.Distribution"/> API.
+ </para>
+ <sample id="addFilesToPlayDistribution" dir="play/custom-distribution" title="Add extra files to a Play application distribution">
+ <sourcefile file="build.gradle" snippet="play-custom-distribution"/>
+ </sample>
+ </section>
+ </section>
+
+ <section>
+ <title>Resources</title>
+ <para>
+ For additional information about developing Play applications:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Play types in the Gradle DSL Guide:
+ </para>
+ <itemizedlist>
+ <listitem><apilink class="org.gradle.play.PlayApplicationBinarySpec"/></listitem>
+ <listitem><apilink class="org.gradle.play.PlayApplicationSpec"/></listitem>
+ <listitem><apilink class="org.gradle.play.platform.PlayPlatform"/></listitem>
+ <listitem><apilink class="org.gradle.play.JvmClasses"/></listitem>
+ <listitem><apilink class="org.gradle.play.PublicAssets"/></listitem>
+ <listitem><apilink class="org.gradle.play.distribution.PlayDistributionContainer"/></listitem>
+ <listitem><apilink class="org.gradle.play.tasks.JavaScriptMinify"/></listitem>
+ <listitem><apilink class="org.gradle.play.tasks.PlayRun"/></listitem>
+ <listitem><apilink class="org.gradle.play.tasks.RoutesCompile"/></listitem>
+ <listitem><apilink class="org.gradle.play.tasks.TwirlCompile"/></listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="https://www.playframework.com/documentation">Play Framework Documentation</ulink>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </section>
+</chapter>
diff --git a/subprojects/docs/src/docs/userguide/scalaPlugin.xml b/subprojects/docs/src/docs/userguide/scalaPlugin.xml
index c4df510..0eb855e 100644
--- a/subprojects/docs/src/docs/userguide/scalaPlugin.xml
+++ b/subprojects/docs/src/docs/userguide/scalaPlugin.xml
@@ -209,7 +209,7 @@
<title>Convention properties</title>
<para>The Scala plugin does not add any convention properties to the project.</para>
</section>
-
+
<section>
<title>Source set properties</title>
<para>The Scala plugin adds the following convention properties to each source set in the project. You can
@@ -356,7 +356,8 @@
<para>
The Scala plugin adds a configuration named <literal>zinc</literal> to resolve the Zinc library and its dependencies.
Gradle will have a default version of the Zinc library, but if you want to override the
- Zinc version that Gradle uses, add an explicit dependency like <literal>“com.typesafe.zinc:zinc:0.1.4”</literal>.
+ Zinc version that Gradle uses, add an explicit dependency like <literal>“com.typesafe.zinc:zinc:0.3.6”</literal>. Gradle will support
+ version 0.3.0 of Zinc and above, although due to a regression in the Zinc library, versions 0.3.2 through 0.3.5.2 cannot be used.
Regardless of which Zinc version is used, Zinc will always use the Scala compiler found on the <literal>scalaTools</literal> configuration.
</para>
diff --git a/subprojects/docs/src/docs/userguide/standardPlugins.xml b/subprojects/docs/src/docs/userguide/standardPlugins.xml
index c4562f4..23c6a19 100644
--- a/subprojects/docs/src/docs/userguide/standardPlugins.xml
+++ b/subprojects/docs/src/docs/userguide/standardPlugins.xml
@@ -184,7 +184,7 @@
</link>
</td>
<td>
- <literal>java</literal>
+ <literal>java</literal>, <literal>distribution</literal>
</td>
<td>-</td>
<td>
diff --git a/subprojects/docs/src/docs/userguide/testKit.xml b/subprojects/docs/src/docs/userguide/testKit.xml
new file mode 100644
index 0000000..6a57428
--- /dev/null
+++ b/subprojects/docs/src/docs/userguide/testKit.xml
@@ -0,0 +1,180 @@
+<!--
+ ~ Copyright 2015 the original author or authors.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<chapter id="test_kit">
+ <title>The Gradle TestKit</title>
+ <note>
+ <para>
+ The Gradle TestKit is currently <link linkend="feature_lifecycle">incubating</link>.
+ Please be aware that its API and other characteristics may change in later Gradle versions.
+ </para>
+ </note>
+ <para>
+ The Gradle TestKit (a.k.a. just TestKit) is a library that aids in testing Gradle plugins and build logic generally.
+ At this time, it is focused on
+ <emphasis>functional</emphasis>
+ testing.
+ That is, testing build logic by exercising it as part of a programmatically executed build.
+ Over time, the TestKit will likely expand to facilitate other kinds of tests.
+ </para>
+
+ <section>
+ <title>Usage</title>
+ <para>To use the TestKit, include the following in your plugin's build:</para>
+ <sample id="testKitDependency" dir="testKit/testKitJunit" title="Declaring the TestKit dependency">
+ <sourcefile file="build.gradle" snippet="declare-gradle-testkit-dependency"/>
+ </sample>
+ <para>
+ The
+ <literal>gradleTestKit()</literal>
+ encompasses the classes of the TestKit, as well as the <link linkend="embedding">Gradle Tooling API client</link>.
+ It does not include a version of<ulink url="http://junit.org">JUnit</ulink>,<ulink url="http://testng.org">TestNG</ulink>, or any other test execution framework.
+ Such a dependency must be explicitly declared.
+ </para>
+ <sample id="junitDependency" dir="testKit/testKitJunit" title="Declaring the JUnit dependency">
+ <sourcefile file="build.gradle" snippet="declare-junit-dependency"/>
+ </sample>
+ </section>
+
+ <section>
+ <title>Functionally testing with the Gradle runner</title>
+ <para>
+ The <apilink class="org.gradle.testkit.runner.GradleRunner"/> facilitates programmatically executing Gradle builds, and inspecting the result.
+ </para>
+ <para>
+ A contrived build can be created (e.g. programmatically, or from a template) that exercises the “logic under test”.
+ The build can then be executed, potentially in a variety of ways (e.g. different combinations of tasks and arguments).
+ The correctness of the logic can then be verified by asserting the following, potentially in combination:
+ <itemizedlist>
+ <listitem>The build's output;</listitem>
+ <listitem>The build's logging (i.e. console output);</listitem>
+ <listitem>The set of tasks executed by the build and their results (e.g. FAILED, UP-TO-DATE etc.).</listitem>
+ </itemizedlist>
+ After creating and configuring a runner instance, the build can be executed via the
+ <apilink class="org.gradle.testkit.runner.GradleRunner" method="build"/>
+ or
+ <apilink class="org.gradle.testkit.runner.GradleRunner" method="buildAndFail"/>
+ methods depending on the anticipated outcome.
+ </para>
+ <para>
+ The following demonstrates the usage of Gradle runner in a Java JUnit test:
+ </para>
+ <sample id="testKitFunctionalTestJunit" dir="testKit/testKitJunit/src/test/java/org/gradle/sample" title="Using GradleRunner with JUnit">
+ <sourcefile file="BuildLogicFunctionalTest.java" snippet="functional-test-junit"/>
+ </sample>
+ <para>
+ Any test execution framework can be used.
+ </para>
+ <para>
+ As Gradle build scripts are written in the Groovy programming language, and as many plugins are implemented in Groovy,
+ it is often a productive choice to write Gradle functional tests in Groovy.
+ Furthermore, it is recommended to use the (Groovy based) <ulink url="https://code.google.com/p/spock/">Spock test execution framework</ulink>
+ as it offers many compelling features over the use of JUnit.
+ </para>
+ <para>
+ The following demonstrates the usage of Gradle runner in a Groovy Spock test:
+ </para>
+ <sample id="testKitFunctionalTestSpock" dir="testKit/testKitSpock/src/test/groovy/org/gradle/sample" title="Using GradleRunner with Spock">
+ <sourcefile file="BuildLogicFunctionalTest.groovy" snippet="functional-test-spock"/>
+ </sample>
+ <para>
+ It is a common practice to implement any custom build logic (like plugins and task types) that is more complex in nature as external classes in a standalone project. The main
+ driver behind this approach is bundle the compiled code into a JAR file, publish it to a binary repository and reuse it across various projects.
+ </para>
+ <section>
+ <title>Getting the code under test into the test build</title>
+ <para>
+ The runner uses the <link linkend="embedding">Tooling API</link> to execute builds.
+ An implication of this is that the builds are executed in a separate process (i.e. not the same process executing the tests).
+ Therefore, the test build does not share the same classpath or classloaders as the test process and the code under test is not implicitly available to the test build.
+ </para>
+ <para>
+ At the moment the TestKit does not provide any convenient mechanism to inject the code under test into the test builds.
+ This feature will be added to future versions.
+ </para>
+ <para>
+ In the meantime, it is possible to manually make the code under test available via some extra configuration.
+ The following example demonstrates having the build generate a file denoting the implementation classpath of the code under test, and making it available at test runtime.
+ </para>
+ <sample id="testKitFunctionalTestSpockClassesBuildConfig" dir="testKit/testKitSpockClasspath" includeLocation="true" title="Making the code under test classpath available to the tests">
+ <sourcefile file="plugin/build.gradle" snippet="test-logic-classpath"/>
+ </sample>
+ <para>
+ The tests can then read this value, and inject the classpath into the test build.
+ The following is an example (in Groovy) of doing this from within a Spock Framework <literal>setup()</literal> method, which is analogous to a JUnit <literal>@Before</literal> method.
+ </para>
+ <sample id="testKitFunctionalTestSpockClassesTestConfig" dir="testKit/testKitSpockClasspath" includeLocation="true" title="Injecting the code under test classes into test builds">
+ <sourcefile file="plugin/src/test/groovy/org/gradle/sample/BuildLogicFunctionalTest.groovy" snippet="functional-test-classpath-setup"/>
+ </sample>
+ <para>
+ This approach works well when executing the functional tests as part of the Gradle build.
+ When executing the functional tests from an IDE, there are extra considerations.
+ Namely, the classpath manifest file points to the class files etc. generated by Gradle and not the IDE.
+ This means that after making a change to the source of the code under test, the source must be recompiled by Gradle.
+ Similarly, if the effective classpath of the code under test changes, the manifest must be regenerated.
+ In either case, executing the <literal>testClasses</literal> task of the build will ensure that things are up to date.
+ </para>
+ </section>
+ <section>
+ <title>Controlling the build environment</title>
+ <para>
+ The runner executes the test builds in an isolated environment by specifying a dedicated "working directory" in a directory inside the JVM's temp directory
+ (i.e. the location specified by the <literal>java.io.tmpdir</literal> system property, typically <literal>/tmp</literal>).
+ Any configuration in the default Gradle user home directory (e.g. <literal>~/.gradle/gradle.properties</literal>) is not used for test execution.
+ The TestKit does not expose a mechanism for fine grained control of environment variables etc.
+ Future versions of the TestKit will provide improved configuration options.
+ </para>
+ <para>
+ The TestKit uses dedicated daemon processes that are automatically shut down after test execution.
+ </para>
+ </section>
+ <section>
+ <title>The Gradle version used to test</title>
+ <para>
+ The Gradle runner requires a Gradle distribution in order to execute the build.
+ The TestKit does not depend on all of Gradle's implementation.
+ </para>
+ <para>
+ When a runner is created, it will attempt to find a Gradle distribution based on where the <literal>GradleRunner</literal> class was loaded from.
+ That is, it is expected that the class was loaded from a Gradle distribution, as is the case when using the <literal>gradleTestKit()</literal> dependency declaration.
+ </para>
+ <para>
+ When using the runner as part of tests <emphasis>being executed by Gradle</emphasis> (e.g. executing the <literal>test</literal> task of a plugin project), the same distribution used to execute the tests will be used by the runner.
+ When using the runner as part of tests <emphasis>being executed by an IDE</emphasis>, the same distribution of Gradle that was used when importing the project will be used.
+ This means that the plugin will effectively be tested with the same version of Gradle that it is being built with.
+ </para>
+ <para>
+ If a Gradle distribution cannot be found, creation of the runner instance will fail.
+ </para>
+ <para>
+ Future versions of the TestKit will support more powerful distribution discovery, facilitating cross version testing.
+ </para>
+ </section>
+ <section>
+ <title>Debugging build logic</title>
+ <para>
+ The runner uses the <link linkend="embedding">Tooling API</link> to execute builds.
+ An implication of this is that the builds are executed in a separate process (i.e. not the same process executing the tests).
+ Therefore, executing your <emphasis>tests</emphasis> in debug mode does not allow you to debug your build logic as you may expect.
+ Any breakpoints set in your IDE will be not be tripped by the code being exercised by the test build.
+ </para>
+ <para>
+ At this time, there is no way to effectively debug the build logic under test.
+ This, highly desirable, feature will be available in future versions of the test kit.
+ </para>
+ </section>
+ </section>
+</chapter>
diff --git a/subprojects/docs/src/docs/userguide/userguide.xml b/subprojects/docs/src/docs/userguide/userguide.xml
index 4722ce0..6b1956f 100755
--- a/subprojects/docs/src/docs/userguide/userguide.xml
+++ b/subprojects/docs/src/docs/userguide/userguide.xml
@@ -77,11 +77,13 @@
<xi:include href='wrapperPlugin.xml'/>
<xi:include href='buildDashboardPlugin.xml'/>
<xi:include href='javaGradlePlugin.xml' />
+ <xi:include href='testKit.xml' />
<xi:include href='depMngmt.xml'/>
<xi:include href='artifactMngmt.xml'/>
<xi:include href='mavenPlugin.xml'/>
<xi:include href='signingPlugin.xml'/>
<xi:include href='nativeBinaries.xml'/>
+ <xi:include href='playPlugin.xml'/>
<xi:include href='buildLifecycle.xml'/>
<xi:include href='multiproject.xml'/>
<xi:include href='customTasks.xml'/>
@@ -94,6 +96,7 @@
<xi:include href='publishingIvy.xml'/>
<xi:include href='publishingMaven.xml'/>
<xi:include href='newModel.xml'/>
+ <xi:include href='newJavaPlugin.xml'/>
<!-- this is generated -->
<xi:include href='../../../build/src/samplesList.xml'/>
<xi:include href='potentialTraps.xml'/>
diff --git a/subprojects/docs/src/samples/jvmComponents/java/build.gradle b/subprojects/docs/src/samples/jvmComponents/java/build.gradle
deleted file mode 100644
index 27803a5..0000000
--- a/subprojects/docs/src/samples/jvmComponents/java/build.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-plugins {
- id 'jvm-component'
- id 'java-lang'
-}
-
-model {
- components {
- main(JvmLibrarySpec)
- }
-}
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/jvmComponents/java/src/main/java/org/gradle/samples/HelloWorld.java b/subprojects/docs/src/samples/jvmComponents/java/src/main/java/org/gradle/samples/HelloWorld.java
deleted file mode 100644
index 9203c34..0000000
--- a/subprojects/docs/src/samples/jvmComponents/java/src/main/java/org/gradle/samples/HelloWorld.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.gradle.samples;
-
-public class HelloWorld {
- public static void main(String[] args) {
- System.out.println("Hello World!");
- }
-}
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/modelRules/basicRuleSourcePlugin/build.gradle b/subprojects/docs/src/samples/modelRules/basicRuleSourcePlugin/build.gradle
index 2443470..eb952cc 100644
--- a/subprojects/docs/src/samples/modelRules/basicRuleSourcePlugin/build.gradle
+++ b/subprojects/docs/src/samples/modelRules/basicRuleSourcePlugin/build.gradle
@@ -1,9 +1,59 @@
+// START SNIPPET managed-type-plugin-and-dsl
// START SNIPPET managed-type-and-plugin
// START SNIPPET managed-type
@Managed
interface Person {
- void setFirstName(String n); String getFirstName()
- void setLastName(String n); String getLastName()
+// START SNIPPET property-type-string
+ void setFirstName(String n)
+ String getFirstName()
+// END SNIPPET property-type-string
+
+ void setLastName(String n)
+ String getLastName()
+// END SNIPPET managed-type
+// END SNIPPET managed-type-and-plugin
+// END SNIPPET managed-type-plugin-and-dsl
+
+// START SNIPPET property-type-int
+ void setAge(int age)
+ int getAge()
+// END SNIPPET property-type-int
+
+// START SNIPPET property-type-boolean
+ void setEmployed(boolean isEmployed)
+ boolean isEmployed()
+// END SNIPPET property-type-boolean
+
+// START SNIPPET property-type-managed
+ void setMother(Person mother)
+ Person getMother()
+// END SNIPPET property-type-managed
+
+ void setFather(Person father)
+ Person getFather()
+
+// START SNIPPET property-type-managedset
+ ManagedSet<Person> getChildren()
+// END SNIPPET property-type-managedset
+
+// START SNIPPET property-type-file
+ void setHomeDirectory(File homeDir)
+ File getHomeDirectory()
+// END SNIPPET property-type-file
+
+// START SNIPPET property-type-long
+ void setId(Long id)
+ Long getId()
+// END SNIPPET property-type-long
+
+// START SNIPPET property-type-enum
+ void setMaritalStatus(MaritalStatus status)
+ MaritalStatus getMaritalStatus()
+// END SNIPPET property-type-enum
+
+// START SNIPPET managed-type-plugin-and-dsl
+// START SNIPPET managed-type-and-plugin
+// START SNIPPET managed-type
}
// END SNIPPET managed-type
@@ -41,3 +91,9 @@ model {
}
}
// END SNIPPET dsl
+// END SNIPPET managed-type-plugin-and-dsl
+
+enum MaritalStatus {
+ SINGLE,
+ MARRIED
+}
diff --git a/subprojects/docs/src/samples/native-binaries/cpp-exe/build.gradle b/subprojects/docs/src/samples/native-binaries/cpp-exe/build.gradle
index d8b6bfd..d241e74 100644
--- a/subprojects/docs/src/samples/native-binaries/cpp-exe/build.gradle
+++ b/subprojects/docs/src/samples/native-binaries/cpp-exe/build.gradle
@@ -13,17 +13,20 @@ model {
}
}
}
-}
-
-binaries.withType(NativeExecutableBinary) { binary ->
- def linkTask = binary.tasks.link
- def stripTask = task("strip${binary.name.capitalize()}") {
- dependsOn linkTask
- doFirst {
- if (binary.toolChain in Gcc) {
- ["strip", linkTask.outputFile].execute()
+ tasks { t ->
+ $("components.main").binaries { binaries ->
+ binaries.values().each { binary ->
+ def stripTask = "strip${binary.name.capitalize()}"
+ t.create(stripTask) {
+ dependsOn binary.tasks.link
+ doFirst {
+ if (binary.toolChain in Gcc) {
+ ["strip", binary.tasks.link.outputFile].execute()
+ }
+ }
+ }
+ binary.tasks.build.dependsOn stripTask
}
}
}
- binary.builtBy stripTask
}
diff --git a/subprojects/docs/src/samples/native-binaries/sourceset-variant/build.gradle b/subprojects/docs/src/samples/native-binaries/sourceset-variant/build.gradle
new file mode 100644
index 0000000..e8ecccc
--- /dev/null
+++ b/subprojects/docs/src/samples/native-binaries/sourceset-variant/build.gradle
@@ -0,0 +1,28 @@
+apply plugin: 'c'
+
+model {
+ components {
+ main(NativeExecutableSpec) {
+ binaries.all {
+ sources {
+ if (targetPlatform.operatingSystem.windows) {
+ platformWindows(CSourceSet) {
+ source.srcDir "src/main/windows"
+ lib main.sources.c
+ }
+ } else if (targetPlatform.operatingSystem.linux) {
+ platformLinux(CSourceSet) {
+ source.srcDir "src/main/linux"
+ lib main.sources.c
+ }
+ } else if (targetPlatform.operatingSystem.macOsX) {
+ platformMacOSX(CSourceSet) {
+ source.srcDir "src/main/mac"
+ lib main.sources.c
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/c/main.c b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/c/main.c
new file mode 100644
index 0000000..7da9ee4
--- /dev/null
+++ b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/c/main.c
@@ -0,0 +1,10 @@
+#include "platform.h"
+#include "stdio.h"
+
+int main(int argc, char** argv) {
+ printf("Attributes of '%s' platform\n", platform_name);
+ printf("Is Posix like? %s\n", is_posix_like()?"true":"false");
+ printf("Max Path Length: %d bytes\n", max_path_length());
+ printf("Max memory supported: %llu Kbytes\n", max_memory());
+ return 0;
+}
diff --git a/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/headers/platform.h b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/headers/platform.h
new file mode 100644
index 0000000..383c379
--- /dev/null
+++ b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/headers/platform.h
@@ -0,0 +1,17 @@
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+const char* platform_name;
+
+int max_path_length();
+
+unsigned long long max_memory();
+
+int is_posix_like();
+
+#define KB(x) x
+#define MB(x) KB(x)*1024
+#define GB(x) MB(x)*1024
+#define TB(x) GB(x)*1024
+
+#endif // PLATFORM_H
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/linux/platform-linux.c b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/linux/platform-linux.c
new file mode 100644
index 0000000..1b21bd4
--- /dev/null
+++ b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/linux/platform-linux.c
@@ -0,0 +1,9 @@
+#include "platform.h"
+
+const char* platform_name = "Linux";
+
+int max_path_length() { return -1; }
+
+unsigned long long max_memory() { return TB(128); }
+
+int is_posix_like() { return 1; }
diff --git a/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/mac/platform-mac.c b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/mac/platform-mac.c
new file mode 100644
index 0000000..5ed68fb
--- /dev/null
+++ b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/mac/platform-mac.c
@@ -0,0 +1,9 @@
+#include "platform.h"
+
+const char* platform_name = "MacOSX";
+
+int max_path_length() { return 1024; }
+
+unsigned long long max_memory() { return GB(96); }
+
+int is_posix_like() { return 1; }
diff --git a/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/windows/platform-windows.c b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/windows/platform-windows.c
new file mode 100644
index 0000000..16eec39
--- /dev/null
+++ b/subprojects/docs/src/samples/native-binaries/sourceset-variant/src/main/windows/platform-windows.c
@@ -0,0 +1,10 @@
+#include "platform.h"
+
+const char* platform_name = "Windows";
+
+int max_path_length() { return 260; }
+
+// 640K ought to be enough for anybody.
+unsigned long long max_memory() { return KB(640); }
+
+int is_posix_like() { return 0; }
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/build.gradle b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/build.gradle
new file mode 100644
index 0000000..9bec926
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/build.gradle
@@ -0,0 +1,45 @@
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+// START SNIPPET simple-dependency
+model {
+ components {
+ core(JvmLibrarySpec)
+
+ server(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'core'
+ }
+ }
+ }
+ }
+ }
+}
+// END SNIPPET simple-dependency
+
+model {
+ components {
+// START SNIPPET dependency-other-project
+ client(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':util' library 'main'
+ }
+// END SNIPPET dependency-other-project
+// START SNIPPET dependency-other-project-implicit-lib
+ dependencies {
+ project ':util'
+ }
+// END SNIPPET dependency-other-project-implicit-lib
+// START SNIPPET dependency-other-project
+ }
+ }
+ }
+// END SNIPPET dependency-other-project
+ }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/settings.gradle b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/settings.gradle
new file mode 100644
index 0000000..f7707cb
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/settings.gradle
@@ -0,0 +1,2 @@
+include 'util'
+
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/client/java/org/gradle/Client.java b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/client/java/org/gradle/Client.java
new file mode 100644
index 0000000..c11fb26
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/client/java/org/gradle/Client.java
@@ -0,0 +1,9 @@
+package org.gradle;
+
+public class Client {
+ public static void main(String... args) {
+ if ("1.0".equals(Utils.getCompatibility())) {
+ System.out.println("Compatible!");
+ }
+ }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/core/java/org/gradle/Person.java b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/core/java/org/gradle/Person.java
new file mode 100644
index 0000000..d76e9e4
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/core/java/org/gradle/Person.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle;
+
+public class Person {
+ private final String name;
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/core/resources/org/gradle/resource.xml b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/core/resources/org/gradle/resource.xml
new file mode 100644
index 0000000..b5db07b
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/core/resources/org/gradle/resource.xml
@@ -0,0 +1 @@
+<some-element/>
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/server/java/org/gradle/PersonServer.java b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/server/java/org/gradle/PersonServer.java
new file mode 100644
index 0000000..4d4e2c9
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/src/server/java/org/gradle/PersonServer.java
@@ -0,0 +1,10 @@
+package org.gradle;
+
+import java.util.List;
+
+public class PersonServer {
+ private List<Person> persons;
+
+ List<Person> getPersons() { return persons; }
+ void setPersons(List<Person> persons) { this.persons = persons; }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/util/build.gradle b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/util/build.gradle
new file mode 100644
index 0000000..7b1b7ee
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/util/build.gradle
@@ -0,0 +1,11 @@
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec)
+ }
+}
+
diff --git a/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/util/src/main/java/org/gradle/Utils.java b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/util/src/main/java/org/gradle/Utils.java
new file mode 100644
index 0000000..82c0393
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/multiplecomponents/util/src/main/java/org/gradle/Utils.java
@@ -0,0 +1,5 @@
+package org.gradle;
+
+public class Utils {
+ public static String getCompatibility() { return "1.0"; }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/quickstart/build.gradle b/subprojects/docs/src/samples/newJavaPlugin/quickstart/build.gradle
new file mode 100644
index 0000000..60a401f
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/quickstart/build.gradle
@@ -0,0 +1,38 @@
+// START SNIPPET use-plugin
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+// END SNIPPET use-plugin
+
+// START SNIPPET single-lib
+model {
+ components {
+ main(JvmLibrarySpec)
+ }
+// END SNIPPET single-lib
+// START SNIPPET configure-sourceset
+ components {
+ main {
+ sources {
+ java {
+ // configure the "java" source set
+ }
+ }
+ }
+ }
+// END SNIPPET configure-sourceset
+// START SNIPPET new-sourceset
+ components {
+ main {
+ sources {
+ mySourceSet(JavaSourceSet) {
+ // configure the "mySourceSet" source set
+ }
+ }
+ }
+ }
+// END SNIPPET new-sourceset
+// START SNIPPET single-lib
+}
+// END SNIPPET single-lib
diff --git a/subprojects/docs/src/samples/newJavaPlugin/quickstart/src/main/java/org/gradle/Person.java b/subprojects/docs/src/samples/newJavaPlugin/quickstart/src/main/java/org/gradle/Person.java
new file mode 100644
index 0000000..d76e9e4
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/quickstart/src/main/java/org/gradle/Person.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle;
+
+public class Person {
+ private final String name;
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/quickstart/src/main/resources/org/gradle/resource.xml b/subprojects/docs/src/samples/newJavaPlugin/quickstart/src/main/resources/org/gradle/resource.xml
new file mode 100644
index 0000000..b5db07b
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/quickstart/src/main/resources/org/gradle/resource.xml
@@ -0,0 +1 @@
+<some-element/>
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/build.gradle b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/build.gradle
new file mode 100644
index 0000000..0fb654a
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/build.gradle
@@ -0,0 +1,28 @@
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+// START SNIPPET declare-target-platforms
+model {
+ components {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java5'
+ targetPlatform 'java6'
+ }
+// END SNIPPET declare-target-platforms
+// START SNIPPET binary-specific-sourceset
+ main {
+ binaries.named('java6MainJar') {
+ sources {
+ java6(JavaSourceSet) {
+ source.srcDir 'src/main/java6'
+ }
+ }
+ }
+ }
+// END SNIPPET binary-specific-sourceset
+// START SNIPPET declare-target-platforms
+ }
+}
+// END SNIPPET declare-target-platforms
diff --git a/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/java/org/gradle/Person.java b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/java/org/gradle/Person.java
new file mode 100644
index 0000000..d76e9e4
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/java/org/gradle/Person.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle;
+
+public class Person {
+ private final String name;
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/java6/org/gradle/Person6.java b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/java6/org/gradle/Person6.java
new file mode 100644
index 0000000..83479d6
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/java6/org/gradle/Person6.java
@@ -0,0 +1,10 @@
+package org.gradle;
+
+import java.util.ArrayDeque;
+
+public class Person6 {
+ // ArrayDeque is a Java 6+ only class
+ public static ArrayDeque<Person6> getAll() {
+ return null;
+ }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/resources/org/gradle/resource.xml b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/resources/org/gradle/resource.xml
new file mode 100644
index 0000000..b5db07b
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/core/src/main/resources/org/gradle/resource.xml
@@ -0,0 +1 @@
+<some-element/>
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/server/build.gradle b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/server/build.gradle
new file mode 100644
index 0000000..94b8d50
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/server/build.gradle
@@ -0,0 +1,22 @@
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+// START SNIPPET dependency-with-platform
+model {
+ components {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java5'
+ targetPlatform 'java6'
+ sources {
+ java {
+ dependencies {
+ project ':core' library 'main'
+ }
+ }
+ }
+ }
+ }
+}
+// END SNIPPET dependency-with-platform
diff --git a/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/server/src/main/java/org/gradle/Server.java b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/server/src/main/java/org/gradle/Server.java
new file mode 100644
index 0000000..814a409
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/server/src/main/java/org/gradle/Server.java
@@ -0,0 +1,7 @@
+package org.gradle;
+
+import java.util.List;
+
+public class Server {
+ List<Person> listPersons() { return null; }
+}
diff --git a/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/settings.gradle b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/settings.gradle
new file mode 100644
index 0000000..df69a23
--- /dev/null
+++ b/subprojects/docs/src/samples/newJavaPlugin/targetplatforms/settings.gradle
@@ -0,0 +1,2 @@
+include 'server', 'core'
+
diff --git a/subprojects/docs/src/samples/play/advanced/build.gradle b/subprojects/docs/src/samples/play/advanced/build.gradle
index 5ab0581..461a95f 100644
--- a/subprojects/docs/src/samples/play/advanced/build.gradle
+++ b/subprojects/docs/src/samples/play/advanced/build.gradle
@@ -1,8 +1,11 @@
+// START SNIPPET play-coffeescript
plugins {
id 'play'
id 'play-coffeescript'
}
+// END SNIPPET play-coffeescript
+// START SNIPPET play-platform
model {
components {
play {
@@ -10,19 +13,28 @@ model {
}
}
}
+// END SNIPPET play-platform
+// START SNIPPET play-dependencies
dependencies {
play "commons-lang:commons-lang:2.6"
}
+// END SNIPPET play-dependencies
-repositories{
+repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
+
maven {
- name = "gradle-js"
- url = "https://repo.gradle.org/gradle/javascript-public"
+ name "gradle-js"
+ url "https://repo.gradle.org/gradle/javascript-public"
}
}
diff --git a/subprojects/docs/src/samples/play/advanced/conf/routes b/subprojects/docs/src/samples/play/advanced/conf/routes
index 79b72e0..ff5cb39 100644
--- a/subprojects/docs/src/samples/play/advanced/conf/routes
+++ b/subprojects/docs/src/samples/play/advanced/conf/routes
@@ -16,4 +16,4 @@ POST /questions controllers.QuestionsThreeController.subm
GET /assets/*file controllers.Assets.at(path="/public", file)
# Custom routes
--> /hello hello.Routes
\ No newline at end of file
+-> /hello hello.Routes
diff --git a/subprojects/docs/src/samples/play/basic/build.gradle b/subprojects/docs/src/samples/play/basic/build.gradle
index eb21fb5..5193b60 100644
--- a/subprojects/docs/src/samples/play/basic/build.gradle
+++ b/subprojects/docs/src/samples/play/basic/build.gradle
@@ -1,16 +1,23 @@
+// START SNIPPET use-plugin
plugins {
id 'play'
}
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
+// END SNIPPET use-plugin
+
dependencies {
play 'commons-lang:commons-lang:2.6'
playTest "com.google.guava:guava:17.0"
}
-
-repositories{
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
-}
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/configure-compiler/app/controllers/Application.scala b/subprojects/docs/src/samples/play/configure-compiler/app/controllers/Application.scala
new file mode 100644
index 0000000..827737e
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/app/controllers/Application.scala
@@ -0,0 +1,14 @@
+package controllers
+
+import play.api._
+import play.api.mvc._
+
+import org.apache.commons.lang.StringUtils
+
+object Application extends Controller {
+
+ def index = Action {
+ Ok(views.html.index(StringUtils.trim(" Your new application is ready. ")))
+ }
+
+}
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/configure-compiler/app/views/index.scala.html b/subprojects/docs/src/samples/play/configure-compiler/app/views/index.scala.html
new file mode 100644
index 0000000..d6a6b22
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/app/views/index.scala.html
@@ -0,0 +1,7 @@
+@(message: String)
+
+ at main("Welcome to Play") {
+
+ @play20.welcome(message)
+
+}
diff --git a/subprojects/docs/src/samples/play/configure-compiler/app/views/main.scala.html b/subprojects/docs/src/samples/play/configure-compiler/app/views/main.scala.html
new file mode 100644
index 0000000..5025aa5
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/app/views/main.scala.html
@@ -0,0 +1,15 @@
+@(title: String)(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>@title</title>
+ <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
+ <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
+ <script src="@routes.Assets.at("javascripts/hello.js")" type="text/javascript"></script>
+ </head>
+ <body>
+ @content
+ </body>
+</html>
diff --git a/subprojects/docs/src/samples/play/configure-compiler/build.gradle b/subprojects/docs/src/samples/play/configure-compiler/build.gradle
new file mode 100644
index 0000000..9d16f1f
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/build.gradle
@@ -0,0 +1,35 @@
+plugins {
+ id 'play'
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
+
+dependencies {
+ play 'commons-lang:commons-lang:2.6'
+ playTest "com.google.guava:guava:17.0"
+}
+
+// START SNIPPET play-configure-compiler
+model {
+ components {
+ play {
+ binaries.all {
+ tasks.withType(PlatformScalaCompile) {
+ scalaCompileOptions.additionalParameters = ["-feature", "-language:implicitConversions"]
+ }
+ }
+ }
+ }
+}
+// END SNIPPET play-configure-compiler
diff --git a/subprojects/docs/src/samples/play/configure-compiler/conf/application.conf b/subprojects/docs/src/samples/play/configure-compiler/conf/application.conf
new file mode 100644
index 0000000..0cf04ae
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/conf/application.conf
@@ -0,0 +1,62 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+#
+# This must be changed for production, but we recommend not changing it in this file.
+#
+# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
+application.secret="dxbAjiDdqlIV83LY<:;hSxql?tG`CPNgXEXt2asjk>lYQ<xfR`GsdeFJ at uuYBH=0"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# application.global=Global
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# This router will be looked up first when the application is starting up,
+# so make sure this is the entry point.
+# Furthermore, it's assumed your route file is named properly.
+# So for an application router like `my.application.Router`,
+# you may need to define a router file `conf/my.application.routes`.
+# Default to Routes in the root package (and conf/routes)
+# application.router=my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.user=sa
+# db.default.password=""
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/),
+# by providing an application-logger.xml file in the conf directory.
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+
diff --git a/subprojects/docs/src/samples/play/configure-compiler/conf/routes b/subprojects/docs/src/samples/play/configure-compiler/conf/routes
new file mode 100644
index 0000000..20fd042
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/conf/routes
@@ -0,0 +1,9 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET / controllers.Application.index
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.at(path="/public", file)
diff --git a/subprojects/docs/src/samples/play/configure-compiler/public/images/favicon.png b/subprojects/docs/src/samples/play/configure-compiler/public/images/favicon.png
new file mode 100644
index 0000000..c7d92d2
Binary files /dev/null and b/subprojects/docs/src/samples/play/configure-compiler/public/images/favicon.png differ
diff --git a/subprojects/docs/src/samples/play/configure-compiler/public/javascripts/hello.js b/subprojects/docs/src/samples/play/configure-compiler/public/javascripts/hello.js
new file mode 100644
index 0000000..209fbee
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/public/javascripts/hello.js
@@ -0,0 +1,3 @@
+if (window.console) {
+ console.log("Welcome to your Play application's JavaScript!");
+}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css b/subprojects/docs/src/samples/play/configure-compiler/public/stylesheets/main.css
similarity index 100%
copy from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
copy to subprojects/docs/src/samples/play/configure-compiler/public/stylesheets/main.css
diff --git a/subprojects/docs/src/samples/play/configure-compiler/test/ApplicationSpec.scala b/subprojects/docs/src/samples/play/configure-compiler/test/ApplicationSpec.scala
new file mode 100644
index 0000000..599decb
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/test/ApplicationSpec.scala
@@ -0,0 +1,41 @@
+import org.specs2.mutable._
+import org.specs2.runner._
+import org.junit.runner._
+
+import play.api.test._
+import play.api.test.Helpers._
+
+import org.apache.commons.lang.StringUtils
+import com.google.common.collect.Lists
+
+/**
+ * Add your spec here.
+ * You can mock out a whole application including requests, plugins etc.
+ * For more information, consult the wiki.
+ */
+ at RunWith(classOf[JUnitRunner])
+class ApplicationSpec extends Specification {
+
+ "Application" should {
+
+ "send 404 on a bad request" in new WithApplication{
+ route(FakeRequest(GET, "/boum")) must beNone
+ }
+
+ "render the index page" in new WithApplication{
+ val home = route(FakeRequest(GET, "/")).get
+
+ status(home) must equalTo(OK)
+ contentType(home) must beSome.which(_ == "text/html")
+ contentAsString(home) must contain ("Your new application is ready.")
+ }
+
+ "tests can use commons-lang play dependency" in {
+ StringUtils.reverse("foobar") must equalTo("raboof")
+ }
+
+ "tests can use guava play-test dependency" in {
+ Lists.newArrayList("foo", "bar").size() must equalTo(2)
+ }
+ }
+}
diff --git a/subprojects/docs/src/samples/play/configure-compiler/test/IntegrationSpec.scala b/subprojects/docs/src/samples/play/configure-compiler/test/IntegrationSpec.scala
new file mode 100644
index 0000000..652edde
--- /dev/null
+++ b/subprojects/docs/src/samples/play/configure-compiler/test/IntegrationSpec.scala
@@ -0,0 +1,24 @@
+import org.specs2.mutable._
+import org.specs2.runner._
+import org.junit.runner._
+
+import play.api.test._
+import play.api.test.Helpers._
+
+/**
+ * add your integration spec here.
+ * An integration test will fire up a whole play application in a real (or headless) browser
+ */
+ at RunWith(classOf[JUnitRunner])
+class IntegrationSpec extends Specification {
+
+ "Application" should {
+
+ "work from within a browser" in new WithBrowser {
+
+ browser.goTo("http://localhost:" + port)
+
+ browser.pageSource must contain("Your new application is ready.")
+ }
+ }
+}
diff --git a/subprojects/docs/src/samples/play/custom-assets/app/controllers/Application.scala b/subprojects/docs/src/samples/play/custom-assets/app/controllers/Application.scala
new file mode 100644
index 0000000..827737e
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/app/controllers/Application.scala
@@ -0,0 +1,14 @@
+package controllers
+
+import play.api._
+import play.api.mvc._
+
+import org.apache.commons.lang.StringUtils
+
+object Application extends Controller {
+
+ def index = Action {
+ Ok(views.html.index(StringUtils.trim(" Your new application is ready. ")))
+ }
+
+}
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/custom-assets/app/views/index.scala.html b/subprojects/docs/src/samples/play/custom-assets/app/views/index.scala.html
new file mode 100644
index 0000000..d6a6b22
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/app/views/index.scala.html
@@ -0,0 +1,7 @@
+@(message: String)
+
+ at main("Welcome to Play") {
+
+ @play20.welcome(message)
+
+}
diff --git a/subprojects/docs/src/samples/play/custom-assets/app/views/main.scala.html b/subprojects/docs/src/samples/play/custom-assets/app/views/main.scala.html
new file mode 100644
index 0000000..5025aa5
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/app/views/main.scala.html
@@ -0,0 +1,15 @@
+@(title: String)(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>@title</title>
+ <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
+ <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
+ <script src="@routes.Assets.at("javascripts/hello.js")" type="text/javascript"></script>
+ </head>
+ <body>
+ @content
+ </body>
+</html>
diff --git a/subprojects/docs/src/samples/play/custom-assets/build.gradle b/subprojects/docs/src/samples/play/custom-assets/build.gradle
new file mode 100644
index 0000000..04e7108
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/build.gradle
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'play'
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
+
+dependencies {
+ play 'commons-lang:commons-lang:2.6'
+ playTest "com.google.guava:guava:17.0"
+}
+
+// START SNIPPET custom-assets
+model {
+ components {
+ play {
+ binaries.all { binary ->
+ tasks.create("addCopyrightTo${binary.name.capitalize()}Assets", AddCopyrights) { copyrightTask ->
+ source "raw-assets"
+ copyrightFile = project.file('copyright.txt')
+ destinationDir = project.file("${buildDir}/${binary.name}/addCopyRights")
+
+ // Hook this task into the binary
+ binary.assets.addAssetDir destinationDir
+ binary.assets.builtBy copyrightTask
+ }
+ }
+ }
+ }
+}
+
+class AddCopyrights extends SourceTask {
+ @InputFile
+ File copyrightFile
+
+ @OutputDirectory
+ File destinationDir
+
+ @TaskAction
+ void generateAssets() {
+ String copyright = copyrightFile.text
+ getSource().files.each { File file ->
+ File outputFile = new File(destinationDir, file.name)
+ outputFile.text = "${copyright}\n${file.text}"
+ }
+ }
+}
+// END SNIPPET custom-assets
diff --git a/subprojects/docs/src/samples/play/custom-assets/conf/application.conf b/subprojects/docs/src/samples/play/custom-assets/conf/application.conf
new file mode 100644
index 0000000..0cf04ae
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/conf/application.conf
@@ -0,0 +1,62 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+#
+# This must be changed for production, but we recommend not changing it in this file.
+#
+# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
+application.secret="dxbAjiDdqlIV83LY<:;hSxql?tG`CPNgXEXt2asjk>lYQ<xfR`GsdeFJ at uuYBH=0"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# application.global=Global
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# This router will be looked up first when the application is starting up,
+# so make sure this is the entry point.
+# Furthermore, it's assumed your route file is named properly.
+# So for an application router like `my.application.Router`,
+# you may need to define a router file `conf/my.application.routes`.
+# Default to Routes in the root package (and conf/routes)
+# application.router=my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.user=sa
+# db.default.password=""
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/),
+# by providing an application-logger.xml file in the conf directory.
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+
diff --git a/subprojects/docs/src/samples/play/custom-assets/conf/routes b/subprojects/docs/src/samples/play/custom-assets/conf/routes
new file mode 100644
index 0000000..20fd042
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/conf/routes
@@ -0,0 +1,9 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET / controllers.Application.index
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.at(path="/public", file)
diff --git a/subprojects/docs/src/samples/play/custom-assets/copyright.txt b/subprojects/docs/src/samples/play/custom-assets/copyright.txt
new file mode 100644
index 0000000..82ca41c
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/copyright.txt
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/subprojects/docs/src/samples/play/custom-assets/public/images/favicon.png b/subprojects/docs/src/samples/play/custom-assets/public/images/favicon.png
new file mode 100644
index 0000000..c7d92d2
Binary files /dev/null and b/subprojects/docs/src/samples/play/custom-assets/public/images/favicon.png differ
diff --git a/subprojects/docs/src/samples/play/custom-assets/public/javascripts/hello.js b/subprojects/docs/src/samples/play/custom-assets/public/javascripts/hello.js
new file mode 100644
index 0000000..209fbee
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/public/javascripts/hello.js
@@ -0,0 +1,3 @@
+if (window.console) {
+ console.log("Welcome to your Play application's JavaScript!");
+}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css b/subprojects/docs/src/samples/play/custom-assets/public/stylesheets/main.css
similarity index 100%
copy from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
copy to subprojects/docs/src/samples/play/custom-assets/public/stylesheets/main.css
diff --git a/subprojects/docs/src/samples/play/custom-assets/raw-assets/sample.js b/subprojects/docs/src/samples/play/custom-assets/raw-assets/sample.js
new file mode 100644
index 0000000..2e70c10
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-assets/raw-assets/sample.js
@@ -0,0 +1,9 @@
+var cubes = (function() {
+ var _i, _len, _results;
+ _results = [];
+ for (_i = 0, _len = list.length; _i < _len; _i++) {
+ num = list[_i];
+ _results.push(math.cube(num));
+ }
+ return _results;
+})();
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/custom-distribution/LICENSE b/subprojects/docs/src/samples/play/custom-distribution/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/custom-distribution/README.md b/subprojects/docs/src/samples/play/custom-distribution/README.md
new file mode 100644
index 0000000..6bcf5fd
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/README.md
@@ -0,0 +1,2 @@
+# Custom Distribution Example
+This is an example to demonstrate how one can add additional content to a play distribution.
diff --git a/subprojects/docs/src/samples/play/custom-distribution/app/controllers/Application.scala b/subprojects/docs/src/samples/play/custom-distribution/app/controllers/Application.scala
new file mode 100644
index 0000000..827737e
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/app/controllers/Application.scala
@@ -0,0 +1,14 @@
+package controllers
+
+import play.api._
+import play.api.mvc._
+
+import org.apache.commons.lang.StringUtils
+
+object Application extends Controller {
+
+ def index = Action {
+ Ok(views.html.index(StringUtils.trim(" Your new application is ready. ")))
+ }
+
+}
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/custom-distribution/app/views/index.scala.html b/subprojects/docs/src/samples/play/custom-distribution/app/views/index.scala.html
new file mode 100644
index 0000000..d6a6b22
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/app/views/index.scala.html
@@ -0,0 +1,7 @@
+@(message: String)
+
+ at main("Welcome to Play") {
+
+ @play20.welcome(message)
+
+}
diff --git a/subprojects/docs/src/samples/play/custom-distribution/app/views/main.scala.html b/subprojects/docs/src/samples/play/custom-distribution/app/views/main.scala.html
new file mode 100644
index 0000000..5025aa5
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/app/views/main.scala.html
@@ -0,0 +1,15 @@
+@(title: String)(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>@title</title>
+ <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
+ <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
+ <script src="@routes.Assets.at("javascripts/hello.js")" type="text/javascript"></script>
+ </head>
+ <body>
+ @content
+ </body>
+</html>
diff --git a/subprojects/docs/src/samples/play/custom-distribution/build.gradle b/subprojects/docs/src/samples/play/custom-distribution/build.gradle
new file mode 100644
index 0000000..fecadcd
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/build.gradle
@@ -0,0 +1,36 @@
+plugins {
+ id 'play'
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
+
+dependencies {
+ play 'commons-lang:commons-lang:2.6'
+ playTest "com.google.guava:guava:17.0"
+}
+
+// START SNIPPET play-custom-distribution
+model {
+ distributions {
+ playBinary {
+ contents {
+ from("README.md")
+ from("scripts") {
+ into "bin"
+ }
+ }
+ }
+ }
+}
+// END SNIPPET play-custom-distribution
diff --git a/subprojects/docs/src/samples/play/custom-distribution/conf/application.conf b/subprojects/docs/src/samples/play/custom-distribution/conf/application.conf
new file mode 100644
index 0000000..0cf04ae
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/conf/application.conf
@@ -0,0 +1,62 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+#
+# This must be changed for production, but we recommend not changing it in this file.
+#
+# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
+application.secret="dxbAjiDdqlIV83LY<:;hSxql?tG`CPNgXEXt2asjk>lYQ<xfR`GsdeFJ at uuYBH=0"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# application.global=Global
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# This router will be looked up first when the application is starting up,
+# so make sure this is the entry point.
+# Furthermore, it's assumed your route file is named properly.
+# So for an application router like `my.application.Router`,
+# you may need to define a router file `conf/my.application.routes`.
+# Default to Routes in the root package (and conf/routes)
+# application.router=my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.user=sa
+# db.default.password=""
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/),
+# by providing an application-logger.xml file in the conf directory.
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+
diff --git a/subprojects/docs/src/samples/play/custom-distribution/conf/routes b/subprojects/docs/src/samples/play/custom-distribution/conf/routes
new file mode 100644
index 0000000..20fd042
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/conf/routes
@@ -0,0 +1,9 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET / controllers.Application.index
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.at(path="/public", file)
diff --git a/subprojects/docs/src/samples/play/custom-distribution/public/images/favicon.png b/subprojects/docs/src/samples/play/custom-distribution/public/images/favicon.png
new file mode 100644
index 0000000..c7d92d2
Binary files /dev/null and b/subprojects/docs/src/samples/play/custom-distribution/public/images/favicon.png differ
diff --git a/subprojects/docs/src/samples/play/custom-distribution/public/javascripts/hello.js b/subprojects/docs/src/samples/play/custom-distribution/public/javascripts/hello.js
new file mode 100644
index 0000000..209fbee
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/public/javascripts/hello.js
@@ -0,0 +1,3 @@
+if (window.console) {
+ console.log("Welcome to your Play application's JavaScript!");
+}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css b/subprojects/docs/src/samples/play/custom-distribution/public/stylesheets/main.css
similarity index 100%
copy from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
copy to subprojects/docs/src/samples/play/custom-distribution/public/stylesheets/main.css
diff --git a/subprojects/docs/src/samples/play/custom-distribution/scripts/runPlayBinaryAsUser.sh b/subprojects/docs/src/samples/play/custom-distribution/scripts/runPlayBinaryAsUser.sh
new file mode 100644
index 0000000..9e85942
--- /dev/null
+++ b/subprojects/docs/src/samples/play/custom-distribution/scripts/runPlayBinaryAsUser.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+RUNASUSER=$1
+
+if test "${RUNASUSER}" = ""
+then
+ echo "Usage: `basename $0` <username>"
+ exit 1
+fi
+
+SCRIPTDIR=`dirname $0`
+SCRIPTDIR=`cd ${SCRIPTDIR}; pwd`
+sudo -u ${RUNASUSER} ${SCRIPTDIR}/playBinary
+
diff --git a/subprojects/docs/src/samples/play/multiproject/build.gradle b/subprojects/docs/src/samples/play/multiproject/build.gradle
index 798153a..2daf84f 100644
--- a/subprojects/docs/src/samples/play/multiproject/build.gradle
+++ b/subprojects/docs/src/samples/play/multiproject/build.gradle
@@ -3,17 +3,24 @@ plugins {
}
allprojects {
- repositories{
+ repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
}
}
+// START SNIPPET play-multiproject-dependencies
dependencies {
play project(":admin")
play project(":user")
play project(":util")
}
+// END SNIPPET play-multiproject-dependencies
diff --git a/subprojects/docs/src/samples/play/play-2.4/app/controllers/Application.scala b/subprojects/docs/src/samples/play/play-2.4/app/controllers/Application.scala
new file mode 100644
index 0000000..94d929c
--- /dev/null
+++ b/subprojects/docs/src/samples/play/play-2.4/app/controllers/Application.scala
@@ -0,0 +1,14 @@
+package controllers
+
+import play.api._
+import play.api.mvc._
+
+import org.apache.commons.lang.StringUtils
+
+class Application extends Controller {
+
+ def index = Action {
+ Ok(views.html.index(StringUtils.trim(" Your new application is ready. ")))
+ }
+
+}
diff --git a/subprojects/docs/src/samples/play/play-2.4/app/views/index.scala.html b/subprojects/docs/src/samples/play/play-2.4/app/views/index.scala.html
new file mode 100644
index 0000000..d6a6b22
--- /dev/null
+++ b/subprojects/docs/src/samples/play/play-2.4/app/views/index.scala.html
@@ -0,0 +1,7 @@
+@(message: String)
+
+ at main("Welcome to Play") {
+
+ @play20.welcome(message)
+
+}
diff --git a/subprojects/docs/src/samples/play/play-2.4/app/views/main.scala.html b/subprojects/docs/src/samples/play/play-2.4/app/views/main.scala.html
new file mode 100644
index 0000000..5025aa5
--- /dev/null
+++ b/subprojects/docs/src/samples/play/play-2.4/app/views/main.scala.html
@@ -0,0 +1,15 @@
+@(title: String)(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>@title</title>
+ <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
+ <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
+ <script src="@routes.Assets.at("javascripts/hello.js")" type="text/javascript"></script>
+ </head>
+ <body>
+ @content
+ </body>
+</html>
diff --git a/subprojects/docs/src/samples/play/play-2.4/build.gradle b/subprojects/docs/src/samples/play/play-2.4/build.gradle
new file mode 100644
index 0000000..9c3d70b
--- /dev/null
+++ b/subprojects/docs/src/samples/play/play-2.4/build.gradle
@@ -0,0 +1,39 @@
+plugins {
+ id 'play'
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
+
+dependencies {
+ play 'commons-lang:commons-lang:2.6'
+ playTest "com.google.guava:guava:17.0"
+}
+
+model {
+ components {
+ play {
+ targetPlatform 'play-2.4.0'
+ }
+ }
+}
+
+// START SNIPPET play-injected-routes-compiler
+model {
+ components {
+ play {
+ injectedRoutesGenerator = true
+ }
+ }
+}
+// END SNIPPET play-injected-routes-compiler
diff --git a/subprojects/docs/src/samples/play/play-2.4/conf/application.conf b/subprojects/docs/src/samples/play/play-2.4/conf/application.conf
new file mode 100644
index 0000000..0cf04ae
--- /dev/null
+++ b/subprojects/docs/src/samples/play/play-2.4/conf/application.conf
@@ -0,0 +1,62 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+#
+# This must be changed for production, but we recommend not changing it in this file.
+#
+# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
+application.secret="dxbAjiDdqlIV83LY<:;hSxql?tG`CPNgXEXt2asjk>lYQ<xfR`GsdeFJ at uuYBH=0"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# application.global=Global
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# This router will be looked up first when the application is starting up,
+# so make sure this is the entry point.
+# Furthermore, it's assumed your route file is named properly.
+# So for an application router like `my.application.Router`,
+# you may need to define a router file `conf/my.application.routes`.
+# Default to Routes in the root package (and conf/routes)
+# application.router=my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.user=sa
+# db.default.password=""
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/),
+# by providing an application-logger.xml file in the conf directory.
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+
diff --git a/subprojects/docs/src/samples/play/play-2.4/conf/routes b/subprojects/docs/src/samples/play/play-2.4/conf/routes
new file mode 100644
index 0000000..20fd042
--- /dev/null
+++ b/subprojects/docs/src/samples/play/play-2.4/conf/routes
@@ -0,0 +1,9 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET / controllers.Application.index
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.at(path="/public", file)
diff --git a/subprojects/docs/src/samples/play/play-2.4/public/images/favicon.png b/subprojects/docs/src/samples/play/play-2.4/public/images/favicon.png
new file mode 100644
index 0000000..c7d92d2
Binary files /dev/null and b/subprojects/docs/src/samples/play/play-2.4/public/images/favicon.png differ
diff --git a/subprojects/docs/src/samples/play/play-2.4/public/javascripts/hello.js b/subprojects/docs/src/samples/play/play-2.4/public/javascripts/hello.js
new file mode 100644
index 0000000..209fbee
--- /dev/null
+++ b/subprojects/docs/src/samples/play/play-2.4/public/javascripts/hello.js
@@ -0,0 +1,3 @@
+if (window.console) {
+ console.log("Welcome to your Play application's JavaScript!");
+}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css b/subprojects/docs/src/samples/play/play-2.4/public/stylesheets/main.css
similarity index 100%
copy from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
copy to subprojects/docs/src/samples/play/play-2.4/public/stylesheets/main.css
diff --git a/subprojects/docs/src/samples/play/sourcesets/additional/java/controllers/hello/HelloController.java b/subprojects/docs/src/samples/play/sourcesets/additional/java/controllers/hello/HelloController.java
new file mode 100644
index 0000000..a3772a3
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/additional/java/controllers/hello/HelloController.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package controllers.hello;
+
+import play.*;
+import play.mvc.*;
+import views.html.*;
+
+import org.apache.commons.lang.StringUtils;
+
+public class HelloController extends Controller {
+
+ public static Result index(String name) {
+ return ok(String.format("Hello %s!", StringUtils.capitalize(name)));
+ }
+}
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/sourcesets/additional/javascript/old_sample.js b/subprojects/docs/src/samples/play/sourcesets/additional/javascript/old_sample.js
new file mode 100644
index 0000000..a2d61de
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/additional/javascript/old_sample.js
@@ -0,0 +1,10 @@
+
+var old_cubes = (function() {
+ var _i, _len, _results;
+ _results = [];
+ for (_i = 0, _len = list.length; _i < _len; _i++) {
+ num = list[_i];
+ _results.push(math.cube(num));
+ }
+ return _results;
+})();
diff --git a/subprojects/docs/src/samples/play/sourcesets/additional/javascript/sample.js b/subprojects/docs/src/samples/play/sourcesets/additional/javascript/sample.js
new file mode 100644
index 0000000..2e70c10
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/additional/javascript/sample.js
@@ -0,0 +1,9 @@
+var cubes = (function() {
+ var _i, _len, _results;
+ _results = [];
+ for (_i = 0, _len = list.length; _i < _len; _i++) {
+ num = list[_i];
+ _results.push(math.cube(num));
+ }
+ return _results;
+})();
\ No newline at end of file
diff --git a/subprojects/docs/src/samples/play/sourcesets/app/assets/greetings.js b/subprojects/docs/src/samples/play/sourcesets/app/assets/greetings.js
new file mode 100644
index 0000000..a72d0be
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/app/assets/greetings.js
@@ -0,0 +1,4 @@
+
+if (window.console) {
+ console.log("Greetings from your Play application's JavaScript!");
+}
diff --git a/subprojects/docs/src/samples/play/sourcesets/app/controllers/Application.scala b/subprojects/docs/src/samples/play/sourcesets/app/controllers/Application.scala
new file mode 100644
index 0000000..573ae9f
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/app/controllers/Application.scala
@@ -0,0 +1,14 @@
+package controllers
+
+import play.api._
+import play.api.mvc._
+
+import org.apache.commons.lang.StringUtils
+
+object Application extends Controller {
+
+ def index = Action {
+ Ok(" Your new application is ready. ")
+ }
+
+}
diff --git a/subprojects/docs/src/samples/play/sourcesets/build.gradle b/subprojects/docs/src/samples/play/sourcesets/build.gradle
new file mode 100644
index 0000000..f62247e
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/build.gradle
@@ -0,0 +1,62 @@
+plugins {
+ id 'play'
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
+
+dependencies {
+ play 'commons-lang:commons-lang:2.6'
+ playTest "com.google.guava:guava:17.0"
+}
+
+// START SNIPPET default-sourcesets
+model {
+ components {
+ play {
+ sources {
+ java {
+ source.srcDir "additional/java"
+ }
+ javaScript {
+ source {
+ srcDir "additional/javascript"
+ exclude "**/old_*.js"
+ }
+ }
+ }
+ }
+ }
+}
+// END SNIPPET default-sourcesets
+
+// START SNIPPET play-extra-sourcesets
+model {
+ components {
+ play {
+ sources {
+ extraJava(JavaSourceSet) {
+ source.srcDir "extra/java"
+ }
+ extraTwirl(TwirlSourceSet) {
+ source.srcDir "extra/twirl"
+ }
+ extraRoutes(RoutesSourceSet) {
+ source.srcDir "extra/routes"
+ }
+ }
+ }
+ }
+}
+// END SNIPPET play-extra-sourcesets
+
diff --git a/subprojects/docs/src/samples/play/sourcesets/conf/application.conf b/subprojects/docs/src/samples/play/sourcesets/conf/application.conf
new file mode 100644
index 0000000..0cf04ae
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/conf/application.conf
@@ -0,0 +1,62 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+#
+# This must be changed for production, but we recommend not changing it in this file.
+#
+# See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
+application.secret="dxbAjiDdqlIV83LY<:;hSxql?tG`CPNgXEXt2asjk>lYQ<xfR`GsdeFJ at uuYBH=0"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# application.global=Global
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# This router will be looked up first when the application is starting up,
+# so make sure this is the entry point.
+# Furthermore, it's assumed your route file is named properly.
+# So for an application router like `my.application.Router`,
+# you may need to define a router file `conf/my.application.routes`.
+# Default to Routes in the root package (and conf/routes)
+# application.router=my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.user=sa
+# db.default.password=""
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/),
+# by providing an application-logger.xml file in the conf directory.
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+
diff --git a/subprojects/docs/src/samples/play/sourcesets/conf/routes b/subprojects/docs/src/samples/play/sourcesets/conf/routes
new file mode 100644
index 0000000..b3c1764
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/conf/routes
@@ -0,0 +1,13 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET / controllers.Application.index
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.at(path="/public", file)
+
+# Custom routes
+-> /hello hello.Routes
+-> /date date.Routes
diff --git a/subprojects/docs/src/samples/play/sourcesets/extra/java/controllers/date/DateController.java b/subprojects/docs/src/samples/play/sourcesets/extra/java/controllers/date/DateController.java
new file mode 100644
index 0000000..c285c8b
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/extra/java/controllers/date/DateController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package controllers.date;
+
+import play.*;
+import play.mvc.*;
+import views.html.*;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Date;
+
+public class DateController extends Controller {
+
+ public static Result index() {
+ return ok(String.format("The current date is %s!", new Date()));
+ }
+}
diff --git a/subprojects/docs/src/samples/play/sourcesets/extra/routes/date.routes b/subprojects/docs/src/samples/play/sourcesets/extra/routes/date.routes
new file mode 100644
index 0000000..fda08f2
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/extra/routes/date.routes
@@ -0,0 +1,2 @@
+# date routes
+GET / controllers.date.DateController.index
diff --git a/subprojects/docs/src/samples/play/sourcesets/extra/routes/hello.routes b/subprojects/docs/src/samples/play/sourcesets/extra/routes/hello.routes
new file mode 100644
index 0000000..bc3e759
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/extra/routes/hello.routes
@@ -0,0 +1,3 @@
+# Hello page
+GET /:name controllers.hello.HelloController.index(name)
+
diff --git a/subprojects/docs/src/samples/play/sourcesets/extra/twirl/main.scala.html b/subprojects/docs/src/samples/play/sourcesets/extra/twirl/main.scala.html
new file mode 100644
index 0000000..5025aa5
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/extra/twirl/main.scala.html
@@ -0,0 +1,15 @@
+@(title: String)(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>@title</title>
+ <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
+ <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
+ <script src="@routes.Assets.at("javascripts/hello.js")" type="text/javascript"></script>
+ </head>
+ <body>
+ @content
+ </body>
+</html>
diff --git a/subprojects/docs/src/samples/play/sourcesets/public/images/favicon.png b/subprojects/docs/src/samples/play/sourcesets/public/images/favicon.png
new file mode 100644
index 0000000..c7d92d2
Binary files /dev/null and b/subprojects/docs/src/samples/play/sourcesets/public/images/favicon.png differ
diff --git a/subprojects/docs/src/samples/play/sourcesets/public/javascripts/hello.js b/subprojects/docs/src/samples/play/sourcesets/public/javascripts/hello.js
new file mode 100644
index 0000000..209fbee
--- /dev/null
+++ b/subprojects/docs/src/samples/play/sourcesets/public/javascripts/hello.js
@@ -0,0 +1,3 @@
+if (window.console) {
+ console.log("Welcome to your Play application's JavaScript!");
+}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css b/subprojects/docs/src/samples/play/sourcesets/public/stylesheets/main.css
similarity index 100%
copy from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
copy to subprojects/docs/src/samples/play/sourcesets/public/stylesheets/main.css
diff --git a/subprojects/docs/src/samples/testKit/testKitJunit/build.gradle b/subprojects/docs/src/samples/testKit/testKitJunit/build.gradle
new file mode 100644
index 0000000..0a149bd
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitJunit/build.gradle
@@ -0,0 +1,17 @@
+apply plugin: 'java'
+
+// START SNIPPET declare-gradle-testkit-dependency
+dependencies {
+ testCompile gradleTestKit()
+}
+// END SNIPPET declare-gradle-testkit-dependency
+
+// START SNIPPET declare-junit-dependency
+dependencies {
+ testCompile 'junit:junit:4.12'
+}
+// END SNIPPET declare-junit-dependency
+
+repositories {
+ mavenCentral()
+}
diff --git a/subprojects/docs/src/samples/testKit/testKitJunit/src/test/java/org/gradle/sample/BuildLogicFunctionalTest.java b/subprojects/docs/src/samples/testKit/testKitJunit/src/test/java/org/gradle/sample/BuildLogicFunctionalTest.java
new file mode 100644
index 0000000..e399d70
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitJunit/src/test/java/org/gradle/sample/BuildLogicFunctionalTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.sample;
+
+// START SNIPPET functional-test-junit
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.GradleRunner;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import static org.gradle.testkit.runner.TaskOutcome.*;
+
+public class BuildLogicFunctionalTest {
+ @Rule public final TemporaryFolder testProjectDir = new TemporaryFolder();
+ private File buildFile;
+
+ @Before
+ public void setup() throws IOException {
+ buildFile = testProjectDir.newFile("build.gradle");
+ }
+
+ @Test
+ public void testHelloWorldTask() throws IOException {
+ String buildFileContent = "task helloWorld {" +
+ " doLast {" +
+ " println 'Hello world!'" +
+ " }" +
+ "}";
+ writeFile(buildFile, buildFileContent);
+
+ BuildResult result = GradleRunner.create()
+ .withProjectDir(testProjectDir.getRoot())
+ .withArguments("helloWorld")
+ .build();
+
+ assertTrue(result.getStandardOutput().contains("Hello world!"));
+ assertEquals(result.task(":helloWorld").getOutcome(), SUCCESS);
+ }
+
+ private void writeFile(File destination, String content) throws IOException {
+ BufferedWriter output = null;
+ try {
+ output = new BufferedWriter(new FileWriter(destination));
+ output.write(content);
+ } finally {
+ if (output != null) {
+ output.close();
+ }
+ }
+ }
+}
+// END SNIPPET functional-test-junit
diff --git a/subprojects/docs/src/samples/testKit/testKitSpock/build.gradle b/subprojects/docs/src/samples/testKit/testKitSpock/build.gradle
new file mode 100644
index 0000000..ea17742
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpock/build.gradle
@@ -0,0 +1,16 @@
+apply plugin: 'groovy'
+
+dependencies {
+ testCompile localGroovy()
+ testCompile gradleTestKit()
+}
+
+// START SNIPPET declare-spock-dependency
+dependencies {
+ testCompile 'org.spockframework:spock-core:1.0-groovy-2.3'
+}
+// END SNIPPET declare-spock-dependency
+
+repositories {
+ mavenCentral()
+}
diff --git a/subprojects/docs/src/samples/testKit/testKitSpock/src/test/groovy/org/gradle/sample/BuildLogicFunctionalTest.groovy b/subprojects/docs/src/samples/testKit/testKitSpock/src/test/groovy/org/gradle/sample/BuildLogicFunctionalTest.groovy
new file mode 100644
index 0000000..c72b127
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpock/src/test/groovy/org/gradle/sample/BuildLogicFunctionalTest.groovy
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.sample
+
+// START SNIPPET functional-test-spock
+import org.gradle.testkit.runner.GradleRunner
+import static org.gradle.testkit.runner.TaskOutcome.*
+import org.junit.Rule
+import org.junit.rules.TemporaryFolder
+import spock.lang.Specification
+
+class BuildLogicFunctionalTest extends Specification {
+ @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
+ File buildFile
+
+ def setup() {
+ buildFile = testProjectDir.newFile('build.gradle')
+ }
+
+ def "hello world task prints hello world"() {
+ given:
+ buildFile << """
+ task helloWorld {
+ doLast {
+ println 'Hello world!'
+ }
+ }
+ """
+
+ when:
+ def result = GradleRunner.create()
+ .withProjectDir(testProjectDir.root)
+ .withArguments('helloWorld')
+ .build()
+
+ then:
+ result.standardOutput.contains('Hello world!')
+ result.task(":helloWorld").outcome == SUCCESS
+ }
+}
+// END SNIPPET functional-test-spock
diff --git a/subprojects/docs/src/samples/testKit/testKitSpockClasspath/lib/build.gradle b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/lib/build.gradle
new file mode 100644
index 0000000..6bfe32a
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/lib/build.gradle
@@ -0,0 +1,5 @@
+apply plugin: 'groovy'
+
+dependencies {
+ compile localGroovy()
+}
diff --git a/subprojects/docs/src/samples/testKit/testKitSpockClasspath/lib/src/main/groovy/org/gradle/sample/lib/Messages.groovy b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/lib/src/main/groovy/org/gradle/sample/lib/Messages.groovy
new file mode 100644
index 0000000..e998964
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/lib/src/main/groovy/org/gradle/sample/lib/Messages.groovy
@@ -0,0 +1,5 @@
+package org.gradle.sample.lib
+
+class Messages {
+ final static String HELLO_WORLD = "Hello world!"
+}
diff --git a/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/build.gradle b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/build.gradle
new file mode 100644
index 0000000..e13bd93
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'groovy'
+
+dependencies {
+ compile localGroovy()
+ compile gradleApi()
+ testCompile gradleTestKit()
+ testCompile 'org.spockframework:spock-core:1.0-groovy-2.3'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile project(":lib")
+}
+
+// START SNIPPET test-logic-classpath
+// Write the plugin's classpath to a file to share with the tests
+task createClasspathManifest {
+ def outputDir = file("$buildDir/$name")
+
+ inputs.files sourceSets.main.runtimeClasspath
+ outputs.dir outputDir
+
+ doLast {
+ outputDir.mkdirs()
+ file("$outputDir/plugin-classpath.txt").text = sourceSets.main.runtimeClasspath.join("\n")
+ }
+}
+
+// Add the classpath file to the test runtime classpath
+dependencies {
+ testRuntime files(createClasspathManifest)
+}
+// END SNIPPET test-logic-classpath
diff --git a/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/main/groovy/org/gradle/sample/HelloWorld.groovy b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/main/groovy/org/gradle/sample/HelloWorld.groovy
new file mode 100644
index 0000000..7f80898
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/main/groovy/org/gradle/sample/HelloWorld.groovy
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.sample
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.tasks.TaskAction
+import org.gradle.sample.lib.Messages
+
+class HelloWorld extends DefaultTask {
+ @TaskAction
+ void printMessage() {
+ println Messages.HELLO_WORLD
+ }
+}
diff --git a/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/main/groovy/org/gradle/sample/HelloWorldPlugin.groovy b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/main/groovy/org/gradle/sample/HelloWorldPlugin.groovy
new file mode 100644
index 0000000..aef131d
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/main/groovy/org/gradle/sample/HelloWorldPlugin.groovy
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.sample
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class HelloWorldPlugin implements Plugin<Project> {
+ void apply(Project project) {
+ project.task('helloWorld', type: HelloWorld)
+ }
+}
diff --git a/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/test/groovy/org/gradle/sample/BuildLogicFunctionalTest.groovy b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/test/groovy/org/gradle/sample/BuildLogicFunctionalTest.groovy
new file mode 100644
index 0000000..97ceb98
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/plugin/src/test/groovy/org/gradle/sample/BuildLogicFunctionalTest.groovy
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.sample
+
+import org.gradle.testkit.runner.GradleRunner
+import static org.gradle.testkit.runner.TaskOutcome.*
+import org.junit.Rule
+import org.junit.rules.TemporaryFolder
+import spock.lang.Specification
+
+class BuildLogicFunctionalTest extends Specification {
+
+ @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
+ File buildFile
+
+ // START SNIPPET functional-test-classpath-setup
+ def setup() {
+ buildFile = testProjectDir.newFile('build.gradle')
+
+ def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt")
+ if (pluginClasspathResource == null) {
+ throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.")
+ }
+
+ def pluginClasspath = pluginClasspathResource.readLines()
+ .collect { it.replace('\\', '\\\\') } // escape backslashes in Windows paths
+ .collect { "'$it'" }
+ .join(", ")
+
+ // Add the logic under test to the test build
+ buildFile << """
+ buildscript {
+ dependencies {
+ classpath files($pluginClasspath)
+ }
+ }
+ """
+ }
+ // END SNIPPET functional-test-classpath-setup
+
+ def "hello world task prints hello world"() {
+ given:
+ buildFile << 'apply plugin: org.gradle.sample.HelloWorldPlugin'
+
+ when:
+ def result = GradleRunner.create()
+ .withProjectDir(testProjectDir.root)
+ .withArguments('helloWorld')
+ .build()
+
+ then:
+ result.standardOutput.contains('Hello world!')
+ result.task(":helloWorld").outcome == SUCCESS
+ }
+}
diff --git a/subprojects/docs/src/samples/testKit/testKitSpockClasspath/settings.gradle b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/settings.gradle
new file mode 100644
index 0000000..788bd44
--- /dev/null
+++ b/subprojects/docs/src/samples/testKit/testKitSpockClasspath/settings.gradle
@@ -0,0 +1 @@
+include 'plugin', 'lib'
diff --git a/subprojects/docs/src/samples/userguide/artifacts/defineRepository/build.gradle b/subprojects/docs/src/samples/userguide/artifacts/defineRepository/build.gradle
index 402b25a..a209c51 100644
--- a/subprojects/docs/src/samples/userguide/artifacts/defineRepository/build.gradle
+++ b/subprojects/docs/src/samples/userguide/artifacts/defineRepository/build.gradle
@@ -241,3 +241,33 @@ repositories.localRepository {
dirs 'lib'
}
//END SNIPPET configure-resolver
+
+//START SNIPPET digest-authentication
+repositories {
+ maven {
+ url 'https://repo.mycompany.com/maven2'
+ credentials {
+ username 'user'
+ password 'password'
+ }
+ authentication {
+ digest(DigestAuthentication)
+ }
+ }
+}
+//END SNIPPET digest-authentication
+
+//START SNIPPET preemptive-authentication
+repositories {
+ maven {
+ url 'https://repo.mycompany.com/maven2'
+ credentials {
+ username 'user'
+ password 'password'
+ }
+ authentication {
+ basic(BasicAuthentication)
+ }
+ }
+}
+//END SNIPPET preemptive-authentication
diff --git a/subprojects/docs/src/samples/userguide/files/copy/build.gradle b/subprojects/docs/src/samples/userguide/files/copy/build.gradle
index d51a20d..3745eb9 100644
--- a/subprojects/docs/src/samples/userguide/files/copy/build.gradle
+++ b/subprojects/docs/src/samples/userguide/files/copy/build.gradle
@@ -109,6 +109,10 @@ task filter(type: Copy) {
filter { String line ->
"[$line]"
}
+ // Use a closure to remove lines
+ filter { String line ->
+ line.startsWith('-') ? null : line
+ }
}
// END SNIPPET filter-files
@@ -116,4 +120,4 @@ task test {
dependsOn tasks.withType(Copy)
dependsOn copyMethod
dependsOn copyMethodWithExplicitDependencies
-}
\ No newline at end of file
+}
diff --git a/subprojects/docs/src/samples/userguideOutput/basicRuleSourcePlugin-model-task.out b/subprojects/docs/src/samples/userguideOutput/basicRuleSourcePlugin-model-task.out
index f014184..c2f69b3 100644
--- a/subprojects/docs/src/samples/userguideOutput/basicRuleSourcePlugin-model-task.out
+++ b/subprojects/docs/src/samples/userguideOutput/basicRuleSourcePlugin-model-task.out
@@ -4,19 +4,114 @@
Root project
------------------------------------------------------------
-model
- person
- firstName = John
- lastName = Smith
- tasks
- components = task ':components'
- dependencies = task ':dependencies'
- dependencyInsight = task ':dependencyInsight'
- hello = task ':hello'
- help = task ':help'
- init = task ':init'
- model = task ':model'
- projects = task ':projects'
- properties = task ':properties'
- tasks = task ':tasks'
- wrapper = task ':wrapper'
++ model
+ + person
+ | Type: Person
+ | Creator: PersonRules#person
+ | Rules:
+ ⤷ PersonRules#setFirstName
+ ⤷ model.person
+ + age
+ | Type: int
+ | Creator: PersonRules#person
+ + children
+ | Type: org.gradle.model.collection.ManagedSet<Person>
+ | Creator: PersonRules#person
+ + employed
+ | Type: boolean
+ | Creator: PersonRules#person
+ + father
+ | Type: Person
+ | Creator: PersonRules#person
+ + firstName
+ | Type: java.lang.String
+ | Value: John
+ | Creator: PersonRules#person
+ + homeDirectory
+ | Type: java.io.File
+ | Creator: PersonRules#person
+ + id
+ | Type: java.lang.Long
+ | Creator: PersonRules#person
+ + lastName
+ | Type: java.lang.String
+ | Value: Smith
+ | Creator: PersonRules#person
+ + maritalStatus
+ | Type: MaritalStatus
+ | Creator: PersonRules#person
+ + mother
+ | Type: Person
+ | Creator: PersonRules#person
+ + tasks
+ | Type: org.gradle.model.ModelMap<org.gradle.api.Task>
+ | Creator: Project.<init>.tasks()
+ | Rules:
+ ⤷ PersonRules#createHelloTask
+ + components
+ | Type: org.gradle.api.reporting.components.ComponentReport
+ | Value: task ':components'
+ | Creator: tasks.addPlaceholderAction(components)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + dependencies
+ | Type: org.gradle.api.tasks.diagnostics.DependencyReportTask
+ | Value: task ':dependencies'
+ | Creator: tasks.addPlaceholderAction(dependencies)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + dependencyInsight
+ | Type: org.gradle.api.tasks.diagnostics.DependencyInsightReportTask
+ | Value: task ':dependencyInsight'
+ | Creator: tasks.addPlaceholderAction(dependencyInsight)
+ | Rules:
+ ⤷ HelpTasksPlugin.Rules#addDefaultDependenciesReportConfiguration
+ ⤷ copyToTaskContainer
+ + hello
+ | Type: org.gradle.api.Task
+ | Value: task ':hello'
+ | Creator: PersonRules#createHelloTask > create(hello)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + help
+ | Type: org.gradle.configuration.Help
+ | Value: task ':help'
+ | Creator: tasks.addPlaceholderAction(help)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + init
+ | Type: org.gradle.buildinit.tasks.InitBuild
+ | Value: task ':init'
+ | Creator: tasks.addPlaceholderAction(init)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + model
+ | Type: org.gradle.api.reporting.model.ModelReport
+ | Value: task ':model'
+ | Creator: tasks.addPlaceholderAction(model)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + projects
+ | Type: org.gradle.api.tasks.diagnostics.ProjectReportTask
+ | Value: task ':projects'
+ | Creator: tasks.addPlaceholderAction(projects)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + properties
+ | Type: org.gradle.api.tasks.diagnostics.PropertyReportTask
+ | Value: task ':properties'
+ | Creator: tasks.addPlaceholderAction(properties)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + tasks
+ | Type: org.gradle.api.tasks.diagnostics.TaskReportTask
+ | Value: task ':tasks'
+ | Creator: tasks.addPlaceholderAction(tasks)
+ | Rules:
+ ⤷ copyToTaskContainer
+ + wrapper
+ | Type: org.gradle.api.tasks.wrapper.Wrapper
+ | Value: task ':wrapper'
+ | Creator: tasks.addPlaceholderAction(wrapper)
+ | Rules:
+ ⤷ copyToTaskContainer
diff --git a/subprojects/docs/src/samples/userguideOutput/newJavaComponentReport.out b/subprojects/docs/src/samples/userguideOutput/newJavaComponentReport.out
new file mode 100644
index 0000000..0ed1cf7
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/newJavaComponentReport.out
@@ -0,0 +1,29 @@
+:components
+
+------------------------------------------------------------
+Root project
+------------------------------------------------------------
+
+JVM library 'main'
+------------------
+
+Source sets
+ Java source 'main:java'
+ srcDir: src/main/java
+ Java source 'main:mySourceSet'
+ srcDir: src/main/mySourceSet
+ JVM resources 'main:resources'
+ srcDir: src/main/resources
+
+Binaries
+ Jar 'mainJar'
+ build using task: :mainJar
+ platform: java7
+ tool chain: JDK 7 (1.7)
+ Jar file: build/jars/mainJar/main.jar
+
+Note: currently not all plugins register their components, so some components may not be visible here.
+
+BUILD SUCCESSFUL
+
+Total time: 1 secs
diff --git a/subprojects/docs/src/samples/userguideOutput/newJavaMultiComponents-clientJar.out b/subprojects/docs/src/samples/userguideOutput/newJavaMultiComponents-clientJar.out
new file mode 100644
index 0000000..f726630
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/newJavaMultiComponents-clientJar.out
@@ -0,0 +1,9 @@
+:util:compileMainJarMainJava
+:util:createMainJar
+:util:mainJar
+:compileClientJarClientJava
+:createClientJar
+:clientJar
+
+BUILD SUCCESSFUL
+
diff --git a/subprojects/docs/src/samples/userguideOutput/newJavaMultiComponents-serverJar.out b/subprojects/docs/src/samples/userguideOutput/newJavaMultiComponents-serverJar.out
new file mode 100644
index 0000000..ed03b5f
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/newJavaMultiComponents-serverJar.out
@@ -0,0 +1,9 @@
+:compileCoreJarCoreJava
+:processCoreJarCoreResources
+:createCoreJar
+:coreJar
+:compileServerJarServerJava
+:createServerJar
+:serverJar
+
+BUILD SUCCESSFUL
diff --git a/subprojects/docs/src/samples/userguideOutput/newJavaQuickstart.out b/subprojects/docs/src/samples/userguideOutput/newJavaQuickstart.out
new file mode 100644
index 0000000..f21e891
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/newJavaQuickstart.out
@@ -0,0 +1,9 @@
+:compileMainJarMainJava
+:processMainJarMainResources
+:createMainJar
+:mainJar
+:assemble
+:check UP-TO-DATE
+:build
+
+BUILD SUCCESSFUL
diff --git a/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms-java6MainJar.out b/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms-java6MainJar.out
new file mode 100644
index 0000000..fc3fa1d
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms-java6MainJar.out
@@ -0,0 +1,8 @@
+:core:compileJava6MainJarMainJava UP-TO-DATE
+:core:compileJava6MainJarMainJava6 UP-TO-DATE
+:core:processJava6MainJarMainResources UP-TO-DATE
+:core:createJava6MainJar UP-TO-DATE
+:core:java6MainJar UP-TO-DATE
+
+BUILD SUCCESSFUL
+
diff --git a/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms-server.out b/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms-server.out
new file mode 100644
index 0000000..772b748
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms-server.out
@@ -0,0 +1,20 @@
+:core:compileJava5MainJarMainJava UP-TO-DATE
+:core:processJava5MainJarMainResources UP-TO-DATE
+:core:createJava5MainJar UP-TO-DATE
+:core:java5MainJar UP-TO-DATE
+:server:compileJava5MainJarMainJava
+:server:createJava5MainJar
+:server:java5MainJar
+:core:compileJava6MainJarMainJava UP-TO-DATE
+:core:compileJava6MainJarMainJava6 UP-TO-DATE
+:core:processJava6MainJarMainResources UP-TO-DATE
+:core:createJava6MainJar UP-TO-DATE
+:core:java6MainJar UP-TO-DATE
+:server:compileJava6MainJarMainJava
+:server:createJava6MainJar
+:server:java6MainJar
+:server:assemble
+:server:check UP-TO-DATE
+:server:build
+
+BUILD SUCCESSFUL
diff --git a/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms.out b/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms.out
new file mode 100644
index 0000000..79dd0ec
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/newJavaTargetPlatforms.out
@@ -0,0 +1,14 @@
+:core:compileJava5MainJarMainJava
+:core:processJava5MainJarMainResources
+:core:createJava5MainJar
+:core:java5MainJar
+:core:compileJava6MainJarMainJava
+:core:compileJava6MainJarMainJava6
+:core:processJava6MainJarMainResources
+:core:createJava6MainJar
+:core:java6MainJar
+:core:assemble
+:core:check UP-TO-DATE
+:core:build
+
+BUILD SUCCESSFUL
diff --git a/subprojects/docs/src/samples/userguideOutput/playComponentReport.out b/subprojects/docs/src/samples/userguideOutput/playComponentReport.out
new file mode 100644
index 0000000..7d186f0
--- /dev/null
+++ b/subprojects/docs/src/samples/userguideOutput/playComponentReport.out
@@ -0,0 +1,38 @@
+:components
+
+------------------------------------------------------------
+Root project
+------------------------------------------------------------
+
+Play Application 'play'
+-----------------------
+
+Source sets
+ Java source 'play:java'
+ srcDir: app
+ includes: **/*.java
+ JavaScript source 'play:javaScript'
+ srcDir: app/assets
+ includes: **/*.js
+ JVM resources 'play:resources'
+ srcDir: conf
+ Routes source 'play:routes'
+ srcDir: conf
+ includes: routes, *.routes
+ Scala source 'play:scala'
+ srcDir: app
+ includes: **/*.scala
+ Twirl template source 'play:twirlTemplates'
+ srcDir: app
+ includes: **/*.html
+
+Binaries
+ Play Application Jar 'playBinary'
+ build using task: :playBinary
+ platform: Play Platform (Play 2.3.9, Scala: 2.11, Java: Java SE 8)
+
+Note: currently not all plugins register their components, so some components may not be visible here.
+
+BUILD SUCCESSFUL
+
+Total time: 1 secs
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/cdt/model/CprojectSettings.groovy b/subprojects/ide-native/src/main/groovy/org/gradle/ide/cdt/model/CprojectSettings.groovy
index c8189b4..4290436 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/cdt/model/CprojectSettings.groovy
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/cdt/model/CprojectSettings.groovy
@@ -37,12 +37,12 @@ class CprojectSettings {
includeRoots = project.files()
libs = project.files()
- binary.source.withType(HeaderExportingSourceSet).all {
+ binary.sources.withType(HeaderExportingSourceSet).all {
includeRoots.builtBy(it.exportedHeaders) // have to manually add because we use srcDirs in from, not the real collection
includeRoots.from(it.exportedHeaders.srcDirs)
}
- binary.source.withType(CppSourceSet).all { sourceSet ->
+ binary.sources.withType(CppSourceSet).all { sourceSet ->
sourceSet.libs.each { NativeDependencySet lib ->
this.libs.from(lib.linkFiles)
this.includeRoots.from(lib.includeRoots)
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioExtension.java b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioExtension.java
index 19905b3..329eb36 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioExtension.java
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioExtension.java
@@ -17,19 +17,19 @@ package org.gradle.ide.visualstudio.internal;
import org.gradle.api.NamedDomainObjectSet;
import org.gradle.api.internal.file.FileResolver;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
import org.gradle.ide.visualstudio.VisualStudioProject;
import org.gradle.ide.visualstudio.VisualStudioSolution;
import org.gradle.internal.reflect.Instantiator;
-import org.gradle.nativeplatform.internal.resolve.ProjectLocator;
public class DefaultVisualStudioExtension implements VisualStudioExtensionInternal {
private final VisualStudioProjectRegistry projectRegistry;
private final VisualStudioSolutionRegistry solutionRegistry;
- public DefaultVisualStudioExtension(Instantiator instantiator, ProjectLocator projectLocator, FileResolver fileResolver) {
+ public DefaultVisualStudioExtension(Instantiator instantiator, ProjectModelResolver projectModelResolver, FileResolver fileResolver) {
VisualStudioProjectMapper projectMapper = new VisualStudioProjectMapper();
projectRegistry = new VisualStudioProjectRegistry(fileResolver, projectMapper, instantiator);
- VisualStudioProjectResolver projectResolver = new VisualStudioProjectResolver(projectLocator);
+ VisualStudioProjectResolver projectResolver = new VisualStudioProjectResolver(projectModelResolver);
solutionRegistry = new VisualStudioSolutionRegistry(fileResolver, projectResolver, instantiator);
}
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioProject.groovy b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioProject.groovy
index 8395f31..7a18518 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioProject.groovy
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/DefaultVisualStudioProject.groovy
@@ -22,12 +22,12 @@ import org.gradle.api.internal.file.FileResolver
import org.gradle.ide.visualstudio.VisualStudioProject
import org.gradle.ide.visualstudio.XmlConfigFile
import org.gradle.internal.reflect.Instantiator
-import org.gradle.language.nativeplatform.HeaderExportingSourceSet
import org.gradle.language.base.LanguageSourceSet
+import org.gradle.language.nativeplatform.HeaderExportingSourceSet
import org.gradle.language.rc.WindowsResourceSet
-import org.gradle.nativeplatform.NativeBinary
import org.gradle.nativeplatform.NativeBinarySpec
import org.gradle.nativeplatform.NativeComponentSpec
+import org.gradle.nativeplatform.internal.NativeBinarySpecInternal
import org.gradle.util.CollectionUtils
/**
* A VisualStudio project represents a set of binaries for a component that may vary in build type and target platform.
@@ -39,7 +39,7 @@ class DefaultVisualStudioProject extends AbstractBuildableModelElement implement
private final NativeComponentSpec component
private final List<File> additionalFiles = []
final Set<LanguageSourceSet> sources = new LinkedHashSet<LanguageSourceSet>()
- private final Map<NativeBinary, VisualStudioProjectConfiguration> configurations = [:]
+ private final Map<NativeBinarySpec, VisualStudioProjectConfiguration> configurations = [:]
DefaultVisualStudioProject(String name, NativeComponentSpec component, FileResolver fileResolver, Instantiator instantiator) {
this.name = name
@@ -117,7 +117,8 @@ class DefaultVisualStudioProject extends AbstractBuildableModelElement implement
void addConfiguration(NativeBinarySpec nativeBinary, VisualStudioProjectConfiguration configuration) {
configurations[nativeBinary] = configuration
- source nativeBinary.source
+ def specInternal = nativeBinary as NativeBinarySpecInternal
+ source specInternal.inputs
}
VisualStudioProjectConfiguration getConfiguration(NativeBinarySpec nativeBinary) {
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfiguration.groovy b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfiguration.groovy
index 03066d9..ce77a52 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfiguration.groovy
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfiguration.groovy
@@ -15,12 +15,11 @@
*/
package org.gradle.ide.visualstudio.internal
-
import org.gradle.api.plugins.ExtensionAware
+import org.gradle.language.PreprocessingTool
import org.gradle.language.nativeplatform.HeaderExportingSourceSet
import org.gradle.nativeplatform.NativeBinarySpec
import org.gradle.nativeplatform.internal.NativeBinarySpecInternal
-import org.gradle.language.PreprocessingTool
import org.gradle.nativeplatform.toolchain.internal.MacroArgsConverter
class VisualStudioProjectConfiguration {
@@ -93,8 +92,10 @@ class VisualStudioProjectConfiguration {
List<File> getIncludePaths() {
def includes = [] as Set
- binary.source.withType(HeaderExportingSourceSet).each { HeaderExportingSourceSet sourceSet ->
- includes.addAll sourceSet.exportedHeaders.srcDirs
+ binary.inputs.each { sourceSet ->
+ if (sourceSet instanceof HeaderExportingSourceSet) {
+ includes.addAll sourceSet.exportedHeaders.srcDirs
+ }
}
binary.libs*.includeRoots.each {
includes.addAll it.files
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectResolver.java b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectResolver.java
index 575b776..bd13179 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectResolver.java
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectResolver.java
@@ -16,31 +16,30 @@
package org.gradle.ide.visualstudio.internal;
-import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
import org.gradle.ide.visualstudio.VisualStudioExtension;
import org.gradle.model.internal.core.ModelPath;
+import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.model.internal.type.ModelType;
import org.gradle.nativeplatform.NativeBinarySpec;
-import org.gradle.nativeplatform.internal.resolve.ProjectLocator;
public class VisualStudioProjectResolver {
- private final ProjectLocator projectLocator;
+ private final ProjectModelResolver projectModelResolver;
- public VisualStudioProjectResolver(ProjectLocator projectLocator) {
- this.projectLocator = projectLocator;
+ public VisualStudioProjectResolver(ProjectModelResolver projectModelResolver) {
+ this.projectModelResolver = projectModelResolver;
}
public VisualStudioProjectConfiguration lookupProjectConfiguration(NativeBinarySpec nativeBinary) {
// Looks in the correct project registry for this binary
- ProjectInternal componentProject = getComponentProject(nativeBinary);
- VisualStudioExtension visualStudioExtension = componentProject.getModelRegistry().realize(ModelPath.path("visualStudio"), ModelType.of(VisualStudioExtension.class));
+ VisualStudioExtension visualStudioExtension = getComponentModel(nativeBinary).realize(ModelPath.path("visualStudio"), ModelType.of(VisualStudioExtension.class));
VisualStudioProjectRegistry projectRegistry = ((VisualStudioExtensionInternal) visualStudioExtension).getProjectRegistry();
return projectRegistry.getProjectConfiguration(nativeBinary);
}
- private ProjectInternal getComponentProject(NativeBinarySpec nativeBinary) {
+ private ModelRegistry getComponentModel(NativeBinarySpec nativeBinary) {
String projectPath = nativeBinary.getComponent().getProjectPath();
- return projectLocator.locateProject(projectPath);
+ return projectModelResolver.resolveProjectModel(projectPath);
}
}
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/plugins/VisualStudioPlugin.java b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/plugins/VisualStudioPlugin.java
index 08fcce2..1be7c45 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/plugins/VisualStudioPlugin.java
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/plugins/VisualStudioPlugin.java
@@ -19,6 +19,7 @@ package org.gradle.ide.visualstudio.plugins;
import org.gradle.api.*;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.api.internal.project.ProjectIdentifier;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
import org.gradle.api.tasks.Delete;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.ide.visualstudio.VisualStudioProject;
@@ -37,7 +38,6 @@ import org.gradle.model.Mutate;
import org.gradle.model.RuleSource;
import org.gradle.nativeplatform.NativeBinarySpec;
import org.gradle.nativeplatform.NativeComponentSpec;
-import org.gradle.nativeplatform.internal.resolve.ProjectLocator;
import org.gradle.nativeplatform.plugins.NativeComponentModelPlugin;
import org.gradle.platform.base.BinaryContainer;
@@ -56,10 +56,10 @@ public class VisualStudioPlugin implements Plugin<Project> {
@Model
public static VisualStudioExtensionInternal visualStudio(ServiceRegistry serviceRegistry) {
Instantiator instantiator = serviceRegistry.get(Instantiator.class);
- ProjectLocator projectLocator = serviceRegistry.get(ProjectLocator.class);
+ ProjectModelResolver projectModelResolver = serviceRegistry.get(ProjectModelResolver.class);
FileResolver fileResolver = serviceRegistry.get(FileResolver.class);
- return instantiator.newInstance(DefaultVisualStudioExtension.class, instantiator, projectLocator, fileResolver);
+ return instantiator.newInstance(DefaultVisualStudioExtension.class, instantiator, projectModelResolver, fileResolver);
}
@Mutate
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateFiltersFileTask.groovy b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateFiltersFileTask.groovy
index d1640eb..b5a9d54 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateFiltersFileTask.groovy
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateFiltersFileTask.groovy
@@ -14,10 +14,11 @@
* limitations under the License.
*/
package org.gradle.ide.visualstudio.tasks
+
import org.gradle.api.Incubating
+import org.gradle.ide.visualstudio.tasks.internal.RelativeFileNameTransformer
import org.gradle.ide.visualstudio.VisualStudioProject
import org.gradle.ide.visualstudio.internal.DefaultVisualStudioProject
-import org.gradle.ide.visualstudio.tasks.internal.RelativeFileNameTransformer
import org.gradle.ide.visualstudio.tasks.internal.VisualStudioFiltersFile
import org.gradle.plugins.ide.api.XmlGeneratorTask
@@ -62,4 +63,4 @@ class GenerateFiltersFileTask extends XmlGeneratorTask<VisualStudioFiltersFile>
protected VisualStudioFiltersFile create() {
return new VisualStudioFiltersFile(xmlTransformer, RelativeFileNameTransformer.forFile(project.rootDir, visualStudioProject.filtersFile.location))
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateProjectFileTask.groovy b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateProjectFileTask.groovy
index a7922c4..e6d977d 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateProjectFileTask.groovy
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/GenerateProjectFileTask.groovy
@@ -15,11 +15,11 @@
*/
package org.gradle.ide.visualstudio.tasks
import org.gradle.api.Incubating
+import org.gradle.ide.visualstudio.tasks.internal.RelativeFileNameTransformer
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.ide.visualstudio.VisualStudioProject
import org.gradle.ide.visualstudio.internal.DefaultVisualStudioProject
-import org.gradle.ide.visualstudio.tasks.internal.RelativeFileNameTransformer
import org.gradle.ide.visualstudio.tasks.internal.VisualStudioProjectFile
import org.gradle.plugins.ide.api.XmlGeneratorTask
@@ -109,4 +109,4 @@ class GenerateProjectFileTask extends XmlGeneratorTask<VisualStudioProjectFile>
return exe + " " + args.trim()
}
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/internal/AbsoluteFileNameTransformer.java b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/internal/AbsoluteFileNameTransformer.java
deleted file mode 100644
index e3edc00..0000000
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/internal/AbsoluteFileNameTransformer.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.ide.visualstudio.tasks.internal;
-
-import org.gradle.api.Transformer;
-
-import java.io.File;
-
-public class AbsoluteFileNameTransformer implements Transformer<String, File> {
- public String transform(File file) {
- return file.getAbsolutePath();
- }
-}
\ No newline at end of file
diff --git a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformer.java b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformer.java
index 1530c4d..3f14eb8 100644
--- a/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformer.java
+++ b/subprojects/ide-native/src/main/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformer.java
@@ -42,6 +42,14 @@ public class RelativeFileNameTransformer implements Transformer<String, File> {
return new RelativeFileNameTransformer(rootDir, currentDirectory);
}
+ public static Transformer<String, File> from(File file) {
+ if (file.isFile()) {
+ File parentFile = file.getParentFile();
+ return new RelativeFileNameTransformer(parentFile, parentFile);
+ }
+ return new RelativeFileNameTransformer(file, file);
+ }
+
public String transform(File file) {
String canonicalRoot;
String canonicalFrom;
@@ -93,4 +101,4 @@ public class RelativeFileNameTransformer implements Transformer<String, File> {
}
return split;
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfigurationTest.groovy b/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfigurationTest.groovy
index 0db9442..b498265 100644
--- a/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfigurationTest.groovy
+++ b/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectConfigurationTest.groovy
@@ -135,10 +135,10 @@ class VisualStudioProjectConfigurationTest extends Specification {
}
def "include paths include component headers"() {
- final sources = new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet)
+ final inputs = new DefaultDomainObjectSet(LanguageSourceSet)
when:
- exeBinary.source >> sources
+ exeBinary.inputs >> inputs
exeBinary.libs >> []
then:
@@ -151,10 +151,10 @@ class VisualStudioProjectConfigurationTest extends Specification {
def sourceSet = Mock(LanguageSourceSet)
def sourceSet1 = headerSourceSet(file1, file2)
def sourceSet2 = headerSourceSet(file3)
- sources.addAll(sourceSet, sourceSet1, sourceSet2)
+ inputs.addAll(sourceSet, sourceSet1, sourceSet2)
and:
- exeBinary.source >> sources
+ exeBinary.inputs >> inputs
exeBinary.libs >> []
then:
@@ -170,7 +170,7 @@ class VisualStudioProjectConfigurationTest extends Specification {
def deps1 = dependencySet(file1, file2)
def deps2 = dependencySet(file3)
- exeBinary.source >> new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet)
+ exeBinary.inputs >> new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet)
exeBinary.libs >> [deps1, deps2]
then:
diff --git a/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectRegistryTest.groovy b/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectRegistryTest.groovy
index a15c914..c909dd1 100644
--- a/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectRegistryTest.groovy
+++ b/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/internal/VisualStudioProjectRegistryTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.ide.visualstudio.internal
+
import org.gradle.api.internal.DefaultDomainObjectSet
import org.gradle.api.internal.file.FileResolver
import org.gradle.internal.reflect.DirectInstantiator
@@ -24,7 +25,7 @@ import org.gradle.nativeplatform.internal.NativeExecutableBinarySpecInternal
import spock.lang.Specification
class VisualStudioProjectRegistryTest extends Specification {
- private DefaultDomainObjectSet<LanguageSourceSet> sources = new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet)
+ private Set<LanguageSourceSet> sources = new DefaultDomainObjectSet<>(LanguageSourceSet)
def fileResolver = Mock(FileResolver)
def visualStudioProjectMapper = Mock(VisualStudioProjectMapper)
def registry = new VisualStudioProjectRegistry(fileResolver, visualStudioProjectMapper, DirectInstantiator.INSTANCE)
@@ -36,7 +37,7 @@ class VisualStudioProjectRegistryTest extends Specification {
when:
visualStudioProjectMapper.mapToConfiguration(executableBinary) >> new VisualStudioProjectMapper.ProjectConfigurationNames("vsProject", "vsConfig", "vsPlatform")
executableBinary.component >> executable
- executableBinary.source >> sources
+ executableBinary.inputs >> sources
and:
registry.addProjectConfiguration(executableBinary)
@@ -57,8 +58,8 @@ class VisualStudioProjectRegistryTest extends Specification {
when:
visualStudioProjectMapper.mapToConfiguration(executableBinary1) >> new VisualStudioProjectMapper.ProjectConfigurationNames("vsProject", "vsConfig1", "vsPlatform")
visualStudioProjectMapper.mapToConfiguration(executableBinary2) >> new VisualStudioProjectMapper.ProjectConfigurationNames("vsProject", "vsConfig2", "vsPlatform")
- executableBinary1.source >> sources
- executableBinary2.source >> sources
+ executableBinary1.inputs >> sources
+ executableBinary2.inputs >> sources
and:
registry.addProjectConfiguration(executableBinary1)
@@ -92,8 +93,8 @@ class VisualStudioProjectRegistryTest extends Specification {
when:
visualStudioProjectMapper.mapToConfiguration(executableBinary1) >> new VisualStudioProjectMapper.ProjectConfigurationNames("vsProject", "vsConfig1", "vsPlatform")
visualStudioProjectMapper.mapToConfiguration(executableBinary2) >> new VisualStudioProjectMapper.ProjectConfigurationNames("vsProject", "vsConfig2", "vsPlatform")
- executableBinary1.source >> new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet, [sourceCommon, source1])
- executableBinary2.source >> new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet, [sourceCommon, source2])
+ executableBinary1.inputs >> new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet, [sourceCommon, source1])
+ executableBinary2.inputs >> new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet, [sourceCommon, source2])
and:
registry.addProjectConfiguration(executableBinary1)
diff --git a/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformerTest.groovy b/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformerTest.groovy
index 7d970dc..90a3cb0 100644
--- a/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformerTest.groovy
+++ b/subprojects/ide-native/src/test/groovy/org/gradle/ide/visualstudio/tasks/internal/RelativeFileNameTransformerTest.groovy
@@ -16,6 +16,9 @@
package org.gradle.ide.visualstudio.tasks.internal
+import org.gradle.test.fixtures.file.TestFile
+import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.junit.Rule
import spock.lang.Specification
import static org.gradle.util.TextUtil.normaliseFileSeparators
@@ -23,6 +26,9 @@ import static org.gradle.util.TextUtil.normaliseFileSeparators
class RelativeFileNameTransformerTest extends Specification {
static rootDir = new File("root")
+ @Rule
+ TestNameTestDirectoryProvider testDir = new TestNameTestDirectoryProvider()
+
def "returns canonical path where file outside of root"() {
expect:
transform(relative, file) == normaliseFileSeparators(file.canonicalPath)
@@ -116,7 +122,45 @@ class RelativeFileNameTransformerTest extends Specification {
"subdir/another" | "../.."
}
+ def "finds relative path to descendant from and to both files and directories "() {
+ setup:
+ TestFile parentDir = testDir.createDir('parent')
+ parentDir.create {
+ file 'parent.txt'
+ dir1 {
+ file 'file1.txt'
+ dir2 {
+ file 'file2.txt'
+ dir3 {
+ file 'file3.txt'
+ }
+ }
+
+ }
+ }
+
+ when:
+ File startingDir = parentDir.getParentFile()
+
+ then:
+ pathToDescendant(new File("${startingDir}/$parent"), new File("${startingDir}/$child")) == expected
+
+ where:
+ parent | child | expected
+ "parent/" | "parent/dir1/file1.txt" | 'dir1/file1.txt'
+ "parent/parent.txt" | "parent/dir1/file1.txt" | 'dir1/file1.txt'
+ "parent/" | "parent/dir1/" | 'dir1'
+ "parent/dir1/" | "parent/dir1/dir2/file2.txt" | 'dir2/file2.txt'
+ "parent/dir1/" | "parent/dir1/dir2/dir3/file3.txt" | 'dir2/dir3/file3.txt'
+ }
+
String transform(File from, File to) {
return normaliseFileSeparators(RelativeFileNameTransformer.forDirectory(rootDir, from).transform(to))
}
+
+ String pathToDescendant(File parent, File to) {
+ assert parent.exists()
+ assert to.exists()
+ return normaliseFileSeparators(RelativeFileNameTransformer.from(parent).transform(to))
+ }
}
diff --git a/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseClasspathIntegrationTest.groovy b/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseClasspathIntegrationTest.groovy
index c16076b..c7c691c 100644
--- a/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseClasspathIntegrationTest.groovy
+++ b/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseClasspathIntegrationTest.groovy
@@ -641,6 +641,121 @@ apply plugin: 'eclipse'
assert classpath.sources.size() == 2
}
+ @Issue('GRADLE-3335')
+ @Test
+ void handlesExcludeOnSharedSourceFolders() {
+ given:
+ def buildFile = file("build.gradle") << """
+apply plugin: 'java'
+apply plugin: 'eclipse'
+
+sourceSets {
+ main {
+ java {
+ srcDirs = ['src']
+ }
+ resources{
+ srcDirs = ['src']
+ exclude '**/*.java'
+ }
+ }
+}
+"""
+ buildFile.parentFile.file("src").createDir()
+
+ when:
+ executer.usingBuildScript(buildFile).withTasks('eclipseClasspath').run()
+
+ then:
+ assert classpath.entries.size() == 3
+ assert classpath.sources.size() == 1
+ assert classpath.entries.find { it. at kind == 'src' }.attribute("excluding") == null
+
+ when:
+ buildFile.text = """
+apply plugin: 'java'
+apply plugin: 'eclipse'
+
+sourceSets {
+ main {
+ java {
+ srcDirs = ['src']
+ exclude '**/*.xml'
+ }
+ resources{
+ srcDirs = ['src']
+ exclude '**/*.xml'
+ }
+ }
+}
+"""
+ when:
+ executer.usingBuildScript(buildFile).withTasks('cleanEclipseClasspath', 'eclipseClasspath').run()
+ then:
+ assert classpath.entries.size() == 3
+ assert classpath.sources.size() == 1
+ assert classpath.entries.find { it. at kind == 'src' }.attribute("excluding") == "**/*.xml"
+ }
+
+ @Test
+ void handlesIncludesOnSharedSourceFolders() {
+ given:
+ def buildFile = file("build.gradle") << """
+apply plugin: 'java'
+apply plugin: 'eclipse'
+
+sourceSets {
+ main {
+ java {
+ srcDirs = ['src']
+ include '**/*.java'
+ }
+ resources{
+ srcDirs = ['src']
+ include '**/*.properties'
+ }
+ }
+}
+"""
+ buildFile.parentFile.file("src").createDir()
+
+ when:
+ executer.usingBuildScript(buildFile).withTasks('eclipseClasspath').run()
+
+ then:
+ assert classpath.entries.size() == 3
+ assert classpath.sources.size() == 1
+ assert classpath.entries.find { it. at kind == 'src' }.attribute("including") == "**/*.properties|**/*.java"
+
+
+ when:
+ buildFile.text = """
+apply plugin: 'java'
+apply plugin: 'eclipse'
+
+sourceSets {
+ main {
+ java {
+ srcDirs = ['src']
+ include '**/*.java'
+ }
+ resources{
+ srcDirs = ['src']
+ }
+ }
+}
+"""
+ buildFile.parentFile.file("src").createDir()
+
+ when:
+ executer.usingBuildScript(buildFile).withTasks('cleanEclipse', 'eclipseClasspath').run()
+
+ then:
+ assert classpath.entries.size() == 3
+ assert classpath.sources.size() == 1
+ assert classpath.entries.find { it. at kind == 'src' }.attribute("including") == null
+ }
+
@Test
void canAccessXmlModelBeforeAndAfterGeneration() {
//given
@@ -869,4 +984,5 @@ dependencies {
libraries[0].assertHasJar(otherLib)
assert classpath.containers == ['org.eclipse.jdt.launching.JRE_CONTAINER', 'org.scala-ide.sdt.launching.SCALA_CONTAINER']
}
+
}
diff --git a/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseLinkedResourceIntegrationTest.groovy b/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseLinkedResourceIntegrationTest.groovy
new file mode 100644
index 0000000..ac6d808
--- /dev/null
+++ b/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseLinkedResourceIntegrationTest.groovy
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.plugins.ide.eclipse
+
+class EclipseLinkedResourceIntegrationTest extends AbstractEclipseIntegrationSpec {
+
+ def "can reference linked resources as source folders"() {
+ given:
+ multiProjectWithSiblingSourceFolders()
+ when:
+ run("eclipse")
+ then:
+
+ classpath("projectA").sources[0] == "src"
+ classpath("projectA").sources[1] == "projectB-src"
+ classpath("projectA").sources[2] == "sibling-source"
+ classpath("projectA").sources[3] == "source-c"
+ classpath("projectA").sources[4] == testDirectory.getName() + "-src"
+
+ and:
+ project("projectA").assertHasLinkedResources("projectB-src", "sibling-source", "source-c", "${testDirectory.name}-src")
+ }
+
+ def multiProjectWithSiblingSourceFolders() {
+ settingsFile.text = """
+rootProject.name = 'multiprojectroot'
+include 'projectA'
+include 'projectB'
+include 'projectC'
+
+"""
+ buildFile.text = """
+allprojects {
+ apply plugin: 'java'
+ apply plugin: 'eclipse'
+}
+
+configure(project(":projectA")){
+ sourceSets {
+ main {
+ java {
+ srcDirs = ['src', '../projectB/src', '../projectB/sibling-source', '../projectC/source-c', '../src']
+ }
+ }
+ }
+}
+"""
+ file("projectA/src").mkdirs()
+ file("projectB/src").mkdirs()
+ file("projectB/sibling-source").mkdirs()
+ file("projectC/source-c").mkdirs()
+ file("src").mkdirs()
+ }
+}
diff --git a/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseProjectFixture.groovy b/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseProjectFixture.groovy
index 5d20ae9..71b25dd 100644
--- a/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseProjectFixture.groovy
+++ b/subprojects/ide/src/integTest/groovy/org/gradle/plugins/ide/eclipse/EclipseProjectFixture.groovy
@@ -56,4 +56,9 @@ class EclipseProjectFixture {
void assertHasBuilders(String... builders) {
assert getProject().buildSpec.buildCommand.name*.text() == builders as List
}
+
+ void assertHasLinkedResources(String... names) {
+ assert getProject().linkedResources.link.name*.text() == names as List
+ }
+
}
diff --git a/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolder.groovy b/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolder.groovy
index 7beef2d..4e4974e 100644
--- a/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolder.groovy
+++ b/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolder.groovy
@@ -24,6 +24,7 @@ class SourceFolder extends AbstractClasspathEntry {
List<String> excludes
//optional
File dir
+ String name;
SourceFolder(Node node) {
super(node)
@@ -43,15 +44,14 @@ class SourceFolder extends AbstractClasspathEntry {
'src'
}
- String getName() {
- dir.name
- }
-
String getAbsolutePath() {
dir.absolutePath
}
- void trimPath() {
+ void trim(String prefix = null) {
+ if(prefix != null){
+ name = prefix + "-" + name
+ }
path = name
}
@@ -73,7 +73,6 @@ class SourceFolder extends AbstractClasspathEntry {
if (nativeLibraryLocation != that.nativeLibraryLocation) { return false }
if (output != that.output) { return false }
if (path != that.path) { return false }
-
return true
}
@@ -87,6 +86,7 @@ class SourceFolder extends AbstractClasspathEntry {
result = 31 * result + (output != null ? output.hashCode() : 0);
result = 31 * result + excludes.hashCode();
result = 31 * result + includes.hashCode();
+ result = 31 * result + (name != null ? name.hashCode() : 0)
return result;
}
diff --git a/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/internal/SourceFoldersCreator.groovy b/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/internal/SourceFoldersCreator.groovy
index 114036f..fa5e512 100644
--- a/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/internal/SourceFoldersCreator.groovy
+++ b/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/eclipse/model/internal/SourceFoldersCreator.groovy
@@ -16,23 +16,20 @@
package org.gradle.plugins.ide.eclipse.model.internal
+import com.google.common.base.Equivalence
import org.gradle.api.file.DirectoryTree
import org.gradle.api.tasks.SourceSet
import org.gradle.plugins.ide.eclipse.model.ClasspathEntry
import org.gradle.plugins.ide.eclipse.model.EclipseClasspath
import org.gradle.plugins.ide.eclipse.model.SourceFolder
+import org.gradle.util.CollectionUtils
class SourceFoldersCreator {
void populateForClasspath(List<ClasspathEntry> entries, EclipseClasspath classpath) {
def provideRelativePath = { classpath.project.relativePath(it) }
- List regulars = getRegularSourceFolders(classpath.sourceSets, provideRelativePath)
-
- //externals are mapped to linked resources so we just need a name of the resource, without full path
- List trimmedExternals = getExternalSourceFolders(classpath.sourceSets, provideRelativePath).collect { SourceFolder folder ->
- folder.trimPath()
- folder
- }
+ List<SourceFolder> regulars = getRegularSourceFolders(classpath.sourceSets, provideRelativePath)
+ List trimmedExternals = getExternalSourceFolders(classpath.sourceSets, provideRelativePath)
entries.addAll(regulars)
entries.addAll(trimmedExternals)
}
@@ -55,14 +52,35 @@ class SourceFoldersCreator {
*/
List<SourceFolder> getExternalSourceFolders(Iterable<SourceSet> sourceSets, Closure provideRelativePath) {
def sourceFolders = projectRelativeFolders(sourceSets, provideRelativePath)
- return sourceFolders.findAll { it.path.contains('..') }
+ def externalSourceFolders = sourceFolders.findAll { it.path.contains('..') }
+
+ List<SourceFolder> trimmedSourceFolders = trimAndDedup(externalSourceFolders, getRegularSourceFolders(sourceSets, provideRelativePath).collect { it.name })
+ trimmedSourceFolders
+ }
+
+ private List<SourceFolder> trimAndDedup(ArrayList<SourceFolder> externalSourceFolders, givenSources) {
+ // externals are mapped to linked resources so we just need a name of the resource, without full path
+ // non unique folder names are naively deduped by adding parent filename as a prefix till unique
+ // since this seems like a rare edge case this simple approach should be enough
+ def trimmedSourceFolders = externalSourceFolders.collect { folder ->
+ folder.trim()
+ def parentFile = folder.dir.parentFile
+ while (givenSources.contains(folder.name) && parentFile != null) {
+ folder.trim(parentFile.name)
+ parentFile = parentFile.parentFile
+ }
+ givenSources.add(folder.name)
+ folder
+ }
+ trimmedSourceFolders
}
private List<SourceFolder> projectRelativeFolders(Iterable<SourceSet> sourceSets, Closure provideRelativePath) {
def entries = []
- def sortedSourceSets = sortSourceSetsAsPerUsualConvention(sourceSets.collect{it})
+ def sortedSourceSets = sortSourceSetsAsPerUsualConvention(sourceSets.collect { it })
sortedSourceSets.each { SourceSet sourceSet ->
+
def sortedSourceDirs = sortSourceDirsAsPerUsualConvention(sourceSet.allSource.srcDirTrees)
sortedSourceDirs.each { tree ->
@@ -70,8 +88,9 @@ class SourceFoldersCreator {
if (dir.isDirectory()) {
def folder = new SourceFolder(provideRelativePath(dir), null)
folder.dir = dir
- folder.includes = tree.patterns.includes as List
- folder.excludes = tree.patterns.excludes as List
+ folder.name = dir.name
+ folder.includes = getIncludesForTree(sourceSet, tree)
+ folder.excludes = getExcludesForTree(sourceSet, tree)
entries.add(folder)
}
}
@@ -79,9 +98,36 @@ class SourceFoldersCreator {
entries
}
+ private List<String> getExcludesForTree(SourceSet sourceSet, DirectoryTree directoryTree) {
+ def excludesByType = getFiltersForTreeGroupedByType(sourceSet, directoryTree, "excludes")
+ return CollectionUtils.intersection(excludesByType);
+ }
+
+ private List<String> getIncludesForTree(SourceSet sourceSet, DirectoryTree directoryTree) {
+ def includesByType = getFiltersForTreeGroupedByType(sourceSet, directoryTree, "includes")
+ if (includesByType.any { it.isEmpty() }) {
+ return []
+ } else {
+ List<String> allIncludes = CollectionUtils.flattenCollections(String.class, includesByType)
+ return CollectionUtils.dedup(allIncludes, Equivalence.equals());
+ }
+ }
+
+ private List<Set<String>> getFiltersForTreeGroupedByType(SourceSet sourceSet, DirectoryTree directoryTree, String filterOperation) {
+ // check for duplicate entries in java and resources
+ if (!CollectionUtils.intersection([sourceSet.allJava.srcDirs, sourceSet.resources.srcDirs]).contains(directoryTree.dir)) {
+ return [directoryTree.patterns."${filterOperation}" as List]
+ } else {
+ def resourcesFilter = sourceSet.resources.srcDirTrees.find { it.dir == directoryTree.dir }.patterns."${filterOperation}" as Set
+ def sourceFilters = sourceSet.allJava.srcDirTrees.find { it.dir == directoryTree.dir }.patterns."${filterOperation}" as Set
+ return [resourcesFilter, sourceFilters]
+ }
+ }
+
+
private List<SourceSet> sortSourceSetsAsPerUsualConvention(Collection<SourceSet> sourceSets) {
return sourceSets.sort { sourceSet ->
- switch(sourceSet.name) {
+ switch (sourceSet.name) {
case SourceSet.MAIN_SOURCE_SET_NAME: return 0
case SourceSet.TEST_SOURCE_SET_NAME: return 1
default: return 2
@@ -91,9 +137,13 @@ class SourceFoldersCreator {
private List<DirectoryTree> sortSourceDirsAsPerUsualConvention(Collection<DirectoryTree> sourceDirs) {
return sourceDirs.sort { sourceDir ->
- if (sourceDir.dir.path.endsWith("java")) { 0 }
- else if (sourceDir.dir.path.endsWith("resources")) { 2 }
- else { 1 }
+ if (sourceDir.dir.path.endsWith("java")) {
+ 0
+ } else if (sourceDir.dir.path.endsWith("resources")) {
+ 2
+ } else {
+ 1
+ }
}
}
}
diff --git a/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/internal/tooling/EclipseModelBuilder.java b/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/internal/tooling/EclipseModelBuilder.java
index f6f81d8..7d8c986 100644
--- a/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/internal/tooling/EclipseModelBuilder.java
+++ b/subprojects/ide/src/main/groovy/org/gradle/plugins/ide/internal/tooling/EclipseModelBuilder.java
@@ -45,7 +45,7 @@ public class EclipseModelBuilder implements ToolingModelBuilder {
public boolean canBuild(String modelName) {
return modelName.equals("org.gradle.tooling.model.eclipse.EclipseProject")
- || modelName.equals("org.gradle.tooling.model.eclipse.HierarchicalEclipseProject");
+ || modelName.equals("org.gradle.tooling.model.eclipse.HierarchicalEclipseProject");
}
public DefaultEclipseProject buildAll(String modelName, Project project) {
@@ -102,8 +102,9 @@ public class EclipseModelBuilder implements ToolingModelBuilder {
final String path = StringUtils.removeStart(projectDependency.getPath(), "/");
projectDependencies.add(new DefaultEclipseProjectDependency(path, projectMapping.get(projectDependency.getGradlePath()), projectDependency.isExported()));
} else if (entry instanceof SourceFolder) {
- String path = ((SourceFolder) entry).getPath();
- sourceDirectories.add(new DefaultEclipseSourceDirectory(path, project.file(path)));
+ final SourceFolder sourceFolder = (SourceFolder) entry;
+ String path = sourceFolder.getPath();
+ sourceDirectories.add(new DefaultEclipseSourceDirectory(path, sourceFolder.getDir()));
}
}
@@ -140,7 +141,7 @@ public class EclipseModelBuilder implements ToolingModelBuilder {
String name = internalProject.getName();
String description = GUtil.elvis(internalProject.getComment(), null);
DefaultEclipseProject eclipseProject =
- new DefaultEclipseProject(name, project.getPath(), description, project.getProjectDir(), children)
+ new DefaultEclipseProject(name, project.getPath(), description, project.getProjectDir(), children)
.setGradleProject(rootGradleProject.findByPath(project.getPath()));
for (DefaultEclipseProject child : children) {
diff --git a/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/EclipsePluginTest.groovy b/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/EclipsePluginTest.groovy
index 9f993be..47948a8 100644
--- a/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/EclipsePluginTest.groovy
+++ b/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/EclipsePluginTest.groovy
@@ -132,6 +132,9 @@ class EclipsePluginTest extends Specification {
assert eclipseProjectTask instanceof GenerateEclipseProject
assert project.tasks.eclipse.taskDependencies.getDependencies(project.tasks.eclipse).contains(eclipseProjectTask)
assert eclipseProjectTask.outputFile == project.file('.project')
+
+ assert project.eclipse.project.buildCommands == buildCommands
+ assert project.eclipse.project.natures == natures
}
private void checkEclipseClasspath(def configurations, def additionalContainers = []) {
diff --git a/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolderTest.groovy b/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolderTest.groovy
index 45bea65..f947fcf 100644
--- a/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolderTest.groovy
+++ b/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/model/SourceFolderTest.groovy
@@ -80,11 +80,24 @@ class SourceFolderTest extends Specification {
given:
def one = createSourceFolder()
one.dir = new File('/some/path/to/foo')
-
+ one.name = "foo"
when:
- one.trimPath()
+ one.trim()
then:
one.path == 'foo'
}
+
+ def "trims path with provided prefix"() {
+ given:
+ def one = createSourceFolder()
+ one.dir = new File('/some/path/to/foo')
+ one.name = "foo"
+ when:
+ one.trim("prefix")
+
+ then:
+ one.path == 'prefix-foo'
+ one.name== 'prefix-foo'
+ }
}
diff --git a/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/model/internal/SourceFoldersCreatorTest.groovy b/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/model/internal/SourceFoldersCreatorTest.groovy
new file mode 100644
index 0000000..fb384dd
--- /dev/null
+++ b/subprojects/ide/src/test/groovy/org/gradle/plugins/ide/eclipse/model/internal/SourceFoldersCreatorTest.groovy
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.plugins.ide.eclipse.model.internal
+
+import org.gradle.api.file.DirectoryTree
+import org.gradle.api.file.SourceDirectorySet
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.util.PatternSet
+import org.gradle.plugins.ide.eclipse.model.SourceFolder
+import org.junit.Rule
+import org.junit.rules.TemporaryFolder
+import spock.lang.Specification
+
+class SourceFoldersCreatorTest extends Specification {
+
+ @Rule
+ TemporaryFolder tempFolder;
+
+ SourceSet sourceSet;
+ SourceDirectorySet java
+ SourceDirectorySet resources
+ SourceDirectorySet allSource
+
+ DirectoryTree javaTree;
+ DirectoryTree resourcesTree;
+
+ def setup() {
+ sourceSet = Mock()
+ java = Mock()
+ resources = Mock()
+ allSource = Mock()
+ _ * sourceSet.allSource >> allSource
+ _ * sourceSet.allJava >> java
+ _ * sourceSet.resources >> resources
+ }
+
+ def "applies excludes/includes for src folders"() {
+ given:
+ def patterns = ["**/*.xml"]
+ javaTree = dirTree("java", [], patterns)
+ resourcesTree = dirTree("resources", patterns, [])
+ when:
+ def folders = regularSourceFolders()
+ then:
+ folders.find { it.dir.path.endsWith("java") }.excludes == []
+ folders.find { it.dir.path.endsWith("java") }.includes== patterns
+ folders.find { it.dir.path.endsWith("resources") }.excludes == patterns
+ folders.find { it.dir.path.endsWith("resources") }.includes== []
+ }
+
+ def "ignores excludes patterns when specified for one of shared resources/sources folders"() {
+ given:
+ def patterns = ["**/*.java"]
+ javaTree = dirTree("shared", [], [])
+ resourcesTree = dirTree("shared", patterns, [])
+ when:
+ def folders = regularSourceFolders()
+ then:
+ folders.find { it.dir.path.endsWith("shared") }.excludes == []
+ }
+
+ def "applies excludes when specified on resources and on sources"() {
+ given:
+ def patterns = ["**/*.xml"]
+ javaTree = dirTree("shared", patterns, [])
+ resourcesTree = dirTree("shared", patterns, [])
+ when:
+ def folders = regularSourceFolders()
+ then:
+ folders.find { it.dir.path.endsWith("shared") }.excludes == patterns
+ folders.find { it.dir.path.endsWith("shared") }.includes == []
+ }
+
+ def "applies no includes when one source type has no includes declared"() {
+ given:
+ javaTree = dirTree("shared", [], [])
+ resourcesTree = dirTree("shared", [], ["**/*.properties"])
+ when:
+ def folders = regularSourceFolders()
+ then:
+ folders.find { it.dir.path.endsWith("shared") }.excludes == []
+ folders.find { it.dir.path.endsWith("shared") }.includes == []
+ }
+
+ def "applies includes when all source types have declared includes"() {
+ given:
+ javaTree = dirTree("shared", [], ["**/*.java", "**/*.xml"])
+ resourcesTree = dirTree("shared", [], ["**/*.properties", "**/*.xml"])
+ when:
+ def folders = regularSourceFolders()
+ then:
+ folders.find { it.dir.path.endsWith("shared") }.excludes == []
+ folders.find { it.dir.path.endsWith("shared") }.includes == ["**/*.properties", "**/*.xml", "**/*.java"]
+ }
+
+ private List<SourceFolder> regularSourceFolders() {
+ _ * java.srcDirs >> [javaTree.dir]
+ _ * java.excludes >> javaTree.patterns.excludes
+ _ * java.includes >> javaTree.patterns.includes
+ _ * java.srcDirTrees >> [javaTree]
+ _ * resources.srcDirs >> [resourcesTree.dir]
+ _ * resources.excludes >> resourcesTree.patterns.excludes
+ _ * resources.includes >> resourcesTree.patterns.includes
+ _ * resources.srcDirTrees >> [resourcesTree]
+ _ * allSource.getSrcDirTrees() >> [javaTree, resourcesTree]
+ return new SourceFoldersCreator().getRegularSourceFolders([sourceSet], { File file -> file.path })
+ }
+
+
+ private def dirTree(String dirName, List excludes, List includes) {
+ def dir = new File(tempFolder.root, dirName);
+ if (!dir.exists()) {
+ tempFolder.newFolder(dirName)
+ }
+ new TestDirectoryTree(dir: dir,
+ patterns: new PatternSet().setExcludes(excludes).setIncludes(includes));
+ }
+
+ private static class TestDirectoryTree implements DirectoryTree {
+ File dir
+ PatternSet patterns
+ }
+}
diff --git a/subprojects/integ-test/integ-test.gradle b/subprojects/integ-test/integ-test.gradle
index 59d1455..f8713ec 100644
--- a/subprojects/integ-test/integ-test.gradle
+++ b/subprojects/integ-test/integ-test.gradle
@@ -21,11 +21,13 @@ useTestFixtures(sourceSet: 'integTest', project: ':platformNative')
integTestTasks.all {
dependsOn({ rootProject.getTasksByName('publishLocalArchives', true) }, ':docs:userguideDocbook')
- jvmArgs '-Xmx512m', '-XX:MaxPermSize=256m'
+
+ def userguideOutput = new File(project(':docs').samplesSrcDir, "userguideOutput")
+ inputs.files(fileTree(userguideOutput))
doFirst {
systemProperties['integTest.userGuideInfoDir'] = project(':docs').docbookSrc
- systemProperties['integTest.userGuideOutputDir'] = new File(project(':docs').samplesSrcDir, "userguideOutput").absolutePath
+ systemProperties['integTest.userGuideOutputDir'] = userguideOutput.absolutePath
}
// You can exclude the userguide samples by their ids by specifying this system property.
@@ -41,4 +43,4 @@ parallelIntegTest {
systemProperty "org.gradle.userguide.samples.exclude", "multiProjectBuildSrc,multiprojectMessagesHack"
}
-useClassycle()
\ No newline at end of file
+useClassycle()
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ApplicationIntegrationSpec.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ApplicationIntegrationSpec.groovy
index 188f7da..74aaf75 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ApplicationIntegrationSpec.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ApplicationIntegrationSpec.groovy
@@ -317,7 +317,7 @@ ${installTask}.destinationDir = buildDir
File generatedLinuxStartScript = file("build/scripts/application")
generatedLinuxStartScript.exists()
- assertLineSeparators(generatedLinuxStartScript, TextUtil.unixLineSeparator, 164);
+ assertLineSeparators(generatedLinuxStartScript, TextUtil.unixLineSeparator, 160);
assertLineSeparators(generatedLinuxStartScript, TextUtil.windowsLineSeparator, 1)
file("build/scripts/application").exists()
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/BuildScriptClasspathIntegrationTest.java b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/BuildScriptClasspathIntegrationTest.java
index 2e11493..9eed782 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/BuildScriptClasspathIntegrationTest.java
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/BuildScriptClasspathIntegrationTest.java
@@ -24,7 +24,7 @@ import org.junit.Test;
import static org.junit.Assert.fail;
- at LeaksFileHandles
+ at SuppressWarnings("ResultOfMethodCallIgnored")
public class BuildScriptClasspathIntegrationTest extends AbstractIntegrationTest {
@Test
public void providesADefaultBuildForBuildSrcProject() {
@@ -34,6 +34,7 @@ public class BuildScriptClasspathIntegrationTest extends AbstractIntegrationTest
}
@Test
+ @LeaksFileHandles("second build opens repo/test-1.3.jar and doesn't release")
public void canExtendTheDefaultBuildForBuildSrcProject() {
ArtifactBuilder builder = artifactBuilder();
builder.sourceFile("org/gradle/test/DepClass.java").writelns(
@@ -84,6 +85,7 @@ public class BuildScriptClasspathIntegrationTest extends AbstractIntegrationTest
}
@Test
+ @LeaksFileHandles("second build opens repo/test-1.3.jar and doesn't release")
public void canDeclareClasspathInBuildScript() {
ArtifactBuilder builder = artifactBuilder();
builder.sourceFile("org/gradle/test/ImportedClass.java").writelns(
@@ -174,6 +176,7 @@ public class BuildScriptClasspathIntegrationTest extends AbstractIntegrationTest
}
@Test
+ @LeaksFileHandles("second build opens repo/test-1.3.jar and doesn't release")
public void inheritsClassPathOfParentProject() {
ArtifactBuilder builder = artifactBuilder();
builder.sourceFile("org/gradle/test/BuildClass.java").writelns(
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CacheProjectIntegrationTest.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CacheProjectIntegrationTest.groovy
index ff4a877..6805f66 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CacheProjectIntegrationTest.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CacheProjectIntegrationTest.groovy
@@ -55,8 +55,8 @@ public class CacheProjectIntegrationTest extends AbstractIntegrationTest {
userHomeDir = executer.gradleUserHomeDir
buildFile = projectDir.file('build.gradle')
ScriptSource source = new UriScriptSource("build file", buildFile)
- propertiesFile = userHomeDir.file("caches/$version/scripts/$source.className/ProjectScript/no_buildscript/cache.properties")
- classFile = userHomeDir.file("caches/$version/scripts/$source.className/ProjectScript/no_buildscript/classes/${source.className}.class")
+ propertiesFile = userHomeDir.file("caches/$version/scripts/$source.className/proj/cache.properties")
+ classFile = userHomeDir.file("caches/$version/scripts/$source.className/proj/classes/${source.className}.class")
artifactsCache = projectDir.file(".gradle/$version/taskArtifacts/taskArtifacts.bin")
repo = new MavenHttpRepository(server, mavenRepo)
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CommandLineIntegrationTest.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CommandLineIntegrationTest.groovy
index 00c6f2a..ba7c711 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CommandLineIntegrationTest.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/CommandLineIntegrationTest.groovy
@@ -21,6 +21,7 @@ import org.gradle.integtests.fixtures.executer.ExecutionFailure
import org.gradle.internal.jvm.Jvm
import org.gradle.internal.os.OperatingSystem
import org.gradle.test.fixtures.file.TestFile
+import org.gradle.testfixtures.internal.NativeServicesTestFixture
import org.gradle.util.PreconditionVerifier
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@@ -30,11 +31,14 @@ import org.junit.Test
public class CommandLineIntegrationTest extends AbstractIntegrationTest {
- @Rule public final TestResources resources = new TestResources(testDirectoryProvider)
- @Rule public final PreconditionVerifier verifier = new PreconditionVerifier()
+ @Rule
+ public final TestResources resources = new TestResources(testDirectoryProvider)
+ @Rule
+ public final PreconditionVerifier verifier = new PreconditionVerifier()
@Before
void setup() {
+ NativeServicesTestFixture.initialize()
executer.requireGradleHome()
}
@@ -84,18 +88,25 @@ public class CommandLineIntegrationTest extends AbstractIntegrationTest {
@Test
@Requires(TestPrecondition.SYMLINKS)
public void failsWhenJavaHomeNotSetAndPathDoesNotContainJava() {
- def path
- if (OperatingSystem.current().windows) {
- path = ''
- } else {
- // Set up a fake bin directory, containing the things that the script needs, minus any java that might be in /usr/bin
- def binDir = file('fake-bin')
- ['basename', 'dirname', 'uname', 'which', 'bash'].each { linkToBinary(it, binDir) }
- path = binDir.absolutePath
+ def links = ['basename', 'dirname', 'uname', 'which', 'bash']
+ def binDir = file('fake-bin')
+ try {
+ def path
+ if (OperatingSystem.current().windows) {
+ path = ''
+ } else {
+ // Set up a fake bin directory, containing the things that the script needs, minus any java that might be in /usr/bin
+ links.each { linkToBinary(it, binDir) }
+ path = binDir.absolutePath
+ }
+
+ def failure = executer.withEnvironmentVars('PATH': path, 'JAVA_HOME': '').withTasks('checkJavaHome').runWithFailure()
+ assert failure.output.contains("ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.")
+ } finally {
+ links.each {
+ new File(getTestDirectory(), "fake-bin/$it").delete()
+ }
}
-
- def failure = executer.withEnvironmentVars('PATH': path, 'JAVA_HOME': '').withTasks('checkJavaHome').runWithFailure()
- assert failure.output.contains("ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.")
}
def linkToBinary(String command, TestFile binDir) {
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ParallelTaskExecutionIntegrationTest.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ParallelTaskExecutionIntegrationTest.groovy
index 1ebede2..0bbbc79 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ParallelTaskExecutionIntegrationTest.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/ParallelTaskExecutionIntegrationTest.groovy
@@ -20,10 +20,10 @@ import org.gradle.execution.taskgraph.DefaultTaskExecutionPlan
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
import org.gradle.integtests.fixtures.executer.GradleHandle
+import org.gradle.test.fixtures.ConcurrentTestUtil
import org.gradle.test.fixtures.server.http.BlockingHttpServer
import org.junit.Rule
import spock.lang.IgnoreIf
-import spock.util.concurrent.PollingConditions
@IgnoreIf({ GradleContextualExecuter.parallel })
// no point, always runs in parallel
@@ -115,7 +115,7 @@ class ParallelTaskExecutionIntegrationTest extends AbstractIntegrationSpec {
GradleHandle handle
def handleStarter = { handle = executer.withTasks(":aPing", ":bPing").start() }
blockingServer.expectConcurrentExecution([":aPing"]) {
- new PollingConditions().eventually {
+ ConcurrentTestUtil.poll(1) {
assert handle.standardOutput.contains("Cannot execute task :bPing in parallel with task :aPing due to overlapping output: ${file("dir")}")
}
}
@@ -137,7 +137,7 @@ class ParallelTaskExecutionIntegrationTest extends AbstractIntegrationSpec {
GradleHandle handle
def handleStarter = { handle = executer.withTasks(":aPing", ":bPing").start() }
blockingServer.expectConcurrentExecution([":aPing"]) {
- new PollingConditions().eventually {
+ ConcurrentTestUtil.poll(1) {
assert handle.standardOutput.contains("Unable to parallelize task :bPing due to presence of custom actions (e.g. doFirst()/doLast())")
}
}
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/StdioIntegrationTest.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/StdioIntegrationTest.groovy
index 88962d1..d67ca10 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/StdioIntegrationTest.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/StdioIntegrationTest.groovy
@@ -36,9 +36,17 @@ task echo << {
}
}
'''
+ executer.withStdinPipe(new PipedOutputStream() {
+ @Override
+ void connect(PipedInputStream snk) throws IOException {
+ super.connect(snk)
+ write(TextUtil.toPlatformLineSeparators("abc\n123").bytes)
+ close()
+ }
+ })
when:
- executer.withStdIn("abc\n123").withArguments("-s", "--info")
+ executer.withArguments("-s", "--info")
run "echo"
then:
@@ -46,9 +54,6 @@ task echo << {
}
def "build can read stdin when stdin has unbounded length"() {
- def writeEnd = new PipedOutputStream()
- def readEnd = new PipedInputStream(writeEnd)
-
given:
requireOwnGradleUserHomeDir()
buildFile << '''
@@ -63,11 +68,14 @@ task echo << {
}
}
'''
- and:
- writeEnd.write(TextUtil.toPlatformLineSeparators("abc\n123\nclose\n").bytes)
-
when:
- executer.withStdIn(readEnd).withArguments("-s", "--info")
+ executer.withArguments("-s", "--info").withStdinPipe(new PipedOutputStream() {
+ @Override
+ void connect(PipedInputStream snk) throws IOException {
+ super.connect(snk)
+ write(TextUtil.toPlatformLineSeparators("abc\n123\nclose\n").bytes)
+ }
+ })
run "echo"
then:
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/environment/BuildEnvironmentIntegrationTest.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/environment/BuildEnvironmentIntegrationTest.groovy
index 7987340..737af60 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/environment/BuildEnvironmentIntegrationTest.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/environment/BuildEnvironmentIntegrationTest.groovy
@@ -152,13 +152,12 @@ assert classesDir.directory
file('gradle.properties') << """
org.gradle.java.home=${TextUtil.escapeString(alternateJavaHome.canonicalPath)}
-org.gradle.jvmargs=-XX:+IgnoreUnrecognizedVMOptions
"""
file('build.gradle') << "println 'javaHome=' + org.gradle.internal.jvm.Jvm.current().javaHome.absolutePath"
when:
// Need the forking executer for this to work. Embedded executer will not fork a new process if jvm doesn't match.
- def out = executer.requireGradleHome().run().output
+ def out = executer.requireGradleHome().useDefaultBuildJvmArgs().run().output
then:
out.contains("javaHome=" + alternateJavaHome.canonicalPath)
@@ -173,7 +172,7 @@ assert System.getProperty('some-prop') == 'some-value'
"""
when:
- executer.requireGradleHome().withNoDefaultJvmArgs().run()
+ executer.requireGradleHome().useDefaultBuildJvmArgs().run()
then:
noExceptionThrown()
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/SamplesWebQuickstartIntegrationTest.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/SamplesWebQuickstartIntegrationTest.groovy
index 3e97f7b..7e703d7 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/SamplesWebQuickstartIntegrationTest.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/SamplesWebQuickstartIntegrationTest.groovy
@@ -17,13 +17,16 @@
package org.gradle.integtests.samples
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.Sample
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
+import org.gradle.util.ports.FixedAvailablePortAllocator
import org.junit.Rule
import spock.lang.Timeout
import spock.lang.Unroll
import static org.gradle.integtests.fixtures.UrlValidator.available
+ at LeaksFileHandles
class SamplesWebQuickstartIntegrationTest extends AbstractIntegrationSpec {
@Rule public final Sample sample = new Sample(temporaryFolder, 'webApplication/quickstart')
@@ -51,18 +54,22 @@ class SamplesWebQuickstartIntegrationTest extends AbstractIntegrationSpec {
@Timeout(120)
@Unroll
def "can use #jettyTask for testing"() {
+ def portFinder = FixedAvailablePortAllocator.getInstance()
+ def httpPort = portFinder.assignPort()
+ def stopPort = portFinder.assignPort()
+
expect:
- jettyLifecycle(jettyTask)
+ jettyLifecycle(jettyTask, httpPort, stopPort)
+
+ cleanup:
+ portFinder.releasePort(httpPort)
+ portFinder.releasePort(stopPort)
where:
jettyTask << ["jettyRun", "jettyRunWar"]
}
- private void jettyLifecycle(String jettyStartTask) {
- def portFinder = org.gradle.util.AvailablePortFinder.createPrivate()
- def httpPort = portFinder.nextAvailable
- def stopPort = portFinder.nextAvailable
-
+ private void jettyLifecycle(String jettyStartTask, int httpPort, int stopPort) {
// Inject some int test stuff
sample.dir.file('build.gradle') << """
httpPort = ${httpPort}
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesIntegrationTest.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesIntegrationTest.groovy
index 3ba1753..61c4978 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesIntegrationTest.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesIntegrationTest.groovy
@@ -27,6 +27,12 @@ class UserGuideSamplesIntegrationTest {
- gradle intTestImage makes sure that the samples' resources are copied to the right place
- gradle docs:userguideDocbook makes sure that samples' info is extracted from XMLs
- the 'expected' content of the asserting mechanism lives under docs/src/samples/userguideOutput
+ - Running:
+ ./gradlew intTestImage docs:userguideDocbook integtest:integTest --tests org.gradle.integtests.samples.UserGuideSamplesIntegrationTest
+ Samples are not tested by default. For a sample to be executed and tested, you need to:
+ - add a nested <output/> tag to the <sample/> tag
+ - use the `args` parameter of the output tag to specify the tasks to be executed
+ - optionally set the name of the reference output file (by default, will use [sample id].out)
*/
}
diff --git a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesRunner.groovy b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesRunner.groovy
index e481c1a..838e540 100644
--- a/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesRunner.groovy
+++ b/subprojects/integ-test/src/integTest/groovy/org/gradle/integtests/samples/UserGuideSamplesRunner.groovy
@@ -14,12 +14,13 @@
* limitations under the License.
*/
package org.gradle.integtests.samples
-
import com.google.common.collect.ArrayListMultimap
import groovy.io.PlatformLineWriter
import org.apache.tools.ant.taskdefs.Delete
import org.gradle.api.Transformer
+import org.gradle.api.reporting.components.JvmComponentReportOutputFormatter
import org.gradle.api.reporting.components.NativeComponentReportOutputFormatter
+import org.gradle.api.reporting.components.PlayComponentReportOutputFormatter
import org.gradle.integtests.fixtures.executer.*
import org.gradle.internal.SystemProperties
import org.gradle.test.fixtures.file.TestFile
@@ -255,6 +256,8 @@ class UserGuideSamplesRunner extends Runner {
}
samplesById.nativeComponentReport.runs.each { it.outputFormatter = new NativeComponentReportOutputFormatter() }
+ samplesById.playComponentReport.runs.each { it.outputFormatter = new PlayComponentReportOutputFormatter() }
+ samplesById.newJavaComponentReport.runs.each { it.outputFormatter = new JvmComponentReportOutputFormatter() }
if ("true".equals(System.getProperty("org.gradle.integtest.unknownos"))) {
// Ignore for now
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractHttpDependencyResolutionTest.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractHttpDependencyResolutionTest.groovy
index ea9bcdd..3949be2 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractHttpDependencyResolutionTest.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractHttpDependencyResolutionTest.groovy
@@ -19,14 +19,14 @@ package org.gradle.integtests.fixtures
import org.gradle.test.fixtures.server.http.IvyHttpRepository
import org.gradle.test.fixtures.maven.MavenFileRepository
import org.gradle.test.fixtures.server.http.MavenHttpRepository
-import org.gradle.test.fixtures.server.http.HttpServer
+import org.gradle.test.fixtures.server.http.RepositoryHttpServer
import org.gradle.util.GradleVersion
import org.junit.Rule
import static org.gradle.test.matchers.UserAgentMatcher.matchesNameAndVersion
abstract class AbstractHttpDependencyResolutionTest extends AbstractDependencyResolutionTest {
- @Rule public final HttpServer server = new HttpServer()
+ @Rule public final RepositoryHttpServer server = new RepositoryHttpServer(temporaryFolder)
def setup() {
server.expectUserAgent(matchesNameAndVersion("Gradle", GradleVersion.current().getVersion()))
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractIntegrationSpec.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractIntegrationSpec.groovy
index 8b3e90e..715bde8 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractIntegrationSpec.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AbstractIntegrationSpec.groovy
@@ -25,10 +25,10 @@ import org.gradle.test.fixtures.maven.MavenFileRepository
import org.gradle.test.fixtures.maven.MavenLocalRepository
import org.hamcrest.CoreMatchers
import org.junit.Rule
-import org.junit.runners.model.FrameworkMethod
-import org.junit.runners.model.Statement
import spock.lang.Specification
+import static org.gradle.util.Matchers.normalizedLineSeparators
+
/**
* Spockified version of AbstractIntegrationTest.
*
@@ -36,21 +36,7 @@ import spock.lang.Specification
*/
class AbstractIntegrationSpec extends Specification implements TestDirectoryProvider {
@Rule
- final TestNameTestDirectoryProvider temporaryFolder = new TestNameTestDirectoryProvider() {
- @Override
- Statement apply(Statement base, FrameworkMethod method, Object target) {
- return super.apply(new Statement() {
- @Override
- void evaluate() throws Throwable {
- try {
- base.evaluate()
- } finally {
- cleanupWhileTestFilesExist()
- }
- }
- }, method, target)
- }
- }
+ final TestNameTestDirectoryProvider temporaryFolder = new TestNameTestDirectoryProvider()
GradleDistribution distribution = new UnderDevelopmentGradleDistribution()
GradleExecuter executer = new GradleContextualExecuter(distribution, temporaryFolder)
@@ -60,9 +46,6 @@ class AbstractIntegrationSpec extends Specification implements TestDirectoryProv
private MavenFileRepository mavenRepo
private IvyFileRepository ivyRepo
- protected void cleanupWhileTestFilesExist() {
- }
-
protected TestFile getBuildFile() {
testDirectory.file('build.gradle')
}
@@ -190,11 +173,15 @@ class AbstractIntegrationSpec extends Specification implements TestDirectoryProv
}
protected void failureDescriptionStartsWith(String description) {
- failure.assertThatDescription(CoreMatchers.startsWith(description))
+ failure.assertThatDescription(normalizedLineSeparators(CoreMatchers.containsString(description)))
}
protected void failureDescriptionContains(String description) {
- failure.assertThatDescription(CoreMatchers.containsString(description))
+ failure.assertThatDescription(normalizedLineSeparators(CoreMatchers.containsString(description)))
+ }
+
+ protected void failureCauseContains(String description) {
+ failure.assertThatCause(normalizedLineSeparators(CoreMatchers.containsString(description)))
}
private assertHasResult() {
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AvailableJavaHomes.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AvailableJavaHomes.java
index 1da5422..3747ff6 100755
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AvailableJavaHomes.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/AvailableJavaHomes.java
@@ -168,6 +168,7 @@ abstract public class AvailableJavaHomes {
jvms = addJvm(jvms, JavaVersion.VERSION_1_6, "1.6.0", new File("/opt/jdk/ibm-jdk-6"), true, JvmInstallation.Arch.x86_64);
jvms = addJvm(jvms, JavaVersion.VERSION_1_7, "1.7.0", new File("/opt/jdk/oracle-jdk-7"), true, JvmInstallation.Arch.x86_64);
jvms = addJvm(jvms, JavaVersion.VERSION_1_8, "1.8.0", new File("/opt/jdk/oracle-jdk-8"), true, JvmInstallation.Arch.x86_64);
+ jvms = addJvm(jvms, JavaVersion.VERSION_1_9, "1.9.0", new File("/opt/jdk/oracle-jdk-9"), true, JvmInstallation.Arch.x86_64);
}
return CollectionUtils.filter(jvms, new Spec<JvmInstallation>() {
public boolean isSatisfiedBy(JvmInstallation element) {
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/PersistentBuildProcessIntegrationTest.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/PersistentBuildProcessIntegrationTest.groovy
index 7a8de51..c250cbf 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/PersistentBuildProcessIntegrationTest.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/PersistentBuildProcessIntegrationTest.groovy
@@ -29,8 +29,7 @@ class PersistentBuildProcessIntegrationTest extends AbstractIntegrationSpec {
executer.requireIsolatedDaemons()
}
- @Override
- protected void cleanupWhileTestFilesExist() {
+ protected void cleanup() {
if (GradleContextualExecuter.daemon) {
executer.withArguments("-i", "--stop").run()
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/AbstractDaemonFixture.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/AbstractDaemonFixture.groovy
index ff986fb..10b20b8 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/AbstractDaemonFixture.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/AbstractDaemonFixture.groovy
@@ -27,6 +27,9 @@ abstract class AbstractDaemonFixture implements DaemonFixture {
AbstractDaemonFixture(File daemonLog) {
this.context = DaemonContextParser.parseFrom(daemonLog.text)
+ if(!this.context) {
+ println "Could not parse daemon log: \n$daemonLog.text"
+ }
if (this.context.pid == null) {
println "PID in daemon log ($daemonLog.absolutePath) is null."
println "daemon.log exists: ${daemonLog.exists()}"
@@ -39,6 +42,10 @@ abstract class AbstractDaemonFixture implements DaemonFixture {
}
}
+ DaemonContext getContext() {
+ context
+ }
+
void becomesIdle() {
waitForState(State.idle)
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonFixture.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonFixture.java
index 8f1e104..4bf61db 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonFixture.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonFixture.java
@@ -16,8 +16,15 @@
package org.gradle.integtests.fixtures.daemon;
+import org.gradle.launcher.daemon.context.DaemonContext;
+
public interface DaemonFixture {
/**
+ * Returns the context information of this daemon.
+ */
+ DaemonContext getContext();
+
+ /**
* Returns the TCP port used by this daemon.
*/
int getPort();
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonIntegrationSpec.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonIntegrationSpec.groovy
index 256ab4c..5c7aeef 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonIntegrationSpec.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/daemon/DaemonIntegrationSpec.groovy
@@ -17,7 +17,6 @@
package org.gradle.integtests.fixtures.daemon
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.integtests.fixtures.executer.DaemonGradleExecuter
import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
import org.gradle.test.fixtures.file.LeaksFileHandles
import spock.lang.IgnoreIf
@@ -25,19 +24,12 @@ import spock.lang.IgnoreIf
@IgnoreIf({ GradleContextualExecuter.daemon })
@LeaksFileHandles
abstract class DaemonIntegrationSpec extends AbstractIntegrationSpec {
-
- @Override
- DaemonGradleExecuter getExecuter() {
- super.executer as DaemonGradleExecuter
- }
-
def setup() {
- executer = new DaemonGradleExecuter(distribution, temporaryFolder)
+ executer.requireDaemon()
executer.requireIsolatedDaemons()
}
- @Override
- protected void cleanupWhileTestFilesExist() {
+ protected void cleanup() {
// Need to kill daemons before test files are cleaned up, as the log files and registry are used to locate the daemons and these live under
// the test file directory.
daemons.killAll()
@@ -47,9 +39,8 @@ abstract class DaemonIntegrationSpec extends AbstractIntegrationSpec {
result = executer.withArguments("--stop", "--info").run()
}
- void buildSucceeds(String script = '') {
- file('build.gradle') << script
- result = executer.withArguments("--info").withNoDefaultJvmArgs().run()
+ void buildSucceeds() {
+ result = executer.withArguments("--info").run()
}
DaemonsFixture getDaemons() {
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java
index b1ce71b..ae32545 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/AbstractGradleExecuter.java
@@ -19,27 +19,30 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import groovy.lang.Closure;
import org.gradle.api.Action;
+import org.gradle.api.Transformer;
import org.gradle.api.internal.ClosureBackedAction;
import org.gradle.api.internal.initialization.DefaultClassLoaderScope;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
+import org.gradle.internal.UncheckedException;
import org.gradle.internal.jvm.Jvm;
import org.gradle.launcher.daemon.configuration.DaemonParameters;
import org.gradle.launcher.daemon.configuration.GradleProperties;
import org.gradle.listener.ActionBroadcast;
-import org.gradle.process.internal.JvmOptions;
+import org.gradle.process.internal.streams.SafeStreams;
import org.gradle.test.fixtures.file.TestDirectoryProvider;
import org.gradle.test.fixtures.file.TestFile;
+import org.gradle.util.CollectionUtils;
import org.gradle.util.DeprecationLogger;
import org.gradle.util.TextUtil;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.InputStream;
+import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
-import static java.util.Arrays.asList;
+import static org.gradle.launcher.daemon.client.DefaultDaemonConnector.DISABLE_STARTING_DAEMON_MESSAGE_PROPERTY;
+import static org.gradle.util.CollectionUtils.collect;
+import static org.gradle.util.CollectionUtils.join;
import static org.gradle.util.Matchers.containsLine;
import static org.gradle.util.Matchers.matchesRegexp;
@@ -78,14 +81,16 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
private File buildScript;
private File projectDir;
private File settingsFile;
- private InputStream stdin;
+ private PipedOutputStream stdinPipe;
private String defaultCharacterEncoding;
private String tmpDir;
private Locale defaultLocale;
private int daemonIdleTimeoutSecs = 60;
+ private boolean requireDaemon;
private File daemonBaseDir = buildContext.getDaemonBaseDir();
- private final List<String> gradleOpts = new ArrayList<String>();
- private boolean noDefaultJvmArgs;
+ private final List<String> buildJvmOpts = new ArrayList<String>();
+ private final List<String> commandLineJvmOpts = new ArrayList<String>();
+ private boolean useOnlyRequestedJvmOpts;
private boolean requireGradleHome;
private boolean daemonStartingMessageDisabled = true;
@@ -127,11 +132,13 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
executable = null;
javaHome = null;
environmentVars.clear();
- stdin = null;
+ stdinPipe = null;
defaultCharacterEncoding = null;
tmpDir = null;
defaultLocale = null;
- noDefaultJvmArgs = false;
+ commandLineJvmOpts.clear();
+ buildJvmOpts.clear();
+ useOnlyRequestedJvmOpts = false;
deprecationChecksOn = true;
stackTraceChecksOn = true;
debug = Boolean.getBoolean(DEBUG_SYSPROP);
@@ -139,7 +146,6 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return this;
}
-
public GradleDistribution getDistribution() {
return distribution;
}
@@ -198,7 +204,7 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
}
executer.withTasks(tasks);
executer.withArguments(args);
- executer.withEnvironmentVars(getMergedEnvironmentVars());
+ executer.withEnvironmentVars(environmentVars);
executer.usingExecutable(executable);
if (quiet) {
executer.withQuietLogging();
@@ -213,9 +219,11 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
if (userHomeDir != null) {
executer.withUserHomeDir(userHomeDir);
}
- if (stdin != null) {
- executer.withStdIn(stdin);
+
+ if (stdinPipe != null) {
+ executer.withStdinPipe(stdinPipe);
}
+
if (defaultCharacterEncoding != null) {
executer.withDefaultCharacterEncoding(defaultCharacterEncoding);
}
@@ -225,9 +233,10 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
if (defaultLocale != null) {
executer.withDefaultLocale(defaultLocale);
}
- executer.withGradleOpts(gradleOpts.toArray(new String[gradleOpts.size()]));
- if (noDefaultJvmArgs) {
- executer.withNoDefaultJvmArgs();
+ executer.withCommandLineGradleOpts(commandLineJvmOpts);
+ executer.withBuildJvmOpts(buildJvmOpts);
+ if (useOnlyRequestedJvmOpts) {
+ executer.useDefaultBuildJvmArgs();
}
executer.noExtraLogging();
@@ -246,6 +255,9 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
if (!daemonStartingMessageDisabled) {
executer.withDaemonStartingMessageEnabled();
}
+ if (requireDaemon) {
+ executer.requireDaemon();
+ }
executer.withDebug(debug);
executer.withForceInteractive(interactive);
@@ -289,23 +301,82 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return userHomeDir;
}
+ protected GradleInvocation buildInvocation() {
+ validateDaemonVisibility();
+
+ GradleInvocation gradleInvocation = new GradleInvocation();
+ gradleInvocation.environmentVars.putAll(environmentVars);
+ gradleInvocation.buildJvmArgs.addAll(buildJvmOpts);
+ if (!useOnlyRequestedJvmOpts) {
+ gradleInvocation.buildJvmArgs.addAll(getImplicitBuildJvmArgs());
+ }
+ calculateLauncherJvmArgs(gradleInvocation);
+ gradleInvocation.args.addAll(getAllArgs());
+
+ transformInvocation(gradleInvocation);
+
+ if (!gradleInvocation.implicitLauncherJvmArgs.isEmpty()) {
+ throw new IllegalStateException("Implicit JVM args have not been handled.");
+ }
+
+ return gradleInvocation;
+ }
+
+ protected void validateDaemonVisibility() {
+ if (isUseDaemon() && isSharedDaemons()) {
+ throw new IllegalStateException("Daemon that will be visible to other tests has been requested.");
+ }
+ }
+
/**
- * Returns the gradle opts set with withGradleOpts() (does not consider any set via withEnvironmentVars())
+ * Adjusts the calculated invocation prior to execution. This method is responsible for handling the implicit launcher JVM args in some way, by mutating the invocation appropriately.
*/
- protected List<String> getGradleOpts() {
- List<String> gradleOpts = new ArrayList<String>(this.gradleOpts);
+ protected void transformInvocation(GradleInvocation gradleInvocation) {
+ gradleInvocation.launcherJvmArgs.addAll(gradleInvocation.implicitLauncherJvmArgs);
+ gradleInvocation.implicitLauncherJvmArgs.clear();
+ }
+
+ /**
+ * Returns the JVM opts that should be used to start a forked JVM.
+ */
+ private void calculateLauncherJvmArgs(GradleInvocation gradleInvocation) {
+ // Add JVM args that were explicitly requested
+ gradleInvocation.launcherJvmArgs.addAll(commandLineJvmOpts);
+
+ if (isUseDaemon() && !gradleInvocation.buildJvmArgs.isEmpty()) {
+ // Pass build JVM args through to daemon via system property on the launcher JVM
+ String quotedArgs = join(" ", collect(gradleInvocation.buildJvmArgs, new Transformer<String, String>() {
+ public String transform(String input) {
+ return String.format("'%s'", input);
+ }
+ }));
+ gradleInvocation.implicitLauncherJvmArgs.add("-Dorg.gradle.jvmargs=" + quotedArgs);
+ } else {
+ // Have to pass build JVM args directly to launcher JVM
+ gradleInvocation.launcherJvmArgs.addAll(gradleInvocation.buildJvmArgs);
+ }
+
+ // Set the implicit system properties regardless of whether default JVM args are required or not, this should not interfere with tests' intentions
+ // These will also be copied across to any daemon used
for (Map.Entry<String, String> entry : getImplicitJvmSystemProperties().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
- gradleOpts.add(String.format("-D%s=%s", key, value));
+ gradleInvocation.implicitLauncherJvmArgs.add(String.format("-D%s=%s", key, value));
}
- gradleOpts.add("-ea");
+ gradleInvocation.implicitLauncherJvmArgs.add("-ea");
+ }
+
+ /**
+ * Returns additional JVM args that should be used to start the build JVM.
+ */
+ protected List<String> getImplicitBuildJvmArgs() {
+ List<String> buildJvmOpts = new ArrayList<String>();
+ buildJvmOpts.add("-ea");
if (isDebug()) {
- gradleOpts.addAll(DEBUG_ARGS);
+ buildJvmOpts.addAll(DEBUG_ARGS);
}
-
- return gradleOpts;
+ return buildJvmOpts;
}
public GradleExecuter withUserHomeDir(File userHomeDir) {
@@ -331,18 +402,27 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return executable;
}
- public GradleExecuter withStdIn(String text) {
- this.stdin = new ByteArrayInputStream(TextUtil.toPlatformLineSeparators(text).getBytes());
- return this;
+ @Override
+ public GradleExecuter withStdinPipe() {
+ return withStdinPipe(new PipedOutputStream());
}
- public GradleExecuter withStdIn(InputStream stdin) {
- this.stdin = stdin;
+ @Override
+ public GradleExecuter withStdinPipe(PipedOutputStream stdInPipe) {
+ this.stdinPipe = stdInPipe;
return this;
}
- public InputStream getStdin() {
- return stdin == null ? new ByteArrayInputStream(new byte[0]) : stdin;
+ public InputStream connectStdIn() {
+ try {
+ return stdinPipe == null ? SafeStreams.emptyInput() : new PipedInputStream(stdinPipe);
+ } catch (IOException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+
+ public PipedOutputStream getStdinPipe() {
+ return stdinPipe;
}
public GradleExecuter withDefaultCharacterEncoding(String defaultCharacterEncoding) {
@@ -415,20 +495,6 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return this;
}
- /**
- * Returns the effective env vars, having merged in specific settings.
- *
- * For example, GRADLE_OPTS will be anything that was specified via withEnvironmentVars() and withGradleOpts(). JAVA_HOME will also be set according to getJavaHome().
- */
- protected Map<String, String> getMergedEnvironmentVars() {
- Map<String, String> environmentVars = new HashMap<String, String>(getEnvironmentVars());
- environmentVars.put("GRADLE_OPTS", toJvmArgsString(getMergedGradleOpts()));
- if (!environmentVars.containsKey("JAVA_HOME")) {
- environmentVars.put("JAVA_HOME", getJavaHome().getAbsolutePath());
- }
- return environmentVars;
- }
-
protected String toJvmArgsString(Iterable<String> jvmArgs) {
StringBuilder result = new StringBuilder();
for (String jvmArg : jvmArgs) {
@@ -448,20 +514,6 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return result.toString();
}
- private List<String> getMergedGradleOpts() {
- List<String> gradleOpts = new ArrayList<String>(getGradleOpts());
- String gradleOptsEnv = getEnvironmentVars().get("GRADLE_OPTS");
- if (gradleOptsEnv != null) {
- gradleOpts.addAll(JvmOptions.fromString(gradleOptsEnv));
- }
-
- return gradleOpts;
- }
-
- protected Map<String, String> getEnvironmentVars() {
- return environmentVars;
- }
-
public GradleExecuter withTasks(String... names) {
return withTasks(Arrays.asList(names));
}
@@ -477,8 +529,8 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return this;
}
- public GradleExecuter withNoDefaultJvmArgs() {
- noDefaultJvmArgs = true;
+ public GradleExecuter useDefaultBuildJvmArgs() {
+ useOnlyRequestedJvmOpts = true;
return this;
}
@@ -491,12 +543,30 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return withDaemonBaseDir(testDirectoryProvider.getTestDirectory().file("daemon"));
}
- protected File getDaemonBaseDir() {
+ public File getDaemonBaseDir() {
return daemonBaseDir;
}
- protected boolean isNoDefaultJvmArgs() {
- return noDefaultJvmArgs;
+ @Override
+ public GradleExecuter requireDaemon() {
+ requireDaemon = true;
+ return this;
+ }
+
+ protected boolean isSharedDaemons() {
+ return daemonBaseDir.equals(buildContext.getDaemonBaseDir());
+ }
+
+ protected boolean isUseDaemon() {
+ for (int i = args.size() - 1; i >= 0; i--) {
+ if (args.get(i).equals("--daemon")) {
+ return true;
+ }
+ if (args.get(i).equals("--no-daemon")) {
+ return false;
+ }
+ }
+ return requireDaemon;
}
protected List<String> getAllArgs() {
@@ -520,6 +590,9 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
if (quiet) {
allArgs.add("--quiet");
}
+ if (isUseDaemon()) {
+ allArgs.add("--daemon");
+ }
if (taskList) {
allArgs.add("tasks");
}
@@ -558,6 +631,9 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return allArgs;
}
+ /**
+ * Returns the set of system properties that should be set on every JVM used by this executer.
+ */
protected Map<String, String> getImplicitJvmSystemProperties() {
Map<String, String> properties = new LinkedHashMap<String, String>();
@@ -593,6 +669,10 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
properties.put(DaemonParameters.INTERACTIVE_TOGGLE, "true");
}
+ if (daemonStartingMessageDisabled) {
+ properties.put(DISABLE_STARTING_DAEMON_MESSAGE_PROPERTY, "true");
+ }
+
return properties;
}
@@ -647,11 +727,27 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
protected abstract ExecutionFailure doRunWithFailure();
- /**
- * {@inheritDoc}
- */
- public AbstractGradleExecuter withGradleOpts(String... gradleOpts) {
- this.gradleOpts.addAll(asList(gradleOpts));
+ @Override
+ public GradleExecuter withCommandLineGradleOpts(Iterable<String> jvmOpts) {
+ CollectionUtils.addAll(commandLineJvmOpts, jvmOpts);
+ return this;
+ }
+
+ @Override
+ public GradleExecuter withCommandLineGradleOpts(String... jvmOpts) {
+ CollectionUtils.addAll(commandLineJvmOpts, jvmOpts);
+ return this;
+ }
+
+ @Override
+ public AbstractGradleExecuter withBuildJvmOpts(String... jvmOpts) {
+ CollectionUtils.addAll(buildJvmOpts, jvmOpts);
+ return this;
+ }
+
+ @Override
+ public GradleExecuter withBuildJvmOpts(Iterable<String> jvmOpts) {
+ CollectionUtils.addAll(buildJvmOpts, jvmOpts);
return this;
}
@@ -746,10 +842,6 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
return this;
}
- public boolean isDaemonStartingMessageDisabled() {
- return daemonStartingMessageDisabled;
- }
-
@Override
public GradleExecuter withDebug(boolean flag) {
debug = flag;
@@ -766,4 +858,16 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
public boolean isDebug() {
return debug;
}
+
+ protected static class GradleInvocation {
+ final Map<String, String> environmentVars = new HashMap<String, String>();
+ final List<String> args = new ArrayList<String>();
+ // JVM args that must be used for the build JVM
+ final List<String> buildJvmArgs = new ArrayList<String>();
+ // JVM args that must be used to fork a JVM
+ final List<String> launcherJvmArgs = new ArrayList<String>();
+ // Implicit JVM args that should be used to fork a JVM
+ final List<String> implicitLauncherJvmArgs = new ArrayList<String>();
+ }
+
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DaemonGradleExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DaemonGradleExecuter.java
index f94f303..f60c713 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DaemonGradleExecuter.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DaemonGradleExecuter.java
@@ -15,7 +15,9 @@
*/
package org.gradle.integtests.fixtures.executer;
-import org.gradle.api.Transformer;
+import org.gradle.api.JavaVersion;
+import org.gradle.internal.jvm.Jvm;
+import org.gradle.launcher.daemon.client.JvmVersionDetector;
import org.gradle.test.fixtures.file.TestDirectoryProvider;
import java.util.ArrayList;
@@ -23,21 +25,22 @@ import java.util.List;
import static java.util.Arrays.asList;
import static org.apache.commons.collections.CollectionUtils.containsAny;
-import static org.gradle.launcher.daemon.client.DefaultDaemonConnector.DISABLE_STARTING_DAEMON_MESSAGE_PROPERTY;
-import static org.gradle.util.CollectionUtils.collect;
-import static org.gradle.util.CollectionUtils.join;
public class DaemonGradleExecuter extends ForkingGradleExecuter {
public DaemonGradleExecuter(GradleDistribution distribution, TestDirectoryProvider testDirectoryProvider) {
super(distribution, testDirectoryProvider);
+ requireDaemon();
+ }
+
+ @Override
+ protected void validateDaemonVisibility() {
+ // Ignore. Should really ignore only when daemon has not been explicitly enabled or disabled
}
@Override
protected List<String> getAllArgs() {
List<String> args = new ArrayList<String>(super.getAllArgs());
- args.add(0, "--daemon");
-
if(!isQuiet() && isAllowExtraLogging()) {
if (!containsAny(args, asList("-i", "--info", "-d", "--debug", "-q", "--quiet"))) {
args.add(0, "-i");
@@ -53,37 +56,21 @@ public class DaemonGradleExecuter extends ForkingGradleExecuter {
}
@Override
- protected List<String> getGradleOpts() {
- List<String> gradleOpts = new ArrayList<String>(super.getGradleOpts());
-
- gradleOpts.removeAll(DEBUG_ARGS);
- if (isDebug()) {
- gradleOpts.add("-Dorg.gradle.daemon.debug=true");
- }
-
- if (isDaemonStartingMessageDisabled()) {
- gradleOpts.add("-D" + DISABLE_STARTING_DAEMON_MESSAGE_PROPERTY + "=true");
+ protected List<String> getImplicitBuildJvmArgs() {
+ if (!isUseDaemon() || !isSharedDaemons()) {
+ return super.getImplicitBuildJvmArgs();
}
- if (isNoDefaultJvmArgs()) {
- return gradleOpts;
- } else {
- // Workaround for https://issues.gradle.org/browse/GRADLE-2629
- // Instead of just adding these as standalone opts, we need to add to
- // -Dorg.gradle.jvmArgs in order for them to be effectual
- List<String> jvmArgs = new ArrayList<String>(4);
- jvmArgs.add("-XX:MaxPermSize=320m");
- jvmArgs.add("-XX:+HeapDumpOnOutOfMemoryError");
- jvmArgs.add("-XX:HeapDumpPath=" + buildContext.getGradleUserHomeDir().getAbsolutePath());
- String quotedArgs = join(" ", collect(jvmArgs, new Transformer<String, String>() {
- public String transform(String input) {
- return String.format("'%s'", input);
- }
- }));
+ // Add JVM heap settings only for shared daemons
+ List<String> buildJvmOpts = new ArrayList<String>(super.getImplicitBuildJvmArgs());
- gradleOpts.add("-Dorg.gradle.jvmArgs=" + quotedArgs);
- return gradleOpts;
+ if (new JvmVersionDetector().getJavaVersion(Jvm.forHome(getJavaHome())).compareTo(JavaVersion.VERSION_1_9) < 0) {
+ buildJvmOpts.add("-XX:MaxPermSize=320m");
}
+
+ buildJvmOpts.add("-XX:+HeapDumpOnOutOfMemoryError");
+ buildJvmOpts.add("-XX:HeapDumpPath=" + buildContext.getGradleUserHomeDir().getAbsolutePath());
+ return buildJvmOpts;
}
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DefaultGradleDistribution.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DefaultGradleDistribution.java
index 7a4329e..ba6b683 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DefaultGradleDistribution.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/DefaultGradleDistribution.java
@@ -16,6 +16,7 @@
package org.gradle.integtests.fixtures.executer;
+import org.gradle.api.JavaVersion;
import org.gradle.internal.jvm.Jvm;
import org.gradle.internal.os.OperatingSystem;
import org.gradle.test.fixtures.file.TestDirectoryProvider;
@@ -108,6 +109,26 @@ public class DefaultGradleDistribution implements GradleDistribution {
return isSameOrNewer("1.0-milestone-3");
}
+ @Override
+ public boolean isToolingApiTargetJvmSupported(JavaVersion javaVersion) {
+ if (isSameOrNewer("2.7")) {
+ return true;
+ }
+
+ // Gradle versions older than 2.7 did not fully support Java 1.9 as the target JVM
+ if (javaVersion.compareTo(JavaVersion.VERSION_1_9) >= 0) {
+ return false;
+ }
+
+ // Use Java 1.6 or later for Gradle 2.0 and later
+ if (isSameOrNewer("2.0")) {
+ return javaVersion.compareTo(JavaVersion.VERSION_1_6) >= 0;
+ }
+
+ // Use Java 1.5 or later for earlier Gradle versions
+ return javaVersion.compareTo(JavaVersion.VERSION_1_5) >= 0;
+ }
+
public boolean isToolingApiNonAsciiOutputSupported() {
if (OperatingSystem.current().isWindows()) {
return !isVersion("1.0-milestone-7") && !isVersion("1.0-milestone-8") && !isVersion("1.0-milestone-8a");
@@ -119,6 +140,11 @@ public class DefaultGradleDistribution implements GradleDistribution {
return isSameOrNewer("2.2-rc-1");
}
+ @Override
+ public boolean isToolingApiEventsInEmbeddedModeSupported() {
+ return isSameOrNewer("2.6-rc-1");
+ }
+
public VersionNumber getArtifactCacheLayoutVersion() {
if (isSameOrNewer("2.4-rc-1")) {
return VersionNumber.parse("2.15");
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleExecuter.java
index 617618a..09cf09d 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleExecuter.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleExecuter.java
@@ -41,15 +41,15 @@ class ForkingGradleExecuter extends AbstractGradleExecuter {
public void assertCanExecute() throws AssertionError {
if (!getDistribution().isSupportsSpacesInGradleAndJavaOpts()) {
- Map<String, String> mergedEnvironmentVars = getMergedEnvironmentVars();
+ Map<String, String> environmentVars = buildInvocation().environmentVars;
for (String envVarName : Arrays.asList("JAVA_OPTS", "GRADLE_OPTS")) {
- String envVarValue = mergedEnvironmentVars.get(envVarName);
+ String envVarValue = environmentVars.get(envVarName);
if (envVarValue == null) {
continue;
}
for (String arg : JvmOptions.fromString(envVarValue)) {
if (arg.contains(" ")) {
- throw new AssertionError(String.format("Env var %s contains arg with space (%s) which is not supported", envVarName, arg));
+ throw new AssertionError(String.format("Env var %s contains arg with space (%s) which is not supported by Gradle %s", envVarName, arg, getDistribution().getVersion().getVersion()));
}
}
}
@@ -57,6 +57,47 @@ class ForkingGradleExecuter extends AbstractGradleExecuter {
}
@Override
+ protected void transformInvocation(GradleInvocation invocation) {
+ if (getDistribution().isSupportsSpacesInGradleAndJavaOpts()) {
+ // Mix the implicit launcher JVM args in with the requested JVM args
+ invocation.launcherJvmArgs.addAll(invocation.implicitLauncherJvmArgs);
+ } else {
+ // Need to move those implicit JVM args that contain a space to the Gradle command-line (if possible)
+ // Note that this isn't strictly correct as some system properties can only be set on JVM start up.
+ // Should change the implementation to deal with these properly
+ for (String jvmArg : invocation.implicitLauncherJvmArgs) {
+ if (!jvmArg.contains(" ")) {
+ invocation.launcherJvmArgs.add(jvmArg);
+ } else if (jvmArg.startsWith("-D")) {
+ invocation.args.add(jvmArg);
+ } else {
+ throw new UnsupportedOperationException(String.format("Cannot handle launcher JVM arg '%s' as it contains whitespace. This is not supported by Gradle %s.",
+ jvmArg, getDistribution().getVersion().getVersion()));
+ }
+ }
+ }
+ invocation.implicitLauncherJvmArgs.clear();
+
+ // Inject the launcher JVM args via one of the environment variables
+ Map<String, String> environmentVars = invocation.environmentVars;
+ String jvmOptsEnvVar;
+ if (!environmentVars.containsKey("GRADLE_OPTS")) {
+ jvmOptsEnvVar = "GRADLE_OPTS";
+ } else if (!environmentVars.containsKey("JAVA_OPTS")) {
+ jvmOptsEnvVar = "JAVA_OPTS";
+ } else {
+ // This could be handled, just not implemented yet
+ throw new UnsupportedOperationException(String.format("Both GRADLE_OPTS and JAVA_OPTS environment variables are being used. Cannot provide JVM args %s to Gradle command.", invocation.launcherJvmArgs));
+ }
+ environmentVars.put(jvmOptsEnvVar, toJvmArgsString(invocation.launcherJvmArgs));
+
+ // Add a JAVA_HOME if none provided
+ if (!environmentVars.containsKey("JAVA_HOME")) {
+ environmentVars.put("JAVA_HOME", getJavaHome().getAbsolutePath());
+ }
+ }
+
+ @Override
protected List<String> getAllArgs() {
List<String> args = new ArrayList<String>();
args.addAll(super.getAllArgs());
@@ -97,11 +138,13 @@ class ForkingGradleExecuter extends AbstractGradleExecuter {
builder.environment("GRADLE_OPTS", "");
builder.environment("JAVA_OPTS", "");
- builder.environment(getMergedEnvironmentVars());
+ GradleInvocation invocation = buildInvocation();
+
+ builder.environment(invocation.environmentVars);
builder.workingDir(getWorkingDir());
- builder.setStandardInput(getStdin());
+ builder.setStandardInput(connectStdIn());
- builder.args(getAllArgs());
+ builder.args(invocation.args);
ExecHandlerConfigurer configurer = OperatingSystem.current().isWindows() ? new WindowsConfigurer() : new UnixConfigurer();
configurer.configure(builder);
@@ -121,7 +164,7 @@ class ForkingGradleExecuter extends AbstractGradleExecuter {
}
protected ForkingGradleHandle createGradleHandle(Action<ExecutionResult> resultAssertion, String encoding, Factory<ExecHandleBuilder> execHandleFactory) {
- return new ForkingGradleHandle(resultAssertion, encoding, execHandleFactory);
+ return new ForkingGradleHandle(getStdinPipe(), isUseDaemon(), resultAssertion, encoding, execHandleFactory);
}
protected ExecutionResult doRun() {
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleHandle.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleHandle.java
index ae3a99e..62b8218 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleHandle.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ForkingGradleHandle.java
@@ -18,14 +18,18 @@ package org.gradle.integtests.fixtures.executer;
import org.apache.commons.io.output.CloseShieldOutputStream;
import org.apache.commons.io.output.TeeOutputStream;
import org.gradle.api.Action;
+import org.gradle.api.UncheckedIOException;
import org.gradle.internal.Factory;
import org.gradle.internal.UncheckedException;
import org.gradle.process.ExecResult;
import org.gradle.process.internal.AbstractExecHandleBuilder;
import org.gradle.process.internal.ExecHandle;
import org.gradle.process.internal.ExecHandleState;
+import org.gradle.util.TextUtil;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PipedOutputStream;
import java.io.UnsupportedEncodingException;
class ForkingGradleHandle extends OutputScrapingGradleHandle {
@@ -34,14 +38,23 @@ class ForkingGradleHandle extends OutputScrapingGradleHandle {
final private ByteArrayOutputStream standardOutput = new ByteArrayOutputStream();
final private ByteArrayOutputStream errorOutput = new ByteArrayOutputStream();
private final Action<ExecutionResult> resultAssertion;
+ private final PipedOutputStream stdinPipe;
+ private final boolean isDaemon;
private ExecHandle execHandle;
private final String outputEncoding;
- public ForkingGradleHandle(Action<ExecutionResult> resultAssertion, String outputEncoding, Factory<? extends AbstractExecHandleBuilder> execHandleFactory) {
+ public ForkingGradleHandle(PipedOutputStream stdinPipe, boolean isDaemon, Action<ExecutionResult> resultAssertion, String outputEncoding, Factory<? extends AbstractExecHandleBuilder> execHandleFactory) {
this.resultAssertion = resultAssertion;
this.execHandleFactory = execHandleFactory;
this.outputEncoding = outputEncoding;
+ this.isDaemon = isDaemon;
+ this.stdinPipe = stdinPipe;
+ }
+
+ @Override
+ public PipedOutputStream getStdinPipe() {
+ return stdinPipe;
}
public String getStandardOutput() {
@@ -75,6 +88,41 @@ class ForkingGradleHandle extends OutputScrapingGradleHandle {
return this;
}
+ @Override
+ public GradleHandle cancel() {
+ if (stdinPipe == null) {
+ throw new UnsupportedOperationException("Handle must be started using GradleExecuter.withStdinPipe() to use cancel()");
+ }
+
+ try {
+ stdinPipe.close();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ return this;
+ }
+
+ @Override
+ public GradleHandle cancelWithEOT() {
+ if (stdinPipe == null) {
+ throw new UnsupportedOperationException("Handle must be started using GradleExecuter.withStdinPipe() to use cancelwithEOT()");
+ }
+
+ try {
+ stdinPipe.write(4);
+ if (isDaemon) {
+ // When running a test in a daemon executer, the input is buffered until a
+ // newline char is received
+ stdinPipe.write(TextUtil.toPlatformLineSeparators("\n").getBytes());
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ return this;
+ }
+
public GradleHandle abort() {
getExecHandle().abort();
return this;
@@ -100,6 +148,11 @@ class ForkingGradleHandle extends OutputScrapingGradleHandle {
return (ExecutionFailure) waitForStop(true);
}
+ @Override
+ public void waitForExit() {
+ getExecHandle().waitForFinish().rethrowFailure();
+ }
+
protected ExecutionResult waitForStop(boolean expectFailure) {
ExecHandle execHandle = getExecHandle();
ExecResult execResult = execHandle.waitForFinish();
@@ -111,7 +164,7 @@ class ForkingGradleHandle extends OutputScrapingGradleHandle {
boolean didFail = execResult.getExitValue() != 0;
if (didFail != expectFailure) {
String message = String.format("Gradle execution %s in %s with: %s %s%nOutput:%n%s%n-----%nError:%n%s%n-----%n",
- expectFailure ? "did not fail" : "failed", execHandle.getDirectory(), execHandle.getCommand(), execHandle.getArguments(), output, error);
+ expectFailure ? "did not fail" : "failed", execHandle.getDirectory(), execHandle.getCommand(), execHandle.getArguments(), output, error);
throw new UnexpectedBuildFailure(message);
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleContextualExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleContextualExecuter.java
index 4be7e49..913678e 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleContextualExecuter.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleContextualExecuter.java
@@ -94,7 +94,7 @@ public class GradleContextualExecuter extends AbstractDelegatingGradleExecuter {
copyTo(gradleExecuter);
if (System.getProperty(UNKNOWN_OS_SYS_PROP) != null) {
- gradleExecuter.withGradleOpts("-Dos.arch=unknown architecture", "-Dos.name=unknown operating system", "-Dos.version=unknown version");
+ gradleExecuter.withBuildJvmOpts("-Dos.arch=unknown architecture", "-Dos.name=unknown operating system", "-Dos.version=unknown version");
}
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleDistribution.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleDistribution.java
index b66581b..e7aa722 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleDistribution.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleDistribution.java
@@ -15,6 +15,7 @@
*/
package org.gradle.integtests.fixtures.executer;
+import org.gradle.api.JavaVersion;
import org.gradle.internal.jvm.Jvm;
import org.gradle.internal.os.OperatingSystem;
import org.gradle.test.fixtures.file.TestDirectoryProvider;
@@ -69,6 +70,11 @@ public interface GradleDistribution {
boolean isToolingApiSupported();
/**
+ * Returns true if the tooling API of this distribution supports the given target JVM.
+ */
+ boolean isToolingApiTargetJvmSupported(JavaVersion javaVersion);
+
+ /**
* Returns true if the tooling API of this distribution correctly handles non-ASCII characters in logging output.
*/
boolean isToolingApiNonAsciiOutputSupported();
@@ -79,6 +85,11 @@ public interface GradleDistribution {
boolean isToolingApiDaemonBaseDirSupported();
/**
+ * Returns true if the tooling API of this distribution correctly implements progress events when in embedded mode.
+ */
+ boolean isToolingApiEventsInEmbeddedModeSupported();
+
+ /**
* Returns the version of the artifact cache layout
*/
VersionNumber getArtifactCacheLayoutVersion();
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleExecuter.java
index a7ef712..556dcb6 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleExecuter.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleExecuter.java
@@ -22,7 +22,7 @@ import org.gradle.test.fixtures.file.TestDirectoryProvider;
import org.gradle.test.fixtures.file.TestFile;
import java.io.File;
-import java.io.InputStream;
+import java.io.PipedOutputStream;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -95,6 +95,10 @@ public interface GradleExecuter {
/**
* Sets the <em>Gradle</em> user home dir. Setting to null requests that the executer use the real default Gradle user home dir rather than the default used for testing.
+ *
+ * This value is persistent across executions by this executer.
+ *
+ * <p>Note: does not affect the daemon base dir.</p>
*/
GradleExecuter withGradleUserHomeDir(File userHomeDir);
@@ -104,24 +108,19 @@ public interface GradleExecuter {
GradleExecuter withJavaHome(File userHomeDir);
/**
- * Sets the executable to use. Set to null to use the read default executable (if any) rather than the default used for testing.
+ * Sets the executable to use. Set to null to use the real default executable (if any) rather than the default used for testing.
*/
GradleExecuter usingExecutable(String script);
/**
- * Sets the stdin to use for the build. Defaults to an empty string.
+ * Sets a stream to use for writing to stdin which can be retrieved with getStdinPipe().
*/
- GradleExecuter withStdIn(String text);
+ GradleExecuter withStdinPipe();
/**
- * Sets the stdin to use for the build. Defaults to an empty string.
+ * Sets a stream to use for writing to stdin.
*/
- GradleExecuter withStdIn(InputStream stdin);
-
- /**
- * Specifies that the executer should not set any default jvm args.
- */
- GradleExecuter withNoDefaultJvmArgs();
+ GradleExecuter withStdinPipe(PipedOutputStream stdInPipe);
/**
* Executes the requested build, asserting that the build succeeds. Resets the configuration of this executer.
@@ -145,12 +144,35 @@ public interface GradleExecuter {
GradleHandle start();
/**
- * Adds options that should be used to start the JVM, if a JVM is to be started. Ignored if not.
+ * Adds JVM args that should be used to start any command-line `gradle` executable used to run the build. Note that this may be different to the build JVM,
+ * for example the build may run in a daemon process. You should prefer using {@link #withBuildJvmOpts(String...)} over this method.
+ */
+ GradleExecuter withCommandLineGradleOpts(String... jvmOpts);
+
+ /**
+ * See {@link #withCommandLineGradleOpts(String...)}.
+ */
+ GradleExecuter withCommandLineGradleOpts(Iterable<String> jvmOpts);
+
+ /**
+ * Adds JVM args that should be used by the build JVM. Does not necessarily imply that the build will be run in a separate process, or that a new build JVM will
+ * be started, only that the build will run in a JVM that was started with the specified args.
*
- * @param gradleOpts the jvm opts
+ * @param jvmOpts the JVM opts
* @return this executer
*/
- GradleExecuter withGradleOpts(String... gradleOpts);
+ GradleExecuter withBuildJvmOpts(String... jvmOpts);
+
+ /**
+ * See {@link #withBuildJvmOpts(String...)}.
+ */
+ GradleExecuter withBuildJvmOpts(Iterable<String> jvmOpts);
+
+ /**
+ * Specifies that the executer should only those JVM args explicitly requested using {@link #withBuildJvmOpts(String...)} and {@link #withCommandLineGradleOpts(String...)}
+ * (where appropriate) for the build JVM and not attempt to provide any others.
+ */
+ GradleExecuter useDefaultBuildJvmArgs();
/**
* Sets the default character encoding to use.
@@ -187,13 +209,22 @@ public interface GradleExecuter {
GradleExecuter withDaemonIdleTimeoutSecs(int secs);
/**
- * Set the working space for the daemon and launched daemons
+ * Set the working space for any daemons used by the builds.
+ *
+ * This value is persistent across executions by this executer.
+ *
+ * <p>Note: this does not affect the Gradle user home directory.</p>
*
* @return this executer
*/
GradleExecuter withDaemonBaseDir(File baseDir);
/**
+ * Requires that the build run in a separate daemon process.
+ */
+ GradleExecuter requireDaemon();
+
+ /**
* Asserts that this executer will be able to run a build, given its current configuration.
*
* @throws AssertionError When this executer will not be able to run a build.
@@ -249,13 +280,18 @@ public interface GradleExecuter {
/**
* Requires that there is a gradle home for the execution, which in process execution does not.
+ *
+ * <p>Note: try to avoid using this method. It has some major drawbacks when it comes to development: 1. It requires a Gradle distribution or installation, and this will
+ * need to be rebuilt after each change in order to use the test, and 2. it requires that the build run in a different JVM, which makes it very difficult to debug.</p>
*/
GradleExecuter requireGradleHome();
/**
- * Configures that any daemons launched by or during the execution are unique to the test.
+ * Configures that any daemons used by the execution are unique to the test.
+ *
+ * This value is persistent across executions by this executer.
*
- * This value is persistent across executions in the same test.
+ * <p>Note: this does not affect the Gradle user home directory.</p>
*/
GradleExecuter requireIsolatedDaemons();
@@ -264,7 +300,9 @@ public interface GradleExecuter {
*
* The gradle user home dir used will be underneath the {@link #getTestDirectoryProvider()} directory.
*
- * This value is persistent across executions in the same test.
+ * This value is persistent across executions by this executer.
+ *
+ * <p>Note: does not affect the daemon base dir.</p>
*/
GradleExecuter requireOwnGradleUserHomeDir();
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleHandle.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleHandle.java
index 29afeb2..c939c89 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleHandle.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleHandle.java
@@ -15,8 +15,15 @@
*/
package org.gradle.integtests.fixtures.executer;
+import java.io.PipedOutputStream;
+
public interface GradleHandle {
/**
+ * Returns the stream for writing to stdin.
+ */
+ PipedOutputStream getStdinPipe();
+
+ /**
* Returns the stdout output currently received from the build. This is live.
*/
String getStandardOutput();
@@ -32,6 +39,16 @@ public interface GradleHandle {
GradleHandle abort();
/**
+ * Cancel a build that was started as a cancellable build by closing stdin. Does not block until the build has finished.
+ */
+ GradleHandle cancel();
+
+ /**
+ * Cancel a build that was started as a cancellable build by sending EOT (ctrl-d). Does not block until the build has finished.
+ */
+ GradleHandle cancelWithEOT();
+
+ /**
* Blocks until the build is complete and assert that the build completed successfully.
*/
ExecutionResult waitForFinish();
@@ -42,6 +59,11 @@ public interface GradleHandle {
ExecutionFailure waitForFailure();
/**
+ * Blocks until the build is complete and exits, disregarding the result.
+ */
+ void waitForExit();
+
+ /**
* Returns true if the build is currently running.
*/
boolean isRunning();
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleVersions.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleVersions.java
index db5070c..2d30d83 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleVersions.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/GradleVersions.java
@@ -26,5 +26,5 @@ public class GradleVersions {
public static final String SUPPORTS_CONTINUOUS = ">=2.5";
public static final String PRE_CONTINUOUS = ">=1.2 <2.5";
-
+ public static final String SUPPORTS_DEPLOYMENT_REGISTRY = ">=2.6";
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/InProcessGradleExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/InProcessGradleExecuter.java
index 4a270bf..2586399 100755
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/InProcessGradleExecuter.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/InProcessGradleExecuter.java
@@ -23,7 +23,7 @@ import org.gradle.api.Task;
import org.gradle.api.execution.TaskExecutionGraph;
import org.gradle.api.execution.TaskExecutionGraphListener;
import org.gradle.api.execution.TaskExecutionListener;
-import org.gradle.api.internal.classpath.DefaultModuleRegistry;
+import org.gradle.api.internal.classpath.ModuleRegistry;
import org.gradle.api.internal.file.TestFiles;
import org.gradle.api.logging.StandardOutputListener;
import org.gradle.api.tasks.TaskState;
@@ -49,7 +49,6 @@ import org.gradle.launcher.daemon.configuration.DaemonUsage;
import org.gradle.launcher.exec.BuildActionExecuter;
import org.gradle.launcher.exec.BuildActionParameters;
import org.gradle.launcher.exec.DefaultBuildActionParameters;
-import org.gradle.initialization.ReportedException;
import org.gradle.logging.LoggingServiceRegistry;
import org.gradle.logging.ShowStacktrace;
import org.gradle.process.internal.JavaExecHandleBuilder;
@@ -63,7 +62,6 @@ import org.hamcrest.Matchers;
import java.io.File;
import java.io.InputStream;
import java.io.StringWriter;
-import java.lang.management.ManagementFactory;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -97,6 +95,10 @@ class InProcessGradleExecuter extends AbstractGradleExecuter {
@Override
protected ExecutionResult doRun() {
+ if (isUseDaemon()) {
+ return doStart().waitForFinish();
+ }
+
StandardOutputListener outputListener = new OutputListenerImpl();
StandardOutputListener errorListener = new OutputListenerImpl();
BuildListenerImpl buildListener = new BuildListenerImpl();
@@ -107,11 +109,15 @@ class InProcessGradleExecuter extends AbstractGradleExecuter {
throw new UnexpectedBuildFailure(e);
}
return assertResult(new InProcessExecutionResult(buildListener.executedTasks, buildListener.skippedTasks,
- new OutputScrapingExecutionResult(outputListener.toString(), errorListener.toString())));
+ new OutputScrapingExecutionResult(outputListener.toString(), errorListener.toString())));
}
@Override
protected ExecutionFailure doRunWithFailure() {
+ if (isUseDaemon()) {
+ return doStart().waitForFailure();
+ }
+
StandardOutputListener outputListener = new OutputListenerImpl();
StandardOutputListener errorListener = new OutputListenerImpl();
BuildListenerImpl buildListener = new BuildListenerImpl();
@@ -120,7 +126,7 @@ class InProcessGradleExecuter extends AbstractGradleExecuter {
throw new AssertionError("expected build to fail but it did not.");
} catch (GradleException e) {
return assertResult(new InProcessExecutionFailure(buildListener.executedTasks, buildListener.skippedTasks,
- new OutputScrapingExecutionFailure(outputListener.toString(), errorListener.toString()), e));
+ new OutputScrapingExecutionFailure(outputListener.toString(), errorListener.toString()), e));
}
}
@@ -131,22 +137,26 @@ class InProcessGradleExecuter extends AbstractGradleExecuter {
@Override
protected GradleHandle doStart() {
- return new ForkingGradleHandle(getResultAssertion(), getDefaultCharacterEncoding(), new Factory<JavaExecHandleBuilder>() {
+ return new ForkingGradleHandle(getStdinPipe(), isUseDaemon(), getResultAssertion(), getDefaultCharacterEncoding(), getJavaExecBuilder()).start();
+ }
+
+ private Factory<JavaExecHandleBuilder> getJavaExecBuilder() {
+ return new Factory<JavaExecHandleBuilder>() {
public JavaExecHandleBuilder create() {
+ GradleInvocation invocation = buildInvocation();
JavaExecHandleBuilder builder = new JavaExecHandleBuilder(TestFiles.resolver());
builder.workingDir(getWorkingDir());
- Set<File> classpath = new DefaultModuleRegistry().getFullClasspath();
+ Collection<File> classpath = GLOBAL_SERVICES.get(ModuleRegistry.class).getAdditionalClassPath().getAsFiles();
builder.classpath(classpath);
- builder.jvmArgs(getGradleOpts());
+ builder.jvmArgs(invocation.launcherJvmArgs);
+
builder.setMain(Main.class.getName());
- builder.args(getAllArgs());
- builder.setStandardInput(getStdin());
- if (isDebug()) {
- builder.jvmArgs(DEBUG_ARGS);
- }
+ builder.args(invocation.args);
+ builder.setStandardInput(connectStdIn());
+
return builder;
}
- }).start();
+ };
}
private BuildResult doRun(StandardOutputListener outputListener, StandardOutputListener errorListener, BuildListenerImpl listener) {
@@ -157,10 +167,12 @@ class InProcessGradleExecuter extends AbstractGradleExecuter {
File originalUserDir = new File(originalSysProperties.getProperty("user.dir"));
Map<String, String> originalEnv = new HashMap<String, String>(System.getenv());
+ GradleInvocation invocation = buildInvocation();
+
// Augment the environment for the execution
- System.setIn(getStdin());
+ System.setIn(connectStdIn());
processEnvironment.maybeSetProcessDir(getWorkingDir());
- for (Map.Entry<String, String> entry : getEnvironmentVars().entrySet()) {
+ for (Map.Entry<String, String> entry : invocation.environmentVars.entrySet()) {
processEnvironment.maybeSetEnvironmentVariable(entry.getKey(), entry.getValue());
}
Map<String, String> implicitJvmSystemProperties = getImplicitJvmSystemProperties();
@@ -195,11 +207,11 @@ class InProcessGradleExecuter extends AbstractGradleExecuter {
);
BuildRequestContext buildRequestContext = new DefaultBuildRequestContext(
new DefaultBuildRequestMetaData(new GradleLauncherMetaData(),
- ManagementFactory.getRuntimeMXBean().getStartTime()),
+ System.currentTimeMillis()),
new DefaultBuildCancellationToken(),
new NoOpBuildEventConsumer(),
outputListener, errorListener);
- actionExecuter.execute(action, buildRequestContext, buildActionParameters);
+ actionExecuter.execute(action, buildRequestContext, buildActionParameters, GLOBAL_SERVICES);
return new BuildResult(null, null);
} catch (ReportedException e) {
return new BuildResult(null, e.getCause());
@@ -207,7 +219,7 @@ class InProcessGradleExecuter extends AbstractGradleExecuter {
// Restore the environment
System.setProperties(originalSysProperties);
processEnvironment.maybeSetProcessDir(originalUserDir);
- for (String envVar : getEnvironmentVars().keySet()) {
+ for (String envVar : invocation.environmentVars.keySet()) {
String oldValue = originalEnv.get(envVar);
if (oldValue != null) {
processEnvironment.maybeSetEnvironmentVariable(envVar, oldValue);
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/OutputScrapingExecutionFailure.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/OutputScrapingExecutionFailure.java
index 0ee73b4..a6ea66b 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/OutputScrapingExecutionFailure.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/OutputScrapingExecutionFailure.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.regex.Pattern;
import static org.gradle.util.Matchers.isEmpty;
+import static org.gradle.util.Matchers.normalizedLineSeparators;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
@@ -126,7 +127,7 @@ public class OutputScrapingExecutionFailure extends OutputScrapingExecutionResul
}
public ExecutionFailure assertHasCause(String description) {
- assertThatCause(startsWith(description));
+ assertThatCause(normalizedLineSeparators(startsWith(description)));
return this;
}
@@ -178,4 +179,4 @@ public class OutputScrapingExecutionFailure extends OutputScrapingExecutionResul
this.causes = causes;
}
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleExecuter.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleExecuter.java
index 8af59c3..c0ecc16 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleExecuter.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleExecuter.java
@@ -47,6 +47,6 @@ class ParallelForkingGradleExecuter extends ForkingGradleExecuter {
@Override
protected ForkingGradleHandle createGradleHandle(Action<ExecutionResult> resultAssertion, String encoding, Factory<ExecHandleBuilder> execHandleFactory) {
- return new ParallelForkingGradleHandle(resultAssertion, encoding, execHandleFactory);
+ return new ParallelForkingGradleHandle(getStdinPipe(), isUseDaemon(), resultAssertion, encoding, execHandleFactory);
}
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleHandle.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleHandle.java
index fecee7f..cbcf457 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleHandle.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ParallelForkingGradleHandle.java
@@ -21,6 +21,7 @@ import org.gradle.internal.Factory;
import org.gradle.process.internal.AbstractExecHandleBuilder;
import org.gradle.util.SingleMessageLogger;
+import java.io.PipedOutputStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -31,8 +32,8 @@ import static org.junit.Assert.assertThat;
public class ParallelForkingGradleHandle extends ForkingGradleHandle {
- public ParallelForkingGradleHandle(Action<ExecutionResult> resultAssertion, String outputEncoding, Factory<? extends AbstractExecHandleBuilder> execHandleFactory) {
- super(resultAssertion, outputEncoding, execHandleFactory);
+ public ParallelForkingGradleHandle(PipedOutputStream stdinPipe, boolean isDaemon, Action<ExecutionResult> resultAssertion, String outputEncoding, Factory<? extends AbstractExecHandleBuilder> execHandleFactory) {
+ super(stdinPipe, isDaemon, resultAssertion, outputEncoding, execHandleFactory);
}
@Override
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ProgressLoggingFixture.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ProgressLoggingFixture.groovy
index 1aad1d5..af0a60a 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ProgressLoggingFixture.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/executer/ProgressLoggingFixture.groovy
@@ -67,7 +67,7 @@ class ProgressLoggingFixture extends InitScriptExecuterFixture {
}
boolean downloadProgressLogged(String url) {
- return progressLogged("Download", url)
+ return progressLogged("Download $url")
}
boolean uploadProgressLogged(URI url) {
@@ -75,17 +75,17 @@ class ProgressLoggingFixture extends InitScriptExecuterFixture {
}
boolean uploadProgressLogged(String url) {
- return progressLogged("Upload", url)
+ return progressLogged("Upload $url")
}
- private boolean progressLogged(String operation, String url) {
+ boolean progressLogged(String operation) {
def lines = progressContent
- def startIndex = lines.indexOf("[START " + operation + " " + url + "]")
+ def startIndex = lines.indexOf("[START " + operation + "]")
if (startIndex == -1) {
return false
}
lines = lines[startIndex..<lines.size()]
- lines = lines[0..lines.indexOf("[END " + operation + " " + url + "]")]
+ lines = lines[0..lines.indexOf("[END " + operation + "]")]
lines.size() >= 2
}
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/InstalledJvmLocator.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/InstalledJvmLocator.java
index 70755a0..f14f1b3 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/InstalledJvmLocator.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/InstalledJvmLocator.java
@@ -65,7 +65,7 @@ public class InstalledJvmLocator {
}
if (!installs.containsKey(currentJvm.getJavaHome())) {
// TODO - this isn't quite right
- boolean isJdk = !currentJvm.getJre().getHomeDir().equals(currentJvm.getJavaHome());
+ boolean isJdk = currentJvm.getJre() == null || !currentJvm.getJre().getHomeDir().equals(currentJvm.getJavaHome());
installs.put(currentJvm.getJavaHome(), new JvmInstallation(currentJvm.getJavaVersion(), System.getProperty("java.version"), currentJvm.getJavaHome(), isJdk, toArch(System.getProperty("os.arch"))));
}
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/JvmInstallation.java b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/JvmInstallation.java
index 9b2ed4f..01cbef2 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/JvmInstallation.java
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/integtests/fixtures/jvm/JvmInstallation.java
@@ -21,6 +21,9 @@ import org.gradle.util.VersionNumber;
import java.io.File;
+/**
+ * Should be synced with {@link org.gradle.internal.jvm.Jvm}.
+ */
public class JvmInstallation {
public enum Arch { i386, x86_64, Unknown }
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/ivy/IvyFileModule.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/ivy/IvyFileModule.groovy
index 0c1bfde..812c689 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/ivy/IvyFileModule.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/ivy/IvyFileModule.groovy
@@ -143,7 +143,7 @@ class IvyFileModule extends AbstractModule implements IvyModule {
}
protected String getIvyFilePath() {
- getArtifactFilePath(name: "ivy", type: "ivy", ext: "xml")
+ getArtifactFilePath([name: "ivy", type: "ivy", ext: "xml"], ivyPattern)
}
TestFile getIvyFile() {
@@ -162,10 +162,10 @@ class IvyFileModule extends AbstractModule implements IvyModule {
return moduleDir.file(getArtifactFilePath(options))
}
- protected String getArtifactFilePath(Map<String, ?> options) {
+ protected String getArtifactFilePath(Map<String, ?> options, String pattern = artifactPattern) {
def artifact = toArtifact(options)
def tokens = [organisation: organisation, module: module, revision: revision, artifact: artifact.name, type: artifact.type, ext: artifact.ext, classifier: artifact.classifier]
- M2CompatibleIvyPatternHelper.substitute(artifactPattern, m2Compatible, tokens)
+ M2CompatibleIvyPatternHelper.substitute(pattern, m2Compatible, tokens)
}
/**
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/HttpServer.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/HttpServer.groovy
index 3d58276..d0a67bb 100755
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/HttpServer.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/HttpServer.groovy
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.gradle.test.fixtures.server.http
-
+import com.google.common.collect.Sets
import com.google.common.net.UrlEscapers
import com.google.gson.Gson
import com.google.gson.JsonElement
@@ -51,13 +51,15 @@ class HttpServer extends ServerWithExpectations {
private Connector connector
private SslSocketConnector sslConnector
AuthScheme authenticationScheme = AuthScheme.BASIC
+ boolean logRequests = true
+ final Set<String> authenticationOrder = Sets.newLinkedHashSet()
protected Matcher expectedUserAgent = null
List<ServerExpectation> expectations = []
enum AuthScheme {
- BASIC(new BasicAuthHandler()), DIGEST(new DigestAuthHandler())
+ BASIC(new BasicAuthHandler()), DIGEST(new DigestAuthHandler()), PREEMPTIVE_BASIC(new PreemptiveBasicAuthHandler())
final AuthSchemeHandler handler;
@@ -92,7 +94,15 @@ class HttpServer extends ServerWithExpectations {
HandlerCollection handlers = new HandlerCollection()
handlers.addHandler(new AbstractHandler() {
void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) {
- println("handling http request: $request.method $target")
+ String authorization = request.getHeader(HttpHeaders.AUTHORIZATION)
+ if (authorization!=null) {
+ authenticationOrder << authorization.split(" ")[0]
+ } else {
+ authenticationOrder << "None"
+ }
+ if (logRequests) {
+ println("handling http request: $request.method $target")
+ }
}
})
handlers.addHandler(collection)
@@ -603,7 +613,7 @@ class HttpServer extends ServerWithExpectations {
})
}
- void addHandler(Handler handler){
+ void addHandler(Handler handler) {
collection.addHandler(handler)
}
@@ -717,6 +727,23 @@ class HttpServer extends ServerWithExpectations {
}
}
+ public static class PreemptiveBasicAuthHandler extends AuthSchemeHandler {
+ @Override
+ protected String constraintName() {
+ return Constraint.__BASIC_AUTH
+ }
+
+ @Override
+ protected Authenticator getAuthenticator() {
+ return new BasicAuthenticator() {
+ @Override
+ void sendChallenge(UserRealm realm, Response response) throws IOException {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ }
+ }
+ }
+
public static class DigestAuthHandler extends AuthSchemeHandler {
@Override
protected String constraintName() {
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/TestProxyServer.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/TestProxyServer.groovy
index 3b255d9..7e19e5b 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/TestProxyServer.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/http/TestProxyServer.groovy
@@ -15,7 +15,7 @@
*/
package org.gradle.test.fixtures.server.http
-import org.gradle.util.AvailablePortFinder
+import org.gradle.util.ports.FixedAvailablePortAllocator
import org.jboss.netty.handler.codec.http.HttpRequest
import org.junit.rules.ExternalResource
import org.littleshoot.proxy.DefaultHttpProxyServer
@@ -31,6 +31,7 @@ import org.littleshoot.proxy.ProxyAuthorizationHandler
class TestProxyServer extends ExternalResource {
private HttpProxyServer proxyServer
private HttpServer httpServer
+ private portFinder = FixedAvailablePortAllocator.getInstance()
int port
int requestCount
@@ -45,7 +46,7 @@ class TestProxyServer extends ExternalResource {
}
void start() {
- port = AvailablePortFinder.createPrivate().nextAvailable
+ port = portFinder.assignPort()
String remote = "localhost:${httpServer.port}"
proxyServer = new DefaultHttpProxyServer(port, [:], remote, null, new HttpRequestFilter() {
void filter(HttpRequest httpRequest) {
@@ -57,6 +58,7 @@ class TestProxyServer extends ExternalResource {
void stop() {
proxyServer?.stop()
+ portFinder.releasePort(port)
}
void requireAuthentication(final String expectedUsername, final String expectedPassword) {
diff --git a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/sftp/SFTPServer.groovy b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/sftp/SFTPServer.groovy
index 34ba403..a08b18e 100644
--- a/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/sftp/SFTPServer.groovy
+++ b/subprojects/internal-integ-testing/src/main/groovy/org/gradle/test/fixtures/server/sftp/SFTPServer.groovy
@@ -35,7 +35,6 @@ import org.gradle.test.fixtures.server.ExpectOne
import org.gradle.test.fixtures.server.RepositoryServer
import org.gradle.test.fixtures.server.ServerExpectation
import org.gradle.test.fixtures.server.ServerWithExpectations
-import org.gradle.util.AvailablePortFinder
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -93,15 +92,15 @@ class SFTPServer extends ServerWithExpectations implements RepositoryServer {
baseDir = testDirectoryProvider.getTestDirectory().createDir("sshd/files")
configDir = testDirectoryProvider.getTestDirectory().createDir("sshd/config")
- def portFinder = AvailablePortFinder.createPrivate()
- port = portFinder.nextAvailable
- sshd = setupConfiguredTestSshd()
+ // Set the port to 0 to have it automatically assign a port
+ sshd = setupConfiguredTestSshd(0)
sshd.start()
+ port = sshd.getPort()
allowInit()
}
- public void stop(boolean immediately = false) {
- sshd?.stop(immediately);
+ public void stop(boolean immediately = true) {
+ sshd?.stop(immediately)
}
public void restart() {
@@ -115,13 +114,13 @@ class SFTPServer extends ServerWithExpectations implements RepositoryServer {
passwordAuthenticationEnabled = true
}
- private SshServer setupConfiguredTestSshd() {
+ private SshServer setupConfiguredTestSshd(int sshPort) {
//copy dsa key to config directory
URL fileUrl = ClassLoader.getSystemResource("sshd-config/test-dsa.key");
FileUtils.copyURLToFile(fileUrl, new File(configDir, "test-dsa.key"));
SshServer sshServer = SshServer.setUpDefaultServer();
- sshServer.setPort(port);
+ sshServer.setPort(sshPort);
sshServer.setFileSystemFactory(new TestVirtualFileSystemFactory());
sshServer.setSubsystemFactories(Arrays.<NamedFactory<Command>> asList(new SftpSubsystem.Factory() {
Command create() {
diff --git a/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/jvm/UbuntuJvmLocatorTest.groovy b/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/jvm/UbuntuJvmLocatorTest.groovy
index fa2e23b..e00fd4f 100644
--- a/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/jvm/UbuntuJvmLocatorTest.groovy
+++ b/subprojects/internal-integ-testing/src/test/groovy/org/gradle/integtests/fixtures/jvm/UbuntuJvmLocatorTest.groovy
@@ -17,6 +17,7 @@ package org.gradle.integtests.fixtures.jvm
import org.gradle.api.JavaVersion
import org.gradle.internal.nativeintegration.filesystem.FileCanonicalizer
+import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@@ -90,7 +91,8 @@ class UbuntuJvmLocatorTest extends Specification {
def "locates JDK in canonicalized directory"() {
given:
jdk("real-install/java-1.7-openjdk-amd64")
- libDir.file("java-1.7.0-openjdk-amd64").createLink("real-install/java-1.7-openjdk-amd64")
+ def link = libDir.file("java-1.7.0-openjdk-amd64")
+ link.createLink("real-install/java-1.7-openjdk-amd64")
expect:
def jvms = locator.findJvms()
@@ -99,6 +101,9 @@ class UbuntuJvmLocatorTest extends Specification {
jvms[0].javaVersion == JavaVersion.VERSION_1_7
jvms[0].jdk
jvms[0].javaHome == libDir.file("real-install/java-1.7-openjdk-amd64")
+
+ cleanup:
+ link.delete()
}
def jre(String name) {
@@ -106,7 +111,7 @@ class UbuntuJvmLocatorTest extends Specification {
libDir.createFile("${name}/jre/bin/java")
}
- def jdk(String name) {
+ TestFile jdk(String name) {
jre(name)
libDir.createFile("${name}/bin/javac")
}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/integtests/fixtures/UrlValidator.groovy b/subprojects/internal-testing/src/main/groovy/org/gradle/integtests/fixtures/UrlValidator.groovy
index 954ecbc..03f23f2 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/integtests/fixtures/UrlValidator.groovy
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/integtests/fixtures/UrlValidator.groovy
@@ -17,24 +17,21 @@
package org.gradle.integtests.fixtures
import org.gradle.internal.hash.HashUtil
+import org.gradle.test.fixtures.ConcurrentTestUtil
import org.gradle.util.TextUtil
import org.junit.Assert
class UrlValidator {
- static void available(String theUrl, String application = null, int timeout = 30000) {
+ static void available(String theUrl, String application = null, int timeout = 30) {
URL url = new URL(theUrl)
- long expiry = System.currentTimeMillis() + timeout
- while (System.currentTimeMillis() <= expiry) {
- try {
- url.text
- return
- } catch (IOException e) {
- // continue
+ try {
+ ConcurrentTestUtil.poll(timeout) {
+ assert urlIsAvailable(url)
}
- Thread.sleep(200)
+ } catch(AssertionError e) {
+ throw new RuntimeException(String.format("Timeout waiting for %s to become available.", application != null ? application : theUrl));
}
- throw new RuntimeException(String.format("Timeout waiting for %s to become available.", application != null ? application : theUrl));
}
static void notAvailable(String theUrl) {
@@ -45,6 +42,15 @@ class UrlValidator {
}
}
+ private static boolean urlIsAvailable(URL url) {
+ try {
+ url.text
+ return true
+ } catch (IOException e) {
+ return false
+ }
+ }
+
/**
* Asserts that the content at the specified url matches the content in the provided String
*/
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/ConcurrentTestUtil.groovy b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/ConcurrentTestUtil.groovy
new file mode 100644
index 0000000..376abcd
--- /dev/null
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/ConcurrentTestUtil.groovy
@@ -0,0 +1,806 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.test.fixtures
+
+import org.gradle.internal.concurrent.ExecutorFactory
+import org.gradle.internal.concurrent.StoppableExecutor
+import org.junit.rules.ExternalResource
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import java.util.concurrent.AbstractExecutorService
+import java.util.concurrent.CopyOnWriteArraySet
+import java.util.concurrent.Executor
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.locks.Condition
+import java.util.concurrent.locks.Lock
+import java.util.concurrent.locks.ReentrantLock
+
+/**
+ * <p>A base class for writing specifications which exercise concurrent code.
+ *
+ * <p>See {@link org.gradle.util.ConcurrentSpecificationTest} for some examples.
+ *
+ * <p>Provides {@link Executor} and {@link ExecutorFactory} implementations for use during the test. These provide real concurrency.
+ * The test threads are cleaned up at the end of the test, and any exceptions thrown by those tests are propagated.
+ *
+ * <p>Provides some fixtures for testing:</p>
+ *
+ * <ul>
+ * <li>An action starts another action asynchronously without waiting for the result.</li>
+ * <li>An action starts another action asynchronously and waits for the result.</li>
+ * </ul>
+ */
+class ConcurrentTestUtil extends ExternalResource {
+ private static final Logger LOG = LoggerFactory.getLogger(ConcurrentTestUtil.class)
+
+ private Lock lock = new ReentrantLock()
+ private Condition threadsChanged = lock.newCondition()
+ private Set<TestThread> threads = [] as Set
+ private Closure failureHandler
+ private List<Throwable> failures = []
+ private timeout = 5000
+
+ ConcurrentTestUtil() {}
+
+ ConcurrentTestUtil(int timeout) {
+ this.timeout = timeout
+ }
+
+ @Override
+ protected void after() {
+ finished()
+ }
+
+ //simplistic polling assertion. attempts asserting every x millis up to some max timeout
+ static void poll(double timeout = 10, double initialDelay = 0, Closure assertion) {
+ def start = System.currentTimeMillis()
+ Thread.sleep(toMillis(initialDelay))
+ def expiry = start + toMillis(timeout) // convert to ms
+ long sleepTime = 100
+ while(true) {
+ try {
+ assertion()
+ return
+ } catch (Throwable t) {
+ if (System.currentTimeMillis() > expiry) {
+ throw t
+ }
+ sleepTime = Math.min(250, (long) (sleepTime * 1.2))
+ Thread.sleep(sleepTime);
+ }
+ }
+ }
+
+ static long toMillis(double seconds) {
+ return (long) (seconds * 1000);
+ }
+
+ void setShortTimeout(int millis) {
+ this.timeout = millis
+ }
+
+ ExecutorFactory getExecutorFactory() {
+ return new ExecutorFactory() {
+ StoppableExecutor create(String displayName) {
+ return new StoppableExecutorStub(ConcurrentTestUtil.this)
+ }
+
+ StoppableExecutor create(String displayName, int fixedSize) {
+ // Ignores size of thread pool
+ return new StoppableExecutorStub(ConcurrentTestUtil.this)
+ }
+ }
+ }
+
+ Executor getExecutor() {
+ return new Executor() {
+ void execute(Runnable runnable) {
+ startThread(runnable)
+ }
+ }
+ }
+
+ TestThread startThread(Runnable cl) {
+ lock.lock()
+ try {
+ TestThread thread = new TestThread(this, lock, cl)
+ thread.start()
+ return thread
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ /**
+ * Starts a thread which executes the given action/closure. Does not wait for the thread to complete.
+ *
+ * @return A handle to the test thread.
+ */
+ TestParticipant start(Runnable cl) {
+ lock.lock()
+ try {
+ TestThread thread = new TestThread(this, lock, cl)
+ thread.start()
+ return new TestParticipantImpl(this, thread)
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ /**
+ * Creates a new asynchronous action.
+ */
+ StartAsyncAction startsAsyncAction() {
+ return new StartAsyncAction(this)
+ }
+
+ /**
+ * Creates a new blocking action.
+ */
+ WaitForAsyncCallback waitsForAsyncCallback() {
+ return new WaitForAsyncCallback(this)
+ }
+
+ /**
+ * Creates a new action which waits until an async. action is complete.
+ */
+ WaitForAsyncAction waitsForAsyncActionToComplete() {
+ return new WaitForAsyncAction(this)
+ }
+
+ /**
+ * Returns a composite participant, which you can use to perform atomic operations on.
+ *
+ * @return A handle to the composite participant.
+ */
+ TestParticipant all(TestParticipant... participants) {
+ return new CompositeTestParticipant(this, lock, participants as List)
+ }
+
+ void onFailure(Closure cl) {
+ lock.lock()
+ try {
+ failureHandler = cl
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ private void failed(Throwable t) {
+ lock.lock()
+ try {
+ if (failureHandler != null) {
+ failureHandler.call(t)
+ } else {
+ failures << t
+ }
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ /**
+ * Waits for all threads to complete. Asserts that the threads complete in a 'short' time. Rethrows any exceptions thrown by test threads.
+ */
+ void finished() {
+ Date timeout = shortTimeout()
+ lock.lock()
+ try {
+ LOG.info("Waiting for test threads to complete.")
+ while (!threads.isEmpty()) {
+ if (!threadsChanged.awaitUntil(timeout)) {
+ failed(new IllegalStateException("Timeout waiting for test threads to complete."))
+ break;
+ }
+ }
+ threads.each { thread ->
+ thread.interrupt()
+ }
+
+ LOG.info("Finishing up.")
+ if (!failures.isEmpty()) {
+ throw failures[0]
+ }
+ } finally {
+ failureHandler = null
+ threads.clear()
+ failures.clear()
+ lock.unlock()
+ }
+
+ }
+
+ Date shortTimeout() {
+ return new Date(System.currentTimeMillis() + timeout)
+ }
+
+ void run(Closure cl, Date timeout) {
+ def thread = new TestThread(this, lock, cl)
+ thread.start()
+ thread.completesBefore(timeout)
+ }
+
+ void onThreadStart(TestThread thread) {
+ lock.lock()
+ try {
+ threads << thread
+ threadsChanged.signalAll()
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ void onThreadComplete(TestThread thread, Throwable failure) {
+ lock.lock()
+ try {
+ threads.remove(thread)
+ if (failure) {
+ failed(failure)
+ }
+ threadsChanged.signalAll()
+ } finally {
+ lock.unlock()
+ }
+ }
+}
+
+class TestThread extends Thread {
+ private static final Logger LOG = LoggerFactory.getLogger(TestThread.class)
+ private final ConcurrentTestUtil owner
+ private final Runnable action
+ private final Lock lock
+ private final Condition stateChanged
+ private boolean complete
+
+ TestThread(ConcurrentTestUtil owner, Lock lock, Runnable action) {
+ this.owner = owner
+ this.action = action
+ this.lock = lock
+ this.stateChanged = lock.newCondition()
+ }
+
+ @Override
+ void start() {
+ LOG.info("$this started.")
+
+ lock.lock()
+ try {
+ owner.onThreadStart(this)
+ stateChanged.signalAll()
+ } finally {
+ lock.unlock()
+ }
+
+ super.start()
+ }
+
+ void running() {
+ lock.lock()
+ try {
+ if (complete) {
+ throw new IllegalStateException("$this should still be running, but is not.")
+ }
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ void completesBefore(Date timeout) {
+ lock.lock()
+ try {
+ LOG.info("Waiting for $this to complete.")
+ while (!complete) {
+ if (!stateChanged.awaitUntil(timeout)) {
+ interrupt()
+ throw new IllegalStateException("Timeout waiting for $this to complete.")
+ }
+ }
+ LOG.info("$this completed.")
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ @Override
+ void run() {
+ Throwable failure = null
+ try {
+ action.run()
+ } catch (Throwable t) {
+ failure = t
+ }
+
+ lock.lock()
+ try {
+ complete = true
+ stateChanged.signalAll()
+ owner.onThreadComplete(this, failure)
+ LOG.info("$this completed.")
+ } finally {
+ lock.unlock()
+ }
+ }
+}
+
+/**
+ * Some potentially long running operation.
+ */
+interface LongRunningAction {
+ /**
+ * Blocks until this action has completed. Asserts that the action completes in a 'short' time. Rethrows any exception from the action.
+ */
+ void completed()
+
+ /**
+ * Blocks until this action has completed. Asserts that the action completes within the specified time. Rethrows any exception from the action.
+ */
+ void completesWithin(long maxWaitValue, TimeUnit maxWaitUnits)
+
+ /**
+ * Blocks until this action has completed. Asserts that the action completes before the given time. Rethrows any exception from the action.
+ */
+ void completesBefore(Date timeout)
+}
+
+interface TestParticipant extends LongRunningAction {
+ /**
+ * Asserts that this test participant is running.
+ */
+ void running()
+}
+
+abstract class AbstractAction implements LongRunningAction {
+
+ Date defaultExpiry
+
+ AbstractAction(Date defaultExpiry) {
+ this.defaultExpiry = defaultExpiry
+ }
+
+ void completed() {
+ completesBefore(defaultExpiry)
+ }
+
+ void completesWithin(long maxWaitValue, TimeUnit maxWaitUnits) {
+ Date expiry = new Date(System.currentTimeMillis() + maxWaitUnits.toMillis(maxWaitValue))
+ completesBefore(expiry + 500)
+ }
+
+ abstract void completesBefore(Date timeout)
+}
+
+abstract class AbstractTestParticipant extends AbstractAction implements TestParticipant {
+ private final ConcurrentTestUtil owner
+
+ AbstractTestParticipant(ConcurrentTestUtil owner) {
+ super(owner.shortTimeout())
+ this.owner = owner
+ }
+}
+
+class TestParticipantImpl extends AbstractTestParticipant {
+ private final TestThread thread
+
+ TestParticipantImpl(ConcurrentTestUtil owner, TestThread thread) {
+ super(owner)
+ this.thread = thread
+ }
+
+ @Override
+ void completesBefore(Date timeout) {
+ thread.completesBefore(timeout)
+ }
+
+ void running() {
+ thread.running()
+ }
+}
+
+class CompositeTestParticipant extends AbstractTestParticipant {
+ private final List<TestParticipant> participants
+ private final Lock lock
+
+ CompositeTestParticipant(ConcurrentTestUtil owner, Lock lock, List<TestParticipant> participants) {
+ super(owner)
+ this.participants = participants
+ this.lock = lock
+ }
+
+ void running() {
+ lock.lock()
+ try {
+ participants*.running()
+ } finally {
+ lock.unlock()
+ }
+ }
+
+ @Override
+ void completesBefore(Date timeout) {
+ lock.lock()
+ try {
+ participants*.completesBefore(timeout)
+ } finally {
+ lock.unlock()
+ }
+ }
+}
+
+class StoppableExecutorStub extends AbstractExecutorService implements StoppableExecutor {
+ final ConcurrentTestUtil owner
+ final Set<TestThread> threads = new CopyOnWriteArraySet<TestThread>()
+
+ StoppableExecutorStub(ConcurrentTestUtil owner) {
+ this.owner = owner
+ }
+
+ void stop() {
+ def timeout = owner.shortTimeout()
+ threads.each { it.completesBefore(timeout) }
+ }
+
+ void stop(int timeoutValue, TimeUnit timeoutUnits) {
+ throw new UnsupportedOperationException()
+ }
+
+ void requestStop() {
+ throw new UnsupportedOperationException()
+ }
+
+ void execute(Runnable runnable) {
+ threads.add(owner.startThread(runnable))
+ }
+
+ void shutdown() {
+ throw new UnsupportedOperationException()
+ }
+
+ List<Runnable> shutdownNow() {
+ throw new UnsupportedOperationException()
+ }
+
+ boolean isShutdown() {
+ throw new UnsupportedOperationException()
+ }
+
+ boolean isTerminated() {
+ throw new UnsupportedOperationException()
+ }
+
+ boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ throw new UnsupportedOperationException()
+ }
+}
+
+class AbstractAsyncAction {
+ protected final ConcurrentTestUtil owner
+ private final Lock lock = new ReentrantLock()
+ protected final Condition condition = lock.newCondition()
+ protected Throwable failure
+
+ AbstractAsyncAction(ConcurrentTestUtil owner) {
+ this.owner = owner
+ }
+
+ protected Date shortTimeout() {
+ return owner.shortTimeout()
+ }
+
+ protected void onFailure(Throwable throwable) {
+ withLock {
+ failure = throwable
+ condition.signalAll()
+ }
+ }
+
+ protected def withLock(Closure cl) {
+ lock.lock()
+ try {
+ return cl.call()
+ } finally {
+ lock.unlock()
+ }
+ }
+}
+
+class StartAsyncAction extends AbstractAsyncAction {
+ private boolean started
+ private boolean completed
+ private Thread startThread
+
+ StartAsyncAction(ConcurrentTestUtil owner) {
+ super(owner)
+ }
+
+ /**
+ * Runs the given action, and then waits until another thread calls {@link #done()}. Asserts that the start action does not block waiting for
+ * the async action to complete.
+ *
+ * @param action The start action
+ * @return this
+ */
+ StartAsyncAction started(Runnable action) {
+ owner.onFailure this.&onFailure
+ doStart(action)
+ waitForStartToComplete()
+ waitForFinish()
+ return this
+ }
+
+ /**
+ * Marks that the async. action is now finished.
+ */
+ void done() {
+ waitForStartToComplete()
+ doFinish()
+ }
+
+
+ private void doStart(Runnable action) {
+ owner.startThread {
+ withLock {
+ if (startThread != null) {
+ throw new IllegalStateException("Cannot start action multiple times.")
+ }
+ startThread = Thread.currentThread()
+ condition.signalAll()
+ }
+
+ action.run()
+
+ withLock {
+ started = true
+ condition.signalAll()
+ }
+ }
+
+ withLock {
+ while (startThread == null) {
+ condition.await()
+ }
+ }
+ }
+
+ private void doFinish() {
+ withLock {
+ if (completed) {
+ throw new IllegalStateException("Cannot run async action multiple times.")
+ }
+ completed = true
+ condition.signalAll()
+ }
+ }
+
+ private void waitForStartToComplete() {
+ Date timeout = shortTimeout()
+ withLock {
+ if (startThread == null) {
+ def e = new IllegalStateException("Action has not been started.")
+ e.printStackTrace()
+ throw e
+ }
+ if (Thread.currentThread() == startThread) {
+ def e = new IllegalStateException("Cannot wait for action to complete from the thread that is executing it.")
+ e.printStackTrace()
+ throw e
+ }
+ while (!started && !failure) {
+ if (!condition.awaitUntil(timeout)) {
+ throw new IllegalStateException("Expected action to complete quickly, but it did not.")
+ }
+ }
+ if (failure) {
+ throw failure
+ }
+ }
+ }
+
+ private void waitForFinish() {
+ Date timeout = shortTimeout()
+ withLock {
+ while (!completed && !failure) {
+ if (!condition.awaitUntil(timeout)) {
+ throw new IllegalStateException("Expected async action to complete, but it did not.")
+ }
+ }
+ if (failure) {
+ throw failure
+ }
+ }
+ }
+}
+
+abstract class AbstractWaitAction extends AbstractAsyncAction {
+ protected boolean started
+ protected boolean completed
+
+ AbstractWaitAction(ConcurrentTestUtil owner) {
+ super(owner)
+ }
+
+ protected void waitForBlockingActionToComplete() {
+ Date expiry = shortTimeout()
+ withLock {
+ while (!completed && !failure) {
+ if (!condition.awaitUntil(expiry)) {
+ throw new IllegalStateException("Expected action to unblock, but it did not.")
+ }
+ }
+ if (failure) {
+ throw failure
+ }
+ }
+ }
+
+ protected void startBlockingAction(Runnable action) {
+ owner.startThread {
+ withLock {
+ started = true
+ condition.signalAll()
+ }
+
+ action.run()
+
+ withLock {
+ completed = true
+ condition.signalAll()
+ }
+ }
+
+ withLock {
+ while (!started) {
+ condition.await()
+ }
+ }
+ }
+
+ protected void assertBlocked() {
+ withLock {
+ if (completed) {
+ throw new IllegalStateException("Expected action to block, but it did not.")
+ }
+ }
+ }
+}
+
+class WaitForAsyncCallback extends AbstractWaitAction {
+ private boolean callbackCompleted
+ private Runnable callback
+
+ WaitForAsyncCallback(ConcurrentTestUtil owner) {
+ super(owner)
+ }
+
+ /**
+ * Runs the given action. Asserts that it blocks until after asynchronous callback is made. The action must register the callback using {@link #callbackLater(Runnable)}.
+ */
+ WaitForAsyncCallback start(Runnable action) {
+ owner.onFailure this.&onFailure
+
+ startBlockingAction(action)
+ waitForCallbackToBeRegistered()
+
+ Thread.sleep(500)
+
+ assertBlocked()
+ runCallbackAction()
+ waitForBlockingActionToComplete()
+
+ return this
+ }
+
+ /**
+ * Registers the callback which will unblock the action.
+ */
+ public void callbackLater(Runnable action) {
+ withLock {
+ if (callback) {
+ throw new IllegalStateException("Cannot register callback action multiple times.")
+ }
+ if (!started) {
+ throw new IllegalStateException("Action has not been started.")
+ }
+ callback = action
+ condition.signalAll()
+ }
+ }
+
+ private def runCallbackAction() {
+ owner.startThread {
+ callback.run()
+
+ withLock {
+ callbackCompleted = true
+ condition.signalAll()
+ }
+ }
+
+ Date timeout = shortTimeout()
+ withLock {
+ while (!callbackCompleted && !failure) {
+ if (!condition.awaitUntil(timeout)) {
+ throw new IllegalStateException("Expected callback action to complete, but it did not.")
+ }
+ }
+ if (failure) {
+ throw failure
+ }
+ }
+ }
+
+ private void waitForCallbackToBeRegistered() {
+ Date expiry = shortTimeout()
+ withLock {
+ while (!callback && !failure && !completed) {
+ if (!condition.awaitUntil(expiry)) {
+ throw new IllegalStateException("Expected action to register a callback action, but it did not.")
+ }
+ }
+ if (failure) {
+ throw failure
+ }
+ if (completed) {
+ throw new IllegalStateException("Expected action to block, but it did not.")
+ }
+ }
+ }
+}
+
+class WaitForAsyncAction extends AbstractWaitAction {
+ boolean asyncActionComplete
+
+ WaitForAsyncAction(ConcurrentTestUtil owner) {
+ super(owner)
+ }
+
+ WaitForAsyncAction start(Runnable action) {
+ owner.onFailure this.&onFailure
+ startBlockingAction(action)
+ waitForAsyncAction()
+ waitForBlockingActionToComplete()
+ return this
+ }
+
+ WaitForAsyncAction done() {
+ Thread.sleep(500)
+ assertBlocked()
+
+ withLock {
+ asyncActionComplete = true
+ condition.signalAll()
+ }
+
+ return this
+ }
+
+ def waitForAsyncAction() {
+ Date expiry = shortTimeout()
+ withLock {
+ while (!asyncActionComplete && !completed && !failure) {
+ if (!condition.awaitUntil(expiry)) {
+ throw new IllegalStateException("Expected async action to be started, but it was not.")
+ }
+ }
+ if (failure) {
+ throw failure
+ }
+ if (!asyncActionComplete && completed) {
+ throw new IllegalStateException("Expected action to block, but it did not.")
+ }
+ }
+ }
+}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/archive/ArchiveTestFixture.groovy b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/archive/ArchiveTestFixture.groovy
index b10908d..642e756 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/archive/ArchiveTestFixture.groovy
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/archive/ArchiveTestFixture.groovy
@@ -37,6 +37,11 @@ class ArchiveTestFixture {
this
}
+ def assertNotContainsFile(String relativePath) {
+ assert !filesByRelativePath.keySet().contains(relativePath)
+ this
+ }
+
def assertContainsFile(String relativePath, int occurrences) {
assertContainsFile(relativePath)
def actualOccurrences = filesByRelativePath.get(relativePath).size()
@@ -74,6 +79,13 @@ class ArchiveTestFixture {
this
}
+ def doesNotContainDescendants(String... relativePaths) {
+ for (String path : relativePaths) {
+ assertNotContainsFile(path)
+ }
+ this
+ }
+
/**
* Asserts that there is exactly one file present with the given path, and that this file has the given content.
*/
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/AbstractTestDirectoryProvider.java b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/AbstractTestDirectoryProvider.java
index 8498f52..9ecea64 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/AbstractTestDirectoryProvider.java
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/AbstractTestDirectoryProvider.java
@@ -16,15 +16,12 @@
package org.gradle.test.fixtures.file;
+import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
-import org.gradle.internal.os.OperatingSystem;
-import org.junit.rules.MethodRule;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
-import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
-import java.io.File;
import java.util.Random;
import java.util.regex.Pattern;
@@ -32,7 +29,7 @@ import java.util.regex.Pattern;
/**
* A JUnit rule which provides a unique temporary folder for the test.
*/
-abstract class AbstractTestDirectoryProvider implements MethodRule, TestRule, TestDirectoryProvider {
+abstract class AbstractTestDirectoryProvider implements TestRule, TestDirectoryProvider {
private TestFile dir;
private String prefix;
protected static TestFile root;
@@ -51,42 +48,44 @@ abstract class AbstractTestDirectoryProvider implements MethodRule, TestRule, Te
return "unknown-test-class";
}
- protected Statement doApply(final Statement base, FrameworkMethod method, Object target) {
- Class<?> testClass = target.getClass();
- init(method.getName(), testClass.getSimpleName());
- boolean leaksHandles = testClass.getAnnotation(LeaksFileHandles.class) != null || method.getAnnotation(LeaksFileHandles.class) != null;
- return new TestDirectoryCleaningStatement(base, getTestDirectory(), leaksHandles);
- }
-
public Statement apply(final Statement base, Description description) {
Class<?> testClass = description.getTestClass();
init(description.getMethodName(), testClass.getSimpleName());
- boolean leaksHandles = testClass.getAnnotation(LeaksFileHandles.class) != null || description.getAnnotation(LeaksFileHandles.class) != null;
- return new TestDirectoryCleaningStatement(base, getTestDirectory(), leaksHandles);
+ boolean leaksHandles =
+ testClass.getAnnotation(LeaksFileHandles.class) != null
+ || description.getAnnotation(LeaksFileHandles.class) != null;
+ // For now, assume that all tests run with the daemon executer leak file handles
+ // This seems to be true for any test that uses `GradleExecuter.requireOwnGradleUserHomeDir`
+ leaksHandles = leaksHandles
+ || "daemon".equals(System.getProperty("org.gradle.integtest.executer"));
+ return new TestDirectoryCleaningStatement(base, getTestDirectory(), leaksHandles, description.getDisplayName());
}
- private static class TestDirectoryCleaningStatement extends Statement {
+ private class TestDirectoryCleaningStatement extends Statement {
private final Statement base;
private final TestFile testDirectory;
private final boolean leaksHandles;
+ private final String displayName;
- private TestDirectoryCleaningStatement(Statement base, TestFile testDirectory, boolean leaksHandles) {
+ private TestDirectoryCleaningStatement(Statement base, TestFile testDirectory, boolean leaksHandles, String displayName) {
this.base = base;
this.testDirectory = testDirectory;
this.leaksHandles = leaksHandles;
+ this.displayName = displayName;
}
@Override
public void evaluate() throws Throwable {
base.evaluate();
- // Don't delete on failure
try {
- testDirectory.deleteDir();
+ if (testDirectory.exists()) {
+ FileUtils.forceDelete(testDirectory);
+ }
} catch (Exception e) {
- boolean suppressException = leaksHandles && OperatingSystem.current().isWindows();
- if (suppressException) {
- e.printStackTrace();
+ if (leaksHandles) {
+ System.err.println("Couldn't delete test dir for " + displayName + " (test is holding files open)");
+ e.printStackTrace(System.err);
} else {
throw e;
}
@@ -100,9 +99,9 @@ abstract class AbstractTestDirectoryProvider implements MethodRule, TestRule, Te
methodName = getClass().getSimpleName();
}
if (prefix == null) {
- String safeMethodName = methodName.replaceAll("\\s", "_").replace(File.pathSeparator, "_").replace(":", "_").replace('"', '_');
- if (safeMethodName.length() > 60) {
- safeMethodName = safeMethodName.substring(0, 29) + "..." + safeMethodName.substring(safeMethodName.length() - 29);
+ String safeMethodName = methodName.replaceAll("[^\\w]", "_");
+ if (safeMethodName.length() > 30) {
+ safeMethodName = safeMethodName.substring(0, 19) + "..." + safeMethodName.substring(safeMethodName.length() - 9);
}
prefix = String.format("%s/%s", className, safeMethodName);
}
@@ -141,4 +140,5 @@ abstract class AbstractTestDirectoryProvider implements MethodRule, TestRule, Te
public TestFile createDir(Object... path) {
return file((Object[]) path).createDir();
}
+
}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/ClassFile.groovy b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/ClassFile.groovy
index 78ef1f6..cd2c5a8 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/ClassFile.groovy
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/ClassFile.groovy
@@ -29,34 +29,38 @@ class ClassFile {
}
ClassFile(InputStream inputStream) {
- def methodVisitor = new MethodVisitor(Opcodes.ASM5) {
- @Override
- void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
- hasLocalVars = true
- }
+ try {
+ def methodVisitor = new MethodVisitor(Opcodes.ASM5) {
+ @Override
+ void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ hasLocalVars = true
+ }
- @Override
- void visitLineNumber(int line, Label start) {
- hasLineNumbers = true
- }
- }
- def visitor = new ClassVisitor(Opcodes.ASM5) {
- @Override
- void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
- classFileVersion = version
+ @Override
+ void visitLineNumber(int line, Label start) {
+ hasLineNumbers = true
+ }
}
+ def visitor = new ClassVisitor(Opcodes.ASM5) {
+ @Override
+ void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ classFileVersion = version
+ }
- @Override
- MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
- return methodVisitor
- }
+ @Override
+ MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ return methodVisitor
+ }
- @Override
- void visitSource(String source, String debug) {
- hasSourceFile = true
+ @Override
+ void visitSource(String source, String debug) {
+ hasSourceFile = true
+ }
}
+ new ClassReader(inputStream).accept(visitor, 0)
+ } finally {
+ inputStream.close()
}
- new ClassReader(inputStream).accept(visitor, 0)
}
boolean getDebugIncludesSourceFile() {
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/LeaksFileHandles.java b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/LeaksFileHandles.java
index fec39ef..c41e87f 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/LeaksFileHandles.java
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/LeaksFileHandles.java
@@ -18,8 +18,14 @@ package org.gradle.test.fixtures.file;
import java.lang.annotation.*;
+/**
+ * Declares that the test holds files open and therefore not to error if the test workspace can't be cleaned up.
+ *
+ * @see AbstractTestDirectoryProvider
+ */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Inherited
public @interface LeaksFileHandles {
+ String value() default "";
}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestDistributionDirectoryProvider.java b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestDistributionDirectoryProvider.java
index 49f4d68..dcd297c 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestDistributionDirectoryProvider.java
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestDistributionDirectoryProvider.java
@@ -17,7 +17,6 @@
package org.gradle.test.fixtures.file;
import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.Statement;
import java.io.File;
@@ -27,10 +26,6 @@ public class TestDistributionDirectoryProvider extends AbstractTestDirectoryProv
root = new TestFile(new File("build/tmp/test distros"));
}
- public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
- return doApply(base, method, target);
- }
-
public static TestDistributionDirectoryProvider newInstance() {
return new TestDistributionDirectoryProvider();
}
@@ -41,4 +36,4 @@ public class TestDistributionDirectoryProvider extends AbstractTestDirectoryProv
return testDirectoryProvider;
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestNameTestDirectoryProvider.java b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestNameTestDirectoryProvider.java
index 1db5ce2..88e7499 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestNameTestDirectoryProvider.java
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/test/fixtures/file/TestNameTestDirectoryProvider.java
@@ -16,7 +16,6 @@
package org.gradle.test.fixtures.file;
import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.Statement;
import java.io.File;
@@ -29,10 +28,6 @@ public class TestNameTestDirectoryProvider extends AbstractTestDirectoryProvider
root = new TestFile(new File("build/tmp/test files"));
}
- public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
- return doApply(base, method, target);
- }
-
public static TestNameTestDirectoryProvider newInstance() {
return new TestNameTestDirectoryProvider();
}
@@ -42,4 +37,4 @@ public class TestNameTestDirectoryProvider extends AbstractTestDirectoryProvider
testDirectoryProvider.init(method.getName(), target.getClass().getSimpleName());
return testDirectoryProvider;
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/testfixtures/internal/NativeServicesTestFixture.java b/subprojects/internal-testing/src/main/groovy/org/gradle/testfixtures/internal/NativeServicesTestFixture.java
index 2a7a97c..715509c 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/testfixtures/internal/NativeServicesTestFixture.java
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/testfixtures/internal/NativeServicesTestFixture.java
@@ -17,7 +17,6 @@
package org.gradle.testfixtures.internal;
import org.gradle.internal.nativeintegration.services.NativeServices;
-import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider;
import java.io.File;
@@ -25,15 +24,9 @@ public class NativeServicesTestFixture {
static NativeServices nativeServices;
static boolean initialized;
- public static void initialize(File gradleUserHomeDir) {
- if (!initialized) {
- NativeServices.initialize(gradleUserHomeDir);
- }
- }
-
public static void initialize() {
if (!initialized) {
- File nativeDir = TestNameTestDirectoryProvider.newInstance().getTestDirectory();
+ File nativeDir = new File(System.getProperty("integTest.gradleUserHomeDir", "build/user-home"), "worker-1/test-fixtures");
NativeServices.initialize(nativeDir);
}
}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/util/Matchers.java b/subprojects/internal-testing/src/main/groovy/org/gradle/util/Matchers.java
index 8695c8a..14fed4c 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/util/Matchers.java
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/util/Matchers.java
@@ -83,7 +83,7 @@ public class Matchers {
public static <T extends CharSequence> Matcher<T> matchesRegexp(final String pattern) {
return new BaseMatcher<T>() {
public boolean matches(Object o) {
- return Pattern.compile(pattern).matcher((CharSequence) o).matches();
+ return Pattern.compile(pattern, Pattern.DOTALL).matcher((CharSequence) o).matches();
}
public void describeTo(Description description) {
@@ -109,9 +109,8 @@ public class Matchers {
public static <T extends CharSequence> Matcher<T> containsText(final String pattern) {
return new BaseMatcher<T>() {
public boolean matches(Object o) {
- return Pattern.compile(pattern).matcher((CharSequence) o).find();
+ return ((String) o).contains(pattern);
}
-
public void describeTo(Description description) {
description.appendText("a CharSequence that contains text ").appendValue(pattern);
}
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/util/SetSystemProperties.java b/subprojects/internal-testing/src/main/groovy/org/gradle/util/SetSystemProperties.java
index 46dbdf6..ba05206 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/util/SetSystemProperties.java
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/util/SetSystemProperties.java
@@ -16,8 +16,8 @@
package org.gradle.util;
-import org.junit.rules.MethodRule;
-import org.junit.runners.model.FrameworkMethod;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import java.util.HashMap;
@@ -27,7 +27,7 @@ import java.util.Properties;
/**
* A JUnit rule which restores system properties at the end of the test.
*/
-public class SetSystemProperties implements MethodRule {
+public class SetSystemProperties implements TestRule {
private final Properties properties;
private final Map<String, Object> customProperties = new HashMap<String, Object>();
@@ -41,7 +41,8 @@ public class SetSystemProperties implements MethodRule {
customProperties.putAll(properties);
}
- public Statement apply(final Statement base, FrameworkMethod method, Object target) {
+ @Override
+ public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
diff --git a/subprojects/internal-testing/src/main/groovy/org/gradle/util/TestPrecondition.groovy b/subprojects/internal-testing/src/main/groovy/org/gradle/util/TestPrecondition.groovy
index 9b2bfbb..f71179b 100644
--- a/subprojects/internal-testing/src/main/groovy/org/gradle/util/TestPrecondition.groovy
+++ b/subprojects/internal-testing/src/main/groovy/org/gradle/util/TestPrecondition.groovy
@@ -110,6 +110,9 @@ enum TestPrecondition implements org.gradle.internal.Factory<Boolean> {
NOT_JDK_IBM({
System.getProperty('java.vm.vendor') != 'IBM Corporation'
}),
+ JDK_IBM({
+ !NOT_JDK_IBM
+ }),
JDK_ORACLE({
System.getProperty('java.vm.vendor') == 'Oracle Corporation'
}),
@@ -125,8 +128,20 @@ enum TestPrecondition implements org.gradle.internal.Factory<Boolean> {
FILE_PERMISSIONS.fulfilled || WINDOWS.fulfilled
}),
// TODO:DAZ Should be detecting this based on tool chain, not OS
- OBJECTIVE_C_SUPPORT({
+ OBJECTIVE_C_SUPPORT({
NOT_WINDOWS.fulfilled && NOT_UNKNOWN_OS.fulfilled
+ }),
+ SMART_TERMINAL({
+ System.getenv("TERM")?.toUpperCase() != "DUMB"
+ }),
+ NOT_PULL_REQUEST_BUILD({
+ if (System.getenv("TRAVIS")?.toUpperCase() == "TRUE") {
+ return false
+ }
+ if (System.getenv("PULL_REQUEST_BUILD")?.toUpperCase() == "TRUE") {
+ return false
+ }
+ return true
});
/**
diff --git a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishBasicIntegTest.groovy b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishBasicIntegTest.groovy
index 67a234c..a6aeee0 100644
--- a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishBasicIntegTest.groovy
+++ b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishBasicIntegTest.groovy
@@ -149,9 +149,7 @@ public class IvyPublishBasicIntegTest extends AbstractIvyPublishIntegTest {
fails 'publish'
then:
- failure.assertHasCause("Exception thrown while executing model rule: org.gradle.api.publish.plugins.PublishingPlugin\$Rules#publishing(org.gradle.api.plugins.ExtensionContainer)")
+ failure.assertHasCause("Exception thrown while executing model rule: PublishingPlugin.Rules#publishing")
failure.assertHasCause("Ivy publication 'ivy' cannot include multiple components")
}
-
-
}
diff --git a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishDescriptorCustomizationIntegTest.groovy b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishDescriptorCustomizationIntegTest.groovy
index 15f3121..1e92768 100644
--- a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishDescriptorCustomizationIntegTest.groovy
+++ b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishDescriptorCustomizationIntegTest.groovy
@@ -180,7 +180,7 @@ class IvyPublishDescriptorCustomizationIntegTest extends AbstractIvyPublishInteg
then:
failure.assertHasDescription("A problem occurred configuring root project 'publish'.")
- failure.assertHasCause("Exception thrown while executing model rule: org.gradle.api.publish.plugins.PublishingPlugin\$Rules#publishing(org.gradle.api.plugins.ExtensionContainer)")
+ failure.assertHasCause("Exception thrown while executing model rule: PublishingPlugin.Rules#publishing")
failure.assertHasCause("Invalid ivy extra info element name: '${name}'")
where:
diff --git a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishHttpsIntegTest.groovy b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishHttpsIntegTest.groovy
index b1d7b6a..8ad5119 100644
--- a/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishHttpsIntegTest.groovy
+++ b/subprojects/ivy/src/integTest/groovy/org/gradle/api/publish/ivy/IvyPublishHttpsIntegTest.groovy
@@ -85,6 +85,7 @@ class IvyPublishHttpsIntegTest extends AbstractIvyPublishIntegTest {
failure.assertHasCause("javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated")
}
+ @LeaksFileHandles
def "decent error message when server can't authenticate client"() {
keyStore.enableSslWithServerAndBadClientCert(server)
initBuild()
diff --git a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/IvyPublishServices.java b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/IvyPublishServices.java
index 77b3867..f362725 100644
--- a/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/IvyPublishServices.java
+++ b/subprojects/ivy/src/main/java/org/gradle/api/publish/ivy/internal/IvyPublishServices.java
@@ -33,6 +33,9 @@ public class IvyPublishServices implements PluginServiceRegistry {
registration.addProvider(new GlobalServices());
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new ComponentRegistrationAction());
}
@@ -54,7 +57,6 @@ public class IvyPublishServices implements PluginServiceRegistry {
private static class ComponentRegistrationAction {
public void configure(ServiceRegistration registration, ComponentTypeRegistry componentTypeRegistry) {
// TODO There should be a more explicit way to execute an action against existing services
- // TODO:DAZ Dependency Management should be able to extract this from the plugin, without explicit registration
componentTypeRegistry.maybeRegisterComponentType(IvyModule.class)
.registerArtifactType(IvyDescriptorArtifact.class, ArtifactType.IVY_DESCRIPTOR);
}
diff --git a/subprojects/language-groovy/src/main/java/org/gradle/api/internal/tasks/compile/ApiGroovyCompiler.java b/subprojects/language-groovy/src/main/java/org/gradle/api/internal/tasks/compile/ApiGroovyCompiler.java
index 1caba5a..3086d36 100644
--- a/subprojects/language-groovy/src/main/java/org/gradle/api/internal/tasks/compile/ApiGroovyCompiler.java
+++ b/subprojects/language-groovy/src/main/java/org/gradle/api/internal/tasks/compile/ApiGroovyCompiler.java
@@ -70,6 +70,7 @@ public class ApiGroovyCompiler implements org.gradle.language.base.internal.comp
} catch (NoSuchMethodError ignored) { /* method was only introduced in Groovy 1.8 */ }
Map<String, Object> jointCompilationOptions = new HashMap<String, Object>();
final File stubDir = spec.getGroovyCompileOptions().getStubDir();
+ stubDir.mkdirs();
jointCompilationOptions.put("stubDir", stubDir);
jointCompilationOptions.put("keepStubs", spec.getGroovyCompileOptions().isKeepStubs());
configuration.setJointCompilationOptions(jointCompilationOptions);
diff --git a/subprojects/language-groovy/src/main/java/org/gradle/api/tasks/compile/package-info.java b/subprojects/language-groovy/src/main/java/org/gradle/api/tasks/compile/package-info.java
deleted file mode 100644
index 6b99da1..0000000
--- a/subprojects/language-groovy/src/main/java/org/gradle/api/tasks/compile/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * The compile tasks and options for Groovy.
- */
-package org.gradle.api.tasks.compile;
\ No newline at end of file
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/CustomComponentJarBinariesIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/CustomComponentJarBinariesIntegrationTest.groovy
new file mode 100644
index 0000000..736eecd
--- /dev/null
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/CustomComponentJarBinariesIntegrationTest.groovy
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.java
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.test.fixtures.archive.JarTestFixture
+
+class CustomComponentJarBinariesIntegrationTest extends AbstractIntegrationSpec {
+ def "custom component defined by plugin is built from Java source using JVM component plugin" () {
+ given:
+ file("src/lib1/java/Lib1.java") << "public class Lib1 {}"
+ file("src/lib1/resources/sample.properties") << "origin=lib1"
+
+ file("src/lib2/java/Lib2.java") << "public class Lib2 {}"
+ file("src/lib2/resources/sample.properties") << "origin=lib2"
+
+ file("src/sampleLib/lib/Sample.java") << "public class Sample extends Lib1 {}"
+ file("src/sampleLib/libResources/sample.properties") << "origin=sample"
+
+ file("src/sampleLib/bin/Bin.java") << "public class Bin extends Lib2 {}"
+ file("src/sampleLib/binResources/bin.properties") << "origin=bin"
+
+ // These should not be included in the resulting JAR
+ file("src/main/java/Java.java") << "public class Java {}"
+ file("src/main/resources/java.properties") << "origin=java"
+
+ buildFile << """
+import org.gradle.jvm.platform.internal.DefaultJavaPlatform
+import org.gradle.platform.base.internal.BinaryNamingSchemeBuilder
+
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+interface SampleLibrarySpec extends ComponentSpec {}
+
+class DefaultSampleLibrarySpec extends BaseComponentSpec implements SampleLibrarySpec {}
+
+class SampleLibraryRules extends RuleSource {
+ @ComponentType
+ void register(ComponentTypeBuilder<SampleLibrarySpec> builder) {
+ builder.defaultImplementation(DefaultSampleLibrarySpec)
+ }
+
+ @ComponentBinaries
+ public void createBinaries(ModelMap<JarBinarySpec> binaries, SampleLibrarySpec library,
+ BinaryNamingSchemeBuilder namingSchemeBuilder,
+ @Path("buildDir") File buildDir) {
+ def platform = DefaultJavaPlatform.current()
+ def binaryName = namingSchemeBuilder.withComponentName(library.name).withTypeString("jar").build().lifecycleTaskName
+ binaries.create(binaryName) { binary ->
+ binary.targetPlatform = platform
+ }
+ }
+}
+
+apply plugin: SampleLibraryRules
+
+model {
+ components {
+ lib1(JvmLibrarySpec)
+ lib2(JvmLibrarySpec)
+
+ sampleLib(SampleLibrarySpec) {
+ sources {
+ lib(JavaSourceSet) {
+ dependencies {
+ library "lib1"
+ }
+ }
+ libResources(JvmResourceSet) {}
+ }
+ binaries {
+ sampleLibJar {
+ sources {
+ bin(JavaSourceSet) {
+ source.srcDir "src/sampleLib/bin"
+ dependencies {
+ library "lib2"
+ }
+ }
+ binResources(JvmResourceSet) {
+ source.srcDir "src/sampleLib/binResources"
+ }
+ }
+ }
+ }
+ }
+ }
+ tasks {
+ create("validate") { task ->
+ task.doLast {
+ // Check for isolation of compiler source- and classpaths
+ assert compileLib1JarLib1Java.source.files*.name == [ "Lib1.java" ]
+ assert compileLib2JarLib2Java.source.files*.name == [ "Lib2.java" ]
+ assert compileSampleLibJarSampleLibLib.source.files*.name == [ "Sample.java" ]
+ assert compileSampleLibJarSampleLibBin.source.files*.name == [ "Bin.java" ]
+
+ assert compileLib1JarLib1Java.classpath.files*.name == []
+ assert compileLib2JarLib2Java.classpath.files*.name == []
+ assert compileSampleLibJarSampleLibLib.classpath.files*.name == [ "lib1.jar" ]
+ assert compileSampleLibJarSampleLibBin.classpath.files*.name == [ "lib2.jar" ]
+ }
+ }
+ }
+}
+"""
+
+ when:
+ succeeds "sampleLibJar", "validate"
+
+ then:
+ executed ":lib1Jar", ":lib2Jar"
+ new JarTestFixture(file("build/jars/sampleLibJar/sampleLib.jar")).hasDescendants(
+ "Sample.class",
+ "sample.properties",
+
+ "Bin.class",
+ "bin.properties"
+ )
+ }
+}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JarBinaryTypeVariantsTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JarBinaryTypeVariantsTest.groovy
new file mode 100644
index 0000000..64c81f7
--- /dev/null
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JarBinaryTypeVariantsTest.groovy
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.java
+
+class JarBinaryTypeVariantsTest extends VariantAwareDependencyResolutionSpec {
+
+ def "can depend on a component without specifying any variant dimension"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ first(FlavorAndBuildTypeAwareLibrary) {
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(FlavorAndBuildTypeAwareLibrary) {
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+ tasks {
+ firstDefaultDefaultJar {
+ doLast {
+ assert compileFirstDefaultDefaultJarFirstJava.taskDependencies.getDependencies(compileFirstDefaultDefaultJarFirstJava).contains(secondDefaultDefaultJar)
+ assert compileFirstDefaultDefaultJarFirstJava.classpath.files == [file("${buildDir}/jars/secondDefaultDefaultJar/second.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/first/java/FirstApp.java') << 'public class FirstApp extends SecondApp {}'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp {}'
+
+ expect:
+ succeeds ':firstDefaultDefaultJar'
+
+ }
+
+ def "can depend on a component with explicit flavors"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ first(FlavorAndBuildTypeAwareLibrary) {
+ flavors 'paid', 'free'
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(FlavorAndBuildTypeAwareLibrary) {
+ flavors 'paid', 'free'
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+ tasks {
+ firstPaidDefaultJar {
+ doLast {
+ assert compileFirstPaidDefaultJarFirstJava.taskDependencies.getDependencies(compileFirstPaidDefaultJarFirstJava).contains(secondPaidDefaultJar)
+ assert compileFirstPaidDefaultJarFirstJava.classpath.files == [file("${buildDir}/jars/secondPaidDefaultJar/second.jar")] as Set
+ }
+ }
+ firstFreeDefaultJar {
+ doLast {
+ assert compileFirstFreeDefaultJarFirstJava.taskDependencies.getDependencies(compileFirstFreeDefaultJarFirstJava).contains(secondFreeDefaultJar)
+ assert compileFirstFreeDefaultJarFirstJava.classpath.files == [file("${buildDir}/jars/secondFreeDefaultJar/second.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/first/java/FirstApp.java') << 'public class FirstApp extends SecondApp {}'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp {}'
+
+ expect:
+ succeeds ':firstPaidDefaultJar'
+ succeeds ':firstFreeDefaultJar'
+
+ }
+
+}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageCustomLibraryDependencyResolutionIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageCustomLibraryDependencyResolutionIntegrationTest.groovy
new file mode 100644
index 0000000..d418e68
--- /dev/null
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageCustomLibraryDependencyResolutionIntegrationTest.groovy
@@ -0,0 +1,1011 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.java
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import spock.lang.Unroll
+
+class JavaLanguageCustomLibraryDependencyResolutionIntegrationTest extends AbstractIntegrationSpec {
+
+ def "can depend on a custom component producing a JVM library"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ zdep(CustomLibrary)
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'zdep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ mainJar {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).contains(zdepJar)
+ assert compileMainJarMainJava.classpath.files*.name == ['zdep.jar']
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':mainJar'
+ }
+
+ @Unroll
+ def "can depend on a custom component producing a JVM library in another project with dependency {#dependency}"() {
+ given:
+ applyJavaPlugin(buildFile)
+ file('settings.gradle') << 'include "sub"'
+
+ def subBuildFile = file('sub/build.gradle')
+ subBuildFile << '''
+plugins {
+ id 'jvm-component'
+}
+'''
+ addCustomLibraryType(subBuildFile)
+ subBuildFile << '''
+model {
+ components {
+ zdep(CustomLibrary)
+ }
+}
+'''
+ buildFile << """
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ $dependency
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ mainJar {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).path.contains(':sub:zdepJar')
+ assert compileMainJarMainJava.classpath.files*.name == ['zdep.jar']
+ }
+ }
+ }
+}
+"""
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':mainJar'
+
+ where:
+ dependency << ["project ':sub' library 'zdep'", "project ':sub'"]
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "can depend on a custom component producing a JVM library with corresponding platform"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ zdep(CustomLibrary) {
+ javaVersions 6,7
+ }
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'zdep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ java6MainJar {
+ doLast {
+ assert compileJava6MainJarMainJava.taskDependencies.getDependencies(compileJava6MainJarMainJava).contains(zdep6Jar)
+ assert compileJava6MainJarMainJava.classpath.files == [file("${buildDir}/jars/zdep6Jar/zdep.jar")] as Set
+ }
+ }
+ java7MainJar {
+ doLast {
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(zdep7Jar)
+ assert compileJava7MainJarMainJava.classpath.files == [file("${buildDir}/jars/zdep7Jar/zdep.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks', ':java6MainJar', ':java7MainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':java6MainJar', ':java7MainJar'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "should fail resolving dependencies only for the missing dependency variant"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ zdep(CustomLibrary) {
+ javaVersions 7
+ }
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'zdep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ java7MainJar {
+ doLast {
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(zdepJar)
+ assert compileJava7MainJarMainJava.classpath.files == [file("${buildDir}/jars/zdepJar/zdep.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when: 'The Java 7 variant of the main jar can be built'
+ succeeds ':tasks', ':java7MainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':java7MainJar'
+
+ and: 'the Java 6 variant fails'
+ fails ':java6MainJar'
+
+ and: 'error message indicates the available platforms for the target dependency'
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'java6MainJar'' source set 'Java source 'main:java''")
+ failure.assertHasCause("Cannot find a compatible binary for library 'zdep' (Java SE 6). Available platforms: [Java SE 7]")
+
+ }
+
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "should choose the highest compatible platform variant of the target binary when dependency is a JVM component"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ zdep(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ targetPlatform 'java8'
+ }
+ main(CustomLibrary) {
+ javaVersions 7
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'zdep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ mainJar {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).contains(java7ZdepJar)
+ assert compileMainJarMainJava.classpath.files == [file("${buildDir}/jars/java7ZdepJar/zdep.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':mainJar'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "should choose the highest compatible platform variant of the target binary when dependency is a custom component"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ zdep(CustomLibrary) {
+ javaVersions 6,7,8
+ }
+ main(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'zdep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ mainJar {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).contains(zdep7Jar)
+ assert compileMainJarMainJava.classpath.files == [file("${buildDir}/jars/zdep7Jar/zdep.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':mainJar'
+ }
+
+ def "custom component can consume a JVM library"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec)
+ zdep(CustomLibrary) {
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'main'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ zdepJar {
+ doLast {
+ assert compileZdepJarZdepJava.taskDependencies.getDependencies(compileZdepJarZdepJava).contains(mainJar)
+ assert compileZdepJarZdepJava.classpath.files == [file("${buildDir}/jars/mainJar/main.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/zdep/java/App.java') << 'public class App extends TestApp {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks', ':zdepJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':zdepJar'
+ }
+
+ def "Java consumes custom component consuming Java component"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(CustomLibrary) {
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ third(JvmLibrarySpec)
+ }
+
+ tasks {
+ mainJar {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).contains(secondJar)
+ assert compileMainJarMainJava.classpath.files == [file("${buildDir}/jars/secondJar/second.jar")] as Set
+
+ assert compileSecondJarSecondJava.taskDependencies.getDependencies(compileSecondJarSecondJava).contains(thirdJar)
+ assert compileSecondJarSecondJava.classpath.files == [file("${buildDir}/jars/thirdJar/third.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(ThirdApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':mainJar'
+ }
+
+ def "Custom consumes Java component consuming custom component"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(CustomLibrary) {
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ third(CustomLibrary) {
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+ tasks {
+ mainJar {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).contains(secondJar)
+ assert compileMainJarMainJava.classpath.files == [file("${buildDir}/jars/secondJar/second.jar")] as Set
+
+ assert compileSecondJarSecondJava.taskDependencies.getDependencies(compileSecondJarSecondJava).contains(thirdJar)
+ assert compileSecondJarSecondJava.classpath.files == [file("${buildDir}/jars/thirdJar/third.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(ThirdApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':mainJar'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "Cannot build all variants of main component because of missing dependency variant"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(CustomLibrary) {
+ javaVersions 7
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ third(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ }
+ }
+
+ tasks {
+ java7MainJar {
+ doLast {
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(secondJar)
+ assert compileSecondJarSecondJava.taskDependencies.getDependencies(compileSecondJarSecondJava).contains(thirdJar)
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(ThirdApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp {}'
+
+ when: "Can resolve dependencies and compile the Java 7 variant of the main Jar"
+ succeeds ':tasks', ':java7MainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':java7MainJar'
+
+ and: "Can resolve dependencies and compile any of the dependencies"
+ succeeds ':secondJar'
+ succeeds ':thirdJar'
+
+ and: "Trying to compile the Java 6 variant fails"
+ fails ':java6MainJar'
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'java6MainJar'' source set 'Java source 'main:java''")
+ failure.assertHasCause("Cannot find a compatible binary for library 'second' (Java SE 6). Available platforms: [Java SE 7]")
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "Not all components target the same Java platforms"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(CustomLibrary) {
+ javaVersions 6,7
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ third(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ }
+ }
+
+ tasks {
+ create('checkMainDependencies') {
+ doLast {
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(second7Jar)
+ assert compileJava6MainJarMainJava.taskDependencies.getDependencies(compileJava6MainJarMainJava).contains(second6Jar)
+ }
+ }
+ create('checkSecondJava7VariantDependencies') {
+ doLast {
+ assert compileSecond7JarSecondJava.taskDependencies.getDependencies(compileSecond7JarSecondJava).contains(thirdJar)
+ }
+ }
+ create('checkSecondJava6VariantDependencies') {
+ doLast {
+ assert compileSecond6JarSecondJava.taskDependencies.getDependencies(compileSecond6JarSecondJava).empty
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(ThirdApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "Can resolve dependencies of the Java 6 and Java 7 variant of the main Jar"
+ succeeds ':checkMainDependencies'
+
+ and: "Resolving the dependencies and compiling the Java 7 variant of the second jar should work"
+ succeeds ':checkSecondJava7VariantDependencies'
+ succeeds ':second7Jar'
+
+ and: "Resolving the dependencies of the Java 6 version of the second jar should return an empty set"
+ succeeds ':checkSecondJava6VariantDependencies'
+
+ and: "Can build the Java 7 variant of all components"
+ succeeds ':java7MainJar'
+ succeeds ':second7Jar'
+ succeeds ':thirdJar'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "All components should depend on the corresponding variants"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(CustomLibrary) {
+ javaVersions 6,7
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ third(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ }
+ }
+
+ tasks {
+ java6MainJar {
+ doLast {
+ assert compileJava6MainJarMainJava.taskDependencies.getDependencies(compileJava6MainJarMainJava).contains(second6Jar)
+ assert compileJava6MainJarMainJava.classpath.files == [file("${buildDir}/jars/second6Jar/second.jar")] as Set
+ }
+ }
+ java7MainJar {
+ doLast {
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(second7Jar)
+ assert compileJava7MainJarMainJava.classpath.files == [file("${buildDir}/jars/second7Jar/second.jar")] as Set
+ }
+ }
+ second6Jar {
+ doLast {
+ assert compileSecond6JarSecondJava.taskDependencies.getDependencies(compileSecond6JarSecondJava).contains(java6ThirdJar)
+ assert compileSecond6JarSecondJava.classpath.files == [file("${buildDir}/jars/java6ThirdJar/third.jar")] as Set
+ }
+ }
+ second7Jar {
+ doLast {
+ assert compileSecond7JarSecondJava.taskDependencies.getDependencies(compileSecond7JarSecondJava).contains(java7ThirdJar)
+ assert compileSecond7JarSecondJava.classpath.files == [file("${buildDir}/jars/java7ThirdJar/third.jar")] as Set
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(ThirdApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "Can build the Java 7 variant of all components"
+ succeeds ':java7MainJar'
+ succeeds ':second7Jar'
+ succeeds ':java7ThirdJar'
+
+ and: "Can build the Java 6 variant of all components"
+ succeeds ':java6MainJar'
+ succeeds ':second6Jar'
+ succeeds ':java6ThirdJar'
+ }
+
+ def "can define a cyclic dependency"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(CustomLibrary) {
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ third(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'main'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ create('checkDependencies') {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).contains(secondJar)
+ assert compileSecondJarSecondJava.taskDependencies.getDependencies(compileSecondJarSecondJava).contains(thirdJar)
+ assert compileThirdJarThirdJava.taskDependencies.getDependencies(compileThirdJarThirdJava).contains(mainJar)
+ }
+ }
+ }
+}'''
+
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(ThirdApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp { void dependsOn(TestApp app) {} }'
+
+ and: "Can resolve the dependencies for each component"
+ succeeds ':checkDependencies'
+
+ and: 'building fails'
+ fails ':mainJar'
+ failure.assertHasDescription 'Circular dependency between the following tasks:'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "Fails if one of the dependencies provides more than one binary for the selected variant"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(CustomLibrary) {
+ // duplication is intentional!
+ javaVersions 6,6,7
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ third(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ }
+ }
+
+ tasks {
+ create('checkJava7Dependencies') {
+ doLast {
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(second7Jar)
+ assert compileSecond7JarSecondJava.taskDependencies.getDependencies(compileSecond7JarSecondJava).contains(java7ThirdJar)
+ }
+ }
+ create('checkMainJava6Dependencies') {
+ doLast {
+ assert compileJava6MainJarMainJava.taskDependencies.getDependencies(compileJava6MainJarMainJava).empty
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(ThirdApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "Can resolve dependencies of the Java 7 variant of the main and second components"
+ succeeds ':checkJava7Dependencies'
+
+ and: "Resolving the dependencies of the Java 6 variant of the main component should lead to an empty set"
+ succeeds ':checkMainJava6Dependencies'
+
+ and: "Can build the Java 7 variant of all components"
+ succeeds ':java7MainJar'
+ succeeds ':second7Jar'
+ succeeds ':java7ThirdJar'
+ }
+
+ def "complex graph of dependencies without variants"() {
+ given:
+ /*
+ +----------------+
+ | main |
+ | (Java) +-------------------------------------+
+ +--+-----------+-+ |
+ | | |
+ | | |
+ +-------------v--+ +-v---------------+ +--------v----------+
+ | second | | third <--------------+ fourth |
+ | (Java) | | (Java) | | (custom) |
+ +-------------+--+ +--+--------------+ +-------------------+
+ | |
+ | |
+ +--v------------v-+
+ | fifth |
+ | (custom) |
+ +-----------------+
+
+ */
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ library 'third'
+ library 'fourth'
+ }
+ }
+ }
+ }
+ second(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'fifth'
+ }
+ }
+ }
+ }
+ third(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'fifth'
+ }
+ }
+ }
+ }
+ fourth(CustomLibrary) {
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'third'
+ }
+ }
+ }
+ }
+ fifth(CustomLibrary) {
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+ tasks {
+ create('checkDependencies') {
+ doLast {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).containsAll([secondJar, thirdJar, fourthJar])
+ assert compileSecondJarSecondJava.taskDependencies.getDependencies(compileSecondJarSecondJava).contains(fifthJar)
+ assert compileThirdJarThirdJava.taskDependencies.getDependencies(compileThirdJarThirdJava).contains(fifthJar)
+ assert compileFourthJarFourthJava.taskDependencies.getDependencies(compileFourthJarFourthJava).contains(thirdJar)
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp { void dependsOn(SecondApp app, ThirdApp app3, FourthApp app4) {} }'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp { void dependsOn(FifthApp app) {} }'
+ file('src/third/java/ThirdApp.java') << 'public class ThirdApp { void dependsOn(FifthApp app) {} }'
+ file('src/fourth/java/FourthApp.java') << 'public class FourthApp { void dependsOn(ThirdApp app) {} }'
+ file('src/fifth/java/FifthApp.java') << 'public class FifthApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "can resolve dependencies"
+ succeeds ':checkDependencies'
+
+ and: "can build any of the components"
+ succeeds ':mainJar'
+ succeeds ':secondJar'
+ succeeds ':thirdJar'
+ succeeds ':fourthJar'
+ succeeds ':fifthJar'
+ }
+
+ void applyJavaPlugin(File buildFile) {
+ buildFile << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+'''
+ }
+
+ void addCustomLibraryType(File buildFile) {
+ buildFile << '''
+import org.gradle.internal.service.ServiceRegistry
+import org.gradle.jvm.internal.DefaultJarBinarySpec
+import org.gradle.platform.base.internal.PlatformResolvers
+import org.gradle.jvm.toolchain.JavaToolChainRegistry
+import org.gradle.platform.base.internal.DefaultPlatformRequirement
+
+interface CustomLibrary extends LibrarySpec {
+ void javaVersions(int... platforms)
+ List<Integer> getJavaVersions()
+}
+
+class DefaultCustomLibrary extends BaseComponentSpec implements CustomLibrary {
+ List<Integer> javaVersions = []
+ void javaVersions(int... platforms) { platforms.each { javaVersions << it } }
+}
+
+ class ComponentTypeRules extends RuleSource {
+
+ @ComponentType
+ void registerCustomComponentType(ComponentTypeBuilder<CustomLibrary> builder) {
+ builder.defaultImplementation(DefaultCustomLibrary)
+ }
+
+ @ComponentBinaries
+ void createBinaries(ModelMap<JarBinarySpec> binaries,
+ CustomLibrary library,
+ PlatformResolvers platforms,
+ @Path("buildDir") File buildDir,
+ JavaToolChainRegistry toolChains) {
+
+ def binariesDir = new File(buildDir, "jars")
+ def classesDir = new File(buildDir, "classes")
+ def javaVersions = library.javaVersions ?: [JavaVersion.current().majorVersion]
+ def multipleTargets = javaVersions.size() > 1
+ javaVersions.each { version ->
+ def platform = platforms.resolve(JavaPlatform, DefaultPlatformRequirement.create("java${version}"))
+ def toolChain = toolChains.getForPlatform(platform)
+ String binaryName = "${library.name}${javaVersions.size() > 1 ? version :''}Jar"
+ while (binaries.containsKey(binaryName)) { binaryName = "${binaryName}x" }
+ binaries.create(binaryName) { jar ->
+ jar.toolChain = toolChain
+ jar.targetPlatform = platform
+ }
+ }
+ }
+
+ }
+
+ apply type: ComponentTypeRules
+ '''
+ }
+}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageDependencyResolutionIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageDependencyResolutionIntegrationTest.groovy
index a8172bc..44121a2 100644
--- a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageDependencyResolutionIntegrationTest.groovy
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageDependencyResolutionIntegrationTest.groovy
@@ -16,15 +16,182 @@
package org.gradle.language.java
-import groovy.transform.NotYetImplemented
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
class JavaLanguageDependencyResolutionIntegrationTest extends AbstractIntegrationSpec {
- @NotYetImplemented // dependency resolution is done, but classpath generation still fails
def "can resolve dependency on local library"() {
- setup:
+ given:
+ applyJavaPlugin(buildFile)
buildFile << '''
+model {
+ components {
+ zdep(JvmLibrarySpec)
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'zdep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/zdep/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped ':tasks', ':compileZdepJarZdepJava', ':createZdepJar', ':zdepJar', ':compileMainJarMainJava'
+
+ }
+
+ def "can define a dependency on the same library"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'main'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks', ':mainJar'
+
+ then:
+ executedAndNotSkipped(':tasks', ':createMainJar', ':mainJar')
+
+ }
+
+ def "can define a cyclic dependency but building fails"() {
+ given: "a build file that defines a cyclic dependency"
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+class DependencyResolutionObserver extends RuleSource {
+ @Validate
+ void checkThatCyclicDependencyIsDefined(CollectionBuilder<Task> tasks) {
+ def mainJar = tasks.get('compileMainJarMainJava')
+ def main2Jar = tasks.get('compileMain2JarMain2Java')
+ }
+}
+
+apply plugin: DependencyResolutionObserver
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'main2'
+ }
+ }
+ }
+ }
+ main2(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'main'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+ file('src/main2/java/TestApp2.java') << 'public class TestApp2 {}'
+
+ when: 'Try to compile main Jar'
+ fails ':mainJar'
+
+ then: 'A cyclic dependency is found'
+ failure.assertHasDescription('Circular dependency between the following tasks')
+
+ }
+
+ def "should fail if library doesn't exist"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'someLib'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "build fails"
+ fails ':mainJar'
+
+ then: "displays the possible solution"
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':' library 'someLib'")
+ failure.assertHasCause("Project ':' does not contain library 'someLib'. Did you want to use 'main'?")
+
+ }
+
+ def "can resolve dependency on a different project library"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':dep' library 'main'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ mainJar.finalizedBy('checkDependencies')
+ create('checkDependencies') {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).path.contains(':dep:mainJar')
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << '''
plugins {
id 'jvm-component'
id 'java-lang'
@@ -32,8 +199,803 @@ plugins {
model {
components {
- dep(JvmLibrarySpec)
+ main(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+ file('dep/src/main/java/Dep.java') << 'public class Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ succeeds ':mainJar'
+
+ then:
+ executedAndNotSkipped ':dep:createMainJar'
+
+ }
+
+ def "should fail if project doesn't exist"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':sub' library 'main'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp/* extends Dep */{}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "build fails"
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':sub' library 'main'")
+ failure.assertHasCause("Project ':sub' not found.")
+
+ }
+
+ def "should fail if project exists but not library"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':dep' library 'doesNotExist'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp/* extends Dep */{}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':dep' library 'doesNotExist'")
+
+ and: "displays a suggestion about the library to use"
+ failure.assertHasCause("Project ':dep' does not contain library 'doesNotExist'. Did you want to use 'main'?")
+ }
+
+ def "should display the list of candidate libraries in case a library is not found"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':dep' library 'doesNotExist'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ awesome(JvmLibrarySpec)
+ lib(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp/* extends Dep */{}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':dep' library 'doesNotExist'")
+
+ and: "displays a list of suggestion for libraries to use"
+ failure.assertHasCause("Project ':dep' does not contain library 'doesNotExist'. Did you want to use one of 'awesome', 'lib'?")
+ }
+
+ def "can resolve dependencies on a different projects"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ other(JvmLibrarySpec)
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'other'
+ project ':dep' library 'main'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ mainJar.finalizedBy('checkDependencies')
+ create('checkDependencies') {
+ assert compileMainJarMainJava.taskDependencies.getDependencies(compileMainJarMainJava).path.containsAll(
+ [':otherJar',':dep:mainJar'])
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep implements SomeInterface {}'
+ file('src/other/java/Dep.java') << 'public class Dep {}'
+ file('dep/src/main/java/SomeInterface.java') << 'public interface SomeInterface {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ succeeds ':mainJar'
+
+ then:
+ executedAndNotSkipped ':dep:createMainJar', ':createOtherJar'
+
+ }
+
+ def "should fail and display the list of candidate libraries in case a library is required but multiple candidates available"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':dep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ awesome(JvmLibrarySpec)
+ lib(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp/* extends Dep */{}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':dep'")
+
+ and: "displays a list of suggestions for libraries in dependent project"
+ failure.assertHasCause("Project ':dep' contains more than one library. Please select one of 'awesome', 'lib'")
+ }
+
+ def "should fail and display a sensible error message if target project doesn't define any library"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':dep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp/* extends Dep */{}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':dep'")
+
+ and: "displays that the dependent project doesn't define any dependency"
+ failure.assertHasCause("Project ':dep' doesn't define any library.")
+ }
+
+ def "should fail and display a sensible error message if target project doesn't use new model"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':dep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('settings.gradle') << 'include "dep"'
+ file('dep/build.gradle') << ''
+
+ file('src/main/java/TestApp.java') << 'public class TestApp/* extends Dep */{}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':dep'")
+
+ and:
+ failure.assertHasCause("Project ':dep' doesn't define any library.")
+ }
+
+ def "classpath for sourceset excludes transitive sourceset jar"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':b' library 'main'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ create('checkClasspath') {
+ doLast {
+ def cp = compileMainJarMainJava.classpath.files
+ assert cp.contains(project(':b').createMainJar.archivePath)
+ assert !cp.contains(project(':c').createMainJar.archivePath)
+ }
+ }
+ mainJar.finalizedBy('checkClasspath')
+ }
+
+}
+'''
+ file('settings.gradle') << 'include "b","c"'
+ file('b/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':c' library 'main'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('c/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+ file('b/src/main/java/Dep.java') << 'public class Dep { void someMethod(Deeper deeper) {} }'
+ file('c/src/main/java/Deeper.java') << 'public class Deeper {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ succeeds ':mainJar'
+
+ then:
+ executedAndNotSkipped ':c:createMainJar', ':b:createMainJar'
+
+ }
+
+ def "dependency resolution should be limited to the scope of the API of a single project"() {
+ given: "project 'a' depending on project 'b' depending itself on project 'c' but 'c' doesn't exist"
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+import org.gradle.model.internal.core.ModelPath
+import org.gradle.model.internal.type.ModelType
+
+class DependencyResolutionObserver extends RuleSource {
+ @Mutate void createCheckTask(CollectionBuilder<Task> tasks) {
+ tasks.create('checkDependenciesForMainJar') {
+ doLast {
+ def task = tasks.get('compileMainJarMainJava')
+ def cp = task.classpath.files
+ assert cp == [task.project.project(':b').modelRegistry.find(ModelPath.path('tasks.createMainJar'), ModelType.of(Task)).archivePath] as Set
+
+ }
+ }
+ }
+}
+apply plugin: DependencyResolutionObserver
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':b' library 'main'
+ }
+ }
+ }
+ }
+ }
+
+}
+'''
+ file('settings.gradle') << 'include "b"'
+ file('b/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+import org.gradle.model.internal.core.ModelPath
+import org.gradle.model.internal.type.ModelType
+
+class DependencyResolutionObserver extends RuleSource {
+ @Mutate void createCheckTask(CollectionBuilder<Task> tasks) {
+ tasks.create('checkDependenciesForMainJar') {
+ doLast {
+ def task = tasks.get('compileMainJarMainJava')
+ task.classpath.files
+ }
+ }
+ }
+}
+apply plugin: DependencyResolutionObserver
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':c' library 'main'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+ file('b/src/main/java/Dep.java') << 'public class Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "we query the classpath for project 'a' library 'main'"
+ succeeds ':checkDependenciesForMainJar'
+
+ then: "dependency resolution resolves the classpath"
+ executedAndNotSkipped ':checkDependenciesForMainJar'
+
+ when: "we query the classpath for project 'b' library 'main'"
+ fails ':b:checkDependenciesForMainJar'
+
+ then: "dependency resolution fails because project 'c' doesn't exist"
+ failure.assertHasCause(/Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java''/)
+ failure.assertHasCause(/Could not resolve project ':c' library 'main'./)
+ failure.assertHasCause(/Project ':c' not found./)
+
+ }
+
+ def "classpath for sourceset excludes transitive sourceset jar if no explicit library name is used"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':b'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ create('checkClasspath') {
+ doLast {
+ def cp = compileMainJarMainJava.classpath.files
+ assert cp.contains(project(':b').createMainJar.archivePath)
+ assert !cp.contains(project(':c').createMainJar.archivePath)
+ }
+ }
+ mainJar.finalizedBy('checkClasspath')
+ }
+
+}
+'''
+ file('settings.gradle') << 'include "b","c"'
+ file('b/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':c'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('c/build.gradle') << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec)
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+ file('b/src/main/java/Dep.java') << 'public class Dep { void someMethod(Deeper deeper) {} }'
+ file('c/src/main/java/Deeper.java') << 'public class Deeper {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ succeeds ':mainJar'
+
+ then:
+ executedAndNotSkipped ':c:createMainJar', ':b:createMainJar'
+
+ }
+
+ def "fails if a dependency does not provide any JarBinarySpec"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ buildFile << '''
+
+model {
+ components {
+ zdep(CustomLibrary)
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ library 'zdep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/main/java/TestApp.java') << 'public class TestApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ when:
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Could not resolve project ':' library 'zdep'")
+
+ and:
+ failure.assertHasCause("Project ':' contains a library named 'zdep' but it doesn't have any binary of type JarBinarySpec")
+ }
+
+ def "successfully selects a JVM library if no library name is provided and 2 components are available"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+
+ main(JvmLibrarySpec) {
+ sources {
+ java {
+ dependencies {
+ project ':b'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ def projectB = file('b/build.gradle')
+ applyJavaPlugin(projectB)
+ addCustomLibraryType(projectB)
+ projectB << '''
+model {
+ components {
+ main(JvmLibrarySpec)
+ other(CustomLibrary)
+ }
+}
+'''
+ settingsFile << /include 'b'/
+
+ file('b/src/main/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ succeeds ':mainJar'
+
+ then:
+ executedAndNotSkipped(':b:createMainJar')
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "should choose appropriate Java variants"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ dep(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ }
+
+ main(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ targetPlatform 'java6'
+ sources {
+ java {
+ dependencies {
+ library 'dep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ java6MainJar.finalizedBy('checkDependencies')
+ java7MainJar.finalizedBy('checkDependencies')
+ create('checkDependencies') {
+ assert compileJava6MainJarMainJava.taskDependencies.getDependencies(compileJava6MainJarMainJava).contains(depJar)
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(depJar)
+ }
+ }
+}
+'''
+ file('src/dep/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ succeeds 'java6MainJar'
+
+ and:
+ succeeds 'java7MainJar'
+ }
+
+ def "should fail because multiple binaries match for the same variant"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+
+class CustomBinaries extends RuleSource {
+ @ComponentBinaries
+ void createBinaries(ModelMap<JarBinarySpec> binaries, JvmLibrarySpec spec) {
+ // duplicate binaries, to make sure we have two binaries for the same platform
+ def newBins = [:]
+ binaries.keySet().each { bName ->
+ def binary = binaries.get(bName)
+ newBins["${bName}2"] = binary
+ }
+
+ newBins.each { k,v -> binaries.create(k) {
+ targetPlatform = v.targetPlatform
+ toolChain = v.toolChain
+ jarFile = v.jarFile
+ }}
+ }
+}
+
+apply plugin: CustomBinaries
+
+model {
+ components {
+ dep(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ }
+
main(JvmLibrarySpec) {
+ targetPlatform 'java6'
sources {
java {
dependencies {
@@ -48,27 +1010,313 @@ model {
file('src/dep/java/Dep.java') << 'public class Dep {}'
file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
- expect:
- succeeds 'assemble'
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails ':mainJar'
+
+ then:
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Multiple binaries available for library 'dep' (Java SE 6) : [Jar 'depJar', Jar 'depJar2']")
}
- @NotYetImplemented // assertion error if a dependency doesn't exist
- def "should fail if library doesn't exist"() {
- setup:
+ def "should display reasonable error messages in case of multiple binaries available or no compatible variant is found"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+
+class CustomBinaries extends RuleSource {
+ @ComponentBinaries
+ void createBinaries(ModelMap<JarBinarySpec> binaries, JvmLibrarySpec spec) {
+ // duplicate binaries, to make sure we have two binaries for the same platform
+ def newBins = [:]
+ binaries.keySet().each { bName ->
+ if (bName =~ /dep/) {
+ def binary = binaries.get(bName)
+ newBins["${bName}2"] = binary
+ }
+ }
+
+ newBins.each { k,v -> binaries.create(k) {
+ targetPlatform = v.targetPlatform
+ toolChain = v.toolChain
+ jarFile = v.jarFile
+ }}
+ }
+}
+
+apply plugin: CustomBinaries
+
+model {
+ components {
+ dep(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ }
+
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'dep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/dep/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "attempt to build main jar Java 6"
+ fails ':java6MainJar'
+
+ then: "fails because multiple binaries are available for the Java 6 variant of 'dep'"
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'java6MainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Multiple binaries available for library 'dep' (Java SE 6) : [Jar 'depJar', Jar 'depJar2']")
+
+ when: "attempt to build main jar Java 7"
+ fails ':java7MainJar'
+
+ then: "fails because multiple binaries are available for the Java 6 compatible variant of 'dep'"
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'java7MainJar'' source set 'Java source 'main:java'")
+ failure.assertHasCause("Multiple binaries available for library 'dep' (Java SE 7) : [Jar 'depJar', Jar 'depJar2']")
+
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "should choose matching variants from dependency"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ dep(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ }
+
+ main(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ targetPlatform 'java6'
+ sources {
+ java {
+ dependencies {
+ library 'dep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ java6MainJar.finalizedBy('checkDependencies')
+ java7MainJar.finalizedBy('checkDependencies')
+ create('checkDependencies') {
+ assert compileJava6MainJarMainJava.taskDependencies.getDependencies(compileJava6MainJarMainJava).contains(java6DepJar)
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(java7DepJar)
+ }
+ }
+}
+'''
+ file('src/dep/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ succeeds 'java6MainJar', 'java7MainJar'
+ }
+
+ @Requires(TestPrecondition.JDK8_OR_LATER)
+ def "should not choose higher version than available"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ dep(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ targetPlatform 'java8'
+ }
+
+ main(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ targetPlatform 'java6'
+ sources {
+ java {
+ dependencies {
+ library 'dep'
+ }
+ }
+ }
+ }
+ }
+
+ tasks {
+ java6MainJar.finalizedBy('checkDependencies')
+ java7MainJar.finalizedBy('checkDependencies')
+ create('checkDependencies') {
+ assert compileJava6MainJarMainJava.taskDependencies.getDependencies(compileJava6MainJarMainJava).contains(java6DepJar)
+ assert compileJava7MainJarMainJava.taskDependencies.getDependencies(compileJava7MainJarMainJava).contains(java7DepJar)
+ }
+ }
+}
+'''
+ file('src/dep/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ then:
+ succeeds 'java6MainJar'
+
+ and:
+ succeeds 'java7MainJar'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "should display candidate platforms if no one matches"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ dep(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ }
+
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ sources {
+ java {
+ dependencies {
+ library 'dep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/dep/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails 'mainJar'
+
+ then:
+ failure.assertHasCause("Cannot find a compatible binary for library 'dep' (Java SE 6). Available platforms: [Java SE 7]")
+ }
+
+ @Requires(TestPrecondition.JDK8_OR_LATER)
+ def "should display candidate platforms if no one matches and multiple binaries are defined"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
+model {
+ components {
+ dep(JvmLibrarySpec) {
+ targetPlatform 'java7'
+ targetPlatform 'java8'
+ }
+
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ sources {
+ java {
+ dependencies {
+ library 'dep'
+ }
+ }
+ }
+ }
+ }
+}
+'''
+ file('src/dep/java/Dep.java') << 'public class Dep {}'
+ file('src/main/java/TestApp.java') << 'public class TestApp extends Dep {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and:
+ fails ':java6MainJar'
+
+ then:
+ failure.assertHasCause("Cannot find a compatible binary for library 'dep' (Java SE 6). Available platforms: [Java SE 7, Java SE 8]")
+ }
+
+ void applyJavaPlugin(File buildFile) {
buildFile << '''
plugins {
id 'jvm-component'
id 'java-lang'
}
+'''
+ }
+
+ void addCustomLibraryType(File buildFile) {
+ buildFile << """
+ interface CustomLibrary extends LibrarySpec {}
+ class DefaultCustomLibrary extends BaseComponentSpec implements CustomLibrary {}
+
+ class ComponentTypeRules extends RuleSource {
+ @ComponentType
+ void registerCustomComponentType(ComponentTypeBuilder<CustomLibrary> builder) {
+ builder.defaultImplementation(DefaultCustomLibrary)
+ }
+ }
+
+ apply type: ComponentTypeRules
+ """
+ }
+ def "collects all errors if there's more than one resolution failure"() {
+ given:
+ applyJavaPlugin(buildFile)
+ buildFile << '''
model {
components {
main(JvmLibrarySpec) {
sources {
java {
dependencies {
- library 'someLib'
+ library 'someLib' // first error
+ project ':b' // second error
+ project ':c' library 'foo' // third error
}
}
}
@@ -78,8 +1326,28 @@ model {
'''
file('src/main/java/TestApp.java') << 'public class TestApp {}'
- expect:
- fails 'assemble'
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ and: "build fails"
+ fails ':mainJar'
+
+ then: "displays a reasonable error message indicating the faulty source set"
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar 'mainJar'' source set 'Java source 'main:java'")
+
+ and: "first resolution error is displayed"
+ failure.assertHasCause("Could not resolve project ':' library 'someLib'")
+ failure.assertHasCause("Project ':' does not contain library 'someLib'. Did you want to use 'main'?")
+
+ and: "second resolution error is displayed"
+ failure.assertHasCause("Could not resolve project ':b'")
+ failure.assertHasCause("Project ':b' not found")
+ and: "third resolution error is displayed"
+ failure.assertHasCause("Could not resolve project ':c' library 'foo'")
+ failure.assertHasCause("Project ':c' not found")
}
}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageIntegrationTest.groovy
index 6cfa17a..77db750 100644
--- a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageIntegrationTest.groovy
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaLanguageIntegrationTest.groovy
@@ -24,7 +24,6 @@ import org.gradle.language.fixtures.TestJavaComponent
import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
-import org.hamcrest.Matchers
@LeaksFileHandles
class JavaLanguageIntegrationTest extends AbstractJvmLanguageIntegrationTest {
@@ -132,7 +131,7 @@ class JavaLanguageIntegrationTest extends AbstractJvmLanguageIntegrationTest {
@Requires(TestPrecondition.JDK8_OR_EARLIER)
def "builds all buildable and skips non-buildable platforms when assembling"() {
- def current = new DefaultJavaPlatform(JavaVersion.current())
+ def current = DefaultJavaPlatform.current()
when:
app.sources*.writeToDir(file("src/myLib/java"))
@@ -171,11 +170,9 @@ class JavaLanguageIntegrationTest extends AbstractJvmLanguageIntegrationTest {
}
"""
then:
- // TODO:DAZ Would like to use 'assemble' here, but it currently ignores non-buildable binaries
fails "myLibJar"
and:
- failure.assertHasCause("No tool chains can provide a compiler for type DefaultJavaCompileSpec:")
- failure.assertThatCause(Matchers.containsString("Could not target platform: 'Java SE 9' using tool chain: 'JDK ${JavaVersion.current().majorVersion} (${JavaVersion.current()})'"))
+ assert failure.assertHasCause("Could not target platform: 'Java SE 9' using tool chain: 'JDK ${JavaVersion.current().majorVersion} (${JavaVersion.current()})'")
}
}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaSourceSetIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaSourceSetIntegrationTest.groovy
index bf53e01..03fd030 100644
--- a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaSourceSetIntegrationTest.groovy
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/JavaSourceSetIntegrationTest.groovy
@@ -16,6 +16,9 @@
package org.gradle.language.java
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.EnableModelDsl
+import org.gradle.test.fixtures.archive.JarTestFixture
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
class JavaSourceSetIntegrationTest extends AbstractIntegrationSpec {
@@ -49,7 +52,7 @@ model {
tasks {
create('checkDependencies') {
doLast {
- def deps = $('components.main.sources.java').dependencies
+ def deps = $('components.main.sources.java').dependencies.dependencies
assert deps.size() == 3
assert deps[0].libraryName == 'someLib'
assert deps[1].projectPath == 'otherProject'
@@ -92,7 +95,7 @@ model {
tasks {
create('checkDependencies') {
doLast {
- def deps = $('components.main.sources.java').dependencies
+ def deps = $('components.main.sources.java').dependencies.dependencies
assert deps.size() == 1
assert deps[0].libraryName == 'someLib'
assert deps[0] instanceof org.gradle.platform.base.internal.DefaultDependencySpec // this guy is immutable
@@ -138,7 +141,7 @@ model {
tasks {
create('checkDependencies') {
doLast {
- def libraries = $('components.main.sources.java').dependencies*.libraryName
+ def libraries = $('components.main.sources.java').dependencies.dependencies*.libraryName
}
}
}
@@ -175,7 +178,7 @@ model {
tasks {
create('checkDependencies') {
doLast {
- def libraries = $('components.main.sources.java').dependencies*.libraryName
+ def libraries = $('components.main.sources.java').dependencies.dependencies*.libraryName
}
}
}
@@ -219,7 +222,7 @@ model {
tasks {
create('checkDependencies') {
doLast {
- def deps = $('components.main.sources.java').dependencies
+ def deps = $('components.main.sources.java').dependencies.dependencies
assert deps.size() == 3
assert deps[0].libraryName == 'someLib'
assert deps[1].projectPath == 'otherProject'
@@ -238,4 +241,52 @@ model {
noExceptionThrown()
}
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "can build JAR from multiple source sets"() {
+ given:
+ file("src/main/java/Main.java") << "public class Main {}"
+ file("src/main/resources/main.properties") << "java=6"
+ file("src/main/java7/Java7.java") << "public class Java7 {}"
+ file("src/main/java7-resources/java7.properties") << "java=7"
+
+ buildFile << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ main(JvmLibrarySpec) {
+ targetPlatform 'java6'
+ targetPlatform 'java7'
+ binaries {
+ withType(JarBinarySpec) { binary ->
+ if (binary.targetPlatform.name == "java7") {
+ sources {
+ java7(JavaSourceSet) {
+ source.srcDir "src/main/java7"
+ }
+ java7Resources(JvmResourceSet) {
+ source.srcDir "src/main/java7-resources"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+'''
+
+ when:
+ succeeds "assemble"
+
+ then:
+ new JarTestFixture(file("build/jars/java6MainJar/main.jar")).hasDescendants(
+ "Main.class", "main.properties");
+ new JarTestFixture(file("build/jars/java7MainJar/main.jar")).hasDescendants(
+ "Main.class", "main.properties", "Java7.class", "java7.properties");
+ }
+
}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/MultipleBinaryTypesWithVariantsTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/MultipleBinaryTypesWithVariantsTest.groovy
new file mode 100644
index 0000000..b35743c
--- /dev/null
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/MultipleBinaryTypesWithVariantsTest.groovy
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.java
+
+import spock.lang.Unroll
+
+import static org.gradle.util.Matchers.containsText
+
+class MultipleBinaryTypesWithVariantsTest extends VariantAwareDependencyResolutionSpec {
+
+ @Unroll("Component A(#binaryTypeA) fails resolving on B(#binaryTypeB) because of incompatible variant types")
+ def "binaries have the same variant dimension names but incompatible types"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addConflictingVariantTypesComponents(buildFile)
+ buildFile << """
+model {
+ components {
+ first($binaryTypeA) {
+
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+
+ second($binaryTypeB) {
+
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+}
+"""
+
+ file('src/first/java/FirstApp.java') << 'public class FirstApp extends SecondApp {}'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ when:
+ fails ':firstJar'
+
+ then:
+ failure.assertThatCause(containsText(errorMessage))
+
+ where:
+ binaryTypeA | binaryTypeB | errorMessage
+ 'StringBuildTypeLib' | 'BuildTypeBuildTypeLib' | "Required buildType 'default', available: 'default' but with an incompatible type (expected 'java.lang.String' was 'BuildType')"
+ 'BuildTypeBuildTypeLib' | 'StringBuildTypeLib' | "Required buildType 'default', available: 'default' but with an incompatible type (expected 'BuildType' was 'java.lang.String')"
+ 'BuildTypeBuildTypeLib' | 'AnotherBuildTypeBuildTypeLib' | "Required buildType 'default', available: 'default' but with an incompatible type (expected 'BuildType' was 'AnotherBuildType')"
+
+ }
+
+ void addConflictingVariantTypesComponents(File buildFile) {
+ buildFile << '''import org.gradle.jvm.internal.DefaultJarBinarySpec
+import org.gradle.jvm.toolchain.JavaToolChainRegistry
+import org.gradle.platform.base.internal.DefaultPlatformRequirement
+import org.gradle.platform.base.internal.PlatformResolvers
+
+interface BuildType extends Named {}
+
+interface AnotherBuildType extends Named {}
+
+class DefaultBuildType implements BuildType {
+ String name
+}
+
+class DefaultAnotherBuildType implements AnotherBuildType {
+ String name
+}
+
+trait BuildTypeAsStringJarBinarySpec implements JarBinarySpec {
+ String buildType
+
+ @Variant
+ String getBuildType() { buildType }
+}
+
+trait BuildTypeAsBuildTypeJarBinarySpec implements JarBinarySpec {
+ BuildType buildType
+
+ @Variant
+ BuildType getBuildType() { buildType }
+}
+
+trait BuildTypeAsAnotherBuildTypeJarBinarySpec implements JarBinarySpec {
+ AnotherBuildType buildType
+
+ @Variant
+ AnotherBuildType getBuildType() { buildType }
+}
+
+class StringBinary extends DefaultJarBinarySpec implements BuildTypeAsStringJarBinarySpec {
+ // workaround for Groovy bug
+ JvmBinaryTasks getTasks() { super.tasks }
+}
+
+class BuildTypeBinary extends DefaultJarBinarySpec implements BuildTypeAsBuildTypeJarBinarySpec {
+ // workaround for Groovy bug
+ JvmBinaryTasks getTasks() { super.tasks }
+}
+
+class AnotherBuildTypeBinary extends DefaultJarBinarySpec implements BuildTypeAsAnotherBuildTypeJarBinarySpec {
+ // workaround for Groovy bug
+ JvmBinaryTasks getTasks() { super.tasks }
+}
+
+// define the 3 concrete library types
+interface StringBuildTypeLib extends LibrarySpec {}
+
+interface BuildTypeBuildTypeLib extends LibrarySpec {}
+
+interface AnotherBuildTypeBuildTypeLib extends LibrarySpec {}
+
+class DefaultStringBuildTypeLib extends BaseComponentSpec implements StringBuildTypeLib {}
+
+class DefaultBuildTypeBuildTypeLib extends BaseComponentSpec implements BuildTypeBuildTypeLib {}
+
+class DefaultAnotherBuildTypeBuildTypeLib extends BaseComponentSpec implements AnotherBuildTypeBuildTypeLib {}
+
+
+class ComponentTypeRules extends RuleSource {
+
+ @ComponentType
+ void registerStringBuildTypeComponent(ComponentTypeBuilder<StringBuildTypeLib> builder) {
+ builder.defaultImplementation(DefaultStringBuildTypeLib)
+ }
+
+ @ComponentType
+ void registerBuildTypeBuildTypeComponent(ComponentTypeBuilder<BuildTypeBuildTypeLib> builder) {
+ builder.defaultImplementation(DefaultBuildTypeBuildTypeLib)
+ }
+
+ @ComponentType
+ void registerAnotherBuildTypeBuildTypeComponent(ComponentTypeBuilder<AnotherBuildTypeBuildTypeLib> builder) {
+ builder.defaultImplementation(DefaultAnotherBuildTypeBuildTypeLib)
+ }
+
+ @BinaryType
+ void registerStringBuildTypeJar(BinaryTypeBuilder<BuildTypeAsStringJarBinarySpec> builder) {
+ builder.defaultImplementation(StringBinary)
+ }
+
+ @BinaryType
+ void registerBuildTypeBuildTypeJar(BinaryTypeBuilder<BuildTypeAsBuildTypeJarBinarySpec> builder) {
+ builder.defaultImplementation(BuildTypeBinary)
+ }
+
+ @BinaryType
+ void registerAnotherBuildTypeBuildTypeJar(BinaryTypeBuilder<BuildTypeAsAnotherBuildTypeJarBinarySpec> builder) {
+ builder.defaultImplementation(AnotherBuildTypeBinary)
+ }
+
+ private void createBinary(library, platforms, toolChains, binaries, jarBuildType) {
+
+ def platform = platforms.resolve(JavaPlatform, DefaultPlatformRequirement.create("java${JavaVersion.current().majorVersion}"))
+ def toolChain = toolChains.getForPlatform(platform)
+ def baseName = "${library.name}"
+ String binaryName = "${baseName}Jar"
+ binaries.create(binaryName) { jar ->
+ jar.toolChain = toolChain
+ jar.targetPlatform = platform
+ jar.buildType = jarBuildType
+ }
+
+ }
+
+ @ComponentBinaries
+ void createBuildTypeBinaries(ModelMap<BuildTypeAsBuildTypeJarBinarySpec> binaries,
+ BuildTypeBuildTypeLib library,
+ PlatformResolvers platforms,
+ @Path("buildDir") File buildDir,
+ JavaToolChainRegistry toolChains) {
+
+ createBinary(library, platforms, toolChains, binaries, new DefaultBuildType(name:'default'))
+ }
+
+ @ComponentBinaries
+ void createStringBinaries(ModelMap<BuildTypeAsStringJarBinarySpec> binaries,
+ StringBuildTypeLib library,
+ PlatformResolvers platforms,
+ @Path("buildDir") File buildDir,
+ JavaToolChainRegistry toolChains) {
+
+ createBinary(library, platforms, toolChains, binaries, 'default')
+ }
+
+ @ComponentBinaries
+ void createAnotherBuildTypeBinaries(ModelMap<BuildTypeAsAnotherBuildTypeJarBinarySpec> binaries,
+ AnotherBuildTypeBuildTypeLib library,
+ PlatformResolvers platforms,
+ @Path("buildDir") File buildDir,
+ JavaToolChainRegistry toolChains) {
+
+ createBinary(library, platforms, toolChains, binaries, new DefaultAnotherBuildType(name:'default'))
+ }
+}
+
+apply type: ComponentTypeRules
+'''
+ }
+
+}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/SampleJavaLanguageIntegrationTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/SampleJavaLanguageIntegrationTest.groovy
index 1d3ac81..ca85d39 100644
--- a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/SampleJavaLanguageIntegrationTest.groovy
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/SampleJavaLanguageIntegrationTest.groovy
@@ -24,18 +24,75 @@ import org.junit.Rule
class SampleJavaLanguageIntegrationTest extends AbstractIntegrationSpec {
@Rule
- Sample sample = new Sample(temporaryFolder, "jvmComponents/java")
+ Sample quickstart = new Sample(temporaryFolder, "newJavaPlugin/quickstart")
- def "can build java based jvm component"() {
+ @Rule
+ Sample platformAware = new Sample(temporaryFolder, "newJavaPlugin/targetplatforms")
+
+ @Rule
+ Sample multicomponent = new Sample(temporaryFolder, "newJavaPlugin/multiplecomponents")
+
+ def "quickstart sample builds java based jvm component"() {
setup:
- executer.inDirectory(sample.dir)
+ executer.inDirectory(quickstart.dir)
when:
succeeds("assemble")
then:
- new JarTestFixture(sample.dir.file("build/jars/mainJar/main.jar")).hasDescendants(
- "org/gradle/samples/HelloWorld.class"
+ new JarTestFixture(quickstart.dir.file("build/jars/mainJar/main.jar")).hasDescendants(
+ "org/gradle/Person.class", "org/gradle/resource.xml"
+ )
+ }
+
+ def "targetplatforms sample creates a binary specific source set"() {
+ setup:
+ executer.inDirectory(platformAware.dir)
+
+ when:
+ succeeds("assemble")
+
+ then: "the Java 5 version of the jar doesn't include any Java 6 class"
+ new JarTestFixture(platformAware.dir.file("core/build/jars/java5MainJar/main.jar")).hasDescendants(
+ "org/gradle/Person.class", "org/gradle/resource.xml"
+ )
+
+ and: "the Java 6 jar contains the Person6 class"
+ new JarTestFixture(platformAware.dir.file("core/build/jars/java6MainJar/main.jar")).hasDescendants(
+ "org/gradle/Person.class", "org/gradle/Person6.class", "org/gradle/resource.xml"
+ )
+
+ and:
+ new JarTestFixture(platformAware.dir.file("server/build/jars/java6MainJar/main.jar")).hasDescendants(
+ "org/gradle/Server.class"
+ )
+ }
+
+ def "multiplecomponents sample builds multiple jars"() {
+ setup:
+ executer.inDirectory(multicomponent.dir)
+
+ when:
+ succeeds("assemble")
+
+ then:
+ new JarTestFixture(multicomponent.dir.file("build/jars/clientJar/client.jar")).hasDescendants(
+ "org/gradle/Client.class"
+ )
+
+ and:
+ new JarTestFixture(multicomponent.dir.file("build/jars/serverJar/server.jar")).hasDescendants(
+ "org/gradle/PersonServer.class"
+ )
+
+ and:
+ new JarTestFixture(multicomponent.dir.file("build/jars/coreJar/core.jar")).hasDescendants(
+ "org/gradle/Person.class", "org/gradle/resource.xml"
+ )
+
+ and:
+ new JarTestFixture(multicomponent.dir.file("util/build/jars/mainJar/main.jar")).hasDescendants(
+ "org/gradle/Utils.class"
)
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/SingleBinaryTypeWithVariantsTest.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/SingleBinaryTypeWithVariantsTest.groovy
new file mode 100644
index 0000000..694104c
--- /dev/null
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/SingleBinaryTypeWithVariantsTest.groovy
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.java
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import spock.lang.Unroll
+
+class SingleBinaryTypeWithVariantsTest extends VariantAwareDependencyResolutionSpec {
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ @Unroll("matching {jdk #jdk1, flavors #flavors1, builtTypes #buildTypes1} with {jdk #jdk2, flavors #flavors2, buildTypes #buildTypes2} #outcome")
+ def "check resolution of a custom component onto a component of the same type (same class, same variant dimensions)"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ def firstFlavorsDSL = flavors1 ? 'flavors ' + flavors1.collect { "'$it'" }.join(',') : ''
+ def secondFlavorsDSL = flavors2 ? 'flavors ' + flavors2.collect { "'$it'" }.join(',') : ''
+ def firstBuildTypesDSL = buildTypes1 ? 'buildTypes ' + buildTypes1.collect { "'$it'" }.join(',') : ''
+ def secondBuildTypesDSL = buildTypes2 ? 'buildTypes ' + buildTypes2.collect { "'$it'" }.join(',') : ''
+ def firstJavaVersionsDSL = "javaVersions ${jdk1.join(',')}"
+ def secondJavaVersionsDSL = "javaVersions ${jdk2.join(',')}"
+
+ def flavorsToTest = flavors1 ?: ['default']
+ def buildTypesToTest = buildTypes1 ?: ['default']
+
+ // "selected" contains the information about the expected selected binaries
+ // so we are going to build the "tasks" block which is going to make the assertions about
+ // the selected component binary
+ String tasksBlock = generateCheckDependenciesDSLBlockForCustomComponent(selected, buildTypesToTest, flavorsToTest, jdk1)
+
+ buildFile << """
+
+model {
+ components {
+ first(FlavorAndBuildTypeAwareLibrary) {
+
+ $firstJavaVersionsDSL
+ $firstFlavorsDSL
+ $firstBuildTypesDSL
+
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(FlavorAndBuildTypeAwareLibrary) {
+
+ $secondJavaVersionsDSL
+ $secondFlavorsDSL
+ $secondBuildTypesDSL
+
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+ $tasksBlock
+}
+"""
+ file('src/first/java/FirstApp.java') << 'public class FirstApp extends SecondApp {}'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp {}'
+
+ when:
+ succeeds ':tasks'
+
+ then:
+ executedAndNotSkipped ':tasks'
+
+ expect:
+ Set consumedErrors = []
+ forEachFlavorAndBuildTypeBinary(buildTypesToTest, flavorsToTest, jdk1) { String taskName ->
+ checkResolution(errors, consumedErrors, taskName)
+ }
+
+ and:
+ // sanity check to make sure that we use all errors defined in the spec, in case the name of tasks change due
+ // to internal implementation changes or variant values changes
+ errors.keySet() == consumedErrors
+
+ where:
+ jdk1 | buildTypes1 | flavors1 | jdk2 | buildTypes2 | flavors2 | selected | errors
+ [6] | [] | [] | [6] | [] | [] | [:] | [:]
+ [6] | [] | [] | [6] | [] | [] | [firstDefaultDefaultJar: 'secondDefaultDefaultJar'] | [:]
+ [6] | [] | [] | [6] | [] | ['paid'] | [firstDefaultDefaultJar: 'secondPaidDefaultJar'] | [:]
+ [6] | [] | [] | [6] | [] | ['paid', 'free'] | [:] | [firstDefaultDefaultJar: ["Multiple binaries available for library 'second' (Java SE 6) :",
+ "Jar 'secondFreeDefaultJar'", "flavor 'free'",
+ "Jar 'secondPaidDefaultJar'", "flavor 'paid'"]]
+ [6] | ['release'] | [] | [6] | ['debug'] | [] | [:] | [firstDefaultReleaseJar: ["Cannot find a compatible binary for library 'second' (Java SE 6).",
+ "Required platform 'java6', available: 'java6'",
+ "Required buildType 'release', available: 'debug'"]]
+ [6] | [] | [] | [6] | ['release', 'debug'] | ['paid', 'free'] | [:] | [firstDefaultDefaultJar: ["Multiple binaries available for library 'second' (Java SE 6) :",
+ "Jar 'secondFreeDebugJar'", "buildType 'debug'", "flavor 'free'",
+ "Jar 'secondFreeReleaseJar'", "buildType 'release'", "flavor 'free'",
+ "Jar 'secondPaidDebugJar'", "buildType 'debug'", "flavor 'paid'",
+ "Jar 'secondPaidReleaseJar'", "buildType 'release'", "flavor 'paid'"]]
+ [6] | [] | ['paid'] | [6] | [] | ['paid'] | [firstPaidDefaultJar: 'secondPaidDefaultJar'] | [:]
+ [6] | [] | ['paid', 'free'] | [6] | [] | ['paid', 'free'] | [firstFreeDefaultJar: 'secondFreeDefaultJar',
+ firstPaidDefaultJar: 'secondPaidDefaultJar'] | [:]
+ [6] | ['debug'] | ['free'] | [6] | ['debug', 'release'] | ['free'] | [firstFreeDebugJar: 'secondFreeDebugJar'] | [:]
+ [6] | ['debug'] | ['free'] | [6] | ['debug'] | ['free', 'paid'] | [firstFreeDebugJar: 'secondFreeDebugJar'] | [:]
+ [6] | ['debug'] | ['free'] | [5, 6, 7] | ['debug'] | ['free'] | [firstFreeDebugJar: 'secondFreeDebug6Jar'] | [:]
+ [6] | ['debug'] | ['free'] | [7, 6, 5] | ['debug'] | ['free'] | [firstFreeDebugJar: 'secondFreeDebug6Jar'] | [:]
+ [7] | ['debug'] | ['free'] | [5, 6] | ['debug'] | ['free'] | [firstFreeDebugJar: 'secondFreeDebug6Jar'] | [:]
+ [6] | ['debug'] | ['free'] | [7] | ['debug'] | ['free'] | [:] | [firstFreeDebugJar: ["Cannot find a compatible binary for library 'second' (Java SE 6)",
+ "Required platform 'java6', available: 'java7'",
+ "Required flavor 'free', available: 'free'",
+ "Required buildType 'debug', available: 'debug'"]]
+ [6] | [] | ['paid'] | [6] | [] | ['free'] | [:] | [firstPaidDefaultJar: ["Cannot find a compatible binary for library 'second'",
+ "Required platform 'java6', available: 'java6'",
+ "Required flavor 'paid', available: 'free'"]]
+ [6] | [] | ['paid'] | [6] | [] | ['free', 'other'] | [:] | [firstPaidDefaultJar: ["Cannot find a compatible binary for library 'second'",
+ "Required platform 'java6', available: 'java6' on Jar 'secondFreeDefaultJar','java6' on Jar 'secondOtherDefaultJar'",
+ "Required flavor 'paid', available: 'free' on Jar 'secondFreeDefaultJar','other' on Jar 'secondOtherDefaultJar'"]]
+ [6] | [] | ['paid', 'free'] | [6] | [] | ['free', 'other'] | [:] | [firstPaidDefaultJar: ["Cannot find a compatible binary for library 'second'",
+ "Required platform 'java6', available: 'java6' on Jar 'secondFreeDefaultJar','java6' on Jar 'secondOtherDefaultJar'",
+ "Required flavor 'paid', available: 'free' on Jar 'secondFreeDefaultJar','other' on Jar 'secondOtherDefaultJar'"]]
+ [6] | [] | ['paid', 'test'] | [6] | [] | ['free', 'other'] | [:] | [firstPaidDefaultJar: ["Cannot find a compatible binary for library 'second'",
+ "Required platform 'java6', available: 'java6' on Jar 'secondFreeDefaultJar','java6' on Jar 'secondOtherDefaultJar'",
+ "Required flavor 'paid', available: 'free' on Jar 'secondFreeDefaultJar','other' on Jar 'secondOtherDefaultJar'"],
+ firstTestDefaultJar: ["Cannot find a compatible binary for library 'second'",
+ "Required platform 'java6', available: 'java6' on Jar 'secondFreeDefaultJar','java6' on Jar 'secondOtherDefaultJar'",
+ "Required flavor 'test', available: 'free' on Jar 'secondFreeDefaultJar','other' on Jar 'secondOtherDefaultJar'"]]
+ and:
+ outcome = errors ? 'fails' : 'succeeds'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ @Unroll("matching custom {jdk #jdk1, flavors #flavors1, builtTypes #buildTypes1} with Java {jdk #jdk2} #outcome")
+ def "building a custom binary type and resolving against a library with standard JarBinarySpec instances"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ def firstFlavorsDSL = flavors1 ? 'flavors ' + flavors1.collect { "'$it'" }.join(',') : ''
+ def firstBuildTypesDSL = buildTypes1 ? 'buildTypes ' + buildTypes1.collect { "'$it'" }.join(',') : ''
+ def firstJavaVersionsDSL = "javaVersions ${jdk1.join(',')}"
+ def secondJavaVersionsDSL = "${jdk2.collect { "targetPlatform 'java$it' " }.join('\n')}"
+
+ def flavorsToTest = flavors1 ?: ['default']
+ def buildTypesToTest = buildTypes1 ?: ['default']
+
+ // "selected" contains the information about the expected selected binaries
+ // so we are going to build the "tasks" block which is going to make the assertions about
+ // the selected component binary
+ String tasksBlock = generateCheckDependenciesDSLBlockForCustomComponent(selected, buildTypesToTest, flavorsToTest, jdk1)
+
+ buildFile << """
+
+model {
+ components {
+ first(FlavorAndBuildTypeAwareLibrary) {
+
+ $firstJavaVersionsDSL
+ $firstFlavorsDSL
+ $firstBuildTypesDSL
+
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(JvmLibrarySpec) {
+ $secondJavaVersionsDSL
+ }
+ }
+
+ $tasksBlock
+}
+"""
+ file('src/first/java/FirstApp.java') << 'public class FirstApp extends SecondApp {}'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp {}'
+
+ expect:
+ Set consumedErrors = []
+ forEachFlavorAndBuildTypeBinary(buildTypesToTest, flavorsToTest, jdk1) { String taskName ->
+ checkResolution(errors, consumedErrors, taskName)
+ }
+
+ and:
+ // sanity check to make sure that we use all errors defined in the spec, in case the name of tasks change due
+ // to internal implementation changes or variant values changes
+ errors.keySet() == consumedErrors
+
+ where:
+ jdk1 | buildTypes1 | flavors1 | jdk2 | selected | errors
+ [6] | [] | [] | [6] | [:] | [:]
+ [6] | ['debug'] | ['free'] | [6, 7] | [firstFreeDebugJar: 'java6SecondJar'] | [:]
+ [6, 7] | ['debug'] | ['free'] | [6, 7] | [firstFreeDebug6Jar: 'java6SecondJar',
+ firstFreeDebug7Jar: 'java7SecondJar'] | [:]
+ [5, 6] | ['debug'] | ['free'] | [6, 7] | [firstFreeDebug6Jar: 'java6SecondJar'] | [firstFreeDebug5Jar: ["Cannot find a compatible binary for library 'second' (Java SE 5)",
+ "Required platform 'java5', available: 'java6' on Jar 'java6SecondJar','java7' on Jar 'java7SecondJar'",
+ "Required flavor 'free' but no compatible binary was found",
+ "Required buildType 'debug' but no compatible binary was found"]]
+ [6] | ['debug', 'release'] | ['free', 'paid'] | [6, 7] | [firstFreeDebugJar : 'java6SecondJar',
+ firstFreeReleaseJar: 'java6SecondJar',
+ firstPaidDebugJar : 'java6SecondJar',
+ firstPaidReleaseJar: 'java6SecondJar'] | [:]
+
+ and:
+ outcome = errors ? 'fails' : 'succeeds'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ @Unroll("matching Java #jdk1 with custom {jdk #jdk2, flavors #flavors2, builtTypes #buildTypes2} #outcome")
+ def "building a standard JarBinarySpec instance and resolving against a library with custom binary types. "() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ def flavorsDSL = flavors2 ? 'flavors ' + flavors2.collect { "'$it'" }.join(',') : ''
+ def buildTypesDSL = buildTypes2 ? 'buildTypes ' + buildTypes2.collect { "'$it'" }.join(',') : ''
+ def javaVersionsDSL = "javaVersions ${jdk2.join(',')}"
+ def targetPlatformsDSL = "${jdk1.collect { "targetPlatform 'java$it' " }.join('\n')}"
+
+ // "selected" contains the information about the expected selected binaries
+ // so we are going to build the "tasks" block which is going to make the assertions about
+ // the selected component binary
+ String tasksBlock = generateCheckDependenciesDSLBlockForJavaLibrary(selected, jdk1)
+
+ buildFile << """
+
+model {
+ components {
+ first(JvmLibrarySpec) {
+ $targetPlatformsDSL
+ sources {
+ java {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+ second(FlavorAndBuildTypeAwareLibrary) {
+
+ $javaVersionsDSL
+ $flavorsDSL
+ $buildTypesDSL
+
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+ $tasksBlock
+}
+"""
+ file('src/first/java/FirstApp.java') << 'public class FirstApp extends SecondApp {}'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp {}'
+
+ expect:
+ Set consumedErrors = []
+ forEachJavaBinary(jdk1) { String taskName ->
+ checkResolution(errors, consumedErrors, taskName)
+ }
+
+ and:
+ // sanity check to make sure that we use all errors defined in the spec, in case the name of tasks change due
+ // to internal implementation changes or variant values changes
+ errors.keySet() == consumedErrors
+
+ where:
+ jdk1 | buildTypes2 | flavors2 | jdk2 | selected | errors
+ [6] | [] | [] | [6] | [:] | [:]
+ [6] | ['debug'] | ['free'] | [6, 7] | [firstJar: 'secondFreeDebug6Jar'] | [:]
+ [6, 7] | ['debug'] | ['free'] | [6, 7] | [java6FirstJar: 'secondFreeDebug6Jar',
+ java7FirstJar: 'secondFreeDebug7Jar'] | [:]
+ [5, 6] | ['debug'] | ['free'] | [6, 7] | [java6FirstJar: 'secondFreeDebug6Jar'] | [java5FirstJar: ["Cannot find a compatible binary for library 'second' (Java SE 5). Available platforms: [Java SE 6, Java SE 7]"]]
+ [6] | ['debug', 'release'] | [] | [6, 7] | [:] | [firstJar: ["Multiple binaries available for library 'second' (Java SE 6) :",
+ "Jar 'secondDefaultDebug6Jar'", "buildType 'debug'", "targetPlatform 'java6'",
+ "Jar 'secondDefaultRelease6Jar'", "buildType 'release'", "targetPlatform 'java6'"]]
+ [6] | ['debug', 'release'] | ['free', 'paid'] | [6, 7] | [:] | [firstJar: ["Multiple binaries available for library 'second' (Java SE 6) :",
+ "Jar 'secondFreeDebug6Jar'", "buildType 'debug'", "flavor 'free'", "targetPlatform 'java6'",
+ "Jar 'secondFreeRelease6Jar'", "buildType 'release'", "flavor 'free'", "targetPlatform 'java6'",
+ "Jar 'secondPaidDebug6Jar'", "buildType 'debug'", "flavor 'paid'", "targetPlatform 'java6'",
+ "Jar 'secondPaidRelease6Jar'", "buildType 'release'", "flavor 'paid'", "targetPlatform 'java6'"]]
+
+ and:
+ outcome = errors ? 'fails' : 'succeeds'
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ @Unroll("matching custom1 {jdk #jdk1, flavors #flavors) with custom2 {jdk #jdk2, builtTypes #buildTypes} #outcome")
+ def "building a custom JarBinarySpec type and resolving against a library with a different custom JarBinarySpec type"() {
+ given:
+ applyJavaPlugin(buildFile)
+ addCustomLibraryType(buildFile)
+
+ def flavorsDSL = flavors ? 'flavors ' + flavors.collect { "'$it'" }.join(',') : ''
+ def buildTypesDSL = buildTypes ? 'buildTypes ' + buildTypes.collect { "'$it'" }.join(',') : ''
+ def javaVersionsDSL1 = "javaVersions ${jdk1.join(',')}"
+ def javaVersionsDSL2 = "javaVersions ${jdk2.join(',')}"
+
+ // "selected" contains the information about the expected selected binaries
+ // so we are going to build the "tasks" block which is going to make the assertions about
+ // the selected component binary
+ def flavorsToTest = flavors ?: ['default']
+ String tasksBlock = generateCheckDependenciesDSLBlockForFlavorLibrary(selected, flavorsToTest, jdk1)
+
+ buildFile << """
+
+model {
+ components {
+ first(FlavorOnlyLibrary) {
+
+ $javaVersionsDSL1
+ $flavorsDSL
+
+ sources {
+ java(JavaSourceSet) {
+ dependencies {
+ library 'second'
+ }
+ }
+ }
+ }
+
+ second(BuildTypeOnlyLibrary) {
+
+ $javaVersionsDSL2
+ $buildTypesDSL
+
+ sources {
+ java(JavaSourceSet)
+ }
+ }
+ }
+
+ $tasksBlock
+}
+"""
+ file('src/first/java/FirstApp.java') << 'public class FirstApp extends SecondApp {}'
+ file('src/second/java/SecondApp.java') << 'public class SecondApp {}'
+
+ expect:
+ Set consumedErrors = []
+ forEachFlavor(flavorsToTest, jdk1) { String taskName ->
+ checkResolution(errors, consumedErrors, taskName)
+ }
+
+ and:
+ // sanity check to make sure that we use all errors defined in the spec, in case the name of tasks change due
+ // to internal implementation changes or variant values changes
+ errors.keySet() == consumedErrors
+
+ where:
+ jdk1 | flavors | buildTypes | jdk2 | selected | errors
+ [6] | [] | [] | [6] | [:] | [:]
+ [6] | ['free'] | ['debug'] | [6, 7] | [firstFreeJar: 'secondDebug6Jar'] | [:]
+ [6, 7] | ['free'] | ['debug'] | [6, 7] | [firstFree6Jar: 'secondDebug6Jar',
+ firstFree7Jar: 'secondDebug7Jar'] | [:]
+ [5, 6] | ['free'] | ['debug'] | [6, 7] | [firstFree6Jar: 'secondDebug6Jar'] | [firstFree5Jar: ["Cannot find a compatible binary for library 'second' (Java SE 5)",
+ "Required platform 'java5', available: 'java6' on Jar 'secondDebug6Jar','java7' on Jar 'secondDebug7Jar'",
+ "Required flavor 'free' but no compatible binary was found"]]
+ [6] | [] | ['debug', 'release'] | [6, 7] | [:] | [firstDefaultJar: ["Multiple binaries available for library 'second' (Java SE 6) :",
+ "Jar 'secondDebug6Jar'", "buildType 'debug'", "targetPlatform 'java6'",
+ "Jar 'secondRelease6Jar'", "buildType 'release'", "targetPlatform 'java6'"]]
+ [6] | ['free', 'paid'] | ['debug', 'release'] | [6, 7] | [:] | [firstFreeJar: ["Multiple binaries available for library 'second' (Java SE 6) :",
+ "Jar 'secondDebug6Jar'", "buildType 'debug'", "targetPlatform 'java6'",
+ "Jar 'secondRelease6Jar'", "buildType 'release'", "targetPlatform 'java6'"],
+ firstPaidJar: ["Multiple binaries available for library 'second' (Java SE 6) :",
+ "Jar 'secondDebug6Jar'", "buildType 'debug'", "targetPlatform 'java6'",
+ "Jar 'secondRelease6Jar'", "buildType 'release'", "targetPlatform 'java6'"]]
+
+ and:
+ outcome = errors ? 'fails' : 'succeeds'
+ }
+
+}
diff --git a/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/VariantAwareDependencyResolutionSpec.groovy b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/VariantAwareDependencyResolutionSpec.groovy
new file mode 100644
index 0000000..9976c00
--- /dev/null
+++ b/subprojects/language-java/src/integTest/groovy/org/gradle/language/java/VariantAwareDependencyResolutionSpec.groovy
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.java
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+import static org.gradle.util.Matchers.containsText
+
+abstract class VariantAwareDependencyResolutionSpec extends AbstractIntegrationSpec {
+ protected static String generateCheckDependenciesDSLBlock(Map<String, String> selected, Closure loop) {
+ def checkTasks = [:]
+ def taskNames = []
+
+ loop { taskName ->
+ if (selected[taskName]) {
+ def target = selected[taskName]
+ checkTasks[taskName] = """
+ $taskName {
+ doLast {
+ def t = $taskName
+ while (!(t instanceof PlatformJavaCompile)) {
+ t = t.taskDependencies.getDependencies(t)[0]
+ }
+ assert t.classpath.files == [file("\${buildDir}/jars/$target/second.jar")] as Set
+ }
+ }
+"""
+ } else {
+ taskNames << taskName
+ }
+ }
+
+ if (checkTasks.keySet() != selected.keySet()) {
+ throw new IllegalArgumentException("The following tasks are declared in the datatable 'selected' column but not found in the generated tasks: ${selected.keySet() - checkTasks.keySet()}. Possible solutions = $taskNames")
+ }
+
+ def tasksBlock = checkTasks ? """
+ tasks {
+ ${checkTasks.values().join('\n')}
+ }
+""" : ''
+ tasksBlock
+ }
+
+ protected static void addCustomLibraryType(File buildFile) {
+ buildFile << '''import org.gradle.jvm.internal.DefaultJarBinarySpec
+import org.gradle.jvm.toolchain.JavaToolChainRegistry
+import org.gradle.platform.base.internal.DefaultPlatformRequirement
+import org.gradle.platform.base.internal.PlatformResolvers
+
+trait JavaVersionsAware {
+ List<Integer> javaVersions = []
+
+ void javaVersions(int ... platforms) { javaVersions.addAll(platforms) }
+}
+
+trait FlavorAware {
+ List<String> flavors = []
+
+ void flavors(String... fvs) { flavors.addAll(fvs) }
+}
+
+trait BuildTypeAware {
+ List<BuildType> buildTypes = []
+
+ void buildTypes(String... bts) { buildTypes.addAll(bts.collect { new DefaultBuildType(name: it) }) }
+}
+
+// define the 3 types of libraries used in the tests: flavor only, build type only, and both (all of them include Java version)
+trait FlavorOnlyLibrary implements LibrarySpec, JavaVersionsAware, FlavorAware {}
+
+trait BuildTypeOnlyLibrary implements LibrarySpec, JavaVersionsAware, BuildTypeAware {}
+
+trait FlavorAndBuildTypeAwareLibrary implements LibrarySpec, JavaVersionsAware, FlavorAware, BuildTypeAware {}
+
+interface BuildType extends Named {}
+
+class DefaultBuildType implements BuildType {
+ String name
+}
+
+trait FlavorJarBinarySpec implements JarBinarySpec {
+ String flavor
+
+ @Variant
+ String getFlavor() { flavor }
+}
+
+trait BuildTypeJarBinarySpec implements JarBinarySpec {
+ BuildType buildType
+
+ @Variant
+ BuildType getBuildType() { buildType }
+}
+
+trait FlavorAndBuildTypeJarBinarySpec implements FlavorJarBinarySpec, BuildTypeJarBinarySpec {}
+
+// define the 3 concrete binary types used in tests (flavor, build type and both)
+class FlavorBinary extends DefaultJarBinarySpec implements FlavorJarBinarySpec {
+ // workaround for Groovy bug
+ JvmBinaryTasks getTasks() { super.tasks }
+}
+
+class BuildTypeBinary extends DefaultJarBinarySpec implements BuildTypeJarBinarySpec {
+ // workaround for Groovy bug
+ JvmBinaryTasks getTasks() { super.tasks }
+}
+
+class FlavorAndBuildTypeBinary extends DefaultJarBinarySpec implements FlavorAndBuildTypeJarBinarySpec {
+ // workaround for Groovy bug
+ JvmBinaryTasks getTasks() { super.tasks }
+}
+
+// define the 3 concrete library types
+class DefaultFlavorOnlyLibrary extends BaseComponentSpec implements FlavorOnlyLibrary {}
+
+class DefaultBuildTypeOnlyLibrary extends BaseComponentSpec implements BuildTypeOnlyLibrary {}
+
+class DefaultFlavorAndBuildTypeAwareLibrary extends BaseComponentSpec implements FlavorAndBuildTypeAwareLibrary {}
+
+class ComponentTypeRules extends RuleSource {
+
+ @ComponentType
+ void registerFlavorAndBuildTypeComponent(ComponentTypeBuilder<FlavorAndBuildTypeAwareLibrary> builder) {
+ builder.defaultImplementation(DefaultFlavorAndBuildTypeAwareLibrary)
+ }
+
+ @ComponentType
+ void registerFlavorOnlyComponent(ComponentTypeBuilder<FlavorOnlyLibrary> builder) {
+ builder.defaultImplementation(DefaultFlavorOnlyLibrary)
+ }
+
+ @ComponentType
+ void registerBuildTypeOnlyComponent(ComponentTypeBuilder<BuildTypeOnlyLibrary> builder) {
+ builder.defaultImplementation(DefaultBuildTypeOnlyLibrary)
+ }
+
+ @BinaryType
+ void registerFlavorAndBuildTypeJar(BinaryTypeBuilder<FlavorAndBuildTypeJarBinarySpec> builder) {
+ builder.defaultImplementation(FlavorAndBuildTypeBinary)
+ }
+
+ @BinaryType
+ void registerFlavorOnlyJar(BinaryTypeBuilder<FlavorJarBinarySpec> builder) {
+ builder.defaultImplementation(FlavorBinary)
+ }
+
+ @BinaryType
+ void registerBuildTypeOnlyJar(BinaryTypeBuilder<BuildTypeJarBinarySpec> builder) {
+ builder.defaultImplementation(BuildTypeBinary)
+ }
+
+ @ComponentBinaries
+ void createFlavorAndBuildTypeBinaries(ModelMap<FlavorAndBuildTypeJarBinarySpec> binaries,
+ FlavorAndBuildTypeAwareLibrary library,
+ PlatformResolvers platforms,
+ @Path("buildDir") File buildDir,
+ JavaToolChainRegistry toolChains) {
+
+ def javaVersions = library.javaVersions ?: [JavaVersion.current().majorVersion]
+ def flavors = library.flavors ?: ['default']
+ def buildTypes = library.buildTypes ?: [new DefaultBuildType(name: 'default')]
+ javaVersions.each { version ->
+ flavors.each { flavor ->
+ buildTypes.each { buildType ->
+ def platform = platforms.resolve(JavaPlatform, DefaultPlatformRequirement.create("java${version}"))
+ def toolChain = toolChains.getForPlatform(platform)
+ def baseName = "${library.name}${flavor.capitalize()}${buildType.name.capitalize()}"
+ String binaryName = "$baseName${javaVersions.size() > 1 ? version : ''}Jar"
+ binaries.create(binaryName) { jar ->
+ jar.toolChain = toolChain
+ jar.targetPlatform = platform
+ if (library.flavors) {
+ jar.flavor = flavor
+ }
+ if (library.buildTypes) {
+ jar.buildType = buildType
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @ComponentBinaries
+ void createFlavorOnlyBinaries(ModelMap<FlavorJarBinarySpec> binaries,
+ FlavorOnlyLibrary library,
+ PlatformResolvers platforms,
+ @Path("buildDir") File buildDir,
+ JavaToolChainRegistry toolChains) {
+
+ def javaVersions = library.javaVersions ?: [JavaVersion.current().majorVersion]
+ def flavors = library.flavors ?: ['default']
+ javaVersions.each { version ->
+ flavors.each { flavor ->
+ def platform = platforms.resolve(JavaPlatform, DefaultPlatformRequirement.create("java${version}"))
+ def toolChain = toolChains.getForPlatform(platform)
+ def baseName = "${library.name}${flavor.capitalize()}"
+ String binaryName = "$baseName${javaVersions.size() > 1 ? version : ''}Jar"
+ binaries.create(binaryName) { jar ->
+ jar.toolChain = toolChain
+ jar.targetPlatform = platform
+ if (library.flavors) {
+ jar.flavor = flavor
+ }
+ }
+ }
+ }
+ }
+
+ @ComponentBinaries
+ void createBuildTypeOnlyBinaries(ModelMap<BuildTypeJarBinarySpec> binaries,
+ BuildTypeOnlyLibrary library,
+ PlatformResolvers platforms,
+ @Path("buildDir") File buildDir,
+ JavaToolChainRegistry toolChains) {
+
+ def javaVersions = library.javaVersions ?: [JavaVersion.current().majorVersion]
+ def buildTypes = library.buildTypes ?: [ new DefaultBuildType(name:'default')]
+ javaVersions.each { version ->
+ buildTypes.each { buildType ->
+ def platform = platforms.resolve(JavaPlatform, DefaultPlatformRequirement.create("java${version}"))
+ def toolChain = toolChains.getForPlatform(platform)
+ def baseName = "${library.name}${buildType.name.capitalize()}"
+ String binaryName = "$baseName${javaVersions.size() > 1 ? version : ''}Jar"
+ binaries.create(binaryName) { jar ->
+ jar.toolChain = toolChain
+ jar.targetPlatform = platform
+ if (library.buildTypes) {
+ jar.buildType = buildType
+ }
+ }
+ }
+ }
+ }
+
+}
+
+apply type: ComponentTypeRules
+ '''
+ }
+
+ protected static void applyJavaPlugin(File buildFile) {
+ buildFile << '''
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+'''
+ }
+
+ protected void checkResolution(Map<String, String> errors, Set<String> consumedErrors, String taskName) {
+ if (errors[taskName]) {
+ consumedErrors << taskName
+ fails taskName
+ failure.assertHasDescription("Could not resolve all dependencies for 'Jar '$taskName'' source set 'Java source 'first:java''")
+ errors[taskName].each { err ->
+ failure.assertThatCause(containsText(err))
+ }
+ } else {
+ succeeds taskName
+ }
+ }
+
+ protected static void forEachJavaBinary(List<Integer> platforms, Closure calledWithTaskName) {
+ if (platforms.size() == 1) {
+ calledWithTaskName 'firstJar'
+ } else {
+ platforms.each { platform ->
+ calledWithTaskName "java${platform}FirstJar"
+ }
+ }
+ }
+
+ protected static void forEachFlavorAndBuildTypeBinary(List<String> buildTypesToTest, List<String> flavorsToTest, List<Integer> jdksToTest, Closure calledWithTaskName) {
+ buildTypesToTest.each { buildType ->
+ flavorsToTest.each { flavor ->
+ jdksToTest.each { jdk ->
+ String javaVersion = jdksToTest.size() > 1 ? "$jdk" : ''
+ calledWithTaskName "first${flavor.capitalize()}${buildType.capitalize()}${javaVersion}Jar"
+ }
+ }
+ }
+ }
+
+ protected static void forEachFlavor(List<String> flavorsToTest, List<Integer> jdksToTest, Closure calledWithTaskName) {
+ flavorsToTest.each { flavor ->
+ jdksToTest.each { jdk ->
+ String javaVersion = jdksToTest.size() > 1 ? "$jdk" : ''
+ calledWithTaskName "first${flavor.capitalize()}${javaVersion}Jar"
+ }
+ }
+ }
+
+ protected static String generateCheckDependenciesDSLBlockForCustomComponent(Map<String, String> selected, List<String> buildTypesToTest, List<String> flavorsToTest, List<Integer> jdksToTest) {
+ generateCheckDependenciesDSLBlock(selected, this.&forEachFlavorAndBuildTypeBinary.curry(buildTypesToTest, flavorsToTest, jdksToTest))
+ }
+
+ protected static String generateCheckDependenciesDSLBlockForJavaLibrary(Map<String, String> selected, List<Integer> jdksToTest) {
+ generateCheckDependenciesDSLBlock(selected, this.&forEachJavaBinary.curry(jdksToTest))
+ }
+
+ protected static String generateCheckDependenciesDSLBlockForFlavorLibrary(Map<String, String> selected, List<String> flavors, List<Integer> jdksToTest) {
+ generateCheckDependenciesDSLBlock(selected, this.&forEachFlavor.curry(flavors, jdksToTest))
+ }
+
+
+}
diff --git a/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/SelectiveCompiler.java b/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/SelectiveCompiler.java
index dc83ac1..e25286f 100644
--- a/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/SelectiveCompiler.java
+++ b/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/SelectiveCompiler.java
@@ -59,7 +59,7 @@ class SelectiveCompiler implements org.gradle.language.base.internal.compile.Com
incrementalCompilationInitilizer.initializeCompilation(spec, recompilationSpec.getClassNames());
if (spec.getSource().isEmpty()) {
- LOG.lifecycle("None of the classes needs to compiled! Analysis took {}. ", clock.getTime());
+ LOG.lifecycle("None of the classes needs to be compiled! Analysis took {}. ", clock.getTime());
return new RecompilationNotNecessary();
}
diff --git a/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/CompileOptions.java b/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/CompileOptions.java
index 6e5a01b..fae6121 100644
--- a/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/CompileOptions.java
+++ b/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/CompileOptions.java
@@ -258,8 +258,7 @@ public class CompileOptions extends AbstractOptions {
}
/**
- * Returns the bootstrap classpath to be used for the compiler process.
- * Only takes effect if {@code fork} is {@code true}. Defaults to {@code null}.
+ * Returns the bootstrap classpath to be used for the compiler process. Defaults to {@code null}.
*/
@Input
@Optional
@@ -268,16 +267,14 @@ public class CompileOptions extends AbstractOptions {
}
/**
- * Sets the bootstrap classpath to be used for the compiler process.
- * Only takes effect if {@code fork} is {@code true}. Defaults to {@code null}.
+ * Sets the bootstrap classpath to be used for the compiler process. Defaults to {@code null}.
*/
public void setBootClasspath(String bootClasspath) {
this.bootClasspath = bootClasspath;
}
/**
- * Returns the extension dirs to be used for the compiler process.
- * Only takes effect if {@code fork} is {@code true}. Defaults to {@code null}.
+ * Returns the extension dirs to be used for the compiler process. Defaults to {@code null}.
*/
@Input
@Optional
@@ -286,8 +283,7 @@ public class CompileOptions extends AbstractOptions {
}
/**
- * Sets the extension dirs to be used for the compiler process.
- * Only takes effect if {@code fork} is {@code true}. Defaults to {@code null}.
+ * Sets the extension dirs to be used for the compiler process. Defaults to {@code null}.
*/
public void setExtensionDirs(String extensionDirs) {
this.extensionDirs = extensionDirs;
diff --git a/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/JavaCompile.java b/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/JavaCompile.java
index e9b1a58..90dcaee 100644
--- a/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/JavaCompile.java
+++ b/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/JavaCompile.java
@@ -18,7 +18,6 @@ package org.gradle.api.tasks.compile;
import org.gradle.api.AntBuilder;
import org.gradle.api.Incubating;
-import org.gradle.api.JavaVersion;
import org.gradle.api.internal.changedetection.changes.IncrementalTaskInputsInternal;
import org.gradle.api.internal.file.FileOperations;
import org.gradle.api.internal.tasks.compile.CleaningJavaCompiler;
@@ -36,11 +35,12 @@ import org.gradle.api.tasks.*;
import org.gradle.api.tasks.incremental.IncrementalTaskInputs;
import org.gradle.cache.CacheRepository;
import org.gradle.internal.Factory;
+import org.gradle.jvm.internal.toolchain.JavaToolChainInternal;
import org.gradle.jvm.platform.JavaPlatform;
import org.gradle.jvm.platform.internal.DefaultJavaPlatform;
+import org.gradle.jvm.toolchain.JavaToolChain;
import org.gradle.language.base.internal.compile.Compiler;
import org.gradle.language.base.internal.compile.CompilerUtil;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import org.gradle.util.SingleMessageLogger;
import javax.inject.Inject;
@@ -66,22 +66,24 @@ public class JavaCompile extends AbstractCompile {
private final CompileOptions compileOptions = new CompileOptions();
/**
- * Returns the tool resolver that will be used to find the tool to compile the Java source.
+ * Returns the tool chain that will be used to compile the Java source.
*
- * @return The tool resolver.
+ * @return The tool chain.
*/
@Incubating @Inject
- public ToolResolver getToolResolver() {
+ public JavaToolChain getToolChain() {
+ // Implementation is generated
throw new UnsupportedOperationException();
}
/**
- * Sets the tool resolver that should be used to find the tool to compile the Java source.
+ * Sets the tool chain that should be used to compile the Java source.
*
- * @param toolResolver The tool resolver.
+ * @param toolChain The tool chain.
*/
@Incubating
- public void setToolResolver(ToolResolver toolResolver) {
+ public void setToolChain(JavaToolChain toolChain) {
+ // Implementation is generated
throw new UnsupportedOperationException();
}
@@ -143,14 +145,12 @@ public class JavaCompile extends AbstractCompile {
}
private CleaningJavaCompiler createCompiler(JavaCompileSpec spec) {
- // TODO:DAZ Supply the target platform to the task, using the compatibility flags as overrides
- // Or maybe split the legacy compile task from the new one
- Compiler<JavaCompileSpec> javaCompiler = CompilerUtil.castCompiler(getToolResolver().resolveCompiler(spec.getClass(), getPlatform()).get());
+ Compiler<JavaCompileSpec> javaCompiler = CompilerUtil.castCompiler(((JavaToolChainInternal) getToolChain()).select(getPlatform()).newCompiler(spec.getClass()));
return new CleaningJavaCompiler(javaCompiler, getAntBuilderFactory(), getOutputs());
}
protected JavaPlatform getPlatform() {
- return new DefaultJavaPlatform(JavaVersion.current());
+ return DefaultJavaPlatform.current();
}
private void performCompilation(JavaCompileSpec spec, Compiler<JavaCompileSpec> compiler) {
diff --git a/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/package-info.java b/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/package-info.java
deleted file mode 100644
index 8152d0c..0000000
--- a/subprojects/language-java/src/main/java/org/gradle/api/tasks/compile/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * The compile tasks and options for Java.
- */
-package org.gradle.api.tasks.compile;
\ No newline at end of file
diff --git a/subprojects/language-java/src/main/java/org/gradle/api/tasks/javadoc/Javadoc.java b/subprojects/language-java/src/main/java/org/gradle/api/tasks/javadoc/Javadoc.java
index 31189a0..b2b8273 100644
--- a/subprojects/language-java/src/main/java/org/gradle/api/tasks/javadoc/Javadoc.java
+++ b/subprojects/language-java/src/main/java/org/gradle/api/tasks/javadoc/Javadoc.java
@@ -18,16 +18,16 @@ package org.gradle.api.tasks.javadoc;
import groovy.lang.Closure;
import org.gradle.api.Incubating;
-import org.gradle.api.JavaVersion;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.*;
import org.gradle.api.tasks.javadoc.internal.JavadocSpec;
import org.gradle.external.javadoc.MinimalJavadocOptions;
import org.gradle.external.javadoc.StandardJavadocDocletOptions;
+import org.gradle.jvm.internal.toolchain.JavaToolChainInternal;
+import org.gradle.jvm.platform.JavaPlatform;
import org.gradle.jvm.platform.internal.DefaultJavaPlatform;
+import org.gradle.jvm.toolchain.JavaToolChain;
import org.gradle.language.base.internal.compile.Compiler;
-import org.gradle.platform.base.Platform;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import org.gradle.util.GUtil;
import javax.inject.Inject;
@@ -139,30 +139,30 @@ public class Javadoc extends SourceTask {
spec.setWorkingDir(getProject().getProjectDir());
spec.setOptionsFile(getOptionsFile());
- Compiler<JavadocSpec> generator = getToolResolver().resolveCompiler(JavadocSpec.class, getPlatform()).get();
+ Compiler<JavadocSpec> generator = ((JavaToolChainInternal) getToolChain()).select(getPlatform()).newCompiler(JavadocSpec.class);
generator.execute(spec);
}
/**
- * <p>Returns the the tool resolver which will be used to find the tool to generate the documention.</p>
- *
- * @return the tool resolver
+ * Returns the tool chain that will be used to generate the Javadoc.
*/
@Incubating @Inject
- public ToolResolver getToolResolver() {
+ public JavaToolChain getToolChain() {
+ // Implementation is generated
throw new UnsupportedOperationException();
}
/**
- * Sets the tool resolver which will be used to find the tool to generate the Javadoc.
+ * Sets the tool chain to use to generate the Javadoc.
*/
@Incubating
- public void setToolResolver(ToolResolver toolResolver) {
+ public void setToolChain(JavaToolChain toolChain) {
+ // Implementation is generated
throw new UnsupportedOperationException();
}
- private Platform getPlatform() {
- return new DefaultJavaPlatform(JavaVersion.current());
+ private JavaPlatform getPlatform() {
+ return DefaultJavaPlatform.current();
}
/**
diff --git a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaLanguageSourceSet.java b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaLanguageSourceSet.java
index cc94b69..32dd976 100644
--- a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaLanguageSourceSet.java
+++ b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaLanguageSourceSet.java
@@ -25,7 +25,7 @@ import org.gradle.platform.base.DependencySpecContainer;
import org.gradle.platform.base.internal.DefaultDependencySpecContainer;
public class DefaultJavaLanguageSourceSet extends BaseLanguageSourceSet implements JavaSourceSet, DependentSourceSetInternal {
- private final Classpath compileClasspath = new EmptyClasspath();
+ private final Classpath emptyClasspath = new EmptyClasspath();
private final DefaultDependencySpecContainer dependencies = new DefaultDependencySpecContainer();
@Override
@@ -34,7 +34,7 @@ public class DefaultJavaLanguageSourceSet extends BaseLanguageSourceSet implemen
}
public Classpath getCompileClasspath() {
- return compileClasspath;
+ return emptyClasspath;
}
@Override
diff --git a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaLocalComponentFactory.java b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaLocalComponentFactory.java
deleted file mode 100644
index 93f451a..0000000
--- a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaLocalComponentFactory.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.language.java.internal;
-
-import org.apache.ivy.core.module.descriptor.ExcludeRule;
-import org.gradle.api.Project;
-import org.gradle.api.artifacts.ModuleVersionIdentifier;
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.ComponentSelector;
-import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier;
-import org.gradle.api.internal.artifacts.DefaultModuleVersionSelector;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
-import org.gradle.internal.component.local.model.*;
-import org.gradle.internal.component.model.IvyArtifactName;
-import org.gradle.internal.component.model.LocalComponentDependencyMetaData;
-import org.gradle.platform.base.DependencySpec;
-import org.gradle.platform.base.DependencySpecContainer;
-
-import java.util.Collections;
-
-public class DefaultJavaLocalComponentFactory implements LocalComponentFactory {
-
- private static final ExcludeRule[] EXCLUDE_RULES = new ExcludeRule[0];
-
- @Override
- public boolean canConvert(Object source) {
- return source instanceof DefaultJavaSourceSetResolveContext;
- }
-
- @Override
- public LocalComponentMetaData convert(Object source) {
- DefaultJavaSourceSetResolveContext context = (DefaultJavaSourceSetResolveContext) source;
- String projectPath = context.getProject().getPath();
- String libraryName = context.getSourceSet().getParentName();
- String version = context.getProject().getVersion().toString();
- ModuleVersionIdentifier id = new DefaultModuleVersionIdentifier(
- projectPath, libraryName, version
- );
- ComponentIdentifier component = new DefaultLibraryComponentIdentifier(projectPath, libraryName);
- DefaultLocalComponentMetaData metaData = new DefaultLocalComponentMetaData(id, component, Project.DEFAULT_STATUS);
- metaData.addConfiguration(context.getName(), "Configuration for "+libraryName, Collections.<String>emptySet(), Collections.singleton(context.getName()), true, true);
- addDependencies(projectPath, id, metaData, context.getSourceSet().getDependencies());
- return metaData;
- }
-
- private void addDependencies(String defaultProject, ModuleVersionIdentifier mvi, DefaultLocalComponentMetaData metaData, DependencySpecContainer allDependencies) {
- for (DependencySpec dependency : allDependencies) {
- ComponentSelector selector;
- String projectPath = dependency.getProjectPath();
- if (projectPath==null) {
- projectPath = defaultProject;
- }
- if (dependency.getLibraryName()==null) {
- selector = new DefaultProjectComponentSelector(dependency.getProjectPath());
- } else {
- selector = new DefaultLibraryComponentSelector(projectPath, dependency.getLibraryName());
- }
- DefaultModuleVersionSelector requested = new DefaultModuleVersionSelector(projectPath, dependency.getLibraryName(), mvi.getVersion());
- LocalComponentDependencyMetaData localComponentDependencyMetaData = new LocalComponentDependencyMetaData(
- selector,
- requested,
- //"*", "*",
- DefaultLibraryComponentIdentifier.libraryToConfigurationName(mvi.getGroup(), mvi.getName()),
- DefaultLibraryComponentIdentifier.libraryToConfigurationName(projectPath, dependency.getLibraryName()),
- Collections.<IvyArtifactName>emptySet(),
- EXCLUDE_RULES,
- false,
- false,
- true);
- metaData.addDependency(localComponentDependencyMetaData);
- }
- }
-
-}
diff --git a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaSourceSetResolveContext.java b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaSourceSetResolveContext.java
deleted file mode 100644
index 3e7e3f1..0000000
--- a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/DefaultJavaSourceSetResolveContext.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.language.java.internal;
-
-import org.gradle.api.Project;
-import org.gradle.api.artifacts.Dependency;
-import org.gradle.api.artifacts.DependencySet;
-import org.gradle.api.internal.DefaultDomainObjectSet;
-import org.gradle.api.internal.artifacts.DefaultDependencySet;
-import org.gradle.api.internal.artifacts.ResolveContextInternal;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectComponentRegistry;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectDependencyResolver;
-import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.internal.component.local.model.DefaultLibraryComponentIdentifier;
-import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
-import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
-
-public class DefaultJavaSourceSetResolveContext implements ResolveContextInternal {
- private final Project project;
- private final DefaultJavaLanguageSourceSet sourceSet;
-
- public DefaultJavaSourceSetResolveContext(Project project, DefaultJavaLanguageSourceSet sourceSet) {
- this.project = project;
- this.sourceSet = sourceSet;
- }
-
- @Override
- public String getName() {
- return DefaultLibraryComponentIdentifier.libraryToConfigurationName(project.getPath(), getLibraryName());
- }
-
- private String getLibraryName() {
- return sourceSet.getParentName();
- }
-
- @Override
- public DependencySet getDependencies() {
- DefaultDomainObjectSet<Dependency> backingSet = new DefaultDomainObjectSet<Dependency>(Dependency.class);
- return new DefaultDependencySet(getLibraryName(), backingSet);
- }
-
-
- @Override
- public DependencySet getAllDependencies() {
- return new DefaultDependencySet(getLibraryName(), new DefaultDomainObjectSet<Dependency>(Dependency.class));
- }
-
- public DefaultJavaLanguageSourceSet getSourceSet() {
- return sourceSet;
- }
-
- public Project getProject() {
- return project;
- }
-
- @Override
- public ProjectDependencyResolver newProjectDependencyResolver(final ProjectComponentRegistry projectComponentRegistry, final LocalComponentFactory localComponentFactory, DependencyToComponentIdResolver delegateIdResolver, ComponentMetaDataResolver delegateComponentResolver) {
- return new ProjectLibraryDependencyResolver((ProjectInternal) getProject(), projectComponentRegistry, localComponentFactory, delegateIdResolver, delegateComponentResolver);
- }
-
-}
diff --git a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaLanguagePluginServiceRegistry.java b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaLanguagePluginServiceRegistry.java
index 810c51a..ca7b48a 100644
--- a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaLanguagePluginServiceRegistry.java
+++ b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaLanguagePluginServiceRegistry.java
@@ -27,6 +27,9 @@ public class JavaLanguagePluginServiceRegistry implements PluginServiceRegistry
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new ComponentRegistrationAction());
}
@@ -39,8 +42,6 @@ public class JavaLanguagePluginServiceRegistry implements PluginServiceRegistry
private static class ComponentRegistrationAction {
public void configure(ServiceRegistration registration, ComponentTypeRegistry componentTypeRegistry) {
- // TODO There should be a more explicit way to execute an action against existing services
- // TODO:DAZ Dependency Management should be able to extract this from the plugin, without explicit registration
componentTypeRegistry.maybeRegisterComponentType(JvmLibrary.class)
.registerArtifactType(JavadocArtifact.class, ArtifactType.JAVADOC);
}
diff --git a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaToolChainServiceRegistry.java b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaToolChainServiceRegistry.java
index be974d5..7a5238a 100644
--- a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaToolChainServiceRegistry.java
+++ b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/JavaToolChainServiceRegistry.java
@@ -38,6 +38,9 @@ public class JavaToolChainServiceRegistry implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new BuildScopeCompileServices());
}
diff --git a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/ProjectLibraryDependencyResolver.java b/subprojects/language-java/src/main/java/org/gradle/language/java/internal/ProjectLibraryDependencyResolver.java
deleted file mode 100644
index 266a98c..0000000
--- a/subprojects/language-java/src/main/java/org/gradle/language/java/internal/ProjectLibraryDependencyResolver.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.language.java.internal;
-
-import org.gradle.api.Project;
-import org.gradle.api.artifacts.ModuleVersionIdentifier;
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.component.LibraryComponentSelector;
-import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier;
-import org.gradle.api.internal.artifacts.ivyservice.LocalComponentFactory;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectComponentRegistry;
-import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectDependencyResolver;
-import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.internal.component.local.model.DefaultLibraryComponentIdentifier;
-import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData;
-import org.gradle.internal.component.model.DependencyMetaData;
-import org.gradle.internal.resolve.ModuleVersionResolveException;
-import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
-import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
-import org.gradle.internal.resolve.result.BuildableComponentIdResolveResult;
-import org.gradle.model.ModelMap;
-import org.gradle.model.internal.core.ModelPath;
-import org.gradle.model.internal.type.ModelType;
-import org.gradle.platform.base.ComponentSpecContainer;
-import org.gradle.platform.base.LibrarySpec;
-
-import java.util.Collections;
-
-// TODO: this should probably be in the platform-base module somehow, but it doesn't depend on dependency-resolution
-// module so it's not possible yet
-public class ProjectLibraryDependencyResolver extends ProjectDependencyResolver {
- private final ProjectInternal defaultProject;
-
- public ProjectLibraryDependencyResolver(ProjectInternal project, ProjectComponentRegistry projectComponentRegistry, LocalComponentFactory localComponentFactory, DependencyToComponentIdResolver delegateIdResolver, ComponentMetaDataResolver delegateComponentResolver) {
- super(projectComponentRegistry, localComponentFactory, delegateIdResolver, delegateComponentResolver);
- defaultProject = project;
- }
-
- @Override
- public void resolve(DependencyMetaData dependency, BuildableComponentIdResolveResult result) {
- if (dependency.getSelector() instanceof LibraryComponentSelector) {
- DefaultLocalComponentMetaData metaData = null;
- LibraryComponentSelector selector = (LibraryComponentSelector) dependency.getSelector();
- ProjectInternal project = defaultProject;
- if (selector.getProjectPath()!=null) {
- project = project.getRootProject().findProject(selector.getProjectPath());
- }
- if (project!=null) {
- ComponentSpecContainer components = project.getModelRegistry().realize(
- ModelPath.path("components"),
- ModelType.of(ComponentSpecContainer.class));
- ModelMap<? extends LibrarySpec> libraries = components.withType(LibrarySpec.class);
- String libraryName = selector.getLibraryName();
- if (libraryName==null && libraries.size()==1) {
- libraryName = libraries.values().iterator().next().getName();
- }
- if (libraryName!=null) {
- String version = project.getVersion().toString();
- String projectPath = project.getPath();
- LibrarySpec library = libraries.get(libraryName);
- if (library != null) {
- ModuleVersionIdentifier id = new DefaultModuleVersionIdentifier(
- projectPath, libraryName, version
- );
- ComponentIdentifier component = new DefaultLibraryComponentIdentifier(projectPath, library.getName());
- metaData = new DefaultLocalComponentMetaData(id, component, Project.DEFAULT_STATUS);
- metaData.addConfiguration(DefaultLibraryComponentIdentifier.libraryToConfigurationName(projectPath, libraryName), "Configuration for "+libraryName, Collections.<String>emptySet(), Collections.singleton(DefaultLibraryComponentIdentifier.libraryToConfigurationName(projectPath, libraryName)), true, true);
- }
- }
- }
- if (metaData!=null) {
- result.resolved(metaData.toResolveMetaData());
- } else {
- result.failed(new ModuleVersionResolveException(selector, String.format("Cannot resolve dependency %s", selector)));
- }
- } else {
- super.resolve(dependency, result);
- }
- }
-
-}
diff --git a/subprojects/language-java/src/main/java/org/gradle/language/java/plugins/JavaLanguagePlugin.java b/subprojects/language-java/src/main/java/org/gradle/language/java/plugins/JavaLanguagePlugin.java
index 60bb233..7f36308 100644
--- a/subprojects/language-java/src/main/java/org/gradle/language/java/plugins/JavaLanguagePlugin.java
+++ b/subprojects/language-java/src/main/java/org/gradle/language/java/plugins/JavaLanguagePlugin.java
@@ -16,45 +16,36 @@
package org.gradle.language.java.plugins;
-import com.google.common.collect.ImmutableList;
-import org.gradle.api.*;
-import org.gradle.api.artifacts.component.ComponentIdentifier;
-import org.gradle.api.artifacts.dsl.RepositoryHandler;
-import org.gradle.api.artifacts.repositories.ArtifactRepository;
-import org.gradle.api.artifacts.result.DependencyResult;
-import org.gradle.api.artifacts.result.ResolutionResult;
-import org.gradle.api.artifacts.result.ResolvedComponentResult;
-import org.gradle.api.artifacts.result.ResolvedDependencyResult;
-import org.gradle.api.internal.GradleInternal;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
-import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
-import org.gradle.api.internal.artifacts.ResolverResults;
-import org.gradle.api.internal.artifacts.ivyservice.moduleconverter.CompositeResolveLocalComponentFactory;
-import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
-import org.gradle.api.internal.file.AbstractFileCollection;
-import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.internal.service.ServiceRegistry;
+import org.gradle.jvm.JarBinarySpec;
import org.gradle.jvm.JvmBinarySpec;
import org.gradle.jvm.JvmByteCode;
+import org.gradle.jvm.internal.DependencyResolvingClasspath;
import org.gradle.language.base.LanguageSourceSet;
+import org.gradle.language.base.internal.DependentSourceSetInternal;
import org.gradle.language.base.internal.SourceTransformTaskConfig;
import org.gradle.language.base.internal.registry.LanguageTransform;
import org.gradle.language.base.internal.registry.LanguageTransformContainer;
import org.gradle.language.base.plugins.ComponentModelBasePlugin;
import org.gradle.language.java.JavaSourceSet;
import org.gradle.language.java.internal.DefaultJavaLanguageSourceSet;
-import org.gradle.language.java.internal.DefaultJavaLocalComponentFactory;
-import org.gradle.language.java.internal.DefaultJavaSourceSetResolveContext;
import org.gradle.language.java.tasks.PlatformJavaCompile;
import org.gradle.language.jvm.plugins.JvmResourcesPlugin;
import org.gradle.model.Mutate;
import org.gradle.model.RuleSource;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.platform.base.BinarySpec;
import org.gradle.platform.base.LanguageType;
import org.gradle.platform.base.LanguageTypeBuilder;
import java.io.File;
-import java.util.*;
+import java.util.Collections;
+import java.util.Map;
/**
* Plugin for compiling Java code. Applies the {@link org.gradle.language.base.plugins.ComponentModelBasePlugin} and {@link org.gradle.language.jvm.plugins.JvmResourcesPlugin}. Registers "java"
@@ -65,14 +56,6 @@ public class JavaLanguagePlugin implements Plugin<Project> {
public void apply(Project project) {
project.getPluginManager().apply(ComponentModelBasePlugin.class);
project.getPluginManager().apply(JvmResourcesPlugin.class);
- GradleInternal gradle = (GradleInternal) project.getGradle();
- registerLocalComponentFactory(gradle);
- }
-
- private void registerLocalComponentFactory(GradleInternal gradle) {
- ServiceRegistry services = gradle.getServices();
- CompositeResolveLocalComponentFactory componentFactory = services.get(CompositeResolveLocalComponentFactory.class);
- componentFactory.addFactory(new DefaultJavaLocalComponentFactory());
}
@SuppressWarnings("UnusedDeclaration")
@@ -85,11 +68,18 @@ public class JavaLanguagePlugin implements Plugin<Project> {
@Mutate
void registerLanguageTransform(LanguageTransformContainer languages, ServiceRegistry serviceRegistry) {
- languages.add(new Java());
+ ModelSchemaStore schemaStore = serviceRegistry.get(ModelSchemaStore.class);
+ languages.add(new Java(schemaStore));
}
}
private static class Java implements LanguageTransform<JavaSourceSet, JvmByteCode> {
+ private final ModelSchemaStore schemaStore;
+
+ public Java(ModelSchemaStore schemaStore) {
+ this.schemaStore = schemaStore;
+ }
+
public Class<JavaSourceSet> getSourceSetType() {
return JavaSourceSet.class;
}
@@ -112,25 +102,21 @@ public class JavaLanguagePlugin implements Plugin<Project> {
return PlatformJavaCompile.class;
}
- public void configureTask(Task task, BinarySpec binarySpec, LanguageSourceSet sourceSet) {
+ public void configureTask(Task task, BinarySpec binarySpec, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
PlatformJavaCompile compile = (PlatformJavaCompile) task;
JavaSourceSet javaSourceSet = (JavaSourceSet) sourceSet;
- JvmBinarySpec binary = (JvmBinarySpec) binarySpec;
+ JarBinarySpec binary = (JarBinarySpec) binarySpec;
- // TODO: Probably need to extract this in a utility class for language plugins,
- // or a language plugin superclass in order to avoid the use of internal APIs
- GradleInternal gradle = (GradleInternal) task.getProject().getGradle();
- ArtifactDependencyResolver dependencyResolver = gradle.getServices().get(ArtifactDependencyResolver.class);
- ProjectInternal project = (ProjectInternal) task.getProject();
- RepositoryHandler repositories = project.getRepositories();
- GlobalDependencyResolutionRules globalDependencyResolutionRules = project.getServices().get(GlobalDependencyResolutionRules.class);
+ ArtifactDependencyResolver dependencyResolver = serviceRegistry.get(ArtifactDependencyResolver.class);
compile.setDescription(String.format("Compiles %s.", javaSourceSet));
compile.setDestinationDir(binary.getClassesDir());
+ compile.setToolChain(binary.getToolChain());
compile.setPlatform(binary.getTargetPlatform());
compile.setSource(javaSourceSet.getSource());
- compile.setClasspath(new DependencyResolvingClasspath(project, javaSourceSet, dependencyResolver, repositories, globalDependencyResolutionRules));
+ DependencyResolvingClasspath classpath = new DependencyResolvingClasspath(binary, (DependentSourceSetInternal) javaSourceSet, dependencyResolver, schemaStore);
+ compile.setClasspath(classpath);
compile.setTargetCompatibility(binary.getTargetPlatform().getTargetCompatibility().toString());
compile.setSourceCompatibility(binary.getTargetPlatform().getTargetCompatibility().toString());
@@ -146,64 +132,4 @@ public class JavaLanguagePlugin implements Plugin<Project> {
}
}
- private static class DependencyResolvingClasspath extends AbstractFileCollection {
- private final Project project;
- private final JavaSourceSet sourceSet;
- private final ArtifactDependencyResolver dependencyResolver;
- private final GlobalDependencyResolutionRules globalDependencyResolutionRules;
- private final RepositoryHandler repositories;
-
- private DependencyResolvingClasspath(
- Project project,
- JavaSourceSet sourceSet,
- ArtifactDependencyResolver dependencyResolver,
- RepositoryHandler repositories,
- GlobalDependencyResolutionRules globalDependencyResolutionRules) {
- this.project = project;
- this.sourceSet = sourceSet;
- this.dependencyResolver = dependencyResolver;
- this.repositories = repositories;
- this.globalDependencyResolutionRules = globalDependencyResolutionRules;
- }
-
- @Override
- public String getDisplayName() {
- return "Classpath for "+sourceSet.getDisplayName();
- }
-
- @Override
- public Set<File> getFiles() {
- final Set<File> classpath = new LinkedHashSet<File>();
- classpath.addAll(sourceSet.getCompileClasspath().getFiles().getFiles());
- ResolverResults results = new ResolverResults();
- final List<ResolutionAwareRepository> resolutionRepositories = getResolutionAwareRepositories();
- DefaultJavaSourceSetResolveContext resolveContext = new DefaultJavaSourceSetResolveContext(project, (DefaultJavaLanguageSourceSet) sourceSet);
- dependencyResolver.resolve(resolveContext, resolutionRepositories, globalDependencyResolutionRules, results);
- ResolutionResult resolutionResult = results.getResolutionResult();
- resolutionResult.allDependencies(new Action<DependencyResult>() {
- @Override
- public void execute(DependencyResult dependencyResult) {
- if (dependencyResult instanceof ResolvedDependencyResult) {
- ResolvedDependencyResult resolved = (ResolvedDependencyResult) dependencyResult;
- ResolvedComponentResult selected = resolved.getSelected();
- ComponentIdentifier id = selected.getId();
- // TODO: Convert this into actual classpath!
- // System.out.println("selected = " + selected);
- }
- }
- });
- return classpath;
- }
-
- private List<ResolutionAwareRepository> getResolutionAwareRepositories() {
- ImmutableList<ArtifactRepository> artifactRepositories = ImmutableList.copyOf(repositories.iterator());
- List<ResolutionAwareRepository> resolutionRepositories = new LinkedList<ResolutionAwareRepository>();
- for (ArtifactRepository artifactRepository : artifactRepositories) {
- if (artifactRepository instanceof ResolutionAwareRepository) {
- resolutionRepositories.add((ResolutionAwareRepository)artifactRepository);
- }
- }
- return resolutionRepositories;
- }
- }
}
diff --git a/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/compile/JavaCompileTest.groovy b/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/compile/JavaCompileTest.groovy
index 6ce2e0d..d29e7e1 100644
--- a/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/compile/JavaCompileTest.groovy
+++ b/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/compile/JavaCompileTest.groovy
@@ -18,9 +18,10 @@ package org.gradle.api.tasks.compile
import org.gradle.api.internal.TaskExecutionHistory
import org.gradle.api.tasks.WorkResult
+import org.gradle.jvm.platform.JavaPlatform
import org.gradle.language.base.internal.compile.Compiler
-import org.gradle.platform.base.internal.toolchain.ResolvedTool
-import org.gradle.platform.base.internal.toolchain.ToolResolver
+import org.gradle.jvm.internal.toolchain.JavaToolChainInternal
+import org.gradle.platform.base.internal.toolchain.ToolProvider
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.util.TestUtil
import org.junit.Rule
@@ -28,23 +29,24 @@ import spock.lang.Specification
class JavaCompileTest extends Specification {
@Rule TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()
- def toolResolver = Mock(ToolResolver)
- def resolvedTool = Mock(ResolvedTool)
+ def toolChain = Mock(JavaToolChainInternal)
+ def platform = Mock(JavaPlatform)
+ def toolProvider = Mock(ToolProvider)
def compiler = Mock(Compiler)
def task = TestUtil.createTask(JavaCompile)
- def "uses specified ToolResolver to create a Compiler to do the work"() {
+ def "uses specified ToolChain to create a Compiler to do the work"() {
given:
task.outputs.history = Stub(TaskExecutionHistory)
task.destinationDir = tmpDir.file("classes")
- task.toolResolver = toolResolver
+ task.toolChain = toolChain
when:
task.compile()
then:
- 1 * toolResolver.resolveCompiler(_, {!null}) >> resolvedTool
- 1 * resolvedTool.get() >> compiler
+ 1 * toolChain.select(_) >> toolProvider
+ 1 * toolProvider.newCompiler(!null) >> compiler
1 * compiler.execute(!null) >> Stub(WorkResult)
}
}
diff --git a/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/javadoc/JavadocTest.groovy b/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/javadoc/JavadocTest.groovy
index 57361e9..fe0ed5b 100644
--- a/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/javadoc/JavadocTest.groovy
+++ b/subprojects/language-java/src/test/groovy/org/gradle/api/tasks/javadoc/JavadocTest.groovy
@@ -18,9 +18,9 @@ package org.gradle.api.tasks.javadoc
import org.gradle.api.internal.file.collections.SimpleFileCollection
import org.gradle.external.javadoc.StandardJavadocDocletOptions
+import org.gradle.jvm.internal.toolchain.JavaToolChainInternal
import org.gradle.language.base.internal.compile.Compiler
-import org.gradle.platform.base.internal.toolchain.ResolvedTool
-import org.gradle.platform.base.internal.toolchain.ToolResolver
+import org.gradle.platform.base.internal.toolchain.ToolProvider
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.util.GFileUtils
import org.gradle.util.TestUtil
@@ -38,8 +38,8 @@ public class JavadocTest extends Specification {
def destDir = new File(testDir, "dest");
def srcDir = new File(testDir, "srcdir");
def classpath = WrapUtil.toSet(new File("classpath"));
- def toolResolver = Mock(ToolResolver)
- def resolvedTool = Mock(ResolvedTool)
+ def toolChain = Mock(JavaToolChainInternal);
+ def toolProvider = Mock(ToolProvider);
def generator = Mock(Compiler);
def configurationMock = new SimpleFileCollection(classpath);
def executable = "somepath";
@@ -48,7 +48,7 @@ public class JavadocTest extends Specification {
public void setup() {
task.setClasspath(configurationMock);
task.setExecutable(executable);
- task.setToolResolver(toolResolver);
+ task.setToolChain(toolChain);
GFileUtils.touch(new File(srcDir, "file.java"));
}
@@ -61,8 +61,8 @@ public class JavadocTest extends Specification {
task.execute();
then:
- 1 * toolResolver.resolveCompiler(_,_) >> resolvedTool
- 1 * resolvedTool.get() >> generator
+ 1 * toolChain.select(_) >> toolProvider
+ 1 * toolProvider.newCompiler(!null) >> generator
1 * generator.execute(_)
}
@@ -77,8 +77,8 @@ public class JavadocTest extends Specification {
task.execute()
then:
- 1 * toolResolver.resolveCompiler(_,_) >> resolvedTool
- 1 * resolvedTool.get() >> generator
+ 1 * toolChain.select(_) >> toolProvider
+ 1 * toolProvider.newCompiler(!null) >> generator
1 * generator.execute(_)
}
@@ -91,8 +91,8 @@ public class JavadocTest extends Specification {
task.execute();
then:
- 1 * toolResolver.resolveCompiler(_,_) >> resolvedTool
- 1 * resolvedTool.get() >> generator
+ 1 * toolChain.select(_) >> toolProvider
+ 1 * toolProvider.newCompiler(!null) >> generator
1 * generator.execute(_)
and:
diff --git a/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaLanguageSourceSetTest.groovy b/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaLanguageSourceSetTest.groovy
index c3d83f8..e0bd305 100644
--- a/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaLanguageSourceSetTest.groovy
+++ b/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaLanguageSourceSetTest.groovy
@@ -39,8 +39,8 @@ class DefaultJavaLanguageSourceSetTest extends Specification {
sourceSet.dependencies.project ':foo'
then:
- sourceSet.dependencies.size() == 1
- sourceSet.dependencies[0].projectPath == ':foo'
+ sourceSet.dependencies.dependencies.size() == 1
+ sourceSet.dependencies.dependencies[0].projectPath == ':foo'
}
def "can add a project dependency"() {
@@ -52,8 +52,8 @@ class DefaultJavaLanguageSourceSetTest extends Specification {
}
then:
- sourceSet.dependencies.size() == 1
- sourceSet.dependencies[0].projectPath == ':foo'
+ sourceSet.dependencies.dependencies.size() == 1
+ sourceSet.dependencies.dependencies[0].projectPath == ':foo'
}
def "can add a library dependency"() {
@@ -65,8 +65,8 @@ class DefaultJavaLanguageSourceSetTest extends Specification {
}
then:
- sourceSet.dependencies.size() == 1
- sourceSet.dependencies[0].libraryName == 'fooLib'
+ sourceSet.dependencies.dependencies.size() == 1
+ sourceSet.dependencies.dependencies[0].libraryName == 'fooLib'
}
def "can add a project library dependency"() {
@@ -78,9 +78,9 @@ class DefaultJavaLanguageSourceSetTest extends Specification {
}
then:
- sourceSet.dependencies.size() == 1
- sourceSet.dependencies[0].projectPath == ':foo'
- sourceSet.dependencies[0].libraryName == 'fooLib'
+ sourceSet.dependencies.dependencies.size() == 1
+ sourceSet.dependencies.dependencies[0].projectPath == ':foo'
+ sourceSet.dependencies.dependencies[0].libraryName == 'fooLib'
}
def "can add a multiple dependencies"() {
@@ -94,11 +94,11 @@ class DefaultJavaLanguageSourceSetTest extends Specification {
}
then:
- sourceSet.dependencies.size() == 3
- sourceSet.dependencies[0].projectPath == ':foo'
- sourceSet.dependencies[1].libraryName == 'fooLib'
- sourceSet.dependencies[2].projectPath == ':bar'
- sourceSet.dependencies[2].libraryName == 'barLib'
+ sourceSet.dependencies.dependencies.size() == 3
+ sourceSet.dependencies.dependencies[0].projectPath == ':foo'
+ sourceSet.dependencies.dependencies[1].libraryName == 'fooLib'
+ sourceSet.dependencies.dependencies[2].projectPath == ':bar'
+ sourceSet.dependencies.dependencies[2].libraryName == 'barLib'
}
private DefaultJavaLanguageSourceSet newJavaSourceSet() {
diff --git a/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaLocalComponentFactoryTest.groovy b/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaLocalComponentFactoryTest.groovy
deleted file mode 100644
index 7bcd15b..0000000
--- a/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaLocalComponentFactoryTest.groovy
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.language.java.internal
-
-import org.gradle.api.Project
-import org.gradle.api.artifacts.ModuleVersionIdentifier
-import org.gradle.api.artifacts.component.LibraryComponentIdentifier
-import org.gradle.internal.component.model.ComponentResolveMetaData
-import org.gradle.platform.base.DependencySpecContainer
-import org.gradle.platform.base.internal.DefaultDependencySpec
-import spock.lang.Specification
-import spock.lang.Unroll
-
-class DefaultJavaLocalComponentFactoryTest extends Specification {
- def "can convert java source set resolve context"() {
- given:
- def context = new DefaultJavaSourceSetResolveContext(Mock(Project), Mock(DefaultJavaLanguageSourceSet))
-
- when:
- def factory = new DefaultJavaLocalComponentFactory()
-
- then:
- factory.canConvert(context)
- }
-
- def "can convert a simple java component"() {
- given: "a java sourceset that doesn't define any dependency"
- def sourceSet = Mock(DefaultJavaLanguageSourceSet)
- def dependencySpecs = Mock(DependencySpecContainer)
- def project = Mock(Project)
-
- dependencySpecs.iterator() >> { [].iterator() }
- sourceSet.parentName >> 'myLib'
- sourceSet.dependencies >> dependencySpecs
- project.path >> ':myPath'
- project.version >> '1.0'
-
- def context = new DefaultJavaSourceSetResolveContext(project, sourceSet)
-
- when: "we create a local component factory"
- def factory = new DefaultJavaLocalComponentFactory()
-
- then: "the factory can convert the resolve context"
- factory.canConvert(context)
-
- when: "we convert the context to a local component"
- def component = factory.convert(context)
-
- then: "component metadata reflects the library configuration"
- component.id instanceof ModuleVersionIdentifier
- component.id.group == ':myPath'
- component.id.name == 'myLib'
- component.id.version == '1.0'
- component.id.toString() == ':myPath:myLib:1.0'
-
- when: "we create resolution metadata"
- def metadata = component.toResolveMetaData()
-
- then: "metadata reflects the appropriate library information"
- metadata instanceof ComponentResolveMetaData
- metadata.componentId instanceof LibraryComponentIdentifier
- metadata.componentId.displayName == 'project :myPath library myLib'
- metadata.dependencies.empty
- !metadata.changing
- metadata.configurationNames == ['project :myPath library myLib'] as Set
- metadata.source == null
- }
-
- @Unroll
- def "can convert a java component with #dependenciesDescriptor"() {
- given: "a java sourceset that defines dependencies"
- def sourceSet = Mock(DefaultJavaLanguageSourceSet)
- def dependencySpecs = Mock(DependencySpecContainer)
- def project = Mock(Project)
-
- dependencySpecs.iterator() >> { dependencies.iterator() }
- sourceSet.parentName >> 'myLib'
- sourceSet.dependencies >> dependencySpecs
- project.path >> ':myPath'
- project.version >> '1.0'
-
- def context = new DefaultJavaSourceSetResolveContext(project, sourceSet)
-
- when: "we create a local component factory"
- def factory = new DefaultJavaLocalComponentFactory()
-
- then: "the factory can convert the resolve context"
- factory.canConvert(context)
-
- when: "we convert the context to a local component"
- def component = factory.convert(context)
-
- then: "component metadata reflects the library configuration"
- component.id instanceof ModuleVersionIdentifier
- component.id.group == ':myPath'
- component.id.name == 'myLib'
- component.id.version == '1.0'
- component.id.toString() == ':myPath:myLib:1.0'
-
- when: "we create resolution metadata"
- def metadata = component.toResolveMetaData()
-
- then: "metadata reflects the appropriate library information"
- metadata instanceof ComponentResolveMetaData
- metadata.componentId instanceof LibraryComponentIdentifier
- metadata.componentId.displayName == 'project :myPath library myLib'
- !metadata.changing
- metadata.configurationNames == ['project :myPath library myLib'] as Set
- metadata.source == null
-
- and: "component metadata dependencies correspond to the defined dependencies"
- metadata.dependencies.size() == dependencies.size()
- dependencies.eachWithIndex { spec, i ->
- def componentDep = metadata.dependencies[i]
- assert componentDep.requested.group == spec.projectPath?:project.path
- assert componentDep.requested.name == spec.libraryName
- assert componentDep.requested.version == project.version
- }
-
- where:
- dependencies | dependenciesDescriptor
- [new DefaultDependencySpec('someLib', ':myPath')] | 'single dependency with explicit project'
- [new DefaultDependencySpec('someLib', ':myPath'), new DefaultDependencySpec('someLib2', ':myPath')] | '2 deps on the same project'
- [new DefaultDependencySpec('someLib', ':myPath'), new DefaultDependencySpec('someLib', ':myPath2')] | '2 deps on 2 different projects'
- [new DefaultDependencySpec('someLib', null)] | 'a single dependency on the current project'
-
- }
-}
diff --git a/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaSourceSetResolveContextTest.groovy b/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaSourceSetResolveContextTest.groovy
deleted file mode 100644
index e7b74b3..0000000
--- a/subprojects/language-java/src/test/groovy/org/gradle/language/java/internal/DefaultJavaSourceSetResolveContextTest.groovy
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.language.java.internal
-
-import org.gradle.api.Project
-import spock.lang.Specification
-import spock.lang.Unroll
-
-class DefaultJavaSourceSetResolveContextTest extends Specification {
- def "resolve context can be created from a java source set"() {
- given:
- def project = Mock(Project)
- def sourceset = Mock(DefaultJavaLanguageSourceSet)
-
- when:
- def context = new DefaultJavaSourceSetResolveContext(project, sourceset)
-
- then:
- context.project == project
- context.dependencies.empty
- context.allDependencies.empty
- }
-
- @Unroll
- def "context name for project #path and library #library is #contextName"() {
- given:
- def project = Mock(Project)
- def sourceset = Mock(DefaultJavaLanguageSourceSet)
-
- when:
- project.path >> path
- sourceset.parentName >> library
- def context = new DefaultJavaSourceSetResolveContext(project, sourceset)
-
- then:
- context.name == contextName
-
- where:
- path | library | contextName
- ':myPath' | 'myLib' | 'project :myPath library myLib'
- ':myPath' | 'myLib2' | 'project :myPath library myLib2'
- ':myPath2' | 'myLib' | 'project :myPath2 library myLib'
- }
-}
diff --git a/subprojects/language-jvm/src/integTest/groovy/org/gradle/language/jvm/ResourceOnlyJvmLibraryIntegrationTest.groovy b/subprojects/language-jvm/src/integTest/groovy/org/gradle/language/jvm/ResourceOnlyJvmLibraryIntegrationTest.groovy
index 0536ad9..89ce78a 100644
--- a/subprojects/language-jvm/src/integTest/groovy/org/gradle/language/jvm/ResourceOnlyJvmLibraryIntegrationTest.groovy
+++ b/subprojects/language-jvm/src/integTest/groovy/org/gradle/language/jvm/ResourceOnlyJvmLibraryIntegrationTest.groovy
@@ -49,7 +49,7 @@ model {
assert project.sources as Set == myLib.sources as Set
project.binaries.withType(JarBinarySpec) { jvmBinary ->
- assert jvmBinary.source.toList() == myLib.source.values().toList()
+ assert jvmBinary.inputs.toList() == myLib.sources.values().toList()
}
}
}
diff --git a/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/internal/JvmPluginServiceRegistry.java b/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/internal/JvmPluginServiceRegistry.java
index 2ee8f29..f202b6e 100644
--- a/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/internal/JvmPluginServiceRegistry.java
+++ b/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/internal/JvmPluginServiceRegistry.java
@@ -27,6 +27,9 @@ public class JvmPluginServiceRegistry implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new ComponentRegistrationAction());
}
@@ -39,8 +42,6 @@ public class JvmPluginServiceRegistry implements PluginServiceRegistry {
private static class ComponentRegistrationAction {
public void configure(ServiceRegistration registration, ComponentTypeRegistry componentTypeRegistry) {
- // TODO There should be a more explicit way to execute an action against existing services
- // TODO:DAZ Dependency Management should be able to extract this from the plugin, without explicit registration
componentTypeRegistry.maybeRegisterComponentType(JvmLibrary.class)
.registerArtifactType(SourcesArtifact.class, ArtifactType.SOURCES);
}
diff --git a/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/plugins/JvmResourcesPlugin.java b/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/plugins/JvmResourcesPlugin.java
index 0f426d9..095c44f 100644
--- a/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/plugins/JvmResourcesPlugin.java
+++ b/subprojects/language-jvm/src/main/java/org/gradle/language/jvm/plugins/JvmResourcesPlugin.java
@@ -84,7 +84,7 @@ public class JvmResourcesPlugin implements Plugin<Project> {
return ProcessResources.class;
}
- public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet) {
+ public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
ProcessResources resourcesTask = (ProcessResources) task;
JvmResourceSet resourceSet = (JvmResourceSet) sourceSet;
JvmBinarySpec jvmBinary = (JvmBinarySpec) binary;
diff --git a/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmLanguageIntegrationTest.groovy b/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmLanguageIntegrationTest.groovy
index 8bb1138..b282f2a 100644
--- a/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmLanguageIntegrationTest.groovy
+++ b/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmLanguageIntegrationTest.groovy
@@ -17,6 +17,7 @@
package org.gradle.integtests.language
import com.sun.xml.internal.ws.util.StringUtils
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.EnableModelDsl
import org.gradle.integtests.fixtures.jvm.TestJvmComponent
import org.gradle.internal.SystemProperties
import org.gradle.test.fixtures.archive.JarTestFixture
@@ -26,6 +27,8 @@ abstract class AbstractJvmLanguageIntegrationTest extends AbstractIntegrationSpe
abstract TestJvmComponent getApp()
def setup() {
+ EnableModelDsl.enable(executer)
+
buildFile << """
plugins {
id 'jvm-component'
@@ -177,19 +180,20 @@ abstract class AbstractJvmLanguageIntegrationTest extends AbstractIntegrationSpe
def expectedOutputs = app.expectedOutputs*.fullPath as String[]
and:
- buildFile << """
+ buildFile << '''
model {
components {
- myLib(JvmLibrarySpec)
- }
- jvm {
- allBinaries {
- classesDir = file("\${project.buildDir}/custom-classes")
- resourcesDir = file("\${project.buildDir}/custom-resources")
+ myLib(JvmLibrarySpec) {
+ binaries {
+ all {
+ classesDir = new File($("buildDir"), "custom-classes")
+ resourcesDir = new File($("buildDir"), "custom-resources")
+ }
+ }
}
}
}
-"""
+'''
and:
succeeds "assemble"
diff --git a/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmPluginLanguageIntegrationTest.groovy b/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmPluginLanguageIntegrationTest.groovy
index eb19a5a..379b94f 100644
--- a/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmPluginLanguageIntegrationTest.groovy
+++ b/subprojects/language-jvm/src/testFixtures/groovy/org/gradle/integtests/language/AbstractJvmPluginLanguageIntegrationTest.groovy
@@ -68,7 +68,7 @@ abstract class AbstractJvmPluginLanguageIntegrationTest extends AbstractIntegrat
assert project.sources as Set == myLib.sources as Set
project.binaries.withType(JarBinarySpec) { jvmBinary ->
- assert jvmBinary.source.toList() == myLib.source.values().toList()
+ assert jvmBinary.inputs.toList() == myLib.sources.values().toList()
}
}
}
@@ -110,7 +110,7 @@ abstract class AbstractJvmPluginLanguageIntegrationTest extends AbstractIntegrat
assert project.sources as Set == myLib.sources as Set
project.binaries.withType(JarBinarySpec) { jvmBinary ->
- assert jvmBinary.source.toList() == myLib.source.values().toList()
+ assert jvmBinary.inputs.toList() == myLib.sources.values().toList()
}
}
}
diff --git a/subprojects/language-native/src/integTest/groovy/org/gradle/language/AbstractNativeLanguageIncrementalCompileIntegrationTest.groovy b/subprojects/language-native/src/integTest/groovy/org/gradle/language/AbstractNativeLanguageIncrementalCompileIntegrationTest.groovy
index 9fc3feb..b8719b0 100755
--- a/subprojects/language-native/src/integTest/groovy/org/gradle/language/AbstractNativeLanguageIncrementalCompileIntegrationTest.groovy
+++ b/subprojects/language-native/src/integTest/groovy/org/gradle/language/AbstractNativeLanguageIncrementalCompileIntegrationTest.groovy
@@ -20,6 +20,7 @@ import groovy.io.FileType
import org.gradle.integtests.fixtures.CompilationOutputsFixture
import org.gradle.nativeplatform.fixtures.AbstractInstalledToolChainIntegrationSpec
import org.gradle.nativeplatform.fixtures.app.IncrementalHelloWorldApp
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
import org.gradle.util.GUtil
import spock.lang.Unroll
@@ -422,6 +423,7 @@ model {
objectFileFor(sourceFile).assertDoesNotExist()
}
+ @LeaksFileHandles
def "removes output file when source file is removed"() {
given:
def extraSource = file("src/main/${app.sourceType}/extra.${app.sourceExtension}")
@@ -443,6 +445,7 @@ model {
outputs.noneRecompiled()
}
+ @LeaksFileHandles
def "removes output files when all source files are removed"() {
given:
run "mainExecutable"
diff --git a/subprojects/language-native/src/integTest/groovy/org/gradle/language/c/CLanguageIntegrationTest.groovy b/subprojects/language-native/src/integTest/groovy/org/gradle/language/c/CLanguageIntegrationTest.groovy
index 87f0206..a213d3a 100755
--- a/subprojects/language-native/src/integTest/groovy/org/gradle/language/c/CLanguageIntegrationTest.groovy
+++ b/subprojects/language-native/src/integTest/groovy/org/gradle/language/c/CLanguageIntegrationTest.groovy
@@ -23,7 +23,7 @@ import spock.lang.Issue
import spock.lang.Unroll
import static org.gradle.util.Matchers.containsText
-// TODO:DAZ Some of these tests should apply to all single-language integration tests
+
@LeaksFileHandles
class CLanguageIntegrationTest extends AbstractNativeLanguageIntegrationTest {
diff --git a/subprojects/language-native/src/integTest/groovy/org/gradle/language/cpp/CppLanguageIntegrationTest.groovy b/subprojects/language-native/src/integTest/groovy/org/gradle/language/cpp/CppLanguageIntegrationTest.groovy
index b604f19..6430a73 100755
--- a/subprojects/language-native/src/integTest/groovy/org/gradle/language/cpp/CppLanguageIntegrationTest.groovy
+++ b/subprojects/language-native/src/integTest/groovy/org/gradle/language/cpp/CppLanguageIntegrationTest.groovy
@@ -51,7 +51,7 @@ model {
fails "mainExecutable"
failure.assertHasDescription("Execution failed for task ':compileMainExecutableMainCpp'.");
failure.assertHasCause("A build operation failed.")
- failure.assertThatCause(containsText("C\\+\\+ compiler failed while compiling broken.cpp"))
+ failure.assertThatCause(containsText("C++ compiler failed while compiling broken.cpp"))
}
def "sources are compiled with C++ compiler"() {
diff --git a/subprojects/language-native/src/integTest/groovy/org/gradle/language/nativeplatform/ParallelNativePluginsIntegrationTest.groovy b/subprojects/language-native/src/integTest/groovy/org/gradle/language/nativeplatform/ParallelNativePluginsIntegrationTest.groovy
index 3ada7b3..85c9207 100644
--- a/subprojects/language-native/src/integTest/groovy/org/gradle/language/nativeplatform/ParallelNativePluginsIntegrationTest.groovy
+++ b/subprojects/language-native/src/integTest/groovy/org/gradle/language/nativeplatform/ParallelNativePluginsIntegrationTest.groovy
@@ -22,6 +22,7 @@ import org.gradle.nativeplatform.fixtures.AbstractInstalledToolChainIntegrationS
import org.gradle.nativeplatform.fixtures.ExecutableFixture
import org.gradle.nativeplatform.fixtures.NativeInstallationFixture
import org.gradle.nativeplatform.fixtures.app.*
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
import spock.lang.IgnoreIf
@@ -76,6 +77,7 @@ class ParallelNativePluginsIntegrationTest extends AbstractInstalledToolChainInt
}
@Requires(TestPrecondition.CAN_INSTALL_EXECUTABLE)
+ @LeaksFileHandles("can't delete build/install/firstMainExecutable/lib")
def "can produce multiple executables that use a library from a single project in parallel"() {
given:
Map<String, ExeWithLibraryUsingLibraryHelloWorldApp> apps = [
diff --git a/subprojects/language-native/src/main/java/org/gradle/language/assembler/plugins/internal/AssembleTaskConfig.java b/subprojects/language-native/src/main/java/org/gradle/language/assembler/plugins/internal/AssembleTaskConfig.java
index 74545b1..29a22d6 100644
--- a/subprojects/language-native/src/main/java/org/gradle/language/assembler/plugins/internal/AssembleTaskConfig.java
+++ b/subprojects/language-native/src/main/java/org/gradle/language/assembler/plugins/internal/AssembleTaskConfig.java
@@ -20,6 +20,7 @@ import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.tasks.util.PatternSet;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.language.base.LanguageSourceSet;
import org.gradle.language.base.internal.LanguageSourceSetInternal;
import org.gradle.language.base.internal.SourceTransformTaskConfig;
@@ -37,7 +38,7 @@ public class AssembleTaskConfig implements SourceTransformTaskConfig {
return Assemble.class;
}
- public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet) {
+ public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
configureAssembleTask((Assemble) task, (NativeBinarySpecInternal) binary, (LanguageSourceSetInternal) sourceSet);
}
diff --git a/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/CompileTaskConfig.java b/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/CompileTaskConfig.java
index 3b9c20f..709261d 100644
--- a/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/CompileTaskConfig.java
+++ b/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/CompileTaskConfig.java
@@ -20,6 +20,7 @@ import org.gradle.api.Task;
import org.gradle.api.Transformer;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.ExtensionAware;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.language.PreprocessingTool;
import org.gradle.language.base.LanguageSourceSet;
import org.gradle.language.base.internal.LanguageSourceSetInternal;
@@ -60,7 +61,7 @@ abstract public class CompileTaskConfig implements SourceTransformTaskConfig {
return taskType;
}
- public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet) {
+ public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
configureCompileTaskCommon((AbstractNativeCompileTask) task, (NativeBinarySpecInternal) binary, (LanguageSourceSetInternal) sourceSet);
configureCompileTask((AbstractNativeCompileTask) task, (NativeBinarySpecInternal) binary, (LanguageSourceSetInternal) sourceSet);
}
diff --git a/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/registry/NativeLanguageServices.java b/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/registry/NativeLanguageServices.java
index e2803b1..9a8f674 100644
--- a/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/registry/NativeLanguageServices.java
+++ b/subprojects/language-native/src/main/java/org/gradle/language/nativeplatform/internal/registry/NativeLanguageServices.java
@@ -25,6 +25,9 @@ public class NativeLanguageServices implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
diff --git a/subprojects/language-native/src/main/java/org/gradle/language/rc/plugins/internal/WindowsResourcesCompileTaskConfig.java b/subprojects/language-native/src/main/java/org/gradle/language/rc/plugins/internal/WindowsResourcesCompileTaskConfig.java
index b81b4ec..b7fadf6 100644
--- a/subprojects/language-native/src/main/java/org/gradle/language/rc/plugins/internal/WindowsResourcesCompileTaskConfig.java
+++ b/subprojects/language-native/src/main/java/org/gradle/language/rc/plugins/internal/WindowsResourcesCompileTaskConfig.java
@@ -21,6 +21,7 @@ import org.gradle.api.Task;
import org.gradle.api.file.FileTree;
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.tasks.util.PatternSet;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.language.base.LanguageSourceSet;
import org.gradle.language.base.internal.LanguageSourceSetInternal;
import org.gradle.language.base.internal.SourceTransformTaskConfig;
@@ -44,7 +45,7 @@ public class WindowsResourcesCompileTaskConfig implements SourceTransformTaskCon
return WindowsResourceCompile.class;
}
- public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet) {
+ public void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
configureResourceCompileTask((WindowsResourceCompile) task, (NativeBinarySpecInternal) binary, (WindowsResourceSet) sourceSet);
}
diff --git a/subprojects/language-native/src/test/groovy/org/gradle/language/AbstractNativeComponentPluginTest.groovy b/subprojects/language-native/src/test/groovy/org/gradle/language/AbstractNativeComponentPluginTest.groovy
index 997a1b9..b95e405 100644
--- a/subprojects/language-native/src/test/groovy/org/gradle/language/AbstractNativeComponentPluginTest.groovy
+++ b/subprojects/language-native/src/test/groovy/org/gradle/language/AbstractNativeComponentPluginTest.groovy
@@ -21,7 +21,6 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.TaskDependencyMatchers
-import org.gradle.language.base.FunctionalSourceSet
import org.gradle.language.base.LanguageSourceSet
import org.gradle.model.ModelMap
import org.gradle.model.internal.core.ModelPath
@@ -70,20 +69,20 @@ abstract class AbstractNativeComponentPluginTest extends Specification {
and:
def exe = components.exe
- exe.sources instanceof FunctionalSourceSet
+ exe.sources instanceof ModelMap
sourceSetClass.isInstance(exe.sources."$pluginName")
exe.sources."$pluginName".source.srcDirs == [project.file("src/exe/$pluginName")] as Set
exe.sources."$pluginName".exportedHeaders.srcDirs == [project.file("src/exe/headers")] as Set
and:
def lib = components.lib
- lib.sources instanceof FunctionalSourceSet
+ lib.sources instanceof ModelMap
sourceSetClass.isInstance(lib.sources."$pluginName")
lib.sources."$pluginName".source.srcDirs == [project.file("src/lib/$pluginName")] as Set
lib.sources."$pluginName".exportedHeaders.srcDirs == [project.file("src/lib/headers")] as Set
and:
- project.sources as Set == lib.sources + exe.sources
+ project.sources as Set == (lib.sources as Set) + (exe.sources as Set)
}
def "can configure source set locations"() {
diff --git a/subprojects/language-native/src/test/groovy/org/gradle/language/assembler/plugins/AssemblerPluginTest.groovy b/subprojects/language-native/src/test/groovy/org/gradle/language/assembler/plugins/AssemblerPluginTest.groovy
index 3019e6f..f430751 100644
--- a/subprojects/language-native/src/test/groovy/org/gradle/language/assembler/plugins/AssemblerPluginTest.groovy
+++ b/subprojects/language-native/src/test/groovy/org/gradle/language/assembler/plugins/AssemblerPluginTest.groovy
@@ -20,7 +20,6 @@ import org.gradle.api.Project
import org.gradle.api.tasks.TaskDependencyMatchers
import org.gradle.language.assembler.AssemblerSourceSet
import org.gradle.language.assembler.tasks.Assemble
-import org.gradle.language.base.FunctionalSourceSet
import org.gradle.model.ModelMap
import org.gradle.model.internal.core.ModelPath
import org.gradle.model.internal.type.ModelTypes
@@ -52,7 +51,7 @@ class AssemblerPluginTest extends Specification {
then:
def components = realizeComponents()
def exe = components.exe
- exe.sources instanceof FunctionalSourceSet
+ exe.sources instanceof ModelMap
exe.sources.asm instanceof AssemblerSourceSet
exe.sources.asm.source.srcDirs == [project.file("src/exe/asm")] as Set
diff --git a/subprojects/language-scala/language-scala.gradle b/subprojects/language-scala/language-scala.gradle
index 9d2e0b1..830ceef 100644
--- a/subprojects/language-scala/language-scala.gradle
+++ b/subprojects/language-scala/language-scala.gradle
@@ -6,7 +6,7 @@ dependencies {
compile project(":languageJava")
compile project(":languageJvm")
// keep in sync with ScalaLanguagePlugin code
- provided("com.typesafe.zinc:zinc:0.3.0")
+ provided("com.typesafe.zinc:zinc:0.3.7")
testCompile libraries.groovy
}
@@ -14,4 +14,4 @@ dependencies {
strictCompile()
useTestFixtures()
useTestFixtures(project: ":languageJvm", sourceSet: 'testFixtures')
-useTestFixtures(project: ":platformBase")
\ No newline at end of file
+useTestFixtures(project: ":platformBase")
diff --git a/subprojects/language-scala/src/integTest/groovy/org/gradle/language/scala/JointScalaLangIntegrationTest.groovy b/subprojects/language-scala/src/integTest/groovy/org/gradle/language/scala/JointScalaLangIntegrationTest.groovy
index f0ef6b3..2f275cb 100644
--- a/subprojects/language-scala/src/integTest/groovy/org/gradle/language/scala/JointScalaLangIntegrationTest.groovy
+++ b/subprojects/language-scala/src/integTest/groovy/org/gradle/language/scala/JointScalaLangIntegrationTest.groovy
@@ -16,10 +16,55 @@
package org.gradle.language.scala
+import com.sun.xml.internal.ws.util.StringUtils
+import org.gradle.integtests.fixtures.jvm.JvmSourceFile
import org.gradle.integtests.fixtures.jvm.TestJvmComponent
import org.gradle.integtests.language.AbstractJvmLanguageIntegrationTest
import org.gradle.language.scala.fixtures.TestJointCompiledComponent
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
class JointScalaLangIntegrationTest extends AbstractJvmLanguageIntegrationTest {
TestJvmComponent app = new TestJointCompiledComponent()
+
+ @Requires(TestPrecondition.JDK8_OR_LATER)
+ def "can compile class files with Java 8 features" () {
+ app.sources.add java8SpecificClassFile
+
+ when:
+ app.writeSources(file("src/myLib"))
+ app.writeResources(file("src/myLib/resources"))
+ def expectedOutputs = app.expectedOutputs*.fullPath as String[]
+
+ and:
+ buildFile << """
+ model {
+ components {
+ myLib(JvmLibrarySpec)
+ }
+ }
+ """
+ and:
+ succeeds "assemble"
+
+ then:
+ executedAndNotSkipped ":processMyLibJarMyLibResources", ":compileMyLibJarMyLib${StringUtils.capitalize(app.languageName)}"
+
+ and:
+ file("build/classes/myLibJar").assertHasDescendants(expectedOutputs)
+ }
+
+ def getJava8SpecificClassFile() {
+ new JvmSourceFile("compile/test", "Java8Class.java", '''
+package compile.test;
+
+import java.util.function.Function;
+
+class Java8Class {
+ public static void lambdaMethod() {
+ final Function<Integer, String> f = n -> Integer.toString(n);
+ }
+}
+''')
+ }
}
diff --git a/subprojects/language-scala/src/main/java/org/gradle/api/internal/tasks/scala/ZincScalaCompiler.java b/subprojects/language-scala/src/main/java/org/gradle/api/internal/tasks/scala/ZincScalaCompiler.java
index fad4962..c49d517 100644
--- a/subprojects/language-scala/src/main/java/org/gradle/api/internal/tasks/scala/ZincScalaCompiler.java
+++ b/subprojects/language-scala/src/main/java/org/gradle/api/internal/tasks/scala/ZincScalaCompiler.java
@@ -86,7 +86,10 @@ public class ZincScalaCompiler implements Compiler<ScalaJavaJointCompileSpec>, S
boolean transactional = false;
Option<File> backup = Option.empty();
- return new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, apiDumpDirectory, transactional, backup);
+ // We need to use the deprecated constructor as it is compatible with certain previous versions of the Zinc compiler
+ @SuppressWarnings("deprecation")
+ IncOptions options = new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize, apiDumpDirectory, transactional, backup);
+ return options;
}
static com.typesafe.zinc.Compiler createCompiler(Iterable<File> scalaClasspath, Iterable<File> zincClasspath, xsbti.Logger logger) {
diff --git a/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DefaultScalaToolProvider.java b/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DefaultScalaToolProvider.java
index cde6b3d..6c33ce5 100644
--- a/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DefaultScalaToolProvider.java
+++ b/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DefaultScalaToolProvider.java
@@ -31,7 +31,7 @@ import java.io.File;
import java.util.Set;
public class DefaultScalaToolProvider implements ToolProvider {
- public static final String DEFAULT_ZINC_VERSION = "0.3.5.3";
+ public static final String DEFAULT_ZINC_VERSION = "0.3.7";
private ProjectFinder projectFinder;
private final CompilerDaemonManager compilerDaemonManager;
diff --git a/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DownloadingScalaToolChain.java b/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DownloadingScalaToolChain.java
index 21e7af4..de1f7fd 100644
--- a/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DownloadingScalaToolChain.java
+++ b/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/DownloadingScalaToolChain.java
@@ -31,8 +31,6 @@ import java.io.File;
import java.util.Set;
public class DownloadingScalaToolChain implements ScalaToolChainInternal {
- public static final String DEFAULT_ZINC_VERSION = "0.3.0";
-
private ProjectFinder projectFinder;
private CompilerDaemonManager compilerDaemonManager;
private final ConfigurationContainer configurationContainer;
@@ -58,7 +56,7 @@ public class DownloadingScalaToolChain implements ScalaToolChainInternal {
public ToolProvider select(ScalaPlatform targetPlatform) {
try {
Configuration scalaClasspath = resolveDependency(String.format("org.scala-lang:scala-compiler:%s", targetPlatform.getScalaVersion()));
- Configuration zincClasspath = resolveDependency(String.format("com.typesafe.zinc:zinc:%s", DEFAULT_ZINC_VERSION));
+ Configuration zincClasspath = resolveDependency(String.format("com.typesafe.zinc:zinc:%s", DefaultScalaToolProvider.DEFAULT_ZINC_VERSION));
Set<File> resolvedScalaClasspath = scalaClasspath.resolve();
Set<File> resolvedZincClasspath = zincClasspath.resolve();
return new DefaultScalaToolProvider(projectFinder, compilerDaemonManager, resolvedScalaClasspath, resolvedZincClasspath);
diff --git a/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/ScalaToolChainServiceRegistry.java b/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/ScalaToolChainServiceRegistry.java
index 02d2192..081e922 100644
--- a/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/ScalaToolChainServiceRegistry.java
+++ b/subprojects/language-scala/src/main/java/org/gradle/language/scala/internal/toolchain/ScalaToolChainServiceRegistry.java
@@ -28,6 +28,9 @@ public class ScalaToolChainServiceRegistry implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
@@ -44,4 +47,4 @@ public class ScalaToolChainServiceRegistry implements PluginServiceRegistry {
return new DownloadingScalaToolChain(projectFinder, compilerDaemonManager, configurationContainer, dependencyHandler);
}
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/language-scala/src/main/java/org/gradle/language/scala/plugins/ScalaLanguagePlugin.java b/subprojects/language-scala/src/main/java/org/gradle/language/scala/plugins/ScalaLanguagePlugin.java
index ff77a5a..8ec7a88 100644
--- a/subprojects/language-scala/src/main/java/org/gradle/language/scala/plugins/ScalaLanguagePlugin.java
+++ b/subprojects/language-scala/src/main/java/org/gradle/language/scala/plugins/ScalaLanguagePlugin.java
@@ -99,7 +99,7 @@ public class ScalaLanguagePlugin implements Plugin<Project> {
return PlatformScalaCompile.class;
}
- public void configureTask(Task task, BinarySpec binarySpec, LanguageSourceSet sourceSet) {
+ public void configureTask(Task task, BinarySpec binarySpec, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
PlatformScalaCompile compile = (PlatformScalaCompile) task;
ScalaLanguageSourceSet scalaSourceSet = (ScalaLanguageSourceSet) sourceSet;
JvmBinarySpec binary = (JvmBinarySpec) binarySpec;
diff --git a/subprojects/language-scala/src/main/java/org/gradle/language/scala/tasks/PlatformScalaCompile.java b/subprojects/language-scala/src/main/java/org/gradle/language/scala/tasks/PlatformScalaCompile.java
index a012362..79a247d 100644
--- a/subprojects/language-scala/src/main/java/org/gradle/language/scala/tasks/PlatformScalaCompile.java
+++ b/subprojects/language-scala/src/main/java/org/gradle/language/scala/tasks/PlatformScalaCompile.java
@@ -20,8 +20,8 @@ import org.gradle.api.Incubating;
import org.gradle.api.internal.tasks.scala.ScalaJavaJointCompileSpec;
import org.gradle.language.base.internal.compile.Compiler;
import org.gradle.language.base.internal.compile.CompilerUtil;
+import org.gradle.language.scala.internal.toolchain.ScalaToolChainInternal;
import org.gradle.language.scala.ScalaPlatform;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import javax.inject.Inject;
@@ -47,12 +47,12 @@ public class PlatformScalaCompile extends AbstractScalaCompile {
}
@Inject
- protected ToolResolver getToolResolver() {
+ protected ScalaToolChainInternal getToolChain() {
throw new UnsupportedOperationException();
}
@Override
protected Compiler<ScalaJavaJointCompileSpec> getCompiler(ScalaJavaJointCompileSpec spec) {
- return CompilerUtil.castCompiler(getToolResolver().resolveCompiler(spec.getClass(), getPlatform()).get());
+ return CompilerUtil.castCompiler(getToolChain().select(getPlatform()).newCompiler(spec.getClass()));
}
}
diff --git a/subprojects/launcher/launcher.gradle b/subprojects/launcher/launcher.gradle
index 0bd31cc..b4d19b5 100644
--- a/subprojects/launcher/launcher.gradle
+++ b/subprojects/launcher/launcher.gradle
@@ -17,11 +17,14 @@ dependencies {
integTestCompile project(':internalIntegTesting')
integTestRuntime project(':plugins')
+ testFixturesCompile project(':internalIntegTesting')
+
startScriptGenerator project(':plugins')
}
useTestFixtures()
useTestFixtures(project: ':languageJava')
+useTestFixtures(project: ':messaging')
integTestTasks.all {
if (isCiServer) {
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy
index 17c046d..4cfece0 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/BuildEnvironmentIntegrationTest.groovy
@@ -17,6 +17,7 @@
package org.gradle.launcher
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.executer.ExecutionResult
import spock.lang.Issue
import spock.lang.Unroll
@@ -140,7 +141,7 @@ task check << {
""", expectedEncoding
when:
- run "echoDefaultEncoding"
+ succeeds "echoDefaultEncoding"
then:
output.contains "default encoding: $expectedEncoding"
@@ -171,7 +172,6 @@ task check << {
}
""", executer.getDefaultCharacterEncoding()
-
and:
buildFile.write """
apply plugin: "java"
@@ -183,7 +183,7 @@ task check << {
""", expectedEncoding
when:
- run "echoDefaultEncoding"
+ succeeds "echoDefaultEncoding"
then:
output.contains "default encoding: $expectedEncoding"
@@ -195,4 +195,9 @@ task check << {
null | Charset.defaultCharset().name()
}
+ @Override
+ protected ExecutionResult succeeds(String... tasks) {
+ executer.useDefaultBuildJvmArgs()
+ return super.succeeds(tasks)
+ }
}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/GradleConfigurabilityIntegrationSpec.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/GradleConfigurabilityIntegrationSpec.groovy
index d541f00..7338437 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/GradleConfigurabilityIntegrationSpec.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/GradleConfigurabilityIntegrationSpec.groovy
@@ -37,7 +37,7 @@ class GradleConfigurabilityIntegrationSpec extends AbstractIntegrationSpec {
def buildSucceeds(String script) {
file('build.gradle') << script
- executer.withArguments("--info").withNoDefaultJvmArgs().run()
+ executer.withArguments("--info").useDefaultBuildJvmArgs().run()
}
def "honours jvm args specified in gradle.properties"() {
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/AbstractContinuousIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/AbstractContinuousIntegrationTest.groovy
deleted file mode 100644
index f27203c..0000000
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/AbstractContinuousIntegrationTest.groovy
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.launcher.continuous
-
-import com.google.common.util.concurrent.SimpleTimeLimiter
-import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.integtests.fixtures.executer.*
-import org.gradle.internal.os.OperatingSystem
-import org.gradle.process.internal.streams.SafeStreams
-import org.gradle.util.RedirectStdIn
-import org.gradle.util.TextUtil
-import org.junit.Rule
-import org.spockframework.runtime.SpockTimeoutError
-import spock.util.concurrent.PollingConditions
-
-import java.util.concurrent.TimeUnit
-
-abstract class AbstractContinuousIntegrationTest extends AbstractIntegrationSpec {
- private static final int WAIT_FOR_WATCHING_TIMEOUT_SECONDS = 30
- private static final int WAIT_FOR_SHUTDOWN_TIMEOUT_SECONDS = 10
-
- GradleHandle gradle
-
- private int standardOutputBuildMarker = 0
- private int errorOutputBuildMarker = 0
-
- int buildTimeout = WAIT_FOR_WATCHING_TIMEOUT_SECONDS
- int shutdownTimeout = WAIT_FOR_SHUTDOWN_TIMEOUT_SECONDS
- boolean expectBuildFailure = false
- boolean killToStop
-
- @Rule
- RedirectStdIn redirectStdIn = new RedirectStdIn()
- PipedOutputStream stdinPipe = redirectStdIn.getStdinPipe()
-
- public void turnOnDebug() {
- executer.withDebug(true)
- executer.withArgument("--no-daemon")
- buildTimeout *= 100
- shutdownTimeout *= 100
- }
-
- public void cleanupWhileTestFilesExist() {
- stopGradle()
- if (OperatingSystem.current().isWindows()) {
- // needs delay to release file handles
- sleep(500L)
- }
- }
-
- def setup() {
- // this is here to ensure that the lastModified() timestamps actually change in between builds.
- // if the build is very fast, the timestamp of the file will not change and the JDK file watch service won't see the change.
- executer.beforeExecute {
- def initScript = file("init.gradle")
- initScript.text = """
- def startAt = System.currentTimeMillis()
- gradle.buildFinished {
- def sinceStart = System.currentTimeMillis() - startAt
- if (sinceStart < 2000) {
- sleep 2000 - sinceStart
- }
- }
- """
- withArgument("-I").withArgument(initScript.absolutePath)
- }
- }
-
- @Override
- protected ExecutionResult succeeds(String... tasks) {
- if (tasks) {
- runBuild(tasks)
- } else if (!gradle.isRunning()) {
- throw new UnexpectedBuildFailure("Gradle has exited")
- }
- if (gradle == null) {
- throw new UnexpectedBuildFailure("Gradle never started")
- }
- waitForBuild()
- if (result instanceof ExecutionFailure) {
- throw new UnexpectedBuildFailure("build was expected to succeed but failed")
- }
- result
- }
-
- ExecutionFailure fails(String... tasks) {
- if (tasks) {
- runBuild(tasks)
- } else if (!gradle.isRunning()) {
- throw new UnexpectedBuildFailure("Gradle has exited")
- }
- waitForBuild()
- if (!(result instanceof ExecutionFailure)) {
- throw new UnexpectedBuildFailure("build was expected to fail but succeeded")
- }
- failure = result as ExecutionFailure
- failure
- }
-
- private void runBuild(String... tasks) {
- stopGradle()
- standardOutputBuildMarker = 0
- errorOutputBuildMarker = 0
-
- executer.withStdIn(System.in)
- gradle = executer.withTasks(tasks).withForceInteractive(true).withArgument("--continuous").start()
- }
-
- private void waitForBuild() {
- def lastOutput = buildOutputSoFar()
- def lastActivity = System.currentTimeMillis()
-
- while (gradle.isRunning() && System.currentTimeMillis() - lastActivity < (buildTimeout * 1000)) {
- sleep 100
- def lastLength = lastOutput.size()
- lastOutput = buildOutputSoFar()
-
- if (lastOutput.contains(TextUtil.toPlatformLineSeparators("Waiting for changes to input files of tasks..."))) {
- break
- } else if (lastOutput.size() > lastLength) {
- lastActivity = System.currentTimeMillis()
- }
- }
-
- def out = buildOutputSoFar()
- def err = gradle.errorOutput.substring(errorOutputBuildMarker)
- standardOutputBuildMarker = gradle.standardOutput.length()
- errorOutputBuildMarker = gradle.errorOutput.length()
-
- //noinspection GroovyConditionalWithIdenticalBranches
- result = out.contains("BUILD SUCCESSFUL") ? new OutputScrapingExecutionResult(out, err) : new OutputScrapingExecutionFailure(out, err)
- }
-
- void stopGradle() {
- if (gradle && gradle.isRunning()) {
- if (killToStop) {
- gradle.abort()
- } else {
- closeStdIn()
- new SimpleTimeLimiter().callWithTimeout(
- { expectBuildFailure ? gradle.waitForFailure() : gradle.waitForFinish() },
- shutdownTimeout, TimeUnit.SECONDS, false
- )
- }
- }
- }
-
- void closeStdIn() {
- stdinPipe.close()
- executer.withStdIn(SafeStreams.emptyInput())
- redirectStdIn.resetStdinPipe()
- stdinPipe = redirectStdIn.getStdinPipe()
- }
-
- void noBuildTriggered(int waitSeconds = 3) {
- // TODO - change this general strategy to positively detect changes we are ignoring instead of asserting that a build doesn't happen in some time frame
- try {
- new PollingConditions(initialDelay: 0.5).within(waitSeconds) {
- assert !buildOutputSoFar().empty
- }
- throw new AssertionError("Expected build not to start, but started with output: " + buildOutputSoFar())
- } catch (SpockTimeoutError e) {
- // ok, what we want
- }
- }
-
- // should be private, but is accessed by closures in this class
- protected String buildOutputSoFar() {
- gradle.standardOutput.substring(standardOutputBuildMarker)
- }
-
- void cancelsAndExits() {
- waitForNotRunning()
- assert buildOutputSoFar().contains("Build cancelled.")
- }
-
- void doesntExit() {
- try {
- waitForNotRunning()
- assert gradle.running
- } catch (AssertionError ignore) {
-
- }
- }
-
- private waitForNotRunning() {
- new PollingConditions().within(WAIT_FOR_SHUTDOWN_TIMEOUT_SECONDS) {
- assert !gradle.running
- }
- }
-
-}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/CancellationContinuousIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/CancellationContinuousIntegrationTest.groovy
index e784b17..a354064 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/CancellationContinuousIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/CancellationContinuousIntegrationTest.groovy
@@ -16,7 +16,6 @@
package org.gradle.launcher.continuous
-import org.gradle.internal.SystemProperties
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@@ -31,12 +30,7 @@ class CancellationContinuousIntegrationTest extends Java7RequiringContinuousInte
succeeds("build")
when:
- stdinPipe.write(4) // EOT / CTRL-D
-
- // TODO: this is not right, we are sending a line ending to workaround the input buffering by the daemon
- // Possibly, the daemon should be EOT aware and close the stream.
- // Or, when the client is doing a blocking read of the input we shouldn't buffer.
- stdinPipe.write(SystemProperties.instance.lineSeparator.bytes)
+ gradle.cancelWithEOT()
then:
cancelsAndExits()
@@ -47,7 +41,7 @@ class CancellationContinuousIntegrationTest extends Java7RequiringContinuousInte
succeeds("build")
when:
- closeStdIn()
+ gradle.stdinPipe.close()
then:
cancelsAndExits()
@@ -62,18 +56,26 @@ class CancellationContinuousIntegrationTest extends Java7RequiringContinuousInte
doesntExit()
when:
- stdinPipe.close()
+ gradle.stdinPipe.close()
then:
cancelsAndExits()
}
- @Requires(TestPrecondition.NOT_WINDOWS) // GradleHandle.abort() is unsafe on Windows - this is a test infrastructure problem
+ @Requires(TestPrecondition.NOT_WINDOWS)
+ // GradleHandle.abort() is unsafe on Windows - this is a test infrastructure problem
def "does not cancel on EOT or by closing System.in when not interactive"() {
when:
- executer.beforeExecute { it.withForceInteractive(false) }
+ executer.beforeExecute {
+ it.withForceInteractive(false).withStdinPipe(new PipedOutputStream() {
+ @Override
+ void connect(PipedInputStream snk) throws IOException {
+ super.connect(snk)
+ close()
+ }
+ })
+ }
killToStop = true
- closeStdIn()
then:
succeeds "build" // tests message
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/ContinuousBuildCancellationIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/ContinuousBuildCancellationIntegrationTest.groovy
new file mode 100644
index 0000000..42c77a3
--- /dev/null
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/ContinuousBuildCancellationIntegrationTest.groovy
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.launcher.continuous
+
+import org.gradle.test.fixtures.ConcurrentTestUtil
+import org.gradle.test.fixtures.file.TestFile
+import org.gradle.util.TextUtil
+
+class ContinuousBuildCancellationIntegrationTest extends Java7RequiringContinuousIntegrationTest {
+
+ TestFile setupJavaProject() {
+ buildFile.text = "apply plugin: 'java'"
+ testDirectory.createDir('src/main/java')
+ }
+
+ def "can cancel continuous build by ctrl+d"() {
+ given:
+ setupJavaProject()
+
+ when:
+ succeeds("build")
+
+ then:
+ noExceptionThrown()
+
+ when:
+ if (inputBefore) {
+ stdinPipe << inputBefore
+ }
+ if (flushBefore) {
+ stdinPipe.flush()
+ }
+ sendEOT()
+
+ then:
+ ConcurrentTestUtil.poll(buildTimeout, 0.5) {
+ assert !gradle.isRunning()
+ }
+
+ where:
+ [inputBefore, flushBefore] << [['', ' ', 'a', 'some input', 'a' * 8192], [true, false]].combinations()
+ }
+
+ def "does not cancel continuous build when other than ctrl+d is entered"() {
+ given:
+ setupJavaProject()
+
+ when:
+ succeeds("build")
+
+ then:
+ noExceptionThrown()
+
+ when:
+ stdinPipe << "some input"
+ stdinPipe << TextUtil.platformLineSeparator
+ stdinPipe.flush()
+
+ then:
+ sleep(1000L)
+ assert gradle.isRunning()
+ }
+
+ def "can cancel continuous build by ctrl+d after multiple builds"() {
+ given:
+ def testfile = setupJavaProject().file('Thing.java')
+ testfile.text = 'public class Thing {}'
+
+ when:
+ succeeds("build")
+
+ then:
+ noExceptionThrown()
+
+ when:
+ for (int i = 0; i < 3; i++) {
+ testfile << '// changed'
+ succeeds()
+ }
+ and:
+ sendEOT()
+
+ then:
+ ConcurrentTestUtil.poll(buildTimeout, 0.5) {
+ assert !gradle.isRunning()
+ }
+ }
+}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/JdkVersionsContinuousIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/JdkVersionsContinuousIntegrationTest.groovy
index df3cba2..d393c5c 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/JdkVersionsContinuousIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/JdkVersionsContinuousIntegrationTest.groovy
@@ -22,16 +22,7 @@ import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
import org.gradle.internal.jvm.JavaInfo
import org.gradle.util.Requires
- at Requires(adhoc = {
- // not quite right, we want to allow coverage builds testing against a real distro
- JavaVersion.current().java7Compatible || !GradleContextualExecuter.embedded
-})
class JdkVersionsContinuousIntegrationTest extends AbstractContinuousIntegrationTest {
-
- def setup() {
- executer.requireGradleHome()
- }
-
@Requires(adhoc = { JdkVersionsContinuousIntegrationTest.java6() })
def "requires java 7 build runtime"() {
when:
@@ -44,12 +35,17 @@ class JdkVersionsContinuousIntegrationTest extends AbstractContinuousIntegration
failureDescriptionContains("Continuous build requires Java 7 or later.")
}
- @Requires(adhoc = { JdkVersionsContinuousIntegrationTest.java6() && JdkVersionsContinuousIntegrationTest.java7OrBetter() })
+ @Requires(adhoc = { JdkVersionsContinuousIntegrationTest.java6() && JdkVersionsContinuousIntegrationTest.java7OrBetter() &&
+ // This test doesn't work on Java 1.6 CI commit builds as these builds rebuild the distribution using Java 6 rather than reuse
+ // the distribution that is shared by the coverage builds. The following approximates "don't run this test on the Java 1.6 CI commit builds"
+ (JavaVersion.current().java7Compatible || !GradleContextualExecuter.embedded) })
def "can use java6 client with later build runtime"() {
given:
executer
.withJavaHome(java6().javaHome)
.withArgument("-Dorg.gradle.java.home=${java7OrBetter().javaHome}")
+ .useDefaultBuildJvmArgs()
+ .requireGradleHome()
file("a").text = "foo"
buildScript """
task a {
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/jdk7/SymlinkContinuousIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/jdk7/SymlinkContinuousIntegrationTest.groovy
index 66248b6..98ac0f1 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/jdk7/SymlinkContinuousIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/jdk7/SymlinkContinuousIntegrationTest.groovy
@@ -62,6 +62,9 @@ class SymlinkContinuousIntegrationTest extends Java7RequiringContinuousIntegrati
sourceFile.text = "changed"
then:
noBuildTriggered()
+
+ cleanup:
+ assert symlink.delete()
}
def "can use symlinked directory for input"() {
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonHealthLoggingIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonHealthLoggingIntegrationTest.groovy
index 39e6e16..94bf220 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonHealthLoggingIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonHealthLoggingIntegrationTest.groovy
@@ -21,8 +21,11 @@ import org.gradle.integtests.fixtures.daemon.DaemonIntegrationSpec
class DaemonHealthLoggingIntegrationTest extends DaemonIntegrationSpec {
def "health information is present in build log"() {
- file("gradle.properties") << "org.gradle.jvmargs=-Dorg.gradle.daemon.performance.logging=true"
- when: def r = executer.noExtraLogging().run()
- then: r.output.contains("Starting build in new daemon [memory: ")
+ when:
+ executer.withBuildJvmOpts("-Dorg.gradle.daemon.performance.logging=true")
+ def r = executer.noExtraLogging().run()
+
+ then:
+ r.output.contains("Starting build in new daemon [memory: ")
}
}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonJvmSettingsIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonJvmSettingsIntegrationTest.groovy
new file mode 100644
index 0000000..d6167c9
--- /dev/null
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonJvmSettingsIntegrationTest.groovy
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.launcher.daemon
+
+import org.gradle.integtests.fixtures.daemon.DaemonIntegrationSpec
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+
+ at Requires(TestPrecondition.NOT_UNKNOWN_OS)
+class DaemonJvmSettingsIntegrationTest extends DaemonIntegrationSpec {
+ def "uses current JVM and default JVM args when none specified"() {
+ file('build.gradle') << """
+assert java.lang.management.ManagementFactory.runtimeMXBean.inputArguments.contains('-Xmx1024m')
+assert java.lang.management.ManagementFactory.runtimeMXBean.inputArguments.contains('-XX:+HeapDumpOnOutOfMemoryError')
+"""
+
+ given:
+ executer.useDefaultBuildJvmArgs()
+
+ expect:
+ succeeds()
+ }
+}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonLifecycleSpec.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonLifecycleSpec.groovy
index 3cc3038..5b8d338 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonLifecycleSpec.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonLifecycleSpec.groovy
@@ -47,7 +47,7 @@ class DaemonLifecycleSpec extends DaemonIntegrationSpec {
// set this to change the java home used to launch any gradle, set back to null to use current JVM
def javaHome = null
-
+
// set this to change the desired default encoding for the build request
def buildEncoding = null
@@ -110,10 +110,6 @@ class DaemonLifecycleSpec extends DaemonIntegrationSpec {
}
}
- @Override
- protected void cleanupWhileTestFilesExist() {
- }
-
void stopDaemons() {
run { stopDaemonsNow() }
}
@@ -320,14 +316,14 @@ class DaemonLifecycleSpec extends DaemonIntegrationSpec {
then:
completeBuild(1)
-
+
then:
idle 2
daemonContext(1) {
assert daemonOpts.contains("-Dfile.encoding=UTF-8")
}
}
-
+
def cleanup() {
try {
def registry = new DaemonLogsAnalyzer(executer.daemonBaseDir).registry
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonOutputToggleIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonOutputToggleIntegrationTest.groovy
index 00832b5..c61ddf5 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonOutputToggleIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonOutputToggleIntegrationTest.groovy
@@ -23,18 +23,21 @@ class DaemonOutputToggleIntegrationTest extends DaemonIntegrationSpec {
def "output is received when toggle is off"() {
when:
+ executer.noExtraLogging()
run "help"
then:
- !result.output.empty
+ result.output.contains(":help")
+ result.output.contains("BUILD SUCCESSFUL")
}
def "output is not received when toggle is on"() {
when:
- executer.withArgument("-D$LogToClient.DISABLE_OUTPUT=true").noExtraLogging()
+ executer.withBuildJvmOpts("-D$LogToClient.DISABLE_OUTPUT=true").noExtraLogging()
run "help"
then:
- result.output.empty
+ !result.output.contains(":help")
+ !result.output.contains("BUILD SUCCESSFUL")
}
}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonPerformanceMonitoringIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonPerformanceMonitoringIntegrationTest.groovy
index 2682f05..b068a11 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonPerformanceMonitoringIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonPerformanceMonitoringIntegrationTest.groovy
@@ -20,15 +20,8 @@ package org.gradle.launcher.daemon
import org.gradle.integtests.fixtures.daemon.DaemonIntegrationSpec
import org.gradle.launcher.daemon.server.health.DaemonStatus
-import org.gradle.test.fixtures.file.LeaksFileHandles
- at LeaksFileHandles
class DaemonPerformanceMonitoringIntegrationTest extends DaemonIntegrationSpec {
-
- def setup() {
- executer.withGradleOpts("-D${DaemonStatus.EXPIRE_AT_PROPERTY}=80")
- }
-
def "when build leaks more than available memory the daemon is expired eagerly"() {
expect:
daemonIsExpiredEagerly("-Xmx30m")
@@ -40,12 +33,11 @@ class DaemonPerformanceMonitoringIntegrationTest extends DaemonIntegrationSpec {
}
private boolean daemonIsExpiredEagerly(String xmx) {
- file("gradle.properties") << ("org.gradle.jvmargs=$xmx"
- + " -Dorg.gradle.daemon.performance.logging=true")
-
setupLeakyBuild()
int newDaemons = 0
for (int i = 0; i < 10; i++) {
+ executer.noExtraLogging()
+ executer.withBuildJvmOpts("-D${DaemonStatus.EXPIRE_AT_PROPERTY}=80", xmx, "-Dorg.gradle.daemon.performance.logging=true")
def r = run()
if (r.output.contains("Starting build in new daemon [memory: ")) {
newDaemons++;
@@ -58,7 +50,6 @@ class DaemonPerformanceMonitoringIntegrationTest extends DaemonIntegrationSpec {
}
private void setupLeakyBuild() {
- executer.noExtraLogging()
buildFile << """
class State {
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonReuseIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonReuseIntegrationTest.groovy
index 28a0141..2662e9e 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonReuseIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonReuseIntegrationTest.groovy
@@ -22,7 +22,6 @@ class DaemonReuseIntegrationTest extends DaemonIntegrationSpec {
def "idle daemon is reused in preference to starting a new daemon"() {
given:
- executer.requireIsolatedDaemons()
executer.run()
daemons.daemon.assertIdle()
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonStartupMessageIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonStartupMessageIntegrationTest.groovy
index 840d2be..e5d24d3 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonStartupMessageIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonStartupMessageIntegrationTest.groovy
@@ -19,8 +19,6 @@ package org.gradle.launcher.daemon
import org.gradle.integtests.fixtures.daemon.DaemonIntegrationSpec
import org.gradle.launcher.daemon.client.DefaultDaemonConnector
-import static org.gradle.launcher.daemon.client.DefaultDaemonConnector.DISABLE_STARTING_DAEMON_MESSAGE_PROPERTY
-
class DaemonStartupMessageIntegrationTest extends DaemonIntegrationSpec {
def setup() {
@@ -32,12 +30,7 @@ class DaemonStartupMessageIntegrationTest extends DaemonIntegrationSpec {
succeeds()
then:
- output.contains DefaultDaemonConnector.STARTING_DAEMON_MESSAGE
- }
-
- def "the message is not shown when quiet log level is requested"() {
- given:
- executer.withArgument("-q")
+ output.contains(DefaultDaemonConnector.STARTING_DAEMON_MESSAGE)
when:
succeeds()
@@ -46,9 +39,9 @@ class DaemonStartupMessageIntegrationTest extends DaemonIntegrationSpec {
!output.contains(DefaultDaemonConnector.STARTING_DAEMON_MESSAGE)
}
- def "daemon starting message can be disabled"() {
+ def "the message is not shown when quiet log level is requested"() {
given:
- executer.withGradleOpts("-D${DISABLE_STARTING_DAEMON_MESSAGE_PROPERTY}=true")
+ executer.withArgument("-q")
when:
succeeds()
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonSystemPropertiesIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonSystemPropertiesIntegrationTest.groovy
index 5800f3f..bfdb56a 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonSystemPropertiesIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/DaemonSystemPropertiesIntegrationTest.groovy
@@ -32,7 +32,7 @@ task verify << {
"""
expect:
- executer.withGradleOpts("-Djava.vendor=hollywood", "-Dsun.sunny=california").withTasks("verify").run()
+ executer.withBuildJvmOpts("-Djava.vendor=hollywood", "-Dsun.sunny=california").withTasks("verify").run()
}
def "other client JVM system properties are carried over to daemon JVM"() {
@@ -44,7 +44,7 @@ task verify << {
"""
expect:
- executer.withGradleOpts("-Dfoo.bar=baz").withTasks("verify").run()
+ executer.withBuildJvmOpts("-Dfoo.bar=baz").withTasks("verify").run()
}
}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/IsolatedDaemonSpec.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/IsolatedDaemonSpec.groovy
deleted file mode 100644
index 51919de..0000000
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/IsolatedDaemonSpec.groovy
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.launcher.daemon
-
-import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.integtests.fixtures.daemon.DaemonLogsAnalyzer
-import org.gradle.integtests.fixtures.daemon.DaemonsFixture
-
-abstract class IsolatedDaemonSpec extends AbstractIntegrationSpec {
-
- def setup() {
- executer.requireIsolatedDaemons()
- }
-
- @Override
- protected void cleanupWhileTestFilesExist() {
- daemons.killAll()
- }
-
- DaemonsFixture getDaemons() {
- new DaemonLogsAnalyzer(executer.daemonBaseDir)
- }
-}
\ No newline at end of file
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/SingleUseDaemonIntegrationTest.groovy b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/SingleUseDaemonIntegrationTest.groovy
index 8a9b835..686c704 100644
--- a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/SingleUseDaemonIntegrationTest.groovy
+++ b/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/daemon/SingleUseDaemonIntegrationTest.groovy
@@ -18,10 +18,10 @@ package org.gradle.launcher.daemon
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.AvailableJavaHomes
+import org.gradle.integtests.fixtures.daemon.DaemonLogsAnalyzer
import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
import org.gradle.launcher.daemon.client.DefaultDaemonConnector
import org.gradle.launcher.daemon.client.SingleUseDaemonClient
-import org.gradle.integtests.fixtures.daemon.DaemonLogsAnalyzer
import org.gradle.util.GradleVersion
import spock.lang.IgnoreIf
@@ -37,7 +37,7 @@ class SingleUseDaemonIntegrationTest extends AbstractIntegrationSpec {
executer.requireIsolatedDaemons()
}
- def "stops single use daemon on build complete"() {
+ def "forks build when JVM args are requested"() {
requireJvmArg('-Xmx32m')
file('build.gradle') << "println 'hello world'"
@@ -69,7 +69,28 @@ class SingleUseDaemonIntegrationTest extends AbstractIntegrationSpec {
}
@IgnoreIf({ AvailableJavaHomes.differentJdk == null })
- def "does not fork build if java home from gradle properties matches current process"() {
+ def "forks build with default daemon JVM args when java home from gradle properties does not match current process"() {
+ def javaHome = AvailableJavaHomes.differentJdk.javaHome.canonicalFile
+
+ file('gradle.properties').writeProperties("org.gradle.java.home": javaHome.path)
+
+ file('build.gradle') << """
+println 'javaHome=' + org.gradle.internal.jvm.Jvm.current().javaHome.absolutePath
+assert java.lang.management.ManagementFactory.runtimeMXBean.inputArguments.contains('-Xmx1024m')
+assert java.lang.management.ManagementFactory.runtimeMXBean.inputArguments.contains('-XX:+HeapDumpOnOutOfMemoryError')
+"""
+
+ when:
+ succeeds()
+
+ then:
+ wasForked()
+ output.contains("javaHome=${javaHome}")
+ daemons.daemon.stops()
+ }
+
+ @IgnoreIf({ AvailableJavaHomes.differentJdk == null })
+ def "does not fork build when java home from gradle properties matches current process"() {
def javaHome = AvailableJavaHomes.differentJdk.javaHome
file('gradle.properties').writeProperties("org.gradle.java.home": javaHome.canonicalPath)
@@ -99,9 +120,10 @@ assert java.lang.management.ManagementFactory.runtimeMXBean.inputArguments.conta
and:
wasForked()
+ daemons.daemon.stops()
}
- def "does not fork build and configures system properties from gradle properties"() {
+ def "does not fork build when only mutable system properties requested in gradle properties"() {
when:
requireJvmArg('-Dsome-prop=some-value')
@@ -130,7 +152,7 @@ assert System.getProperty('some-prop') == 'some-value'
failure.assertHasDescription("Gradle ${GradleVersion.current().version} requires Java 6 or later to run. Your build is currently configured to use Java 5.")
}
- def "single use daemon is not used if immutable system property is set on command line with non different value"() {
+ def "does not fork build when immutable system property is set on command line with same value as current JVM"() {
def encoding = Charset.defaultCharset().name()
given:
@@ -158,6 +180,8 @@ assert System.getProperty('some-prop') == 'some-value'
then:
!output.contains(DaemonUsageSuggestionIntegrationTest.DAEMON_USAGE_SUGGESTION_MESSAGE)
+ wasForked()
+ daemons.daemon.stops()
}
def "does not print daemon startup message for a single use daemon"() {
@@ -169,6 +193,8 @@ assert System.getProperty('some-prop') == 'some-value'
then:
!output.contains(DefaultDaemonConnector.STARTING_DAEMON_MESSAGE)
+ wasForked()
+ daemons.daemon.stops()
}
private def requireJvmArg(String jvmArg) {
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/cli/BuildActionsFactory.java b/subprojects/launcher/src/main/java/org/gradle/launcher/cli/BuildActionsFactory.java
index 7e796ed..203ed70 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/cli/BuildActionsFactory.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/cli/BuildActionsFactory.java
@@ -28,10 +28,7 @@ import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.service.ServiceRegistryBuilder;
import org.gradle.internal.service.scopes.GlobalScopeServices;
import org.gradle.launcher.daemon.bootstrap.ForegroundDaemonAction;
-import org.gradle.launcher.daemon.client.DaemonClient;
-import org.gradle.launcher.daemon.client.DaemonClientFactory;
-import org.gradle.launcher.daemon.client.DaemonClientGlobalServices;
-import org.gradle.launcher.daemon.client.DaemonStopClient;
+import org.gradle.launcher.daemon.client.*;
import org.gradle.launcher.daemon.configuration.CurrentProcess;
import org.gradle.launcher.daemon.configuration.DaemonParameters;
import org.gradle.launcher.daemon.configuration.ForegroundDaemonConfiguration;
@@ -56,6 +53,7 @@ class BuildActionsFactory implements CommandLineAction {
public Runnable createAction(CommandLineParser parser, ParsedCommandLine commandLine) {
Parameters parameters = parametersConverter.convert(commandLine, new Parameters());
+ parameters.getDaemonParameters().applyDefaultsFor(new JvmVersionDetector().getJavaVersion(parameters.getDaemonParameters().getEffectiveJvm()));
if (parameters.getDaemonParameters().isStop()) {
return stopAllDaemons(parameters.getDaemonParameters(), loggingServices);
@@ -88,7 +86,7 @@ class BuildActionsFactory implements CommandLineAction {
ServiceRegistry clientSharedServices = createGlobalClientServices();
ServiceRegistry clientServices = clientSharedServices.get(DaemonClientFactory.class).createBuildClientServices(loggingServices.get(OutputEventListener.class), daemonParameters, System.in);
DaemonClient client = clientServices.get(DaemonClient.class);
- return runBuild(startParameter, daemonParameters, client);
+ return runBuild(startParameter, daemonParameters, client, clientSharedServices);
}
private boolean canUseCurrentProcess(DaemonParameters requiredBuildParameters) {
@@ -109,7 +107,7 @@ class BuildActionsFactory implements CommandLineAction {
DocumentationRegistry documentationRegistry = globalServices.get(DocumentationRegistry.class);
DaemonUsageSuggestingBuildActionExecuter daemonUsageSuggestingExecuter = new DaemonUsageSuggestingBuildActionExecuter(executer, textOutputFactory, documentationRegistry);
- return runBuild(startParameter, daemonParameters, daemonUsageSuggestingExecuter);
+ return runBuild(startParameter, daemonParameters, daemonUsageSuggestingExecuter, globalServices);
}
private Runnable runBuildInSingleUseDaemon(StartParameter startParameter, DaemonParameters daemonParameters, ServiceRegistry loggingServices) {
@@ -126,7 +124,7 @@ class BuildActionsFactory implements CommandLineAction {
ServiceRegistry clientSharedServices = createGlobalClientServices();
ServiceRegistry clientServices = clientSharedServices.get(DaemonClientFactory.class).createSingleUseDaemonClientServices(loggingServices.get(OutputEventListener.class), daemonParameters, System.in);
DaemonClient client = clientServices.get(DaemonClient.class);
- return runBuild(startParameter, daemonParameters, client);
+ return runBuild(startParameter, daemonParameters, client, clientSharedServices);
}
private ServiceRegistry createGlobalClientServices() {
@@ -138,14 +136,14 @@ class BuildActionsFactory implements CommandLineAction {
.build();
}
- private Runnable runBuild(StartParameter startParameter, DaemonParameters daemonParameters, BuildActionExecuter<BuildActionParameters> executer) {
+ private Runnable runBuild(StartParameter startParameter, DaemonParameters daemonParameters, BuildActionExecuter<BuildActionParameters> executer, ServiceRegistry sharedServices) {
BuildActionParameters parameters = new DefaultBuildActionParameters(
daemonParameters.getEffectiveSystemProperties(),
System.getenv(),
SystemProperties.getInstance().getCurrentDir(),
startParameter.getLogLevel(),
daemonParameters.getDaemonUsage(), startParameter.isContinuous(), daemonParameters.isInteractive());
- return new RunBuildAction(executer, startParameter, clientMetaData(), getBuildStartTime(), parameters);
+ return new RunBuildAction(executer, startParameter, clientMetaData(), getBuildStartTime(), parameters, sharedServices);
}
private long getBuildStartTime() {
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/cli/RunBuildAction.java b/subprojects/launcher/src/main/java/org/gradle/launcher/cli/RunBuildAction.java
index b345ae0..43c1264 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/cli/RunBuildAction.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/cli/RunBuildAction.java
@@ -17,6 +17,7 @@ package org.gradle.launcher.cli;
import org.gradle.StartParameter;
import org.gradle.initialization.*;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.exec.BuildActionExecuter;
import org.gradle.launcher.exec.BuildActionParameters;
@@ -26,20 +27,23 @@ public class RunBuildAction implements Runnable {
private final BuildClientMetaData clientMetaData;
private final long startTime;
private final BuildActionParameters buildActionParameters;
+ private final ServiceRegistry sharedServices;
public RunBuildAction(BuildActionExecuter<BuildActionParameters> executer, StartParameter startParameter, BuildClientMetaData clientMetaData, long startTime,
- BuildActionParameters buildActionParameters) {
+ BuildActionParameters buildActionParameters, ServiceRegistry sharedServices) {
this.executer = executer;
this.startParameter = startParameter;
this.clientMetaData = clientMetaData;
this.startTime = startTime;
this.buildActionParameters = buildActionParameters;
+ this.sharedServices = sharedServices;
}
public void run() {
executer.execute(
new ExecuteBuildAction(startParameter),
new DefaultBuildRequestContext(new DefaultBuildRequestMetaData(clientMetaData, startTime), new DefaultBuildCancellationToken(), new NoOpBuildEventConsumer()),
- buildActionParameters);
+ buildActionParameters,
+ sharedServices);
}
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverter.java b/subprojects/launcher/src/main/java/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverter.java
index e4b55e4..a555abe 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverter.java
@@ -18,6 +18,7 @@ package org.gradle.launcher.cli.converter;
import org.gradle.api.GradleException;
import org.gradle.internal.jvm.JavaHomeException;
+import org.gradle.internal.jvm.JavaInfo;
import org.gradle.internal.jvm.Jvm;
import org.gradle.launcher.daemon.configuration.DaemonParameters;
import org.gradle.process.internal.JvmOptions;
@@ -49,12 +50,13 @@ public class PropertiesToDaemonParametersConverter {
if (!javaHome.isDirectory()) {
throw new GradleException(String.format("Java home supplied via '%s' is invalid. Invalid directory: %s", JAVA_HOME_PROPERTY, prop));
}
+ JavaInfo jvm;
try {
- Jvm.forHome(javaHome);
+ jvm = Jvm.forHome(javaHome);
} catch (JavaHomeException e) {
throw new GradleException(String.format("Java home supplied via '%s' seems to be invalid: %s", JAVA_HOME_PROPERTY, prop));
}
- target.setJavaHome(javaHome);
+ target.setJvm(jvm);
}
prop = properties.get(DAEMON_BASE_DIR_PROPERTY);
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/DaemonMain.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/DaemonMain.java
index 8e861f3..607471a 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/DaemonMain.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/DaemonMain.java
@@ -20,6 +20,7 @@ import org.gradle.api.UncheckedIOException;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
+import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.internal.nativeintegration.services.NativeServices;
import org.gradle.internal.serialize.kryo.KryoBackedDecoder;
import org.gradle.launcher.bootstrap.EntryPoint;
@@ -68,6 +69,7 @@ public class DaemonMain extends EntryPoint {
File daemonBaseDir;
int idleTimeoutMs;
String daemonUid;
+ List<File> additionalClassPath;
KryoBackedDecoder decoder = new KryoBackedDecoder(new EncodedStream.EncodedInput(System.in));
try {
@@ -80,6 +82,11 @@ public class DaemonMain extends EntryPoint {
for (int i = 0; i < argCount; i++) {
startupOpts.add(decoder.readString());
}
+ int additionalClassPathLength = decoder.readSmallInt();
+ additionalClassPath = new ArrayList<File>(additionalClassPathLength);
+ for (int i = 0; i < additionalClassPathLength; i++) {
+ additionalClassPath.add(new File(decoder.readString()));
+ }
} catch (EOFException e) {
throw new UncheckedIOException(e);
}
@@ -90,7 +97,7 @@ public class DaemonMain extends EntryPoint {
DaemonServerConfiguration parameters = new DefaultDaemonServerConfiguration(daemonUid, daemonBaseDir, idleTimeoutMs, startupOpts);
LoggingServiceRegistry loggingRegistry = LoggingServiceRegistry.newCommandLineProcessLogging();
LoggingManagerInternal loggingManager = loggingRegistry.newInstance(LoggingManagerInternal.class);
- DaemonServices daemonServices = new DaemonServices(parameters, loggingRegistry, loggingManager);
+ DaemonServices daemonServices = new DaemonServices(parameters, loggingRegistry, loggingManager, new DefaultClassPath(additionalClassPath));
File daemonLog = daemonServices.getDaemonLogFile();
initialiseLogging(loggingManager, daemonLog);
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/ForegroundDaemonAction.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/ForegroundDaemonAction.java
index 94d2ce3..0f4f399 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/ForegroundDaemonAction.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/bootstrap/ForegroundDaemonAction.java
@@ -15,6 +15,7 @@
*/
package org.gradle.launcher.daemon.bootstrap;
+import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.daemon.configuration.DaemonServerConfiguration;
import org.gradle.launcher.daemon.registry.DaemonRegistry;
@@ -38,7 +39,7 @@ public class ForegroundDaemonAction implements Runnable {
LoggingManagerInternal loggingManager = loggingRegistry.newInstance(LoggingManagerInternal.class);
loggingManager.start();
- DaemonServices daemonServices = new DaemonServices(configuration, loggingRegistry, loggingManager);
+ DaemonServices daemonServices = new DaemonServices(configuration, loggingRegistry, loggingManager, new DefaultClassPath());
Daemon daemon = daemonServices.get(Daemon.class);
daemon.start();
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClient.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClient.java
index ea5f668..70d8da6 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClient.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClient.java
@@ -15,6 +15,7 @@
*/
package org.gradle.launcher.daemon.client;
+import com.google.common.collect.Lists;
import org.gradle.api.BuildCancelledException;
import org.gradle.api.internal.specs.ExplainingSpec;
import org.gradle.api.logging.Logger;
@@ -27,17 +28,18 @@ import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.id.IdGenerator;
import org.gradle.internal.invocation.BuildAction;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.daemon.context.DaemonContext;
import org.gradle.launcher.daemon.diagnostics.DaemonDiagnostics;
import org.gradle.launcher.daemon.protocol.*;
import org.gradle.launcher.daemon.server.api.DaemonStoppedException;
import org.gradle.launcher.exec.BuildActionExecuter;
import org.gradle.launcher.exec.BuildActionParameters;
-import org.gradle.logging.internal.OutputEvent;
import org.gradle.logging.internal.OutputEventListener;
import org.gradle.messaging.remote.internal.Connection;
import java.io.InputStream;
+import java.util.List;
/**
* The client piece of the build daemon.
@@ -48,7 +50,8 @@ import java.io.InputStream;
* <li>The client creates a connection to daemon.</li>
* <li>The client sends exactly one {@link Build} message.</li>
* <li>The daemon sends exactly one {@link BuildStarted}, {@link Failure} or {@link DaemonUnavailable} message.</li>
- * <li>If the build is started, the daemon may send zero or more {@link OutputEvent} messages.</li>
+ * <li>If the build is started, the daemon may send zero or more {@link OutputMessage} messages.</li>
+ * <li>If the build is started, the daemon may send zero or more {@link BuildEvent} messages.</li>
* <li>If the build is started, the client may send zero or more {@link ForwardInput} messages followed by exactly one {@link CloseInput} message.</li>
* <li>If the build is started, the client may send {@link org.gradle.launcher.daemon.protocol.Cancel} message before {@link CloseInput} message.</li>
* <li>The daemon sends exactly one {@link Result} message. It may no longer send any messages.</li>
@@ -109,24 +112,29 @@ public class DaemonClient implements BuildActionExecuter<BuildActionParameters>
* @param action The action
* @throws org.gradle.initialization.ReportedException On failure, when the failure has already been logged/reported.
*/
- public Object execute(BuildAction action, BuildRequestContext requestContext, BuildActionParameters parameters) {
+ public Object execute(BuildAction action, BuildRequestContext requestContext, BuildActionParameters parameters, ServiceRegistry contextServices) {
Object buildId = idGenerator.generateId();
Build build = new Build(buildId, action, requestContext.getClient(), requestContext.getBuildTimeClock().getStartTime(), parameters);
+ List<DaemonInitialConnectException> accumulatedExceptions = Lists.newArrayList();
+
int saneNumberOfAttempts = 100; //is it sane enough?
+
for (int i = 1; i < saneNumberOfAttempts; i++) {
final DaemonClientConnection connection = connector.connect(compatibilitySpec);
try {
return executeBuild(build, connection, requestContext.getCancellationToken(), requestContext.getEventConsumer());
} catch (DaemonInitialConnectException e) {
- //this exception means that we want to try again.
- LOGGER.info(e.getMessage() + " Trying a different daemon...");
+ // this exception means that we want to try again.
+ LOGGER.debug("{}, Trying a different daemon...", e.getMessage());
+ accumulatedExceptions.add(e);
} finally {
connection.stop();
}
}
- //TODO it would be nice if below includes the errors that were accumulated above.
+
throw new NoUsableDaemonFoundException("Unable to find a usable idle daemon. I have connected to "
- + saneNumberOfAttempts + " different daemons but I could not use any of them to run build: " + build + ".");
+ + saneNumberOfAttempts + " different daemons but I could not use any of them to run build: " + build
+ + ". BuildActionParameters were " + parameters + ".", accumulatedExceptions);
}
protected Object executeBuild(Build build, DaemonClientConnection connection, BuildCancellationToken cancellationToken, BuildEventConsumer buildEventConsumer) throws DaemonInitialConnectException {
@@ -141,21 +149,24 @@ public class DaemonClient implements BuildActionExecuter<BuildActionParameters>
//However, since we haven't yet started running the build, we can recover by just trying again...
throw new DaemonInitialConnectException("Connected to a stale daemon address.", e);
}
+
if (result == null) {
throw new DaemonInitialConnectException("The first result from the daemon was empty. Most likely the process died immediately after connection.");
}
+ LOGGER.info("Received result {} from daemon {} (build should be starting).", result, connection.getDaemon());
+
+ DaemonDiagnostics diagnostics = null;
if (result instanceof BuildStarted) {
- DaemonDiagnostics diagnostics = ((BuildStarted) result).getDiagnostics();
+ diagnostics = ((BuildStarted) result).getDiagnostics();
result = monitorBuild(build, diagnostics, connection, cancellationToken, buildEventConsumer);
}
- LOGGER.info("Received result {} from daemon {}.", result, connection.getDaemon());
+ LOGGER.info("Received result {} from daemon {} (build should be done).", result, connection.getDaemon());
connection.dispatch(new Finished());
if (result instanceof Failure) {
- // Could potentially distinguish between CommandFailure and DaemonFailure here.
Throwable failure = ((Failure) result).getValue();
if (failure instanceof DaemonStoppedException && cancellationToken.isCancellationRequested()) {
LOGGER.error("Daemon was stopped to handle build cancel request.");
@@ -167,12 +178,12 @@ public class DaemonClient implements BuildActionExecuter<BuildActionParameters>
} else if (result instanceof Result) {
return ((Result) result).getValue();
} else {
- throw invalidResponse(result, build);
+ throw invalidResponse(result, build, diagnostics);
}
}
- private Object monitorBuild(Build build, DaemonDiagnostics diagnostics, Connection<Object> connection, BuildCancellationToken cancellationToken, BuildEventConsumer buildEventConsumer) {
- DaemonClientInputForwarder inputForwarder = new DaemonClientInputForwarder(buildStandardInput, connection, executorFactory, idGenerator);
+ private Object monitorBuild(Build build, DaemonDiagnostics diagnostics, Connection<Message> connection, BuildCancellationToken cancellationToken, BuildEventConsumer buildEventConsumer) {
+ DaemonClientInputForwarder inputForwarder = new DaemonClientInputForwarder(buildStandardInput, connection, executorFactory);
DaemonCancelForwarder cancelForwarder = new DaemonCancelForwarder(connection, cancellationToken, idGenerator);
try {
cancelForwarder.start();
@@ -180,13 +191,13 @@ public class DaemonClient implements BuildActionExecuter<BuildActionParameters>
int objectsReceived = 0;
while (true) {
- Object object = connection.receive();
+ Message object = connection.receive();
LOGGER.trace("Received object #{}, type: {}", objectsReceived++, object == null ? null : object.getClass().getName());
if (object == null) {
return handleDaemonDisappearance(build, diagnostics);
- } else if (object instanceof OutputEvent) {
- outputEventListener.onOutput((OutputEvent) object);
+ } else if (object instanceof OutputMessage) {
+ outputEventListener.onOutput(((OutputMessage) object).getEvent());
} else if (object instanceof BuildEvent) {
buildEventConsumer.dispatch(((BuildEvent)object).getPayload());
} else {
@@ -211,10 +222,10 @@ public class DaemonClient implements BuildActionExecuter<BuildActionParameters>
throw new DaemonDisappearedException();
}
- private IllegalStateException invalidResponse(Object response, Build command) {
- //TODO diagnostics could be included in the exception (they might be available).
+ private IllegalStateException invalidResponse(Object response, Build command, DaemonDiagnostics diagnostics) {
+ String diagnosticsMessage = diagnostics==null ? "No diagnostics available." : diagnostics.describe();
return new IllegalStateException(String.format(
- "Received invalid response from the daemon: '%s' is a result of a type we don't have a strategy to handle."
- + "Earlier, '%s' request was sent to the daemon.", response, command));
+ "Received invalid response from the daemon: '%s' is a result of a type we don't have a strategy to handle. "
+ + "Earlier, '%s' request was sent to the daemon. Diagnostics:\n%s", response, command, diagnosticsMessage));
}
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientConnection.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientConnection.java
index 5f1af51..912d96b 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientConnection.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientConnection.java
@@ -19,6 +19,7 @@ import org.gradle.api.Nullable;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.launcher.daemon.context.DaemonInstanceDetails;
+import org.gradle.launcher.daemon.protocol.Message;
import org.gradle.messaging.remote.internal.Connection;
import org.gradle.messaging.remote.internal.MessageIOException;
import org.gradle.messaging.remote.internal.RemoteConnection;
@@ -31,15 +32,15 @@ import java.util.concurrent.locks.ReentrantLock;
*
* <p>Currently, dispatch is thread safe, and receive is not.
*/
-public class DaemonClientConnection implements Connection<Object> {
+public class DaemonClientConnection implements Connection<Message> {
private final static Logger LOG = Logging.getLogger(DaemonClientConnection.class);
- private final RemoteConnection<Object> connection;
+ private final RemoteConnection<Message> connection;
private final DaemonInstanceDetails daemon;
private final StaleAddressDetector staleAddressDetector;
private boolean hasReceived;
private final Lock dispatchLock = new ReentrantLock();
- public DaemonClientConnection(RemoteConnection<Object> connection, DaemonInstanceDetails daemon, StaleAddressDetector staleAddressDetector) {
+ public DaemonClientConnection(RemoteConnection<Message> connection, DaemonInstanceDetails daemon, StaleAddressDetector staleAddressDetector) {
this.connection = connection;
this.daemon = daemon;
this.staleAddressDetector = staleAddressDetector;
@@ -54,7 +55,7 @@ public class DaemonClientConnection implements Connection<Object> {
return daemon;
}
- public void dispatch(Object message) throws DaemonConnectionException {
+ public void dispatch(Message message) throws DaemonConnectionException {
LOG.debug("thread {}: dispatching {}", Thread.currentThread().getId(), message.getClass());
try {
dispatchLock.lock();
@@ -73,7 +74,7 @@ public class DaemonClientConnection implements Connection<Object> {
}
@Nullable
- public Object receive() throws DaemonConnectionException {
+ public Message receive() throws DaemonConnectionException {
try {
return connection.receive();
} catch (MessageIOException e) {
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientGlobalServices.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientGlobalServices.java
index 4ad35b5..f3eb650 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientGlobalServices.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientGlobalServices.java
@@ -16,12 +16,26 @@
package org.gradle.launcher.daemon.client;
+import org.gradle.api.internal.DocumentationRegistry;
import org.gradle.internal.service.ServiceRegistry;
+import org.gradle.launcher.daemon.bootstrap.DaemonGreeter;
/**
* Global services shared by all Gradle daemon clients in a given process.
*/
public class DaemonClientGlobalServices {
+ JvmVersionDetector createJvmVersionDetector() {
+ return new JvmVersionDetector();
+ }
+
+ JvmVersionValidator createJvmVersionValidator(JvmVersionDetector jvmVersionDetector) {
+ return new JvmVersionValidator(jvmVersionDetector);
+ }
+
+ DaemonGreeter createDaemonGreeter(DocumentationRegistry documentationRegistry) {
+ return new DaemonGreeter(documentationRegistry);
+ }
+
DaemonClientFactory createClientFactory(ServiceRegistry sharedServices) {
return new DaemonClientFactory(sharedServices);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientInputForwarder.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientInputForwarder.java
index 25fe7d0..7aacf0a 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientInputForwarder.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientInputForwarder.java
@@ -20,11 +20,10 @@ import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.concurrent.Stoppable;
-import org.gradle.internal.id.IdGenerator;
import org.gradle.internal.io.TextStream;
import org.gradle.launcher.daemon.protocol.CloseInput;
import org.gradle.launcher.daemon.protocol.ForwardInput;
-import org.gradle.launcher.daemon.protocol.IoCommand;
+import org.gradle.launcher.daemon.protocol.InputMessage;
import org.gradle.messaging.dispatch.Dispatch;
import java.io.InputStream;
@@ -40,14 +39,14 @@ public class DaemonClientInputForwarder implements Stoppable {
public static final int DEFAULT_BUFFER_SIZE = 1024;
private final InputForwarder forwarder;
- public DaemonClientInputForwarder(InputStream inputStream, Dispatch<? super IoCommand> dispatch,
- ExecutorFactory executorFactory, IdGenerator<?> idGenerator) {
- this(inputStream, dispatch, executorFactory, idGenerator, DEFAULT_BUFFER_SIZE);
+ public DaemonClientInputForwarder(InputStream inputStream, Dispatch<? super InputMessage> dispatch,
+ ExecutorFactory executorFactory) {
+ this(inputStream, dispatch, executorFactory, DEFAULT_BUFFER_SIZE);
}
- public DaemonClientInputForwarder(InputStream inputStream, Dispatch<? super IoCommand> dispatch,
- ExecutorFactory executorFactory, IdGenerator<?> idGenerator, int bufferSize) {
- TextStream handler = new ForwardTextStreamToConnection(dispatch, idGenerator);
+ public DaemonClientInputForwarder(InputStream inputStream, Dispatch<? super InputMessage> dispatch,
+ ExecutorFactory executorFactory, int bufferSize) {
+ TextStream handler = new ForwardTextStreamToConnection(dispatch);
forwarder = new InputForwarder(inputStream, handler, executorFactory, bufferSize);
}
@@ -60,23 +59,21 @@ public class DaemonClientInputForwarder implements Stoppable {
}
private static class ForwardTextStreamToConnection implements TextStream {
- private final Dispatch<? super IoCommand> dispatch;
- private final IdGenerator<?> idGenerator;
+ private final Dispatch<? super InputMessage> dispatch;
- public ForwardTextStreamToConnection(Dispatch<? super IoCommand> dispatch, IdGenerator<?> idGenerator) {
+ public ForwardTextStreamToConnection(Dispatch<? super InputMessage> dispatch) {
this.dispatch = dispatch;
- this.idGenerator = idGenerator;
}
public void text(String input) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Forwarding input to daemon: '{}'", input.replace("\n", "\\n"));
}
- dispatch.dispatch(new ForwardInput(idGenerator.generateId(), input.getBytes()));
+ dispatch.dispatch(new ForwardInput(input.getBytes()));
}
public void endOfStream(@Nullable Throwable failure) {
- CloseInput message = new CloseInput(idGenerator.generateId());
+ CloseInput message = new CloseInput();
LOGGER.debug("Dispatching close input message: {}", message);
dispatch.dispatch(message);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientServices.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientServices.java
index eb115ff..7f03d89 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientServices.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonClientServices.java
@@ -15,14 +15,13 @@
*/
package org.gradle.launcher.daemon.client;
-import org.gradle.api.internal.DocumentationRegistry;
+import org.gradle.internal.event.ListenerManager;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.daemon.bootstrap.DaemonGreeter;
import org.gradle.launcher.daemon.configuration.DaemonParameters;
import org.gradle.launcher.daemon.context.DaemonContextBuilder;
import org.gradle.launcher.daemon.registry.DaemonDir;
import org.gradle.launcher.daemon.registry.DaemonRegistryServices;
-import org.gradle.internal.event.ListenerManager;
import java.io.InputStream;
@@ -38,18 +37,10 @@ public class DaemonClientServices extends DaemonClientServicesSupport {
addProvider(new DaemonRegistryServices(daemonParameters.getBaseDir()));
}
- JvmVersionValidator createJvmVersionValidator() {
- return new JvmVersionValidator();
- }
-
DaemonStarter createDaemonStarter(DaemonDir daemonDir, DaemonParameters daemonParameters, ListenerManager listenerManager, DaemonGreeter daemonGreeter, JvmVersionValidator jvmVersionValidator) {
return new DefaultDaemonStarter(daemonDir, daemonParameters, daemonGreeter, listenerManager.getBroadcaster(DaemonStartListener.class), jvmVersionValidator);
}
- DaemonGreeter createDaemonGreeter(DocumentationRegistry documentationRegistry) {
- return new DaemonGreeter(documentationRegistry);
- }
-
protected void configureDaemonContextBuilder(DaemonContextBuilder builder) {
builder.setDaemonRegistryDir(get(DaemonDir.class).getBaseDir());
builder.useDaemonParameters(daemonParameters);
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonConnector.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonConnector.java
index 99f71e2..20cd1eb 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonConnector.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DaemonConnector.java
@@ -31,7 +31,7 @@ public interface DaemonConnector {
* @return A connection to a matching daemon, or null if not running.
*/
@Nullable
- public DaemonClientConnection maybeConnect(DaemonInstanceDetails daemonAddress);
+ DaemonClientConnection maybeConnect(DaemonInstanceDetails daemonAddress);
/**
* Attempts to connect to a daemon that matches the given constraint.
@@ -39,18 +39,18 @@ public interface DaemonConnector {
* @return A connection to a matching daemon, or null if none running.
*/
@Nullable
- public DaemonClientConnection maybeConnect(ExplainingSpec<DaemonContext> constraint);
+ DaemonClientConnection maybeConnect(ExplainingSpec<DaemonContext> constraint);
/**
* Connects to a daemon that matches the given constraint, starting one if required.
*
* @return A connection to a matching daemon. Never returns null.
*/
- public DaemonClientConnection connect(ExplainingSpec<DaemonContext> constraint);
+ DaemonClientConnection connect(ExplainingSpec<DaemonContext> constraint);
/**
* Starts a new daemon and returns a connection to it.
*/
- public DaemonClientConnection startDaemon(ExplainingSpec<DaemonContext> constraint);
+ DaemonClientConnection startDaemon(ExplainingSpec<DaemonContext> constraint);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonConnector.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonConnector.java
index 740e740..c1a36fa 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonConnector.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonConnector.java
@@ -19,15 +19,16 @@ import org.gradle.api.internal.specs.ExplainingSpec;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.internal.UncheckedException;
+import org.gradle.internal.serialize.Serializers;
import org.gradle.launcher.daemon.context.DaemonContext;
import org.gradle.launcher.daemon.context.DaemonInstanceDetails;
import org.gradle.launcher.daemon.diagnostics.DaemonStartupInfo;
import org.gradle.launcher.daemon.logging.DaemonMessages;
+import org.gradle.launcher.daemon.protocol.DaemonMessageSerializer;
+import org.gradle.launcher.daemon.protocol.Message;
import org.gradle.launcher.daemon.registry.DaemonInfo;
import org.gradle.launcher.daemon.registry.DaemonRegistry;
-import org.gradle.messaging.remote.internal.ConnectException;
-import org.gradle.messaging.remote.internal.OutgoingConnector;
-import org.gradle.messaging.remote.internal.RemoteConnection;
+import org.gradle.messaging.remote.internal.*;
import java.util.List;
@@ -144,9 +145,10 @@ public class DefaultDaemonConnector implements DaemonConnector {
}
private DaemonClientConnection connectToDaemon(DaemonInstanceDetails daemon, DaemonClientConnection.StaleAddressDetector staleAddressDetector) throws ConnectException {
- RemoteConnection<Object> connection;
+ RemoteConnection<Message> connection;
try {
- connection = connector.connect(daemon.getAddress()).create(getClass().getClassLoader());
+ MessageSerializer<Message> serializer = new KryoBackedMessageSerializer<Message>(Serializers.stateful(DaemonMessageSerializer.create()));
+ connection = connector.connect(daemon.getAddress()).create(serializer);
} catch (ConnectException e) {
staleAddressDetector.maybeStaleAddress(e);
throw e;
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonStarter.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonStarter.java
index 97807ca..f9d44c7 100755
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonStarter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/DefaultDaemonStarter.java
@@ -17,9 +17,14 @@ package org.gradle.launcher.daemon.client;
import org.gradle.api.GradleException;
import org.gradle.api.UncheckedIOException;
+import org.gradle.api.internal.classpath.DefaultGradleDistributionLocator;
import org.gradle.api.internal.classpath.DefaultModuleRegistry;
+import org.gradle.api.internal.classpath.Module;
+import org.gradle.api.internal.classpath.ModuleRegistry;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
+import org.gradle.internal.classpath.ClassPath;
+import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.internal.serialize.FlushableEncoder;
import org.gradle.internal.serialize.kryo.KryoBackedEncoder;
import org.gradle.launcher.daemon.DaemonExecHandleBuilder;
@@ -39,9 +44,8 @@ import org.gradle.util.GradleVersion;
import java.io.*;
import java.util.ArrayList;
-import java.util.LinkedHashSet;
+import java.util.Collections;
import java.util.List;
-import java.util.Set;
public class DefaultDaemonStarter implements DaemonStarter {
@@ -62,32 +66,40 @@ public class DefaultDaemonStarter implements DaemonStarter {
}
public DaemonStartupInfo startDaemon() {
- DefaultModuleRegistry registry = new DefaultModuleRegistry();
- Set<File> bootstrapClasspath = new LinkedHashSet<File>();
- bootstrapClasspath.addAll(registry.getModule("gradle-launcher").getImplementationClasspath().getAsFiles());
- if (registry.getGradleHome() == null) {
- // Running from the classpath - chuck in everything we can find
- bootstrapClasspath.addAll(registry.getFullClasspath());
+ ModuleRegistry registry = new DefaultModuleRegistry();
+ ClassPath classpath;
+ List<File> searchClassPath;
+ if (new DefaultGradleDistributionLocator().getGradleHome() != null) {
+ // When running from a Gradle distro, only need launcher jar. The daemon can find everything from there.
+ classpath = registry.getModule("gradle-launcher").getImplementationClasspath();
+ searchClassPath = Collections.emptyList();
+ } else {
+ // When not running from a Gradle distro, need runtime impl for launcher plus the search path to look for other modules
+ classpath = new DefaultClassPath();
+ for (Module module : registry.getModule("gradle-launcher").getAllRequiredModules()) {
+ classpath = classpath.plus(module.getClasspath());
+ }
+ searchClassPath = registry.getAdditionalClassPath().getAsFiles();
}
- if (bootstrapClasspath.isEmpty()) {
+ if (classpath.isEmpty()) {
throw new IllegalStateException("Unable to construct a bootstrap classpath when starting the daemon");
}
versionValidator.validate(daemonParameters);
List<String> daemonArgs = new ArrayList<String>();
- daemonArgs.add(daemonParameters.getEffectiveJavaExecutable().getAbsolutePath());
+ daemonArgs.add(daemonParameters.getEffectiveJvm().getJavaExecutable().getAbsolutePath());
List<String> daemonOpts = daemonParameters.getEffectiveJvmArgs();
- LOGGER.debug("Using daemon opts: {}", daemonOpts);
daemonArgs.addAll(daemonOpts);
daemonArgs.add("-cp");
- daemonArgs.add(CollectionUtils.join(File.pathSeparator, bootstrapClasspath));
+ daemonArgs.add(CollectionUtils.join(File.pathSeparator, classpath.getAsFiles()));
if (Boolean.getBoolean("org.gradle.daemon.debug")) {
daemonArgs.add("-Xdebug");
daemonArgs.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005");
}
+ LOGGER.debug("Using daemon args: {}", daemonArgs);
daemonArgs.add(GradleDaemon.class.getName());
// Version isn't used, except by a human looking at the output of jps.
@@ -105,6 +117,10 @@ public class DefaultDaemonStarter implements DaemonStarter {
for (String daemonOpt : daemonOpts) {
encoder.writeString(daemonOpt);
}
+ encoder.writeSmallInt(searchClassPath.size());
+ for (File file : searchClassPath) {
+ encoder.writeString(file.getAbsolutePath());
+ }
encoder.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/EmbeddedDaemonClientServices.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/EmbeddedDaemonClientServices.java
index 900ae22..8ef2751 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/EmbeddedDaemonClientServices.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/EmbeddedDaemonClientServices.java
@@ -70,6 +70,7 @@ public class EmbeddedDaemonClientServices extends DaemonClientServicesSupport {
LoggingManagerInternal mgr = newInstance(LoggingManagerInternal.class);
return new DefaultDaemonCommandExecuter(
get(BuildExecuter.class),
+ this,
get(ProcessEnvironment.class),
mgr,
new File("dummy"),
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/JvmVersionDetector.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/JvmVersionDetector.java
new file mode 100644
index 0000000..ec7bab7
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/JvmVersionDetector.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.launcher.daemon.client;
+
+import org.gradle.api.GradleException;
+import org.gradle.api.JavaVersion;
+import org.gradle.api.UncheckedIOException;
+import org.gradle.internal.jvm.JavaInfo;
+import org.gradle.internal.jvm.Jvm;
+import org.gradle.process.internal.ExecHandleBuilder;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Probes a JVM installation to determine the Java version it provides.
+ */
+public class JvmVersionDetector {
+ private final Map<JavaInfo, JavaVersion> cachedResults = new HashMap<JavaInfo, JavaVersion>();
+
+ public JvmVersionDetector() {
+ cachedResults.put(Jvm.current(), JavaVersion.current());
+ }
+
+ public JavaVersion getJavaVersion(JavaInfo jvm) {
+ JavaVersion version = cachedResults.get(jvm);
+ if (version != null) {
+ return version;
+ }
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+ ExecHandleBuilder builder = new ExecHandleBuilder();
+ builder.setWorkingDir(new File(".").getAbsolutePath());
+ builder.setCommandLine(jvm.getJavaExecutable(), "-version");
+ builder.setStandardOutput(new ByteArrayOutputStream());
+ builder.setErrorOutput(outputStream);
+ builder.build().start().waitForFinish().assertNormalExitValue();
+
+ version = parseJavaVersionCommandOutput(jvm.getJavaExecutable().getPath(), new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray()))));
+ cachedResults.put(jvm, version);
+ return version;
+ }
+
+ JavaVersion parseJavaVersionCommandOutput(String javaExecutable, BufferedReader reader) {
+ try {
+ String versionStr = reader.readLine();
+ while (versionStr != null) {
+ Matcher matcher = Pattern.compile("(?:java|openjdk) version \"(.+?)\"").matcher(versionStr);
+ if (matcher.matches()) {
+ return JavaVersion.toVersion(matcher.group(1));
+ }
+ versionStr = reader.readLine();
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ throw new GradleException(String.format("Could not determine Java version using executable %s.", javaExecutable));
+ }
+}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/JvmVersionValidator.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/JvmVersionValidator.java
index f37f21c..ffa63dc 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/JvmVersionValidator.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/JvmVersionValidator.java
@@ -20,62 +20,22 @@ import org.gradle.api.JavaVersion;
import org.gradle.internal.jvm.Jvm;
import org.gradle.internal.jvm.UnsupportedJavaRuntimeException;
import org.gradle.launcher.daemon.configuration.DaemonParameters;
-import org.gradle.process.internal.ExecHandleBuilder;
-
-import java.io.*;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class JvmVersionValidator {
- private final Map<File, JavaVersion> cachedResults = new HashMap<File, JavaVersion>();
+ private final JvmVersionDetector versionDetector;
+
+ public JvmVersionValidator(JvmVersionDetector versionDetector) {
+ this.versionDetector = versionDetector;
+ }
- void validate(DaemonParameters parameters) {
- if (parameters.getEffectiveJavaHome().equals(Jvm.current().getJavaHome())) {
+ public void validate(DaemonParameters parameters) {
+ if (parameters.getEffectiveJvm().equals(Jvm.current())) {
return;
}
- JavaVersion javaVersion = getJavaVersion(parameters);
+ JavaVersion javaVersion = versionDetector.getJavaVersion(parameters.getEffectiveJvm());
if (!javaVersion.isJava6Compatible()) {
throw UnsupportedJavaRuntimeException.configuredWithUnsupportedVersion("Gradle", JavaVersion.VERSION_1_6, javaVersion);
}
}
-
- private JavaVersion getJavaVersion(DaemonParameters parameters) {
- JavaVersion version = cachedResults.get(parameters.getEffectiveJavaExecutable());
- if (version != null) {
- return version;
- }
-
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-
- ExecHandleBuilder builder = new ExecHandleBuilder();
- builder.setWorkingDir(new File(".").getAbsolutePath());
- builder.setCommandLine(parameters.getEffectiveJavaExecutable(), "-version");
- builder.setStandardOutput(new ByteArrayOutputStream());
- builder.setErrorOutput(outputStream);
- builder.build().start().waitForFinish().assertNormalExitValue();
-
- version = parseJavaVersionCommandOutput(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(outputStream.toByteArray()))));
- cachedResults.put(parameters.getEffectiveJavaExecutable(), version);
- return version;
- }
-
- static JavaVersion parseJavaVersionCommandOutput(BufferedReader reader) {
- try {
- String versionStr = reader.readLine();
- while (versionStr != null) {
- Matcher matcher = Pattern.compile("(?:java|openjdk) version \"(.+?)\"").matcher(versionStr);
- if (matcher.matches()) {
- return JavaVersion.toVersion(matcher.group(1));
- }
- versionStr = reader.readLine();
- }
- } catch (IOException e) {
- throw new org.gradle.api.UncheckedIOException(e);
- }
-
- throw new RuntimeException("Could not determine Java version.");
- }
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/NoUsableDaemonFoundException.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/NoUsableDaemonFoundException.java
index ad7ccf6..c1e712f 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/NoUsableDaemonFoundException.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/NoUsableDaemonFoundException.java
@@ -16,10 +16,10 @@
package org.gradle.launcher.daemon.client;
-import org.gradle.api.GradleException;
+import org.gradle.internal.exceptions.DefaultMultiCauseException;
-public class NoUsableDaemonFoundException extends GradleException {
- public NoUsableDaemonFoundException(String message) {
- super(message);
+public class NoUsableDaemonFoundException extends DefaultMultiCauseException {
+ public NoUsableDaemonFoundException(String message, Iterable<? extends Throwable> causes) {
+ super(message, causes);
}
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/SingleUseDaemonClient.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/SingleUseDaemonClient.java
index 7da6ead..7aa22af 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/SingleUseDaemonClient.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/SingleUseDaemonClient.java
@@ -25,6 +25,7 @@ import org.gradle.internal.invocation.BuildAction;
import org.gradle.initialization.BuildRequestContext;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.id.IdGenerator;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.daemon.context.DaemonContext;
import org.gradle.launcher.daemon.protocol.Build;
import org.gradle.launcher.daemon.protocol.BuildAndStop;
@@ -45,7 +46,7 @@ public class SingleUseDaemonClient extends DaemonClient {
}
@Override
- public Object execute(BuildAction action, BuildRequestContext buildRequestContext, BuildActionParameters parameters) {
+ public Object execute(BuildAction action, BuildRequestContext buildRequestContext, BuildActionParameters parameters, ServiceRegistry contextServices) {
LOGGER.lifecycle("{} Please consider using the daemon: {}.", MESSAGE, documentationRegistry.getDocumentationFor("gradle_daemon"));
Build build = new BuildAndStop(getIdGenerator().generateId(), action, buildRequestContext.getClient(), buildRequestContext.getBuildTimeClock().getStartTime(), parameters);
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/StopDispatcher.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/StopDispatcher.java
index 62c4ee8..ccd5e9f 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/StopDispatcher.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/client/StopDispatcher.java
@@ -18,16 +18,13 @@ package org.gradle.launcher.daemon.client;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
-import org.gradle.launcher.daemon.protocol.Command;
-import org.gradle.launcher.daemon.protocol.Failure;
-import org.gradle.launcher.daemon.protocol.Finished;
-import org.gradle.launcher.daemon.protocol.Result;
+import org.gradle.launcher.daemon.protocol.*;
import org.gradle.messaging.remote.internal.Connection;
public class StopDispatcher {
private static final Logger LOGGER = Logging.getLogger(StopDispatcher.class);
- public void dispatch(Connection<Object> connection, Command stopCommand) {
+ public void dispatch(Connection<Message> connection, Command stopCommand) {
Throwable failure = null;
try {
connection.dispatch(stopCommand);
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/CurrentProcess.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/CurrentProcess.java
index a8e88ea..d977286 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/CurrentProcess.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/CurrentProcess.java
@@ -16,28 +16,25 @@
package org.gradle.launcher.daemon.configuration;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
import org.gradle.api.internal.file.IdentityFileResolver;
+import org.gradle.internal.jvm.JavaInfo;
import org.gradle.internal.jvm.Jvm;
import org.gradle.process.internal.JvmOptions;
-import java.io.File;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Properties;
public class CurrentProcess {
- private final File javaHome;
+ private final JavaInfo jvm;
private final JvmOptions effectiveJvmOptions;
public CurrentProcess() {
- this(Jvm.current().getJavaHome(), inferJvmOptions());
+ this(Jvm.current(), inferJvmOptions());
}
- public CurrentProcess(File javaHome, JvmOptions effectiveJvmOptions) {
- this.javaHome = javaHome;
+ CurrentProcess(JavaInfo jvm, JvmOptions effectiveJvmOptions) {
+ this.jvm = jvm;
this.effectiveJvmOptions = effectiveJvmOptions;
}
@@ -45,21 +42,17 @@ public class CurrentProcess {
return effectiveJvmOptions;
}
- public File getJavaHome() {
- return javaHome;
- }
-
/**
* Attempts to configure the current process to run with the required build parameters.
* @return True if the current process could be configured, false otherwise.
*/
public boolean configureForBuild(DaemonParameters requiredBuildParameters) {
- boolean javaHomeMatch = getJavaHome().equals(requiredBuildParameters.getEffectiveJavaHome());
+ boolean javaHomeMatch = jvm.equals(requiredBuildParameters.getEffectiveJvm());
List<String> currentImmutable = new JvmOptions(new IdentityFileResolver()).getAllImmutableJvmArgs();
List<String> requiredImmutable = requiredBuildParameters.getEffectiveJvmArgs();
- List<String> requiredImmutableMinusDefaults = removeDefaults(requiredImmutable);
- boolean noImmutableJvmArgsRequired = requiredImmutableMinusDefaults.equals(currentImmutable);
+ requiredImmutable.removeAll(DaemonParameters.DEFAULT_JVM_ARGS);
+ boolean noImmutableJvmArgsRequired = requiredImmutable.equals(currentImmutable);
if (javaHomeMatch && noImmutableJvmArgsRequired) {
// Set the system properties and use this process
@@ -71,14 +64,6 @@ public class CurrentProcess {
return false;
}
- private List<String> removeDefaults(List<String> effectiveJvmArgs) {
- return Lists.newArrayList(Iterables.filter(effectiveJvmArgs, new Predicate<String>() {
- public boolean apply(String input) {
- return !DaemonParameters.DEFAULT_JVM_ARGS.contains(input);
- }
- }));
- }
-
private static JvmOptions inferJvmOptions() {
// Try to infer the effective jvm options for the currently running process.
// We only care about 'managed' jvm args, anything else is unimportant to the running build
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/DaemonParameters.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/DaemonParameters.java
index e8e11b3..1e7eadf 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/DaemonParameters.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/configuration/DaemonParameters.java
@@ -16,8 +16,11 @@
package org.gradle.launcher.daemon.configuration;
import com.google.common.collect.ImmutableList;
+import org.gradle.api.JavaVersion;
+import org.gradle.api.Nullable;
import org.gradle.api.internal.file.IdentityFileResolver;
import org.gradle.initialization.BuildLayoutParameters;
+import org.gradle.internal.jvm.JavaInfo;
import org.gradle.internal.jvm.Jvm;
import org.gradle.process.internal.JvmOptions;
import org.gradle.util.GUtil;
@@ -25,12 +28,11 @@ import org.gradle.util.GUtil;
import java.io.File;
import java.util.*;
-import static org.gradle.util.GFileUtils.canonicalise;
-
public class DaemonParameters {
static final int DEFAULT_IDLE_TIMEOUT = 3 * 60 * 60 * 1000;
public static final List<String> DEFAULT_JVM_ARGS = ImmutableList.of("-Xmx1024m", "-XX:MaxPermSize=256m", "-XX:+HeapDumpOnOutOfMemoryError");
+ public static final List<String> DEFAULT_JVM_9_ARGS = ImmutableList.of("-Xmx1024m", "-XX:+HeapDumpOnOutOfMemoryError");
public static final String INTERACTIVE_TOGGLE = "org.gradle.interactive";
private final String uid;
@@ -40,10 +42,11 @@ public class DaemonParameters {
private int idleTimeout = DEFAULT_IDLE_TIMEOUT;
private final JvmOptions jvmOptions = new JvmOptions(new IdentityFileResolver());
private DaemonUsage daemonUsage = DaemonUsage.IMPLICITLY_DISABLED;
- private File javaHome;
+ private boolean hasJvmArgs;
private boolean foreground;
private boolean stop;
private boolean interactive = System.console() != null || Boolean.getBoolean(INTERACTIVE_TOGGLE);
+ private JavaInfo jvm = Jvm.current();
public DaemonParameters(BuildLayoutParameters layout) {
this(layout, Collections.<String, String>emptyMap());
@@ -51,7 +54,6 @@ public class DaemonParameters {
public DaemonParameters(BuildLayoutParameters layout, Map<String, String> extraSystemProperties) {
this.uid = UUID.randomUUID().toString();
- jvmOptions.setAllJvmArgs(DEFAULT_JVM_ARGS);
jvmOptions.systemProperties(extraSystemProperties);
baseDir = new File(layout.getGradleUserHomeDir(), "daemon");
gradleUserHomeDir = layout.getGradleUserHomeDir();
@@ -90,32 +92,25 @@ public class DaemonParameters {
return jvmOptions.getAllImmutableJvmArgs();
}
- public List<String> getAllJvmArgs() {
- return jvmOptions.getAllJvmArgs();
- }
-
- public File getEffectiveJavaHome() {
- if (javaHome == null) {
- return canonicalise(Jvm.current().getJavaHome());
- }
- return javaHome;
- }
-
- public File getEffectiveJavaExecutable() {
- if (javaHome == null) {
- return Jvm.current().getJavaExecutable();
- }
- return Jvm.forHome(javaHome).getJavaExecutable();
+ public JavaInfo getEffectiveJvm() {
+ return jvm;
}
- public DaemonParameters setInteractive(boolean interactive) {
- this.interactive = interactive;
+ @Nullable
+ public DaemonParameters setJvm(JavaInfo jvm) {
+ this.jvm = jvm == null ? Jvm.current() : jvm;
return this;
}
- public DaemonParameters setJavaHome(File javaHome) {
- this.javaHome = javaHome;
- return this;
+ public void applyDefaultsFor(JavaVersion javaVersion) {
+ if (hasJvmArgs) {
+ return;
+ }
+ if (javaVersion.compareTo(JavaVersion.VERSION_1_9) >= 0) {
+ jvmOptions.setAllJvmArgs(DEFAULT_JVM_9_ARGS);
+ } else {
+ jvmOptions.setAllJvmArgs(DEFAULT_JVM_ARGS);
+ }
}
public Map<String, String> getSystemProperties() {
@@ -132,6 +127,7 @@ public class DaemonParameters {
}
public void setJvmArgs(Iterable<String> jvmArgs) {
+ hasJvmArgs = true;
jvmOptions.setAllJvmArgs(jvmArgs);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/context/DaemonContextBuilder.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/context/DaemonContextBuilder.java
index 21cea24..939ae1a 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/context/DaemonContextBuilder.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/context/DaemonContextBuilder.java
@@ -105,7 +105,7 @@ public class DaemonContextBuilder implements Factory<DaemonContext> {
}
public void useDaemonParameters(DaemonParameters daemonParameters) {
- setJavaHome(daemonParameters.getEffectiveJavaHome());
+ setJavaHome(daemonParameters.getEffectiveJvm().getJavaHome());
setDaemonOpts(daemonParameters.getEffectiveJvmArgs());
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/CloseInput.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/CloseInput.java
index d606925..dcabd8b 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/CloseInput.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/CloseInput.java
@@ -15,8 +15,5 @@
*/
package org.gradle.launcher.daemon.protocol;
-public class CloseInput extends IoCommand {
- public CloseInput(Object identifier) {
- super(identifier);
- }
+public class CloseInput extends InputMessage {
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/CommandFailure.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/CommandFailure.java
deleted file mode 100644
index e889a33..0000000
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/CommandFailure.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.launcher.daemon.protocol;
-
-/**
- * Signifies that the daemon was able to run the command as expected, but the command itself did not complete successfully.
- * <p>
- * This is different to {@link DaemonFailure} which signifies that the daemon itself encountered some internal error
- * trying to execute the command it received.
- */
-public class CommandFailure extends Failure {
-
- public CommandFailure(Throwable value) {
- super(value);
- }
-}
\ No newline at end of file
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/DaemonFailure.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/DaemonFailure.java
deleted file mode 100644
index 04619a7..0000000
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/DaemonFailure.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.launcher.daemon.protocol;
-
-/**
- * Signifies that the daemon infrastructure encountered an internal error in trying to
- * execute the command it received.
- * <p>
- * This is different to {@link CommandFailure}, which signifies that the daemon did its job successfully
- * but the command itself failed.
- */
-public class DaemonFailure extends Failure {
- public DaemonFailure(Throwable value) {
- super(value);
- }
-}
\ No newline at end of file
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/DaemonMessageSerializer.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/DaemonMessageSerializer.java
new file mode 100644
index 0000000..1594679
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/DaemonMessageSerializer.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.launcher.daemon.protocol;
+
+import org.gradle.api.logging.LogLevel;
+import org.gradle.internal.progress.OperationIdentifier;
+import org.gradle.internal.serialize.*;
+import org.gradle.logging.StyledTextOutput;
+import org.gradle.logging.internal.*;
+
+import java.util.List;
+
+public class DaemonMessageSerializer {
+ public static Serializer<Message> create() {
+ BaseSerializerFactory factory = new BaseSerializerFactory();
+ Serializer<LogLevel> logLevelSerializer = factory.getSerializerFor(LogLevel.class);
+ Serializer<Throwable> throwableSerializer = factory.getSerializerFor(Throwable.class);
+ DefaultSerializerRegistry<Message> registry = new DefaultSerializerRegistry<Message>();
+
+ registry.register(BuildEvent.class, new BuildEventSerializer());
+ registry.register(Failure.class, new FailureSerializer(throwableSerializer));
+
+ // Input events
+ registry.register(ForwardInput.class, new ForwardInputSerializer());
+ registry.register(CloseInput.class, new CloseInputSerializer());
+
+ // Output events
+ DefaultSerializerRegistry<OutputEvent> outputEventRegistry = new DefaultSerializerRegistry<OutputEvent>();
+ outputEventRegistry.register(LogEvent.class, new LogEventSerializer(logLevelSerializer, throwableSerializer));
+ outputEventRegistry.register(StyledTextOutputEvent.class, new StyledTextOutputEventSerializer(logLevelSerializer, new ListSerializer<StyledTextOutputEvent.Span>(new SpanSerializer(factory.getSerializerFor(StyledTextOutput.Style.class)))));
+ outputEventRegistry.register(ProgressStartEvent.class, new ProgressStartEventSerializer());
+ outputEventRegistry.register(ProgressCompleteEvent.class, new ProgressCompleteEventSerializer());
+ outputEventRegistry.register(ProgressEvent.class, new ProgressEventSerializer());
+ outputEventRegistry.register(LogLevelChangeEvent.class, new LogLevelChangeEventSerializer(logLevelSerializer));
+ registry.register(OutputMessage.class, new OutputMessageSerializer(outputEventRegistry.build()));
+
+ // Default for everything else
+ registry.useJavaSerialization(Message.class);
+
+ return registry.build();
+ }
+
+ private static class FailureSerializer implements Serializer<Failure> {
+ private final Serializer<Throwable> throwableSerializer;
+
+ public FailureSerializer(Serializer<Throwable> throwableSerializer) {
+ this.throwableSerializer = throwableSerializer;
+ }
+
+ @Override
+ public void write(Encoder encoder, Failure failure) throws Exception {
+ throwableSerializer.write(encoder, failure.getValue());
+ }
+
+ @Override
+ public Failure read(Decoder decoder) throws Exception {
+ return new Failure(throwableSerializer.read(decoder));
+ }
+ }
+
+ private static class BuildEventSerializer implements Serializer<BuildEvent> {
+ private final Serializer<Object> payloadSerializer = new DefaultSerializer<Object>();
+
+ @Override
+ public void write(Encoder encoder, BuildEvent buildEvent) throws Exception {
+ payloadSerializer.write(encoder, buildEvent.getPayload());
+ }
+
+ @Override
+ public BuildEvent read(Decoder decoder) throws Exception {
+ return new BuildEvent(payloadSerializer.read(decoder));
+ }
+ }
+
+ private static class ProgressStartEventSerializer implements Serializer<ProgressStartEvent> {
+ @Override
+ public void write(Encoder encoder, ProgressStartEvent event) throws Exception {
+ encoder.writeSmallLong(event.getOperationId().getId());
+ if (event.getParentId() == null) {
+ encoder.writeBoolean(false);
+ } else {
+ encoder.writeBoolean(true);
+ encoder.writeSmallLong(event.getParentId().getId());
+ }
+ encoder.writeLong(event.getTimestamp());
+ encoder.writeString(event.getCategory());
+ encoder.writeString(event.getDescription());
+ encoder.writeNullableString(event.getShortDescription());
+ encoder.writeNullableString(event.getLoggingHeader());
+ encoder.writeString(event.getStatus());
+ }
+
+ @Override
+ public ProgressStartEvent read(Decoder decoder) throws Exception {
+ OperationIdentifier id = new OperationIdentifier(decoder.readSmallLong());
+ OperationIdentifier parentId = decoder.readBoolean() ? new OperationIdentifier(decoder.readSmallLong()) : null;
+ long timestamp = decoder.readLong();
+ String category = decoder.readString();
+ String description = decoder.readString();
+ String shortDescription = decoder.readNullableString();
+ String loggingHeader = decoder.readNullableString();
+ String status = decoder.readString();
+ return new ProgressStartEvent(id, parentId, timestamp, category, description, shortDescription, loggingHeader, status);
+ }
+ }
+
+ private static class ProgressEventSerializer implements Serializer<ProgressEvent> {
+ @Override
+ public void write(Encoder encoder, ProgressEvent event) throws Exception {
+ encoder.writeSmallLong(event.getOperationId().getId());
+ encoder.writeLong(event.getTimestamp());
+ encoder.writeString(event.getCategory());
+ encoder.writeString(event.getStatus());
+ }
+
+ @Override
+ public ProgressEvent read(Decoder decoder) throws Exception {
+ OperationIdentifier id = new OperationIdentifier(decoder.readSmallLong());
+ long timestamp = decoder.readLong();
+ String category = decoder.readString();
+ String status = decoder.readString();
+ return new ProgressEvent(id, timestamp, category, status);
+ }
+ }
+
+ private static class ProgressCompleteEventSerializer implements Serializer<ProgressCompleteEvent> {
+ @Override
+ public void write(Encoder encoder, ProgressCompleteEvent event) throws Exception {
+ encoder.writeSmallLong(event.getOperationId().getId());
+ encoder.writeLong(event.getTimestamp());
+ encoder.writeString(event.getCategory());
+ encoder.writeString(event.getDescription());
+ encoder.writeString(event.getStatus());
+ }
+
+ @Override
+ public ProgressCompleteEvent read(Decoder decoder) throws Exception {
+ OperationIdentifier id = new OperationIdentifier(decoder.readSmallLong());
+ long timestamp = decoder.readLong();
+ String category = decoder.readString();
+ String description = decoder.readString();
+ String status = decoder.readString();
+ return new ProgressCompleteEvent(id, timestamp, category, description, status);
+ }
+ }
+
+ private static class LogLevelChangeEventSerializer implements Serializer<LogLevelChangeEvent> {
+ private final Serializer<LogLevel> logLevelSerializer;
+
+ public LogLevelChangeEventSerializer(Serializer<LogLevel> logLevelSerializer) {
+ this.logLevelSerializer = logLevelSerializer;
+ }
+
+ @Override
+ public void write(Encoder encoder, LogLevelChangeEvent value) throws Exception {
+ logLevelSerializer.write(encoder, value.getNewLogLevel());
+ }
+
+ @Override
+ public LogLevelChangeEvent read(Decoder decoder) throws Exception {
+ LogLevel logLevel = logLevelSerializer.read(decoder);
+ return new LogLevelChangeEvent(logLevel);
+ }
+ }
+
+ private static class LogEventSerializer implements Serializer<LogEvent> {
+ private final Serializer<Throwable> throwableSerializer;
+ private final Serializer<LogLevel> logLevelSerializer;
+
+ public LogEventSerializer(Serializer<LogLevel> logLevelSerializer, Serializer<Throwable> throwableSerializer) {
+ this.logLevelSerializer = logLevelSerializer;
+ this.throwableSerializer = throwableSerializer;
+ }
+
+ @Override
+ public void write(Encoder encoder, LogEvent event) throws Exception {
+ encoder.writeLong(event.getTimestamp());
+ encoder.writeString(event.getCategory());
+ logLevelSerializer.write(encoder, event.getLogLevel());
+ encoder.writeString(event.getMessage());
+ throwableSerializer.write(encoder, event.getThrowable());
+ }
+
+ @Override
+ public LogEvent read(Decoder decoder) throws Exception {
+ long timestamp = decoder.readLong();
+ String category = decoder.readString();
+ LogLevel logLevel = logLevelSerializer.read(decoder);
+ String message = decoder.readString();
+ Throwable throwable = throwableSerializer.read(decoder);
+ return new LogEvent(timestamp, category, logLevel, message, throwable);
+ }
+ }
+
+ private static class SpanSerializer implements Serializer<StyledTextOutputEvent.Span> {
+ private final Serializer<StyledTextOutput.Style> styleSerializer;
+
+ public SpanSerializer(Serializer<StyledTextOutput.Style> styleSerializer) {
+ this.styleSerializer = styleSerializer;
+ }
+
+ @Override
+ public void write(Encoder encoder, StyledTextOutputEvent.Span value) throws Exception {
+ styleSerializer.write(encoder, value.getStyle());
+ encoder.writeString(value.getText());
+ }
+
+ @Override
+ public StyledTextOutputEvent.Span read(Decoder decoder) throws Exception {
+ return new StyledTextOutputEvent.Span(styleSerializer.read(decoder), decoder.readString());
+ }
+ }
+
+ private static class StyledTextOutputEventSerializer implements Serializer<StyledTextOutputEvent> {
+ private final Serializer<LogLevel> logLevelSerializer;
+ private final Serializer<List<StyledTextOutputEvent.Span>> spanSerializer;
+
+ public StyledTextOutputEventSerializer(Serializer<LogLevel> logLevelSerializer, Serializer<List<StyledTextOutputEvent.Span>> spanSerializer) {
+ this.logLevelSerializer = logLevelSerializer;
+ this.spanSerializer = spanSerializer;
+ }
+
+ @Override
+ public void write(Encoder encoder, StyledTextOutputEvent event) throws Exception {
+ encoder.writeLong(event.getTimestamp());
+ encoder.writeString(event.getCategory());
+ logLevelSerializer.write(encoder, event.getLogLevel());
+ spanSerializer.write(encoder, event.getSpans());
+ }
+
+ @Override
+ public StyledTextOutputEvent read(Decoder decoder) throws Exception {
+ long timestamp = decoder.readLong();
+ String category = decoder.readString();
+ LogLevel logLevel = logLevelSerializer.read(decoder);
+ List<StyledTextOutputEvent.Span> spans = spanSerializer.read(decoder);
+ return new StyledTextOutputEvent(timestamp, category, logLevel, spans);
+ }
+ }
+
+ private static class ForwardInputSerializer implements Serializer<ForwardInput> {
+ @Override
+ public void write(Encoder encoder, ForwardInput message) throws Exception {
+ encoder.writeBinary(message.getBytes());
+ }
+
+ @Override
+ public ForwardInput read(Decoder decoder) throws Exception {
+ return new ForwardInput(decoder.readBinary());
+ }
+ }
+
+ private static class CloseInputSerializer implements Serializer<CloseInput> {
+ @Override
+ public void write(Encoder encoder, CloseInput value) {
+ }
+
+ @Override
+ public CloseInput read(Decoder decoder) {
+ return new CloseInput();
+ }
+ }
+
+ private static class OutputMessageSerializer implements Serializer<OutputMessage> {
+ private final Serializer<OutputEvent> eventSerializer;
+
+ public OutputMessageSerializer(Serializer<OutputEvent> eventSerializer) {
+ this.eventSerializer = eventSerializer;
+ }
+
+ @Override
+ public void write(Encoder encoder, OutputMessage message) throws Exception {
+ eventSerializer.write(encoder, message.getEvent());
+ }
+
+ @Override
+ public OutputMessage read(Decoder decoder) throws Exception {
+ return new OutputMessage(eventSerializer.read(decoder));
+ }
+ }
+}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/Failure.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/Failure.java
index ee4f0ff..61df033 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/Failure.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/Failure.java
@@ -20,7 +20,7 @@ package org.gradle.launcher.daemon.protocol;
* <p>
* The “value” of this result will be an exception that represents the failure. It may not be {@code null}.
*/
-abstract public class Failure extends Result<Throwable> {
+public class Failure extends Result<Throwable> {
public Failure(Throwable value) {
super(assertNotNull(value));
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/ForwardInput.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/ForwardInput.java
index dcf3d59..651019c 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/ForwardInput.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/ForwardInput.java
@@ -15,11 +15,10 @@
*/
package org.gradle.launcher.daemon.protocol;
-public class ForwardInput extends IoCommand {
+public class ForwardInput extends InputMessage {
private final byte[] bytes;
- public ForwardInput(Object identifier, byte[] bytes) {
- super(identifier);
+ public ForwardInput(byte[] bytes) {
this.bytes = bytes;
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/InputMessage.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/InputMessage.java
new file mode 100644
index 0000000..a161876
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/InputMessage.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.launcher.daemon.protocol;
+
+abstract public class InputMessage extends Message {
+}
\ No newline at end of file
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/IoCommand.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/IoCommand.java
deleted file mode 100644
index 9839e8e..0000000
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/IoCommand.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.launcher.daemon.protocol;
-
-abstract public class IoCommand extends Command {
- protected IoCommand(Object identifier) {
- super(identifier);
- }
-}
\ No newline at end of file
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/OutputMessage.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/OutputMessage.java
new file mode 100644
index 0000000..89a93d7
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/protocol/OutputMessage.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.launcher.daemon.protocol;
+
+import org.gradle.logging.internal.OutputEvent;
+
+public class OutputMessage extends Message {
+ private final OutputEvent event;
+
+ public OutputMessage(OutputEvent event) {
+ this.event = event;
+ }
+
+ public OutputEvent getEvent() {
+ return event;
+ }
+}
\ No newline at end of file
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonServices.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonServices.java
index 3cae8dd..ca6409d 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonServices.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonServices.java
@@ -17,6 +17,7 @@ package org.gradle.launcher.daemon.server;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
+import org.gradle.internal.classpath.ClassPath;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.nativeintegration.ProcessEnvironment;
import org.gradle.internal.nativeintegration.services.NativeServices;
@@ -48,13 +49,13 @@ public class DaemonServices extends DefaultServiceRegistry {
private final LoggingManagerInternal loggingManager;
private final static Logger LOGGER = Logging.getLogger(DaemonServices.class);
- public DaemonServices(DaemonServerConfiguration configuration, ServiceRegistry loggingServices, LoggingManagerInternal loggingManager) {
+ public DaemonServices(DaemonServerConfiguration configuration, ServiceRegistry loggingServices, LoggingManagerInternal loggingManager, ClassPath additionalModuleClassPath) {
super(NativeServices.getInstance(), loggingServices);
this.configuration = configuration;
this.loggingManager = loggingManager;
addProvider(new DaemonRegistryServices(configuration.getBaseDir()));
- addProvider(new GlobalScopeServices(true));
+ addProvider(new GlobalScopeServices(true, additionalModuleClassPath));
}
protected DaemonContext createDaemonContext() {
@@ -92,6 +93,7 @@ public class DaemonServices extends DefaultServiceRegistry {
"password",
new DefaultDaemonCommandExecuter(
buildActionExecuter,
+ this,
get(ProcessEnvironment.class),
loggingManager,
getDaemonLogFile(),
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonTcpServerConnector.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonTcpServerConnector.java
index 2cb2340..9474472 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonTcpServerConnector.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DaemonTcpServerConnector.java
@@ -19,10 +19,15 @@ import org.gradle.api.Action;
import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.id.UUIDGenerator;
+import org.gradle.internal.serialize.Serializers;
+import org.gradle.launcher.daemon.protocol.DaemonMessageSerializer;
+import org.gradle.launcher.daemon.protocol.Message;
import org.gradle.messaging.remote.Address;
import org.gradle.messaging.remote.ConnectionAcceptor;
import org.gradle.messaging.remote.internal.ConnectCompletion;
import org.gradle.messaging.remote.internal.IncomingConnector;
+import org.gradle.messaging.remote.internal.KryoBackedMessageSerializer;
+import org.gradle.messaging.remote.internal.MessageSerializer;
import org.gradle.messaging.remote.internal.inet.InetAddressFactory;
import org.gradle.messaging.remote.internal.inet.TcpIncomingConnector;
@@ -63,7 +68,8 @@ public class DaemonTcpServerConnector implements DaemonServerConnector {
Action<ConnectCompletion> connectEvent = new Action<ConnectCompletion>() {
public void execute(ConnectCompletion completion) {
- handler.handle(new SynchronizedDispatchConnection<Object>(completion.create(getClass().getClassLoader())));
+ MessageSerializer<Message> serializer = new KryoBackedMessageSerializer<Message>(Serializers.stateful(DaemonMessageSerializer.create()));
+ handler.handle(new SynchronizedDispatchConnection<Message>(completion.create(serializer)));
}
};
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultDaemonConnection.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultDaemonConnection.java
index 0bd94c0..88262c3 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultDaemonConnection.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultDaemonConnection.java
@@ -16,10 +16,10 @@
package org.gradle.launcher.daemon.server;
-import org.gradle.internal.concurrent.CompositeStoppable;
-import org.gradle.internal.concurrent.Stoppable;
import org.gradle.internal.UncheckedException;
+import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.concurrent.ExecutorFactory;
+import org.gradle.internal.concurrent.Stoppable;
import org.gradle.internal.concurrent.StoppableExecutor;
import org.gradle.launcher.daemon.protocol.*;
import org.gradle.launcher.daemon.server.api.DaemonConnection;
@@ -39,14 +39,14 @@ import java.util.concurrent.locks.ReentrantLock;
public class DefaultDaemonConnection implements DaemonConnection {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDaemonConnection.class);
- private final Connection<Object> connection;
+ private final Connection<Message> connection;
private final StoppableExecutor executor;
private final StdinQueue stdinQueue;
private final DisconnectQueue disconnectQueue;
private final CancelQueue cancelQueue;
private final ReceiveQueue receiveQueue;
- public DefaultDaemonConnection(final Connection<Object> connection, ExecutorFactory executorFactory) {
+ public DefaultDaemonConnection(final Connection<Message> connection, ExecutorFactory executorFactory) {
this.connection = connection;
stdinQueue = new StdinQueue(executorFactory);
disconnectQueue = new DisconnectQueue();
@@ -71,9 +71,9 @@ public class DefaultDaemonConnection implements DaemonConnection {
return;
}
- if (message instanceof IoCommand) {
+ if (message instanceof InputMessage) {
LOGGER.debug("Received IO message from client: {}", message);
- stdinQueue.add((IoCommand) message);
+ stdinQueue.add((InputMessage) message);
} else if (message instanceof Cancel) {
LOGGER.debug("Received cancel message from client: {}", message);
cancelQueue.add((Cancel) message);
@@ -117,7 +117,7 @@ public class DefaultDaemonConnection implements DaemonConnection {
}
public void logEvent(OutputEvent logEvent) {
- connection.dispatch(logEvent);
+ connection.dispatch(new OutputMessage(logEvent));
}
@Override
@@ -138,7 +138,7 @@ public class DefaultDaemonConnection implements DaemonConnection {
CompositeStoppable.stoppable(disconnectQueue, connection, executor, receiveQueue, stdinQueue, cancelQueue).stop();
}
- private static abstract class CommandQueue<C extends Command, H> implements Stoppable {
+ private static abstract class CommandQueue<C extends Message, H> implements Stoppable {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
protected final LinkedList<C> queue = new LinkedList<C>();
@@ -253,13 +253,13 @@ public class DefaultDaemonConnection implements DaemonConnection {
}
}
- private static class StdinQueue extends CommandQueue<IoCommand, StdinHandler> {
+ private static class StdinQueue extends CommandQueue<InputMessage, StdinHandler> {
private StdinQueue(ExecutorFactory executorFactory) {
super(executorFactory, "Stdin handler");
}
- protected boolean doHandleCommand(final StdinHandler handler, IoCommand command) {
+ protected boolean doHandleCommand(final StdinHandler handler, InputMessage command) {
try {
if (command instanceof CloseInput) {
handler.onEndOfInput();
@@ -277,7 +277,7 @@ public class DefaultDaemonConnection implements DaemonConnection {
@Override
protected void doHandleDisconnect() {
queue.clear();
- queue.add(new CloseInput("<disconnected>"));
+ queue.add(new CloseInput());
}
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultIncomingConnectionHandler.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultIncomingConnectionHandler.java
index 3bf4d35..c16bbf8 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultIncomingConnectionHandler.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/DefaultIncomingConnectionHandler.java
@@ -25,10 +25,11 @@ import org.gradle.internal.concurrent.StoppableExecutor;
import org.gradle.launcher.daemon.context.DaemonContext;
import org.gradle.launcher.daemon.logging.DaemonMessages;
import org.gradle.launcher.daemon.protocol.Command;
-import org.gradle.launcher.daemon.protocol.DaemonFailure;
-import org.gradle.launcher.daemon.server.exec.DaemonCommandExecuter;
+import org.gradle.launcher.daemon.protocol.Failure;
+import org.gradle.launcher.daemon.protocol.Message;
import org.gradle.launcher.daemon.server.api.DaemonConnection;
import org.gradle.launcher.daemon.server.api.DaemonStateControl;
+import org.gradle.launcher.daemon.server.exec.DaemonCommandExecuter;
import org.gradle.messaging.remote.internal.Connection;
import java.util.HashSet;
@@ -57,7 +58,7 @@ public class DefaultIncomingConnectionHandler implements IncomingConnectionHandl
workers = executorFactory.create("Daemon");
}
- public void handle(final Connection<Object> connection) {
+ public void handle(final Connection<Message> connection) {
// Mark the connection has being handled
onStartHandling(connection);
@@ -67,7 +68,7 @@ public class DefaultIncomingConnectionHandler implements IncomingConnectionHandl
workers.execute(new ConnectionWorker(connection));
}
- private void onStartHandling(Connection<Object> connection) {
+ private void onStartHandling(Connection<?> connection) {
lock.lock();
try {
inProgress.add(connection);
@@ -76,7 +77,7 @@ public class DefaultIncomingConnectionHandler implements IncomingConnectionHandl
}
}
- private void onFinishHandling(Connection<Object> connection) {
+ private void onFinishHandling(Connection<?> connection) {
lock.lock();
try {
inProgress.remove(connection);
@@ -105,9 +106,9 @@ public class DefaultIncomingConnectionHandler implements IncomingConnectionHandl
}
private class ConnectionWorker implements Runnable {
- private final Connection<Object> connection;
+ private final Connection<Message> connection;
- public ConnectionWorker(Connection<Object> connection) {
+ public ConnectionWorker(Connection<Message> connection) {
this.connection = connection;
}
@@ -142,7 +143,7 @@ public class DefaultIncomingConnectionHandler implements IncomingConnectionHandl
return command;
} catch (Throwable e) {
LOGGER.warn(String.format("Unable to receive command from %s. Dispatching the failure to the daemon client", connection), e);
- daemonConnection.completed(new DaemonFailure(e));
+ daemonConnection.completed(new Failure(e));
return null;
}
}
@@ -153,7 +154,7 @@ public class DefaultIncomingConnectionHandler implements IncomingConnectionHandl
commandExecuter.executeCommand(daemonConnection, command, daemonContext, daemonStateControl);
} catch (Throwable e) {
LOGGER.warn(String.format("Unable to execute command %s from %s. Dispatching the failure to the daemon client", command, connection), e);
- daemonConnection.completed(new DaemonFailure(e));
+ daemonConnection.completed(new Failure(e));
} finally {
LOGGER.debug(DaemonMessages.FINISHED_EXECUTING_COMMAND + command);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/IncomingConnectionHandler.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/IncomingConnectionHandler.java
index 80b2659..d476630 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/IncomingConnectionHandler.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/IncomingConnectionHandler.java
@@ -15,8 +15,9 @@
*/
package org.gradle.launcher.daemon.server;
+import org.gradle.launcher.daemon.protocol.Message;
import org.gradle.messaging.remote.internal.Connection;
public interface IncomingConnectionHandler {
- void handle(Connection<Object> connection);
+ void handle(Connection<Message> connection);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/SynchronizedDispatchConnection.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/SynchronizedDispatchConnection.java
index 8a8ee89..5290680 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/SynchronizedDispatchConnection.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/SynchronizedDispatchConnection.java
@@ -16,20 +16,21 @@
package org.gradle.launcher.daemon.server;
-import org.gradle.internal.concurrent.Synchronizer;
-import org.gradle.logging.internal.OutputEvent;
+import org.gradle.launcher.daemon.protocol.OutputMessage;
import org.gradle.messaging.remote.internal.Connection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Connection decorator that synchronizes dispatching.
+ *
+ * The plan is to replace this with a Connection implementation that queues outgoing messages and dispatches them from a worker thread.
*/
public class SynchronizedDispatchConnection<T> implements Connection<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(SynchronizedDispatchConnection.class);
-
- private final Synchronizer sync = new Synchronizer();
+ private final Object lock = new Object();
private final Connection<T> delegate;
+ private boolean dispatching;
public SynchronizedDispatchConnection(Connection<T> delegate) {
this.delegate = delegate;
@@ -41,14 +42,21 @@ public class SynchronizedDispatchConnection<T> implements Connection<T> {
}
public void dispatch(final T message) {
- if (!(message instanceof OutputEvent)) {
+ if (!(message instanceof OutputMessage)) {
LOGGER.debug("thread {}: dispatching {}", Thread.currentThread().getId(), message.getClass());
}
- sync.synchronize(new Runnable() {
- public void run() {
+ synchronized (lock) {
+ if (dispatching) {
+ // Safety check: dispatching a message should not cause the thread to dispatch another message (eg should not do any logging)
+ throw new IllegalStateException("This thread is already dispatching a message.");
+ }
+ dispatching = true;
+ try {
delegate.dispatch(message);
+ } finally {
+ dispatching = false;
}
- });
+ }
}
public T receive() {
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/DefaultDaemonCommandExecuter.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/DefaultDaemonCommandExecuter.java
index 83f1bf7..6191d8d 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/DefaultDaemonCommandExecuter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/DefaultDaemonCommandExecuter.java
@@ -17,6 +17,7 @@ package org.gradle.launcher.daemon.server.exec;
import com.google.common.collect.ImmutableList;
import org.gradle.internal.nativeintegration.ProcessEnvironment;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.daemon.context.DaemonContext;
import org.gradle.launcher.daemon.diagnostics.DaemonDiagnostics;
import org.gradle.launcher.daemon.protocol.Command;
@@ -39,14 +40,16 @@ public class DefaultDaemonCommandExecuter implements DaemonCommandExecuter {
private final DaemonHealthServices healthServices;
private final ProcessEnvironment processEnvironment;
private final File daemonLog;
+ private final ServiceRegistry contextServices;
- public DefaultDaemonCommandExecuter(BuildActionExecuter<BuildActionParameters> actionExecuter, ProcessEnvironment processEnvironment,
+ public DefaultDaemonCommandExecuter(BuildActionExecuter<BuildActionParameters> actionExecuter, ServiceRegistry contextServices, ProcessEnvironment processEnvironment,
LoggingManagerInternal loggingOutput, File daemonLog, DaemonHealthServices healthServices) {
this.processEnvironment = processEnvironment;
this.daemonLog = daemonLog;
this.loggingOutput = loggingOutput;
this.actionExecuter = actionExecuter;
this.healthServices = healthServices;
+ this.contextServices = contextServices;
}
public void executeCommand(DaemonConnection connection, Command command, DaemonContext daemonContext, DaemonStateControl daemonStateControl) {
@@ -74,7 +77,7 @@ public class DefaultDaemonCommandExecuter implements DaemonCommandExecuter {
new RequestStopIfSingleUsedDaemon(),
new ResetDeprecationLogger(),
new WatchForDisconnection(),
- new ExecuteBuild(actionExecuter)
+ new ExecuteBuild(actionExecuter, contextServices)
);
}
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ExecuteBuild.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ExecuteBuild.java
index 800b0d4..c59be15 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ExecuteBuild.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ExecuteBuild.java
@@ -18,6 +18,7 @@ package org.gradle.launcher.daemon.server.exec;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.initialization.*;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.daemon.logging.DaemonMessages;
import org.gradle.launcher.daemon.protocol.Build;
import org.gradle.launcher.daemon.server.api.DaemonCommandExecution;
@@ -27,17 +28,19 @@ import org.gradle.initialization.ReportedException;
/**
* Actually executes the build.
- *
+ *
* Typically the last action in the pipeline.
*/
public class ExecuteBuild extends BuildCommandOnly {
private static final Logger LOGGER = Logging.getLogger(ExecuteBuild.class);
-
+
final private BuildActionExecuter<BuildActionParameters> actionExecuter;
+ final private ServiceRegistry contextServices;
- public ExecuteBuild(BuildActionExecuter<BuildActionParameters> actionExecuter) {
+ public ExecuteBuild(BuildActionExecuter<BuildActionParameters> actionExecuter, ServiceRegistry contextServices) {
this.actionExecuter = actionExecuter;
+ this.contextServices = contextServices;
}
protected void doBuild(final DaemonCommandExecution execution, Build build) {
@@ -46,13 +49,13 @@ public class ExecuteBuild extends BuildCommandOnly {
try {
BuildCancellationToken cancellationToken = execution.getDaemonStateControl().getCancellationToken();
BuildRequestContext buildRequestContext = new DefaultBuildRequestContext(build.getBuildRequestMetaData(), cancellationToken, new DaemonConnectionBackedEventConsumer(execution));
- Object result = actionExecuter.execute(build.getAction(), buildRequestContext, build.getParameters());
+ Object result = actionExecuter.execute(build.getAction(), buildRequestContext, build.getParameters(), contextServices);
execution.setResult(result);
} catch (ReportedException e) {
/*
We have to wrap in a ReportedException so the other side doesn't re-log this exception, because it's already
been logged by the GradleLauncher infrastructure, and that logging has been shipped over to the other side.
-
+
This doesn't seem right. Perhaps we should assume on the client side that all “build failures” (opposed to daemon infrastructure failures)
have already been logged and do away with this wrapper.
*/
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ReturnResult.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ReturnResult.java
index 2205fdd..b6949f1 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ReturnResult.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/ReturnResult.java
@@ -17,7 +17,7 @@ package org.gradle.launcher.daemon.server.exec;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
-import org.gradle.launcher.daemon.protocol.CommandFailure;
+import org.gradle.launcher.daemon.protocol.Failure;
import org.gradle.launcher.daemon.protocol.Result;
import org.gradle.launcher.daemon.protocol.Success;
import org.gradle.launcher.daemon.server.api.DaemonCommandAction;
@@ -38,7 +38,7 @@ public class ReturnResult implements DaemonCommandAction {
Result result;
Throwable commandException = execution.getException();
if (commandException != null) {
- result = new CommandFailure(commandException);
+ result = new Failure(commandException);
} else {
result = new Success(execution.getResult());
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/StartBuildOrRespondWithBusy.java b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/StartBuildOrRespondWithBusy.java
index b9f19df..e78e4f8 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/StartBuildOrRespondWithBusy.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/daemon/server/exec/StartBuildOrRespondWithBusy.java
@@ -20,8 +20,8 @@ import org.gradle.api.logging.Logging;
import org.gradle.launcher.daemon.diagnostics.DaemonDiagnostics;
import org.gradle.launcher.daemon.protocol.Build;
import org.gradle.launcher.daemon.protocol.BuildStarted;
-import org.gradle.launcher.daemon.protocol.CommandFailure;
import org.gradle.launcher.daemon.protocol.DaemonUnavailable;
+import org.gradle.launcher.daemon.protocol.Failure;
import org.gradle.launcher.daemon.server.api.DaemonCommandExecution;
import org.gradle.launcher.daemon.server.api.DaemonStateControl;
import org.gradle.launcher.daemon.server.api.DaemonStoppedException;
@@ -56,7 +56,7 @@ public class StartBuildOrRespondWithBusy extends BuildCommandOnly {
LOGGER.info("Daemon will not handle the command {} because is unavailable: {}", build, e.getMessage());
execution.getConnection().daemonUnavailable(new DaemonUnavailable(e.getMessage()));
} catch (DaemonStoppedException e) {
- execution.getConnection().completed(new CommandFailure(e));
+ execution.getConnection().completed(new Failure(e));
}
}
}
\ No newline at end of file
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/BuildActionExecuter.java b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/BuildActionExecuter.java
index e63f158..7d69c8b 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/BuildActionExecuter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/BuildActionExecuter.java
@@ -17,6 +17,7 @@ package org.gradle.launcher.exec;
import org.gradle.internal.invocation.BuildAction;
import org.gradle.initialization.BuildRequestContext;
+import org.gradle.internal.service.ServiceRegistry;
public interface BuildActionExecuter<P> {
/**
@@ -25,5 +26,5 @@ public interface BuildActionExecuter<P> {
* @param action The action
* @return The result.
*/
- Object execute(BuildAction action, BuildRequestContext requestContext, P actionParameters);
+ Object execute(BuildAction action, BuildRequestContext requestContext, P actionParameters, ServiceRegistry contextServices);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/ContinuousBuildActionExecuter.java b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/ContinuousBuildActionExecuter.java
index 5477023..438aaf1 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/ContinuousBuildActionExecuter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/ContinuousBuildActionExecuter.java
@@ -29,6 +29,7 @@ import org.gradle.execution.PassThruCancellableOperationManager;
import org.gradle.initialization.BuildCancellationToken;
import org.gradle.initialization.BuildRequestContext;
import org.gradle.initialization.ReportedException;
+import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.event.ListenerManager;
import org.gradle.internal.filewatch.DefaultFileSystemChangeWaiter;
@@ -36,6 +37,8 @@ import org.gradle.internal.filewatch.FileSystemChangeWaiter;
import org.gradle.internal.filewatch.FileWatcherFactory;
import org.gradle.internal.invocation.BuildAction;
import org.gradle.internal.os.OperatingSystem;
+import org.gradle.internal.service.ServiceRegistry;
+import org.gradle.internal.service.scopes.BuildSessionScopeServices;
import org.gradle.logging.StyledTextOutput;
import org.gradle.logging.StyledTextOutputFactory;
import org.gradle.util.DisconnectableInputStream;
@@ -65,15 +68,20 @@ public class ContinuousBuildActionExecuter implements BuildExecuter {
}
@Override
- public Object execute(BuildAction action, BuildRequestContext requestContext, BuildActionParameters actionParameters) {
- if (actionParameters.isContinuous()) {
- return executeMultipleBuilds(action, requestContext, actionParameters);
- } else {
- return delegate.execute(action, requestContext, actionParameters);
+ public Object execute(BuildAction action, BuildRequestContext requestContext, BuildActionParameters actionParameters, ServiceRegistry contextServices) {
+ ServiceRegistry buildSessionScopeServices = new BuildSessionScopeServices(contextServices);
+ try {
+ if (actionParameters.isContinuous()) {
+ return executeMultipleBuilds(action, requestContext, actionParameters, buildSessionScopeServices);
+ } else {
+ return delegate.execute(action, requestContext, actionParameters, buildSessionScopeServices);
+ }
+ } finally {
+ CompositeStoppable.stoppable(buildSessionScopeServices).stop();
}
}
- private Object executeMultipleBuilds(BuildAction action, BuildRequestContext requestContext, final BuildActionParameters actionParameters) {
+ private Object executeMultipleBuilds(BuildAction action, BuildRequestContext requestContext, final BuildActionParameters actionParameters, ServiceRegistry buildSessionScopeServices) {
if (!javaVersion.isJava7Compatible()) {
throw new IllegalStateException("Continuous build requires Java 7 or later.");
}
@@ -103,7 +111,7 @@ public class ContinuousBuildActionExecuter implements BuildExecuter {
FileSystemSubset.Builder fileSystemSubsetBuilder = FileSystemSubset.builder();
try {
- lastResult = executeBuildAndAccumulateInputs(action, requestContext, actionParameters, fileSystemSubsetBuilder);
+ lastResult = executeBuildAndAccumulateInputs(action, requestContext, actionParameters, fileSystemSubsetBuilder, buildSessionScopeServices);
} catch (ReportedException t) {
lastResult = t;
}
@@ -149,7 +157,7 @@ public class ContinuousBuildActionExecuter implements BuildExecuter {
}
}
- private Object executeBuildAndAccumulateInputs(BuildAction action, BuildRequestContext requestContext, BuildActionParameters actionParameters, final FileSystemSubset.Builder fileSystemSubsetBuilder) {
+ private Object executeBuildAndAccumulateInputs(BuildAction action, BuildRequestContext requestContext, BuildActionParameters actionParameters, final FileSystemSubset.Builder fileSystemSubsetBuilder, ServiceRegistry buildSessionScopeServices) {
TaskInputsListener listener = new TaskInputsListener() {
@Override
public void onExecute(TaskInternal taskInternal, FileCollectionInternal fileSystemInputs) {
@@ -158,7 +166,7 @@ public class ContinuousBuildActionExecuter implements BuildExecuter {
};
listenerManager.addListener(listener);
try {
- return delegate.execute(action, requestContext, actionParameters);
+ return delegate.execute(action, requestContext, actionParameters, buildSessionScopeServices);
} finally {
listenerManager.removeListener(listener);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuter.java b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuter.java
index a3a24d8..f217f21 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuter.java
@@ -21,6 +21,7 @@ import org.gradle.api.logging.LogLevel;
import org.gradle.initialization.BuildRequestContext;
import org.gradle.internal.invocation.BuildAction;
import org.gradle.internal.os.OperatingSystem;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.logging.StyledTextOutput;
import org.gradle.logging.StyledTextOutputFactory;
@@ -46,8 +47,8 @@ public class DaemonUsageSuggestingBuildActionExecuter implements BuildActionExec
}
@Override
- public Object execute(BuildAction action, BuildRequestContext requestContext, BuildActionParameters actionParameters) {
- Object result = executer.execute(action, requestContext, actionParameters);
+ public Object execute(BuildAction action, BuildRequestContext requestContext, BuildActionParameters actionParameters, ServiceRegistry contextServices) {
+ Object result = executer.execute(action, requestContext, actionParameters, contextServices);
possiblySuggestUsingDaemon(actionParameters);
return result;
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/InProcessBuildActionExecuter.java b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/InProcessBuildActionExecuter.java
index e9e7096..f44a976 100644
--- a/subprojects/launcher/src/main/java/org/gradle/launcher/exec/InProcessBuildActionExecuter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/launcher/exec/InProcessBuildActionExecuter.java
@@ -23,6 +23,7 @@ import org.gradle.initialization.GradleLauncherFactory;
import org.gradle.internal.invocation.BuildAction;
import org.gradle.internal.invocation.BuildActionRunner;
import org.gradle.internal.invocation.BuildController;
+import org.gradle.internal.service.ServiceRegistry;
public class InProcessBuildActionExecuter implements BuildActionExecuter<BuildActionParameters> {
private final GradleLauncherFactory gradleLauncherFactory;
@@ -33,12 +34,11 @@ public class InProcessBuildActionExecuter implements BuildActionExecuter<BuildAc
this.buildActionRunner = buildActionRunner;
}
- public Object execute(BuildAction action, BuildRequestContext buildRequestContext, BuildActionParameters actionParameters) {
- DefaultGradleLauncher gradleLauncher = (DefaultGradleLauncher) gradleLauncherFactory.newInstance(action.getStartParameter(), buildRequestContext);
- gradleLauncher.addStandardOutputListener(buildRequestContext.getOutputListener());
- gradleLauncher.addStandardErrorListener(buildRequestContext.getErrorListener());
-
+ public Object execute(BuildAction action, BuildRequestContext buildRequestContext, BuildActionParameters actionParameters, ServiceRegistry contextServices) {
+ DefaultGradleLauncher gradleLauncher = (DefaultGradleLauncher) gradleLauncherFactory.newInstance(action.getStartParameter(), buildRequestContext, contextServices);
try {
+ gradleLauncher.addStandardOutputListener(buildRequestContext.getOutputListener());
+ gradleLauncher.addStandardErrorListener(buildRequestContext.getErrorListener());
DefaultBuildController buildController = new DefaultBuildController(gradleLauncher);
buildActionRunner.run(action, buildController);
return buildController.result;
@@ -48,7 +48,8 @@ public class InProcessBuildActionExecuter implements BuildActionExecuter<BuildAc
}
private static class DefaultBuildController implements BuildController {
- private enum State { Created, Completed }
+ private enum State {Created, Completed}
+
private State state = State.Created;
private boolean hasResult;
private Object result;
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/BuildModelAction.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/BuildModelAction.java
index 8b0c24d..fe9b7b2 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/BuildModelAction.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/BuildModelAction.java
@@ -16,21 +16,17 @@
package org.gradle.tooling.internal.provider;
import org.gradle.StartParameter;
-import org.gradle.internal.invocation.BuildAction;
-import java.io.Serializable;
-
-public class BuildModelAction implements BuildAction, Serializable {
+public class BuildModelAction extends SubscribableBuildAction {
private final StartParameter startParameter;
private final String modelName;
private final boolean runTasks;
- private final BuildClientSubscriptions clientSubscriptions;
public BuildModelAction(StartParameter startParameter, String modelName, boolean runTasks, BuildClientSubscriptions clientSubscriptions) {
+ super(clientSubscriptions);
this.startParameter = startParameter;
this.modelName = modelName;
this.runTasks = runTasks;
- this.clientSubscriptions = clientSubscriptions;
}
@Override
@@ -46,7 +42,4 @@ public class BuildModelAction implements BuildAction, Serializable {
return runTasks;
}
- public BuildClientSubscriptions getClientSubscriptions() {
- return clientSubscriptions;
- }
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ClientProvidedBuildAction.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ClientProvidedBuildAction.java
index 1ebc628..dcf0e88 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ClientProvidedBuildAction.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ClientProvidedBuildAction.java
@@ -17,19 +17,15 @@
package org.gradle.tooling.internal.provider;
import org.gradle.StartParameter;
-import org.gradle.internal.invocation.BuildAction;
-import java.io.Serializable;
-
-public class ClientProvidedBuildAction implements BuildAction, Serializable {
+public class ClientProvidedBuildAction extends SubscribableBuildAction {
private final StartParameter startParameter;
private final SerializedPayload action;
- private final BuildClientSubscriptions clientSubscriptions;
public ClientProvidedBuildAction(StartParameter startParameter, SerializedPayload action, BuildClientSubscriptions clientSubscriptions) {
+ super(clientSubscriptions);
this.startParameter = startParameter;
this.action = action;
- this.clientSubscriptions = clientSubscriptions;
}
@Override
@@ -40,8 +36,4 @@ public class ClientProvidedBuildAction implements BuildAction, Serializable {
public SerializedPayload getAction() {
return action;
}
-
- public BuildClientSubscriptions getClientSubscriptions() {
- return clientSubscriptions;
- }
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ConnectionScopeServices.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ConnectionScopeServices.java
index e617bb0..0ce1dad 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ConnectionScopeServices.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ConnectionScopeServices.java
@@ -19,9 +19,11 @@ package org.gradle.tooling.internal.provider;
import org.gradle.internal.classloader.ClassLoaderFactory;
import org.gradle.internal.event.ListenerManager;
import org.gradle.internal.service.ServiceRegistration;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.service.scopes.GlobalScopeServices;
import org.gradle.launcher.daemon.client.DaemonClientFactory;
import org.gradle.launcher.daemon.client.DaemonClientGlobalServices;
+import org.gradle.launcher.daemon.client.JvmVersionDetector;
import org.gradle.launcher.exec.BuildExecuter;
import org.gradle.logging.LoggingServiceRegistry;
import org.gradle.logging.internal.OutputEventRenderer;
@@ -50,8 +52,12 @@ public class ConnectionScopeServices {
}
ProviderConnection createProviderConnection(BuildExecuter buildActionExecuter, DaemonClientFactory daemonClientFactory,
- ClassLoaderFactory classLoaderFactory, ClassLoaderCache classLoaderCache, ShutdownCoordinator shutdownCoordinator) {
+ ClassLoaderFactory classLoaderFactory, ServiceRegistry serviceRegistry,
+ JvmVersionDetector jvmVersionDetector,
+ // This is here to trigger creation of the ShutdownCoordinator. Could do this in a nicer way
+ ShutdownCoordinator shutdownCoordinator) {
return new ProviderConnection(
+ serviceRegistry,
loggingServices,
daemonClientFactory,
buildActionExecuter,
@@ -62,7 +68,8 @@ public class ConnectionScopeServices {
new ClientSidePayloadClassLoaderFactory(
new ModelClassLoaderFactory(
classLoaderFactory))),
- new ClasspathInferer()))
+ new ClasspathInferer())),
+ jvmVersionDetector
);
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DaemonBuildActionExecuter.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DaemonBuildActionExecuter.java
index eda1285..4c46fcd 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DaemonBuildActionExecuter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DaemonBuildActionExecuter.java
@@ -19,6 +19,7 @@ import org.gradle.api.BuildCancelledException;
import org.gradle.initialization.BuildRequestContext;
import org.gradle.internal.SystemProperties;
import org.gradle.internal.invocation.BuildAction;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.daemon.configuration.DaemonParameters;
import org.gradle.launcher.exec.BuildActionExecuter;
import org.gradle.launcher.exec.BuildActionParameters;
@@ -40,7 +41,7 @@ public class DaemonBuildActionExecuter implements BuildActionExecuter<ProviderOp
this.daemonParameters = daemonParameters;
}
- public Object execute(BuildAction action, BuildRequestContext buildRequestContext, ProviderOperationParameters parameters) {
+ public Object execute(BuildAction action, BuildRequestContext buildRequestContext, ProviderOperationParameters parameters, ServiceRegistry contextServices) {
boolean continuous = action.getStartParameter() != null && action.getStartParameter().isContinuous() && isNotBuildingModel(action);
if (continuous && !doesConsumerSupportCancellation(buildRequestContext)) {
throw new UnsupportedVersionException("Continuous build requires Tooling API client version 2.1 or later.");
@@ -48,7 +49,7 @@ public class DaemonBuildActionExecuter implements BuildActionExecuter<ProviderOp
BuildActionParameters actionParameters = new DefaultBuildActionParameters(daemonParameters.getEffectiveSystemProperties(),
System.getenv(), SystemProperties.getInstance().getCurrentDir(), parameters.getBuildLogLevel(), daemonParameters.getDaemonUsage(), continuous, false);
try {
- return executer.execute(action, buildRequestContext, actionParameters);
+ return executer.execute(action, buildRequestContext, actionParameters, contextServices);
} catch (ReportedException e) {
Throwable t = e.getCause();
while (t != null) {
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DefaultConnection.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DefaultConnection.java
index d59832d..58dd2f4 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DefaultConnection.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/DefaultConnection.java
@@ -31,10 +31,13 @@ import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter;
import org.gradle.tooling.internal.consumer.versioning.ModelMapping;
import org.gradle.tooling.internal.protocol.*;
import org.gradle.tooling.internal.protocol.exceptions.InternalUnsupportedBuildArgumentException;
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionConnection;
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionRequest;
import org.gradle.tooling.internal.provider.connection.BuildLogLevelMixIn;
import org.gradle.tooling.internal.provider.connection.ProviderBuildResult;
import org.gradle.tooling.internal.provider.connection.ProviderConnectionParameters;
import org.gradle.tooling.internal.provider.connection.ProviderOperationParameters;
+import org.gradle.tooling.internal.provider.test.ProviderInternalTestExecutionRequest;
import org.gradle.util.GradleVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,7 +45,7 @@ import org.slf4j.LoggerFactory;
import java.io.File;
public class DefaultConnection implements InternalConnection, BuildActionRunner,
- ConfigurableConnection, ModelBuilder, InternalBuildActionExecutor, InternalCancellableConnection, StoppableConnection {
+ ConfigurableConnection, ModelBuilder, InternalBuildActionExecutor, InternalCancellableConnection, StoppableConnection, InternalTestExecutionConnection {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultConnection.class);
private ProtocolToModelAdapter adapter;
private ServiceRegistry services;
@@ -188,6 +191,19 @@ public class DefaultConnection implements InternalConnection, BuildActionRunner,
return new ProviderBuildResult<T>((T) results);
}
+ /**
+ * This is used by consumers 2.6-rc1 and later.
+ */
+ public BuildResult<?> runTests(InternalTestExecutionRequest testExecutionRequest, InternalCancellationToken cancellationToken, BuildParameters operationParameters)
+ throws BuildExceptionVersion1, InternalUnsupportedBuildArgumentException, IllegalStateException {
+ validateCanRun();
+ ProviderInternalTestExecutionRequest testExecutionRequestVersion2 = adapter.adapt(ProviderInternalTestExecutionRequest.class, testExecutionRequest);
+ ProviderOperationParameters providerParameters = toProviderParameters(operationParameters);
+ BuildCancellationToken buildCancellationToken = new InternalCancellationTokenAdapter(cancellationToken);
+ Object results = connection.runTests(testExecutionRequestVersion2, buildCancellationToken, providerParameters);
+ return new ProviderBuildResult<Object>(results);
+ }
+
private void validateCanRun() {
LOGGER.info("Tooling API is using target Gradle version: {}.", GradleVersion.current().getVersion());
if (!JavaVersion.current().isJava6Compatible()) {
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LauncherServices.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LauncherServices.java
index b3a8070..4766373 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LauncherServices.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LauncherServices.java
@@ -36,6 +36,9 @@ public class LauncherServices implements PluginServiceRegistry {
registration.addProvider(new ToolingGlobalScopeServices());
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new ToolingBuildScopeServices());
}
@@ -47,8 +50,8 @@ public class LauncherServices implements PluginServiceRegistry {
}
static class ToolingGlobalScopeServices {
- BuildExecuter createBuildExecuter(GradleLauncherFactory gradleLauncherFactory, ServiceRegistry services, ListenerManager listenerManager, FileWatcherFactory fileWatcherFactory, ExecutorFactory executorFactory, StyledTextOutputFactory styledTextOutputFactory) {
- List<BuildActionRunner> buildActionRunners = services.getAll(BuildActionRunner.class);
+ BuildExecuter createBuildExecuter(GradleLauncherFactory gradleLauncherFactory, ServiceRegistry globalServices, ListenerManager listenerManager, FileWatcherFactory fileWatcherFactory, ExecutorFactory executorFactory, StyledTextOutputFactory styledTextOutputFactory) {
+ List<BuildActionRunner> buildActionRunners = globalServices.getAll(BuildActionRunner.class);
BuildActionExecuter<BuildActionParameters> delegate = new InProcessBuildActionExecuter(gradleLauncherFactory, new ChainingBuildActionRunner(buildActionRunners));
return new ContinuousBuildActionExecuter(delegate, fileWatcherFactory, listenerManager, styledTextOutputFactory, executorFactory);
}
@@ -64,6 +67,7 @@ public class LauncherServices implements PluginServiceRegistry {
JarCache createJarCache() {
return new JarCache();
}
+
}
static class ToolingBuildScopeServices {
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuter.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuter.java
index 62b10e7..49fa2d4 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuter.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuter.java
@@ -18,6 +18,7 @@ package org.gradle.tooling.internal.provider;
import org.gradle.internal.invocation.BuildAction;
import org.gradle.initialization.BuildRequestContext;
import org.gradle.internal.Factory;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.exec.BuildActionExecuter;
import org.gradle.logging.LoggingManagerInternal;
import org.gradle.logging.internal.OutputEvent;
@@ -40,7 +41,7 @@ public class LoggingBridgingBuildActionExecuter implements BuildActionExecuter<P
this.loggingManagerFactory = loggingManagerFactory;
}
- public Object execute(BuildAction action, BuildRequestContext buildRequestContext, ProviderOperationParameters actionParameters) {
+ public Object execute(BuildAction action, BuildRequestContext buildRequestContext, ProviderOperationParameters actionParameters, ServiceRegistry contextServices) {
LoggingManagerInternal loggingManager = loggingManagerFactory.create();
loggingManager.removeAllOutputEventListeners();
if (Boolean.TRUE.equals(actionParameters.isColorOutput(null)) && actionParameters.getStandardOutput() != null) {
@@ -59,7 +60,7 @@ public class LoggingBridgingBuildActionExecuter implements BuildActionExecuter<P
loggingManager.setLevel(actionParameters.getBuildLogLevel());
loggingManager.start();
try {
- return executer.execute(action, buildRequestContext, actionParameters);
+ return executer.execute(action, buildRequestContext, actionParameters, contextServices);
} finally {
loggingManager.removeAllOutputEventListeners();
loggingManager.stop();
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ProviderConnection.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ProviderConnection.java
index be236a6..1a06fe7 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ProviderConnection.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/ProviderConnection.java
@@ -21,11 +21,13 @@ import org.gradle.api.logging.LogLevel;
import org.gradle.initialization.*;
import org.gradle.internal.Factory;
import org.gradle.internal.invocation.BuildAction;
+import org.gradle.internal.jvm.Jvm;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.launcher.cli.converter.LayoutToPropertiesConverter;
import org.gradle.launcher.cli.converter.PropertiesToDaemonParametersConverter;
import org.gradle.launcher.daemon.client.DaemonClient;
import org.gradle.launcher.daemon.client.DaemonClientFactory;
+import org.gradle.launcher.daemon.client.JvmVersionDetector;
import org.gradle.launcher.daemon.configuration.DaemonParameters;
import org.gradle.launcher.exec.BuildActionExecuter;
import org.gradle.launcher.exec.BuildActionParameters;
@@ -44,6 +46,7 @@ import org.gradle.tooling.internal.protocol.ModelIdentifier;
import org.gradle.tooling.internal.protocol.events.InternalProgressEvent;
import org.gradle.tooling.internal.provider.connection.ProviderConnectionParameters;
import org.gradle.tooling.internal.provider.connection.ProviderOperationParameters;
+import org.gradle.tooling.internal.provider.test.ProviderInternalTestExecutionRequest;
import org.gradle.util.GradleVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,12 +62,17 @@ public class ProviderConnection {
private final LoggingServiceRegistry loggingServices;
private final DaemonClientFactory daemonClientFactory;
private final BuildActionExecuter<BuildActionParameters> embeddedExecutor;
+ private final ServiceRegistry sharedServices;
+ private final JvmVersionDetector jvmVersionDetector;
- public ProviderConnection(LoggingServiceRegistry loggingServices, DaemonClientFactory daemonClientFactory, BuildActionExecuter<BuildActionParameters> embeddedExecutor, PayloadSerializer payloadSerializer) {
+ public ProviderConnection(ServiceRegistry sharedServices, LoggingServiceRegistry loggingServices, DaemonClientFactory daemonClientFactory,
+ BuildActionExecuter<BuildActionParameters> embeddedExecutor, PayloadSerializer payloadSerializer, JvmVersionDetector jvmVersionDetector) {
this.loggingServices = loggingServices;
this.daemonClientFactory = daemonClientFactory;
this.embeddedExecutor = embeddedExecutor;
this.payloadSerializer = payloadSerializer;
+ this.sharedServices = sharedServices;
+ this.jvmVersionDetector = jvmVersionDetector;
}
public void configure(ProviderConnectionParameters parameters) {
@@ -90,7 +98,7 @@ public class ProviderConnection {
return new DefaultBuildEnvironment(
params.gradleUserhome,
GradleVersion.current().getVersion(),
- params.daemonParams.getEffectiveJavaHome(),
+ params.daemonParams.getEffectiveJvm().getJavaHome(),
params.daemonParams.getEffectiveJvmArgs());
}
@@ -109,11 +117,19 @@ public class ProviderConnection {
return run(action, cancellationToken, listenerConfig, providerParameters, params);
}
+ public Object runTests(ProviderInternalTestExecutionRequest testExecutionRequest, BuildCancellationToken cancellationToken, ProviderOperationParameters providerParameters) {
+ Parameters params = initParams(providerParameters);
+ StartParameter startParameter = new ProviderStartParameterConverter().toStartParameter(providerParameters, params.properties);
+ ProgressListenerConfiguration listenerConfig = ProgressListenerConfiguration.from(providerParameters);
+ TestExecutionRequestAction action = TestExecutionRequestAction.create(listenerConfig.clientSubscriptions, startParameter, testExecutionRequest);
+ return run(action, cancellationToken, listenerConfig, providerParameters, params);
+ }
+
private Object run(BuildAction action, BuildCancellationToken cancellationToken, ProgressListenerConfiguration progressListenerConfiguration, ProviderOperationParameters providerParameters, Parameters parameters) {
try {
BuildActionExecuter<ProviderOperationParameters> executer = createExecuter(providerParameters, parameters);
BuildRequestContext buildRequestContext = new DefaultBuildRequestContext(new DefaultBuildRequestMetaData(providerParameters.getStartTime()), cancellationToken, progressListenerConfiguration.buildEventConsumer);
- BuildActionResult result = (BuildActionResult) executer.execute(action, buildRequestContext, providerParameters);
+ BuildActionResult result = (BuildActionResult) executer.execute(action, buildRequestContext, providerParameters, sharedServices);
if (result.failure != null) {
throw (RuntimeException) payloadSerializer.deserialize(result.failure);
}
@@ -157,10 +173,15 @@ public class ProviderConnection {
}
//override the params with the explicit settings provided by the tooling api
- List<String> defaultJvmArgs = daemonParams.getAllJvmArgs();
- daemonParams.setJvmArgs(operationParameters.getJvmArguments(defaultJvmArgs));
- File defaultJavaHome = daemonParams.getEffectiveJavaHome();
- daemonParams.setJavaHome(operationParameters.getJavaHome(defaultJavaHome));
+ List<String> jvmArguments = operationParameters.getJvmArguments(null);
+ if (jvmArguments != null) {
+ daemonParams.setJvmArgs(jvmArguments);
+ }
+ File javaHome = operationParameters.getJavaHome(null);
+ if (javaHome != null) {
+ daemonParams.setJvm(Jvm.forHome(javaHome));
+ }
+ daemonParams.applyDefaultsFor(jvmVersionDetector.getJavaVersion(daemonParams.getEffectiveJvm()));
if (operationParameters.getDaemonMaxIdleTimeValue() != null && operationParameters.getDaemonMaxIdleTimeUnits() != null) {
int idleTimeout = (int) operationParameters.getDaemonMaxIdleTimeUnits().toMillis(operationParameters.getDaemonMaxIdleTimeValue());
@@ -215,9 +236,28 @@ public class ProviderConnection {
boolean listenToBuildProgress = buildProgressListener != null && buildProgressListener.getSubscribedOperations().contains(InternalBuildProgressListener.BUILD_EXECUTION);
BuildClientSubscriptions clientSubscriptions = new BuildClientSubscriptions(listenToTestProgress, listenToTaskProgress, listenToBuildProgress);
FailsafeBuildProgressListenerAdapter wrapper = new FailsafeBuildProgressListenerAdapter(buildProgressListener);
- BuildEventConsumer buildEventConsumer = clientSubscriptions.isSendAnyProgressEvents()
- ? new BuildProgressListenerInvokingBuildEventConsumer(wrapper) : new NoOpBuildEventConsumer();
+ BuildEventConsumer buildEventConsumer = clientSubscriptions.isSendAnyProgressEvents() ? new BuildProgressListenerInvokingBuildEventConsumer(wrapper) : new NoOpBuildEventConsumer();
+ if (Boolean.TRUE.equals(providerParameters.isEmbedded())) {
+ // Contract requires build events are delivered by a single thread. This is taken care of by the daemon client when not in embedded mode
+ // Need to apply some synchronization when in embedded mode
+ buildEventConsumer = new SynchronizedConsumer(buildEventConsumer);
+ }
return new ProgressListenerConfiguration(clientSubscriptions, buildEventConsumer, wrapper);
}
+
+ private static class SynchronizedConsumer implements BuildEventConsumer {
+ private final BuildEventConsumer delegate;
+
+ public SynchronizedConsumer(BuildEventConsumer delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void dispatch(Object message) {
+ synchronized (this) {
+ delegate.dispatch(message);
+ }
+ }
+ }
}
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/SubscribableBuildAction.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/SubscribableBuildAction.java
new file mode 100644
index 0000000..1b0626a
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/SubscribableBuildAction.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider;
+
+import org.gradle.internal.invocation.BuildAction;
+
+import java.io.Serializable;
+
+public abstract class SubscribableBuildAction implements BuildAction, Serializable {
+ private final BuildClientSubscriptions clientSubscriptions;
+
+ public SubscribableBuildAction(BuildClientSubscriptions clientSubscriptions) {
+ this.clientSubscriptions = clientSubscriptions;
+ }
+
+ public BuildClientSubscriptions getClientSubscriptions() {
+ return clientSubscriptions;
+ }
+
+}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/TestExecutionRequestAction.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/TestExecutionRequestAction.java
new file mode 100644
index 0000000..227e65d
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/TestExecutionRequestAction.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider;
+
+import com.google.common.collect.ImmutableSet;
+import org.gradle.StartParameter;
+import org.gradle.api.Transformer;
+import org.gradle.tooling.internal.protocol.events.InternalTestDescriptor;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+import org.gradle.tooling.internal.provider.test.ProviderInternalJvmTestRequest;
+import org.gradle.tooling.internal.provider.test.ProviderInternalTestExecutionRequest;
+import org.gradle.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class TestExecutionRequestAction extends SubscribableBuildAction {
+ private final StartParameter startParameter;
+ private final Set<InternalTestDescriptor> testDescriptors;
+ private final Set<String> classNames;
+ private final Set<InternalJvmTestRequest> internalJvmTestRequests;
+
+ private TestExecutionRequestAction(BuildClientSubscriptions clientSubscriptions, StartParameter startParameter, ImmutableSet<InternalTestDescriptor> testDescriptors, Set<String> providerClassNames, Set<InternalJvmTestRequest> internalJvmTestRequests) {
+ super(clientSubscriptions);
+ this.startParameter = startParameter;
+ this.testDescriptors = testDescriptors;
+ this.classNames = providerClassNames;
+ this.internalJvmTestRequests = internalJvmTestRequests;
+ }
+
+ // Unpacks the request to serialize across to the daemon and craetes instance of
+ // TestExecutionRequestAction
+ public static TestExecutionRequestAction create(BuildClientSubscriptions clientSubscriptions, StartParameter startParameter, ProviderInternalTestExecutionRequest testExecutionRequest) {
+ final Collection<String> testClassNames = testExecutionRequest.getTestClassNames();
+ final Collection<InternalJvmTestRequest> internalJvmTestRequests = testExecutionRequest.getInternalJvmTestRequests(Collections.<InternalJvmTestRequest>emptyList());
+ Set<InternalJvmTestRequest> providerInternalJvmTestRequests = ImmutableSet.copyOf(toProviderInternalJvmTestRequest(internalJvmTestRequests, testClassNames));
+ return new TestExecutionRequestAction(clientSubscriptions, startParameter,
+ ImmutableSet.copyOf(testExecutionRequest.getTestExecutionDescriptors()),
+ ImmutableSet.copyOf(testClassNames),
+ providerInternalJvmTestRequests);
+ }
+
+ private static List<InternalJvmTestRequest> toProviderInternalJvmTestRequest(Collection<InternalJvmTestRequest> internalJvmTestRequests, Collection<String> testClassNames) {
+ // handle consumer < 2.7
+ if(internalJvmTestRequests.isEmpty()){
+ return CollectionUtils.collect(testClassNames, new Transformer<InternalJvmTestRequest, String>() {
+ @Override
+ public InternalJvmTestRequest transform(String testClass) {
+ return new ProviderInternalJvmTestRequest(testClass, null);
+ }
+ });
+ } else {
+ return CollectionUtils.collect(internalJvmTestRequests, new Transformer<InternalJvmTestRequest, InternalJvmTestRequest>() {
+ @Override
+ public InternalJvmTestRequest transform(InternalJvmTestRequest internalTestMethod) {
+ return new ProviderInternalJvmTestRequest(internalTestMethod.getClassName(), internalTestMethod.getMethodName());
+ }
+ });
+ }
+ }
+
+ @Override
+ public StartParameter getStartParameter() {
+ return startParameter;
+ }
+
+ public Collection<String> getTestClassNames() {
+ return classNames;
+ }
+
+ public Collection<InternalJvmTestRequest> getInternalJvmTestRequests() {
+ return internalJvmTestRequests;
+ }
+
+ public Collection<InternalTestDescriptor> getTestExecutionDescriptors() {
+ return testDescriptors;
+ }
+}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/connection/ProviderOperationParameters.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/connection/ProviderOperationParameters.java
index 26d59f0..8c5a223 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/connection/ProviderOperationParameters.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/connection/ProviderOperationParameters.java
@@ -28,6 +28,8 @@ import java.util.concurrent.TimeUnit;
/**
* Defines what information is needed on the provider side regarding the build operation.
+ *
+ * This is used as an adapter over the {@link org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters} instance provided by the consumer.
*/
public interface ProviderOperationParameters {
boolean getVerboseLogging(boolean defaultValue);
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/events/DefaultTestDescriptor.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/events/DefaultTestDescriptor.java
index 020a7b0..1ff25cd 100644
--- a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/events/DefaultTestDescriptor.java
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/events/DefaultTestDescriptor.java
@@ -31,8 +31,9 @@ public class DefaultTestDescriptor implements Serializable, InternalJvmTestDescr
private final String className;
private final String methodName;
private final Object parentId;
+ private String taskPath;
- public DefaultTestDescriptor(Object id, String name, String displayName, String testKind, String suiteName, String className, String methodName, Object parentId) {
+ public DefaultTestDescriptor(Object id, String name, String displayName, String testKind, String suiteName, String className, String methodName, Object parentId, String taskPath) {
this.id = id;
this.name = name;
this.displayName = displayName;
@@ -41,6 +42,7 @@ public class DefaultTestDescriptor implements Serializable, InternalJvmTestDescr
this.className = className;
this.methodName = methodName;
this.parentId = parentId;
+ this.taskPath = taskPath;
}
@Override
@@ -83,4 +85,7 @@ public class DefaultTestDescriptor implements Serializable, InternalJvmTestDescr
return parentId;
}
+ public String getTaskPath() {
+ return taskPath;
+ }
}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/test/ProviderInternalJvmTestRequest.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/test/ProviderInternalJvmTestRequest.java
new file mode 100644
index 0000000..926d49f
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/test/ProviderInternalJvmTestRequest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.test;
+
+import org.gradle.api.Nullable;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+
+import java.io.Serializable;
+
+public class ProviderInternalJvmTestRequest implements InternalJvmTestRequest, Serializable {
+ private final String className;
+ private final String methodName;
+
+ public ProviderInternalJvmTestRequest(String className, @Nullable String methodName) {
+ this.className = className;
+ this.methodName = methodName;
+ }
+
+ @Override
+ public String getClassName() {
+ return className;
+ }
+
+ @Override
+ public String getMethodName() {
+ return methodName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ProviderInternalJvmTestRequest that = (ProviderInternalJvmTestRequest) o;
+
+ if (className != null ? !className.equals(that.className) : that.className != null) {
+ return false;
+ }
+ return !(methodName != null ? !methodName.equals(that.methodName) : that.methodName != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = className != null ? className.hashCode() : 0;
+ result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/test/ProviderInternalTestExecutionRequest.java b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/test/ProviderInternalTestExecutionRequest.java
new file mode 100644
index 0000000..c1689ff
--- /dev/null
+++ b/subprojects/launcher/src/main/java/org/gradle/tooling/internal/provider/test/ProviderInternalTestExecutionRequest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.test;
+
+import org.gradle.tooling.internal.protocol.events.InternalTestDescriptor;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+
+import java.util.Collection;
+
+/**
+ * @since 2.7-rc-1
+ */
+public interface ProviderInternalTestExecutionRequest {
+ Collection<InternalTestDescriptor> getTestExecutionDescriptors();
+ Collection<String> getTestClassNames();
+ Collection<InternalJvmTestRequest> getInternalJvmTestRequests(Collection<InternalJvmTestRequest> defaults);
+}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/BuildActionsFactoryTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/BuildActionsFactoryTest.groovy
index 0c917de..001a1d3 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/BuildActionsFactoryTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/BuildActionsFactoryTest.groovy
@@ -20,9 +20,10 @@ import org.gradle.cli.CommandLineParser
import org.gradle.cli.SystemPropertiesCommandLineConverter
import org.gradle.initialization.DefaultCommandLineConverter
import org.gradle.initialization.LayoutCommandLineConverter
+import org.gradle.integtests.fixtures.AvailableJavaHomes
import org.gradle.internal.invocation.BuildActionRunner
-import org.gradle.internal.os.OperatingSystem
import org.gradle.internal.service.ServiceRegistry
+import org.gradle.internal.service.scopes.PluginServiceRegistry
import org.gradle.launcher.cli.converter.DaemonCommandLineConverter
import org.gradle.launcher.cli.converter.LayoutToPropertiesConverter
import org.gradle.launcher.cli.converter.PropertiesToDaemonParametersConverter
@@ -30,6 +31,7 @@ import org.gradle.launcher.cli.converter.PropertiesToStartParameterConverter
import org.gradle.launcher.daemon.bootstrap.ForegroundDaemonAction
import org.gradle.launcher.daemon.client.DaemonClient
import org.gradle.launcher.daemon.client.SingleUseDaemonClient
+import org.gradle.launcher.daemon.configuration.DaemonParameters
import org.gradle.launcher.exec.DaemonUsageSuggestingBuildActionExecuter
import org.gradle.logging.ProgressLoggerFactory
import org.gradle.logging.StyledTextOutputFactory
@@ -38,6 +40,7 @@ import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.util.SetSystemProperties
import org.gradle.util.UsesNativeServices
import org.junit.Rule
+import spock.lang.IgnoreIf
import spock.lang.Specification
@UsesNativeServices
@@ -62,6 +65,7 @@ class BuildActionsFactoryTest extends Specification {
_ * loggingServices.get(ProgressLoggerFactory) >> Mock(ProgressLoggerFactory)
_ * loggingServices.getAll(BuildActionRunner) >> []
_ * loggingServices.get(StyledTextOutputFactory) >> Mock(StyledTextOutputFactory)
+ _ * loggingServices.getAll(PluginServiceRegistry) >> []
}
def "check that --max-workers overrides org.gradle.workers.max"() {
@@ -124,11 +128,11 @@ class BuildActionsFactoryTest extends Specification {
action instanceof ForegroundDaemonAction
}
+ @IgnoreIf({ AvailableJavaHomes.differentJdk == null })
def "executes with single use daemon if java home is not current"() {
given:
- def javaHome = tmpDir.createDir("javahome")
- javaHome.createFile(OperatingSystem.current().getExecutableName("bin/java"))
- propertiesToDaemonParametersConverter.convert(_, _) >> { args -> args[1].javaHome = javaHome }
+ def jvm = AvailableJavaHomes.differentJdk
+ propertiesToDaemonParametersConverter.convert(_, _) >> { Map p, DaemonParameters params -> params.jvm = jvm }
when:
def action = convert()
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/RunBuildActionTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/RunBuildActionTest.groovy
index 3f2a929..93a1555 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/RunBuildActionTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/RunBuildActionTest.groovy
@@ -20,6 +20,7 @@ import org.gradle.api.logging.LogLevel
import org.gradle.initialization.BuildClientMetaData
import org.gradle.initialization.BuildRequestContext
import org.gradle.initialization.DefaultBuildCancellationToken
+import org.gradle.internal.service.ServiceRegistry
import org.gradle.launcher.exec.BuildActionExecuter
import org.gradle.launcher.exec.BuildActionParameters
import spock.lang.Specification
@@ -32,7 +33,8 @@ class RunBuildActionTest extends Specification {
final long startTime = 90
final Map<String, String> systemProperties = [key: 'value']
final BuildActionParameters parameters = Mock()
- final RunBuildAction action = new RunBuildAction(client, startParameter, clientMetaData, startTime, parameters)
+ final ServiceRegistry sharedServices = Mock()
+ final RunBuildAction action = new RunBuildAction(client, startParameter, clientMetaData, startTime, parameters, sharedServices)
def runsBuildUsingDaemon() {
when:
@@ -40,12 +42,13 @@ class RunBuildActionTest extends Specification {
then:
startParameter.logLevel >> LogLevel.ERROR
- 1 * client.execute({!null}, {!null}, {!null}) >> { ExecuteBuildAction action, BuildRequestContext context, BuildActionParameters build ->
+ 1 * client.execute({!null}, {!null}, {!null}, {!null}) >> { ExecuteBuildAction action, BuildRequestContext context, BuildActionParameters build, ServiceRegistry services ->
assert action.startParameter == startParameter
assert context.cancellationToken instanceof DefaultBuildCancellationToken
assert context.client == clientMetaData
assert context.buildTimeClock.startTime == startTime
assert build == parameters
+ assert services == sharedServices
}
0 * _._
}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverterTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverterTest.groovy
index 51df6ef..0f261d5 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverterTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/cli/converter/PropertiesToDaemonParametersConverterTest.groovy
@@ -71,7 +71,7 @@ class PropertiesToDaemonParametersConverterTest extends Specification {
then:
params.effectiveJvmArgs.contains("-Xmx256m")
params.debug
- params.effectiveJavaHome == Jvm.current().javaHome
+ params.effectiveJvm == Jvm.current()
params.daemonUsage == EXPLICITLY_ENABLED
params.baseDir == new File("baseDir").absoluteFile
params.idleTimeout == 115
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientConnectionTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientConnectionTest.groovy
index c3e9b25..e75a76a 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientConnectionTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientConnectionTest.groovy
@@ -17,6 +17,7 @@
package org.gradle.launcher.daemon.client
import org.gradle.launcher.daemon.context.DaemonInstanceDetails
+import org.gradle.launcher.daemon.protocol.Message
import org.gradle.messaging.remote.internal.MessageIOException
import org.gradle.messaging.remote.internal.RemoteConnection
import spock.lang.Specification
@@ -44,34 +45,39 @@ class DaemonClientConnectionTest extends Specification {
}
def "dispatches messages"() {
+ def message = Stub(Message)
+
when:
- connection.dispatch("foo")
+ connection.dispatch(message)
then:
- 1 * delegate.dispatch("foo")
+ 1 * delegate.dispatch(message)
0 * staleAddressDetector._
}
def "receives messages"() {
+ def message = Stub(Message)
+
given:
- delegate.receive() >> "bar"
+ delegate.receive() >> message
when:
def out = connection.receive()
then:
- "bar" == out
+ out == message
0 * staleAddressDetector._
}
def "treats failure to dispatch before receiving as a stale address"() {
+ def message = Stub(Message)
def failure = new FooException()
given:
- delegate.dispatch("foo") >> { throw failure }
+ delegate.dispatch(message) >> { throw failure }
when:
- connection.dispatch("foo")
+ connection.dispatch(message)
then:
def ex = thrown(StaleDaemonAddressException)
@@ -82,14 +88,15 @@ class DaemonClientConnectionTest extends Specification {
def "handles failed dispatch"() {
def failure = new FooException()
+ def message = Stub(Message)
given:
- delegate.receive() >> "result"
- delegate.dispatch("broken") >> { throw failure }
+ delegate.receive() >> Stub(Message)
+ delegate.dispatch(message) >> { throw failure }
when:
connection.receive()
- connection.dispatch("broken")
+ connection.dispatch(message)
then:
def ex = thrown(DaemonConnectionException)
@@ -118,7 +125,7 @@ class DaemonClientConnectionTest extends Specification {
def failure = new FooException()
given:
- 1 * delegate.receive() >> "first"
+ 1 * delegate.receive() >> Stub(Message)
delegate.receive() >> { throw failure }
when:
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientInputForwarderTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientInputForwarderTest.groovy
index 7cd2a18..4bb2ce1 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientInputForwarderTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientInputForwarderTest.groovy
@@ -15,7 +15,6 @@
*/
package org.gradle.launcher.daemon.client
-import org.gradle.internal.id.IdGenerator
import org.gradle.launcher.daemon.protocol.CloseInput
import org.gradle.launcher.daemon.protocol.ForwardInput
import org.gradle.messaging.dispatch.Dispatch
@@ -54,7 +53,7 @@ class DaemonClientInputForwarderTest extends ConcurrentSpecification {
def forwarder
def createForwarder() {
- forwarder = new DaemonClientInputForwarder(inputStream, dispatch, executorFactory, { 12 } as IdGenerator, bufferSize)
+ forwarder = new DaemonClientInputForwarder(inputStream, dispatch, executorFactory, bufferSize)
forwarder.start()
}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientServicesTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientServicesTest.groovy
index 77e08ea..ab3e010 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientServicesTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientServicesTest.groovy
@@ -37,6 +37,7 @@ class DaemonClientServicesTest extends Specification {
.parent(LoggingServiceRegistry.newEmbeddableLogging())
.parent(NativeServicesTestFixture.instance)
.provider(new GlobalScopeServices(false))
+ .provider(new DaemonClientGlobalServices())
.build()
final services = new DaemonClientServices(parentServices, parameters, System.in)
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientTest.groovy
index fce0ffa..716f621 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/DaemonClientTest.groovy
@@ -16,10 +16,11 @@
package org.gradle.launcher.daemon.client
import org.gradle.api.BuildCancelledException
-import org.gradle.internal.invocation.BuildAction
import org.gradle.initialization.BuildCancellationToken
import org.gradle.initialization.BuildRequestContext
import org.gradle.internal.id.IdGenerator
+import org.gradle.internal.invocation.BuildAction
+import org.gradle.internal.service.ServiceRegistry
import org.gradle.launcher.daemon.context.DaemonCompatibilitySpec
import org.gradle.launcher.daemon.protocol.*
import org.gradle.launcher.daemon.server.api.DaemonStoppedException
@@ -37,7 +38,7 @@ class DaemonClientTest extends ConcurrentSpecification {
def executesAction() {
when:
- def result = client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters))
+ def result = client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
result == '[result]'
@@ -55,7 +56,7 @@ class DaemonClientTest extends ConcurrentSpecification {
RuntimeException failure = new RuntimeException()
when:
- client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters))
+ client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
RuntimeException e = thrown()
@@ -63,7 +64,7 @@ class DaemonClientTest extends ConcurrentSpecification {
1 * connector.connect(compatibilitySpec) >> connection
_ * connection.daemon
1 * connection.dispatch({it instanceof Build})
- 2 * connection.receive() >>> [Stub(BuildStarted), new CommandFailure(failure)]
+ 2 * connection.receive() >>> [Stub(BuildStarted), new Failure(failure)]
1 * connection.dispatch({it instanceof CloseInput})
1 * connection.dispatch({it instanceof Finished})
1 * connection.stop()
@@ -77,7 +78,7 @@ class DaemonClientTest extends ConcurrentSpecification {
}
when:
- client.execute(Stub(BuildAction), buildRequestContext, Stub(BuildActionParameters))
+ client.execute(Stub(BuildAction), buildRequestContext, Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
BuildCancelledException gce = thrown()
@@ -89,7 +90,7 @@ class DaemonClientTest extends ConcurrentSpecification {
}
1 * connection.dispatch({it instanceof Build})
- 2 * connection.receive() >>> [ Stub(BuildStarted), new CommandFailure(new DaemonStoppedException())]
+ 2 * connection.receive() >>> [ Stub(BuildStarted), new Failure(new DaemonStoppedException())]
1 * connection.dispatch({it instanceof Cancel})
1 * connection.dispatch({it instanceof CloseInput})
1 * connection.dispatch({it instanceof Finished})
@@ -107,7 +108,7 @@ class DaemonClientTest extends ConcurrentSpecification {
}
when:
- client.execute(Stub(BuildAction), buildRequestContext, Stub(BuildActionParameters))
+ client.execute(Stub(BuildAction), buildRequestContext, Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
BuildCancelledException gce = thrown()
@@ -122,7 +123,7 @@ class DaemonClientTest extends ConcurrentSpecification {
1 * cancellationToken.removeCallback(_)
1 * connection.dispatch({it instanceof Build})
- 2 * connection.receive() >>> [ Stub(BuildStarted), new CommandFailure(cancelledException)]
+ 2 * connection.receive() >>> [ Stub(BuildStarted), new Failure(cancelledException)]
1 * connection.dispatch({it instanceof Cancel})
1 * connection.dispatch({it instanceof CloseInput})
1 * connection.dispatch({it instanceof Finished})
@@ -134,7 +135,7 @@ class DaemonClientTest extends ConcurrentSpecification {
DaemonClientConnection connection2 = Mock()
when:
- client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters))
+ client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
2 * connector.connect(compatibilitySpec) >>> [connection, connection2]
@@ -150,7 +151,7 @@ class DaemonClientTest extends ConcurrentSpecification {
DaemonClientConnection connection2 = Mock()
when:
- client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters))
+ client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
2 * connector.connect(compatibilitySpec) >>> [connection, connection2]
@@ -168,7 +169,7 @@ class DaemonClientTest extends ConcurrentSpecification {
DaemonClientConnection connection2 = Mock()
when:
- client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters))
+ client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
2 * connector.connect(compatibilitySpec) >>> [connection, connection2]
@@ -187,7 +188,7 @@ class DaemonClientTest extends ConcurrentSpecification {
connection.receive() >> Mock(DaemonUnavailable)
when:
- client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters))
+ client.execute(Stub(BuildAction), Stub(BuildRequestContext), Stub(BuildActionParameters), Stub(ServiceRegistry))
then:
thrown(NoUsableDaemonFoundException)
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/JvmVersionDetectorTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/JvmVersionDetectorTest.groovy
new file mode 100644
index 0000000..e3b47ae
--- /dev/null
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/JvmVersionDetectorTest.groovy
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.launcher.daemon.client
+
+import org.gradle.api.JavaVersion
+import org.gradle.internal.jvm.Jvm
+import spock.lang.Specification
+
+class JvmVersionDetectorTest extends Specification {
+ def detector = new JvmVersionDetector()
+
+ def "can determine version of current jvm"() {
+ expect:
+ detector.getJavaVersion(Jvm.current()) == JavaVersion.current()
+ }
+
+ def "can parse version number"() {
+ expect:
+ detector.parseJavaVersionCommandOutput("/usr/bin/java", new BufferedReader(new StringReader(output))) == JavaVersion.toVersion(version)
+
+ where:
+ output | version
+ 'java version "1.5"' | "1.5"
+ 'java version "1.5"\ntrailers' | "1.5"
+ 'headers\njava version "1.5"' | "1.5"
+ 'java version "1.5"\r\ntrailers' | "1.5"
+ 'headers\r\njava version "1.5"' | "1.5"
+ 'java version "1.8.0_11"' | "1.8"
+ 'openjdk version "1.8.0-internal"' | "1.8"
+ """java version "1.9.0-ea"
+Java(TM) SE Runtime Environment (build 1.9.0-ea-b53)
+Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b53, mixed mode)
+""" | "1.9"
+ }
+
+ def "fails to parse version number"() {
+ when:
+ detector.parseJavaVersionCommandOutput("/usr/bin/java", new BufferedReader(new StringReader(output)))
+
+ then:
+ RuntimeException e = thrown()
+ e.message == "Could not determine Java version using executable /usr/bin/java."
+
+ where:
+ output << [
+ '',
+ '\n',
+ 'foo',
+ 'foo\nbar',
+ 'foo\r\nbar'
+ ]
+ }
+}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/JvmVersionValidatorTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/JvmVersionValidatorTest.groovy
deleted file mode 100644
index c7a11d7..0000000
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/client/JvmVersionValidatorTest.groovy
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.launcher.daemon.client
-
-import org.gradle.api.JavaVersion
-import spock.lang.Specification
-
-class JvmVersionValidatorTest extends Specification {
-
- def "can parse version number"() {
- expect:
- JvmVersionValidator.parseJavaVersionCommandOutput(new BufferedReader(new StringReader(output))) == JavaVersion.toVersion("1.5")
-
- where:
- output << [
- 'java version "1.5"',
- 'java version "1.5"\ntrailers',
- 'headers\njava version "1.5"',
- 'java version "1.5"\r\ntrailers',
- 'headers\r\njava version "1.5"',
- ]
- }
-
- def "can parse version number for Java 8 "() {
- expect:
- JvmVersionValidator.parseJavaVersionCommandOutput(new BufferedReader(new StringReader(output))) == JavaVersion.toVersion("1.8")
-
- where:
- output << [
- 'java version "1.8.0_11"',
- 'openjdk version "1.8.0-internal"',
- ]
- }
-
- def "fails to parse version number"() {
- when:
- JvmVersionValidator.parseJavaVersionCommandOutput(new BufferedReader(new StringReader(output)))
-
- then:
- thrown RuntimeException
-
- where:
- output << [
- '',
- '\n',
- 'foo',
- 'foo\nbar',
- 'foo\r\nbar'
- ]
- }
-}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/CurrentProcessTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/CurrentProcessTest.groovy
index efef3c2..16b1ab6 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/CurrentProcessTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/CurrentProcessTest.groovy
@@ -18,6 +18,7 @@ package org.gradle.launcher.daemon.configuration
import org.gradle.api.internal.file.FileResolver
import org.gradle.initialization.BuildLayoutParameters
+import org.gradle.internal.jvm.JavaInfo
import org.gradle.process.internal.JvmOptions
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.util.SetSystemProperties
@@ -35,22 +36,22 @@ public class CurrentProcessTest extends Specification {
final SetSystemProperties systemPropertiesSet = new SetSystemProperties()
private FileResolver fileResolver = Mock()
- private def currentJavaHome = tmpDir.file('java_home')
+ private def currentJvm = Stub(JavaInfo)
private JvmOptions currentJvmOptions = new JvmOptions(fileResolver)
def "can only run build with identical java home"() {
when:
- CurrentProcess currentProcess = new CurrentProcess(currentJavaHome, currentJvmOptions)
+ CurrentProcess currentProcess = new CurrentProcess(currentJvm, currentJvmOptions)
then:
- currentProcess.configureForBuild(buildParameters(currentJavaHome))
- !currentProcess.configureForBuild(buildParameters(tmpDir.file('other')))
+ currentProcess.configureForBuild(buildParameters(currentJvm))
+ !currentProcess.configureForBuild(buildParameters(Stub(JavaInfo)))
}
def "can only run build when no immutable jvm arguments specified"() {
when:
currentJvmOptions.setAllJvmArgs(["-Xmx100m", "-XX:SomethingElse", "-Dfoo=bar", "-Dbaz"])
- CurrentProcess currentProcess = new CurrentProcess(currentJavaHome, currentJvmOptions)
+ CurrentProcess currentProcess = new CurrentProcess(currentJvm, currentJvmOptions)
then:
@@ -71,7 +72,7 @@ public class CurrentProcessTest extends Specification {
def "sets all mutable system properties before running build"() {
when:
- CurrentProcess currentProcess = new CurrentProcess(tmpDir.file('java_home'), currentJvmOptions)
+ CurrentProcess currentProcess = new CurrentProcess(currentJvm, currentJvmOptions)
def parameters = buildParameters(["-Dfoo=bar", "-Dbaz"])
then:
@@ -88,19 +89,19 @@ public class CurrentProcessTest extends Specification {
//e.g. those defaults should only be used for launching a new process
//TODO SF this is a bit messy, let's try to clean this up
when:
- CurrentProcess currentProcess = new CurrentProcess(currentJavaHome, currentJvmOptions)
+ CurrentProcess currentProcess = new CurrentProcess(currentJvm, currentJvmOptions)
then:
currentProcess.configureForBuild(buildParameters(["-Xmx1024m"]))
}
private DaemonParameters buildParameters(Iterable<String> jvmArgs) {
- return buildParameters(currentJavaHome, jvmArgs)
+ return buildParameters(currentJvm, jvmArgs)
}
- private static DaemonParameters buildParameters(File javaHome, Iterable<String> jvmArgs = []) {
+ private static DaemonParameters buildParameters(JavaInfo jvm, Iterable<String> jvmArgs = []) {
def parameters = new DaemonParameters(new BuildLayoutParameters())
- parameters.setJavaHome(javaHome)
+ parameters.setJvm(jvm)
parameters.setJvmArgs(jvmArgs)
return parameters
}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/DaemonParametersTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/DaemonParametersTest.groovy
index 1958913..e85f23d 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/DaemonParametersTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/configuration/DaemonParametersTest.groovy
@@ -15,7 +15,10 @@
*/
package org.gradle.launcher.daemon.configuration
+import org.gradle.api.JavaVersion
import org.gradle.initialization.BuildLayoutParameters
+import org.gradle.internal.jvm.JavaInfo
+import org.gradle.internal.jvm.Jvm
import org.gradle.util.UsesNativeServices
import spock.lang.Specification
@@ -35,17 +38,59 @@ class DaemonParametersTest extends Specification {
parameters.idleTimeout == DaemonParameters.DEFAULT_IDLE_TIMEOUT
parameters.baseDir == new File(new BuildLayoutParameters().getGradleUserHomeDir(), "daemon")
parameters.systemProperties.isEmpty()
- parameters.effectiveJvmArgs.containsAll(parameters.DEFAULT_JVM_ARGS)
- parameters.effectiveJvmArgs.size() == parameters.DEFAULT_JVM_ARGS.size() + 1 + 3 // + 1 because effective JVM args contains -Dfile.encoding, +3 for locale props
+ parameters.effectiveJvmArgs.size() == 1 + 3 // + 1 because effective JVM args contains -Dfile.encoding, +3 for locale props
parameters.idleTimeout == DaemonParameters.DEFAULT_IDLE_TIMEOUT
}
+ def "setting jvm to null means use the current jvm"() {
+ def jvm = Stub(JavaInfo)
+
+ when:
+ parameters.jvm = jvm
+
+ then:
+ parameters.effectiveJvm == jvm
+
+ when:
+ parameters.jvm = null
+
+ then:
+ parameters.effectiveJvm == Jvm.current()
+ }
+
def "configuring jvmargs replaces the defaults"() {
when:
parameters.setJvmArgs(["-Xmx17m"])
then:
- parameters.effectiveJvmArgs.each { assert !parameters.DEFAULT_JVM_ARGS.contains(it) }
+ parameters.effectiveJvmArgs.intersect(parameters.DEFAULT_JVM_ARGS).empty
+ }
+
+ def "does not apply defaults when jvmargs already specified"() {
+ when:
+ parameters.setJvmArgs(["-Xmx17m"])
+ parameters.applyDefaultsFor(JavaVersion.VERSION_1_8)
+
+ then:
+ parameters.effectiveJvmArgs.containsAll(["-Xmx17m"])
+ parameters.effectiveJvmArgs.intersect(parameters.DEFAULT_JVM_ARGS).empty
+ }
+
+ def "can apply defaults for Java 8 and earlier"() {
+ when:
+ parameters.applyDefaultsFor(JavaVersion.VERSION_1_8)
+
+ then:
+ parameters.effectiveJvmArgs.containsAll(DaemonParameters.DEFAULT_JVM_ARGS)
+ }
+
+ def "can apply defaults for Java 9"() {
+ when:
+ parameters.applyDefaultsFor(JavaVersion.VERSION_1_9)
+
+ then:
+ parameters.effectiveJvmArgs.containsAll(DaemonParameters.DEFAULT_JVM_9_ARGS)
+ !parameters.effectiveJvmArgs.containsAll(DaemonParameters.DEFAULT_JVM_ARGS)
}
def "can configure debug mode"() {
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/context/DaemonCompatibilitySpecSpec.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/context/DaemonCompatibilitySpecSpec.groovy
index 5b6dda3..70e25ff 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/context/DaemonCompatibilitySpecSpec.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/context/DaemonCompatibilitySpecSpec.groovy
@@ -25,7 +25,8 @@ import spock.lang.Specification
class DaemonCompatibilitySpecSpec extends Specification {
- @Rule TestNameTestDirectoryProvider tmp = new TestNameTestDirectoryProvider()
+ @Rule
+ TestNameTestDirectoryProvider tmp = new TestNameTestDirectoryProvider()
def clientConfigure = {}
def serverConfigure = {}
@@ -92,6 +93,9 @@ class DaemonCompatibilitySpecSpec extends Specification {
expect:
compatible
+
+ cleanup:
+ assert link.delete()
}
def "contexts with same daemon opts are compatible"() {
@@ -126,4 +130,4 @@ class DaemonCompatibilitySpecSpec extends Specification {
expect:
!compatible
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/protocol/DaemonMessageSerializerTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/protocol/DaemonMessageSerializerTest.groovy
new file mode 100644
index 0000000..10b872b
--- /dev/null
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/protocol/DaemonMessageSerializerTest.groovy
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.launcher.daemon.protocol
+
+import org.gradle.api.logging.LogLevel
+import org.gradle.internal.progress.OperationIdentifier
+import org.gradle.internal.serialize.Serializer
+import org.gradle.internal.serialize.SerializerSpec
+import org.gradle.logging.StyledTextOutput
+import org.gradle.logging.internal.*
+import org.gradle.messaging.remote.internal.PlaceholderException
+
+class DaemonMessageSerializerTest extends SerializerSpec {
+ def serializer = DaemonMessageSerializer.create()
+
+ def "can serialize BuildEvent messages"() {
+ expect:
+ def event = new BuildEvent(["a", "b", "c"])
+ def result = usesEfficientSerialization(event, serializer)
+ result instanceof BuildEvent
+ result.payload == ["a", "b", "c"]
+ }
+
+ def "can serialize LogEvent messages"() {
+ expect:
+ def event = new LogEvent(1234, "category", LogLevel.LIFECYCLE, "message", new RuntimeException())
+ def result = serialize(event, serializer)
+ result instanceof LogEvent
+ result.timestamp == 1234
+ result.category == "category"
+ result.logLevel == LogLevel.LIFECYCLE
+ result.message == "message"
+ result.throwable.getClass() == event.throwable.getClass()
+ result.throwable.message == event.throwable.message
+ result.throwable.stackTrace == event.throwable.stackTrace
+
+ def event2 = new LogEvent(1234, "category", LogLevel.LIFECYCLE, "message", null)
+ def result2 = serialize(event2, serializer)
+ result2 instanceof LogEvent
+ result2.timestamp == 1234
+ result2.category == "category"
+ result2.logLevel == LogLevel.LIFECYCLE
+ result2.message == "message"
+ result2.throwable == null
+ }
+
+ def "can serialize StyledTextOutputEvent messages"() {
+ expect:
+ def event = new StyledTextOutputEvent(1234, "category", LogLevel.LIFECYCLE,
+ new StyledTextOutputEvent.Span(StyledTextOutput.Style.Description, "description"),
+ new StyledTextOutputEvent.Span(StyledTextOutput.Style.Error, "error"))
+ def result = serialize(event, serializer)
+ result instanceof StyledTextOutputEvent
+ result.timestamp == 1234
+ result.category == "category"
+ result.logLevel == LogLevel.LIFECYCLE
+ result.spans.size() == 2
+ result.spans[0].style == StyledTextOutput.Style.Description
+ result.spans[0].text == "description"
+ result.spans[1].style == StyledTextOutput.Style.Error
+ result.spans[1].text == "error"
+ }
+
+ def "can serialize LogLevelChangeEvent messages"() {
+ expect:
+ def event = new LogLevelChangeEvent(LogLevel.LIFECYCLE)
+ def result = serialize(event, serializer)
+ result instanceof LogLevelChangeEvent
+ result.newLogLevel == LogLevel.LIFECYCLE
+ }
+
+ def "can serialize ProgressStartEvent messages"() {
+ expect:
+ def event = new ProgressStartEvent(new OperationIdentifier(1234L), new OperationIdentifier(5678L), 321L, "category", "description", "short", "header", "status")
+ def result = serialize(event, serializer)
+ result instanceof ProgressStartEvent
+ result.operationId == new OperationIdentifier(1234L)
+ result.parentId == new OperationIdentifier(5678L)
+ result.timestamp == 321L
+ result.category == "category"
+ result.description == "description"
+ result.shortDescription == "short"
+ result.loggingHeader == "header"
+ result.status == "status"
+
+ def event2 = new ProgressStartEvent(new OperationIdentifier(1234L), null, 321L, "category", "description", null, null, "")
+ def result2 = serialize(event2, serializer)
+ result2 instanceof ProgressStartEvent
+ result2.operationId == new OperationIdentifier(1234L)
+ result2.parentId == null
+ result2.timestamp == 321L
+ result2.category == "category"
+ result2.description == "description"
+ result2.shortDescription == null
+ result2.loggingHeader == null
+ result2.status == ""
+ }
+
+ def "can serialize ProgressCompleteEvent messages"() {
+ expect:
+ def event = new ProgressCompleteEvent(new OperationIdentifier(1234L), 321L, "category", "description", "status")
+ def result = serialize(event, serializer)
+ result instanceof ProgressCompleteEvent
+ result.operationId == new OperationIdentifier(1234L)
+ result.timestamp == 321L
+ result.category == "category"
+ result.description == "description"
+ result.status == "status"
+ }
+
+ def "can serialize ProgressEvent messages"() {
+ expect:
+ def event = new ProgressEvent(new OperationIdentifier(1234L), 321L, "category", "status")
+ def result = serialize(event, serializer)
+ result instanceof ProgressEvent
+ result.operationId == new OperationIdentifier(1234L)
+ result.timestamp == 321L
+ result.category == "category"
+ result.status == "status"
+ }
+
+ def "can serialize Failure messages"() {
+ expect:
+ def failure = new RuntimeException()
+ def message = new Failure(failure)
+ def result = serialize(message, serializer) // Throwable serialization is not more efficient than default
+ result instanceof Failure
+ result.value.getClass() == RuntimeException
+
+ def unserializable = new IOException() {
+ def thing = new Object()
+ }
+ def message2 = new Failure(unserializable)
+ def result2 = serialize(message2, serializer)
+ result2 instanceof Failure
+ result2.value instanceof PlaceholderException
+ }
+
+ def "can serialize CloseInput messages"() {
+ expect:
+ def message = new CloseInput()
+ def messageResult = usesEfficientSerialization(message, serializer)
+ messageResult instanceof CloseInput
+ }
+
+ def "can serialize ForwardInput messages"() {
+ expect:
+ def message = new ForwardInput("greetings".bytes)
+ def messageResult = usesEfficientSerialization(message, serializer)
+ messageResult instanceof ForwardInput
+ messageResult.bytes == message.bytes
+ }
+
+ def "can serialize other messages"() {
+ expect:
+ def message = new Cancel("id")
+ def messageResult = serialize(message, serializer)
+ messageResult instanceof Cancel
+ messageResult.identifier == "id"
+ }
+
+ OutputEvent serialize(OutputEvent event, Serializer<Object> serializer) {
+ def result = serialize(new OutputMessage(event), serializer)
+ assert result instanceof OutputMessage
+ return result.event
+ }
+}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServerExceptionHandlingTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServerExceptionHandlingTest.groovy
index 1f7d103..260ea6b 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServerExceptionHandlingTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServerExceptionHandlingTest.groovy
@@ -23,6 +23,7 @@ import org.gradle.initialization.BuildRequestContext
import org.gradle.internal.invocation.BuildAction
import org.gradle.internal.invocation.BuildController
import org.gradle.internal.nativeintegration.ProcessEnvironment
+import org.gradle.internal.service.ServiceRegistry
import org.gradle.launcher.daemon.client.DaemonClient
import org.gradle.launcher.daemon.client.EmbeddedDaemonClientServices
import org.gradle.launcher.daemon.client.StubDaemonHealthServices
@@ -49,6 +50,7 @@ class DaemonServerExceptionHandlingTest extends Specification {
getClient() >> new GradleLauncherMetaData()
}
def parameters = new DefaultBuildActionParameters(new HashMap(System.properties), [:], temp.testDirectory, LogLevel.ERROR, IMPLICITLY_DISABLED, false, false)
+ def contextServices = Stub(ServiceRegistry)
static class DummyLauncherAction implements BuildAction, Serializable {
StartParameter startParameter
@@ -68,7 +70,7 @@ class DaemonServerExceptionHandlingTest extends Specification {
def action = new DummyLauncherAction(someState: unloadableClass)
when:
- client.execute(action, buildRequestContext, parameters)
+ client.execute(action, buildRequestContext, parameters, contextServices)
then:
def ex = thrown(MessageIOException)
@@ -80,7 +82,7 @@ class DaemonServerExceptionHandlingTest extends Specification {
//we need to override some methods to inject a failure action into the sequence
def services = new EmbeddedDaemonClientServices() {
DaemonCommandExecuter createDaemonCommandExecuter() {
- return new DefaultDaemonCommandExecuter(get(BuildExecuter),
+ return new DefaultDaemonCommandExecuter(get(BuildExecuter), this,
get(ProcessEnvironment), getFactory(LoggingManagerInternal.class).create(),
new File("dummy"), new StubDaemonHealthServices()) {
List<DaemonCommandAction> createActions(DaemonContext daemonContext) {
@@ -104,7 +106,7 @@ class DaemonServerExceptionHandlingTest extends Specification {
}
when:
- services.get(DaemonClient).execute(new DummyLauncherAction(), buildRequestContext, parameters)
+ services.get(DaemonClient).execute(new DummyLauncherAction(), buildRequestContext, parameters, contextServices)
then:
def ex = thrown(Throwable)
@@ -120,7 +122,7 @@ class DaemonServerExceptionHandlingTest extends Specification {
}
when:
- services.get(DaemonClient).execute(new DummyLauncherAction(), buildRequestContext, parameters)
+ services.get(DaemonClient).execute(new DummyLauncherAction(), buildRequestContext, parameters, contextServices)
then:
def ex = thrown(OutOfMemoryError)
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServicesTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServicesTest.groovy
index f7b7e05..48b1d49 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServicesTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DaemonServicesTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.launcher.daemon.server
+import org.gradle.internal.classpath.ClassPath
import org.gradle.internal.nativeintegration.ProcessEnvironment
import org.gradle.launcher.daemon.configuration.DefaultDaemonServerConfiguration
import org.gradle.launcher.daemon.registry.DaemonDir
@@ -31,7 +32,7 @@ import static java.util.Arrays.asList
class DaemonServicesTest extends Specification {
@Rule TestNameTestDirectoryProvider tmp = new TestNameTestDirectoryProvider()
final DaemonServices services = new DaemonServices(new DefaultDaemonServerConfiguration("uid", tmp.testDirectory, 100, asList()),
- LoggingServiceRegistry.newEmbeddableLogging(), Mock(LoggingManagerInternal))
+ LoggingServiceRegistry.newEmbeddableLogging(), Mock(LoggingManagerInternal), Stub(ClassPath))
def "makes a DaemonDir available"() {
expect:
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DefaultDaemonConnectionTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DefaultDaemonConnectionTest.groovy
index f7510d3..0dffd6f 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DefaultDaemonConnectionTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/daemon/server/DefaultDaemonConnectionTest.groovy
@@ -36,9 +36,9 @@ class DefaultDaemonConnectionTest extends ConcurrentSpecification {
def "forwards queued input events to stdin handler until end of input received"() {
StdinHandler handler = Mock()
- def input1 = new ForwardInput(1, "hello".bytes)
- def input2 = new ForwardInput(2, "hello".bytes)
- def closeInput = new CloseInput(3)
+ def input1 = new ForwardInput("hello".bytes)
+ def input2 = new ForwardInput("hello".bytes)
+ def closeInput = new CloseInput()
def received = new CountDownLatch(1)
when:
@@ -58,7 +58,7 @@ class DefaultDaemonConnectionTest extends ConcurrentSpecification {
def "generates end of stdin event when connection disconnects"() {
StdinHandler handler = Mock()
- def input1 = new ForwardInput(1, "hello".bytes)
+ def input1 = new ForwardInput("hello".bytes)
def received = new CountDownLatch(1)
when:
@@ -87,9 +87,9 @@ class DefaultDaemonConnectionTest extends ConcurrentSpecification {
def "buffers stdin events"() {
StdinHandler handler = Mock()
- def input1 = new ForwardInput(1, "hello".bytes)
- def input2 = new ForwardInput(2, "hello".bytes)
- def closeInput = new CloseInput(3)
+ def input1 = new ForwardInput("hello".bytes)
+ def input2 = new ForwardInput("hello".bytes)
+ def closeInput = new CloseInput()
def received = new CountDownLatch(1)
when:
@@ -123,7 +123,7 @@ class DefaultDaemonConnectionTest extends ConcurrentSpecification {
def "discards queued messages on stop"() {
when:
connection.queueIncoming("incoming")
- connection.queueIncoming(new ForwardInput(1, "hello".bytes))
+ connection.queueIncoming(new ForwardInput("hello".bytes))
connection.disconnect()
daemonConnection.stop()
@@ -142,9 +142,9 @@ class DefaultDaemonConnectionTest extends ConcurrentSpecification {
def "handles failure to notify stdin handler"() {
StdinHandler handler = Mock()
- def input1 = new ForwardInput(1, "hello".bytes)
- def input2 = new ForwardInput(2, "hello".bytes)
- def closeInput = new CloseInput(3)
+ def input1 = new ForwardInput("hello".bytes)
+ def input2 = new ForwardInput("hello".bytes)
+ def closeInput = new CloseInput()
def received = new CountDownLatch(1)
when:
@@ -334,8 +334,8 @@ class DefaultDaemonConnectionTest extends ConcurrentSpecification {
def "receive ignores stdin messages"() {
when:
connection.queueIncoming("incoming1")
- connection.queueIncoming(new ForwardInput(12, "yo".bytes))
- connection.queueIncoming(new CloseInput(44))
+ connection.queueIncoming(new ForwardInput("yo".bytes))
+ connection.queueIncoming(new CloseInput())
connection.queueIncoming("incoming2")
def result = []
result << daemonConnection.receive(20, TimeUnit.SECONDS)
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/ContinuousBuildActionExecuterTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/ContinuousBuildActionExecuterTest.groovy
index 5e4f10f..d723053 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/ContinuousBuildActionExecuterTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/ContinuousBuildActionExecuterTest.groovy
@@ -26,11 +26,15 @@ import org.gradle.initialization.DefaultBuildRequestContext
import org.gradle.initialization.NoOpBuildEventConsumer
import org.gradle.initialization.ReportedException
import org.gradle.internal.concurrent.DefaultExecutorFactory
+import org.gradle.internal.concurrent.Stoppable
import org.gradle.internal.event.DefaultListenerManager
import org.gradle.internal.filewatch.FileSystemChangeWaiter
import org.gradle.internal.invocation.BuildAction
-import org.gradle.internal.os.OperatingSystem
+import org.gradle.internal.service.ServiceRegistration
+import org.gradle.internal.service.ServiceRegistry
+import org.gradle.internal.service.scopes.PluginServiceRegistry
import org.gradle.logging.TestStyledTextOutputFactory
+import org.gradle.internal.os.OperatingSystem
import org.gradle.util.Clock
import org.gradle.util.RedirectStdIn
import org.junit.Rule
@@ -53,12 +57,21 @@ class ContinuousBuildActionExecuterTest extends Specification {
def listenerManager = new DefaultListenerManager()
@AutoCleanup("stop")
def executorFactory = new DefaultExecutorFactory()
+ def globalServices = Stub(ServiceRegistry)
def executer = executer()
+ def sessionService = Mock(Stoppable)
private File file = new File('file')
def setup() {
requestMetadata.getBuildTimeClock() >> clock
+ globalServices.getAll(PluginServiceRegistry) >> [
+ Stub(PluginServiceRegistry) {
+ registerBuildSessionServices(_) >> { ServiceRegistration registration ->
+ registration.add(Stoppable, sessionService)
+ }
+ }
+ ]
}
def "uses underlying executer when continuous build is not enabled"() {
@@ -67,14 +80,14 @@ class ContinuousBuildActionExecuterTest extends Specification {
executeBuild()
then:
- 1 * delegate.execute(action, requestContext, actionParameters)
+ 1 * delegate.execute(action, requestContext, actionParameters, _)
0 * waiter._
}
def "allows exceptions to propagate for single builds"() {
when:
singleBuild()
- 1 * delegate.execute(action, requestContext, actionParameters) >> {
+ 1 * delegate.execute(action, requestContext, actionParameters, _) >> {
throw new RuntimeException("!")
}
executeBuild()
@@ -86,7 +99,7 @@ class ContinuousBuildActionExecuterTest extends Specification {
def "waits for waiter"() {
when:
continuousBuild()
- 1 * delegate.execute(action, requestContext, actionParameters) >> {
+ 1 * delegate.execute(action, requestContext, actionParameters, _) >> {
declareInput(file)
}
executeBuild()
@@ -100,7 +113,7 @@ class ContinuousBuildActionExecuterTest extends Specification {
def "exits if there are no file system inputs"() {
when:
continuousBuild()
- 1 * delegate.execute(action, requestContext, actionParameters)
+ 1 * delegate.execute(action, requestContext, actionParameters, _)
executeBuild()
then:
@@ -110,7 +123,7 @@ class ContinuousBuildActionExecuterTest extends Specification {
def "throws exception if last build fails in continous mode"() {
when:
continuousBuild()
- 1 * delegate.execute(action, requestContext, actionParameters) >> {
+ 1 * delegate.execute(action, requestContext, actionParameters, _) >> {
declareInput(file)
throw new ReportedException(new Exception("!"))
}
@@ -129,7 +142,7 @@ class ContinuousBuildActionExecuterTest extends Specification {
executeBuild()
then:
- 1 * delegate.execute(action, requestContext, actionParameters) >> {
+ 1 * delegate.execute(action, requestContext, actionParameters, _) >> {
declareInput(file)
}
@@ -137,7 +150,7 @@ class ContinuousBuildActionExecuterTest extends Specification {
1 * waiter.wait(_, _, _)
and:
- 1 * delegate.execute(action, requestContext, actionParameters) >> {
+ 1 * delegate.execute(action, requestContext, actionParameters, _) >> {
declareInput(file)
throw new ReportedException(new Exception("!"))
}
@@ -146,7 +159,7 @@ class ContinuousBuildActionExecuterTest extends Specification {
1 * waiter.wait(_, _, _)
and:
- 1 * delegate.execute(action, requestContext, actionParameters) >> {
+ 1 * delegate.execute(action, requestContext, actionParameters, _) >> {
declareInput(file)
}
@@ -202,6 +215,24 @@ class ContinuousBuildActionExecuterTest extends Specification {
javaVersion << JavaVersion.values().findAll { it >= JavaVersion.VERSION_1_7 }
}
+ def "closes build session after single build"() {
+ when:
+ singleBuild()
+ executeBuild()
+
+ then:
+ 1 * sessionService.stop()
+ }
+
+ def "closes build session after continuous build"() {
+ when:
+ continuousBuild()
+ executeBuild()
+
+ then:
+ 1 * sessionService.stop()
+ }
+
private void singleBuild() {
actionParameters.continuous >> false
}
@@ -211,7 +242,7 @@ class ContinuousBuildActionExecuterTest extends Specification {
}
private void executeBuild() {
- executer.execute(action, requestContext, actionParameters)
+ executer.execute(action, requestContext, actionParameters, globalServices)
}
private void declareInput(File file) {
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuterTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuterTest.groovy
index 5bc3f36..2b41526 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuterTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/DaemonUsageSuggestingBuildActionExecuterTest.groovy
@@ -23,6 +23,7 @@ import org.gradle.initialization.BuildRequestContext
import org.gradle.internal.environment.GradleBuildEnvironment
import org.gradle.internal.invocation.BuildAction
import org.gradle.internal.os.OperatingSystem
+import org.gradle.internal.service.ServiceRegistry
import org.gradle.logging.StyledTextOutput
import org.gradle.logging.StyledTextOutputFactory
import spock.lang.Specification
@@ -51,15 +52,16 @@ class DaemonUsageSuggestingBuildActionExecuterTest extends Specification {
}
final BuildRequestContext buildRequestContext = Mock()
final BuildActionParameters params = Mock()
+ final ServiceRegistry serviceRegistry = Mock()
def "delegates execution to the underlying executer"() {
given:
def executionResult = new Object()
- delegate.execute(action, buildRequestContext, params) >> executionResult
+ delegate.execute(action, buildRequestContext, params, serviceRegistry) >> executionResult
params.daemonUsage >> EXPLICITLY_ENABLED
when:
- def result = executer.execute(action, buildRequestContext, params)
+ def result = executer.execute(action, buildRequestContext, params, serviceRegistry)
then:
result == executionResult
@@ -72,7 +74,7 @@ class DaemonUsageSuggestingBuildActionExecuterTest extends Specification {
os.windows >> false
when:
- executer.execute(action, buildRequestContext, params)
+ executer.execute(action, buildRequestContext, params, serviceRegistry)
then:
1 * textOutput.println()
@@ -89,7 +91,7 @@ class DaemonUsageSuggestingBuildActionExecuterTest extends Specification {
os.windows >> isWindows
when:
- executer.execute(action, buildRequestContext, params)
+ executer.execute(action, buildRequestContext, params, serviceRegistry)
then:
0 * textOutput._
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/InProcessBuildActionExecuterTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/InProcessBuildActionExecuterTest.groovy
index 7367b2b..8fb6559 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/InProcessBuildActionExecuterTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/launcher/exec/InProcessBuildActionExecuterTest.groovy
@@ -26,6 +26,7 @@ import org.gradle.initialization.GradleLauncherFactory
import org.gradle.internal.invocation.BuildAction
import org.gradle.internal.invocation.BuildActionRunner
import org.gradle.internal.invocation.BuildController
+import org.gradle.internal.service.ServiceRegistry
import spock.lang.Specification
class InProcessBuildActionExecuterTest extends Specification {
@@ -41,6 +42,7 @@ class InProcessBuildActionExecuterTest extends Specification {
BuildAction action = Mock() {
getStartParameter() >> startParameter
}
+ final ServiceRegistry sessionServices = Mock()
final InProcessBuildActionExecuter executer = new InProcessBuildActionExecuter(factory, actionRunner)
def setup() {
@@ -52,13 +54,13 @@ class InProcessBuildActionExecuterTest extends Specification {
param.envVariables >> [:]
when:
- def result = executer.execute(action, buildRequestContext, param)
+ def result = executer.execute(action, buildRequestContext, param, sessionServices)
then:
result == '<result>'
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * actionRunner.run(action, !null) >> { BuildAction a, BuildController controller ->
controller.result = '<result>'
}
@@ -70,13 +72,13 @@ class InProcessBuildActionExecuterTest extends Specification {
param.envVariables >> [:]
when:
- def result = executer.execute(action, buildRequestContext, param)
+ def result = executer.execute(action, buildRequestContext, param, sessionServices)
then:
result == null
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * actionRunner.run(action, !null) >> { BuildAction a, BuildController controller ->
assert !controller.hasResult()
controller.result = null
@@ -90,13 +92,13 @@ class InProcessBuildActionExecuterTest extends Specification {
param.envVariables >> [:]
when:
- def result = executer.execute(action, buildRequestContext, param)
+ def result = executer.execute(action, buildRequestContext, param, sessionServices)
then:
result == '<result>'
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * launcher.run() >> buildResult
_ * buildResult.gradle >> gradle
_ * actionRunner.run(action, !null) >> { BuildAction a, BuildController controller ->
@@ -111,13 +113,13 @@ class InProcessBuildActionExecuterTest extends Specification {
param.envVariables >> [:]
when:
- def result = executer.execute(action, buildRequestContext, param)
+ def result = executer.execute(action, buildRequestContext, param, sessionServices)
then:
result == '<result>'
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * launcher.getBuildAnalysis() >> buildResult
_ * buildResult.gradle >> gradle
_ * actionRunner.run(action, !null) >> { BuildAction a, BuildController controller ->
@@ -135,14 +137,14 @@ class InProcessBuildActionExecuterTest extends Specification {
}
when:
- executer.execute(action, buildRequestContext, param)
+ executer.execute(action, buildRequestContext, param, sessionServices)
then:
IllegalStateException e = thrown()
e.message == 'Cannot use launcher after build has completed.'
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * launcher.run() >> buildResult
1 * launcher.stop()
}
@@ -151,14 +153,14 @@ class InProcessBuildActionExecuterTest extends Specification {
def failure = new RuntimeException()
when:
- executer.execute(action, buildRequestContext, param)
+ executer.execute(action, buildRequestContext, param, sessionServices)
then:
RuntimeException e = thrown()
e == failure
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * launcher.run() >> { throw failure }
_ * actionRunner.run(action, !null) >> { BuildAction action, BuildController controller ->
controller.run()
@@ -170,14 +172,14 @@ class InProcessBuildActionExecuterTest extends Specification {
def failure = new RuntimeException()
when:
- executer.execute(action, buildRequestContext, param)
+ executer.execute(action, buildRequestContext, param, sessionServices)
then:
RuntimeException e = thrown()
e == failure
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * launcher.buildAnalysis >> { throw failure }
_ * actionRunner.run(action, !null) >> { BuildAction action, BuildController controller ->
controller.configure()
@@ -187,14 +189,14 @@ class InProcessBuildActionExecuterTest extends Specification {
def "cannot run after configuration failure"() {
when:
- executer.execute(action, buildRequestContext, param)
+ executer.execute(action, buildRequestContext, param, sessionServices)
then:
IllegalStateException e = thrown()
e.message == 'Cannot use launcher after build has completed.'
and:
- 1 * factory.newInstance(startParameter, buildRequestContext) >> launcher
+ 1 * factory.newInstance(startParameter, buildRequestContext, sessionServices) >> launcher
1 * launcher.buildAnalysis >> { throw new RuntimeException() }
_ * actionRunner.run(action, !null) >> { BuildAction action, BuildController controller ->
try {
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/DaemonBuildActionExecuterTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/DaemonBuildActionExecuterTest.groovy
index 9d72737..304ef6e 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/DaemonBuildActionExecuterTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/DaemonBuildActionExecuterTest.groovy
@@ -17,6 +17,7 @@ package org.gradle.tooling.internal.provider
import org.gradle.initialization.BuildRequestContext
import org.gradle.internal.invocation.BuildAction
+import org.gradle.internal.service.ServiceRegistry
import org.gradle.launcher.daemon.client.DaemonClient
import org.gradle.launcher.daemon.configuration.DaemonParameters
import org.gradle.initialization.ReportedException
@@ -30,18 +31,19 @@ class DaemonBuildActionExecuterTest extends Specification {
final BuildRequestContext buildRequestContext = Mock()
final ProviderOperationParameters parameters = Mock()
final DaemonParameters daemonParameters = Mock()
+ final ServiceRegistry contextServices = Mock()
final DaemonBuildActionExecuter executer = new DaemonBuildActionExecuter(client, daemonParameters)
def unpacksReportedException() {
def failure = new RuntimeException()
when:
- executer.execute(action, buildRequestContext, parameters)
+ executer.execute(action, buildRequestContext, parameters, contextServices)
then:
BuildExceptionVersion1 e = thrown()
e.cause == failure
- 1 * client.execute(action, buildRequestContext, !null) >> { throw new ReportedException(failure) }
+ 1 * client.execute(action, buildRequestContext, !null, contextServices) >> { throw new ReportedException(failure) }
_ * daemonParameters.effectiveSystemProperties >> [:]
}
}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuterTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuterTest.groovy
index b12bbeb..a4cc57e 100644
--- a/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuterTest.groovy
+++ b/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/LoggingBridgingBuildActionExecuterTest.groovy
@@ -19,6 +19,7 @@ import org.gradle.api.logging.LogLevel
import org.gradle.internal.invocation.BuildAction
import org.gradle.initialization.BuildRequestContext
import org.gradle.internal.Factory
+import org.gradle.internal.service.ServiceRegistry
import org.gradle.launcher.exec.BuildActionExecuter
import org.gradle.logging.LoggingManagerInternal
import org.gradle.tooling.internal.provider.connection.ProviderOperationParameters
@@ -31,19 +32,20 @@ class LoggingBridgingBuildActionExecuterTest extends Specification {
final BuildAction action = Mock()
final BuildRequestContext buildRequestContext = Mock()
final ProviderOperationParameters parameters = Mock()
+ final ServiceRegistry contextServices = Mock()
//declared type-lessly to work around groovy eclipse plugin bug
final executer = new LoggingBridgingBuildActionExecuter(target, loggingManagerFactory)
def configuresLoggingWhileActionIsExecuting() {
when:
- executer.execute(action, buildRequestContext, parameters)
+ executer.execute(action, buildRequestContext, parameters, contextServices)
then:
1 * loggingManagerFactory.create() >> loggingManager
1 * loggingManager.addOutputEventListener(!null)
1 * loggingManager.start()
- 1 * target.execute(action, buildRequestContext, parameters)
+ 1 * target.execute(action, buildRequestContext, parameters, contextServices)
1 * loggingManager.stop()
}
@@ -51,14 +53,14 @@ class LoggingBridgingBuildActionExecuterTest extends Specification {
def failure = new RuntimeException()
when:
- executer.execute(action, buildRequestContext, parameters)
+ executer.execute(action, buildRequestContext, parameters, contextServices)
then:
RuntimeException e = thrown()
e == failure
1 * loggingManagerFactory.create() >> loggingManager
1 * loggingManager.start()
- 1 * target.execute(action, buildRequestContext, parameters) >> {throw failure}
+ 1 * target.execute(action, buildRequestContext, parameters, contextServices) >> {throw failure}
1 * loggingManager.stop()
}
@@ -68,8 +70,8 @@ class LoggingBridgingBuildActionExecuterTest extends Specification {
parameters.getBuildLogLevel() >> LogLevel.QUIET
when:
- executer.execute(action, buildRequestContext, parameters)
-
+ executer.execute(action, buildRequestContext, parameters, contextServices)
+
then:
1 * loggingManager.setLevel(LogLevel.QUIET)
}
diff --git a/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/TestExecutionRequestActionTest.groovy b/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/TestExecutionRequestActionTest.groovy
new file mode 100644
index 0000000..962e641
--- /dev/null
+++ b/subprojects/launcher/src/test/groovy/org/gradle/tooling/internal/provider/TestExecutionRequestActionTest.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider
+import org.gradle.StartParameter
+import org.gradle.tooling.internal.provider.test.ProviderInternalTestExecutionRequest
+import spock.lang.Specification
+
+class TestExecutionRequestActionTest extends Specification {
+
+ StartParameter startParameter = Mock()
+ BuildClientSubscriptions buildClientSubscriptions= Mock()
+ ProviderInternalTestExecutionRequest executionRequest = Mock()
+
+ def "maps testClasses to internalJvmTestRequests if empty"(){
+ given:
+ consumerRequestWithClassNamesOnly();
+
+ when:
+ def executionRequestAction = TestExecutionRequestAction.create(buildClientSubscriptions, startParameter, executionRequest);
+ then:
+ executionRequestAction.getTestClassNames() == ["org.acme.Foo"] as Set
+ executionRequestAction.getInternalJvmTestRequests().collect { [clazz:it.className, method:it.methodName]} == [[clazz:"org.acme.Foo", method:null]]
+
+ }
+
+ def consumerRequestWithClassNamesOnly() {
+ 1 * executionRequest.getTestExecutionDescriptors() >> []
+ 1 * executionRequest.getInternalJvmTestRequests(_) >> []
+ 1 * executionRequest.getTestClassNames() >> ["org.acme.Foo"]
+ executionRequest
+ }
+}
diff --git a/subprojects/launcher/src/testFixtures/groovy/org/gradle/launcher/continuous/AbstractContinuousIntegrationTest.groovy b/subprojects/launcher/src/testFixtures/groovy/org/gradle/launcher/continuous/AbstractContinuousIntegrationTest.groovy
new file mode 100644
index 0000000..f893f06
--- /dev/null
+++ b/subprojects/launcher/src/testFixtures/groovy/org/gradle/launcher/continuous/AbstractContinuousIntegrationTest.groovy
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.launcher.continuous
+
+import com.google.common.util.concurrent.SimpleTimeLimiter
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.executer.*
+import org.gradle.internal.os.OperatingSystem
+import org.gradle.test.fixtures.ConcurrentTestUtil
+import org.gradle.util.TextUtil
+
+import java.util.concurrent.TimeUnit
+
+abstract class AbstractContinuousIntegrationTest extends AbstractIntegrationSpec {
+ private static final int WAIT_FOR_WATCHING_TIMEOUT_SECONDS = 30
+ private static final int WAIT_FOR_SHUTDOWN_TIMEOUT_SECONDS = 10
+
+ GradleHandle gradle
+
+ private int standardOutputBuildMarker = 0
+ private int errorOutputBuildMarker = 0
+
+ int buildTimeout = WAIT_FOR_WATCHING_TIMEOUT_SECONDS
+ int shutdownTimeout = WAIT_FOR_SHUTDOWN_TIMEOUT_SECONDS
+ boolean killToStop
+
+ public void turnOnDebug() {
+ executer.withDebug(true)
+ executer.withArgument("--no-daemon")
+ buildTimeout *= 100
+ shutdownTimeout *= 100
+ }
+
+ def cleanup() {
+ stopGradle()
+ if (OperatingSystem.current().isWindows()) {
+ // needs delay to release file handles
+ sleep(500L)
+ }
+ }
+
+ def setup() {
+ // this is here to ensure that the lastModified() timestamps actually change in between builds.
+ // if the build is very fast, the timestamp of the file will not change and the JDK file watch service won't see the change.
+ executer.beforeExecute {
+ def initScript = file("init.gradle")
+ initScript.text = """
+ def startAt = System.currentTimeMillis()
+ gradle.buildFinished {
+ def sinceStart = System.currentTimeMillis() - startAt
+ if (sinceStart < 2000) {
+ sleep 2000 - sinceStart
+ }
+ }
+ """
+ withArgument("-I").withArgument(initScript.absolutePath)
+ }
+ }
+
+ @Override
+ protected ExecutionResult succeeds(String... tasks) {
+ if (tasks) {
+ runBuild(tasks)
+ } else if (!gradle.isRunning()) {
+ throw new UnexpectedBuildFailure("Gradle has exited")
+ }
+ if (gradle == null) {
+ throw new UnexpectedBuildFailure("Gradle never started")
+ }
+ waitForBuild()
+ if (result instanceof ExecutionFailure) {
+ throw new UnexpectedBuildFailure("""build was expected to succeed but failed:
+-- STDOUT --
+${result.output}
+-- STDOUT --
+-- STDERR --
+${result.error}
+-- STDERR --
+""")
+ }
+ result
+ }
+
+ ExecutionFailure fails(String... tasks) {
+ if (tasks) {
+ runBuild(tasks)
+ } else if (!gradle.isRunning()) {
+ throw new UnexpectedBuildFailure("Gradle has exited")
+ }
+ waitForBuild()
+ if (!(result instanceof ExecutionFailure)) {
+ throw new UnexpectedBuildFailure("build was expected to fail but succeeded")
+ }
+ failure = result as ExecutionFailure
+ failure
+ }
+
+ private void runBuild(String... tasks) {
+ stopGradle()
+ standardOutputBuildMarker = 0
+ errorOutputBuildMarker = 0
+ gradle = executer.withStdinPipe()
+ .withTasks(tasks)
+ .withForceInteractive(true)
+ .withArgument("--stacktrace")
+ .withArgument("--continuous")
+ .start()
+ }
+
+ protected OutputStream getStdinPipe() {
+ gradle.stdinPipe
+ }
+
+ private void waitForBuild() {
+ def lastOutput = buildOutputSoFar()
+ def lastActivity = System.currentTimeMillis()
+
+ while (gradle.isRunning() && System.currentTimeMillis() - lastActivity < (buildTimeout * 1000)) {
+ sleep 100
+ def lastLength = lastOutput.size()
+ lastOutput = buildOutputSoFar()
+
+ if (lastOutput.contains(TextUtil.toPlatformLineSeparators("Waiting for changes to input files of tasks..."))) {
+ break
+ } else if (lastOutput.size() > lastLength) {
+ lastActivity = System.currentTimeMillis()
+ }
+ }
+
+ def out = buildOutputSoFar()
+ def err = gradle.errorOutput.substring(errorOutputBuildMarker)
+ standardOutputBuildMarker = gradle.standardOutput.length()
+ errorOutputBuildMarker = gradle.errorOutput.length()
+
+ //noinspection GroovyConditionalWithIdenticalBranches
+ result = out.contains("BUILD SUCCESSFUL") ? new OutputScrapingExecutionResult(out, err) : new OutputScrapingExecutionFailure(out, err)
+ }
+
+ void stopGradle() {
+ if (gradle && gradle.isRunning()) {
+ if (killToStop) {
+ gradle.abort()
+ } else {
+ gradle.cancel()
+ new SimpleTimeLimiter().callWithTimeout(
+ { gradle.waitForExit() },
+ shutdownTimeout, TimeUnit.SECONDS, false
+ )
+ }
+ }
+ }
+
+ void noBuildTriggered(int waitSeconds = 3) {
+ // TODO - change this general strategy to positively detect changes we are ignoring instead of asserting that a build doesn't happen in some time frame
+ try {
+ ConcurrentTestUtil.poll(waitSeconds, 0.5) {
+ // force the poll to continue while there is no output
+ assert !buildOutputSoFar().empty
+ }
+ // if we get here it means that there was build output at some point while polling
+ throw new UnexpectedBuildStartedException("Expected build not to start, but started with output: " + buildOutputSoFar())
+ } catch (AssertionError e) {
+ // ok, what we want
+ }
+ }
+
+ // should be private, but is accessed by closures in this class
+ protected String buildOutputSoFar() {
+ gradle.standardOutput.substring(standardOutputBuildMarker)
+ }
+
+ void cancelsAndExits() {
+ waitForNotRunning()
+ assert buildOutputSoFar().contains("Build cancelled.")
+ }
+
+ void doesntExit() {
+ try {
+ waitForNotRunning()
+ assert gradle.running
+ } catch (AssertionError ignore) {
+
+ }
+ }
+
+ private waitForNotRunning() {
+ ConcurrentTestUtil.poll(WAIT_FOR_SHUTDOWN_TIMEOUT_SECONDS) {
+ assert !gradle.running
+ }
+ }
+
+ void sendEOT() {
+ gradle.cancelWithEOT()
+ }
+
+ private static class UnexpectedBuildStartedException extends Exception {
+ UnexpectedBuildStartedException(String message) {
+ super(message)
+ }
+ }
+}
diff --git a/subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/Java7RequiringContinuousIntegrationTest.groovy b/subprojects/launcher/src/testFixtures/groovy/org/gradle/launcher/continuous/Java7RequiringContinuousIntegrationTest.groovy
similarity index 100%
rename from subprojects/launcher/src/integTest/groovy/org/gradle/launcher/continuous/Java7RequiringContinuousIntegrationTest.groovy
rename to subprojects/launcher/src/testFixtures/groovy/org/gradle/launcher/continuous/Java7RequiringContinuousIntegrationTest.groovy
diff --git a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishBasicIntegTest.groovy b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishBasicIntegTest.groovy
index 07b19be..a1812e0 100644
--- a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishBasicIntegTest.groovy
+++ b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishBasicIntegTest.groovy
@@ -22,11 +22,13 @@ import org.gradle.test.fixtures.maven.MavenLocalRepository
import org.gradle.util.SetSystemProperties
import org.junit.Rule
import spock.lang.Ignore
+
/**
* Tests “simple” maven publishing scenarios
*/
class MavenPublishBasicIntegTest extends AbstractMavenPublishIntegTest {
- @Rule SetSystemProperties sysProp = new SetSystemProperties()
+ @Rule
+ SetSystemProperties sysProp = new SetSystemProperties()
MavenLocalRepository localM2Repo
private M2Installation m2Installation
@@ -232,7 +234,7 @@ class MavenPublishBasicIntegTest extends AbstractMavenPublishIntegTest {
fails 'publish'
then:
- failure.assertHasCause("Exception thrown while executing model rule: org.gradle.api.publish.plugins.PublishingPlugin\$Rules#publishing(org.gradle.api.plugins.ExtensionContainer)")
+ failure.assertHasCause("Exception thrown while executing model rule: PublishingPlugin.Rules#publishing")
failure.assertHasCause("Maven publication 'maven' cannot include multiple components")
}
diff --git a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpIntegTest.groovy b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpIntegTest.groovy
index 81c7b8f..091c7a0 100644
--- a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpIntegTest.groovy
+++ b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpIntegTest.groovy
@@ -16,7 +16,7 @@
package org.gradle.api.publish.maven
-import org.gradle.api.credentials.Credentials
+import org.gradle.api.artifacts.repositories.PasswordCredentials
import org.gradle.api.internal.artifacts.repositories.DefaultPasswordCredentials
import org.gradle.integtests.fixtures.publish.maven.AbstractMavenPublishIntegTest
import org.gradle.test.fixtures.file.LeaksFileHandles
@@ -45,7 +45,6 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
def setup() {
server.start()
- redirectServer.start()
mavenRemoteRepo = new MavenHttpRepository(server, repoPath, mavenRepo)
group = "org.gradle"
@@ -54,11 +53,11 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
module = mavenRemoteRepo.module(group, name, version)
settingsFile << 'rootProject.name = "publish"'
- buildFile << publicationBuild(version, group, mavenRemoteRepo.uri)
}
def "can publish to an unauthenticated http repo"() {
given:
+ buildFile << publicationBuild(version, group, mavenRemoteRepo.uri)
expectModulePublish(module)
when:
@@ -80,14 +79,8 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
@Unroll
def "can publish to authenticated repository using #authScheme auth"() {
given:
- def credentials = new DefaultPasswordCredentials('username', 'password')
-
- buildFile << """
- publishing.repositories.maven.credentials {
- username '${credentials.username}'
- password '${credentials.password}'
- }
- """
+ PasswordCredentials credentials = new DefaultPasswordCredentials('username', 'password')
+ buildFile << publicationBuild(version, group, mavenRemoteRepo.uri, credentials)
server.authenticationScheme = authScheme
@@ -124,14 +117,8 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
@Unroll
def "reports failure publishing with wrong credentials using #authScheme"() {
given:
- def credentials = new DefaultPasswordCredentials('wrong', 'wrong')
-
- buildFile << """
- publishing.repositories.maven.credentials {
- username '${credentials.username}'
- password '${credentials.password}'
- }
- """
+ PasswordCredentials credentials = new DefaultPasswordCredentials('wrong', 'wrong')
+ buildFile << publicationBuild(version, group, mavenRemoteRepo.uri, credentials)
server.authenticationScheme = authScheme
module.artifact.expectPut(401, credentials)
@@ -154,6 +141,7 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
@Unroll
def "reports failure when required credentials are not provided #authScheme"() {
given:
+ buildFile << publicationBuild(version, group, mavenRemoteRepo.uri)
server.authenticationScheme = authScheme
module.artifact.expectPut(401)
module.pom.expectPut(401)
@@ -175,12 +163,14 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
@Issue("GRADLE-3312")
def "can publish to a http repo via redirects"() {
given:
+ buildFile << publicationBuild(version, group, mavenRemoteRepo.uri)
+ redirectServer.start()
buildFile.text = publicationBuild(version, group, new URI("${redirectServer.uri}/repo"))
redirectServer.expectGetRedirected(module.rootMetaData.path, "${server.uri}${module.rootMetaData.path}")
module.rootMetaData.expectGetMissing()
- expectRedirectPublish(module, server.getUri(), redirectServer)
+ expectModulePublishViaRedirect(module, server.getUri(), redirectServer)
when:
succeeds 'publish'
@@ -201,20 +191,15 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
@Issue("GRADLE-3312")
def "can publish to an authenticated http repo via redirects"() {
given:
- buildFile.text = publicationBuild(version, group, new URI("${redirectServer.uri}/repo"))
+ redirectServer.start()
- def credentials = new DefaultPasswordCredentials('username', 'password')
- buildFile << """
- publishing.repositories.maven.credentials {
- username '${credentials.username}'
- password '${credentials.password}'
- }
- """
+ PasswordCredentials credentials = new DefaultPasswordCredentials('username', 'password')
+ buildFile.text = publicationBuild(version, group, new URI("${redirectServer.uri}/repo"), credentials)
redirectServer.expectGetRedirected(module.rootMetaData.path, "${server.uri}${module.rootMetaData.path}")
module.rootMetaData.expectGetMissing(credentials)
- expectRedirectPublish(module, server.getUri(), redirectServer, credentials)
+ expectModulePublishViaRedirect(module, server.getUri(), redirectServer, credentials)
when:
succeeds 'publish'
@@ -232,7 +217,13 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
module.rootMetaData.versions == ["2"]
}
- private String publicationBuild(String version, String group, URI uri) {
+ private String publicationBuild(String version, String group, URI uri, PasswordCredentials credentials = null) {
+ String credentialsBlock = credentials ? """
+ credentials{
+ username '${credentials.username}'
+ password '${credentials.password}'
+ }
+ """ : ''
return """
apply plugin: 'java'
apply plugin: 'maven-publish'
@@ -243,6 +234,7 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
repositories {
maven {
url "$uri"
+ ${credentialsBlock}
}
}
publications {
@@ -267,7 +259,7 @@ class MavenPublishHttpIntegTest extends AbstractMavenPublishIntegTest {
module.pom.md5.expectPut()
}
- private void expectRedirectPublish(MavenHttpModule module, URI targetServerUri, HttpServer httpServer, Credentials credentials = null) {
+ private void expectModulePublishViaRedirect(MavenHttpModule module, URI targetServerUri, HttpServer httpServer, PasswordCredentials credentials = null) {
String redirectUri = targetServerUri.toString()
[module.artifact, module.pom, module.rootMetaData].each { artifact ->
[artifact, artifact.sha1, artifact.md5].each { innerArtifact ->
diff --git a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpsIntegTest.groovy b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpsIntegTest.groovy
index 280d2b8..e696a13 100644
--- a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpsIntegTest.groovy
+++ b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishHttpsIntegTest.groovy
@@ -97,7 +97,6 @@ class MavenPublishHttpsIntegTest extends AbstractMavenPublishIntegTest {
then:
failure.assertHasCause("Failed to publish publication 'maven' to repository 'maven'")
failure.assertHasCause("Failed to deploy artifacts: Could not transfer artifact org.gradle:publish:jar:2 from/to remote (https://localhost:${server.sslPort}/repo): Could not write to resource 'org/gradle/publish/2/publish-2.jar'")
- // TODO:DAZ Get this exception into the cause
failure.error.contains("peer not authenticated")
}
diff --git a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishMultiProjectIntegTest.groovy b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishMultiProjectIntegTest.groovy
index 4841878..998d54d 100644
--- a/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishMultiProjectIntegTest.groovy
+++ b/subprojects/maven/src/integTest/groovy/org/gradle/api/publish/maven/MavenPublishMultiProjectIntegTest.groovy
@@ -85,7 +85,7 @@ project(":project3") {
fails "publish"
then:
- failure.assertHasCause "Exception thrown while executing model rule: org.gradle.api.publish.plugins.PublishingPlugin\$Rules#publishing(org.gradle.api.plugins.ExtensionContainer)"
+ failure.assertHasCause "Exception thrown while executing model rule: PublishingPlugin.Rules#publishing"
failure.assertHasCause "Publishing is not yet able to resolve a dependency on a project with multiple different publications."
}
diff --git a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/AbstractMavenPublishAction.java b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/AbstractMavenPublishAction.java
index 5f8f89e..b6808ee 100644
--- a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/AbstractMavenPublishAction.java
+++ b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/AbstractMavenPublishAction.java
@@ -19,6 +19,8 @@ package org.gradle.api.publication.maven.internal.action;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.repository.internal.MavenRepositorySystemSession;
+import org.apache.maven.repository.internal.SnapshotMetadataGeneratorFactory;
+import org.apache.maven.repository.internal.VersionsMetadataGeneratorFactory;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.PlexusContainerException;
@@ -30,6 +32,8 @@ import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.artifact.ArtifactType;
+import org.sonatype.aether.impl.Deployer;
+import org.sonatype.aether.impl.internal.DefaultDeployer;
import org.sonatype.aether.impl.internal.SimpleLocalRepositoryManager;
import org.sonatype.aether.util.DefaultRepositorySystemSession;
import org.sonatype.aether.util.artifact.DefaultArtifact;
@@ -48,6 +52,7 @@ abstract class AbstractMavenPublishAction implements MavenPublishAction {
private final List<Artifact> attached = new ArrayList<Artifact>();
private final Artifact pomArtifact;
private Artifact mainArtifact;
+ private SnapshotVersionManager snapshotVersionManager = new SnapshotVersionManager();
protected AbstractMavenPublishAction(File pomFile) {
container = newPlexusContainer();
@@ -104,6 +109,14 @@ abstract class AbstractMavenPublishAction implements MavenPublishAction {
private RepositorySystem newRepositorySystem() {
try {
+ DefaultDeployer deployer = (DefaultDeployer) getContainer().lookup(Deployer.class);
+ // This is a workaround for https://issues.gradle.org/browse/GRADLE-3324.
+ // Somehow the ArrayList 'result' in `org.sonatype.aether.impl.internal.Utils#sortMetadataGeneratorFactories` ends up
+ // being a list of nulls on windows and IBM's 1.6 JDK.
+ deployer.setMetadataFactories(null);
+ deployer.addMetadataGeneratorFactory(new VersionsMetadataGeneratorFactory());
+ deployer.addMetadataGeneratorFactory(new SnapshotMetadataGeneratorFactory());
+ deployer.addMetadataGeneratorFactory(snapshotVersionManager);
return container.lookup(RepositorySystem.class);
} catch (ComponentLookupException e) {
throw UncheckedException.throwAsUncheckedException(e);
@@ -137,4 +150,8 @@ abstract class AbstractMavenPublishAction implements MavenPublishAction {
}
return new DefaultArtifact(pomArtifact.getGroupId(), pomArtifact.getArtifactId(), classifier, extension, pomArtifact.getVersion());
}
+
+ public void setUniqueVersion(boolean uniqueVersion) {
+ snapshotVersionManager.setUniqueVersion(uniqueVersion);
+ }
}
diff --git a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/MavenDeployAction.java b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/MavenDeployAction.java
index 221812b..e3185ba 100644
--- a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/MavenDeployAction.java
+++ b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/MavenDeployAction.java
@@ -15,10 +15,10 @@
*/
package org.gradle.api.publication.maven.internal.action;
-import java.io.File;
-import java.util.Collection;
-
import org.apache.maven.artifact.ant.RemoteRepository;
+import org.gradle.api.GradleException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.artifact.Artifact;
@@ -27,16 +27,15 @@ import org.sonatype.aether.deployment.DeploymentException;
import org.sonatype.aether.repository.Authentication;
import org.sonatype.aether.repository.Proxy;
import org.sonatype.aether.util.repository.DefaultProxySelector;
-import org.gradle.api.GradleException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.Collection;
public class MavenDeployAction extends AbstractMavenPublishAction {
private static final Logger LOGGER = LoggerFactory.getLogger(MavenDeployAction.class);
private RemoteRepository remoteRepository;
private RemoteRepository remoteSnapshotRepository;
- private SnapshotVersionManager snapshotVersionManager = new SnapshotVersionManager();
public MavenDeployAction(File pomFile) {
super(pomFile);
@@ -47,10 +46,6 @@ public class MavenDeployAction extends AbstractMavenPublishAction {
this.remoteSnapshotRepository = snapshotRepository;
}
- public void setUniqueVersion(boolean uniqueVersion) {
- snapshotVersionManager.setUniqueVersion(uniqueVersion);
- }
-
@Override
protected void publishArtifacts(Collection<Artifact> artifacts, RepositorySystem repositorySystem, RepositorySystemSession session) throws DeploymentException {
RemoteRepository gradleRepo = remoteRepository;
@@ -69,15 +64,12 @@ public class MavenDeployAction extends AbstractMavenPublishAction {
request.addArtifact(artifact);
}
- snapshotVersionManager.install(repositorySystem);
-
LOGGER.info("Deploying to " + gradleRepo.getUrl());
repositorySystem.deploy(session, request);
}
private org.sonatype.aether.repository.RemoteRepository createRepository(RemoteRepository gradleRepo) {
- org.sonatype.aether.repository.RemoteRepository repo = new org.sonatype.aether.repository.RemoteRepository("remote",
- gradleRepo.getLayout(), gradleRepo.getUrl());
+ org.sonatype.aether.repository.RemoteRepository repo = new org.sonatype.aether.repository.RemoteRepository("remote", gradleRepo.getLayout(), gradleRepo.getUrl());
org.apache.maven.artifact.ant.Authentication auth = gradleRepo.getAuthentication();
if (auth != null) {
diff --git a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/SnapshotVersionManager.java b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/SnapshotVersionManager.java
index 7ca2c92..1fedf1d 100644
--- a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/SnapshotVersionManager.java
+++ b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/action/SnapshotVersionManager.java
@@ -16,19 +16,14 @@
package org.gradle.api.publication.maven.internal.action;
-import org.gradle.internal.UncheckedException;
-import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.deployment.DeployRequest;
import org.sonatype.aether.impl.MetadataGenerator;
import org.sonatype.aether.impl.MetadataGeneratorFactory;
-import org.sonatype.aether.impl.internal.DefaultDeployer;
-import org.sonatype.aether.impl.internal.DefaultRepositorySystem;
import org.sonatype.aether.installation.InstallRequest;
import org.sonatype.aether.metadata.Metadata;
-import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
@@ -39,19 +34,6 @@ class SnapshotVersionManager implements MetadataGeneratorFactory, MetadataGenera
this.uniqueVersion = uniqueVersion;
}
- public void install(RepositorySystem repositorySystem) {
- try {
- Field field = DefaultRepositorySystem.class.getDeclaredField("deployer");
- field.setAccessible(true);
- DefaultDeployer deployer = (DefaultDeployer) field.get(repositorySystem);
- deployer.addMetadataGeneratorFactory(this);
- } catch (NoSuchFieldException e) {
- throw UncheckedException.throwAsUncheckedException(e);
- } catch (IllegalAccessException e) {
- throw UncheckedException.throwAsUncheckedException(e);
- }
- }
-
@Override
public int getPriority() {
return -100;
diff --git a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/pom/ProjectDependencyArtifactIdExtractorHack.java b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/pom/ProjectDependencyArtifactIdExtractorHack.java
index f050b5a..f9774fd 100644
--- a/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/pom/ProjectDependencyArtifactIdExtractorHack.java
+++ b/subprojects/maven/src/main/groovy/org/gradle/api/publication/maven/internal/pom/ProjectDependencyArtifactIdExtractorHack.java
@@ -17,6 +17,7 @@
package org.gradle.api.publication.maven.internal.pom;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import org.apache.maven.project.MavenProject;
import org.gradle.api.Nullable;
import org.gradle.api.Project;
@@ -26,7 +27,6 @@ import org.gradle.api.artifacts.maven.MavenResolver;
import org.gradle.api.artifacts.repositories.ArtifactRepository;
import org.gradle.api.plugins.BasePluginConvention;
import org.gradle.api.tasks.Upload;
-import org.testng.internal.annotations.Sets;
import java.util.Collection;
import java.util.Set;
diff --git a/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/MavenPublishServices.java b/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/MavenPublishServices.java
index 8866c1f..388df93 100644
--- a/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/MavenPublishServices.java
+++ b/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/MavenPublishServices.java
@@ -32,6 +32,9 @@ public class MavenPublishServices implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new ComponentRegistrationAction());
}
@@ -45,7 +48,6 @@ public class MavenPublishServices implements PluginServiceRegistry {
private static class ComponentRegistrationAction {
public void configure(ServiceRegistration registration, ComponentTypeRegistry componentTypeRegistry) {
// TODO There should be a more explicit way to execute an action against existing services
- // TODO:DAZ Dependency Management should be able to extract this from the plugin, without explicit registration
componentTypeRegistry.maybeRegisterComponentType(MavenModule.class)
.registerArtifactType(MavenPomArtifact.class, ArtifactType.MAVEN_POM);
}
diff --git a/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/publisher/MavenRemotePublisher.java b/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/publisher/MavenRemotePublisher.java
index a2bc5e2..5b60fbf 100644
--- a/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/publisher/MavenRemotePublisher.java
+++ b/subprojects/maven/src/main/groovy/org/gradle/api/publish/maven/internal/publisher/MavenRemotePublisher.java
@@ -19,7 +19,6 @@ package org.gradle.api.publish.maven.internal.publisher;
import org.apache.maven.artifact.ant.RemoteRepository;
import org.apache.maven.wagon.Wagon;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
-import org.gradle.api.credentials.Credentials;
import org.gradle.api.internal.artifacts.mvnsettings.LocalMavenRepositoryLocator;
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransport;
import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransportFactory;
@@ -92,8 +91,8 @@ public class MavenRemotePublisher extends AbstractMavenPublisher {
}
private RepositoryTransportWagonAdapter createAdapter(String protocol, MavenArtifactRepository artifactRepository, RepositoryTransportFactory repositoryTransportFactory) {
- Credentials credentials = ((AuthenticationSupportedInternal) artifactRepository).getConfiguredCredentials();
- RepositoryTransport transport = repositoryTransportFactory.createTransport(protocol, artifactRepository.getName(), credentials);
+ RepositoryTransport transport = repositoryTransportFactory.createTransport(protocol, artifactRepository.getName(),
+ ((AuthenticationSupportedInternal)artifactRepository).getConfiguredAuthentication());
URI rootUri = artifactRepository.getUrl();
return new RepositoryTransportWagonAdapter(transport, rootUri);
}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/event/AbstractBroadcastDispatch.java b/subprojects/messaging/src/main/java/org/gradle/internal/event/AbstractBroadcastDispatch.java
new file mode 100755
index 0000000..eb5918d
--- /dev/null
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/event/AbstractBroadcastDispatch.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.event;
+
+import org.gradle.internal.UncheckedException;
+import org.gradle.messaging.dispatch.Dispatch;
+import org.gradle.messaging.dispatch.MethodInvocation;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class AbstractBroadcastDispatch<T> implements Dispatch<MethodInvocation> {
+ protected final Class<T> type;
+
+ public AbstractBroadcastDispatch(Class<T> type) {
+ this.type = type;
+ }
+
+ private String getErrorMessage() {
+ String typeDescription = type.getSimpleName().replaceAll("(\\p{Upper})", " $1").trim().toLowerCase();
+ return String.format("Failed to notify %s.", typeDescription);
+ }
+
+ protected void dispatch(MethodInvocation invocation, Iterator<? extends Dispatch<MethodInvocation>> handlers) {
+ List<Throwable> failures = new ArrayList<Throwable>();
+ while (handlers.hasNext()) {
+ Dispatch<MethodInvocation> handler = handlers.next();
+ try {
+ handler.dispatch(invocation);
+ } catch (UncheckedException e) {
+ failures.add(e.getCause());
+ } catch (Throwable t) {
+ failures.add(t);
+ }
+ }
+ if (failures.size() == 1 && failures.get(0) instanceof RuntimeException) {
+ throw (RuntimeException) failures.get(0);
+ }
+ if (!failures.isEmpty()) {
+ throw new ListenerNotificationException(getErrorMessage(), failures);
+ }
+ }
+}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/event/BroadcastDispatch.java b/subprojects/messaging/src/main/java/org/gradle/internal/event/BroadcastDispatch.java
index 68a647a..7ddf101 100755
--- a/subprojects/messaging/src/main/java/org/gradle/internal/event/BroadcastDispatch.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/event/BroadcastDispatch.java
@@ -17,23 +17,21 @@
package org.gradle.internal.event;
import org.gradle.api.Action;
-import org.gradle.internal.UncheckedException;
import org.gradle.messaging.dispatch.Dispatch;
import org.gradle.messaging.dispatch.MethodInvocation;
import org.gradle.messaging.dispatch.ReflectionDispatch;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
-public class BroadcastDispatch<T> implements Dispatch<MethodInvocation> {
- private final Class<T> type;
+public class BroadcastDispatch<T> extends AbstractBroadcastDispatch<T> {
private final Map<Object, Dispatch<MethodInvocation>> handlers = new LinkedHashMap<Object, Dispatch<MethodInvocation>>();
public BroadcastDispatch(Class<T> type) {
- this.type = type;
+ super(type);
}
public Class<T> getType() {
@@ -75,28 +73,10 @@ public class BroadcastDispatch<T> implements Dispatch<MethodInvocation> {
handlers.clear();
}
- private String getErrorMessage() {
- String typeDescription = type.getSimpleName().replaceAll("(\\p{Upper})", " $1").trim().toLowerCase();
- return String.format("Failed to notify %s.", typeDescription);
- }
-
- public void dispatch(MethodInvocation invocation) {
- List<Throwable> failures = new ArrayList<Throwable>();
- for (Dispatch<MethodInvocation> handler : new ArrayList<Dispatch<MethodInvocation>>(handlers.values())) {
- try {
- handler.dispatch(invocation);
- } catch (UncheckedException e) {
- failures.add(e.getCause());
- } catch (Throwable t) {
- failures.add(t);
- }
- }
- if (failures.size() == 1 && failures.get(0) instanceof RuntimeException) {
- throw (RuntimeException) failures.get(0);
- }
- if (!failures.isEmpty()) {
- throw new ListenerNotificationException(getErrorMessage(), failures);
- }
+ @Override
+ public void dispatch(MethodInvocation message) {
+ Iterator<Dispatch<MethodInvocation>> iterator = new ArrayList<Dispatch<MethodInvocation>>(handlers.values()).iterator();
+ dispatch(message, iterator);
}
private class ActionInvocationHandler implements Dispatch<MethodInvocation> {
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/event/DefaultListenerManager.java b/subprojects/messaging/src/main/java/org/gradle/internal/event/DefaultListenerManager.java
index 7cfc921..d9eace4 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/event/DefaultListenerManager.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/event/DefaultListenerManager.java
@@ -16,22 +16,20 @@
package org.gradle.internal.event;
+import org.gradle.internal.UncheckedException;
import org.gradle.messaging.dispatch.Dispatch;
import org.gradle.messaging.dispatch.MethodInvocation;
+import org.gradle.messaging.dispatch.ProxyDispatchAdapter;
import org.gradle.messaging.dispatch.ReflectionDispatch;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
@SuppressWarnings({"unchecked"})
public class DefaultListenerManager implements ListenerManager {
- private final Set<Object> allListeners = new LinkedHashSet<Object>();
- private final Set<Object> allLoggers = new LinkedHashSet<Object>();
- private final Map<Class<?>, ListenerBroadcast> broadcasters = new HashMap<Class<?>, ListenerBroadcast>();
- private final Map<Class<?>, LoggerDispatch> loggers = new HashMap<Class<?>, LoggerDispatch>();
- private final Map<Class<?>, BroadcastDispatch> dispatchers = new HashMap<Class<?>, BroadcastDispatch>();
+ private final Map<Object, ListenerDetails> allListeners = new LinkedHashMap<Object, ListenerDetails>();
+ private final Map<Object, ListenerDetails> allLoggers = new LinkedHashMap<Object, ListenerDetails>();
+ private final Map<Class<?>, EventBroadcast> broadcasters = new HashMap<Class<?>, EventBroadcast>();
private final Object lock = new Object();
private final DefaultListenerManager parent;
@@ -45,9 +43,11 @@ public class DefaultListenerManager implements ListenerManager {
public void addListener(Object listener) {
synchronized (lock) {
- if (allListeners.add(listener)) {
- for (BroadcastDispatch<?> broadcaster : dispatchers.values()) {
- maybeAddToDispatcher(broadcaster, listener);
+ if (!allListeners.containsKey(listener)) {
+ ListenerDetails details = new ListenerDetails(listener);
+ allListeners.put(listener, details);
+ for (EventBroadcast<?> broadcaster : broadcasters.values()) {
+ broadcaster.maybeAdd(details);
}
}
}
@@ -55,108 +55,225 @@ public class DefaultListenerManager implements ListenerManager {
public void removeListener(Object listener) {
synchronized (lock) {
- if (allListeners.remove(listener)) {
- for (BroadcastDispatch<?> broadcaster : dispatchers.values()) {
- broadcaster.remove(listener);
+ ListenerDetails details = allListeners.remove(listener);
+ if (details != null) {
+ details.disconnect();
+ for (EventBroadcast<?> broadcaster : broadcasters.values()) {
+ broadcaster.maybeRemove(details);
}
+ details.untilNotInUse(Thread.currentThread());
}
}
}
public void useLogger(Object logger) {
synchronized (lock) {
- if (allLoggers.add(logger)) {
- for (LoggerDispatch dispatch : loggers.values()) {
- dispatch.maybeSetLogger(logger);
+ if (!allLoggers.containsKey(logger)) {
+ ListenerDetails details = new ListenerDetails(logger);
+ allLoggers.put(logger, details);
+ for (EventBroadcast<?> broadcaster : broadcasters.values()) {
+ broadcaster.maybeSetLogger(details);
}
}
}
}
public <T> T getBroadcaster(Class<T> listenerClass) {
- return getBroadcasterInternal(listenerClass).getSource();
+ return getBroadcasterInternal(listenerClass).getBroadcaster();
}
public <T> ListenerBroadcast<T> createAnonymousBroadcaster(Class<T> listenerClass) {
ListenerBroadcast<T> broadcast = new ListenerBroadcast(listenerClass);
- broadcast.add(getBroadcasterInternal(listenerClass).getSource());
+ broadcast.add(getBroadcasterInternal(listenerClass).getDispatch(true));
return broadcast;
}
- private <T> ListenerBroadcast<T> getBroadcasterInternal(Class<T> listenerClass) {
+ private <T> EventBroadcast<T> getBroadcasterInternal(Class<T> listenerClass) {
synchronized (lock) {
- ListenerBroadcast<T> broadcaster = broadcasters.get(listenerClass);
+ EventBroadcast<T> broadcaster = broadcasters.get(listenerClass);
if (broadcaster == null) {
- broadcaster = new ListenerBroadcast<T>(listenerClass);
- broadcaster.add(getLogger(listenerClass));
- broadcaster.add(getDispatcher(listenerClass));
- if (parent != null) {
- broadcaster.add(parent.getDispatcher(listenerClass));
- }
+ broadcaster = new EventBroadcast<T>(listenerClass);
broadcasters.put(listenerClass, broadcaster);
+ for (ListenerDetails listener : allListeners.values()) {
+ broadcaster.maybeAdd(listener);
+ }
+ for (ListenerDetails logger : allLoggers.values()) {
+ broadcaster.maybeSetLogger(logger);
+ }
}
-
return broadcaster;
}
}
- private <T> BroadcastDispatch<T> getDispatcher(Class<T> listenerClass) {
- synchronized (lock) {
- BroadcastDispatch<T> dispatcher = dispatchers.get(listenerClass);
- if (dispatcher == null) {
- dispatcher = new BroadcastDispatch<T>(listenerClass);
- dispatchers.put(listenerClass, dispatcher);
- for (Object listener : allListeners) {
- maybeAddToDispatcher(dispatcher, listener);
+ public ListenerManager createChild() {
+ return new DefaultListenerManager(this);
+ }
+
+ private class EventBroadcast<T> {
+ private final Class<T> type;
+ private final ProxyDispatchAdapter<T> source;
+ private final ListenerDispatch dispatch;
+ private final ListenerDispatch dispatchNoLogger;
+
+ // The following state is protected by lock
+ private final Set<ListenerDetails> listeners = new LinkedHashSet<ListenerDetails>();
+ private ListenerDetails logger;
+ private Dispatch<MethodInvocation> parentDispatch;
+ private Thread owner;
+
+ EventBroadcast(Class<T> type) {
+ this.type = type;
+ dispatch = new ListenerDispatch(type, true);
+ dispatchNoLogger = new ListenerDispatch(type, false);
+ if (parent != null) {
+ parentDispatch = parent.getBroadcasterInternal(type).getDispatch(true);
+ }
+ source = new ProxyDispatchAdapter<T>(dispatch, type);
+ }
+
+ Dispatch<MethodInvocation> getDispatch(boolean includeLogger) {
+ return includeLogger ? dispatch : dispatchNoLogger;
+ }
+
+ T getBroadcaster() {
+ return source.getSource();
+ }
+
+ // Must be holding lock
+ void maybeAdd(ListenerDetails listener) {
+ if (type.isInstance(listener.listener)) {
+ listeners.add(listener);
+ }
+ }
+
+ // Must be holding lock
+ void maybeRemove(ListenerDetails listener) {
+ listeners.remove(listener);
+ // Another thread may be using listener
+ }
+
+ // Must be holding lock
+ void maybeSetLogger(ListenerDetails candidate) {
+ if (type.isInstance(candidate.listener)) {
+ if (logger == null && parent != null) {
+ parentDispatch = parent.getBroadcasterInternal(type).getDispatch(false);
}
+ logger = candidate;
}
- return dispatcher;
}
- }
- private LoggerDispatch getLogger(Class<?> listenerClass) {
- synchronized (lock) {
- LoggerDispatch dispatch = loggers.get(listenerClass);
- if (dispatch == null) {
- dispatch = new LoggerDispatch(listenerClass, parent == null ? null : parent.getLogger(listenerClass));
- for (Object logger : allLoggers) {
- dispatch.maybeSetLogger(logger);
+ private List<Dispatch<MethodInvocation>> startNotification(boolean includeLogger) {
+ synchronized (lock) {
+ // Mark this listener type as being notified
+ while (owner != null) {
+ if (owner == Thread.currentThread()) {
+ throw new IllegalStateException(String.format("Cannot notify listeners of type %s as these listeners are already being notified.", type.getSimpleName()));
+ }
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
}
- loggers.put(listenerClass, dispatch);
+ owner = Thread.currentThread();
+
+ // Take a snapshot while holding lock
+ List<Dispatch<MethodInvocation>> dispatchers = new ArrayList<Dispatch<MethodInvocation>>(listeners.size() + 2);
+ if (includeLogger && logger != null) {
+ dispatchers.add(logger);
+ }
+ if (parentDispatch != null) {
+ dispatchers.add(parentDispatch);
+ }
+ for (ListenerDetails listener : listeners) {
+ listener.startNotification(owner);
+ dispatchers.add(listener);
+ }
+ return dispatchers;
}
- return dispatch;
}
- }
- private void maybeAddToDispatcher(BroadcastDispatch broadcaster, Object listener) {
- if (broadcaster.getType().isInstance(listener)) {
- broadcaster.add(listener);
+ private void endNotification(List<Dispatch<MethodInvocation>> dispatchers) {
+ synchronized (lock) {
+ for (Dispatch<MethodInvocation> dispatcher : dispatchers) {
+ if (dispatcher instanceof ListenerDetails) {
+ ListenerDetails listener = (ListenerDetails) dispatcher;
+ listener.endNotification(owner);
+ }
+ }
+ owner = null;
+ lock.notifyAll();
+ }
}
- }
- public ListenerManager createChild() {
- return new DefaultListenerManager(this);
+ private class ListenerDispatch extends AbstractBroadcastDispatch<T> {
+ private final boolean includeLogger;
+
+ public ListenerDispatch(Class<T> type, boolean includeLogger) {
+ super(type);
+ this.includeLogger = includeLogger;
+ }
+
+ @Override
+ public void dispatch(MethodInvocation invocation) {
+ List<Dispatch<MethodInvocation>> dispatchers = startNotification(includeLogger);
+ try {
+ dispatch(invocation, dispatchers.iterator());
+ } finally {
+ endNotification(dispatchers);
+ }
+ }
+ }
}
- private static class LoggerDispatch implements Dispatch<MethodInvocation> {
- private final Class<?> type;
- private Dispatch<MethodInvocation> dispatch;
+ private class ListenerDetails implements Dispatch<MethodInvocation> {
+ final Object listener;
+ final Dispatch<MethodInvocation> dispatch;
+ final AtomicBoolean removed = new AtomicBoolean();
- private LoggerDispatch(Class<?> type, LoggerDispatch parentDispatch) {
- this.type = type;
- this.dispatch = parentDispatch;
+ // Protected by lock
+ Thread owner;
+
+ public ListenerDetails(Object listener) {
+ this.listener = listener;
+ this.dispatch = new ReflectionDispatch(listener);
+ }
+
+ void disconnect() {
+ removed.set(true);
}
+ @Override
public void dispatch(MethodInvocation message) {
- if (dispatch != null) {
+ if (!removed.get()) {
dispatch.dispatch(message);
}
}
- public void maybeSetLogger(Object logger) {
- if (type.isInstance(logger)) {
- dispatch = new ReflectionDispatch(logger);
+ // Must be holding lock
+ public void startNotification(Thread owner) {
+ untilNotInUse(owner);
+ this.owner = owner;
+ }
+
+ // Must be holding lock
+ public void untilNotInUse(Thread expectedOwner) {
+ while (this.owner != null && this.owner != expectedOwner) {
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+ }
+
+ // Must be holding lock
+ public void endNotification(Thread owner) {
+ if (this.owner != owner && this.owner != null) {
+ throw new IllegalStateException("Unexpected owner for listener.");
}
+ this.owner = null;
+ lock.notifyAll();
}
}
}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/event/ListenerManager.java b/subprojects/messaging/src/main/java/org/gradle/internal/event/ListenerManager.java
index 14b83b0..61bac11 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/event/ListenerManager.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/event/ListenerManager.java
@@ -20,8 +20,10 @@ package org.gradle.internal.event;
* Unified manager for all listeners for Gradle. Provides a simple way to find all listeners of a given type in the
* system.
*
- * While the methods work with any Object, in general only interfaces should be used as listener types. Also, due to
- * implementation details, any listener method with a non-void return type will return a null.
+ * <p>While the methods work with any Object, in general only interfaces should be used as listener types.
+ *
+ * <p>Implementations are thread-safe: A listener is notified by at most 1 thread at a time, and so do not need to be thread-safe. All listeners
+ * of a given type received events in the same order. Listeners can be added and removed at any time.
*/
public interface ListenerManager {
/**
@@ -29,6 +31,10 @@ public interface ListenerManager {
* single invocation of this method. There is no order dependency: if a broadcaster has already been made for type
* T, the listener will be registered with it if <code>(listener instanceof T)</code> returns true.
*
+ * <p>A listener will be used by a single thread at a time, so the listener implementation does not need to be thread-safe.
+ *
+ * <p>The listener will not receive events that are currently being broadcast from some other thread.
+ *
* @param listener the listener to add.
*/
void addListener(Object listener);
@@ -38,14 +44,21 @@ public interface ListenerManager {
* single invocation of this method. There is no order dependency: if a broadcaster has already been made for type
* T, the listener will be unregistered with it if <code>(listener instanceof T)</code> returns true.
*
+ * <p>When this method returns, the listener will not be in use and will not receive any further events.
+ *
* @param listener the listener to remove.
*/
void removeListener(Object listener);
/**
- * Returns a broadcaster for the given listenerClass. If there are no registered listeners for that type, a
- * broadcaster is returned which does not forward method calls to any listeners. The returned broadcasters are
- * live, that is their list of listeners can be updated by calls to {@link #addListener(Object)} and {@link
+ * Returns a broadcaster for the given listenerClass. Any method invoked on the broadcaster is forwarded to all registered
+ * listeners of the given type. This is done synchronously. Any listener method with a non-void return type will return a null.
+ * Exceptions are propagated, and multiple failures are packaged up in a {@link ListenerNotificationException}.
+ *
+ * <p>A listener is used by a single thread at a time.
+ *
+ * <p>If there are no registered listeners for the requested type, a broadcaster is returned which does not forward method calls to any listeners.
+ * The returned broadcasters are live, that is their list of listeners can be updated by calls to {@link #addListener(Object)} and {@link
* #removeListener(Object)} after they have been returned. Broadcasters are also cached, so that repeatedly calling
* this method with the same listenerClass returns the same broadcaster object.
*
@@ -63,6 +76,8 @@ public interface ListenerManager {
* of the listener as they need. The client code must provide some way for its users to register listeners on the
* specialized broadcasters.
*
+ * <p>The returned value is not thread-safe.</p>
+ *
* @param listenerClass The type of listener for which to create a broadcaster.
* @return A broadcaster that forwards method calls to all listeners assigned to it, or of the same type that have
* been (or will be) registered with this manager.
@@ -71,7 +86,7 @@ public interface ListenerManager {
/**
* Uses the given object as a logger. Each listener class has exactly one logger associated with it. Any existing
- * logger for the listener class is discarded.
+ * logger for the listener class is discarded. Loggers are otherwise treated the same way as listeners.
*
* @param logger The new logger to use.
*/
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/BaseSerializerFactory.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/BaseSerializerFactory.java
index 1ebc2e3..8648dc0 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/BaseSerializerFactory.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/BaseSerializerFactory.java
@@ -17,6 +17,7 @@
package org.gradle.internal.serialize;
import com.google.common.collect.ImmutableMap;
+import org.gradle.messaging.remote.internal.Message;
import java.io.File;
import java.util.Map;
@@ -28,6 +29,7 @@ public class BaseSerializerFactory {
public static final Serializer<File> FILE_SERIALIZER = new FileSerializer();
public static final Serializer<byte[]> BYTE_ARRAY_SERIALIZER = new ByteArraySerializer();
public static final Serializer<Map<String, String>> NO_NULL_STRING_MAP_SERIALIZER = new StringMapSerializer();
+ public static final Serializer<Throwable> THROWABLE_SERIALIZER = new ThrowableSerializer();
public <T> Serializer<T> getSerializerFor(Class<T> type) {
if (type.equals(String.class)) {
@@ -48,6 +50,9 @@ public class BaseSerializerFactory {
if (type.equals(Boolean.class)) {
return (Serializer<T>) BOOLEAN_SERIALIZER;
}
+ if (Throwable.class.isAssignableFrom(type)) {
+ return (Serializer<T>) THROWABLE_SERIALIZER;
+ }
return new DefaultSerializer<T>(type.getClassLoader());
}
@@ -137,4 +142,14 @@ public class BaseSerializerFactory {
encoder.writeBoolean(value);
}
}
+
+ private static class ThrowableSerializer implements Serializer<Throwable> {
+ public Throwable read(Decoder decoder) throws Exception {
+ return (Throwable) Message.receive(decoder.getInputStream(), getClass().getClassLoader());
+ }
+
+ public void write(Encoder encoder, Throwable value) throws Exception {
+ Message.send(value, encoder.getOutputStream());
+ }
+ }
}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Decoder.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Decoder.java
index 9096b4e..3c81598 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Decoder.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Decoder.java
@@ -39,7 +39,7 @@ public interface Decoder {
long readLong() throws EOFException, IOException;
/**
- * Reads a signed 64 bit int value. Can read any value that was written using {@link Encoder#writeSmallLong(int)}.
+ * Reads a signed 64 bit int value. Can read any value that was written using {@link Encoder#writeSmallLong(long)}.
*
* @throws EOFException when the end of the byte stream is reached before the int value can be fully read.
*/
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/DefaultSerializerRegistry.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/DefaultSerializerRegistry.java
index e25e26a..80b1292 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/DefaultSerializerRegistry.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/DefaultSerializerRegistry.java
@@ -16,10 +16,7 @@
package org.gradle.internal.serialize;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeMap;
+import java.util.*;
public class DefaultSerializerRegistry<T> implements SerializerRegistry<T> {
private final Map<Class<?>, Serializer<?>> serializerMap = new TreeMap<Class<?>, Serializer<?>>(new Comparator<Class<?>>() {
@@ -27,45 +24,61 @@ public class DefaultSerializerRegistry<T> implements SerializerRegistry<T> {
return o1.getName().compareTo(o2.getName());
}
});
+ private final Set<Class<?>> javaSerialization = new HashSet<Class<?>>();
public <U extends T> void register(Class<U> implementationType, Serializer<U> serializer) {
serializerMap.put(implementationType, serializer);
}
+ @Override
+ public <U extends T> void useJavaSerialization(Class<U> implementationType) {
+ javaSerialization.add(implementationType);
+ }
+
public Serializer<T> build() {
- if (serializerMap.size() == 1) {
+ if (serializerMap.size() == 1 && javaSerialization.isEmpty()) {
return (Serializer<T>) serializerMap.values().iterator().next();
}
- TaggedTypeSerializer<T> serializer = new TaggedTypeSerializer<T>();
- for (Map.Entry<Class<?>, Serializer<?>> entry : serializerMap.entrySet()) {
- serializer.add(entry.getKey(), entry.getValue());
- }
- return serializer;
+ return new TaggedTypeSerializer<T>(serializerMap, javaSerialization);
}
private static class TypeInfo {
- final byte tag;
+ final int tag;
final Serializer serializer;
- private TypeInfo(byte tag, Serializer serializer) {
+ private TypeInfo(int tag, Serializer serializer) {
this.tag = tag;
this.serializer = serializer;
}
}
private static class TaggedTypeSerializer<T> implements Serializer<T> {
+ private static final int JAVA_TYPE = 1; // Reserve 0 for null (to be added later)
+ private static final TypeInfo JAVA_SERIALIZATION = new TypeInfo(JAVA_TYPE, new DefaultSerializer<Object>());
private final Map<Class<?>, TypeInfo> serializersByType = new HashMap<Class<?>, TypeInfo>();
- private final Map<Byte, TypeInfo> serializersByTag = new HashMap<Byte, TypeInfo>();
+ private final TypeInfo[] serializersByTag;
+ private final Set<Class<?>> javaSerialization;
+
+ public TaggedTypeSerializer(Map<Class<?>, Serializer<?>> serializerMap, Set<Class<?>> javaSerialization) {
+ this.javaSerialization = new HashSet<Class<?>>(javaSerialization);
+ serializersByTag = new TypeInfo[2 + serializerMap.size()];
+ serializersByTag[JAVA_TYPE] = JAVA_SERIALIZATION;
+ int nextTag = 2;
+ for (Map.Entry<Class<?>, Serializer<?>> entry : serializerMap.entrySet()) {
+ add(nextTag, entry.getKey(), entry.getValue());
+ nextTag++;
+ }
+ }
- private <T> void add(Class<?> type, Serializer<?> serializer) {
- TypeInfo typeInfo = new TypeInfo((byte) serializersByTag.size(), serializer);
+ private void add(int tag, Class<?> type, Serializer<?> serializer) {
+ TypeInfo typeInfo = new TypeInfo(tag, serializer);
serializersByType.put(type, typeInfo);
- serializersByTag.put(typeInfo.tag, typeInfo);
+ serializersByTag[typeInfo.tag] = typeInfo;
}
public T read(Decoder decoder) throws Exception {
- byte tag = decoder.readByte();
- TypeInfo typeInfo = serializersByTag.get(tag);
+ int tag = decoder.readSmallInt();
+ TypeInfo typeInfo = tag >= serializersByTag.length ? null : serializersByTag[tag];
if (typeInfo == null) {
throw new IllegalArgumentException(String.format("Unexpected type tag %d found.", tag));
}
@@ -73,13 +86,23 @@ public class DefaultSerializerRegistry<T> implements SerializerRegistry<T> {
}
public void write(Encoder encoder, T value) throws Exception {
- Class<?> targetType = value instanceof Throwable ? Throwable.class : value.getClass();
+ TypeInfo typeInfo = map(value.getClass());
+ encoder.writeSmallInt(typeInfo.tag);
+ typeInfo.serializer.write(encoder, value);
+ }
+
+ private TypeInfo map(Class<?> valueType) {
+ Class<?> targetType = Throwable.class.isAssignableFrom(valueType) ? Throwable.class : valueType;
TypeInfo typeInfo = serializersByType.get(targetType);
- if (typeInfo == null) {
- throw new IllegalArgumentException(String.format("Don't know how to serialize an object of type %s.", value.getClass().getName()));
+ if (typeInfo != null) {
+ return typeInfo;
}
- encoder.writeByte(typeInfo.tag);
- typeInfo.serializer.write(encoder, value);
+ for (Class<?> candidate : javaSerialization) {
+ if (candidate.isAssignableFrom(targetType)) {
+ return JAVA_SERIALIZATION;
+ }
+ }
+ throw new IllegalArgumentException(String.format("Don't know how to serialize an object of type %s.", valueType.getName()));
}
}
}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/ObjectArraySerializer.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/ObjectArraySerializer.java
new file mode 100644
index 0000000..eb8af0c
--- /dev/null
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/ObjectArraySerializer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.serialize;
+
+public class ObjectArraySerializer implements Serializer<Object[]> {
+ private final Serializer<Object> elementSerializer;
+
+ public ObjectArraySerializer(Serializer<Object> elementSerializer) {
+ this.elementSerializer = elementSerializer;
+ }
+
+ @Override
+ public void write(Encoder encoder, Object[] value) throws Exception {
+ encoder.writeSmallInt(value.length);
+ for (int i = 0; i < value.length; i++) {
+ elementSerializer.write(encoder, value[i]);
+ }
+ }
+
+ @Override
+ public Object[] read(Decoder decoder) throws Exception {
+ int len = decoder.readSmallInt();
+ Object[] result = new Object[len];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = elementSerializer.read(decoder);
+ }
+ return result;
+ }
+}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/ObjectReader.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/ObjectReader.java
index d9666c7..b4f9c0d 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/ObjectReader.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/ObjectReader.java
@@ -16,6 +16,13 @@
package org.gradle.internal.serialize;
+import java.io.EOFException;
+
public interface ObjectReader<T> {
- T read() throws Exception;
+ /**
+ * Reads the next object from the stream.
+ *
+ * @throws EOFException When the next object cannot be fully read due to reaching the end of stream.
+ */
+ T read() throws EOFException, Exception;
}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Serializer.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Serializer.java
index 7f503be..aff7c8b 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Serializer.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Serializer.java
@@ -15,12 +15,16 @@
*/
package org.gradle.internal.serialize;
+import java.io.EOFException;
+
public interface Serializer<T> {
/**
* Reads the next object from the given stream. The implementation must not perform any buffering, so that it reads only those bytes from the input stream that are
* required to deserialize the next object.
+ *
+ * @throws EOFException When the next object cannot be fully read due to reaching the end of stream.
*/
- T read(Decoder decoder) throws Exception;
+ T read(Decoder decoder) throws EOFException, Exception;
/**
* Writes the given object to the given stream. The implementation must not perform any buffering.
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/SerializerRegistry.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/SerializerRegistry.java
index 5d39fd4..5153ede 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/SerializerRegistry.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/SerializerRegistry.java
@@ -17,7 +17,19 @@
package org.gradle.internal.serialize;
public interface SerializerRegistry<T> {
+ /**
+ * Use the given serializer for objects of the given type.
+ */
<U extends T> void register(Class<U> implementationType, Serializer<U> serializer);
+ /**
+ * Use Java serialization for the specified type and all subtypes. Should be avoided, but useful when migrating to using serializers or when dealing with
+ * arbitrary user types.
+ */
+ <U extends T> void useJavaSerialization(Class<U> implementationType);
+
+ /**
+ * Creates a serializer that uses the current registrations.
+ */
Serializer<T> build();
}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Serializers.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Serializers.java
new file mode 100644
index 0000000..baff541
--- /dev/null
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/Serializers.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.serialize;
+
+public class Serializers {
+ public static <T> StatefulSerializer<T> stateful(final Serializer<T> serializer) {
+ return new StatefulSerializerAdapter<T>(serializer);
+ }
+
+ private static class StatefulSerializerAdapter<T> implements StatefulSerializer<T> {
+ private final Serializer<T> serializer;
+
+ public StatefulSerializerAdapter(Serializer<T> serializer) {
+ this.serializer = serializer;
+ }
+
+ @Override
+ public ObjectReader<T> newReader(final Decoder decoder) {
+ return new ObjectReader<T>() {
+ @Override
+ public T read() throws Exception {
+ return serializer.read(decoder);
+ }
+ };
+ }
+
+ @Override
+ public ObjectWriter<T> newWriter(final Encoder encoder) {
+ return new ObjectWriter<T>() {
+ @Override
+ public void write(T value) throws Exception {
+ serializer.write(encoder, value);
+ }
+ };
+ }
+ }
+}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/StatefulSerializer.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/StatefulSerializer.java
new file mode 100644
index 0000000..0b9ffc5
--- /dev/null
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/StatefulSerializer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.serialize;
+
+public interface StatefulSerializer<T> {
+ /**
+ * Should not perform any buffering
+ */
+ ObjectReader<T> newReader(Decoder decoder);
+
+ /**
+ * Should not perform any buffering
+ */
+ ObjectWriter<T> newWriter(Encoder encoder);
+}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/JavaSerializer.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/JavaSerializer.java
index 02bf471..3aa2d52 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/JavaSerializer.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/JavaSerializer.java
@@ -16,10 +16,7 @@
package org.gradle.internal.serialize.kryo;
-import org.gradle.internal.serialize.Decoder;
-import org.gradle.internal.serialize.Encoder;
-import org.gradle.internal.serialize.ObjectReader;
-import org.gradle.internal.serialize.ObjectWriter;
+import org.gradle.internal.serialize.*;
import org.gradle.messaging.remote.internal.Message;
public class JavaSerializer<T> implements StatefulSerializer<T> {
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/StatefulSerializer.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/StatefulSerializer.java
deleted file mode 100644
index d9550cc..0000000
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/StatefulSerializer.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.serialize.kryo;
-
-import org.gradle.internal.serialize.Decoder;
-import org.gradle.internal.serialize.Encoder;
-import org.gradle.internal.serialize.ObjectReader;
-import org.gradle.internal.serialize.ObjectWriter;
-
-public interface StatefulSerializer<T> {
- ObjectReader<T> newReader(Decoder decoder);
-
- ObjectWriter<T> newWriter(Encoder encoder);
-}
diff --git a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/TypeSafeSerializer.java b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/TypeSafeSerializer.java
index 68790f3..86d3504 100644
--- a/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/TypeSafeSerializer.java
+++ b/subprojects/messaging/src/main/java/org/gradle/internal/serialize/kryo/TypeSafeSerializer.java
@@ -16,10 +16,7 @@
package org.gradle.internal.serialize.kryo;
-import org.gradle.internal.serialize.Decoder;
-import org.gradle.internal.serialize.Encoder;
-import org.gradle.internal.serialize.ObjectReader;
-import org.gradle.internal.serialize.ObjectWriter;
+import org.gradle.internal.serialize.*;
public class TypeSafeSerializer<T> implements StatefulSerializer<Object> {
private final Class<T> type;
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/ObjectConnectionBuilder.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/ObjectConnectionBuilder.java
index 148fe05..e234512 100755
--- a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/ObjectConnectionBuilder.java
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/ObjectConnectionBuilder.java
@@ -15,7 +15,7 @@
*/
package org.gradle.messaging.remote;
-import org.gradle.internal.serialize.kryo.StatefulSerializer;
+import org.gradle.internal.serialize.Serializer;
public interface ObjectConnectionBuilder {
/**
@@ -41,9 +41,9 @@ public interface ObjectConnectionBuilder {
<T> void addIncoming(Class<T> type, T instance);
/**
- * Use the specified serializer for all incoming and outgoing parameters.
+ * Use the specified serializer for all incoming and outgoing method parameters.
*/
- void useParameterSerializer(StatefulSerializer<Object[]> serializer);
+ void useParameterSerializer(Serializer<Object[]> serializer);
/**
* Use Java serialization for the parameters of incoming and outgoing method calls, with the specified ClassLoader used to deserialize incoming
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/KryoBackedMessageSerializer.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/KryoBackedMessageSerializer.java
new file mode 100644
index 0000000..cf4df84
--- /dev/null
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/KryoBackedMessageSerializer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.messaging.remote.internal;
+
+import org.gradle.internal.serialize.Decoder;
+import org.gradle.internal.serialize.FlushableEncoder;
+import org.gradle.internal.serialize.ObjectReader;
+import org.gradle.internal.serialize.ObjectWriter;
+import org.gradle.internal.serialize.kryo.KryoBackedDecoder;
+import org.gradle.internal.serialize.kryo.KryoBackedEncoder;
+import org.gradle.internal.serialize.StatefulSerializer;
+import org.gradle.messaging.remote.Address;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A message serializer that uses Kryo to perform encoding/decoding
+ * @param <T>
+ */
+public class KryoBackedMessageSerializer<T> implements MessageSerializer<T> {
+ private final StatefulSerializer<T> payloadSerializer;
+
+ public KryoBackedMessageSerializer(StatefulSerializer<T> payloadSerializer) {
+ this.payloadSerializer = payloadSerializer;
+ }
+
+ @Override
+ public ObjectReader<T> newReader(InputStream inputStream, Address localAddress, Address remoteAddress) {
+ Decoder decoder = new KryoBackedDecoder(inputStream);
+ return payloadSerializer.newReader(decoder);
+ }
+
+ @Override
+ public ObjectWriter<T> newWriter(OutputStream outputStream) {
+ final FlushableEncoder encoder = new KryoBackedEncoder(outputStream);
+ final ObjectWriter<T> writer = payloadSerializer.newWriter(encoder);
+ return new ObjectWriter<T>() {
+ @Override
+ public void write(T value) throws Exception {
+ writer.write(value);
+ encoder.flush();
+ }
+ };
+ }
+}
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializer.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializer.java
index c7c4193..17188f2 100644
--- a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializer.java
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializer.java
@@ -16,27 +16,21 @@
package org.gradle.messaging.remote.internal.hub;
-import org.gradle.messaging.remote.Address;
-import org.gradle.messaging.remote.internal.MessageSerializer;
+import org.gradle.internal.serialize.Decoder;
+import org.gradle.internal.serialize.Encoder;
+import org.gradle.internal.serialize.ObjectReader;
+import org.gradle.internal.serialize.ObjectWriter;
+import org.gradle.internal.serialize.StatefulSerializer;
import org.gradle.messaging.remote.internal.hub.protocol.ChannelIdentifier;
import org.gradle.messaging.remote.internal.hub.protocol.ChannelMessage;
import org.gradle.messaging.remote.internal.hub.protocol.EndOfStream;
import org.gradle.messaging.remote.internal.hub.protocol.InterHubMessage;
-import org.gradle.internal.serialize.Decoder;
-import org.gradle.internal.serialize.FlushableEncoder;
-import org.gradle.internal.serialize.ObjectReader;
-import org.gradle.internal.serialize.ObjectWriter;
-import org.gradle.internal.serialize.kryo.StatefulSerializer;
-import org.gradle.internal.serialize.kryo.KryoBackedDecoder;
-import org.gradle.internal.serialize.kryo.KryoBackedEncoder;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
-public class InterHubMessageSerializer implements MessageSerializer<InterHubMessage> {
+public class InterHubMessageSerializer implements StatefulSerializer<InterHubMessage> {
private static final byte CHANNEL_MESSAGE = 1;
private static final byte END_STREAM_MESSAGE = 2;
private final StatefulSerializer<Object> payloadSerializer;
@@ -45,13 +39,13 @@ public class InterHubMessageSerializer implements MessageSerializer<InterHubMess
this.payloadSerializer = payloadSerializer;
}
- public ObjectReader<InterHubMessage> newReader(InputStream inputStream, Address localAddress, Address remoteAddress) {
- Decoder decoder = new KryoBackedDecoder(inputStream);
+ @Override
+ public ObjectReader<InterHubMessage> newReader(Decoder decoder) {
return new MessageReader(decoder, payloadSerializer.newReader(decoder));
}
- public ObjectWriter<InterHubMessage> newWriter(OutputStream outputStream) {
- FlushableEncoder encoder = new KryoBackedEncoder(outputStream);
+ @Override
+ public ObjectWriter<InterHubMessage> newWriter(Encoder encoder) {
return new MessageWriter(encoder, payloadSerializer.newWriter(encoder));
}
@@ -92,10 +86,10 @@ public class InterHubMessageSerializer implements MessageSerializer<InterHubMess
private static class MessageWriter implements ObjectWriter<InterHubMessage> {
private final Map<ChannelIdentifier, Integer> channels = new HashMap<ChannelIdentifier, Integer>();
- private final FlushableEncoder encoder;
+ private final Encoder encoder;
private final ObjectWriter<Object> payloadWriter;
- public MessageWriter(FlushableEncoder encoder, ObjectWriter<Object> payloadWriter) {
+ public MessageWriter(Encoder encoder, ObjectWriter<Object> payloadWriter) {
this.encoder = encoder;
this.payloadWriter = payloadWriter;
}
@@ -111,7 +105,6 @@ public class InterHubMessageSerializer implements MessageSerializer<InterHubMess
} else {
throw new IllegalArgumentException();
}
- encoder.flush();
}
private void writeChannelId(ChannelMessage channelMessage) throws IOException {
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MessageHubBackedObjectConnection.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MessageHubBackedObjectConnection.java
index e1a3428..cf9eaeb 100644
--- a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MessageHubBackedObjectConnection.java
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MessageHubBackedObjectConnection.java
@@ -20,17 +20,20 @@ import org.gradle.api.Action;
import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.concurrent.ExecutorFactory;
import org.gradle.internal.concurrent.ThreadSafe;
+import org.gradle.internal.serialize.Serializer;
+import org.gradle.internal.serialize.Serializers;
+import org.gradle.internal.serialize.kryo.JavaSerializer;
+import org.gradle.internal.serialize.StatefulSerializer;
+import org.gradle.internal.serialize.kryo.TypeSafeSerializer;
import org.gradle.messaging.dispatch.MethodInvocation;
import org.gradle.messaging.dispatch.ProxyDispatchAdapter;
import org.gradle.messaging.dispatch.ReflectionDispatch;
import org.gradle.messaging.remote.ObjectConnection;
import org.gradle.messaging.remote.internal.ConnectCompletion;
import org.gradle.messaging.remote.internal.Connection;
+import org.gradle.messaging.remote.internal.KryoBackedMessageSerializer;
import org.gradle.messaging.remote.internal.MessageSerializer;
import org.gradle.messaging.remote.internal.hub.protocol.InterHubMessage;
-import org.gradle.internal.serialize.kryo.JavaSerializer;
-import org.gradle.internal.serialize.kryo.StatefulSerializer;
-import org.gradle.internal.serialize.kryo.TypeSafeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,7 +43,7 @@ public class MessageHubBackedObjectConnection implements ObjectConnection {
private ConnectCompletion completion;
private Connection<InterHubMessage> connection;
private ClassLoader methodParamClassLoader;
- private StatefulSerializer<Object[]> paramSerializer;
+ private Serializer<Object[]> paramSerializer;
public MessageHubBackedObjectConnection(ExecutorFactory executorFactory, ConnectCompletion completion) {
this.hub = new MessageHub(completion.toString(), executorFactory, new Action<Throwable>() {
@@ -70,7 +73,7 @@ public class MessageHubBackedObjectConnection implements ObjectConnection {
this.methodParamClassLoader = methodParamClassLoader;
}
- public void useParameterSerializer(StatefulSerializer<Object[]> serializer) {
+ public void useParameterSerializer(Serializer<Object[]> serializer) {
this.paramSerializer = serializer;
}
@@ -79,15 +82,19 @@ public class MessageHubBackedObjectConnection implements ObjectConnection {
methodParamClassLoader = getClass().getClassLoader();
}
- StatefulSerializer<Object[]> paramSerializer = this.paramSerializer;
- if (paramSerializer == null) {
+ StatefulSerializer<Object[]> paramSerializer;
+ if (this.paramSerializer != null) {
+ paramSerializer = Serializers.stateful(this.paramSerializer);
+ } else {
paramSerializer = new JavaSerializer<Object[]>(methodParamClassLoader);
}
- MessageSerializer<InterHubMessage> serializer = new InterHubMessageSerializer(
- new TypeSafeSerializer<MethodInvocation>(MethodInvocation.class, new MethodInvocationSerializer(
- methodParamClassLoader,
- paramSerializer)));
+ MessageSerializer<InterHubMessage> serializer = new KryoBackedMessageSerializer<InterHubMessage>(
+ new InterHubMessageSerializer(
+ new TypeSafeSerializer<MethodInvocation>(MethodInvocation.class,
+ new MethodInvocationSerializer(
+ methodParamClassLoader,
+ paramSerializer))));
connection = completion.create(serializer);
hub.addConnection(connection);
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializer.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializer.java
index cb53750..e7ccbd2 100644
--- a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializer.java
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializer.java
@@ -21,7 +21,7 @@ import org.gradle.internal.serialize.Decoder;
import org.gradle.internal.serialize.Encoder;
import org.gradle.internal.serialize.ObjectReader;
import org.gradle.internal.serialize.ObjectWriter;
-import org.gradle.internal.serialize.kryo.StatefulSerializer;
+import org.gradle.internal.serialize.StatefulSerializer;
import java.io.IOException;
import java.lang.reflect.Method;
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/SocketConnection.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/SocketConnection.java
index e1e1a09..086dda2 100755
--- a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/SocketConnection.java
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/SocketConnection.java
@@ -19,11 +19,13 @@ package org.gradle.messaging.remote.internal.inet;
import com.google.common.base.Objects;
import org.gradle.internal.UncheckedException;
import org.gradle.internal.concurrent.CompositeStoppable;
+import org.gradle.internal.serialize.ObjectReader;
+import org.gradle.internal.serialize.ObjectWriter;
import org.gradle.messaging.remote.internal.MessageIOException;
import org.gradle.messaging.remote.internal.MessageSerializer;
import org.gradle.messaging.remote.internal.RemoteConnection;
-import org.gradle.internal.serialize.ObjectReader;
-import org.gradle.internal.serialize.ObjectWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.EOFException;
import java.io.IOException;
@@ -37,6 +39,7 @@ import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
public class SocketConnection<T> implements RemoteConnection<T> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SocketConnection.class);
private final SocketChannel socket;
private final SocketInetAddress localAddress;
private final SocketInetAddress remoteAddress;
@@ -72,15 +75,17 @@ public class SocketConnection<T> implements RemoteConnection<T> {
public T receive() throws MessageIOException {
try {
return objectReader.read();
- } catch (Exception e) {
- if (isEndOfStream(e)) {
- return null;
+ } catch (EOFException e) {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Discarding EOFException: {}", e.toString());
}
+ return null;
+ } catch (Exception e) {
throw new MessageIOException(String.format("Could not read message from '%s'.", remoteAddress), e);
}
}
- private boolean isEndOfStream(Exception e) {
+ private static boolean isEndOfStream(Exception e) {
if (e instanceof EOFException) {
return true;
}
@@ -155,7 +160,17 @@ public class SocketConnection<T> implements RemoteConnection<T> {
}
buffer.clear();
- int nread = socket.read(buffer);
+ int nread;
+ try {
+ nread = socket.read(buffer);
+ } catch (IOException e) {
+ if (isEndOfStream(e)) {
+ buffer.position(0);
+ buffer.limit(0);
+ return -1;
+ }
+ throw e;
+ }
buffer.flip();
if (nread < 0) {
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpIncomingConnector.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpIncomingConnector.java
index 1d9dab7..e999f4a 100755
--- a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpIncomingConnector.java
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpIncomingConnector.java
@@ -106,11 +106,16 @@ public class TcpIncomingConnector implements IncomingConnector {
continue;
}
LOGGER.debug("Accepted connection from {} to {}.", socket.socket().getRemoteSocketAddress(), socket.socket().getLocalSocketAddress());
- action.execute(new SocketConnectCompletion(socket));
+ try {
+ action.execute(new SocketConnectCompletion(socket));
+ } catch (Throwable t) {
+ socket.close();
+ throw t;
+ }
}
} catch (ClosedChannelException e) {
// Ignore
- } catch (Exception e) {
+ } catch (Throwable e) {
LOGGER.error("Could not accept remote connection.", e);
}
} finally {
diff --git a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpOutgoingConnector.java b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpOutgoingConnector.java
index 364414b..cd831c0 100755
--- a/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpOutgoingConnector.java
+++ b/subprojects/messaging/src/main/java/org/gradle/messaging/remote/internal/inet/TcpOutgoingConnector.java
@@ -23,14 +23,15 @@ import org.gradle.messaging.remote.internal.OutgoingConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
+import java.io.IOException;
+import java.net.*;
import java.nio.channels.SocketChannel;
import java.util.List;
public class TcpOutgoingConnector implements OutgoingConnector {
private static final Logger LOGGER = LoggerFactory.getLogger(TcpOutgoingConnector.class);
+ private static final int CONNECT_TIMEOUT = 10000;
+ private static final int MAXIMUM_RETRIES = 3;
public ConnectCompletion connect(Address destinationAddress) throws ConnectException {
if (!(destinationAddress instanceof InetEndpoint)) {
@@ -50,11 +51,15 @@ public class TcpOutgoingConnector implements OutgoingConnector {
LOGGER.debug("Trying to connect to address {}.", candidate);
SocketChannel socketChannel;
try {
- socketChannel = SocketChannel.open(new InetSocketAddress(candidate, address.getPort()));
+ socketChannel = tryConnect(address, candidate);
} catch (SocketException e) {
LOGGER.debug("Cannot connect to address {}, skipping.", candidate);
lastFailure = e;
continue;
+ } catch (SocketTimeoutException e) {
+ LOGGER.debug("Timeout connecting to address {}, skipping.", candidate);
+ lastFailure = e;
+ continue;
}
LOGGER.debug("Connected to address {}.", socketChannel.socket().getRemoteSocketAddress());
return new SocketConnectCompletion(socketChannel);
@@ -68,4 +73,29 @@ public class TcpOutgoingConnector implements OutgoingConnector {
destinationAddress, candidateAddresses), e);
}
}
+
+ private SocketChannel tryConnect(InetEndpoint address, InetAddress candidate) throws IOException {
+ for (int i=0; i< MAXIMUM_RETRIES; i++) {
+ SocketChannel socketChannel = SocketChannel.open();
+ socketChannel.socket().connect(new InetSocketAddress(candidate, address.getPort()), CONNECT_TIMEOUT);
+ if (!detectSelfConnect(socketChannel)) {
+ return socketChannel;
+ }
+ LOGGER.info("Retrying connection... {}/{}", i, MAXIMUM_RETRIES);
+ socketChannel.close();
+ }
+ throw new SocketException("Exceeded retries after detecting TCP self-connect.");
+ }
+
+ boolean detectSelfConnect(SocketChannel socketChannel) {
+ Socket socket = socketChannel.socket();
+ SocketAddress localAddress = socket.getLocalSocketAddress();
+ SocketAddress remoteAddress = socket.getRemoteSocketAddress();
+ if (localAddress.equals(remoteAddress)) {
+ LOGGER.info("Detected that socket was bound to {} while connecting to {}. This looks like the socket connected to itself.",
+ localAddress, remoteAddress);
+ return true;
+ }
+ return false;
+ }
}
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/internal/event/DefaultListenerManagerTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/internal/event/DefaultListenerManagerTest.groovy
new file mode 100644
index 0000000..0a3059d
--- /dev/null
+++ b/subprojects/messaging/src/test/groovy/org/gradle/internal/event/DefaultListenerManagerTest.groovy
@@ -0,0 +1,763 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.event
+
+import org.gradle.test.fixtures.concurrent.ConcurrentSpec
+import spock.lang.Timeout
+
+import java.util.concurrent.CopyOnWriteArrayList
+
+ at Timeout(60)
+class DefaultListenerManagerTest extends ConcurrentSpec {
+ def manager = new DefaultListenerManager();
+
+ def fooListener1 = Mock(TestFooListener.class)
+ def fooListener2 = Mock(TestFooListener.class)
+ def fooListener3 = Mock(TestFooListener.class)
+ def barListener1 = Mock(TestBarListener.class)
+
+ def broadcasterDoesNothingWhenNoListenersRegistered() {
+ given:
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ broadcaster.foo("param");
+
+ then:
+ 0 * _
+ }
+
+ def cachesBroadcasters() {
+ expect:
+ manager.getBroadcaster(TestFooListener.class).is(manager.getBroadcaster(TestFooListener.class))
+ }
+
+ def canAddListenerBeforeObtainingBroadcaster() {
+ given:
+ manager.addListener(fooListener1);
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ broadcaster.foo("param");
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+ }
+
+ def canAddListenerAfterObtainingBroadcaster() {
+ given:
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+ manager.addListener(fooListener1);
+
+ when:
+ broadcaster.foo("param");
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+ }
+
+ def canAddLoggerBeforeObtainingBroadcaster() {
+ given:
+ manager.useLogger(fooListener1)
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ broadcaster.foo("param");
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+ }
+
+ def canAddLoggerAfterObtainingBroadcaster() {
+ given:
+ manager.useLogger(fooListener1)
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ broadcaster.foo("param");
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+ }
+
+ def canHaveListenersOfDifferentTypes() {
+ given:
+ manager.addListener(fooListener1)
+ manager.addListener(barListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+
+ when:
+ manager.getBroadcaster(TestBarListener.class).bar(12)
+
+ then:
+ 1 * barListener1.bar(12)
+ 0 * _
+ }
+
+ def listenerCanImplementMultipleTypes() {
+ given:
+ def listener = Mock(BothListener)
+ manager.addListener(listener)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 1 * listener.foo("param")
+ 0 * _
+
+ when:
+ manager.getBroadcaster(TestBarListener.class).bar(12)
+
+ then:
+ 1 * listener.bar(12)
+ 0 * _
+ }
+
+ def addedListenersGetMessagesInOrderAdded() {
+ given:
+ manager.addListener(fooListener1)
+ manager.addListener(fooListener2)
+
+ // get the broadcaster and then add more listeners (because broadcasters
+ // are cached and so must be maintained correctly after getting defined
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+
+ manager.addListener(fooListener3)
+
+ when:
+ broadcaster.foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+
+ then:
+ 1 * fooListener2.foo("param")
+
+ then:
+ 1 * fooListener3.foo("param")
+ 0 * _
+ }
+
+ def loggersReceiveMessagesBeforeListeners() {
+ given:
+ manager.addListener(fooListener1)
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+ manager.useLogger(fooListener2)
+
+ when:
+ broadcaster.foo("param")
+
+ then:
+ 1 * fooListener2.foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+ }
+
+ def listenersReceiveMessagesInSameOrderRegardlessOfGeneratingThread() {
+ given:
+ def events1 = events("a", 20)
+ def events2 = events("b", 20)
+ def events3 = events("c", 20)
+ def received1 = new CopyOnWriteArrayList<String>()
+ def received2 = new CopyOnWriteArrayList<String>()
+ def listener1 = { String p ->
+ received1 << p
+ } as TestFooListener
+ def listener2 = { String p ->
+ received2 << p
+ } as TestFooListener
+
+ manager.addListener(listener1)
+ manager.addListener(listener2)
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ async {
+ start {
+ events1.each {
+ broadcaster.foo(it)
+ }
+ }
+ start {
+ events2.each {
+ broadcaster.foo(it)
+ }
+ }
+ start {
+ events3.each {
+ broadcaster.foo(it)
+ }
+ }
+ }
+
+ then:
+ received1.size() == 60
+ received2.size() == 60
+ received1 == received2
+ received1.findAll { it.startsWith("a") } == events1
+ received1.findAll { it.startsWith("b") } == events2
+ }
+
+ List<String> events(String prefix, int count) {
+ return (1..count).collect { i -> "$prefix-$i" as String }
+ }
+
+ def notifyBlocksWhenAnotherThreadIsNotifyingOnTheSameType() {
+ given:
+ def listener1 = { String p ->
+ if (p == "a") {
+ instant.aReceived
+ thread.block()
+ instant.aHandled
+ } else {
+ instant.bReceived
+ }
+ } as TestFooListener
+
+ manager.addListener(listener1)
+ def broadcaster = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ async {
+ start {
+ broadcaster.foo("a")
+ }
+ start {
+ thread.blockUntil.aReceived
+ broadcaster.foo("b")
+ }
+ }
+
+ then:
+ instant.bReceived > instant.aHandled
+ }
+
+ def notifyDoesNotBlockWhenAnotherThreadIsNotifyingOnDifferentType() {
+ given:
+ def listener1 = { String p ->
+ instant.aReceived
+ thread.block()
+ instant.aHandled
+ } as TestFooListener
+ def listener2 = {
+ instant.bReceived
+ } as TestBarListener
+
+ manager.addListener(listener1)
+ manager.addListener(listener2)
+ def broadcaster1 = manager.getBroadcaster(TestFooListener.class)
+ def broadcaster2 = manager.getBroadcaster(TestBarListener.class)
+
+ when:
+ async {
+ start {
+ broadcaster1.foo("a")
+ }
+ start {
+ thread.blockUntil.aReceived
+ broadcaster2.bar(12)
+ }
+ }
+
+ then:
+ instant.bReceived < instant.aHandled
+ }
+
+ def notifyBlocksWhenAnotherThreadIsNotifyingTheSameListenerWithDifferentType() {
+ given:
+ def listener = [foo: { String p ->
+ instant.aReceived
+ thread.block()
+ instant.aHandled
+ },
+ bar: { int i ->
+ instant.bReceived
+ }
+ ] as BothListener
+
+ manager.addListener(listener)
+
+ when:
+ async {
+ start {
+ manager.getBroadcaster(TestFooListener.class).foo("a")
+ }
+ start {
+ thread.blockUntil.aReceived
+ manager.getBroadcaster(TestBarListener.class).bar(12)
+ }
+ }
+
+ then:
+ instant.bReceived > instant.aHandled
+ }
+
+ def removedListenersDontGetMessages() {
+ given:
+ manager.addListener(fooListener1)
+ manager.addListener(fooListener2)
+ manager.removeListener(fooListener2)
+ def testFooListener = manager.getBroadcaster(TestFooListener.class)
+ manager.removeListener(fooListener1)
+
+ when:
+ testFooListener.foo("param")
+
+ then:
+ 0 * _
+ }
+
+ def replacedLoggersDontGetMessages() {
+ given:
+ manager.useLogger(fooListener1)
+ manager.useLogger(fooListener2)
+ def testFooListener = manager.getBroadcaster(TestFooListener.class)
+ manager.useLogger(fooListener3)
+
+ when:
+ testFooListener.foo("param")
+
+ then:
+ 1 * fooListener3.foo("param")
+ 0 * _
+ }
+
+ def collectsFailureAndContinuesToNotifyListeners() {
+ given:
+ def failure = new RuntimeException()
+ manager.addListener(fooListener1)
+ manager.addListener(fooListener2)
+ def testFooListener = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ testFooListener.foo("param")
+
+ then:
+ 1 * fooListener1.foo("param") >> { throw failure }
+ 1 * fooListener2.foo("param")
+ 0 * _
+
+ and:
+ RuntimeException e = thrown()
+ e == failure
+ }
+
+ def collectsMultipleFailuresAndContinuesToNotifyListeners() {
+ given:
+ def failure1 = new RuntimeException()
+ def failure2 = new RuntimeException()
+ manager.addListener(fooListener1)
+ manager.addListener(fooListener2)
+ manager.addListener(fooListener3)
+ def testFooListener = manager.getBroadcaster(TestFooListener.class)
+
+ when:
+ testFooListener.foo("param")
+
+ then:
+ 1 * fooListener1.foo("param") >> { throw failure1 }
+ 1 * fooListener2.foo("param") >> { throw failure2 }
+ 1 * fooListener3.foo("param")
+ 0 * _
+
+ and:
+ ListenerNotificationException e = thrown()
+ e.causes == [failure1, failure2]
+ }
+
+ def listenerReceivesEventsFromAnonymousBroadcasters() {
+ given:
+ manager.addListener(fooListener1)
+ def broadcaster = manager.createAnonymousBroadcaster(TestFooListener.class)
+
+ when:
+ broadcaster.source.foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+ }
+
+ def listenerOnAnonymousBroadcasterDoesNotReceiveEventsFromListenerManager() {
+ given:
+ manager.createAnonymousBroadcaster(TestFooListener.class).add(fooListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener).foo("param")
+
+ then:
+ 0 * _
+ }
+
+ def listenerReceivesEventsFromChildren() {
+ given:
+ manager.addListener(fooListener1)
+ def child = manager.createChild()
+ child.addListener(fooListener2)
+ def broadcaster = child.getBroadcaster(TestFooListener.class)
+ manager.addListener(fooListener3)
+
+ when:
+ broadcaster.foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+ 1 * fooListener2.foo("param")
+ 1 * fooListener3.foo("param")
+ 0 * _
+ }
+
+ def listenerDoesNotReceiveEventsFromParent() {
+ given:
+ manager.createChild().addListener(fooListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 0 * _
+ }
+
+ def loggerReceivesEventsFromChildren() {
+ given:
+ manager.useLogger(fooListener1)
+ def child = manager.createChild();
+ def broadcaster = child.getBroadcaster(TestFooListener.class)
+
+ when:
+ broadcaster.foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+ 0 * _
+
+ when:
+ manager.useLogger(fooListener2) // replace listener
+ broadcaster.foo("param")
+
+ then:
+ 1 * fooListener2.foo("param")
+ 0 * _
+ }
+
+ def loggerDoesNotReceiveEventsFromParent() {
+ given:
+ manager.createChild().useLogger(fooListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 0 * _
+ }
+
+ def loggerInChildHasPrecedenceOverLoggerInParent() {
+ given:
+ manager.useLogger(fooListener1)
+ def child = manager.createChild()
+ def broadcaster = child.getBroadcaster(TestFooListener.class)
+ child.useLogger(fooListener2)
+
+ when:
+ broadcaster.foo("param")
+
+ then:
+ 1 * fooListener2.foo("param")
+ 0 * _
+
+ when:
+ child.useLogger(fooListener3)
+ broadcaster.foo("param2")
+
+ then:
+ 1 * fooListener3.foo("param2")
+ 0 * _
+ }
+
+ def listenerCanAddAnotherListenerOfSameType() {
+ given:
+ manager.addListener(fooListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 1 * fooListener1.foo("param") >> {
+ manager.addListener(fooListener2)
+ }
+ 0 * _
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param 2")
+
+ then:
+ 1 * fooListener1.foo("param 2")
+ 1 * fooListener2.foo("param 2")
+ }
+
+ def listenerCanAddAnotherListenerOfDifferentType() {
+ given:
+ manager.addListener(fooListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 1 * fooListener1.foo("param") >> {
+ manager.addListener(barListener1)
+ manager.getBroadcaster(TestBarListener.class).bar(12)
+ }
+ 1 * barListener1.bar(12)
+ 0 * _
+ }
+
+ def listenerCanRemoveAnotherListener() {
+ given:
+ manager.addListener(fooListener1)
+ manager.addListener(fooListener2)
+ manager.addListener(fooListener3)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+ 1 * fooListener2.foo("param") >> {
+ manager.removeListener(fooListener1)
+ manager.removeListener(fooListener3)
+ }
+ 0 * _
+ }
+
+ def listenerCannotGenerateEventsOfSameType() {
+ given:
+ manager.addListener(fooListener1)
+ manager.addListener(barListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ IllegalStateException e = thrown()
+ e.message == "Cannot notify listeners of type TestFooListener as these listeners are already being notified."
+
+ and:
+ 1 * fooListener1.foo("param") >> {
+ manager.getBroadcaster(TestFooListener.class).foo("param2")
+ }
+ 0 * _
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ IllegalStateException e2 = thrown()
+ e2.message == "Cannot notify listeners of type TestFooListener as these listeners are already being notified."
+
+ and:
+ 1 * fooListener1.foo("param") >> {
+ manager.getBroadcaster(TestBarListener.class).bar(12)
+ }
+ 1 * barListener1.bar(12) >> {
+ manager.getBroadcaster(TestFooListener.class).foo("param 2")
+ }
+ 0 * _
+ }
+
+ def listenerCanGenerateEventsOfDifferentType() {
+ given:
+ manager.addListener(fooListener1)
+ manager.addListener(barListener1)
+
+ when:
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 1 * fooListener1.foo("param") >> {
+ manager.getBroadcaster(TestBarListener.class).bar(12)
+ }
+ 1 * barListener1.bar(12)
+ 0 * _
+ }
+
+ def multipleThreadsCanAddListeners() {
+ when:
+ async {
+ start {
+ manager.addListener(fooListener1)
+ }
+ start {
+ manager.addListener(fooListener2)
+ }
+ start {
+ manager.addListener(fooListener3)
+ }
+ }
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 1 * fooListener1.foo("param")
+ 1 * fooListener2.foo("param")
+ 1 * fooListener3.foo("param")
+ 0 * _
+ }
+
+ def multipleThreadsCanRemoveListeners() {
+ when:
+ async {
+ start {
+ manager.addListener(fooListener1)
+ manager.removeListener(fooListener1)
+ }
+ start {
+ manager.addListener(fooListener2)
+ manager.removeListener(fooListener2)
+ }
+ start {
+ manager.addListener(fooListener3)
+ manager.removeListener(fooListener3)
+ }
+ }
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+
+ then:
+ 0 * _
+ }
+
+ def addingListenerDoesNotBlockWhileAnotherThreadIsNotifying() {
+ given:
+ def listener1 = {
+ instant.received
+ thread.block()
+ instant.handled
+ } as TestFooListener
+ manager.addListener(listener1)
+
+ when:
+ async {
+ start {
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+ }
+ thread.blockUntil.received
+ manager.addListener(fooListener2)
+ instant.added
+ }
+
+ then:
+ instant.added < instant.handled
+
+ and:
+ 0 * _
+ }
+
+ def addingListenerDoesNotBlockWhileAnotherThreadIsNotifyingOnDifferentType() {
+ given:
+ def listener1 = {
+ instant.received
+ thread.block()
+ instant.handled
+ } as TestFooListener
+ manager.addListener(listener1)
+
+ when:
+ async {
+ start {
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+ }
+ thread.blockUntil.received
+ manager.addListener(barListener1)
+ instant.added
+ }
+
+ then:
+ instant.added < instant.handled
+
+ and:
+ 0 * _
+ }
+
+ def removingListenerBlocksWhileAnotherThreadIsNotifyingListener() {
+ given:
+ def listener1 = {
+ instant.received
+ thread.block()
+ instant.handled
+ } as TestFooListener
+ manager.addListener(listener1)
+
+ when:
+ async {
+ start {
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+ }
+ thread.blockUntil.received
+ manager.removeListener(listener1)
+ instant.removed
+ }
+
+ then:
+ instant.removed > instant.handled
+ }
+
+ def removingListenerDoesNotBlockWhileAnotherThreadIsNotifyingOnDifferentType() {
+ given:
+ def listener1 = {
+ instant.received
+ thread.block()
+ instant.handled
+ } as TestFooListener
+ manager.addListener(listener1)
+ manager.addListener(barListener1)
+
+ when:
+ async {
+ start {
+ manager.getBroadcaster(TestFooListener.class).foo("param")
+ }
+ thread.blockUntil.received
+ manager.removeListener(barListener1)
+ instant.removed
+ }
+
+ then:
+ instant.removed < instant.handled
+ }
+
+ public interface TestFooListener {
+ void foo(String param);
+ }
+
+ public interface TestBarListener {
+ void bar(int value);
+ }
+
+ public interface BothListener extends TestFooListener, TestBarListener {
+ }
+}
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/internal/event/DefaultListenerManagerTest.java b/subprojects/messaging/src/test/groovy/org/gradle/internal/event/DefaultListenerManagerTest.java
deleted file mode 100644
index 97a618e..0000000
--- a/subprojects/messaging/src/test/groovy/org/gradle/internal/event/DefaultListenerManagerTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.internal.event;
-
-import org.jmock.Expectations;
-import org.jmock.Sequence;
-import org.jmock.integration.junit4.JMock;
-import org.jmock.integration.junit4.JUnit4Mockery;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertSame;
-
- at RunWith(JMock.class)
-public class DefaultListenerManagerTest {
- private final JUnit4Mockery context = new JUnit4Mockery();
- private final ListenerManager manager = new DefaultListenerManager();
-
- private final TestFooListener fooListener1 = context.mock(TestFooListener.class, "foo listener 1");
- private final TestFooListener fooListener2 = context.mock(TestFooListener.class, "foo listener 2");
- private final TestFooListener fooListener3 = context.mock(TestFooListener.class, "foo listener 3");
- private final TestFooListener fooListener4 = context.mock(TestFooListener.class, "foo listener 4");
- private final TestBarListener barListener1 = context.mock(TestBarListener.class, "bar listener 1");
-
- @Test
- public void canAddListenerBeforeObtainingBroadcaster() {
- manager.addListener(fooListener1);
-
- context.checking(new Expectations() {{
- one(fooListener1).foo("param");
- }});
-
- manager.getBroadcaster(TestFooListener.class).foo("param");
- }
-
- @Test
- public void canAddListenerAfterObtainingBroadcaster() {
- TestFooListener broadcaster = manager.getBroadcaster(TestFooListener.class);
-
- manager.addListener(fooListener1);
-
- context.checking(new Expectations() {{
- one(fooListener1).foo("param");
- }});
-
- broadcaster.foo("param");
- }
-
- @Test
- public void canAddLoggerBeforeObtainingBroadcaster() {
- manager.useLogger(fooListener1);
-
- context.checking(new Expectations() {{
- one(fooListener1).foo("param");
- }});
-
- manager.getBroadcaster(TestFooListener.class).foo("param");
- }
-
- @Test
- public void canAddLoggerAfterObtainingBroadcaster() {
- TestFooListener broadcaster = manager.getBroadcaster(TestFooListener.class);
-
- manager.useLogger(fooListener1);
-
- context.checking(new Expectations() {{
- one(fooListener1).foo("param");
- }});
-
- broadcaster.foo("param");
- }
-
- @Test
- public void addedListenersGetMessagesInOrderAdded() {
- context.checking(new Expectations() {{
- Sequence sequence = context.sequence("sequence");
- one(fooListener1).foo("param"); inSequence(sequence);
- one(fooListener2).foo("param"); inSequence(sequence);
- one(fooListener3).foo("param"); inSequence(sequence);
- one(fooListener4).foo("param"); inSequence(sequence);
- }});
-
- manager.addListener(fooListener1);
- manager.addListener(barListener1);
- manager.addListener(fooListener2);
- manager.addListener(fooListener3);
-
- // get the broadcaster and then add more listeners (because broadcasters
- // are cached and so must be maintained correctly after getting defined
- TestFooListener broadcaster = manager.getBroadcaster(TestFooListener.class);
-
- manager.addListener(fooListener4);
-
- broadcaster.foo("param");
- }
-
- @Test
- public void cachesBroadcasters() {
- assertSame(manager.getBroadcaster(TestFooListener.class), manager.getBroadcaster(TestFooListener.class));
- }
-
- @Test
- public void removedListenersDontGetMessages() {
- manager.addListener(fooListener1);
- manager.addListener(fooListener2);
-
- manager.removeListener(fooListener2);
-
- TestFooListener testFooListener = manager.getBroadcaster(TestFooListener.class);
-
- manager.removeListener(fooListener1);
-
- testFooListener.foo("param");
- }
-
- @Test
- public void replacedLoggersDontGetMessages() {
- context.checking(new Expectations() {{
- one(fooListener4).foo("param");
- }});
-
- manager.useLogger(fooListener1);
- manager.useLogger(fooListener2);
-
- TestFooListener testFooListener = manager.getBroadcaster(TestFooListener.class);
-
- manager.useLogger(fooListener3);
- manager.useLogger(fooListener4);
-
- testFooListener.foo("param");
- }
-
- @Test
- public void listenerReceivesEventsFromAnonymousBroadcasters() {
- manager.addListener(fooListener1);
-
- context.checking(new Expectations() {{
- one(fooListener1).foo("param");
- }});
-
- manager.createAnonymousBroadcaster(TestFooListener.class).getSource().foo("param");
- }
-
- @Test
- public void listenerReceivesEventsFromChildren() {
- manager.addListener(fooListener1);
-
- context.checking(new Expectations() {{
- one(fooListener1).foo("param");
- }});
-
- manager.createChild().getBroadcaster(TestFooListener.class).foo("param");
- }
-
- @Test
- public void listenerDoesNotReceiveEventsFromParent() {
- manager.createChild().addListener(fooListener1);
-
- manager.getBroadcaster(TestFooListener.class).foo("param");
- }
-
- @Test
- public void loggerReceivesEventsFromChildren() {
- manager.useLogger(fooListener1);
-
- ListenerManager child = manager.createChild();
- TestFooListener broadcaster = child.getBroadcaster(TestFooListener.class);
-
- context.checking(new Expectations() {{
- one(fooListener1).foo("param");
- }});
- broadcaster.foo("param");
-
- manager.useLogger(fooListener2);
-
- context.checking(new Expectations() {{
- one(fooListener2).foo("param");
- }});
- broadcaster.foo("param");
- }
-
- @Test
- public void loggerDoesNotReceiveEventsFromParent() {
- manager.createChild().useLogger(fooListener1);
-
- manager.getBroadcaster(TestFooListener.class).foo("param");
- }
-
- @Test
- public void loggerInChildHasPrecedenceOverLoggerInParent() {
- manager.useLogger(fooListener1);
-
- ListenerManager child = manager.createChild();
- TestFooListener broadcaster = child.getBroadcaster(TestFooListener.class);
-
- child.useLogger(fooListener2);
-
- context.checking(new Expectations() {{
- one(fooListener2).foo("param");
- }});
-
- broadcaster.foo("param");
- }
-
- public interface TestFooListener {
- void foo(String param);
- }
-
- public interface TestBarListener {
- void bar(int value);
- }
-}
-
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/AbstractCodecTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/AbstractCodecTest.groovy
index 0d3e462..b3124f8 100644
--- a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/AbstractCodecTest.groovy
+++ b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/AbstractCodecTest.groovy
@@ -19,6 +19,8 @@ package org.gradle.internal.serialize
import spock.lang.Specification
import spock.lang.Unroll
+import java.nio.CharBuffer
+
abstract class AbstractCodecTest extends Specification {
def "can encode and decode raw bytes using Stream view"() {
expect:
@@ -443,13 +445,13 @@ abstract class AbstractCodecTest extends Specification {
where:
value | _
-// "" | _
-// "all ascii" | _
+ "" | _
+ "all ascii" | _
"\u0000\u0101\u3100" | _
-// "${1 + 2}" | _
-// new StringBuilder("some string") | _
-// CharBuffer.wrap("a string") | _
-// (0..1000).join("-") | _
+ "${1 + 2}" | _
+ new StringBuilder("some string") | _
+ CharBuffer.wrap("a string") | _
+ (0..1000).join("-") | _
}
def "decode fails when string cannot be fully read"() {
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/BaseSerializerFactoryTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/BaseSerializerFactoryTest.groovy
index 23c2159..c28abfc 100644
--- a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/BaseSerializerFactoryTest.groovy
+++ b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/BaseSerializerFactoryTest.groovy
@@ -20,51 +20,21 @@ class BaseSerializerFactoryTest extends SerializerSpec {
def factory = new BaseSerializerFactory()
def "uses efficient serialization for Strings"() {
- def encoder = Mock(Encoder)
- def decoder = Mock(Decoder)
-
- when:
+ expect:
def serializer = factory.getSerializerFor(String)
- serializer.write(encoder, "hi")
- def result = serializer.read(decoder)
-
- then:
- result == "bye"
- 1 * encoder.writeString("hi")
- 1 * decoder.readString() >> "bye"
- 0 * _
+ usesEfficientSerialization("hi", serializer, 3) == "hi"
}
def "uses efficient serialization for Files"() {
- def encoder = Mock(Encoder)
- def decoder = Mock(Decoder)
-
- when:
+ expect:
def serializer = factory.getSerializerFor(File)
- serializer.write(encoder, new File("some-file"))
- def result = serializer.read(decoder)
-
- then:
- result == new File("some-file")
- 1 * encoder.writeString("some-file")
- 1 * decoder.readString() >> "some-file"
- 0 * _
+ usesEfficientSerialization(new File("some-file"), serializer, 10) == new File("some-file")
}
def "uses efficient serialization for Long"() {
- def encoder = Mock(Encoder)
- def decoder = Mock(Decoder)
-
- when:
+ expect:
def serializer = factory.getSerializerFor(Long)
- serializer.write(encoder, 123L)
- def result = serializer.read(decoder)
-
- then:
- result == 456L
- 1 * encoder.writeLong(123L)
- 1 * decoder.readLong() >> 456L
- 0 * _
+ usesEfficientSerialization(123L, serializer) == 123L
}
enum Letters {
@@ -72,37 +42,24 @@ class BaseSerializerFactoryTest extends SerializerSpec {
}
def "uses efficient serialization for Enum"() {
- def encoder = Mock(Encoder)
- def decoder = Mock(Decoder)
-
- when:
+ expect:
def serializer = factory.getSerializerFor(Letters)
- serializer.write(encoder, Letters.B)
- def result = serializer.read(decoder)
-
- then:
- result == Letters.C
- 1 * encoder.writeSmallInt(1)
- 1 * decoder.readSmallInt() >> 2
- 0 * _
+ usesEfficientSerialization(Letters.B, serializer) == Letters.B
}
def "uses efficient serialization for byte arrays"() {
- def s = factory.getSerializerFor(byte[])
- def os = new ByteArrayOutputStream()
- s.write(new OutputStreamBackedEncoder(os), new byte[5])
-
expect:
- def result = serialize(new byte[5], s)
+ def serializer = factory.getSerializerFor(byte[])
+ def result = usesEfficientSerialization(new byte[5], serializer)
result instanceof byte[]
result.length == 5
}
- def "can serialize string maps"() {
- def s = BaseSerializerFactory.NO_NULL_STRING_MAP_SERIALIZER
+ def "uses efficient serialization for string maps"() {
+ def serializer = BaseSerializerFactory.NO_NULL_STRING_MAP_SERIALIZER
expect:
- serialize(map, s) == map
+ usesEfficientSerialization(map, serializer) == map
where:
map << [
@@ -117,9 +74,9 @@ class BaseSerializerFactoryTest extends SerializerSpec {
class Thing {}
- def "serialize booleans"() {
+ def "uses efficient serialization for booleans"() {
expect:
- serialize(true, factory.getSerializerFor(Boolean))
- !serialize(false, factory.getSerializerFor(Boolean))
+ usesEfficientSerialization(true, factory.getSerializerFor(Boolean))
+ !usesEfficientSerialization(false, factory.getSerializerFor(Boolean))
}
}
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/DefaultSerializerRegistryTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/DefaultSerializerRegistryTest.groovy
index c675778..f470357 100644
--- a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/DefaultSerializerRegistryTest.groovy
+++ b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/DefaultSerializerRegistryTest.groovy
@@ -81,12 +81,59 @@ class DefaultSerializerRegistryTest extends SerializerSpec {
def registry = new DefaultSerializerRegistry()
registry.register(Long, longSerializer)
registry.register(Integer, intSerializer)
+ registry.useJavaSerialization(String)
def serializer = registry.build()
when:
toBytes(123.4, serializer)
then:
- thrown(IllegalArgumentException)
+ IllegalArgumentException e = thrown()
+ e.message == "Don't know how to serialize an object of type java.math.BigDecimal."
+ }
+
+ def "can use Java serialization for registered type"() {
+ given:
+ def registry = new DefaultSerializerRegistry()
+ registry.useJavaSerialization(Long)
+ registry.useJavaSerialization(Integer)
+ def serializer = registry.build()
+
+ expect:
+ serialize(123L, serializer) == 123L
+ serialize(123, serializer) == 123
+ }
+
+ def "can use Java serialization for subtypes of registered type"() {
+ given:
+ def registry = new DefaultSerializerRegistry()
+ registry.useJavaSerialization(Number)
+ def serializer = registry.build()
+
+ expect:
+ serialize(123L, serializer) == 123L
+ serialize(123, serializer) == 123
+ serialize(123.4, serializer) == 123.4
+ }
+
+ def "custom serialization takes precedence over Java serialization"() {
+ given:
+ def customSerializer = Stub(Serializer) {
+ read(_) >> { Decoder decoder ->
+ return decoder.readSmallLong() + 1
+ }
+ write(_, _) >> { Encoder encoder, Long value ->
+ encoder.writeSmallLong(value + 1)
+ }
+ }
+ def registry = new DefaultSerializerRegistry()
+ registry.useJavaSerialization(Number)
+ registry.register(Long, customSerializer)
+ def serializer = registry.build()
+
+ expect:
+ serialize(123L, serializer) == 125L
+ serialize(123, serializer) == 123
+ serialize(123.4, serializer) == 123.4
}
}
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/ObjectArraySerializerTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/ObjectArraySerializerTest.groovy
new file mode 100644
index 0000000..4e0f295
--- /dev/null
+++ b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/ObjectArraySerializerTest.groovy
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.serialize
+
+class ObjectArraySerializerTest extends SerializerSpec {
+ def serializer = new ObjectArraySerializer(new BaseSerializerFactory().getSerializerFor(String))
+
+ def "can serialize arrays"() {
+ expect:
+ serialize(elements as Object[], serializer) == elements as Object[]
+
+ where:
+ elements | _
+ [] | _
+ ["a", "b", "c"] | _
+ }
+}
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/SerializersTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/SerializersTest.groovy
new file mode 100644
index 0000000..1b1f742
--- /dev/null
+++ b/subprojects/messaging/src/test/groovy/org/gradle/internal/serialize/SerializersTest.groovy
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.serialize
+
+import spock.lang.Specification
+
+class SerializersTest extends Specification {
+ def "adapts Serializer to StatefulSerializer"() {
+ def serializer = Mock(Serializer)
+ def decoder = Mock(Decoder)
+ def encoder = Mock(Encoder)
+
+ given:
+ def stateful = Serializers.stateful(serializer)
+ def reader = stateful.newReader(decoder)
+ def writer = stateful.newWriter(encoder)
+
+ when:
+ def result1 = reader.read()
+ def result2 = reader.read()
+
+ then:
+ result1 == "one"
+ result2 == "two"
+ 1 * serializer.read(decoder) >> "one"
+ 1 * serializer.read(decoder) >> "two"
+ 0 * serializer._
+
+ when:
+ writer.write("one")
+ writer.write("two")
+
+ then:
+ 1 * serializer.write(encoder, "one")
+ 1 * serializer.write(encoder, "two")
+ 0 * serializer._
+ }
+}
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/KryoBackedMessageSerializerTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/KryoBackedMessageSerializerTest.groovy
new file mode 100644
index 0000000..6db5346
--- /dev/null
+++ b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/KryoBackedMessageSerializerTest.groovy
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.messaging.remote.internal
+
+import org.gradle.internal.serialize.BaseSerializerFactory
+import org.gradle.internal.serialize.Serializers
+import org.gradle.internal.serialize.StatefulSerializer
+import spock.lang.Specification
+
+class KryoBackedMessageSerializerTest extends Specification {
+ def serializer = Mock(StatefulSerializer)
+ def messageSerializer = new KryoBackedMessageSerializer<String>(Serializers.stateful(BaseSerializerFactory.STRING_SERIALIZER))
+
+ def "creates reader and writer backed by serializer"() {
+ def outputStream = new ByteArrayOutputStream()
+
+ when:
+ def writer = messageSerializer.newWriter(outputStream)
+ writer.write("a")
+ writer.write("b")
+ writer.write("c")
+
+ then:
+ def reader = messageSerializer.newReader(new ByteArrayInputStream(outputStream.toByteArray()), null, null)
+ reader.read() == "a"
+ reader.read() == "b"
+ reader.read() == "c"
+ }
+}
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializerTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializerTest.groovy
index 929f6f1..18fde9d 100644
--- a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializerTest.groovy
+++ b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/InterHubMessageSerializerTest.groovy
@@ -16,15 +16,18 @@
package org.gradle.messaging.remote.internal.hub
+import org.gradle.internal.serialize.DefaultSerializer
+import org.gradle.internal.serialize.InputStreamBackedDecoder
+import org.gradle.internal.serialize.OutputStreamBackedEncoder
+import org.gradle.internal.serialize.Serializers
import org.gradle.messaging.remote.internal.hub.protocol.ChannelIdentifier
import org.gradle.messaging.remote.internal.hub.protocol.ChannelMessage
import org.gradle.messaging.remote.internal.hub.protocol.EndOfStream
import org.gradle.messaging.remote.internal.hub.protocol.InterHubMessage
-import org.gradle.internal.serialize.kryo.JavaSerializer
import spock.lang.Specification
class InterHubMessageSerializerTest extends Specification {
- final InterHubMessageSerializer serializer = new InterHubMessageSerializer(new JavaSerializer<Object>())
+ final InterHubMessageSerializer serializer = new InterHubMessageSerializer(Serializers.stateful(new DefaultSerializer<Object>(getClass().classLoader)))
def "can serialise ChannelMessage"() {
def channelId = new ChannelIdentifier("channel name")
@@ -97,19 +100,21 @@ class InterHubMessageSerializerTest extends Specification {
def serialize(InterHubMessage... messages) {
def outStr = new ByteArrayOutputStream()
- def writer = serializer.newWriter(outStr)
+ def encoder = new OutputStreamBackedEncoder(outStr)
+ def writer = serializer.newWriter(encoder)
messages.each {
writer.write(it)
}
+ encoder.flush()
return outStr.toByteArray()
}
def deserialize(byte[] data) {
- return serializer.newReader(new ByteArrayInputStream(data), null, null).read()
+ return serializer.newReader(new InputStreamBackedDecoder(new ByteArrayInputStream(data))).read()
}
def deserializeMultiple(byte[] data, int count) {
- def reader = serializer.newReader(new ByteArrayInputStream(data), null, null)
+ def reader = serializer.newReader(new InputStreamBackedDecoder(new ByteArrayInputStream(data)))
def result = []
count.times {
result << reader.read()
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializerTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializerTest.groovy
index feb48a7..5e39473 100644
--- a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializerTest.groovy
+++ b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/hub/MethodInvocationSerializerTest.groovy
@@ -16,15 +16,16 @@
package org.gradle.messaging.remote.internal.hub
-import org.gradle.messaging.dispatch.MethodInvocation
-import org.gradle.internal.serialize.kryo.JavaSerializer
+import org.gradle.internal.serialize.DefaultSerializer
+import org.gradle.internal.serialize.Serializers
import org.gradle.internal.serialize.kryo.KryoBackedDecoder
import org.gradle.internal.serialize.kryo.KryoBackedEncoder
+import org.gradle.messaging.dispatch.MethodInvocation
import spock.lang.Specification
class MethodInvocationSerializerTest extends Specification {
final classLoader = new GroovyClassLoader(getClass().classLoader)
- final serializer = new MethodInvocationSerializer(classLoader, new JavaSerializer<Object[]>(getClass().classLoader))
+ final serializer = new MethodInvocationSerializer(classLoader, Serializers.stateful(new DefaultSerializer<Object[]>(getClass().classLoader)))
def "serializes a method invocation with parameters"() {
def method = String.class.getMethod("substring", Integer.TYPE, Integer.TYPE)
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/MulticastConnectionTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/MulticastConnectionTest.groovy
index a867d87..13f5566 100644
--- a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/MulticastConnectionTest.groovy
+++ b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/MulticastConnectionTest.groovy
@@ -18,7 +18,7 @@ package org.gradle.messaging.remote.internal.inet
import org.gradle.messaging.remote.internal.DefaultMessageSerializer
import org.gradle.test.fixtures.concurrent.ConcurrentSpec
-import org.gradle.util.AvailablePortFinder
+import org.gradle.util.ports.FixedAvailablePortAllocator
import org.junit.internal.AssumptionViolatedException
import spock.lang.Timeout
@@ -27,7 +27,9 @@ class MulticastConnectionTest extends ConcurrentSpec {
def addressFactory = new InetAddressFactory()
def "can send multicast messages between peers"() {
- def address = new SocketInetAddress(InetAddress.getByName("233.253.17.122"), AvailablePortFinder.createPrivate().nextAvailable)
+ def portFinder = FixedAvailablePortAllocator.getInstance()
+ def port = portFinder.assignPort()
+ def address = new SocketInetAddress(InetAddress.getByName("233.253.17.122"), port)
def serializer = new DefaultMessageSerializer<String>(getClass().classLoader)
given:
@@ -44,6 +46,7 @@ class MulticastConnectionTest extends ConcurrentSpec {
cleanup:
connection1?.stop()
connection2?.stop()
+ portFinder.releasePort(port)
}
void multicastAvailable(SocketInetAddress address) {
diff --git a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/TcpConnectorTest.groovy b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/TcpConnectorTest.groovy
index a222997..1347550 100644
--- a/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/TcpConnectorTest.groovy
+++ b/subprojects/messaging/src/test/groovy/org/gradle/messaging/remote/internal/inet/TcpConnectorTest.groovy
@@ -14,16 +14,25 @@
* limitations under the License.
*/
package org.gradle.messaging.remote.internal.inet
-
import org.gradle.api.Action
import org.gradle.internal.id.UUIDGenerator
-import org.gradle.messaging.remote.internal.ConnectCompletion
-import org.gradle.messaging.remote.internal.ConnectException
-import org.gradle.messaging.remote.internal.DefaultMessageSerializer
+import org.gradle.internal.serialize.*
+import org.gradle.messaging.remote.internal.*
import org.gradle.test.fixtures.concurrent.ConcurrentSpec
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import org.gradle.util.ports.FixedAvailablePortAllocator
+import spock.lang.Issue
+import spock.lang.Shared
+import spock.lang.Timeout
+import spock.lang.Unroll
+
+import java.nio.channels.SocketChannel
+ at Timeout(60)
class TcpConnectorTest extends ConcurrentSpec {
- final def serializer = new DefaultMessageSerializer<String>(getClass().classLoader)
+ @Shared def serializer = new DefaultMessageSerializer<String>(getClass().classLoader)
+ @Shared def kryoSerializer = new KryoBackedMessageSerializer<String>(Serializers.stateful(BaseSerializerFactory.STRING_SERIALIZER))
final def idGenerator = new UUIDGenerator()
final def addressFactory = new InetAddressFactory()
final def outgoingConnector = new TcpOutgoingConnector()
@@ -40,7 +49,8 @@ class TcpConnectorTest extends ConcurrentSpec {
connection != null
cleanup:
- acceptor?.requestStop()
+ acceptor?.stop()
+ connection?.stop()
}
def "client can connect to server using remote addresses"() {
@@ -54,7 +64,8 @@ class TcpConnectorTest extends ConcurrentSpec {
connection != null
cleanup:
- acceptor?.requestStop()
+ acceptor?.stop()
+ connection?.stop()
}
def "server executes action when incoming connection received"() {
@@ -62,14 +73,15 @@ class TcpConnectorTest extends ConcurrentSpec {
when:
def acceptor = incomingConnector.accept(action, false)
- outgoingConnector.connect(acceptor.address)
+ def connection = outgoingConnector.connect(acceptor.address).create(serializer)
thread.blockUntil.connected
then:
1 * action.execute(!null) >> { instant.connected }
cleanup:
- acceptor?.requestStop()
+ acceptor?.stop()
+ connection?.stop()
}
def "client throws exception when cannot connect to server"() {
@@ -96,10 +108,10 @@ class TcpConnectorTest extends ConcurrentSpec {
e.cause instanceof java.net.ConnectException
}
- def "client cannot connect when server has requested stop"() {
+ def "client cannot connect after server stopped"() {
when:
def acceptor = incomingConnector.accept(Mock(Action), false)
- acceptor.requestStop()
+ acceptor.stop()
outgoingConnector.connect(acceptor.address)
then:
@@ -108,6 +120,27 @@ class TcpConnectorTest extends ConcurrentSpec {
e.cause instanceof java.net.ConnectException
}
+ def "server closes connection when action fails"() {
+ Action action = Mock()
+
+ given:
+ _ * action.execute(_) >> {
+ throw new RuntimeException()
+ }
+
+ when:
+ def acceptor = incomingConnector.accept(action, false)
+ def connection = outgoingConnector.connect(acceptor.address).create(serializer)
+ def result = connection.receive()
+
+ then:
+ result == null
+
+ cleanup:
+ connection.stop()
+ acceptor?.stop()
+ }
+
def "server stops accepting connections when action fails"() {
Action action = Mock()
@@ -119,7 +152,8 @@ class TcpConnectorTest extends ConcurrentSpec {
when:
def acceptor = incomingConnector.accept(action, false)
async {
- outgoingConnector.connect(acceptor.address)
+ def connection = outgoingConnector.connect(acceptor.address).create(serializer)
+ connection.stop()
}
outgoingConnector.connect(acceptor.address)
@@ -129,7 +163,7 @@ class TcpConnectorTest extends ConcurrentSpec {
e.cause instanceof java.net.ConnectException
cleanup:
- acceptor?.requestStop()
+ acceptor?.stop()
}
def "acceptor stop blocks until accept action has completed"() {
@@ -144,7 +178,7 @@ class TcpConnectorTest extends ConcurrentSpec {
when:
def acceptor = incomingConnector.accept(action, false)
- outgoingConnector.connect(acceptor.address)
+ def connection = outgoingConnector.connect(acceptor.address).create(serializer)
thread.blockUntil.connected
operation.stop {
acceptor.stop()
@@ -154,21 +188,23 @@ class TcpConnectorTest extends ConcurrentSpec {
operation.stop.end > instant.actionFinished
cleanup:
- acceptor?.requestStop()
+ acceptor?.stop()
+ connection?.stop()
}
- def "can receive message from peer after peer has closed connection"() {
+ @Unroll
+ def "can receive message from peer after peer has closed connection using #serializerName"() {
// This is a test to simulate the messaging that the daemon does on build completion, in order to validate some assumptions
when:
def acceptor = incomingConnector.accept({ ConnectCompletion event ->
- def connection = event.create(serializer)
+ def connection = event.create(messageSerializer)
connection.dispatch("bye")
connection.stop()
instant.closed
} as Action, false)
- def connection = outgoingConnector.connect(acceptor.address).create(serializer)
+ def connection = outgoingConnector.connect(acceptor.address).create(messageSerializer)
thread.blockUntil.closed
then:
@@ -178,6 +214,111 @@ class TcpConnectorTest extends ConcurrentSpec {
cleanup:
connection?.stop()
acceptor?.stop()
+
+ where:
+ messageSerializer | serializerName
+ serializer | "java"
+ kryoSerializer | "kryo"
+ }
+
+ def "returns null on failure to receive due to truncated input"() {
+ given:
+ def incomingSerializer = { Encoder encoder, String value ->
+ encoder.writeInt(value.length())
+ } as Serializer
+ def action = { ConnectCompletion completion ->
+ def connection = completion.create(new KryoBackedMessageSerializer<String>(Serializers.stateful(incomingSerializer)))
+ connection.dispatch("string")
+ connection.stop()
+ } as Action
+ def outgoingSerializer = { Decoder decoder ->
+ decoder.readInt()
+ return decoder.readString()
+ } as Serializer
+
+ when:
+ def acceptor = incomingConnector.accept(action, false)
+ def connection = outgoingConnector.connect(acceptor.address).create(new KryoBackedMessageSerializer<String>(Serializers.stateful(outgoingSerializer)))
+ def result = connection.receive()
+
+ then:
+ result == null
+
+ cleanup:
+ connection?.stop()
+ acceptor?.stop()
+ }
+
+ def "reports failure to receive due to broken serializer"() {
+ def outgoingSerializer = Mock(Serializer)
+ def failure = new RuntimeException()
+
+ given:
+ def action = { ConnectCompletion completion ->
+ def connection = completion.create(kryoSerializer)
+ connection.dispatch("string")
+ connection.stop()
+ } as Action
+ outgoingSerializer.read(_) >> { Decoder decoder ->
+ throw failure
+ }
+
+ when:
+ def acceptor = incomingConnector.accept(action, false)
+ def connection = outgoingConnector.connect(acceptor.address).create(new KryoBackedMessageSerializer<String>(Serializers.stateful(outgoingSerializer)))
+ connection.receive()
+
+ then:
+ MessageIOException e = thrown()
+ e.message == "Could not read message from '${connection.remoteAddress}'."
+ e.cause == failure
+
+ cleanup:
+ connection?.stop()
+ acceptor?.stop()
+ }
+
+ @Issue("GRADLE-2316")
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "detects self connect when outgoing connection binds to same port"() {
+ given:
+ def socketChannel = SocketChannel.open()
+ def port = FixedAvailablePortAllocator.instance.assignPort()
+ def localAddress = addressFactory.findLocalAddresses().find { it instanceof Inet6Address }
+ def selfConnect = new InetSocketAddress(localAddress, port)
+
+ when:
+ socketChannel.socket().bind(selfConnect)
+ socketChannel.socket().connect(selfConnect)
+ then:
+ outgoingConnector.detectSelfConnect(socketChannel)
+
+ cleanup:
+ socketChannel.close()
+ }
+
+ @Issue("GRADLE-2316")
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "does not detect self connect when outgoing connection bind to different ports"() {
+ given:
+ def action = Mock(Action)
+ def socketChannel = SocketChannel.open()
+ def acceptor = incomingConnector.accept(action, false)
+ def localAddress = addressFactory.findLocalAddresses().find { it instanceof Inet6Address }
+ def bindPort = FixedAvailablePortAllocator.instance.assignPort()
+ def bindAddress = new InetSocketAddress(localAddress, bindPort)
+ def connectAddress = new InetSocketAddress(localAddress, acceptor.address.port)
+
+ when:
+ socketChannel.socket().bind(bindAddress)
+ socketChannel.socket().connect(connectAddress)
+
+ then:
+ !outgoingConnector.detectSelfConnect(socketChannel)
+
+ cleanup:
+ acceptor?.stop()
+ socketChannel.close()
}
}
diff --git a/subprojects/messaging/src/testFixtures/groovy/org/gradle/internal/serialize/SerializerSpec.groovy b/subprojects/messaging/src/testFixtures/groovy/org/gradle/internal/serialize/SerializerSpec.groovy
index 9dcfbc6..3131cec 100644
--- a/subprojects/messaging/src/testFixtures/groovy/org/gradle/internal/serialize/SerializerSpec.groovy
+++ b/subprojects/messaging/src/testFixtures/groovy/org/gradle/internal/serialize/SerializerSpec.groovy
@@ -18,14 +18,33 @@ package org.gradle.internal.serialize
import org.gradle.internal.serialize.kryo.KryoBackedDecoder
import org.gradle.internal.serialize.kryo.KryoBackedEncoder
+import org.gradle.messaging.remote.internal.Message
import spock.lang.Specification
-class SerializerSpec extends Specification {
+abstract class SerializerSpec extends Specification {
public <T> T serialize(T value, Serializer<T> serializer) {
def bytes = toBytes(value, serializer)
return fromBytes(bytes, serializer)
}
+ /**
+ * Serializes and deserializes the given value, asserting that the generated byte sequence is shorter than it would be when default
+ * Java serialization is used.
+ */
+ public <T> T usesEfficientSerialization(T value, Serializer<T> serializer, Integer expectedLength = null) {
+ def bytes = toBytes(value, serializer)
+ def length = bytes.length
+
+ def defaultBytes = new ByteArrayOutputStream()
+ Message.send(value, defaultBytes)
+ def defaultLength = defaultBytes.size()
+
+ println "${length} < ${defaultLength}"
+ assert length < defaultLength
+ assert expectedLength == null || length == expectedLength
+ return fromBytes(bytes, serializer)
+ }
+
public <T> T fromBytes(byte[] bytes, Serializer<T> serializer) {
return serializer.read(new KryoBackedDecoder(new ByteArrayInputStream(bytes)))
}
diff --git a/subprojects/model-core/model-core.gradle b/subprojects/model-core/model-core.gradle
index d9dad15..e1c6866 100644
--- a/subprojects/model-core/model-core.gradle
+++ b/subprojects/model-core/model-core.gradle
@@ -39,6 +39,7 @@ dependencies {
}
useTestFixtures()
+useTestFixtures(project: ':diagnostics', sourceSet: 'testFixtures')
//Re-enable classycle after removal of CollectionBuilder
//useClassycle()
strictCompileIgnoreDeprecations()
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ConfigurationCycleIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ConfigurationCycleIntegrationTest.groovy
index f87e8f7..c9d1c29 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ConfigurationCycleIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ConfigurationCycleIntegrationTest.groovy
@@ -63,11 +63,11 @@ class ConfigurationCycleIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasCause("""A cycle has been detected in model rule dependencies. References forming the cycle:
first
-\\- Rules#first(java.lang.String)
+\\- Rules#first
\\- second
- \\- model.second @ build file '${buildFile}' line 26, column 17
+ \\- model.second @ build.gradle line 26, column 17
\\- third
- \\- Rules#third(java.lang.String)
+ \\- Rules#third
\\- first""")
}
@@ -105,9 +105,9 @@ first
and:
failure.assertHasCause("""A cycle has been detected in model rule dependencies. References forming the cycle:
m1
-\\- Rules#m3ToM1(java.lang.Object, java.lang.Object)
+\\- Rules#m3ToM1
\\- m3
- \\- Rules#m1ToM3(java.lang.Object, java.lang.Object)
+ \\- Rules#m1ToM3
\\- m1""")
}
@@ -153,9 +153,9 @@ m1
and:
failure.assertHasCause("""A cycle has been detected in model rule dependencies. References forming the cycle:
m1
-\\- Rules#m3ToM1(java.lang.Object, java.lang.Object)
+\\- Rules#m3ToM1
\\- m3
- \\- Rules#m1ToM3(java.lang.Object, java.lang.Object)
+ \\- Rules#m1ToM3
\\- m1""")
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingFailureIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingFailureIntegrationTest.groovy
index 193dbd6..bd43ff1 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingFailureIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingFailureIntegrationTest.groovy
@@ -45,7 +45,7 @@ class ModelRuleBindingFailureIntegrationTest extends AbstractIntegrationSpec {
}
@Mutate
- void mutateThing2(MyThing2 thing2, MyThing3 thing3) {
+ void mutateThing2(MyThing2 thing2, MyThing3 thing3n, String someOtherThing, Integer intParam) {
}
}
}
@@ -57,15 +57,19 @@ class ModelRuleBindingFailureIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
then:
- failure.assertHasCause("""The following model rules are unbound:
- MyPlugin\$Rules#mutateThing2(MyPlugin\$MyThing2, MyPlugin\$MyThing3)
- Mutable:
- - <unspecified> (MyPlugin\$MyThing2) parameter 1
- Immutable:
- - <unspecified> (MyPlugin\$MyThing3) parameter 2
- MyPlugin\$Rules#thing1(MyPlugin\$MyThing2)
- Immutable:
- - <unspecified> (MyPlugin\$MyThing2) parameter 1""")
+ failureCauseContains '''
+ MyPlugin.Rules#mutateThing2
+ subject:
+ - <no path> MyPlugin.MyThing2 (parameter 1) [*]
+ inputs:
+ - <no path> MyPlugin.MyThing3 (parameter 2) [*]
+ - <no path> String (parameter 3) [*]
+ - <no path> Integer (parameter 4) [*]
+
+ MyPlugin.Rules#thing1
+ inputs:
+ - <no path> MyPlugin.MyThing2 (parameter 1) [*]
+'''
}
def "unbound dsl rules are reported"() {
@@ -83,10 +87,11 @@ class ModelRuleBindingFailureIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
then:
- failure.assertHasCause("""The following model rules are unbound:
- model.foo.bar @ build file '${buildFile}' line 4, column 17
- Mutable:
- - foo.bar (java.lang.Object)""")
+ failureCauseContains """
+ model.foo.bar @ build.gradle line 4, column 17
+ subject:
+ - foo.bar Object [*]
+"""
}
def "suggestions are provided for unbound rules"() {
@@ -114,10 +119,12 @@ class ModelRuleBindingFailureIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
then:
- failure.assertHasCause("""The following model rules are unbound:
- model.tasks.foonar @ build file '${buildFile}' line 15, column 17
- Mutable:
- - tasks.foonar (java.lang.Object) - suggestions: tasks.foobar""")
+ failureCauseContains '''
+ model.tasks.foonar @ build.gradle line 15, column 17
+ subject:
+ - tasks.foonar Object [*]
+ suggestions: tasks.foobar
+'''
}
def "ambiguous binding integration test"() {
@@ -160,10 +167,10 @@ class ModelRuleBindingFailureIntegrationTest extends AbstractIntegrationSpec {
then:
failure.assertHasDescription("A problem occurred evaluating root project")
- failure.assertHasCause("There is a problem with model rule Plugin3\$Rules#m(java.lang.String).")
+ failure.assertHasCause("There is a problem with model rule Plugin3.Rules#m.")
failure.assertHasCause("""Type-only model reference of type java.lang.String (parameter 1) is ambiguous as multiple model elements are available for this type:
- - s1 (created by: Plugin1\$Rules#s1())
- - s2 (created by: Plugin2\$Rules#s2())""")
+ - s1 (created by: Plugin1.Rules#s1)
+ - s2 (created by: Plugin2.Rules#s2)""")
}
def "incompatible type binding"() {
@@ -185,7 +192,7 @@ class ModelRuleBindingFailureIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
then:
- failure.assertHasCause("There is a problem with model rule Plugin1\$Rules#addTasks(java.lang.Integer).")
+ failure.assertHasCause("There is a problem with model rule Plugin1.Rules#addTasks.")
failure.assertHasCause("""Model reference to element 'tasks' with type java.lang.Integer (parameter 1) is invalid due to incompatible types.
This element was created by Project.<init>.tasks() and can be mutated as the following types:
- org.gradle.model.ModelMap<org.gradle.api.Task>
@@ -210,21 +217,57 @@ This element was created by Project.<init>.tasks() and can be mutated as the fol
fails "tasks"
then:
- failure.assertHasCause("""The following model rules are unbound:
- Rules#foo(java.lang.Integer)
- Immutable:
- - bar (java.lang.Integer) parameter 1""")
+ failureCauseContains '''
+ Rules#foo
+ inputs:
+ - bar Integer (parameter 1) [*]
+'''
}
- def "unbound rule for project that has no needed tasks does not cause error"() {
+ def "bound subject with unbound inputs are reported"() {
+ given:
+ buildScript """
+ class MyPlugin {
+ static class MyThing1 {}
+ static class MyThing2 {}
+ static class MyThing3 {}
+
+ static class Rules extends RuleSource {
+ @Model
+ MyThing1 thing1() {
+ new MyThing1()
+ }
+
+ @Mutate
+ void thing1(MyThing1 MyThing1, MyThing3 thing3) {
+
+ }
+
+ @Mutate
+ void mutateThing2(MyThing2 thing2, MyThing3 thing3) {
+ }
+ }
+ }
+
+ apply type: MyPlugin
+ """
+
when:
- settingsFile << "include 'a', 'b'"
- file("a/build.gradle") << "model { foo {} }"
+ fails "tasks"
then:
- succeeds ":b:dependencies"
- fails ":a:dependencies"
- failure.assertHasDescription("A problem occurred configuring project ':a'")
- failure.assertHasCause("The following model rules are unbound:")
+ failureCauseContains '''
+ MyPlugin.Rules#mutateThing2
+ subject:
+ - <no path> MyPlugin.MyThing2 (parameter 1) [*]
+ inputs:
+ - <no path> MyPlugin.MyThing3 (parameter 2) [*]
+
+ MyPlugin.Rules#thing1
+ subject:
+ - thing1 MyPlugin.MyThing1 (parameter 1)
+ inputs:
+ - <no path> MyPlugin.MyThing3 (parameter 2) [*]
+'''
}
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingValidationIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingValidationIntegrationTest.groovy
index 629ed0b..96f5ec3 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingValidationIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleBindingValidationIntegrationTest.groovy
@@ -60,10 +60,12 @@ class ModelRuleBindingValidationIntegrationTest extends AbstractIntegrationSpec
then:
fails "help"
- failure.assertHasCause("""The following model rules are unbound:
- Rules#s1(java.lang.Integer)
- Immutable:
- - <unspecified> (java.lang.Integer) parameter 1""")
+ failureCauseContains("""
+ Rules#s1
+ inputs:
+ - <no path> Integer (parameter 1) [*]
+
+[*] - indicates that a model item could not be found for the path or type.""")
}
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleSamplesIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleSamplesIntegrationTest.groovy
index 20b7328..064648c 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleSamplesIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleSamplesIntegrationTest.groovy
@@ -35,3 +35,5 @@ class ModelRuleSamplesIntegrationTest extends AbstractIntegrationSpec {
output.contains("Hello John Smith!")
}
}
+
+
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleValidationIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleValidationIntegrationTest.groovy
index 6b82226..6ef78be 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleValidationIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ModelRuleValidationIntegrationTest.groovy
@@ -40,7 +40,7 @@ class ModelRuleValidationIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasCause("Failed to apply plugin [class 'MyPlugin']")
- failure.assertHasCause("Path of declared model element created by rule MyPlugin\$Rules#strings() is invalid.")
+ failure.assertHasCause("Path of declared model element created by rule MyPlugin.Rules#strings is invalid.")
failure.assertHasCause("Model element name ' ' has illegal first character ' ' (names must start with an ASCII letter or underscore)")
}
@@ -64,7 +64,7 @@ class ModelRuleValidationIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasCause("Failed to apply plugin [class 'MyPlugin']")
- failure.assertHasCause("Path of declared model element created by rule MyPlugin\$Rules#strings() is invalid.")
+ failure.assertHasCause("Path of declared model element created by rule MyPlugin.Rules#strings is invalid.")
failure.assertHasCause("Model path 'foo. bar' is invalid due to invalid name component")
failure.assertHasCause("Model element name ' bar' has illegal first character ' ' (names must start with an ASCII letter or underscore)")
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/PluginRuleSourceIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/PluginRuleSourceIntegrationTest.groovy
index db044c3..c528b00 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/PluginRuleSourceIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/PluginRuleSourceIntegrationTest.groovy
@@ -135,7 +135,7 @@ class PluginRuleSourceIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasCause("Failed to apply plugin [class 'MyOtherPlugin']")
- failure.assertHasCause("Cannot create 'string' using creation rule 'MyOtherPlugin\$Rules#string()' as the rule 'MyPlugin\$Rules#string()' is already registered to create this model element.")
+ failure.assertHasCause("Cannot create 'string' using creation rule 'MyOtherPlugin.Rules#string' as the rule 'MyPlugin.Rules#string' is already registered to create this model element.")
}
def "informative error message when two plugins declare model at the same path and model is already created"() {
@@ -175,7 +175,7 @@ class PluginRuleSourceIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasCause("Failed to apply plugin [class 'MyOtherPlugin']")
- failure.assertHasCause("Cannot create 'string' using creation rule 'MyOtherPlugin\$Rules#string()' as the rule 'MyPlugin\$Rules#string()' has already been used to create this model element.")
+ failure.assertHasCause("Cannot create 'string' using creation rule 'MyOtherPlugin.Rules#string' as the rule 'MyPlugin.Rules#string' has already been used to create this model element.")
}
def "informative error message when creation rule throws"() {
@@ -201,7 +201,7 @@ class PluginRuleSourceIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
and:
- failure.assertHasCause("Exception thrown while executing model rule: MyPlugin\$Rules#string()")
+ failure.assertHasCause("Exception thrown while executing model rule: MyPlugin.Rules#string")
failure.assertHasCause("oh no!")
}
@@ -260,7 +260,7 @@ class PluginRuleSourceIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
and:
- failure.assertHasCause("error executing model rule: MyPlugin\$Rules#string() - rule returned null")
+ failure.assertHasCause("error executing model rule: MyPlugin.Rules#string - rule returned null")
}
def "plugin applied by plugin can contribute rules"() {
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ScopedRuleSourceIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ScopedRuleSourceIntegrationTest.groovy
index 381faa6..1055a6d 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/ScopedRuleSourceIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/ScopedRuleSourceIntegrationTest.groovy
@@ -87,7 +87,7 @@ class ScopedRuleSourceIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
and:
- failure.assertHasCause("Exception thrown while executing model rule: ThrowingRule#badRule(org.gradle.api.Task)")
+ failure.assertHasCause("Exception thrown while executing model rule: ThrowingRule#badRule")
failure.assertHasCause("I'm broken")
}
@@ -115,8 +115,8 @@ class ScopedRuleSourceIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
and:
- failure.assertHasCause("Exception thrown while executing model rule: Rules#addTasks(org.gradle.model.ModelMap<org.gradle.api.Task>)")
- failure.assertHasCause("InvalidRuleSource#invalidRule(org.gradle.api.Task) is not a valid model rule method")
+ failure.assertHasCause("Exception thrown while executing model rule: Rules#addTasks")
+ failure.assertHasCause("InvalidRuleSource#invalidRule is not a valid model rule method")
}
def "unbound inputs of scoped rules are reported and their scope is shown"() {
@@ -143,12 +143,15 @@ class ScopedRuleSourceIntegrationTest extends AbstractIntegrationSpec {
fails "tasks"
and:
- failure.assertHasCause("""The following model rules are unbound:
- UnboundRuleSource#unboundRule(java.lang.String, java.lang.Integer, java.lang.String)
- Mutable:
- - <unspecified> (java.lang.String) parameter 1 in scope of 'tasks.taskWithUnboundRuleSourceApplied'
- Immutable:
- - <unspecified> (java.lang.Integer) parameter 2
- - tasks.taskWithUnboundRuleSourceApplied.some.inner.path (java.lang.String) parameter 3""")
+ failureCauseContains '''
+ UnboundRuleSource#unboundRule
+ subject:
+ - <no path> String (parameter 1) [*]
+ scope: tasks.taskWithUnboundRuleSourceApplied
+ inputs:
+ - <no path> Integer (parameter 2) [*]
+ - tasks.taskWithUnboundRuleSourceApplied.some.inner.path String (parameter 3) [*]
+'''
}
+
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/TaskCreationIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/TaskCreationIntegrationTest.groovy
index 138e4b7..b1cfaf5 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/TaskCreationIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/TaskCreationIntegrationTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.model
+import org.gradle.api.reporting.model.ModelReportOutput
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.util.TextUtil
@@ -229,7 +230,7 @@ class TaskCreationIntegrationTest extends AbstractIntegrationSpec {
fails "bar"
then:
- failure.assertHasCause('Exception thrown while executing model rule: MyPlugin#checkTask(MessageTask)')
+ failure.assertHasCause('Exception thrown while executing model rule: MyPlugin#checkTask')
failure.assertHasCause('task is invalid!')
}
@@ -498,8 +499,8 @@ foo configured
fails "tasks"
then:
- failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks2(org.gradle.model.ModelMap<org.gradle.api.Task>, MyModel)")
- failure.assertHasCause("Cannot create 'tasks.a' using creation rule 'MyPlugin#addTasks2(org.gradle.model.ModelMap<org.gradle.api.Task>, MyModel) > create(a)' as the rule 'MyPlugin#addTasks1(org.gradle.model.ModelMap<org.gradle.api.Task>, MyModel) > create(a)' is already registered to create this model element.")
+ failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks2")
+ failure.assertHasCause("Cannot create 'tasks.a' using creation rule 'MyPlugin#addTasks2 > create(a)' as the rule 'MyPlugin#addTasks1 > create(a)' is already registered to create this model element.")
}
def "cannot create tasks during config of task"() {
@@ -521,8 +522,8 @@ foo configured
fails "tasks"
then:
- failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks(org.gradle.model.ModelMap<org.gradle.api.Task>) > foo.<init>")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelMap<org.gradle.api.Task>' given to rule 'MyPlugin#addTasks(org.gradle.model.ModelMap<org.gradle.api.Task>)'")
+ failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks > create(foo)")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelMap<org.gradle.api.Task>' given to rule 'MyPlugin#addTasks'")
}
def "failure during task instantiation is reasonably reported"() {
@@ -548,7 +549,7 @@ foo configured
fails "tasks"
then:
- failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks(org.gradle.model.ModelMap<org.gradle.api.Task>)")
+ failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks > create(foo)")
failure.assertHasCause("Could not create task of type 'Faulty'")
}
@@ -571,7 +572,7 @@ foo configured
fails "tasks"
then:
- failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks(org.gradle.model.ModelMap<org.gradle.api.Task>)")
+ failure.assertHasCause("Exception thrown while executing model rule: MyPlugin#addTasks")
failure.assertHasCause("config failure")
}
@@ -655,7 +656,7 @@ foo configured
fails "foo"
and:
- failure.assertHasCause("Cannot create 'tasks.foo' using creation rule 'MyPlugin#addTask(org.gradle.model.ModelMap<org.gradle.api.Task>) > create(foo)' as the rule 'Project.<init>.tasks.foo()' is already registered to create this model element.")
+ failure.assertHasCause("Cannot create 'tasks.foo' using creation rule 'MyPlugin#addTask > create(foo)' as the rule 'Project.<init>.tasks.foo()' is already registered to create this model element.")
}
def "can create task with invalid model space name"() {
@@ -669,4 +670,38 @@ foo configured
then:
":." in executedTasks
}
+
+ def "proxy classes are never used as task instance nodes types"(){
+ given:
+ buildFile << """
+tasks.create(name: 'taskContainerTask', type: DefaultTask) { }
+
+task standardTask << {}
+
+model {
+ tasks {
+ newModelTask(Task) {}
+ }
+}
+
+class MyPlugin extends RuleSource {
+ @Mutate
+ void addTasks(ModelMap<Task> tasks) {
+ tasks.create('modelMapTask') {}
+ }
+}
+apply type: MyPlugin
+"""
+
+ when:
+ succeeds("model")
+
+ then:
+ def tasksNode = ModelReportOutput.from(output).modelNode.tasks
+ tasksNode.taskContainerTask. at type[0] == 'org.gradle.api.DefaultTask'
+ tasksNode.standardTask. at type[0] == 'org.gradle.api.DefaultTask'
+ tasksNode.newModelTask. at type[0] == 'org.gradle.api.Task'
+ tasksNode.modelMapTask. at type[0] == 'org.gradle.api.Task'
+ tasksNode.model. at type[0] == 'org.gradle.api.reporting.model.ModelReport' //Placeholder task
+ }
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ComplexManagedTypeIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ComplexManagedTypeIntegrationTest.groovy
deleted file mode 100644
index 2cc1eaa..0000000
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ComplexManagedTypeIntegrationTest.groovy
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.managed
-
-import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-
-class ComplexManagedTypeIntegrationTest extends AbstractIntegrationSpec {
-
- def "rule can provide a composite managed model element"() {
- when:
- buildScript '''
- @Managed
- interface Platform {
- String getDisplayName()
- void setDisplayName(String name)
-
- OperatingSystem getOperatingSystem()
- }
-
- @Managed
- interface OperatingSystem {
- Family getFamily()
-
- String getVersion()
- void setVersion(String name)
- }
-
- @Managed
- interface Family {
- String getName()
- void setName(String name)
- }
-
- class RulePlugin extends RuleSource {
- @Model
- void somePlatform(Platform platform) {
- assert platform.displayName == null
- assert platform.operatingSystem != null
- assert platform.operatingSystem.version == null
- assert platform.operatingSystem.family != null
- assert platform.operatingSystem.family.name == null
-
- platform.displayName = "Microsoft Windows 8.1"
- platform.operatingSystem.version = "8.1"
- platform.operatingSystem.family.name = "windows"
-
- assert platform.displayName == "Microsoft Windows 8.1"
- assert platform.operatingSystem.version == "8.1"
- assert platform.operatingSystem.family.name == "windows"
-
- assert platform.operatingSystem.is(platform.operatingSystem)
- assert platform.operatingSystem.family.is(platform.operatingSystem.family)
- }
-
- @Mutate
- void addPersonTask(ModelMap<Task> tasks, Platform platform) {
- tasks.create("echo") {
- it.doLast {
- println "platform: $platform"
- println "os: $platform.operatingSystem"
- println "family: $platform.operatingSystem.family"
- println "platform name: $platform.operatingSystem.family.name $platform.operatingSystem.version"
- }
- }
- }
- }
-
- apply type: RulePlugin
- '''
-
- then:
- succeeds "echo"
-
- and:
- output.contains("platform: Platform 'somePlatform'")
- output.contains("os: OperatingSystem 'somePlatform.operatingSystem'")
- output.contains("family: Family 'somePlatform.operatingSystem.family'")
- output.contains("platform name: windows 8.1")
- }
-
- def "rule can apply defaults to a nested managed model element"() {
- when:
- buildScript '''
- @Managed
- interface Platform {
- String getDisplayName()
- void setDisplayName(String name)
-
- OperatingSystem getOperatingSystem()
- }
-
- @Managed
- interface OperatingSystem {
- String getName()
- void setName(String name)
- }
-
- class RulePlugin extends RuleSource {
- @Model
- void platform(Platform platform) {
- platform.displayName = "Microsoft Windows"
- platform.operatingSystem.name += " OS"
- }
-
- @Defaults
- void defaultOs(@Path('platform.operatingSystem') OperatingSystem os) {
- os.name = "default"
- }
-
- @Finalize
- void cleanUpOs(@Path('platform.operatingSystem') OperatingSystem os) {
- os.name += " x86"
- }
-
- @Mutate
- void addPersonTask(ModelMap<Task> tasks, Platform platform) {
- tasks.create("echo") {
- it.doLast {
- println "platform: $platform.operatingSystem.name"
- }
- }
- }
- }
-
- apply type: RulePlugin
- '''
-
- then:
- succeeds "echo"
-
- and:
- output.contains("platform: default OS x86")
- }
-
- def "rule can provide a managed model element that references another managed model element"() {
- when:
- buildScript '''
- @Managed
- interface Platform {
- String getDisplayName()
- void setDisplayName(String name)
-
- OperatingSystem getOperatingSystem()
- void setOperatingSystem(OperatingSystem operatingSystem)
- }
-
- @Managed
- interface OperatingSystem {
- String getName()
- void setName(String name)
- }
-
- @Managed
- interface OperatingSystems {
- OperatingSystem getWindows()
- OperatingSystem getLinux()
- }
-
- class RulePlugin extends RuleSource {
- @Model
- void os(OperatingSystems os) {
- os.windows.name = "windows"
- os.linux.name = "linux"
- }
-
- @Model
- void windowsPlatform(Platform platform, OperatingSystems os) {
- platform.displayName = "Microsoft Windows"
-
- assert platform.operatingSystem == null
-
- platform.operatingSystem = os.linux
- assert platform.operatingSystem.is(os.linux)
-
- platform.operatingSystem = null
- assert platform.operatingSystem == null
-
- platform.operatingSystem = os.windows
- assert platform.operatingSystem.is(os.windows)
- }
-
- @Mutate
- void addPersonTask(ModelMap<Task> tasks, Platform platform) {
- tasks.create("echo") {
- it.doLast {
- println "platform: $platform"
- println "os: $platform.operatingSystem"
- println "platform name: $platform.operatingSystem.name"
- }
- }
- }
- }
-
- apply type: RulePlugin
- '''
-
- then:
- succeeds "echo"
-
- and:
- output.contains("platform: Platform 'windowsPlatform'")
- output.contains("os: OperatingSystem 'os.windows'")
- output.contains("platform name: windows")
- }
-}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/CyclicalManagedTypeIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/CyclicalManagedTypeIntegrationTest.groovy
index a5d22be..4210bed 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/CyclicalManagedTypeIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/CyclicalManagedTypeIntegrationTest.groovy
@@ -39,7 +39,7 @@ class CyclicalManagedTypeIntegrationTest extends AbstractIntegrationSpec {
class RulePlugin extends RuleSource {
@Model
- void createParent(Parent parent) {
+ void parent(Parent parent) {
parent.name = "parent"
parent.child.parent = parent
}
@@ -88,7 +88,7 @@ class CyclicalManagedTypeIntegrationTest extends AbstractIntegrationSpec {
class RulePlugin extends RuleSource {
@Model
- void createA(A a) {
+ void a(A a) {
a.name = "a"
a.b.c.a = a
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelMutationIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelMutationIntegrationTest.groovy
index 7fb65de..0133ce2 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelMutationIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelMutationIntegrationTest.groovy
@@ -56,8 +56,8 @@ class InvalidManagedModelMutationIntegrationTest extends AbstractIntegrationSpec
fails "tasks"
and:
- failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#name(Person)")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'Person' given to rule 'RulePlugin#name(Person)")
+ failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#name")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'Person' given to rule 'RulePlugin#name")
}
def "mutating composite managed inputs of a rule is not allowed"() {
@@ -93,7 +93,7 @@ class InvalidManagedModelMutationIntegrationTest extends AbstractIntegrationSpec
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToModifyCompositeSubjectOfAnotherRule")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'Pet' given to rule 'RulePlugin#tryToModifyCompositeSubjectOfAnotherRule(org.gradle.model.ModelMap<org.gradle.api.Task>, Person)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'Pet' given to rule 'RulePlugin#tryToModifyCompositeSubjectOfAnotherRule'")
}
def "mutating managed inputs of a dsl rule is not allowed"() {
@@ -125,7 +125,7 @@ class InvalidManagedModelMutationIntegrationTest extends AbstractIntegrationSpec
and:
failure.assertHasCause("Exception thrown while executing model rule: model.tasks")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'Person' given to rule 'model.tasks @ build file")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'Person' given to rule 'model.tasks @ build.gradle")
}
def "mutating managed objects outside of a creation rule is not allowed"() {
@@ -161,7 +161,7 @@ class InvalidManagedModelMutationIntegrationTest extends AbstractIntegrationSpec
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToModifyManagedObject")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'Person' given to rule 'RulePlugin#person(Person)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'Person' given to rule 'RulePlugin#person'")
}
def "mutating composite managed objects outside of a creation rule is not allowed"() {
@@ -202,7 +202,7 @@ class InvalidManagedModelMutationIntegrationTest extends AbstractIntegrationSpec
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToModifyManagedObject")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'Pet' given to rule 'RulePlugin#person(Person)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'Pet' given to rule 'RulePlugin#person'")
}
def "mutating managed objects referenced by another managed object outside of a creation rule is not allowed"() {
@@ -249,6 +249,6 @@ class InvalidManagedModelMutationIntegrationTest extends AbstractIntegrationSpec
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToModifyManagedObject")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'Pet' given to rule 'RulePlugin#person(Person, Pet)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'Pet' given to rule 'RulePlugin#person'")
}
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelRuleIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelRuleIntegrationTest.groovy
index 74cf6ab..377a36a 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelRuleIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/InvalidManagedModelRuleIntegrationTest.groovy
@@ -48,7 +48,7 @@ class InvalidManagedModelRuleIntegrationTest extends AbstractIntegrationSpec{
fails "tasks"
and:
- failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#createPerson(Person)")
+ failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#createPerson")
failure.assertThatCause(Matchers.containsLine(Matchers.matchesRegexp(/No signature of method: .*\.setName\(\) is applicable for argument types: \(java.lang.Integer\) values: \[123\]/)))
}
@@ -85,7 +85,7 @@ class InvalidManagedModelRuleIntegrationTest extends AbstractIntegrationSpec{
fails "tasks"
and:
- failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#createPerson(Person)")
+ failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#createPerson")
failure.assertHasCause("argument type mismatch")
}
@@ -148,7 +148,7 @@ class InvalidManagedModelRuleIntegrationTest extends AbstractIntegrationSpec{
fails "tasks"
and:
- failure.assertHasCause("Rules#s(java.lang.String) is not a valid model rule method: a void returning model element creation rule cannot take a value type as the first parameter, which is the element being created. Return the value from the method.")
+ failure.assertHasCause("Rules#s is not a valid model rule method: a void returning model element creation rule cannot take a value type as the first parameter, which is the element being created. Return the value from the method.")
}
def "provides a useful error message when an invalid managed type is used in a rule"() {
@@ -172,7 +172,7 @@ class InvalidManagedModelRuleIntegrationTest extends AbstractIntegrationSpec{
fails "tasks"
and:
- failure.assertHasCause("Declaration of model rule RulePlugin#createPerson(Person) is invalid")
+ failure.assertHasCause("Declaration of model rule RulePlugin#createPerson is invalid")
failure.assertHasCause("Invalid managed model type Person: read only property 'name' has non managed type java.lang.String, only managed types can be used")
}
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelMapIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelMapIntegrationTest.groovy
index 2d63ad8..3ed0f17 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelMapIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelMapIntegrationTest.groovy
@@ -157,7 +157,7 @@ class ManagedModelMapIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasDescription('A problem occurred configuring root project')
- failure.assertHasCause('Exception thrown while executing model rule: Rules#people(org.gradle.model.ModelMap<Person>) > foo.<init>')
+ failure.assertHasCause('Exception thrown while executing model rule: Rules#people > create(foo)')
failure.assertHasCause('broken')
}
@@ -189,7 +189,7 @@ class ManagedModelMapIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#people")
- failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.ModelMap<Person>' given to rule 'RulePlugin#people(org.gradle.model.ModelMap<Person>)'")
+ failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.ModelMap<Person>' given to rule 'RulePlugin#people'")
}
def "cannot mutate when used as an input"() {
@@ -219,7 +219,7 @@ class ManagedModelMapIntegrationTest extends AbstractIntegrationSpec {
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#mutate")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelMap<Person>' given to rule 'RulePlugin#mutate(org.gradle.model.ModelMap<org.gradle.api.Task>, org.gradle.model.ModelMap<Person>)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelMap<Person>' given to rule 'RulePlugin#mutate'")
}
def "can read children of map when used as input"() {
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelPropertyTargetingRuleIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelPropertyTargetingRuleIntegrationTest.groovy
index 32c38a5..c1534ca 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelPropertyTargetingRuleIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedModelPropertyTargetingRuleIntegrationTest.groovy
@@ -25,7 +25,7 @@ class ManagedModelPropertyTargetingRuleIntegrationTest extends AbstractIntegrati
EnableModelDsl.enable(executer)
}
- def "rule can target structured property of managed element"() {
+ def "rule can target nested element of managed element as input"() {
when:
buildScript '''
@Managed
@@ -72,7 +72,7 @@ class ManagedModelPropertyTargetingRuleIntegrationTest extends AbstractIntegrati
output.contains("fromScript: foo")
}
- def "rule can target structured property of managed element as subject"() {
+ def "rule can target nested element of managed element as subject"() {
when:
buildScript '''
@Managed
@@ -106,6 +106,9 @@ class ManagedModelPropertyTargetingRuleIntegrationTest extends AbstractIntegrati
apply type: RulePlugin
model {
+ platform.operatingSystem {
+ name = "$name os"
+ }
tasks {
create("fromScript") {
it.doLast { println "fromScript: " + $("platform.operatingSystem.name") }
@@ -118,11 +121,64 @@ class ManagedModelPropertyTargetingRuleIntegrationTest extends AbstractIntegrati
succeeds "fromPlugin", "fromScript"
and:
+ output.contains("fromPlugin: foo os")
+ output.contains("fromScript: foo os")
+ }
+
+ def "rule can target reference property of managed element as input"() {
+ when:
+ buildScript '''
+ @Managed
+ interface Platform {
+ OperatingSystem getOperatingSystem()
+ void setOperatingSystem(OperatingSystem os)
+ }
+
+ @Managed
+ interface OperatingSystem {
+ String getName()
+ void setName(String name)
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void os(OperatingSystem os) {
+ os.name = "foo"
+ }
+
+ @Model
+ void platform(Platform platform, OperatingSystem os) {
+ platform.operatingSystem = os
+ }
+
+ @Mutate
+ void addTask(ModelMap<Task> tasks, @Path("platform.operatingSystem") OperatingSystem os) {
+ tasks.create("fromPlugin") {
+ doLast { println "fromPlugin: $os.name" }
+ }
+ }
+ }
+
+ apply type: RulePlugin
+
+ model {
+ tasks {
+ create("fromScript") {
+ it.doLast { println "fromScript: " + $("platform.operatingSystem").name }
+ }
+ }
+ }
+ '''
+
+ then:
+ succeeds "fromPlugin", "fromScript"
+
+ and:
output.contains("fromPlugin: foo")
output.contains("fromScript: foo")
}
- def "rule can target simple property of managed element"() {
+ def "rule can target scalar property of managed element as input"() {
when:
buildScript '''
@Managed
@@ -164,7 +220,7 @@ class ManagedModelPropertyTargetingRuleIntegrationTest extends AbstractIntegrati
output.contains("fromScript: foo")
}
- def "mutation rule can target property of managed element"() {
+ def "rule can configure scalar property of managed element"() {
when:
buildScript '''
@Managed
@@ -195,6 +251,9 @@ class ManagedModelPropertyTargetingRuleIntegrationTest extends AbstractIntegrati
apply type: RulePlugin
model {
+ platform {
+ operatingSystem.name = "$operatingSystem.name os"
+ }
tasks {
create("fromScript") {
it.doLast { println "fromScript: " + $("platform.operatingSystem.name") }
@@ -207,11 +266,11 @@ class ManagedModelPropertyTargetingRuleIntegrationTest extends AbstractIntegrati
succeeds "fromPlugin", "fromScript"
and:
- output.contains("fromPlugin: foo")
- output.contains("fromScript: foo")
+ output.contains("fromPlugin: foo os")
+ output.contains("fromScript: foo os")
}
- def "creation rule can target property of managed element"() {
+ def "creation rule can target scalar property of managed element as input"() {
when:
buildScript '''
@Managed
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedSetIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedSetIntegrationTest.groovy
index 56e15fb..d93fe0b 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedSetIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedSetIntegrationTest.groovy
@@ -178,7 +178,7 @@ class ManagedSetIntegrationTest extends AbstractIntegrationSpec {
output.contains 'Women in computing: Ada Lovelace, Grace Hooper'
}
- def "managed model type can reference a collection of managed types"() {
+ def "managed model cannot have a reference to a managed set"() {
when:
buildScript '''
@Managed
@@ -192,48 +192,25 @@ class ManagedSetIntegrationTest extends AbstractIntegrationSpec {
String getName()
void setName(String string)
ManagedSet<Person> getMembers()
+ //Invalid setter
void setMembers(ManagedSet<Person> members)
}
class Rules extends RuleSource {
@Model
- void people(ManagedSet<Person> people) {
- people.create { name = "Ada Lovelace" }
- people.create { name = "Grace Hooper" }
- }
-
- @Model
void group(Group group, @Path("people") ManagedSet<Person> people) {
- group.name = "Women in computing"
-
- assert group.members == null
-
- group.members = people
-
- assert group.members.is(people)
}
}
apply type: Rules
-
- model {
- tasks {
- create("printGroup") {
- doLast {
- def members = $("group").members*.name.sort().join(", ")
- def name = $("group").name
- println "$name: $members"
- }
- }
- }
- }
'''
then:
- succeeds "printGroup"
+ fails "tasks"
and:
- output.contains 'Women in computing: Ada Lovelace, Grace Hooper'
+ failure.assertHasCause("Declaration of model rule Rules#group is invalid.")
+ failure.assertHasCause("Invalid managed model type Group: property 'members' cannot have a setter (org.gradle.model.collection.ManagedSet<Person> properties must be read only)")
}
def "rule method can apply defaults to a managed set"() {
@@ -390,7 +367,7 @@ configure p3
and:
failure.assertHasDescription('A problem occurred configuring root project')
- failure.assertHasCause('Exception thrown while executing model rule: Rules#people(org.gradle.model.collection.ManagedSet<Person>)')
+ failure.assertHasCause('Exception thrown while executing model rule: Rules#people')
failure.assertHasCause('broken')
}
@@ -420,7 +397,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#people")
- failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#people(org.gradle.model.collection.ManagedSet<Person>)'")
+ failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#people'")
}
def "read methods of ManagedSet throw exceptions when used in a mutation rule"() {
@@ -453,7 +430,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#readPeople")
- failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#readPeople(org.gradle.model.collection.ManagedSet<Person>)'")
+ failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#readPeople'")
}
def "mutating a managed set that is an input of a rule is not allowed"() {
@@ -481,7 +458,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToMutateInputManagedSet")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#tryToMutateInputManagedSet(org.gradle.model.ModelMap<org.gradle.api.Task>, org.gradle.model.collection.ManagedSet<Person>)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#tryToMutateInputManagedSet'")
}
def "mutating a managed set outside of a creation rule is not allowed"() {
@@ -515,7 +492,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToMutateManagedSetOutsideOfCreationRule")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#people(org.gradle.model.collection.ManagedSet<Person>)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'RulePlugin#people'")
}
def "mutating managed set which is an input of a DSL rule is not allowed"() {
@@ -545,7 +522,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: model.tasks")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'model.tasks @ build file")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.collection.ManagedSet<Person>' given to rule 'model.tasks @ build.gradle")
}
def "cannot view managed set as model set"() {
@@ -571,6 +548,6 @@ configure p3
fails "tasks"
and:
- failure.assertHasCause("The following model rules are unbound")
+ failure.assertHasCause("The following model rules could not be applied due to unbound inputs and/or subjects:")
}
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedTypeReferencesIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedTypeReferencesIntegrationTest.groovy
new file mode 100644
index 0000000..a9450f3
--- /dev/null
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ManagedTypeReferencesIntegrationTest.groovy
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.managed
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+class ManagedTypeReferencesIntegrationTest extends AbstractIntegrationSpec {
+ def "rule can provide a managed model element that references another managed model element"() {
+ when:
+ buildScript '''
+ @Managed
+ interface Platform {
+ String getDisplayName()
+ void setDisplayName(String name)
+
+ OperatingSystem getOperatingSystem()
+ void setOperatingSystem(OperatingSystem operatingSystem)
+ }
+
+ @Managed
+ interface OperatingSystem {
+ String getName()
+ void setName(String name)
+ }
+
+ @Managed
+ interface OperatingSystems {
+ OperatingSystem getWindows()
+ OperatingSystem getLinux()
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void os(OperatingSystems os) {
+ os.windows.name = "windows"
+ os.linux.name = "linux"
+ }
+
+ @Model
+ void windowsPlatform(Platform platform, OperatingSystems os) {
+ platform.displayName = "Microsoft Windows"
+
+ assert platform.operatingSystem == null
+
+ platform.operatingSystem = os.linux
+ assert platform.operatingSystem.is(os.linux)
+
+ platform.operatingSystem = null
+ assert platform.operatingSystem == null
+
+ platform.operatingSystem = os.windows
+ assert platform.operatingSystem.is(os.windows)
+ }
+
+ @Mutate
+ void addPersonTask(ModelMap<Task> tasks, Platform platform) {
+ tasks.create("echo") {
+ it.doLast {
+ println "platform: $platform"
+ println "os: $platform.operatingSystem"
+ println "platform name: $platform.operatingSystem.name"
+ }
+ }
+ }
+ }
+
+ apply type: RulePlugin
+ '''
+
+ then:
+ succeeds "echo"
+
+ and:
+ output.contains("platform: Platform 'windowsPlatform'")
+ output.contains("os: OperatingSystem 'os.windows'")
+ output.contains("platform name: windows")
+ }
+}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ModelSetIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ModelSetIntegrationTest.groovy
index 972de8e..4f17a1f 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ModelSetIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ModelSetIntegrationTest.groovy
@@ -174,7 +174,7 @@ class ModelSetIntegrationTest extends AbstractIntegrationSpec {
output.contains 'Women in computing: Ada Lovelace, Grace Hooper'
}
- def "managed model type can reference a collection of managed types"() {
+ def "managed model cannot have a reference to a model set"() {
when:
buildScript '''
@Managed
@@ -188,48 +188,25 @@ class ModelSetIntegrationTest extends AbstractIntegrationSpec {
String getName()
void setName(String string)
ModelSet<Person> getMembers()
+ //Invalid setter
void setMembers(ModelSet<Person> members)
}
class Rules extends RuleSource {
@Model
- void people(ModelSet<Person> people) {
- people.create { name = "Ada Lovelace" }
- people.create { name = "Grace Hooper" }
- }
-
- @Model
void group(Group group, @Path("people") ModelSet<Person> people) {
- group.name = "Women in computing"
-
- assert group.members == null
-
- group.members = people
-
- assert group.members.is(people)
}
}
apply type: Rules
-
- model {
- tasks {
- create("printGroup") {
- doLast {
- def members = $("group").members*.name.sort().join(", ")
- def name = $("group").name
- println "$name: $members"
- }
- }
- }
- }
'''
then:
- succeeds "printGroup"
+ fails "tasks"
and:
- output.contains 'Women in computing: Ada Lovelace, Grace Hooper'
+ failure.assertHasCause("Declaration of model rule Rules#group is invalid.")
+ failure.assertHasCause("Invalid managed model type Group: property 'members' cannot have a setter (org.gradle.model.ModelSet<Person> properties must be read only)")
}
def "rule method can apply defaults to a managed set"() {
@@ -386,7 +363,7 @@ configure p3
and:
failure.assertHasDescription('A problem occurred configuring root project')
- failure.assertHasCause('Exception thrown while executing model rule: Rules#people(org.gradle.model.ModelSet<Person>)')
+ failure.assertHasCause('Exception thrown while executing model rule: Rules#people')
failure.assertHasCause('broken')
}
@@ -416,7 +393,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#people")
- failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#people(org.gradle.model.ModelSet<Person>)'")
+ failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#people'")
}
def "read methods of ModelSet throw exceptions when used in a mutation rule"() {
@@ -449,7 +426,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#readPeople")
- failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#readPeople(org.gradle.model.ModelSet<Person>)'")
+ failure.assertHasCause("Attempt to read a write only view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#readPeople'")
}
def "mutating a managed set that is an input of a rule is not allowed"() {
@@ -477,7 +454,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToMutateInputModelSet")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#tryToMutateInputModelSet(org.gradle.model.ModelMap<org.gradle.api.Task>, org.gradle.model.ModelSet<Person>)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#tryToMutateInputModelSet'")
}
def "mutating a managed set outside of a creation rule is not allowed"() {
@@ -511,7 +488,7 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: RulePlugin#tryToMutateModelSetOutsideOfCreationRule")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#people(org.gradle.model.ModelSet<Person>)'")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'RulePlugin#people'")
}
def "mutating managed set which is an input of a DSL rule is not allowed"() {
@@ -541,6 +518,6 @@ configure p3
and:
failure.assertHasCause("Exception thrown while executing model rule: model.tasks")
- failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'model.tasks @ build file")
+ failure.assertHasCause("Attempt to mutate closed view of model of type 'org.gradle.model.ModelSet<Person>' given to rule 'model.tasks @ build.gradle")
}
}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/NestedManagedTypeIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/NestedManagedTypeIntegrationTest.groovy
new file mode 100644
index 0000000..0563e33
--- /dev/null
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/NestedManagedTypeIntegrationTest.groovy
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.managed
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+class NestedManagedTypeIntegrationTest extends AbstractIntegrationSpec {
+
+ def "rule can provide a managed model tree"() {
+ when:
+ buildScript '''
+ @Managed
+ interface Platform {
+ String getDisplayName()
+ void setDisplayName(String name)
+
+ OperatingSystem getOperatingSystem()
+ }
+
+ @Managed
+ interface OperatingSystem {
+ Family getFamily()
+
+ String getVersion()
+ void setVersion(String name)
+ }
+
+ @Managed
+ interface Family {
+ String getName()
+ void setName(String name)
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void somePlatform(Platform platform) {
+ assert platform.displayName == null
+ assert platform.operatingSystem != null
+ assert platform.operatingSystem.version == null
+ assert platform.operatingSystem.family != null
+ assert platform.operatingSystem.family.name == null
+
+ platform.displayName = "Microsoft Windows 8.1"
+ platform.operatingSystem.version = "8.1"
+ platform.operatingSystem.family.name = "windows"
+
+ assert platform.displayName == "Microsoft Windows 8.1"
+ assert platform.operatingSystem.version == "8.1"
+ assert platform.operatingSystem.family.name == "windows"
+
+ assert platform.operatingSystem.is(platform.operatingSystem)
+ assert platform.operatingSystem.family.is(platform.operatingSystem.family)
+ }
+
+ @Mutate
+ void addPersonTask(ModelMap<Task> tasks, Platform platform) {
+ tasks.create("echo") {
+ it.doLast {
+ println "platform: $platform"
+ println "os: $platform.operatingSystem"
+ println "family: $platform.operatingSystem.family"
+ println "platform name: $platform.operatingSystem.family.name $platform.operatingSystem.version"
+ }
+ }
+ }
+ }
+
+ apply type: RulePlugin
+ '''
+
+ then:
+ succeeds "echo"
+
+ and:
+ output.contains("platform: Platform 'somePlatform'")
+ output.contains("os: OperatingSystem 'somePlatform.operatingSystem'")
+ output.contains("family: Family 'somePlatform.operatingSystem.family'")
+ output.contains("platform name: windows 8.1")
+ }
+
+ def "rule can apply defaults to a nested managed model element"() {
+ when:
+ buildScript '''
+ @Managed
+ interface Platform {
+ String getDisplayName()
+ void setDisplayName(String name)
+
+ OperatingSystem getOperatingSystem()
+ }
+
+ @Managed
+ interface OperatingSystem {
+ String getName()
+ void setName(String name)
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void platform(Platform platform) {
+ platform.displayName = "Microsoft Windows"
+ platform.operatingSystem.name += " OS"
+ }
+
+ @Defaults
+ void defaultOs(@Path('platform.operatingSystem') OperatingSystem os) {
+ os.name = "default"
+ }
+
+ @Finalize
+ void cleanUpOs(@Path('platform.operatingSystem') OperatingSystem os) {
+ os.name += " x86"
+ }
+
+ @Mutate
+ void addPersonTask(ModelMap<Task> tasks, Platform platform) {
+ tasks.create("echo") {
+ it.doLast {
+ println "platform: $platform.operatingSystem.name"
+ }
+ }
+ }
+ }
+
+ apply type: RulePlugin
+ '''
+
+ then:
+ succeeds "echo"
+
+ and:
+ output.contains("platform: default OS x86")
+ }
+}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/PolymorphicManagedTypeIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/PolymorphicManagedTypeIntegrationTest.groovy
index a9a6dfc..b856e40 100644
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/PolymorphicManagedTypeIntegrationTest.groovy
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/PolymorphicManagedTypeIntegrationTest.groovy
@@ -23,6 +23,7 @@ class PolymorphicManagedTypeIntegrationTest extends AbstractIntegrationSpec {
def "rule can provide a managed model element backed by an abstract class that implements interfaces"() {
when:
buildScript '''
+ @Managed
interface Named {
String getName()
}
@@ -61,6 +62,7 @@ class PolymorphicManagedTypeIntegrationTest extends AbstractIntegrationSpec {
def "rule can provide a managed model element backed by an abstract class that extends other classes"() {
when:
buildScript '''
+ @Managed
abstract class Named {
abstract String getName()
}
@@ -99,6 +101,7 @@ class PolymorphicManagedTypeIntegrationTest extends AbstractIntegrationSpec {
def "managed model interface can extend other interface"() {
when:
buildScript '''
+ @Managed
interface Named {
String getName()
void setName(String name)
@@ -140,6 +143,7 @@ class PolymorphicManagedTypeIntegrationTest extends AbstractIntegrationSpec {
def "can depend on managed super type as input and subject"() {
when:
buildScript '''
+ @Managed
interface Named {
String getName()
void setName(String name)
@@ -182,6 +186,7 @@ class PolymorphicManagedTypeIntegrationTest extends AbstractIntegrationSpec {
def "two managed types can extend the same parent"() {
when:
buildScript '''
+ @Managed
interface Named {
String getName()
void setName(String name)
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/PrimitivesInManagedModelIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/PrimitivesInManagedModelIntegrationTest.groovy
deleted file mode 100644
index 4abcba8..0000000
--- a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/PrimitivesInManagedModelIntegrationTest.groovy
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.managed
-
-import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-
-class PrimitivesInManagedModelIntegrationTest extends AbstractIntegrationSpec {
-
- def "values of primitive types and boxed primitive types are widened as usual when using groovy"() {
- when:
- buildScript '''
- @Managed
- interface PrimitiveTypes {
- Long getLongPropertyFromInt()
- void setLongPropertyFromInt(Long value)
-
- Long getLongPropertyFromInteger()
- void setLongPropertyFromInteger(Long value)
- }
-
- class RulePlugin extends RuleSource {
- @Model
- void createPrimitiveTypes(PrimitiveTypes primitiveTypes) {
- primitiveTypes.longPropertyFromInt = 123
- primitiveTypes.longPropertyFromInteger = new Integer(321)
- }
-
- @Mutate
- void addEchoTask(ModelMap<Task> tasks, final PrimitiveTypes primitiveTypes) {
- tasks.create("echo") {
- it.doLast {
- println "from int: $primitiveTypes.longPropertyFromInt"
- println "from Integer: $primitiveTypes.longPropertyFromInteger"
- }
- }
- }
- }
-
- apply type: RulePlugin
- '''
-
- then:
- succeeds "echo"
-
- and:
- output.contains "from int: 123"
- output.contains "from Integer: 321"
- }
-
- def "values of primitive types are boxed as usual when using java"() {
- when:
- file('buildSrc/src/main/java/Rules.java') << '''
- import org.gradle.api.*;
- import org.gradle.model.*;
-
- @Managed
- interface PrimitiveProperty {
- Long getLongProperty();
- void setLongProperty(Long value);
- Integer getIntegerProperty();
- void setIntegerProperty(Integer value);
- Boolean getBooleanProperty();
- void setBooleanProperty(Boolean value);
- Character getCharacterProperty();
- void setCharacterProperty(Character value);
- }
-
- class RulePlugin extends RuleSource {
- @Model
- void createPrimitiveProperty(PrimitiveProperty primitiveProperty) {
- primitiveProperty.setLongProperty(123l);
- primitiveProperty.setIntegerProperty(456);
- primitiveProperty.setBooleanProperty(true);
- primitiveProperty.setCharacterProperty('a');
- }
-
- @Mutate
- void addEchoTask(ModelMap<Task> tasks, final PrimitiveProperty primitiveProperty) {
- tasks.create("echo", new Action<Task>() {
- public void execute(Task task) {
- task.doLast(new Action<Task>() {
- public void execute(Task unused) {
- System.out.println(String.format("long: %d", primitiveProperty.getLongProperty()));
- System.out.println(String.format("integer: %d", primitiveProperty.getIntegerProperty()));
- System.out.println(String.format("boolean: %s", primitiveProperty.getBooleanProperty()));
- System.out.println(String.format("character: %s", primitiveProperty.getCharacterProperty()));
- }
- });
- }
- });
- }
- }
- '''
-
- buildScript '''
- apply type: RulePlugin
- '''
-
- then:
- succeeds "echo"
-
- and:
- output.contains "long: 123"
- output.contains "integer: 456"
- output.contains "boolean: true"
- output.contains "character: a"
- }
-
- def "can set/get properties of all supported unmanaged types"() {
- when:
- buildScript '''
- @Managed
- interface AllSupportedUnmanagedTypes {
- Boolean getBooleanProperty()
-
- void setBooleanProperty(Boolean value)
-
- Integer getIntegerProperty()
-
- void setIntegerProperty(Integer value)
-
- Long getLongProperty()
-
- void setLongProperty(Long value)
-
- Double getDoubleProperty()
-
- void setDoubleProperty(Double value)
-
- BigInteger getBigIntegerProperty()
-
- void setBigIntegerProperty(BigInteger value)
-
- BigDecimal getBigDecimalProperty()
-
- void setBigDecimalProperty(BigDecimal value)
-
- String getStringProperty()
-
- void setStringProperty(String value)
-
- File getFile()
-
- void setFile(File file)
- }
-
- class RulePlugin extends RuleSource {
- @Model
- void supportedUnmanagedTypes(AllSupportedUnmanagedTypes element) {
- element.booleanProperty = Boolean.TRUE
- element.integerProperty = Integer.valueOf(1)
- element.longProperty = Long.valueOf(2L)
- element.doubleProperty = Double.valueOf(3.3)
- element.bigIntegerProperty = new BigInteger("4")
- element.bigDecimalProperty = new BigDecimal("5.5")
- element.stringProperty = "test"
- element.file = new File('sample.txt')
- }
-
- @Mutate
- void addEchoTask(ModelMap<Task> tasks, AllSupportedUnmanagedTypes element) {
- tasks.create("echo") {
- it.doLast {
- println "boolean: ${element.booleanProperty}"
- println "integer: ${element.integerProperty}"
- println "long: ${element.longProperty}"
- println "double: ${element.doubleProperty}"
- println "big integer: ${element.bigIntegerProperty}"
- println "big decimal: ${element.bigDecimalProperty}"
- println "string: ${element.stringProperty}"
- println "file: ${element.file}"
- }
- }
- }
- }
-
- apply type: RulePlugin
- '''
-
- then:
- succeeds "echo"
-
- and:
- output.contains "boolean: true"
- output.contains "integer: 1"
- output.contains "long: 2"
- output.contains "double: 3.3"
- output.contains "big integer: 4"
- output.contains "big decimal: 5.5"
- output.contains "string: test"
- output.contains "file: sample.txt"
- }
-
- def "can specify managed models with file types"() {
- when:
- buildScript '''
- @Managed
- interface FileContainer {
- File getFile()
- void setFile(File file)
- }
-
- model {
- gradleFileContainer(FileContainer) {
- file = file('sample.txt')
- }
-
- jdkFileContainer(FileContainer) {
- file = new File('sample.txt')
- }
- }
- '''
-
- then:
- succeeds "model"
- }
-}
diff --git a/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ScalarTypesInManagedModelIntegrationTest.groovy b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ScalarTypesInManagedModelIntegrationTest.groovy
new file mode 100644
index 0000000..2647062
--- /dev/null
+++ b/subprojects/model-core/src/integTest/groovy/org/gradle/model/managed/ScalarTypesInManagedModelIntegrationTest.groovy
@@ -0,0 +1,570 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.managed
+import org.gradle.api.artifacts.Configuration
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+class ScalarTypesInManagedModelIntegrationTest extends AbstractIntegrationSpec {
+
+ def "values of primitive types and boxed primitive types are widened as usual when using groovy"() {
+ when:
+ buildScript '''
+ @Managed
+ interface PrimitiveTypes {
+ Long getLongPropertyFromInt()
+ void setLongPropertyFromInt(Long value)
+
+ Long getLongPropertyFromInteger()
+ void setLongPropertyFromInteger(Long value)
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void createPrimitiveTypes(PrimitiveTypes primitiveTypes) {
+ primitiveTypes.longPropertyFromInt = 123
+ primitiveTypes.longPropertyFromInteger = new Integer(321)
+ }
+
+ @Mutate
+ void addCheckTask(ModelMap<Task> tasks, final PrimitiveTypes primitiveTypes) {
+ tasks.create("check") {
+ it.doLast {
+ assert primitiveTypes.longPropertyFromInt == 123
+ assert primitiveTypes.longPropertyFromInteger == 321
+ }
+ }
+ }
+ }
+
+ apply type: RulePlugin
+ '''
+
+ then:
+ succeeds "check"
+
+ }
+
+ def "mismatched types error in managed type are propagated to the user"() {
+ when:
+ buildScript '''
+ @Managed
+ interface PrimitiveTypes {
+ Long getLongProperty()
+ void setLongProperty(long value)
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void createPrimitiveTypes(PrimitiveTypes primitiveTypes) {
+ primitiveTypes.longProperty = 123L
+ }
+ }
+
+ apply type: RulePlugin
+ '''
+
+ then:
+ fails "modelReport"
+
+ and:
+ failure.assertHasCause('Invalid managed model type PrimitiveTypes: setter method param must be of exactly the same type as the getter returns (expected: java.lang.Long, found: long) (invalid method: void PrimitiveTypes#setLongProperty(long))')
+ }
+
+ def "values of primitive types are boxed as usual when using java"() {
+ when:
+ file('buildSrc/src/main/java/Rules.java') << '''
+ import org.gradle.api.*;
+ import org.gradle.model.*;
+
+ @Managed
+ interface PrimitiveProperty {
+ Long getLongProperty();
+ void setLongProperty(Long value);
+ Integer getIntegerProperty();
+ void setIntegerProperty(Integer value);
+ Boolean getBooleanProperty();
+ void setBooleanProperty(Boolean value);
+ Character getCharacterProperty();
+ void setCharacterProperty(Character value);
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void createPrimitiveProperty(PrimitiveProperty primitiveProperty) {
+ primitiveProperty.setLongProperty(123l);
+ primitiveProperty.setIntegerProperty(456);
+ primitiveProperty.setBooleanProperty(true);
+ primitiveProperty.setCharacterProperty('a');
+ }
+
+ @Mutate
+ void addCheckTask(ModelMap<Task> tasks, final PrimitiveProperty primitiveProperty) {
+ tasks.create("check", new Action<Task>() {
+ public void execute(Task task) {
+ task.doLast(new Action<Task>() {
+ public void execute(Task unused) {
+ assert primitiveProperty.getLongProperty() == 123L;
+ assert primitiveProperty.getIntegerProperty() == 456;
+ assert primitiveProperty.getBooleanProperty() == true;
+ assert primitiveProperty.getCharacterProperty() == 'a';
+ }
+ });
+ }
+ });
+ }
+ }
+ '''
+
+ buildScript '''
+ apply type: RulePlugin
+ '''
+
+ then:
+ succeeds "check"
+ }
+
+ def "can set/get properties of all supported unmanaged types using Groovy"() {
+ when:
+ buildScript '''
+ @Managed
+ interface AllSupportedUnmanagedTypes {
+ Boolean getBooleanProperty()
+ void setBooleanProperty(Boolean value)
+
+ Integer getIntegerProperty()
+ void setIntegerProperty(Integer value)
+
+ Long getLongProperty()
+ void setLongProperty(Long value)
+
+ Double getDoubleProperty()
+ void setDoubleProperty(Double value)
+
+ BigInteger getBigIntegerProperty()
+ void setBigIntegerProperty(BigInteger value)
+
+ BigDecimal getBigDecimalProperty()
+ void setBigDecimalProperty(BigDecimal value)
+
+ String getStringProperty()
+ void setStringProperty(String value)
+
+ File getFile()
+ void setFile(File file)
+
+ boolean isFlag()
+ void setFlag(boolean flag)
+
+ boolean getOtherFlag()
+ void setOtherFlag(boolean flag)
+
+ boolean isThirdFlag()
+ boolean getThirdFlag()
+ void setThirdFlag(boolean flag)
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void supportedUnmanagedTypes(AllSupportedUnmanagedTypes element) {
+ element.booleanProperty = Boolean.TRUE
+ element.integerProperty = Integer.valueOf(1)
+ element.longProperty = Long.valueOf(2L)
+ element.doubleProperty = Double.valueOf(3.3)
+ element.bigIntegerProperty = new BigInteger("4")
+ element.bigDecimalProperty = new BigDecimal("5.5")
+ element.stringProperty = "test"
+ element.file = new File('sample.txt')
+ element.flag = true
+ element.otherFlag = true
+ element.thirdFlag = true
+ }
+
+ @Mutate
+ void addCheckTask(ModelMap<Task> tasks, AllSupportedUnmanagedTypes element) {
+ tasks.create("check") {
+ it.doLast {
+ assert element.booleanProperty.is(Boolean.TRUE)
+ assert element.integerProperty == 1
+ assert element.longProperty == 2L
+ assert element.doubleProperty == 3.3d
+ assert element.bigIntegerProperty == 4G
+ assert element.bigDecimalProperty == 5.5G
+ assert element.stringProperty == 'test'
+ assert element.file.toString() == 'sample.txt'
+ assert element.flag == true
+ assert element.otherFlag == true
+ assert element.getOtherFlag() == true
+ assert element.thirdFlag == true
+ assert element.isThirdFlag() == true
+ assert element.getThirdFlag() == true
+ }
+ }
+ }
+ }
+
+ apply type: RulePlugin
+ '''
+
+ then:
+ succeeds "check"
+ }
+
+ def "can set/get properties of all supported unmanaged types using Java"() {
+ given:
+ file('buildSrc/src/main/java/Rules.java') << '''
+ import org.gradle.api.*;
+ import org.gradle.model.*;
+ import java.math.BigInteger;
+ import java.math.BigDecimal;
+ import java.io.File;
+
+ @Managed
+ interface AllSupportedUnmanagedTypes {
+ Boolean getBooleanProperty();
+ void setBooleanProperty(Boolean value);
+
+ Integer getIntegerProperty();
+ void setIntegerProperty(Integer value);
+
+ Long getLongProperty();
+ void setLongProperty(Long value);
+
+ Double getDoubleProperty();
+ void setDoubleProperty(Double value);
+
+ BigInteger getBigIntegerProperty();
+ void setBigIntegerProperty(BigInteger value);
+
+ BigDecimal getBigDecimalProperty();
+ void setBigDecimalProperty(BigDecimal value);
+
+ String getStringProperty();
+ void setStringProperty(String value);
+
+ File getFile();
+ void setFile(File file);
+
+ boolean isFlag();
+ void setFlag(boolean flag);
+
+ boolean getOtherFlag();
+ void setOtherFlag(boolean flag);
+
+ boolean isThirdFlag();
+ boolean getThirdFlag();
+ void setThirdFlag(boolean flag);
+
+ };
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void supportedUnmanagedTypes(AllSupportedUnmanagedTypes element) {
+ element.setBooleanProperty(Boolean.TRUE);
+ element.setIntegerProperty(Integer.valueOf(1));
+ element.setLongProperty(Long.valueOf(2L));
+ element.setDoubleProperty(Double.valueOf(3.3d));
+ element.setBigIntegerProperty(new BigInteger("4"));
+ element.setBigDecimalProperty(new BigDecimal("5.5"));
+ element.setStringProperty("test");
+ element.setFile(new File("sample.txt"));
+ element.setFlag(true);
+ element.setOtherFlag(true);
+ element.setThirdFlag(true);
+ }
+
+ @Mutate
+ void addCheckTask(ModelMap<Task> tasks, final AllSupportedUnmanagedTypes element) {
+ tasks.create("check", new Action<Task>() {
+ public void execute(Task task) {
+ task.doLast(new Action<Task>() {
+ public void execute(Task unused) {
+ assert element.getBooleanProperty() == Boolean.TRUE;
+ assert element.getIntegerProperty() == 1;
+ assert element.getLongProperty() == 2L;
+ assert element.getDoubleProperty() == 3.3d;
+ assert new BigInteger("4").equals(element.getBigIntegerProperty());
+ assert new BigDecimal("5.5").equals(element.getBigDecimalProperty());
+ assert element.getStringProperty().equals("test");
+ assert "sample.txt".equals(element.getFile().toString());
+ assert element.isFlag() == true;
+ assert element.getOtherFlag() == true;
+ assert element.isThirdFlag() == true;
+ assert element.getThirdFlag() == true;
+ }
+ });
+ }
+ });
+ }
+ }
+
+ '''
+
+ when:
+ buildScript '''
+ apply type: RulePlugin
+ '''
+
+ then:
+ succeeds "check"
+ }
+
+ def "can specify managed models with file types"() {
+ when:
+ buildScript '''
+ @Managed
+ interface FileContainer {
+ File getFile()
+ void setFile(File file)
+ }
+
+ model {
+ gradleFileContainer(FileContainer) {
+ file = file('sample.txt')
+ }
+
+ jdkFileContainer(FileContainer) {
+ file = new File('sample.txt')
+ }
+ }
+ '''
+
+ then:
+ succeeds "model"
+ }
+
+ def "can read and write to managed property of scalar type when using Groovy"() {
+ given:
+ def i = 0
+ def properties = [[byte, "123"],
+ [Byte, "123"],
+ [boolean, "false"],
+ [Boolean, "false"],
+ [boolean, "true"],
+ [Boolean, "true"],
+ [char, "'c'"],
+ [Character, "'c'"],
+ [float, "123.45f"],
+ [Float, "123.45f"],
+ [long, "123L"],
+ [Long, "123L"],
+ [short, "123"],
+ [Short, "123"],
+ [int, "123"],
+ [Integer, "123"],
+ [double, "123.456d"],
+ [Double, "123.456d"],
+ [String, '"Mogette"'],
+ [BigDecimal, '999G'],
+ [BigInteger, '777G'],
+ [Configuration.State, 'org.gradle.api.artifacts.Configuration.State.UNRESOLVED'],
+ [File, 'new File("foo")']].collect { propertyDef ->
+ def (type, value) = propertyDef
+ def propName = type.primitive ? "primitive${type.name.capitalize()}${i++}" : "boxed${type.simpleName}${i++}"
+ [dsl : """${type.canonicalName} get${propName.capitalize()}()
+ void set${propName.capitalize()}(${type.canonicalName} value)
+""",
+ assignment: "p.$propName=$value",
+ check : "assert p.$propName == $value"]
+ }
+
+ buildScript """
+ import org.gradle.api.artifacts.Configuration.State
+
+ @Managed
+ interface ManagedType {
+ ${properties.dsl.join('\n')}
+ }
+
+ class PluginRules extends RuleSource {
+ @Model
+ void createModel(ManagedType p) {
+ ${properties.assignment.join('\n')}
+ }
+
+ @Mutate
+ void addCheckTask(ModelMap<Task> tasks, ManagedType p) {
+ tasks.create("check") {
+ it.doLast {
+ ${properties.check.join('\n')}
+ }
+ }
+ }
+ }
+
+ apply plugin: PluginRules
+
+ """
+
+ expect:
+ succeeds 'check'
+
+ }
+
+ def "can read and write to managed property of scalar type when using Java"() {
+ given:
+ def i = 0
+ def properties = [[byte, "(byte) 123"],
+ [Byte, "(byte) 123"],
+ [boolean, "false"],
+ [Boolean, "false"],
+ [boolean, "true"],
+ [Boolean, "true"],
+ [char, "'c'"],
+ [Character, "'c'"],
+ [float, "123.45f"],
+ [Float, "123.45f"],
+ [long, "123L"],
+ [Long, "123L"],
+ [short, "(short) 123"],
+ [Short, "(short) 123"],
+ [int, "123"],
+ [Integer, "123"],
+ [double, "123.456d"],
+ [Double, "123.456d"],
+ [String, '"Mogette"'],
+ [BigDecimal, 'new BigDecimal(999)'],
+ [BigInteger, 'new BigInteger("777")'],
+ [Configuration.State, 'org.gradle.api.artifacts.Configuration.State.UNRESOLVED'],
+ [File, 'new File("foo")']].collect { propertyDef ->
+ def (type, value) = propertyDef
+ def propName = type.primitive ? "primitive${type.name.capitalize()}${i++}" : "boxed${type.simpleName}${i++}"
+ [dsl : """${type.canonicalName} get${propName.capitalize()}();
+ void set${propName.capitalize()}(${type.canonicalName} value);
+""",
+ assignment: "p.set${propName.capitalize()}($value);",
+ check : (type.primitive?"assert p.get${propName.capitalize()}() == $value":"assert p.get${propName.capitalize()}().equals($value)") + ":\"$propName validation failed\";"
+ ]
+ }
+
+ file('buildSrc/src/main/java/Rules.java') << """
+ import org.gradle.api.*;
+ import org.gradle.model.*;
+ import java.math.BigDecimal;
+ import java.math.BigInteger;
+ import java.io.File;
+ import org.gradle.api.artifacts.Configuration.State;
+
+ @Managed
+ interface ManagedType {
+ ${properties.dsl.join('\n')}
+ }
+
+ class RulePlugin extends RuleSource {
+ @Model
+ void createModel(ManagedType p) {
+ ${properties.assignment.join('\n')}
+ }
+
+ @Mutate
+ void addCheckTask(ModelMap<Task> tasks, final ManagedType p) {
+ tasks.create("check", new Action<Task>() {
+ public void execute(Task task) {
+ task.doLast(new Action<Task>() {
+ public void execute(Task unused) {
+ ${properties.check.join('\n')}
+ }
+ });
+ }
+ });
+ }
+ }
+ """
+
+ buildScript '''
+ apply type: RulePlugin
+ '''
+
+ expect:
+ succeeds 'check'
+
+ }
+
+ def "cannot mutate managed property of scalar type when view is immutable"() {
+ given:
+ def i = 0
+ def datatable = [[byte, "123"],
+ [Byte, "123"],
+ [boolean, "false"],
+ [Boolean, "false"],
+ [boolean, "true"],
+ [Boolean, "true"],
+ [char, "'c'"],
+ [Character, "'c'"],
+ [float, "123.45f"],
+ [Float, "123.45f"],
+ [long, "123L"],
+ [Long, "123L"],
+ [short, "123"],
+ [Short, "123"],
+ [int, "123"],
+ [Integer, "123"],
+ [double, "123.456d"],
+ [Double, "123.456d"],
+ [String, '"Mogette"'],
+ [BigDecimal, '999G'],
+ [BigInteger, '777G'],
+ [Configuration.State, 'org.gradle.api.artifacts.Configuration.State.UNRESOLVED'],
+ [File, 'new File("foo")']]
+ def properties = datatable.collect { propertyDef ->
+ def (type, value) = propertyDef
+ def propName = type.primitive ? "primitive${type.name.capitalize()}${i++}" : "boxed${type.simpleName}${i++}"
+ [dsl : """${type.canonicalName} get${propName.capitalize()}()
+ void set${propName.capitalize()}(${type.canonicalName} value)
+""",
+ check: """
+ tasks.create("check${propName.capitalize()}") {
+ it.doLast {
+ p.$propName=$value
+ }
+ }"""]
+ }
+
+ buildScript """
+ import org.gradle.api.artifacts.Configuration.State
+
+ @Managed
+ interface ManagedType {
+ ${properties.dsl.join('\n')}
+ }
+
+ class PluginRules extends RuleSource {
+ @Model
+ void createModel(ManagedType p) {
+ }
+
+ @Mutate
+ void addCheckTask(ModelMap<Task> tasks, ManagedType p) {
+ ${properties.check.join('\n')}
+ }
+ }
+
+ apply plugin: PluginRules
+
+ """
+ i=0
+
+ expect:
+ datatable.each { propertyDef ->
+ def (type, value) = propertyDef
+ def propName = type.primitive ? "primitive${type.name.capitalize()}${i++}" : "boxed${type.simpleName}${i++}"
+ fails "check${propName.capitalize()}"
+ failure.assertHasCause(/Attempt to mutate closed view of model of type 'ManagedType' given to rule 'PluginRules#addCheckTask'/)
+ }
+
+ }
+
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/Managed.java b/subprojects/model-core/src/main/java/org/gradle/model/Managed.java
index 69227ec..687c6c8 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/Managed.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/Managed.java
@@ -46,6 +46,13 @@ import java.lang.annotation.Target;
* A getter and setter must be declared for each property that is not of a managed type or of {@link ModelSet}.
* For properties of managed types or of {@link ModelSet} the getter is mandatory and the setter is optional.
* If no setter is provided the property is considered inherent and defaults to an "empty" instance of the type.
+ * In addition to the traditional getter method, properties of type <pre>boolean</pre> also support a getter
+ * method which name starts with <pre>is</pre>:
+ *
+ * <pre>
+ * void setEnabled(boolean enabled);
+ * boolean isEnabed();
+ * </pre>
*
* <h4>Supported property types</h4>
* <p>
@@ -54,15 +61,18 @@ import java.lang.annotation.Target;
* <li>{@link String}</li>
* <li>{@link Boolean}</li>
* <li>{@link Character}</li>
+ * <li>{@link Byte}</li>
+ * <li>{@link Short}</li>
* <li>{@link Integer}</li>
* <li>{@link Long}</li>
+ * <li>{@link Float}</li>
* <li>{@link Double}</li>
* <li>{@link java.math.BigInteger}</li>
* <li>{@link java.math.BigDecimal}</li>
* <li>{@link java.io.File}</li>
* </ul>
* <p>
- * All {@link Enum} types are also allowed.
+ * All primitive types and {@link Enum} types are also allowed.
* <p>
* Properties that are themselves of a managed type are also supported.
* <p>
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/ModelMap.java b/subprojects/model-core/src/main/java/org/gradle/model/ModelMap.java
index 90cd7f9..406e015 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/ModelMap.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/ModelMap.java
@@ -34,7 +34,7 @@ import java.util.Set;
*/
@SuppressWarnings("deprecation")
@Incubating
-public interface ModelMap<T> extends CollectionBuilder<T> {
+public interface ModelMap<T> extends CollectionBuilder<T>, Iterable<T> {
/**
* {@inheritDoc}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/collection/internal/ModelMapModelProjection.java b/subprojects/model-core/src/main/java/org/gradle/model/collection/internal/ModelMapModelProjection.java
index 3fb0875..5403716 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/collection/internal/ModelMapModelProjection.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/collection/internal/ModelMapModelProjection.java
@@ -42,25 +42,25 @@ public class ModelMapModelProjection<I> implements ModelProjection {
@SuppressWarnings("deprecation")
private final static Set<Class<?>> SUPPORTED_CONTAINER_TYPES = ImmutableSet.<Class<?>>of(ModelMap.class, CollectionBuilder.class);
- public static <T> ModelProjection unmanaged(ModelType<T> itemType, ChildNodeCreatorStrategy<? super T> creatorStrategy) {
+ public static <T> ModelProjection unmanaged(ModelType<T> itemType, ChildNodeInitializerStrategy<? super T> creatorStrategy) {
return new ModelMapModelProjection<T>(itemType, false, false, creatorStrategy);
}
- public static <T> ModelProjection unmanaged(Class<T> itemType, ChildNodeCreatorStrategy<? super T> creatorStrategy) {
+ public static <T> ModelProjection unmanaged(Class<T> itemType, ChildNodeInitializerStrategy<? super T> creatorStrategy) {
return unmanaged(ModelType.of(itemType), creatorStrategy);
}
- public static <T> ModelProjection managed(ModelType<T> itemType, ChildNodeCreatorStrategy<? super T> creatorStrategy) {
+ public static <T> ModelProjection managed(ModelType<T> itemType, ChildNodeInitializerStrategy<? super T> creatorStrategy) {
return new ModelMapModelProjection<T>(itemType, false, true, creatorStrategy);
}
protected final Class<I> baseItemType;
protected final ModelType<I> baseItemModelType;
private final boolean eager;
- private final ChildNodeCreatorStrategy<? super I> creatorStrategy;
+ private final ChildNodeInitializerStrategy<? super I> creatorStrategy;
private final boolean managed;
- protected ModelMapModelProjection(ModelType<I> baseItemModelType, boolean eager, boolean managed, ChildNodeCreatorStrategy<? super I> creatorStrategy) {
+ protected ModelMapModelProjection(ModelType<I> baseItemModelType, boolean eager, boolean managed, ChildNodeInitializerStrategy<? super I> creatorStrategy) {
this.baseItemModelType = baseItemModelType;
this.eager = eager;
this.managed = managed;
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ChildNodeCreatorStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ChildNodeCreatorStrategy.java
deleted file mode 100644
index 124cd27..0000000
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ChildNodeCreatorStrategy.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.internal.core;
-
-import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
-import org.gradle.model.internal.type.ModelType;
-
-public interface ChildNodeCreatorStrategy<T> {
-
- // Node must project item as S
- <S extends T> ModelCreator creator(MutableModelNode parentNode, ModelRuleDescriptor sourceDescriptor, ModelType<S> type, String name);
-
-}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ChildNodeInitializerStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ChildNodeInitializerStrategy.java
new file mode 100644
index 0000000..94f0e6f
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ChildNodeInitializerStrategy.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.core;
+
+import org.gradle.model.internal.type.ModelType;
+
+public interface ChildNodeInitializerStrategy<T> {
+
+ // Node must project item as S
+ <S extends T> NodeInitializer initializer(ModelType<S> type);
+
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/EmptyModelProjection.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/EmptyModelProjection.java
index c0bdce5..ac8df27 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/EmptyModelProjection.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/EmptyModelProjection.java
@@ -67,4 +67,5 @@ public class EmptyModelProjection implements ModelProjection {
public Optional<String> getValueDescription(MutableModelNode modelNodeInternal) {
return Optional.absent();
}
+
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/FactoryBasedNodeInitializer.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/FactoryBasedNodeInitializer.java
new file mode 100644
index 0000000..35625b3
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/FactoryBasedNodeInitializer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.core;
+
+import org.gradle.internal.Cast;
+import org.gradle.model.internal.type.ModelType;
+
+import java.util.Collections;
+import java.util.List;
+
+public class FactoryBasedNodeInitializer<T, S extends T> implements NodeInitializer {
+ private final ModelReference<? extends InstanceFactory<? super T, String>> factoryReference;
+ private final ModelType<S> type;
+
+ public FactoryBasedNodeInitializer(ModelReference<? extends InstanceFactory<? super T, String>> factoryReference, ModelType<S> type) {
+ this.factoryReference = factoryReference;
+ this.type = type;
+ }
+
+ @Override
+ public List<? extends ModelReference<?>> getInputs() {
+ return Collections.singletonList(factoryReference);
+ }
+
+ @Override
+ public void execute(MutableModelNode modelNode, List<ModelView<?>> inputs) {
+ InstanceFactory<? super T, String> instantiator = Cast.uncheckedCast(inputs.get(0).getInstance());
+ S item = instantiator.create(type.getConcreteClass(), modelNode, modelNode.getPath().getName());
+ modelNode.setPrivateData(type, item);
+ }
+
+ @Override
+ public List<? extends ModelProjection> getProjections() {
+ return Collections.singletonList(UnmanagedModelProjection.of(type));
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelAdapter.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelAdapter.java
index a69756b..5f79eb1 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelAdapter.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelAdapter.java
@@ -35,5 +35,5 @@ public interface ModelAdapter {
// must implement logical equality
boolean equals(Object other);
- Optional<String> getValueDescription(MutableModelNode modelNodeInternal);
+ Optional<String> getValueDescription(MutableModelNode mutableModelNode);
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreator.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreator.java
index cd4432c..20187cb 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreator.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreator.java
@@ -33,5 +33,5 @@ public interface ModelCreator extends ModelRule {
boolean isEphemeral();
- List<ModelReference<?>> getInputs();
+ List<? extends ModelReference<?>> getInputs();
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreatorFactory.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreatorFactory.java
deleted file mode 100644
index 017c811..0000000
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreatorFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.internal.core;
-
-import org.gradle.api.Action;
-import org.gradle.internal.BiAction;
-import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
-import org.gradle.model.internal.manage.schema.ModelSchema;
-
-import java.util.List;
-
-public interface ModelCreatorFactory {
- <T> ModelCreator creator(ModelRuleDescriptor descriptor,
- ModelPath path,
- ModelSchema<T> schema,
- Action<? super T> initializer);
-
- <T> ModelCreator creator(ModelRuleDescriptor descriptor,
- ModelPath path,
- ModelSchema<T> schema,
- List<ModelReference<?>> initializerInputs,
- BiAction<? super T, ? super List<ModelView<?>>> initializer);
-
- <T> ModelCreator creator(ModelRuleDescriptor descriptor,
- ModelPath path,
- ModelSchema<T> schema);
-}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreators.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreators.java
index 962bc6d..7210371 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreators.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelCreators.java
@@ -68,6 +68,17 @@ abstract public class ModelCreators {
return new Builder(path, BiActions.doNothing());
}
+ public static Builder of(ModelPath path, final NodeInitializer initializer) {
+ return of(path, new BiAction<MutableModelNode, List<ModelView<?>>>() {
+ @Override
+ public void execute(MutableModelNode modelNode, List<ModelView<?>> views) {
+ initializer.execute(modelNode, views);
+ }
+ })
+ .inputs(initializer.getInputs())
+ .withProjections(initializer.getProjections());
+ }
+
public static Builder of(ModelPath path, BiAction<? super MutableModelNode, ? super List<ModelView<?>>> initializer) {
return new Builder(path, initializer);
}
@@ -96,7 +107,7 @@ abstract public class ModelCreators {
private boolean hidden;
private ModelRuleDescriptor modelRuleDescriptor;
- private List<ModelReference<?>> inputs = Collections.emptyList();
+ private List<? extends ModelReference<?>> inputs = Collections.emptyList();
private Builder(ModelPath path, BiAction<? super MutableModelNode, ? super List<ModelView<?>>> initializer) {
this.path = path;
@@ -128,7 +139,7 @@ abstract public class ModelCreators {
return this;
}
- public Builder inputs(List<ModelReference<?>> inputs) {
+ public Builder inputs(List<? extends ModelReference<?>> inputs) {
this.inputs = inputs;
return this;
}
@@ -171,6 +182,13 @@ abstract public class ModelCreators {
}
return new ProjectionBackedModelCreator(path, modelRuleDescriptor, ephemeral, hidden, inputs, projection, effectiveInitializer);
}
+
+ public Builder withProjections(Iterable<? extends ModelProjection> projections) {
+ for (ModelProjection projection : projections) {
+ withProjection(projection);
+ }
+ return this;
+ }
}
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelMapGroovyDecorator.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelMapGroovyDecorator.java
index 9413611..f41e516 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelMapGroovyDecorator.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelMapGroovyDecorator.java
@@ -27,6 +27,7 @@ import org.gradle.model.ModelMap;
import org.gradle.model.RuleSource;
import java.util.Collection;
+import java.util.Iterator;
import java.util.Set;
import static org.gradle.internal.Cast.uncheckedCast;
@@ -164,6 +165,11 @@ public class ModelMapGroovyDecorator<I> extends GroovyObjectSupport implements M
return delegate.values();
}
+ @Override
+ public Iterator<I> iterator() {
+ return delegate.iterator();
+ }
+
// TODO - mix this in and validate closure parameters
public void create(String name, Closure<? super I> configAction) {
create(name, new ClosureBackedAction<I>(configAction));
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelNode.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelNode.java
index 4c9581a..f88ff99 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelNode.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ModelNode.java
@@ -21,6 +21,7 @@ import org.gradle.api.Nullable;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.type.ModelType;
+import java.util.List;
import java.util.Set;
public interface ModelNode {
@@ -88,4 +89,22 @@ public interface ModelNode {
* Calling this method may create or transition the node.
*/
Optional<String> getValueDescription();
+
+ /**
+ * Gets the underlying type of this node.
+ * <p>
+ * Calling this method may create or transition the node.
+ * <p>
+ * In practice, this describes the type that you would get if you asked for this node as Object, read only.
+ * This is used in the model report.
+ * In the future we may need a more sophisticated (e.g. multi-type aware, visibility aware) mechanism for advertising the type.
+ * <p>
+ * If an absent is returned, this node can not be viewed as an object.
+ */
+ Optional<String> getTypeDescription();
+
+ /**
+ * Gets the rules that have been executed on this node in the order in which they were executed.
+ */
+ List<ModelRuleDescriptor> getExecutedRules();
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/MutableModelNode.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/MutableModelNode.java
index 2f8e6c6..d6202d9 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/MutableModelNode.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/MutableModelNode.java
@@ -121,9 +121,6 @@ public interface MutableModelNode extends ModelNode {
Object getPrivateData();
- @Nullable
- MutableModelNode getTarget();
-
void setTarget(ModelNode target);
/**
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelMap.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelMap.java
index 1b113e0..9235923 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelMap.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelMap.java
@@ -18,23 +18,23 @@ package org.gradle.model.internal.core;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import org.gradle.api.Action;
import org.gradle.api.Nullable;
import org.gradle.api.Transformer;
import org.gradle.internal.Actions;
-import org.gradle.internal.BiAction;
-import org.gradle.internal.Cast;
import org.gradle.model.ModelMap;
import org.gradle.model.RuleSource;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.core.rule.describe.NestedModelRuleDescriptor;
import org.gradle.model.internal.manage.instance.ManagedInstance;
+import org.gradle.model.internal.manage.schema.ManagedImplModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.type.ModelType;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
import static org.gradle.internal.Cast.uncheckedCast;
@@ -46,9 +46,9 @@ public class NodeBackedModelMap<T> implements ModelMap<T>, ManagedInstance {
private final String description;
private final boolean eager;
private final ModelViewState viewState;
- private final ChildNodeCreatorStrategy<? super T> creatorStrategy;
+ private final ChildNodeInitializerStrategy<? super T> creatorStrategy;
- public NodeBackedModelMap(String description, ModelType<T> elementType, ModelRuleDescriptor sourceDescriptor, MutableModelNode modelNode, boolean eager, ModelViewState viewState, ChildNodeCreatorStrategy<? super T> creatorStrategy) {
+ public NodeBackedModelMap(String description, ModelType<T> elementType, ModelRuleDescriptor sourceDescriptor, MutableModelNode modelNode, boolean eager, ModelViewState viewState, ChildNodeInitializerStrategy<? super T> creatorStrategy) {
this.description = description;
this.eager = eager;
this.viewState = viewState;
@@ -58,11 +58,11 @@ public class NodeBackedModelMap<T> implements ModelMap<T>, ManagedInstance {
this.sourceDescriptor = sourceDescriptor;
}
- public NodeBackedModelMap(ModelType<T> type, ModelRuleDescriptor sourceDescriptor, MutableModelNode modelNode, boolean eager, ModelViewState viewState, ChildNodeCreatorStrategy<? super T> childNodeCreatorStrategy) {
- this(derivedDescription(modelNode, type), type, sourceDescriptor, modelNode, eager, viewState, childNodeCreatorStrategy);
+ public NodeBackedModelMap(ModelType<T> type, ModelRuleDescriptor sourceDescriptor, MutableModelNode modelNode, boolean eager, ModelViewState viewState, ChildNodeInitializerStrategy<? super T> childStrategy) {
+ this(derivedDescription(modelNode, type), type, sourceDescriptor, modelNode, eager, viewState, childStrategy);
}
- public static <T> ChildNodeCreatorStrategy<T> createUsingParentNode(final ModelType<T> baseItemModelType) {
+ public static <T> ChildNodeInitializerStrategy<T> createUsingParentNode(final ModelType<T> baseItemModelType) {
return createUsingParentNode(new Transformer<NamedEntityInstantiator<T>, MutableModelNode>() {
@Override
public NamedEntityInstantiator<T> transform(MutableModelNode modelNode) {
@@ -71,43 +71,51 @@ public class NodeBackedModelMap<T> implements ModelMap<T>, ManagedInstance {
});
}
- public static <T> ChildNodeCreatorStrategy<T> createUsingParentNode(final Transformer<? extends NamedEntityInstantiator<T>, ? super MutableModelNode> instantiatorTransform) {
- return new ChildNodeCreatorStrategy<T>() {
+ public static <T> ChildNodeInitializerStrategy<T> createUsingParentNode(final Transformer<? extends NamedEntityInstantiator<T>, ? super MutableModelNode> instantiatorTransform) {
+ return new ChildNodeInitializerStrategy<T>() {
@Override
- public <S extends T> ModelCreator creator(final MutableModelNode parentNode, ModelRuleDescriptor sourceDescriptor, final ModelType<S> type, final String name) {
- return ModelCreators.of(
- parentNode.getPath().child(name), new BiAction<MutableModelNode, List<ModelView<?>>>() {
- @Override
- public void execute(MutableModelNode modelNode, List<ModelView<?>> modelViews) {
- NamedEntityInstantiator<T> instantiator = instantiatorTransform.transform(parentNode);
- S item = instantiator.create(name, type.getConcreteClass());
- modelNode.setPrivateData(type, item);
- }
- })
- .withProjection(UnmanagedModelProjection.of(type))
- .descriptor(NestedModelRuleDescriptor.append(sourceDescriptor, "create(%s)", name))
- .build();
+ public <S extends T> NodeInitializer initializer(final ModelType<S> type) {
+ return new NodeInitializer() {
+ @Override
+ public List<? extends ModelReference<?>> getInputs() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void execute(MutableModelNode modelNode, List<ModelView<?>> inputs) {
+ NamedEntityInstantiator<T> instantiator = instantiatorTransform.transform(modelNode.getParent());
+ S item = instantiator.create(modelNode.getPath().getName(), type.getConcreteClass());
+ modelNode.setPrivateData(type, item);
+ }
+
+ @Override
+ public List<? extends ModelProjection> getProjections() {
+ return Collections.singletonList(UnmanagedModelProjection.of(type));
+ }
+ };
}
};
}
- public static <T> ChildNodeCreatorStrategy<T> createUsingFactory(final ModelReference<? extends InstanceFactory<? super T, String>> factoryReference) {
- return new ChildNodeCreatorStrategy<T>() {
+ public static <T> ChildNodeInitializerStrategy<T> createUsingFactory(final ModelReference<? extends InstanceFactory<? super T, String>> factoryReference) {
+ return new ChildNodeInitializerStrategy<T>() {
@Override
- public <S extends T> ModelCreator creator(final MutableModelNode parentNode, ModelRuleDescriptor sourceDescriptor, final ModelType<S> type, final String name) {
- return ModelCreators.of(
- parentNode.getPath().child(name), new BiAction<MutableModelNode, List<ModelView<?>>>() {
- @Override
- public void execute(MutableModelNode modelNode, List<ModelView<?>> modelViews) {
- InstanceFactory<? super T, String> instantiator = Cast.uncheckedCast(modelViews.get(0).getInstance());
- S item = instantiator.create(type.getConcreteClass(), modelNode, name);
- modelNode.setPrivateData(type, item);
- }
- })
- .inputs(factoryReference)
- .withProjection(UnmanagedModelProjection.of(type))
- .descriptor(NestedModelRuleDescriptor.append(sourceDescriptor, "create(%s)", name))
- .build();
+ public <S extends T> NodeInitializer initializer(ModelType<S> type) {
+ return new FactoryBasedNodeInitializer<T, S>(factoryReference, type);
+ }
+ };
+ }
+
+ public static <T> ChildNodeInitializerStrategy<T> createManagedOrUsingFactory(final ModelSchemaStore schemaStore, final ModelReference<? extends InstanceFactory<? super T, String>> factoryReference) {
+ return new ChildNodeInitializerStrategy<T>() {
+ @Override
+ public <S extends T> NodeInitializer initializer(final ModelType<S> type) {
+ ModelSchema<S> schema = schemaStore.getSchema(type);
+ if (schema instanceof ManagedImplModelSchema) {
+ return ((ManagedImplModelSchema<S>) schema).getNodeInitializer();
+ } else {
+ return new FactoryBasedNodeInitializer<T, S>(factoryReference, type);
+ }
}
};
}
@@ -192,10 +200,18 @@ public class NodeBackedModelMap<T> implements ModelMap<T>, ManagedInstance {
private <S extends T> void doCreate(final String name, final ModelType<S> type, final Action<? super S> initAction) {
viewState.assertCanMutate();
- ModelCreator creator = creatorStrategy.creator(modelNode, sourceDescriptor, type, name);
+ ModelPath childPath = modelNode.getPath().child(name);
+ ModelRuleDescriptor descriptor = NestedModelRuleDescriptor.append(sourceDescriptor, "create(%s)", name);
+
+ NodeInitializer nodeInitializer = creatorStrategy.initializer(type);
+
+ ModelCreator creator = ModelCreators.of(childPath, nodeInitializer)
+ .descriptor(descriptor)
+ .action(ModelActionRole.Initialize, NoInputsModelAction.of(ModelReference.of(childPath, type), descriptor, initAction))
+ .build();
+
modelNode.addLink(creator);
- ModelRuleDescriptor descriptor = NestedModelRuleDescriptor.append(sourceDescriptor, "%s.<init>", name);
- modelNode.applyToLink(ModelActionRole.Initialize, NoInputsModelAction.of(ModelReference.of(creator.getPath(), type), descriptor, initAction));
+
if (eager) {
//noinspection ConstantConditions
modelNode.getLink(name).ensureUsable();
@@ -274,7 +290,7 @@ public class NodeBackedModelMap<T> implements ModelMap<T>, ManagedInstance {
}
public <S extends T> ModelMap<S> toSubType(Class<S> type) {
- ChildNodeCreatorStrategy<S> creatorStrategy = uncheckedCast(this.creatorStrategy);
+ ChildNodeInitializerStrategy<S> creatorStrategy = uncheckedCast(this.creatorStrategy);
return new NodeBackedModelMap<S>(ModelType.of(type), sourceDescriptor, modelNode, eager, viewState, creatorStrategy);
}
@@ -290,6 +306,17 @@ public class NodeBackedModelMap<T> implements ModelMap<T>, ManagedInstance {
}
@Override
+ public Iterator<T> iterator() {
+ viewState.assertCanReadChildren();
+ return Iterators.transform(keySet().iterator(), new Function<String, T>() {
+ @Override
+ public T apply(@Nullable String name) {
+ return get(name);
+ }
+ });
+ }
+
+ @Override
public <S> void withType(Class<S> type, Action<? super S> configAction) {
ModelRuleDescriptor descriptor = NestedModelRuleDescriptor.append(sourceDescriptor, "withType()");
ModelReference<S> subject = ModelReference.of(type);
@@ -315,11 +342,12 @@ public class NodeBackedModelMap<T> implements ModelMap<T>, ManagedInstance {
return uncheckedCast(subType);
}
- return new NodeBackedModelMap<S>(ModelType.of(type), sourceDescriptor, modelNode, eager, viewState, new ChildNodeCreatorStrategy<S>() {
+ return new NodeBackedModelMap<S>(ModelType.of(type), sourceDescriptor, modelNode, eager, viewState, new ChildNodeInitializerStrategy<S>() {
@Override
- public <D extends S> ModelCreator creator(MutableModelNode parentNode, ModelRuleDescriptor sourceDescriptor, ModelType<D> type, String name) {
+ public <D extends S> NodeInitializer initializer(ModelType<D> type) {
throw new IllegalArgumentException(String.format("Cannot create an item of type %s as this is not a subtype of %s.", type, elementType.toString()));
}
});
}
+
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelSet.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelSet.java
index 4a1ca5d..f72135b 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelSet.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeBackedModelSet.java
@@ -38,12 +38,12 @@ public class NodeBackedModelSet<T> implements ModelSet<T>, ManagedInstance {
private final ModelRuleDescriptor descriptor;
private final MutableModelNode modelNode;
private final ModelViewState state;
- private final ChildNodeCreatorStrategy<T> creatorStrategy;
+ private final ChildNodeInitializerStrategy<T> creatorStrategy;
private final ModelReference<T> elementTypeReference;
private Collection<T> elements;
- public NodeBackedModelSet(String toString, ModelType<T> elementType, ModelRuleDescriptor descriptor, MutableModelNode modelNode, ModelViewState state, ChildNodeCreatorStrategy<T> creatorStrategy) {
+ public NodeBackedModelSet(String toString, ModelType<T> elementType, ModelRuleDescriptor descriptor, MutableModelNode modelNode, ModelViewState state, ChildNodeInitializerStrategy<T> creatorStrategy) {
this.toString = toString;
this.elementType = elementType;
this.elementTypeReference = ModelReference.of(elementType);
@@ -66,11 +66,18 @@ public class NodeBackedModelSet<T> implements ModelSet<T>, ManagedInstance {
@Override
public void create(final Action<? super T> action) {
state.assertCanMutate();
+
String name = String.valueOf(modelNode.getLinkCount(elementType));
- modelNode.addLink(creatorStrategy.creator(modelNode, descriptor, elementType, name));
- modelNode.applyToLink(ModelActionRole.Initialize, NoInputsModelAction.of(
- ModelReference.of(modelNode.getPath().child(name), elementType), NestedModelRuleDescriptor.append(descriptor, "create()"), action)
- );
+ ModelPath childPath = modelNode.getPath().child(name);
+ final ModelRuleDescriptor descriptor = NestedModelRuleDescriptor.append(this.descriptor, "create()");
+
+ NodeInitializer nodeInitializer = creatorStrategy.initializer(elementType);
+ ModelCreator creator = ModelCreators.of(childPath, nodeInitializer)
+ .descriptor(descriptor)
+ .action(ModelActionRole.Initialize, NoInputsModelAction.of(ModelReference.of(childPath, elementType), descriptor, action))
+ .build();
+
+ modelNode.addLink(creator);
}
@Override
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeInitializer.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeInitializer.java
new file mode 100644
index 0000000..1578643
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/NodeInitializer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.core;
+
+import java.util.List;
+
+/**
+ * A standalone strategy for initializing a node.
+ * <p>
+ * Differs from {@link ModelCreator} in that it's more of a template for a creator.
+ * It does not say anything about the actual entity (e.g. its path) or the identity of the creation rule.
+ *
+ * @see ModelCreators
+ */
+public interface NodeInitializer {
+
+ List<? extends ModelReference<?>> getInputs();
+
+ void execute(MutableModelNode modelNode, List<ModelView<?>> inputs);
+
+ List<? extends ModelProjection> getProjections();
+
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ProjectionBackedModelCreator.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ProjectionBackedModelCreator.java
index c50c125..04a914b 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ProjectionBackedModelCreator.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/ProjectionBackedModelCreator.java
@@ -29,7 +29,7 @@ public class ProjectionBackedModelCreator implements ModelCreator {
private final boolean ephemeral;
private final boolean hidden;
private final ModelProjection projection;
- private final List<ModelReference<?>> inputs;
+ private final List<? extends ModelReference<?>> inputs;
private final BiAction<? super MutableModelNode, ? super List<ModelView<?>>> initializer;
public ProjectionBackedModelCreator(
@@ -37,7 +37,7 @@ public class ProjectionBackedModelCreator implements ModelCreator {
ModelRuleDescriptor descriptor,
boolean ephemeral,
boolean hidden,
- List<ModelReference<?>> inputs,
+ List<? extends ModelReference<?>> inputs,
ModelProjection projection,
BiAction<? super MutableModelNode, ? super List<ModelView<?>>> initializer
) {
@@ -72,7 +72,7 @@ public class ProjectionBackedModelCreator implements ModelCreator {
return ephemeral;
}
- public List<ModelReference<?>> getInputs() {
+ public List<? extends ModelReference<?>> getInputs() {
return inputs;
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/SpecializedModelMapProjection.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/SpecializedModelMapProjection.java
index 41197bc..3261f66 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/SpecializedModelMapProjection.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/SpecializedModelMapProjection.java
@@ -36,9 +36,9 @@ public class SpecializedModelMapProjection<P extends ModelMap<E>, E> implements
private final ModelType<E> elementType;
private final Class<? extends P> viewImpl;
- private final ChildNodeCreatorStrategy<E> creatorStrategy;
+ private final ChildNodeInitializerStrategy<E> creatorStrategy;
- public SpecializedModelMapProjection(ModelType<P> publicType, ModelType<E> elementType, Class<? extends P> viewImpl, ChildNodeCreatorStrategy<E> creatorStrategy) {
+ public SpecializedModelMapProjection(ModelType<P> publicType, ModelType<E> elementType, Class<? extends P> viewImpl, ChildNodeInitializerStrategy<E> creatorStrategy) {
this.publicType = publicType;
this.elementType = elementType;
this.viewImpl = viewImpl;
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/TypeCompatibilityModelProjectionSupport.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/TypeCompatibilityModelProjectionSupport.java
index 6b0ca07..b119fc6 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/TypeCompatibilityModelProjectionSupport.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/TypeCompatibilityModelProjectionSupport.java
@@ -42,11 +42,15 @@ public abstract class TypeCompatibilityModelProjectionSupport<M> implements Mode
}
public <T> boolean canBeViewedAsWritable(ModelType<T> targetType) {
- return canBeViewedAsWritable && targetType.isAssignableFrom(type);
+ return canBeViewedAsWritable && canBeAssignedTo(targetType);
+ }
+
+ private <T> boolean canBeAssignedTo(ModelType<T> targetType) {
+ return targetType.isAssignableFrom(type) || (targetType== ModelType.UNTYPED && type.getRawClass().isPrimitive());
}
public <T> boolean canBeViewedAsReadOnly(ModelType<T> targetType) {
- return canBeViewedAsReadOnly && targetType.isAssignableFrom(type);
+ return canBeViewedAsReadOnly && canBeAssignedTo(targetType);
}
public <T> ModelView<? extends T> asWritable(ModelType<T> type, MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, List<ModelView<?>> inputs) {
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/AbstractModelRuleDescriptor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/AbstractModelRuleDescriptor.java
index 02d3691..7a3c361 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/AbstractModelRuleDescriptor.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/AbstractModelRuleDescriptor.java
@@ -27,5 +27,4 @@ public abstract class AbstractModelRuleDescriptor implements ModelRuleDescriptor
describeTo(sb);
return sb.toString();
}
-
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptor.java
index a697875..a0773a0 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptor.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptor.java
@@ -16,10 +16,10 @@
package org.gradle.model.internal.core.rule.describe;
+import com.google.common.base.Objects;
import net.jcip.annotations.ThreadSafe;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.specs.Spec;
-import org.gradle.internal.reflect.MethodDescription;
import org.gradle.model.internal.method.WeaklyTypeReferencingMethod;
import org.gradle.model.internal.type.ModelType;
import org.gradle.util.CollectionUtils;
@@ -54,15 +54,16 @@ public class MethodModelRuleDescriptor extends AbstractModelRuleDescriptor {
private String getDescription() {
if (description == null) {
- description = MethodDescription.name(method.getName())
- .owner(method.getDeclaringClass())
- .takes(method.getGenericParameterTypes())
- .toString();
+ description = getClassName() + "#" + method.getName();
}
return description;
}
+ private String getClassName() {
+ return ModelType.of(method.getDeclaringClass()).getSimpleName();
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -71,15 +72,13 @@ public class MethodModelRuleDescriptor extends AbstractModelRuleDescriptor {
if (o == null || getClass() != o.getClass()) {
return false;
}
-
MethodModelRuleDescriptor that = (MethodModelRuleDescriptor) o;
-
- return method.equals(that.method);
+ return Objects.equal(method, that.method);
}
@Override
public int hashCode() {
- return method.hashCode();
+ return Objects.hashCode(method);
}
public static ModelRuleDescriptor of(Class<?> clazz, final String methodName) {
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/ModelRuleDescriptor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/ModelRuleDescriptor.java
index cfaa66e..3b3439b 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/ModelRuleDescriptor.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/ModelRuleDescriptor.java
@@ -16,6 +16,10 @@
package org.gradle.model.internal.core.rule.describe;
+/**
+ * Describes a method rule.
+ * All implementations of this class are expected to implement the equals and hashCode method
+ */
public interface ModelRuleDescriptor {
// TODO - expand to include the concept of identity and description
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/NestedModelRuleDescriptor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/NestedModelRuleDescriptor.java
index 68412b8..856ad04 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/NestedModelRuleDescriptor.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/NestedModelRuleDescriptor.java
@@ -16,6 +16,7 @@
package org.gradle.model.internal.core.rule.describe;
+import com.google.common.base.Objects;
import net.jcip.annotations.ThreadSafe;
import org.gradle.api.UncheckedIOException;
@@ -46,6 +47,24 @@ public class NestedModelRuleDescriptor extends AbstractModelRuleDescriptor {
child.describeTo(appendable);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ NestedModelRuleDescriptor that = (NestedModelRuleDescriptor) o;
+ return Objects.equal(parent, that.parent)
+ && Objects.equal(child, that.child);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(parent, child);
+ }
+
public static ModelRuleDescriptor append(ModelRuleDescriptor parent, String str) {
return new NestedModelRuleDescriptor(parent, new SimpleModelRuleDescriptor(str));
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/SimpleModelRuleDescriptor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/SimpleModelRuleDescriptor.java
index 9161720..cf57984 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/SimpleModelRuleDescriptor.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/core/rule/describe/SimpleModelRuleDescriptor.java
@@ -16,6 +16,7 @@
package org.gradle.model.internal.core.rule.describe;
+import com.google.common.base.Objects;
import net.jcip.annotations.ThreadSafe;
import org.gradle.api.UncheckedIOException;
@@ -38,4 +39,20 @@ public class SimpleModelRuleDescriptor extends AbstractModelRuleDescriptor {
}
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SimpleModelRuleDescriptor that = (SimpleModelRuleDescriptor) o;
+ return Objects.equal(descriptor, that.descriptor);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(descriptor);
+ }
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/DefaultModelCreatorFactory.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/DefaultModelCreatorFactory.java
deleted file mode 100644
index 18908e8..0000000
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/DefaultModelCreatorFactory.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.internal.inspect;
-
-import org.gradle.api.Action;
-import org.gradle.api.Named;
-import org.gradle.api.Nullable;
-import org.gradle.internal.BiAction;
-import org.gradle.internal.Cast;
-import org.gradle.model.ModelSet;
-import org.gradle.model.collection.ManagedSet;
-import org.gradle.model.collection.internal.ModelMapModelProjection;
-import org.gradle.model.internal.core.*;
-import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
-import org.gradle.model.internal.core.rule.describe.NestedModelRuleDescriptor;
-import org.gradle.model.internal.manage.instance.ManagedProxyFactory;
-import org.gradle.model.internal.manage.projection.ManagedModelProjection;
-import org.gradle.model.internal.manage.schema.ModelCollectionSchema;
-import org.gradle.model.internal.manage.schema.ModelSchema;
-import org.gradle.model.internal.manage.schema.ModelSchemaStore;
-import org.gradle.model.internal.manage.schema.ModelStructSchema;
-import org.gradle.model.internal.type.ModelType;
-import org.gradle.model.internal.type.ModelTypes;
-
-import java.util.Collections;
-import java.util.List;
-
-public class DefaultModelCreatorFactory implements ModelCreatorFactory {
- private final ModelSchemaStore schemaStore;
- private final ManagedProxyFactory proxyFactory;
- private ManagedChildNodeCreatorStrategy<?> managedChildCreatorStrategy;
-
- public DefaultModelCreatorFactory(ModelSchemaStore schemaStore) {
- this.schemaStore = schemaStore;
- this.proxyFactory = new ManagedProxyFactory();
- this.managedChildCreatorStrategy = new ManagedChildNodeCreatorStrategy<Object>(this, schemaStore);
- }
-
- @Override
- public <T> ModelCreator creator(ModelRuleDescriptor descriptor, ModelPath path, ModelSchema<T> schema) {
- return creator(descriptor, path, schema, (ModelAction<T>) null);
- }
-
- @Override
- public <T> ModelCreator creator(ModelRuleDescriptor descriptor, ModelPath path, ModelSchema<T> schema, Action<? super T> initializer) {
- ModelReference<T> modelReference = ModelReference.of(path, schema.getType());
- ModelAction<T> modelAction = new NoInputsModelAction<T>(modelReference, descriptor, initializer);
- return creator(descriptor, path, schema, modelAction);
- }
-
- @Override
- public <T> ModelCreator creator(ModelRuleDescriptor descriptor, ModelPath path, ModelSchema<T> schema, List<ModelReference<?>> initializerInputs, BiAction<? super T, ? super List<ModelView<?>>> initializer) {
- ModelReference<T> modelReference = ModelReference.of(path, schema.getType());
- ModelAction<T> modelAction = new InputUsingModelAction<T>(modelReference, descriptor, initializerInputs, initializer);
- return creator(descriptor, path, schema, modelAction);
- }
-
- private <T> ModelCreator creator(ModelRuleDescriptor descriptor, ModelPath path, ModelSchema<T> schema, @Nullable ModelAction<T> initializer) {
- ModelType<T> type = schema.getType();
- ModelCreators.Builder builder;
-
- if (schema instanceof ModelCollectionSchema) {
- builder = ModelCreators.of(path);
- ModelCollectionSchema<T> collectionSchema = (ModelCollectionSchema<T>) schema;
- ModelType<?> elementType = collectionSchema.getElementType();
- addCollectionProjection(builder, collectionSchema, elementType);
- } else if (schema instanceof ModelStructSchema) {
- ModelStructSchema<T> structSchema = (ModelStructSchema<T>) schema;
- builder = ModelCreators.of(path, new ManagedModelInitializer<T>(descriptor, structSchema, schemaStore, this))
- .withProjection(new ManagedModelProjection<T>(structSchema, schemaStore, proxyFactory));
- } else {
- throw new IllegalArgumentException("Don't know how to create model element from schema for " + type);
- }
-
- builder.descriptor(descriptor);
-
- if (schema.getKind() == ModelSchema.Kind.STRUCT && Named.class.isAssignableFrom(type.getRawClass())) {
- builder.action(ModelActionRole.Initialize, new NamedInitializer(path, descriptor));
- }
- if (initializer != null) {
- builder.action(ModelActionRole.Initialize, initializer);
- }
-
- return builder.build();
- }
-
- @SuppressWarnings("deprecation")
- private <T, E> void addCollectionProjection(ModelCreators.Builder builder, ModelCollectionSchema<T> collectionSchema, ModelType<E> elementType) {
- if (collectionSchema.isMap()) {
- builder.withProjection(modelMapProjection(elementType));
- } else {
- Class<? super T> setType = collectionSchema.getType().getRawClass();
- if (setType.equals(ModelSet.class)) {
- builder.withProjection(
- TypedModelProjection.of(ModelTypes.modelSet(elementType), modelSetFactory(elementType))
- );
- } else if (setType.equals(ManagedSet.class)) {
- builder.withProjection(
- TypedModelProjection.of(ModelTypes.managedSet(elementType), managedSetFactory(elementType))
- );
- } else {
- throw new IllegalStateException("Expected ModelSet or ManagedSet");
- }
- }
- }
-
- private <T> ModelProjection modelMapProjection(ModelType<T> elementType) {
- return ModelMapModelProjection.managed(elementType, childCreator());
- }
-
- private <T> ChildNodeCreatorStrategy<T> childCreator() {
- return Cast.uncheckedCast(managedChildCreatorStrategy);
- }
-
- private <T> ChildNodeCreatorStrategy<T> childCreator(@SuppressWarnings("UnusedParameters") ModelType<T> modelType) {
- return Cast.uncheckedCast(managedChildCreatorStrategy);
- }
-
- private static class ManagedChildNodeCreatorStrategy<T> implements ChildNodeCreatorStrategy<T> {
- private final ModelCreatorFactory modelCreatorFactory;
- private final ModelSchemaStore modelSchemaStore;
-
- public ManagedChildNodeCreatorStrategy(ModelCreatorFactory modelCreatorFactory, ModelSchemaStore modelSchemaStore) {
- this.modelCreatorFactory = modelCreatorFactory;
- this.modelSchemaStore = modelSchemaStore;
- }
-
- @Override
- public <S extends T> ModelCreator creator(MutableModelNode parentNode, ModelRuleDescriptor sourceDescriptor, ModelType<S> type, final String name) {
- ModelPath childPath = parentNode.getPath().child(name);
- return modelCreatorFactory.creator(sourceDescriptor, childPath, modelSchemaStore.getSchema(type));
- }
- }
-
- private static class NamedInitializer implements ModelAction<Object> {
-
- private final ModelPath modelPath;
- private final ModelRuleDescriptor parentDescriptor;
-
- public NamedInitializer(ModelPath modelPath, ModelRuleDescriptor parentDescriptor) {
- this.modelPath = modelPath;
- this.parentDescriptor = parentDescriptor;
- }
-
- @Override
- public ModelReference<Object> getSubject() {
- return ModelReference.of(modelPath);
- }
-
- @Override
- public void execute(MutableModelNode modelNode, Object object, List<ModelView<?>> inputs) {
- MutableModelNode nameLink = modelNode.getLink("name");
- if (nameLink == null) {
- throw new IllegalStateException("expected name node for " + modelNode.getPath());
- }
- nameLink.setPrivateData(ModelType.of(String.class), modelNode.getPath().getName());
- }
-
- @Override
- public List<ModelReference<?>> getInputs() {
- return Collections.emptyList();
- }
-
- @Override
- public ModelRuleDescriptor getDescriptor() {
- return new NestedModelRuleDescriptor(parentDescriptor, "<set name>");
- }
- }
-
- @SuppressWarnings("deprecation")
- private <T> ModelViewFactory<ManagedSet<T>> managedSetFactory(final ModelType<T> elementType) {
- return new ManagedSetModelViewFactory<T>(elementType);
- }
-
- private <T> ModelViewFactory<ModelSet<T>> modelSetFactory(final ModelType<T> elementType) {
- return new ModelSetModelViewFactory<T>(elementType);
- }
-
- private class ManagedSetModelViewFactory<T> implements ModelViewFactory<ManagedSet<T>> {
- private final ModelType<T> elementType;
-
- public ManagedSetModelViewFactory(ModelType<T> elementType) {
- this.elementType = elementType;
- }
-
- @Override
- public ModelView<ManagedSet<T>> toView(MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean writable) {
- ModelType<ManagedSet<T>> setType = ModelTypes.managedSet(elementType);
- DefaultModelViewState state = new DefaultModelViewState(setType, ruleDescriptor, writable, !writable);
- NodeBackedModelSet<T> set = new NodeBackedModelSet<T>(setType.toString() + " '" + modelNode.getPath() + "'", elementType, ruleDescriptor, modelNode, state, childCreator(elementType));
- return new InstanceModelView<ManagedSet<T>>(modelNode.getPath(), setType, set, state.closer());
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- ManagedSetModelViewFactory<?> that = (ManagedSetModelViewFactory<?>) o;
- return elementType.equals(that.elementType);
-
- }
-
- @Override
- public int hashCode() {
- return elementType.hashCode();
- }
- }
-
- private class ModelSetModelViewFactory<T> implements ModelViewFactory<ModelSet<T>> {
- private final ModelType<T> elementType;
-
- public ModelSetModelViewFactory(ModelType<T> elementType) {
- this.elementType = elementType;
- }
-
- @Override
- public ModelView<ModelSet<T>> toView(MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean writable) {
- ModelType<ModelSet<T>> setType = ModelTypes.modelSet(elementType);
- DefaultModelViewState state = new DefaultModelViewState(setType, ruleDescriptor, writable, !writable);
- NodeBackedModelSet<T> set = new NodeBackedModelSet<T>(setType.toString() + " '" + modelNode.getPath() + "'", elementType, ruleDescriptor, modelNode, state, childCreator(elementType));
- return new InstanceModelView<ModelSet<T>>(modelNode.getPath(), setType, set, state.closer());
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- ModelSetModelViewFactory<?> that = (ModelSetModelViewFactory<?>) o;
- return elementType.equals(that.elementType);
-
- }
-
- @Override
- public int hashCode() {
- return elementType.hashCode();
- }
- }
-}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedChildNodeCreatorStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedChildNodeCreatorStrategy.java
new file mode 100644
index 0000000..3158f88
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedChildNodeCreatorStrategy.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.inspect;
+
+import org.gradle.model.internal.core.ChildNodeInitializerStrategy;
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.manage.schema.ManagedImplModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.type.ModelType;
+
+public class ManagedChildNodeCreatorStrategy<T> implements ChildNodeInitializerStrategy<T> {
+
+ private final ModelSchemaStore modelSchemaStore;
+
+ public ManagedChildNodeCreatorStrategy(ModelSchemaStore modelSchemaStore) {
+ this.modelSchemaStore = modelSchemaStore;
+ }
+
+ @Override
+ public <S extends T> NodeInitializer initializer(ModelType<S> type) {
+ ModelSchema<S> schema = modelSchemaStore.getSchema(type);
+ if (!(schema instanceof ManagedImplModelSchema)) {
+ throw new IllegalArgumentException("Type is not managed: " + type);
+ }
+ return ((ManagedImplModelSchema<S>) schema).getNodeInitializer();
+ }
+
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelCreationRuleExtractor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelCreationRuleExtractor.java
index 97258ec..02f49f5 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelCreationRuleExtractor.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelCreationRuleExtractor.java
@@ -21,8 +21,10 @@ import org.gradle.api.specs.Spec;
import org.gradle.model.InvalidModelRuleDeclarationException;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
+import org.gradle.model.internal.manage.schema.ManagedImplModelSchema;
import org.gradle.model.internal.manage.schema.ModelSchema;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.ModelValueSchema;
import org.gradle.model.internal.manage.schema.extract.InvalidManagedModelElementTypeException;
import org.gradle.model.internal.type.ModelType;
@@ -31,11 +33,9 @@ import java.util.List;
@NotThreadSafe
public class ManagedModelCreationRuleExtractor extends AbstractModelCreationRuleExtractor {
private final ModelSchemaStore schemaStore;
- private final ModelCreatorFactory modelCreatorFactory;
- public ManagedModelCreationRuleExtractor(ModelSchemaStore schemaStore, ModelCreatorFactory modelCreatorFactory) {
+ public ManagedModelCreationRuleExtractor(ModelSchemaStore schemaStore) {
this.schemaStore = schemaStore;
- this.modelCreatorFactory = modelCreatorFactory;
}
public String getDescription() {
@@ -68,20 +68,29 @@ public class ManagedModelCreationRuleExtractor extends AbstractModelCreationRule
private <T> ModelCreator buildModelCreatorForManagedType(ModelType<T> managedType, final MethodRuleDefinition<?, ?> ruleDefinition, ModelPath modelPath) {
ModelSchema<T> modelSchema = getModelSchema(managedType, ruleDefinition);
- if (modelSchema.getKind().equals(ModelSchema.Kind.VALUE)) {
+ if (modelSchema instanceof ModelValueSchema) {
throw new InvalidModelRuleDeclarationException(ruleDefinition.getDescriptor(), "a void returning model element creation rule cannot take a value type as the first parameter, which is the element being created. Return the value from the method.");
}
- if (!modelSchema.getKind().isManaged()) {
- String description = String.format("a void returning model element creation rule has to take an instance of a managed type as the first argument");
+ if (!(modelSchema instanceof ManagedImplModelSchema)) {
+ String description = "a void returning model element creation rule has to take an instance of a managed type as the first argument";
throw new InvalidModelRuleDeclarationException(ruleDefinition.getDescriptor(), description);
}
+ ManagedImplModelSchema<T> managedSchema = (ManagedImplModelSchema<T>) modelSchema;
+
List<ModelReference<?>> bindings = ruleDefinition.getReferences();
List<ModelReference<?>> inputs = bindings.subList(1, bindings.size());
ModelRuleDescriptor descriptor = ruleDefinition.getDescriptor();
- return modelCreatorFactory.creator(descriptor, modelPath, modelSchema, inputs, new RuleMethodBackedMutationAction<T>(ruleDefinition.getRuleInvoker()));
+ final ModelReference<T> reference = ModelReference.of(modelPath, managedType);
+ return ModelCreators.of(modelPath, managedSchema.getNodeInitializer())
+ .descriptor(descriptor)
+ .action(ModelActionRole.Initialize, InputUsingModelAction.of(
+ reference, descriptor, inputs, new RuleMethodBackedMutationAction<T>(ruleDefinition.getRuleInvoker())
+ )
+ )
+ .build();
}
private <T> ModelSchema<T> getModelSchema(ModelType<T> managedType, MethodRuleDefinition<?, ?> ruleDefinition) {
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelInitializer.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelInitializer.java
index e3eaf5e..1313e1b 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelInitializer.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ManagedModelInitializer.java
@@ -16,46 +16,78 @@
package org.gradle.model.internal.inspect;
-import org.gradle.internal.BiAction;
+import org.gradle.api.Named;
import org.gradle.internal.BiActions;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
-import org.gradle.model.internal.manage.schema.ModelProperty;
-import org.gradle.model.internal.manage.schema.ModelSchema;
-import org.gradle.model.internal.manage.schema.ModelSchemaStore;
-import org.gradle.model.internal.manage.schema.ModelStructSchema;
+import org.gradle.model.internal.manage.instance.ManagedProxyFactory;
+import org.gradle.model.internal.manage.projection.ManagedModelProjection;
+import org.gradle.model.internal.manage.schema.*;
import org.gradle.model.internal.type.ModelType;
-public class ManagedModelInitializer<T> implements BiAction<MutableModelNode, Object> {
+import java.util.Collections;
+import java.util.List;
- private final ModelStructSchema<T> modelSchema;
- private final ModelRuleDescriptor descriptor;
- private final ModelSchemaStore schemaStore;
- private final ModelCreatorFactory modelCreatorFactory;
+public class ManagedModelInitializer<T> implements NodeInitializer {
- public ManagedModelInitializer(ModelRuleDescriptor descriptor, ModelStructSchema<T> modelSchema, ModelSchemaStore schemaStore, ModelCreatorFactory modelCreatorFactory) {
- this.descriptor = descriptor;
- this.schemaStore = schemaStore;
- this.modelCreatorFactory = modelCreatorFactory;
+ private static final ManagedProxyFactory PROXY_FACTORY = new ManagedProxyFactory();
+ protected final ModelManagedImplStructSchema<T> modelSchema;
+ protected final ModelSchemaStore schemaStore;
+
+ public ManagedModelInitializer(ModelManagedImplStructSchema<T> modelSchema, ModelSchemaStore schemaStore) {
this.modelSchema = modelSchema;
+ this.schemaStore = schemaStore;
}
- public void execute(MutableModelNode modelNode, Object object) {
- for (ModelProperty<?> property : modelSchema.getProperties().values()) {
+ @Override
+ public List<? extends ModelReference<?>> getInputs() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void execute(MutableModelNode modelNode, List<ModelView<?>> inputs) {
+ for (ModelProperty<?> property : modelSchema.getProperties()) {
addPropertyLink(modelNode, property);
}
+ if (Named.class.isAssignableFrom(modelSchema.getType().getRawClass())) {
+ // Only initialize "name" child node if the schema has such a managed property.
+ // This is not the case for a managed subtype of an unmanaged type that implements Named.
+ ModelProperty<?> nameProperty = modelSchema.getProperty("name");
+ if (nameProperty != null && nameProperty.getStateManagementType().equals(ModelProperty.StateManagementType.MANAGED)) {
+ MutableModelNode nameLink = modelNode.getLink("name");
+ if (nameLink == null) {
+ throw new IllegalStateException("expected name node for " + modelNode.getPath());
+ }
+ nameLink.setPrivateData(ModelType.of(String.class), modelNode.getPath().getName());
+ }
+ }
+ }
+
+ @Override
+ public List<? extends ModelProjection> getProjections() {
+ return Collections.singletonList(new ManagedModelProjection<T>(modelSchema, schemaStore, PROXY_FACTORY));
}
private <P> void addPropertyLink(MutableModelNode modelNode, ModelProperty<P> property) {
+ // No need to create nodes for unmanaged properties
+ if (!property.getStateManagementType().equals(ModelProperty.StateManagementType.MANAGED)) {
+ return;
+ }
+
ModelType<P> propertyType = property.getType();
ModelSchema<P> propertySchema = schemaStore.getSchema(propertyType);
- if (propertySchema.getKind().isManaged()) {
+ final ModelRuleDescriptor descriptor = modelNode.getDescriptor();
+ if (propertySchema instanceof ManagedImplModelSchema) {
if (!property.isWritable()) {
- ModelCreator creator = modelCreatorFactory.creator(descriptor, modelNode.getPath().child(property.getName()), propertySchema);
+ ManagedImplModelSchema<P> managedPropertySchema = (ManagedImplModelSchema<P>) propertySchema;
+ ModelCreator creator = ModelCreators.of(modelNode.getPath().child(property.getName()), managedPropertySchema.getNodeInitializer())
+ .descriptor(descriptor)
+ .build();
modelNode.addLink(creator);
} else {
- ModelProjection projection = new UnmanagedModelProjection<P>(propertyType, true, true);
+ ModelManagedImplStructSchema<P> structSchema = (ModelManagedImplStructSchema<P>) propertySchema;
+ ModelProjection projection = new ManagedModelProjection<P>(structSchema, schemaStore, PROXY_FACTORY);
ModelCreator creator = ModelCreators.of(modelNode.getPath().child(property.getName()), BiActions.doNothing())
.withProjection(projection)
.descriptor(descriptor).build();
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/MethodModelRuleExtractors.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/MethodModelRuleExtractors.java
index 0fa9130..c0d3f9f 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/MethodModelRuleExtractors.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/MethodModelRuleExtractors.java
@@ -18,7 +18,6 @@ package org.gradle.model.internal.inspect;
import com.google.common.collect.ImmutableList;
import net.jcip.annotations.ThreadSafe;
-import org.gradle.model.internal.core.ModelCreatorFactory;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import java.util.List;
@@ -26,14 +25,14 @@ import java.util.List;
@ThreadSafe
abstract public class MethodModelRuleExtractors {
- public static List<MethodModelRuleExtractor> coreExtractors(ModelSchemaStore modelSchemaStore, ModelCreatorFactory modelCreatorFactory) {
+ public static List<MethodModelRuleExtractor> coreExtractors(ModelSchemaStore modelSchemaStore) {
return ImmutableList.<MethodModelRuleExtractor>of(
- new UnmanagedModelCreationRuleExtractor(),
- new ManagedModelCreationRuleExtractor(modelSchemaStore, modelCreatorFactory),
- new DefaultsModelRuleExtractor(),
- new MutateModelRuleExtractor(),
- new FinalizeModelRuleExtractor(),
- new ValidateModelRuleExtractor()
+ new UnmanagedModelCreationRuleExtractor(),
+ new ManagedModelCreationRuleExtractor(modelSchemaStore),
+ new DefaultsModelRuleExtractor(),
+ new MutateModelRuleExtractor(),
+ new FinalizeModelRuleExtractor(),
+ new ValidateModelRuleExtractor()
);
}
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ProjectionOnlyNodeInitializer.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ProjectionOnlyNodeInitializer.java
new file mode 100644
index 0000000..f41a508
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/inspect/ProjectionOnlyNodeInitializer.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.inspect;
+
+import org.gradle.model.internal.core.*;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ProjectionOnlyNodeInitializer implements NodeInitializer {
+
+ private final ModelProjection projection;
+
+ public ProjectionOnlyNodeInitializer(ModelProjection projection) {
+ this.projection = projection;
+ }
+
+ @Override
+ public List<? extends ModelReference<?>> getInputs() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void execute(MutableModelNode modelNode, List<ModelView<?>> inputs) {
+
+ }
+
+ @Override
+ public List<? extends ModelProjection> getProjections() {
+ return Collections.singletonList(projection);
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/instance/ManagedProxyFactory.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/instance/ManagedProxyFactory.java
index 76d7091..d88b718 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/instance/ManagedProxyFactory.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/instance/ManagedProxyFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,21 +17,28 @@
package org.gradle.model.internal.manage.instance;
import org.gradle.internal.UncheckedException;
-import org.gradle.model.internal.manage.schema.ModelStructSchema;
+import org.gradle.model.internal.manage.schema.ModelManagedImplStructSchema;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ManagedProxyFactory {
- public <T> T createProxy(ModelElementState state, ModelStructSchema<T> schema) {
+ public <T> T createProxy(ModelElementState state, ModelManagedImplStructSchema<T> schema) {
try {
Class<? extends T> generatedClass = schema.getManagedImpl();
if (generatedClass == null) {
throw new IllegalStateException("No managed implementation class available for: " + schema.getType());
}
- Constructor<? extends T> constructor = generatedClass.getConstructor(ModelElementState.class);
- return constructor.newInstance(state);
+ Class<?> delegateType = schema.getDelegateType();
+ if (delegateType == null) {
+ Constructor<? extends T> constructor = generatedClass.getConstructor(ModelElementState.class);
+ return constructor.newInstance(state);
+ } else {
+ Object delegate = state.getBackingNode().getPrivateData(delegateType);
+ Constructor<? extends T> constructor = generatedClass.getConstructor(ModelElementState.class, delegateType);
+ return constructor.newInstance(state, delegate);
+ }
} catch (InvocationTargetException e) {
throw UncheckedException.throwAsUncheckedException(e.getTargetException());
} catch (Exception e) {
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/projection/ManagedModelProjection.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/projection/ManagedModelProjection.java
index 7b48c20..59cfeef 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/projection/ManagedModelProjection.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/projection/ManagedModelProjection.java
@@ -27,10 +27,7 @@ import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.manage.instance.ManagedInstance;
import org.gradle.model.internal.manage.instance.ManagedProxyFactory;
import org.gradle.model.internal.manage.instance.ModelElementState;
-import org.gradle.model.internal.manage.schema.ModelProperty;
-import org.gradle.model.internal.manage.schema.ModelSchema;
-import org.gradle.model.internal.manage.schema.ModelSchemaStore;
-import org.gradle.model.internal.manage.schema.ModelStructSchema;
+import org.gradle.model.internal.manage.schema.*;
import org.gradle.model.internal.type.ModelType;
import java.util.HashMap;
@@ -40,9 +37,9 @@ public class ManagedModelProjection<M> extends TypeCompatibilityModelProjectionS
private final ModelSchemaStore schemaStore;
private final ManagedProxyFactory proxyFactory;
- private final ModelStructSchema<M> schema;
+ private final ModelManagedImplStructSchema<M> schema;
- public ManagedModelProjection(ModelStructSchema<M> schema, ModelSchemaStore schemaStore, ManagedProxyFactory proxyFactory) {
+ public ManagedModelProjection(ModelManagedImplStructSchema<M> schema, ModelSchemaStore schemaStore, ManagedProxyFactory proxyFactory) {
super(schema.getType(), true, true);
this.schema = schema;
this.schemaStore = schemaStore;
@@ -89,7 +86,7 @@ public class ManagedModelProjection<M> extends TypeCompatibilityModelProjectionS
return propertyViews.get(name);
}
- ModelProperty<?> property = schema.getProperties().get(name);
+ ModelProperty<?> property = schema.getProperty(name);
Object value = doGet(property, name);
propertyViews.put(name, value);
@@ -98,28 +95,19 @@ public class ManagedModelProjection<M> extends TypeCompatibilityModelProjectionS
private <T> T doGet(ModelProperty<T> property, String propertyName) {
ModelType<T> propertyType = property.getType();
- ModelSchema<T> schema = schemaStore.getSchema(propertyType);
// TODO we are relying on the creator having established these links, we should be checking
MutableModelNode propertyNode = modelNode.getLink(propertyName);
propertyNode.ensureUsable();
- MutableModelNode targetNode = propertyNode;
- if (property.isWritable() && schema.getKind().isManaged()) {
- targetNode = propertyNode.getTarget();
- if (targetNode == null) {
- return null;
- }
- }
-
if (writable) {
- ModelView<? extends T> modelView = targetNode.asWritable(propertyType, ruleDescriptor, null);
+ ModelView<? extends T> modelView = propertyNode.asWritable(propertyType, ruleDescriptor, null);
if (closed) {
modelView.close();
}
return modelView.getInstance();
} else {
- return targetNode.asReadOnly(propertyType, ruleDescriptor).getInstance();
+ return propertyNode.asReadOnly(propertyType, ruleDescriptor).getInstance();
}
}
@@ -128,7 +116,7 @@ public class ManagedModelProjection<M> extends TypeCompatibilityModelProjectionS
throw new ModelViewClosedException(getType(), ruleDescriptor);
}
- ModelProperty<?> property = schema.getProperties().get(name);
+ ModelProperty<?> property = schema.getProperty(name);
ModelType<?> propertyType = property.getType();
doSet(name, value, propertyType);
@@ -136,13 +124,13 @@ public class ManagedModelProjection<M> extends TypeCompatibilityModelProjectionS
}
private <T> void doSet(String name, Object value, ModelType<T> propertyType) {
- ModelSchema<T> schema = schemaStore.getSchema(propertyType);
+ ModelSchema<T> propertySchema = schemaStore.getSchema(propertyType);
// TODO we are relying on the creator having established these links, we should be checking
MutableModelNode propertyNode = modelNode.getLink(name);
propertyNode.ensureUsable();
- if (schema.getKind().isManaged()) {
+ if (propertySchema instanceof ManagedImplModelSchema) {
if (value == null) {
propertyNode.setTarget(null);
} else if (ManagedInstance.class.isInstance(value)) {
@@ -171,6 +159,7 @@ public class ManagedModelProjection<M> extends TypeCompatibilityModelProjectionS
return Optional.absent();
}
+
@Override
public int hashCode() {
return super.hashCode();
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/AbstractModelSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/AbstractModelSchema.java
new file mode 100644
index 0000000..f853f11
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/AbstractModelSchema.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema;
+
+import net.jcip.annotations.ThreadSafe;
+import org.gradle.model.internal.type.ModelType;
+
+ at ThreadSafe
+public abstract class AbstractModelSchema<T> implements ModelSchema<T> {
+
+ private final ModelType<T> type;
+
+ protected AbstractModelSchema(ModelType<T> type) {
+ this.type = type;
+ }
+
+ @Override
+ public ModelType<T> getType() {
+ return type;
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/AbstractModelStructSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/AbstractModelStructSchema.java
new file mode 100644
index 0000000..2435ff1
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/AbstractModelStructSchema.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.Maps;
+import org.gradle.internal.Cast;
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspect;
+import org.gradle.model.internal.type.ModelType;
+
+import java.util.Collection;
+import java.util.Map;
+
+public abstract class AbstractModelStructSchema<T> extends AbstractModelSchema<T> implements ModelStructSchema<T> {
+ private final ImmutableSortedMap<String, ModelProperty<?>> properties;
+ private final Map<Class<? extends ModelSchemaAspect>, ModelSchemaAspect> aspects;
+
+ public AbstractModelStructSchema(ModelType<T> type, Iterable<ModelProperty<?>> properties, Iterable<ModelSchemaAspect> aspects) {
+ super(type);
+ ImmutableSortedMap.Builder<String, ModelProperty<?>> builder = ImmutableSortedMap.naturalOrder();
+ for (ModelProperty<?> property : properties) {
+ builder.put(property.getName(), property);
+ }
+ this.properties = builder.build();
+ this.aspects = Maps.uniqueIndex(aspects, new Function<ModelSchemaAspect, Class<? extends ModelSchemaAspect>>() {
+ @Override
+ public Class<? extends ModelSchemaAspect> apply(ModelSchemaAspect aspect) {
+ return aspect.getClass();
+ }
+ });
+ }
+
+ @Override
+ public Collection<ModelProperty<?>> getProperties() {
+ return properties.values();
+ }
+
+ @Override
+ public boolean hasProperty(String name) {
+ return properties.containsKey(name);
+ }
+
+ @Override
+ public ModelProperty<?> getProperty(String name) {
+ return properties.get(name);
+ }
+
+ @Override
+ public boolean hasAspect(Class<? extends ModelSchemaAspect> aspectType) {
+ return aspects.containsKey(aspectType);
+ }
+
+ @Override
+ public <A extends ModelSchemaAspect> A getAspect(Class<A> aspectType) {
+ return Cast.uncheckedCast(aspects.get(aspectType));
+ }
+
+ @Override
+ public Collection<ModelSchemaAspect> getAspects() {
+ return aspects.values();
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ManagedImplModelSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ManagedImplModelSchema.java
new file mode 100644
index 0000000..bc80e72
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ManagedImplModelSchema.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema;
+
+import org.gradle.model.internal.core.NodeInitializer;
+
+/**
+ * Model schema with managed implementation. This means that we have control over the actual implementation type for the type
+ * described in the schema, and we also control the instantiation of managed view instances.
+ *
+ * @param <T> the type the schema is extracted from.
+ */
+public interface ManagedImplModelSchema<T> extends ModelSchema<T> {
+ NodeInitializer getNodeInitializer();
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelCollectionSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelCollectionSchema.java
index cab14f0..99cf31b 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelCollectionSchema.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelCollectionSchema.java
@@ -16,32 +16,32 @@
package org.gradle.model.internal.manage.schema;
-import org.gradle.model.ModelMap;
-import org.gradle.model.ModelSet;
-import org.gradle.model.collection.ManagedSet;
+import com.google.common.base.Function;
+import org.gradle.model.internal.core.NodeInitializer;
import org.gradle.model.internal.type.ModelType;
-public class ModelCollectionSchema<T> extends ModelSchema<T> {
- private final ModelType<?> elementType;
- private boolean map;
+public class ModelCollectionSchema<T, E> extends AbstractModelSchema<T> implements ManagedImplModelSchema<T> {
- public ModelCollectionSchema(ModelType<T> type, ModelType<?> elementType) {
- super(type, Kind.COLLECTION);
+ private final ModelType<E> elementType;
+ private final NodeInitializer nodeInitializer;
+
+ public ModelCollectionSchema(ModelType<T> type, ModelType<E> elementType, Function<ModelCollectionSchema<T, E>, NodeInitializer> nodeInitializer) {
+ super(type);
this.elementType = elementType;
- if (type.getRawClass().equals(ModelMap.class)) {
- map = true;
- } else if (type.getRawClass().equals(ModelSet.class) || type.getRawClass().equals(ManagedSet.class)) {
- map = false;
- } else {
- throw new IllegalArgumentException("Expected type of either ModelMap or ModelSet");
- }
+ this.nodeInitializer = nodeInitializer.apply(this);
}
- public ModelType<?> getElementType() {
+ public ModelType<E> getElementType() {
return elementType;
}
- public boolean isMap() {
- return map;
+ @Override
+ public NodeInitializer getNodeInitializer() {
+ return nodeInitializer;
+ }
+
+ @Override
+ public String toString() {
+ return "collection " + getType();
}
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelManagedImplStructSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelManagedImplStructSchema.java
new file mode 100644
index 0000000..ff5ddb0
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelManagedImplStructSchema.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema;
+
+import com.google.common.base.Function;
+import org.gradle.api.Nullable;
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspect;
+import org.gradle.model.internal.type.ModelType;
+
+import java.lang.ref.WeakReference;
+
+public class ModelManagedImplStructSchema<T> extends AbstractModelStructSchema<T> implements ManagedImplModelSchema<T> {
+ private final WeakReference<Class<? extends T>> managedImpl;
+ private final WeakReference<Class<?>> delegateType;
+ private final NodeInitializer nodeInitializer;
+
+ public ModelManagedImplStructSchema(ModelType<T> type, Iterable<ModelProperty<?>> properties, Iterable<ModelSchemaAspect> aspects, Class<? extends T> managedImpl, @Nullable Class<?> delegateType, Function<? super ModelManagedImplStructSchema<T>, NodeInitializer> nodeInitializer) {
+ super(type, properties, aspects);
+ this.nodeInitializer = nodeInitializer.apply(this);
+ this.managedImpl = new WeakReference<Class<? extends T>>(managedImpl);
+ this.delegateType = new WeakReference<Class<?>>(delegateType);
+ }
+
+ public Class<? extends T> getManagedImpl() {
+ return managedImpl.get();
+ }
+
+ @Nullable
+ public Class<?> getDelegateType() {
+ return delegateType.get();
+ }
+
+ @Override
+ public NodeInitializer getNodeInitializer() {
+ return nodeInitializer;
+ }
+
+ @Override
+ public String toString() {
+ return "managed " + getType();
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelMapSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelMapSchema.java
index 0640ce7..26a1fbc 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelMapSchema.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelMapSchema.java
@@ -20,12 +20,12 @@ import org.gradle.model.internal.type.ModelType;
import java.lang.ref.WeakReference;
-public class ModelMapSchema<T> extends ModelSchema<T> {
+public class ModelMapSchema<T> extends AbstractModelSchema<T> {
private final WeakReference<Class<?>> managedImpl;
private final ModelType<?> elementType;
public ModelMapSchema(ModelType<T> type, ModelType<?> elementType, Class<?> managedImpl) {
- super(type, Kind.SPECIALIZED_MAP);
+ super(type);
this.elementType = elementType;
this.managedImpl = new WeakReference<Class<?>>(managedImpl);
}
@@ -37,4 +37,9 @@ public class ModelMapSchema<T> extends ModelSchema<T> {
public Class<?> getManagedImpl() {
return managedImpl.get();
}
+
+ @Override
+ public String toString() {
+ return "model map " + getType();
+ }
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelProperty.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelProperty.java
index 78e20e1..69ef160 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelProperty.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelProperty.java
@@ -16,8 +16,11 @@
package org.gradle.model.internal.manage.schema;
+import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import net.jcip.annotations.ThreadSafe;
+import org.gradle.internal.Cast;
+import org.gradle.model.internal.method.WeaklyTypeReferencingMethod;
import org.gradle.model.internal.type.ModelType;
import java.util.Set;
@@ -25,36 +28,55 @@ import java.util.Set;
@ThreadSafe
public class ModelProperty<T> {
+ public enum StateManagementType {
+ /**
+ * The state of the property is stored as child nodes in the model.
+ */
+ MANAGED,
+
+ /**
+ * The state of the property is handled by the view.
+ */
+ UNMANAGED,
+
+ /**
+ * The state of the property is handled by an unmanaged delegate.
+ */
+ DELEGATED
+ }
+
private final String name;
private final ModelType<T> type;
+ private final StateManagementType stateManagementType;
private final boolean writable;
private final Set<ModelType<?>> declaredBy;
- private final boolean unmanaged;
+ private final WeaklyTypeReferencingMethod<?, T> getter;
- private ModelProperty(ModelType<T> type, String name, boolean writable, Set<ModelType<?>> declaredBy, boolean unmanaged) {
+ private ModelProperty(ModelType<T> type, String name, StateManagementType stateManagementType, boolean writable, Set<ModelType<?>> declaredBy, WeaklyTypeReferencingMethod<?, T> getter) {
this.name = name;
this.type = type;
+ this.stateManagementType = stateManagementType;
this.writable = writable;
this.declaredBy = ImmutableSet.copyOf(declaredBy);
- this.unmanaged = unmanaged;
+ this.getter = getter;
}
- public static <T> ModelProperty<T> of(ModelType<T> type, String name, boolean writable, Set<ModelType<?>> declaredBy, boolean unmanaged) {
- return new ModelProperty<T>(type, name, writable, declaredBy, unmanaged);
+ public static <T> ModelProperty<T> of(ModelType<T> type, String name, StateManagementType stateManagementType, boolean writable, Set<ModelType<?>> declaredBy, WeaklyTypeReferencingMethod<?, T> getter) {
+ return new ModelProperty<T>(type, name, stateManagementType, writable, declaredBy, getter);
}
public String getName() {
return name;
}
- public boolean isUnmanaged() {
- return unmanaged;
- }
-
public ModelType<T> getType() {
return type;
}
+ public StateManagementType getStateManagementType() {
+ return stateManagementType;
+ }
+
public boolean isWritable() {
return writable;
}
@@ -63,6 +85,10 @@ public class ModelProperty<T> {
return declaredBy;
}
+ public <I> T getPropertyValue(I instance) {
+ return Cast.<WeaklyTypeReferencingMethod<I, T>>uncheckedCast(getter).invoke(instance);
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -74,15 +100,23 @@ public class ModelProperty<T> {
ModelProperty<?> that = (ModelProperty<?>) o;
-
- return name.equals(that.name) && type.equals(that.type) && writable == that.writable;
+ return Objects.equal(this.name, that.name)
+ && Objects.equal(this.type, that.type)
+ && Objects.equal(this.stateManagementType, that.stateManagementType)
+ && writable == that.writable;
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + type.hashCode();
+ result = 31 * result + stateManagementType.hashCode();
result = 31 * result + Boolean.valueOf(writable).hashCode();
return result;
}
+
+ @Override
+ public String toString() {
+ return stateManagementType.name().toLowerCase() + " " + getName() + "(" + getType().getSimpleName() + ")";
+ }
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelSchema.java
index da8a74e..c9becec 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelSchema.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelSchema.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,78 +16,8 @@
package org.gradle.model.internal.manage.schema;
-import net.jcip.annotations.ThreadSafe;
import org.gradle.model.internal.type.ModelType;
- at ThreadSafe
-public class ModelSchema<T> {
-
- public enum Kind {
- VALUE(false, true), // at the moment we are conflating this with unstructured primitives
- COLLECTION,
- SPECIALIZED_MAP(false, false), // not quite
- STRUCT,
- UNMANAGED(false, false); // some type we know nothing about
-
- private final boolean isManaged;
- private final boolean isAllowedPropertyTypeOfManagedType;
-
- Kind() {
- this(true, true);
- }
-
- Kind(boolean isManaged, boolean isAllowedPropertyTypeOfManagedType) {
- this.isManaged = isManaged;
- this.isAllowedPropertyTypeOfManagedType = isAllowedPropertyTypeOfManagedType;
- }
-
- public boolean isManaged() {
- return isManaged;
- }
-
- public boolean isAllowedPropertyTypeOfManagedType() {
- return isAllowedPropertyTypeOfManagedType;
- }
- }
-
- private final ModelType<T> type;
- private final Kind kind;
-
- public static <T> ModelSchema<T> value(ModelType<T> type) {
- return new ModelSchema<T>(type, Kind.VALUE);
- }
-
- public static <T> ModelStructSchema<T> struct(ModelType<T> type, Iterable<ModelProperty<?>> properties, Class<? extends T> managedImpl) {
- return new ModelStructSchema<T>(type, properties, managedImpl);
- }
-
- public static <T> ModelCollectionSchema<T> collection(ModelType<T> type, ModelType<?> elementType) {
- return new ModelCollectionSchema<T>(type, elementType);
- }
-
- public static <T> ModelMapSchema<T> specializedMap(ModelType<T> type, ModelType<?> elementType, Class<?> managedImpl) {
- return new ModelMapSchema<T>(type, elementType, managedImpl);
- }
-
- public static <T> ModelSchema<T> unmanaged(ModelType<T> type) {
- return new ModelSchema<T>(type, Kind.UNMANAGED);
- }
-
- protected ModelSchema(ModelType<T> type, Kind kind) {
- this.type = type;
- this.kind = kind;
- }
-
- public ModelType<T> getType() {
- return type;
- }
-
- public Kind getKind() {
- return kind;
- }
-
- @Override
- public String toString() {
- return kind.toString().toLowerCase() + " " + type;
- }
+public interface ModelSchema<T> {
+ ModelType<T> getType();
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelStructSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelStructSchema.java
index 414d462..e99aeb0 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelStructSchema.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelStructSchema.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 the original author or authors.
+ * Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,30 +16,20 @@
package org.gradle.model.internal.manage.schema;
-import com.google.common.collect.ImmutableSortedMap;
-import org.gradle.model.internal.type.ModelType;
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspect;
-import java.lang.ref.WeakReference;
+import java.util.Collection;
-public class ModelStructSchema<T> extends ModelSchema<T> {
- private final WeakReference<Class<? extends T>> managedImpl;
- private final ImmutableSortedMap<String, ModelProperty<?>> properties;
+public interface ModelStructSchema<T> extends ModelSchema<T> {
+ boolean hasProperty(String name);
- public ModelStructSchema(ModelType<T> type, Iterable<ModelProperty<?>> properties, Class<? extends T> managedImpl) {
- super(type, Kind.STRUCT);
- ImmutableSortedMap.Builder<String, ModelProperty<?>> builder = ImmutableSortedMap.naturalOrder();
- for (ModelProperty<?> property : properties) {
- builder.put(property.getName(), property);
- }
- this.properties = builder.build();
- this.managedImpl = new WeakReference<Class<? extends T>>(managedImpl);
- }
+ ModelProperty<?> getProperty(String name);
- public ImmutableSortedMap<String, ModelProperty<?>> getProperties() {
- return properties;
- }
+ Collection<ModelProperty<?>> getProperties();
- public Class<? extends T> getManagedImpl() {
- return managedImpl.get();
- }
+ boolean hasAspect(Class<? extends ModelSchemaAspect> aspectType);
+
+ <A extends ModelSchemaAspect> A getAspect(Class<A> aspectType);
+
+ Collection<ModelSchemaAspect> getAspects();
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelUnmanagedImplStructSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelUnmanagedImplStructSchema.java
new file mode 100644
index 0000000..b02f92d
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelUnmanagedImplStructSchema.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema;
+
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspect;
+import org.gradle.model.internal.type.ModelType;
+
+public class ModelUnmanagedImplStructSchema<T> extends AbstractModelStructSchema<T> {
+ public ModelUnmanagedImplStructSchema(ModelType<T> type, Iterable<ModelProperty<?>> properties, Iterable<ModelSchemaAspect> aspects) {
+ super(type, properties, aspects);
+ }
+
+ @Override
+ public String toString() {
+ return "unmanaged " + getType();
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelValueSchema.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelValueSchema.java
new file mode 100644
index 0000000..7059ebd
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/ModelValueSchema.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema;
+
+import org.gradle.model.internal.type.ModelType;
+
+public class ModelValueSchema<T> extends AbstractModelSchema<T> {
+ public ModelValueSchema(ModelType<T> type) {
+ super(type);
+ }
+
+ @Override
+ public String toString() {
+ return "value " + getType();
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStore.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStore.java
index f5fcd1e..e96c047 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStore.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStore.java
@@ -25,20 +25,21 @@ import org.gradle.model.internal.type.ModelType;
@NotThreadSafe
public class DefaultModelSchemaStore implements ModelSchemaStore {
- private static final DefaultModelSchemaStore INSTANCE = new DefaultModelSchemaStore();
+ private static final DefaultModelSchemaStore INSTANCE = new DefaultModelSchemaStore(new ModelSchemaExtractor());
final ModelSchemaCache cache = new ModelSchemaCache();
- final ModelSchemaExtractor extractor = new ModelSchemaExtractor();
+ final ModelSchemaExtractor extractor;
public static DefaultModelSchemaStore getInstance() {
return INSTANCE;
}
- DefaultModelSchemaStore() {
+ public DefaultModelSchemaStore(ModelSchemaExtractor extractor) {
+ this.extractor = extractor;
}
public <T> ModelSchema<T> getSchema(ModelType<T> type) {
- return extractor.extract(type, cache);
+ return extractor.extract(type, this, cache);
}
@Override
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/EnumStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/EnumStrategy.java
index 0102c54..e9e532c 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/EnumStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/EnumStrategy.java
@@ -16,25 +16,20 @@
package org.gradle.model.internal.manage.schema.extract;
-import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.ModelValueSchema;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
import org.gradle.model.internal.type.ModelType;
-import java.util.Collections;
-
public class EnumStrategy implements ModelSchemaExtractionStrategy {
- public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaCache cache) {
+ public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaStore store, ModelSchemaCache cache) {
ModelType<T> type = extractionContext.getType();
if (type.getRawClass().isEnum()) {
- return new ModelSchemaExtractionResult<T>(ModelSchema.value(type));
+ return new ModelSchemaExtractionResult<T>(new ModelValueSchema<T>(type));
} else {
return null;
}
}
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.singleton("enum types");
- }
-
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/JdkValueTypeStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/JdkValueTypeStrategy.java
index 40e1db3..09b3081 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/JdkValueTypeStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/JdkValueTypeStrategy.java
@@ -16,44 +16,44 @@
package org.gradle.model.internal.manage.schema.extract;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.ModelValueSchema;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
import org.gradle.model.internal.type.ModelType;
import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.Collections;
import java.util.List;
public class JdkValueTypeStrategy implements ModelSchemaExtractionStrategy {
- private final static List<ModelType<?>> TYPES = ImmutableList.<ModelType<?>>of(
- ModelType.of(String.class),
- ModelType.of(Boolean.class),
- ModelType.of(Character.class),
- ModelType.of(Integer.class),
- ModelType.of(Long.class),
- ModelType.of(Double.class),
- ModelType.of(BigInteger.class),
- ModelType.of(BigDecimal.class),
- ModelType.of(File.class)
+ public final static List<ModelType<?>> TYPES = ImmutableList.<ModelType<?>>of(
+ ModelType.of(String.class),
+ ModelType.of(Boolean.class),
+ ModelType.of(Character.class),
+ ModelType.of(Byte.class),
+ ModelType.of(Short.class),
+ ModelType.of(Integer.class),
+ ModelType.of(Float.class),
+ ModelType.of(Long.class),
+ ModelType.of(Double.class),
+ ModelType.of(BigInteger.class),
+ ModelType.of(BigDecimal.class),
+ ModelType.of(File.class)
);
// Expected to be a subset of above
private final static List<ModelType<?>> NON_FINAL_TYPES = ImmutableList.<ModelType<?>>of(
- ModelType.of(BigInteger.class),
- ModelType.of(BigDecimal.class)
+ ModelType.of(BigInteger.class),
+ ModelType.of(BigDecimal.class)
);
- public <R> ModelSchemaExtractionResult<R> extract(ModelSchemaExtractionContext<R> extractionContext, ModelSchemaCache cache) {
+ public <R> ModelSchemaExtractionResult<R> extract(ModelSchemaExtractionContext<R> extractionContext, ModelSchemaStore store, ModelSchemaCache cache) {
ModelType<R> type = extractionContext.getType();
if (TYPES.contains(type)) {
- return new ModelSchemaExtractionResult<R>(ModelSchema.value(type));
+ return new ModelSchemaExtractionResult<R>(new ModelValueSchema<R>(type));
} else {
for (ModelType<?> nonFinalType : NON_FINAL_TYPES) {
if (nonFinalType.isAssignableFrom(type)) {
@@ -65,11 +65,4 @@ public class JdkValueTypeStrategy implements ModelSchemaExtractionStrategy {
}
}
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.singleton("JDK value types: " + Joiner.on(", ").join(Iterables.transform(TYPES, new Function<ModelType<?>, Object>() {
- public Object apply(ModelType<?> input) {
- return input.getRawClass().getSimpleName();
- }
- })));
- }
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedImplStructSchemaExtractionStrategySupport.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedImplStructSchemaExtractionStrategySupport.java
new file mode 100644
index 0000000..0406adc
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedImplStructSchemaExtractionStrategySupport.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Iterables;
+import org.gradle.api.Action;
+import org.gradle.api.Named;
+import org.gradle.internal.reflect.MethodDescription;
+import org.gradle.model.Managed;
+import org.gradle.model.Unmanaged;
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.manage.schema.*;
+import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
+import org.gradle.model.internal.type.ModelType;
+
+import java.lang.reflect.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static org.gradle.model.internal.manage.schema.extract.ModelSchemaUtils.*;
+
+public abstract class ManagedImplStructSchemaExtractionStrategySupport extends StructSchemaExtractionStrategySupport {
+
+ private final ManagedProxyClassGenerator classGenerator = new ManagedProxyClassGenerator();
+
+ private final Class<?> implementedInterface;
+ private final Class<?> delegateType;
+
+ protected ManagedImplStructSchemaExtractionStrategySupport(ModelSchemaAspectExtractor aspectExtractor, Class<?> delegateType, Class<?> implementedInterface) {
+ super(aspectExtractor);
+ this.implementedInterface = implementedInterface;
+ this.delegateType = delegateType;
+ }
+
+ @Override
+ @SuppressWarnings("SimplifiableIfStatement")
+ protected boolean isTarget(ModelType<?> type) {
+ if (!type.getRawClass().isAnnotationPresent(Managed.class)) {
+ return false;
+ }
+ return implementedInterface == null
+ || (!type.getRawClass().equals(implementedInterface)
+ && implementedInterface.isAssignableFrom(type.getRawClass()));
+ }
+
+ @Override
+ protected <R> void validateTypeHierarchy(final ModelSchemaExtractionContext<R> extractionContext, ModelType<R> type) {
+ walkTypeHierarchy(type.getConcreteClass(), new ModelSchemaUtils.TypeVisitor() {
+ @Override
+ public void visitType(Class<?> type) {
+ if (type.isAnnotationPresent(Managed.class)) {
+ validateManagedType(extractionContext, type);
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void handleOverloadedMethods(ModelSchemaExtractionContext<?> extractionContext, Collection<Method> overloadedMethods) {
+ if (isMethodDeclaredInManagedType(overloadedMethods)) {
+ throw invalidMethods(extractionContext, "overloaded methods are not supported", overloadedMethods);
+ }
+ }
+
+ @Override
+ protected ModelProperty.StateManagementType determineStateManagementType(ModelSchemaExtractionContext<?> extractionContext, PropertyAccessorExtractionContext getterContext) {
+ // Named.getName() needs to be handled specially
+ if (getterContext.getMostSpecificDeclaration().getName().equals("getName")
+ && Named.class.isAssignableFrom(extractionContext.getType().getRawClass())) {
+ if (delegateType == null) {
+ return ModelProperty.StateManagementType.MANAGED;
+ }
+ boolean delegateHasGetNameMethod = Iterables.any(Arrays.asList(delegateType.getMethods()), new Predicate<Method>() {
+ @Override
+ public boolean apply(Method method) {
+ return method.getName().equals("getName");
+ }
+ });
+ if (delegateHasGetNameMethod) {
+ return ModelProperty.StateManagementType.DELEGATED;
+ } else {
+ return ModelProperty.StateManagementType.MANAGED;
+ }
+ }
+
+ if (getterContext.isDeclaredInManagedType()) {
+ if (getterContext.isDeclaredAsAbstract()) {
+ return ModelProperty.StateManagementType.MANAGED;
+ } else {
+ return ModelProperty.StateManagementType.UNMANAGED;
+ }
+ } else {
+ return ModelProperty.StateManagementType.DELEGATED;
+ }
+ }
+
+ @Override
+ protected <R> ModelManagedImplStructSchema<R> createSchema(ModelSchemaExtractionContext<R> extractionContext, final ModelSchemaStore store, ModelType<R> type, Iterable<ModelProperty<?>> properties, Iterable<ModelSchemaAspect> aspects) {
+ Class<? extends R> implClass = classGenerator.generate(type.getConcreteClass(), delegateType, properties);
+ return new ModelManagedImplStructSchema<R>(type, properties, aspects, implClass, delegateType, new Function<ModelManagedImplStructSchema<R>, NodeInitializer>() {
+ @Override
+ public NodeInitializer apply(ModelManagedImplStructSchema<R> schema) {
+ return createNodeInitializer(schema, store);
+ }
+ });
+ }
+
+ protected abstract <R> NodeInitializer createNodeInitializer(ModelManagedImplStructSchema<R> schema, ModelSchemaStore store);
+
+ @Override
+ protected void handleInvalidGetter(ModelSchemaExtractionContext<?> extractionContext, Method getter, String message) {
+ if (ModelSchemaUtils.isMethodDeclaredInManagedType(getter)) {
+ throw invalidMethod(extractionContext, message, getter);
+ }
+ }
+
+ @Override
+ protected void validateSetter(ModelSchemaExtractionContext<?> extractionContext, ModelType<?> propertyType, PropertyAccessorExtractionContext getterContext, PropertyAccessorExtractionContext setterContext) {
+ // Get most specific setter
+ Method mostSpecificSetter = setterContext.getMostSpecificDeclaration();
+
+ if (!getterContext.isDeclaredAsAbstract() && setterContext.isDeclaredAsAbstract()) {
+ throw invalidMethod(extractionContext, "setters are not allowed for non-abstract getters", mostSpecificSetter);
+ }
+
+ if (mostSpecificSetter.getName().equals("setName") && Named.class.isAssignableFrom(extractionContext.getType().getRawClass())) {
+ throw new InvalidManagedModelElementTypeException(extractionContext, String.format(
+ "@Managed types implementing %s must not declare a setter for the name property",
+ Named.class.getName()
+ ));
+ } else {
+ if (getterContext.isDeclaredInManagedType() && !setterContext.isDeclaredInManagedType()) {
+ throw invalidMethods(extractionContext, "unmanaged setter for managed getter", Iterables.concat(getterContext.getDeclaringMethods(), setterContext.getDeclaringMethods()));
+ } else if (!getterContext.isDeclaredInManagedType() && setterContext.isDeclaredInManagedType()) {
+ throw invalidMethods(extractionContext, "managed setter for unmanaged getter", Iterables.concat(getterContext.getDeclaringMethods(), setterContext.getDeclaringMethods()));
+ }
+ }
+
+ if (!setterContext.isDeclaredInManagedType()) {
+ return;
+ }
+
+ if (!Modifier.isAbstract(mostSpecificSetter.getModifiers())) {
+ throw invalidMethod(extractionContext, "non-abstract setters are not allowed", mostSpecificSetter);
+ }
+
+ if (!mostSpecificSetter.getReturnType().equals(void.class)) {
+ throw invalidMethod(extractionContext, "setter method must have void return type", mostSpecificSetter);
+ }
+
+ Type[] setterParameterTypes = mostSpecificSetter.getGenericParameterTypes();
+ if (setterParameterTypes.length != 1) {
+ throw invalidMethod(extractionContext, "setter method must have exactly one parameter", mostSpecificSetter);
+ }
+
+ ModelType<?> setterType = ModelType.paramType(mostSpecificSetter, 0);
+ if (!setterType.equals(propertyType)) {
+ String message = "setter method param must be of exactly the same type as the getter returns (expected: " + propertyType + ", found: " + setterType + ")";
+ throw invalidMethod(extractionContext, message, mostSpecificSetter);
+ }
+ }
+
+ @Override
+ protected void validateAllNecessaryMethodsHandled(ModelSchemaExtractionContext<?> extractionContext, Collection<Method> allMethods, final Set<Method> handledMethods) {
+ Iterable<Method> notHandled = Iterables.filter(allMethods, new Predicate<Method>() {
+ @Override
+ public boolean apply(Method method) {
+ return method.getDeclaringClass().isAnnotationPresent(Managed.class) && !handledMethods.contains(method);
+ }
+ });
+
+ // TODO - should call out valid getters without setters
+ if (!Iterables.isEmpty(notHandled)) {
+ throw invalidMethods(extractionContext, "only paired getter/setter methods are supported", notHandled);
+ }
+ }
+
+ @Override
+ protected <P> Action<ModelSchemaExtractionContext<P>> createPropertyValidator(final ModelPropertyExtractionResult<P> propertyResult, final ModelSchemaCache modelSchemaCache) {
+ return new Action<ModelSchemaExtractionContext<P>>() {
+ @Override
+ public void execute(ModelSchemaExtractionContext<P> propertyExtractionContext) {
+ ModelProperty<P> property = propertyResult.getProperty();
+ // Do not validate unmanaged properties
+ if (!property.getStateManagementType().equals(ModelProperty.StateManagementType.MANAGED)) {
+ return;
+ }
+
+ ModelSchemaExtractionContext<?> parentContext = propertyExtractionContext.getParent();
+
+ // The "name" property is handled differently if type implements Named
+ if (property.getName().equals("name") && Named.class.isAssignableFrom(parentContext.getType().getRawClass())) {
+ return;
+ }
+
+ ModelSchema<P> propertySchema = modelSchemaCache.get(property.getType());
+
+ // Only managed implementation and value types are allowed as a managed property type unless marked with @Unmanaged
+ boolean isAllowedPropertyTypeOfManagedType = propertySchema instanceof ManagedImplModelSchema
+ || propertySchema instanceof ModelValueSchema;
+ boolean isDeclaredAsHavingUnmanagedType = propertyResult.getGetter().isAnnotationPresent(Unmanaged.class);
+
+ if (isAllowedPropertyTypeOfManagedType && isDeclaredAsHavingUnmanagedType) {
+ throw new InvalidManagedModelElementTypeException(parentContext, String.format(
+ "property '%s' is marked as @Unmanaged, but is of @Managed type '%s'. Please remove the @Managed annotation.%n",
+ property.getName(), property.getType()
+ ));
+ }
+
+ if (!isAllowedPropertyTypeOfManagedType && !isDeclaredAsHavingUnmanagedType) {
+ throw new InvalidManagedModelElementTypeException(parentContext, String.format(
+ "type %s cannot be used for property '%s' as it is an unmanaged type (please annotate the getter with @org.gradle.model.Unmanaged if you want this property to be unmanaged).%n%s",
+ property.getType(), property.getName(), ModelSchemaExtractor.getManageablePropertyTypesDescription()
+ ));
+ }
+
+ if (!property.isWritable()) {
+ if (isDeclaredAsHavingUnmanagedType) {
+ throw new InvalidManagedModelElementTypeException(parentContext, String.format(
+ "unmanaged property '%s' cannot be read only, unmanaged properties must have setters",
+ property.getName())
+ );
+ }
+
+ if (!(propertySchema instanceof ManagedImplModelSchema)) {
+ throw new InvalidManagedModelElementTypeException(parentContext, String.format(
+ "read only property '%s' has non managed type %s, only managed types can be used",
+ property.getName(), property.getType()));
+ }
+ }
+
+ if (propertySchema instanceof ModelCollectionSchema) {
+ if (property.isWritable()) {
+ throw new InvalidManagedModelElementTypeException(parentContext, String.format(
+ "property '%s' cannot have a setter (%s properties must be read only).",
+ property.getName(), property.getType().toString()));
+ }
+
+ ModelCollectionSchema<P, ?> propertyCollectionsSchema = (ModelCollectionSchema<P, ?>) propertySchema;
+
+ ModelType<?> elementType = propertyCollectionsSchema.getElementType();
+ ModelSchema<?> elementTypeSchema = modelSchemaCache.get(elementType);
+
+ if (!(elementTypeSchema instanceof ManagedImplModelSchema)) {
+ throw new InvalidManagedModelElementTypeException(parentContext, String.format(
+ "property '%s' cannot be a model map of type %s as it is not a %s type.",
+ property.getName(), elementType, Managed.class.getName()
+ ));
+ }
+ }
+ }
+ };
+ }
+
+ private void validateManagedType(ModelSchemaExtractionContext<?> extractionContext, Class<?> typeClass) {
+ if (!typeClass.isInterface() && !Modifier.isAbstract(typeClass.getModifiers())) {
+ throw new InvalidManagedModelElementTypeException(extractionContext, "must be defined as an interface or an abstract class.");
+ }
+
+ if (typeClass.getTypeParameters().length > 0) {
+ throw new InvalidManagedModelElementTypeException(extractionContext, "cannot be a parameterized type.");
+ }
+
+ Constructor<?> customConstructor = findCustomConstructor(typeClass);
+ if (customConstructor != null) {
+ throw invalidMethod(extractionContext, "custom constructors are not allowed", customConstructor);
+ }
+
+ ensureNoInstanceScopedFields(extractionContext, typeClass);
+ ensureNoProtectedOrPrivateMethods(extractionContext, typeClass);
+ }
+
+ private void ensureNoProtectedOrPrivateMethods(ModelSchemaExtractionContext<?> extractionContext, Class<?> typeClass) {
+ Class<?> superClass = typeClass.getSuperclass();
+ if (superClass != null && !superClass.equals(Object.class)) {
+ ensureNoProtectedOrPrivateMethods(extractionContext, superClass);
+ }
+
+ Iterable<Method> protectedAndPrivateMethods = Iterables.filter(Arrays.asList(typeClass.getDeclaredMethods()), new Predicate<Method>() {
+ @Override
+ public boolean apply(Method method) {
+ int modifiers = method.getModifiers();
+ return !method.isSynthetic() && (Modifier.isProtected(modifiers) || Modifier.isPrivate(modifiers));
+ }
+ });
+
+ if (!Iterables.isEmpty(protectedAndPrivateMethods)) {
+ throw invalidMethods(extractionContext, "protected and private methods are not allowed", protectedAndPrivateMethods);
+ }
+ }
+
+ private void ensureNoInstanceScopedFields(ModelSchemaExtractionContext<?> extractionContext, Class<?> typeClass) {
+ Class<?> superClass = typeClass.getSuperclass();
+ if (superClass != null && !superClass.equals(Object.class)) {
+ ensureNoInstanceScopedFields(extractionContext, superClass);
+ }
+
+ List<Field> declaredFields = Arrays.asList(typeClass.getDeclaredFields());
+ Iterable<Field> instanceScopedFields = Iterables.filter(declaredFields, new Predicate<Field>() {
+ public boolean apply(Field field) {
+ return !Modifier.isStatic(field.getModifiers()) && !field.getName().equals("metaClass");
+ }
+ });
+ ImmutableSortedSet<String> sortedDescriptions = ImmutableSortedSet.copyOf(Iterables.transform(instanceScopedFields, new Function<Field, String>() {
+ public String apply(Field field) {
+ return field.toString();
+ }
+ }));
+ if (!sortedDescriptions.isEmpty()) {
+ throw new InvalidManagedModelElementTypeException(extractionContext, "instance scoped fields are not allowed (found fields: " + Joiner.on(", ").join(sortedDescriptions) + ").");
+ }
+ }
+
+ private Constructor<?> findCustomConstructor(Class<?> typeClass) {
+ Class<?> superClass = typeClass.getSuperclass();
+ if (superClass != null && !superClass.equals(Object.class)) {
+ Constructor<?> customSuperConstructor = findCustomConstructor(typeClass.getSuperclass());
+ if (customSuperConstructor != null) {
+ return customSuperConstructor;
+ }
+ }
+ Constructor<?>[] constructors = typeClass.getConstructors();
+ if (constructors.length == 0 || (constructors.length == 1 && constructors[0].getParameterTypes().length == 0)) {
+ return null;
+ } else {
+ for (Constructor<?> constructor : constructors) {
+ if (constructor.getParameterTypes().length > 0) {
+ return constructor;
+ }
+ }
+ //this should never happen
+ throw new RuntimeException(String.format("Expected a constructor taking at least one argument in %s but no such constructors were found", typeClass.getName()));
+ }
+ }
+
+ private InvalidManagedModelElementTypeException invalidMethod(ModelSchemaExtractionContext<?> extractionContext, String message, Method method) {
+ return invalidMethod(extractionContext, message, MethodDescription.of(method));
+ }
+
+ private InvalidManagedModelElementTypeException invalidMethod(ModelSchemaExtractionContext<?> extractionContext, String message, Constructor<?> constructor) {
+ return invalidMethod(extractionContext, message, MethodDescription.of(constructor));
+ }
+
+ private InvalidManagedModelElementTypeException invalidMethod(ModelSchemaExtractionContext<?> extractionContext, String message, MethodDescription methodDescription) {
+ return new InvalidManagedModelElementTypeException(extractionContext, message + " (invalid method: " + methodDescription.toString() + ").");
+ }
+
+ private InvalidManagedModelElementTypeException invalidMethods(ModelSchemaExtractionContext<?> extractionContext, String message, Iterable<Method> methods) {
+ final ImmutableSortedSet<String> descriptions = ImmutableSortedSet.copyOf(Iterables.transform(methods, new Function<Method, String>() {
+ public String apply(Method method) {
+ return MethodDescription.of(method).toString();
+ }
+ }));
+ return new InvalidManagedModelElementTypeException(extractionContext, message + " (invalid methods: " + Joiner.on(", ").join(descriptions) + ").");
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedImplStructStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedImplStructStrategy.java
new file mode 100644
index 0000000..b6bc98b
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedImplStructStrategy.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import org.gradle.api.Action;
+import org.gradle.model.internal.core.MutableModelNode;
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.inspect.ManagedModelInitializer;
+import org.gradle.model.internal.manage.instance.ManagedProxyFactory;
+import org.gradle.model.internal.manage.instance.ModelElementState;
+import org.gradle.model.internal.manage.schema.ModelManagedImplStructSchema;
+import org.gradle.model.internal.manage.schema.ModelProperty;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.type.ModelType;
+
+public class ManagedImplStructStrategy extends ManagedImplStructSchemaExtractionStrategySupport {
+
+ private static final ManagedProxyFactory PROXY_FACTORY = new ManagedProxyFactory();
+ private static final ModelElementState NO_OP_MODEL_ELEMENT_STATE = new ModelElementState() {
+ @Override
+ public MutableModelNode getBackingNode() {
+ return null;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return null;
+ }
+
+ public Object get(String name) {
+ return null;
+ }
+
+ public void set(String name, Object value) {
+ }
+ };
+
+ public ManagedImplStructStrategy(ModelSchemaAspectExtractor aspectExtractor) {
+ super(aspectExtractor, null, null);
+ }
+
+ @Override
+ protected <R> ModelManagedImplStructSchema<R> createSchema(final ModelSchemaExtractionContext<R> extractionContext, final ModelSchemaStore store, ModelType<R> type, Iterable<ModelProperty<?>> properties, Iterable<ModelSchemaAspect> aspects) {
+ final ModelManagedImplStructSchema<R> schema = super.createSchema(extractionContext, store, type, properties, aspects);
+ extractionContext.addValidator(new Action<ModelSchemaExtractionContext<R>>() {
+ @Override
+ public void execute(ModelSchemaExtractionContext<R> validatorModelSchemaExtractionContext) {
+ ensureCanBeInstantiated(extractionContext, schema);
+ }
+ });
+ return schema;
+ }
+
+ @Override
+ protected <R> NodeInitializer createNodeInitializer(ModelManagedImplStructSchema<R> schema, ModelSchemaStore store) {
+ return new ManagedModelInitializer<R>(schema, store);
+ }
+
+ private <R> void ensureCanBeInstantiated(ModelSchemaExtractionContext<R> extractionContext, ModelManagedImplStructSchema<R> schema) {
+ try {
+ PROXY_FACTORY.createProxy(NO_OP_MODEL_ELEMENT_STATE, schema);
+ } catch (Throwable e) {
+ throw new InvalidManagedModelElementTypeException(extractionContext, "instance creation failed", e);
+ }
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGenerator.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGenerator.java
index eef190c..58461dd 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGenerator.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGenerator.java
@@ -16,22 +16,24 @@
package org.gradle.model.internal.manage.schema.extract;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import groovy.lang.MissingMethodException;
import groovy.lang.MissingPropertyException;
import org.apache.commons.lang.StringUtils;
-import org.gradle.internal.reflect.ClassDetails;
-import org.gradle.internal.reflect.ClassInspector;
-import org.gradle.internal.reflect.PropertyDetails;
import org.gradle.model.internal.core.MutableModelNode;
import org.gradle.model.internal.manage.instance.ManagedInstance;
import org.gradle.model.internal.manage.instance.ModelElementState;
+import org.gradle.model.internal.manage.schema.ModelProperty;
import org.objectweb.asm.*;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Map;
public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
/*
@@ -43,11 +45,12 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
*/
private static final String STATE_FIELD_NAME = "$state";
+ private static final String DELEGATE_FIELD_NAME = "$delegate";
private static final String CAN_CALL_SETTERS_FIELD_NAME = "$canCallSetters";
private static final String STATE_SET_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class), Type.getType(Object.class));
private static final String MANAGED_INSTANCE_TYPE = Type.getInternalName(ManagedInstance.class);
private static final Type MODEL_ELEMENT_STATE_TYPE = Type.getType(ModelElementState.class);
- private static final String CONSTRUCTOR_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, MODEL_ELEMENT_STATE_TYPE);
+ private static final String NO_DELEGATE_CONSTRUCTOR_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, MODEL_ELEMENT_STATE_TYPE);
private static final String TO_STRING_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(String.class));
private static final String GET_BACKING_NODE_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(MutableModelNode.class));
private static final String GET_PROPERTY_MISSING_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(String.class));
@@ -60,6 +63,17 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
private static final String METHOD_MISSING_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(String.class), Type.getType(Object.class));
private static final String SET_PROPERTY_MISSING_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(String.class), Type.getType(Object.class));
private static final String MISSING_METHOD_EXCEPTION_CONSTRUCTOR_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class), Type.getType(Class.class), Type.getType(Object[].class));
+ private static final Map<Class<?>, Class<?>> BOXED_TYPES = ImmutableMap.<Class<?>, Class<?>>builder()
+ .put(byte.class, Byte.class)
+ .put(short.class, Short.class)
+ .put(int.class, Integer.class)
+ .put(boolean.class, Boolean.class)
+ .put(float.class, Float.class)
+ .put(char.class, Character.class)
+ .put(double.class, Double.class)
+ .put(long.class, Long.class)
+ .build();
+
/**
* Generates an implementation of the given managed type.
@@ -72,48 +86,63 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
* <li>provide a constructor that accepts a {@link ModelElementState}, which will be used to implement the above.</li>
* </ul>
*/
- public <T> Class<? extends T> generate(Class<T> managedTypeClass) {
+ public <T, M extends T, D extends T> Class<? extends M> generate(Class<M> managedTypeClass, Class<D> delegateType, Iterable<ModelProperty<?>> properties) {
+ if (delegateType != null && !delegateType.isInterface()) {
+ throw new IllegalArgumentException("Delegate type must be null or an interface");
+ }
ClassWriter visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
String generatedTypeName = managedTypeClass.getName() + "_Impl";
Type generatedType = Type.getType("L" + generatedTypeName.replaceAll("\\.", "/") + ";");
Class<?> superclass;
- List<String> interfaceInternalNames;
+ ImmutableSet.Builder<String> interfaceInternalNames = ImmutableSet.builder();
+ interfaceInternalNames.add(MANAGED_INSTANCE_TYPE);
if (managedTypeClass.isInterface()) {
superclass = Object.class;
- interfaceInternalNames = ImmutableList.of(Type.getInternalName(managedTypeClass), MANAGED_INSTANCE_TYPE);
+ interfaceInternalNames = interfaceInternalNames.add(Type.getInternalName(managedTypeClass));
} else {
superclass = managedTypeClass;
- interfaceInternalNames = ImmutableList.of(MANAGED_INSTANCE_TYPE);
+ }
+ if (delegateType != null) {
+ interfaceInternalNames.add(Type.getInternalName(delegateType));
}
- generateProxyClass(visitor, managedTypeClass, interfaceInternalNames, generatedType, Type.getType(superclass));
+ generateProxyClass(visitor, managedTypeClass, delegateType, interfaceInternalNames.build(), generatedType, Type.getType(superclass), properties);
return defineClass(visitor, managedTypeClass.getClassLoader(), generatedTypeName);
}
- private void generateProxyClass(ClassWriter visitor, Class<?> managedTypeClass, List<String> interfaceInternalNames, Type generatedType, Type superclassType) {
+ private void generateProxyClass(ClassWriter visitor, Class<?> managedTypeClass, Class<?> delegateTypeClass, Collection<String> interfaceInternalNames,
+ Type generatedType, Type superclassType, Iterable<ModelProperty<?>> properties) {
declareClass(visitor, interfaceInternalNames, generatedType, superclassType);
declareStateField(visitor);
declareCanCallSettersField(visitor);
- writeConstructor(visitor, generatedType, superclassType);
+ writeConstructor(visitor, generatedType, superclassType, delegateTypeClass);
writeToString(visitor, generatedType, managedTypeClass);
writeManagedInstanceMethods(visitor, generatedType);
+ if (delegateTypeClass != null) {
+ declareDelegateField(visitor, delegateTypeClass);
+ writeDelegateMethods(visitor, generatedType, delegateTypeClass);
+ }
writeGroovyMethods(visitor, managedTypeClass);
- writeMutationMethods(visitor, generatedType, managedTypeClass);
+ writeMutationMethods(visitor, generatedType, managedTypeClass, properties);
visitor.visitEnd();
}
- private void declareClass(ClassVisitor visitor, List<String> interfaceInternalNames, Type generatedType, Type superclassType) {
+ private void declareClass(ClassVisitor visitor, Collection<String> interfaceInternalNames, Type generatedType, Type superclassType) {
visitor.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, generatedType.getInternalName(), null,
- superclassType.getInternalName(), Iterables.toArray(interfaceInternalNames, String.class));
+ superclassType.getInternalName(), Iterables.toArray(interfaceInternalNames, String.class));
}
private void declareStateField(ClassVisitor visitor) {
declareField(visitor, STATE_FIELD_NAME, ModelElementState.class);
}
+ private void declareDelegateField(ClassVisitor visitor, Class<?> delegateTypeClass) {
+ declareField(visitor, DELEGATE_FIELD_NAME, delegateTypeClass);
+ }
+
private void declareCanCallSettersField(ClassVisitor visitor) {
declareField(visitor, CAN_CALL_SETTERS_FIELD_NAME, Boolean.TYPE);
}
@@ -122,12 +151,24 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
visitor.visitField(Opcodes.ACC_PRIVATE, name, Type.getDescriptor(fieldClass), null, null);
}
- private void writeConstructor(ClassVisitor visitor, Type generatedType, Type superclassType) {
- MethodVisitor constructorVisitor = visitor.visitMethod(Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, CONSTRUCTOR_DESCRIPTOR, CONCRETE_SIGNATURE, NO_EXCEPTIONS);
+ private void writeConstructor(ClassVisitor visitor, Type generatedType, Type superclassType, Class<?> delegateTypeClass) {
+ String constructorDescriptor;
+ Type delegateType;
+ if (delegateTypeClass == null) {
+ delegateType = null;
+ constructorDescriptor = NO_DELEGATE_CONSTRUCTOR_DESCRIPTOR;
+ } else {
+ delegateType = Type.getType(delegateTypeClass);
+ constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, MODEL_ELEMENT_STATE_TYPE, delegateType);
+ }
+ MethodVisitor constructorVisitor = visitor.visitMethod(Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, constructorDescriptor, CONCRETE_SIGNATURE, NO_EXCEPTIONS);
constructorVisitor.visitCode();
invokeSuperConstructor(constructorVisitor, superclassType);
assignStateField(constructorVisitor, generatedType);
+ if (delegateType != null) {
+ assignDelegateField(constructorVisitor, generatedType, delegateType);
+ }
setCanCallSettersField(constructorVisitor, generatedType, true);
finishVisitingMethod(constructorVisitor);
}
@@ -223,33 +264,60 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
constructorVisitor.visitFieldInsn(Opcodes.PUTFIELD, generatedType.getInternalName(), STATE_FIELD_NAME, MODEL_ELEMENT_STATE_TYPE.getDescriptor());
}
+ private void assignDelegateField(MethodVisitor constructorVisitor, Type generatedType, Type delegateType) {
+ putThisOnStack(constructorVisitor);
+ putSecondMethodArgumentOnStack(constructorVisitor);
+ constructorVisitor.visitFieldInsn(Opcodes.PUTFIELD, generatedType.getInternalName(), DELEGATE_FIELD_NAME, delegateType.getDescriptor());
+ }
+
private void setCanCallSettersField(MethodVisitor methodVisitor, Type generatedType, boolean canCallSetters) {
putThisOnStack(methodVisitor);
methodVisitor.visitLdcInsn(canCallSetters);
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, generatedType.getInternalName(), CAN_CALL_SETTERS_FIELD_NAME, Type.BOOLEAN_TYPE.getDescriptor());
}
- private void writeMutationMethods(ClassVisitor visitor, Type generatedType, Class<?> managedTypeClass) {
- ClassDetails classDetails = ClassInspector.inspect(managedTypeClass);
- for (PropertyDetails property : classDetails.getProperties()) {
- for (Method method : property.getGetters()) {
- if (Modifier.isAbstract(method.getModifiers())) {
- writeGetter(visitor, generatedType, method);
- } else if (!Modifier.isFinal(method.getModifiers()) && !property.getName().equals("metaClass")) {
- writeNonAbstractMethodWrapper(visitor, generatedType, managedTypeClass, method);
- }
- }
- for (Method method : property.getSetters()) {
- writeSetter(visitor, generatedType, method);
+ private void writeMutationMethods(ClassVisitor visitor, Type generatedType, Class<?> managedTypeClass, Iterable<ModelProperty<?>> properties) {
+ for (ModelProperty<?> property : properties) {
+ String propertyName = property.getName();
+ switch (property.getStateManagementType()) {
+ case MANAGED:
+ Class<?> propertyTypeClass = property.getType().getConcreteClass();
+ writeGetter(visitor, generatedType, propertyName, propertyTypeClass);
+ if (property.isWritable()) {
+ writeSetter(visitor, generatedType, propertyName, propertyTypeClass);
+ }
+ break;
+
+ case UNMANAGED:
+ String getterName = getGetterName(propertyName);
+ Method getterMethod;
+ try {
+ getterMethod = managedTypeClass.getMethod(getterName);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException("Cannot find getter '" + getterName + "' on type " + managedTypeClass.getName(), e);
+ }
+ if (!Modifier.isFinal(getterMethod.getModifiers()) && !propertyName.equals("metaClass")) {
+ writeNonAbstractMethodWrapper(visitor, generatedType, managedTypeClass, getterMethod);
+ }
+ break;
+
+ case DELEGATED:
+ // We'll handle all delegated methods (not just properties) separately
+ break;
}
}
}
- private void writeSetter(ClassVisitor visitor, Type generatedType, Method method) {
- String propertyName = getPropertyName(method);
+ private void writeDelegateMethods(ClassVisitor visitor, Type generatedType, Class<?> delegateTypeClass) {
+ for (Method delegateMethod : delegateTypeClass.getMethods()) {
+ writeDelegatedMethod(visitor, generatedType, delegateTypeClass, delegateMethod);
+ }
+ }
+
+ private void writeSetter(ClassVisitor visitor, Type generatedType, String propertyName, Class<?> propertyTypeClass) {
Label calledOutsideOfConstructor = new Label();
- MethodVisitor methodVisitor = declareMethod(visitor, method);
+ MethodVisitor methodVisitor = declareMethod(visitor, getSetterName(propertyName), Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(propertyTypeClass)));
putCanCallSettersFieldValueOnStack(methodVisitor, generatedType);
jumpToLabelIfStackEvaluatesToTrue(methodVisitor, calledOutsideOfConstructor);
@@ -258,7 +326,10 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
writeLabel(methodVisitor, calledOutsideOfConstructor);
putStateFieldValueOnStack(methodVisitor, generatedType);
putConstantOnStack(methodVisitor, propertyName);
- putFirstMethodArgumentOnStack(methodVisitor);
+ putFirstMethodArgumentOnStack(methodVisitor, propertyTypeClass);
+ if (propertyTypeClass.isPrimitive()) {
+ boxType(methodVisitor, propertyTypeClass);
+ }
invokeStateSetMethod(methodVisitor);
finishVisitingMethod(methodVisitor);
@@ -293,23 +364,60 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
}
private MethodVisitor declareMethod(ClassVisitor visitor, Method method) {
- MethodVisitor methodVisitor = visitor.visitMethod(Opcodes.ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), CONCRETE_SIGNATURE, NO_EXCEPTIONS);
+ return declareMethod(visitor, method.getName(), Type.getMethodDescriptor(method));
+ }
+
+ private MethodVisitor declareMethod(ClassVisitor visitor, String methodName, String methodDescriptor) {
+ MethodVisitor methodVisitor = visitor.visitMethod(Opcodes.ACC_PUBLIC, methodName, methodDescriptor, CONCRETE_SIGNATURE, NO_EXCEPTIONS);
methodVisitor.visitCode();
return methodVisitor;
}
+ private void putFirstMethodArgumentOnStack(MethodVisitor methodVisitor, Class<?> argType) {
+ int loadCode = selectOpcode(argType, Opcodes.ALOAD, Opcodes.ILOAD, Opcodes.LLOAD, Opcodes.FLOAD, Opcodes.DLOAD);
+ methodVisitor.visitVarInsn(loadCode, 1);
+ }
+
+ private int selectOpcode(Class<?> argType, int defaultValue, int intCategoryValue, int longValue, int floatValue, int doubleValue) {
+ int code = defaultValue;
+ if (argType.isPrimitive()) {
+ if (byte.class == argType || short.class == argType || int.class == argType || char.class == argType || boolean.class == argType) {
+ code = intCategoryValue;
+ } else if (long.class == argType) {
+ code = longValue;
+ } else if (float.class == argType) {
+ code = floatValue;
+ } else if (double.class == argType) {
+ code = doubleValue;
+ }
+ }
+ return code;
+ }
+
private void putFirstMethodArgumentOnStack(MethodVisitor methodVisitor) {
- methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
+ putFirstMethodArgumentOnStack(methodVisitor, Object.class);
+ }
+
+ private void putSecondMethodArgumentOnStack(MethodVisitor methodVisitor) {
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 2);
}
private void putMethodArgumentOnStack(MethodVisitor methodVisitor, int index) {
methodVisitor.visitVarInsn(Opcodes.ALOAD, index);
}
+ private void putBooleanMethodArgumentOnStack(MethodVisitor methodVisitor, int index) {
+ methodVisitor.visitVarInsn(Opcodes.ILOAD, index);
+ }
+
private void putStateFieldValueOnStack(MethodVisitor methodVisitor, Type generatedType) {
putFieldValueOnStack(methodVisitor, generatedType, STATE_FIELD_NAME, ModelElementState.class);
}
+ private void putDelegateFieldValueOnStack(MethodVisitor methodVisitor, Type generatedType, Class<?> delegateTypeClass) {
+ putFieldValueOnStack(methodVisitor, generatedType, DELEGATE_FIELD_NAME, delegateTypeClass);
+ }
+
private void putCanCallSettersFieldValueOnStack(MethodVisitor methodVisitor, Type generatedType) {
putFieldValueOnStack(methodVisitor, generatedType, CAN_CALL_SETTERS_FIELD_NAME, Boolean.TYPE);
}
@@ -319,24 +427,80 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, generatedType.getInternalName(), name, Type.getDescriptor(fieldClass));
}
- private void writeGetter(ClassVisitor visitor, Type generatedType, Method method) {
- String propertyName = getPropertyName(method);
+ private void writeGetter(ClassVisitor visitor, Type generatedType, String propertyName, Class<?> propertyTypeClass) {
+ List<String> getters = new ArrayList<String>(2);
+ getters.add(getGetterName(propertyName));
+ if (propertyTypeClass == boolean.class) {
+ getters.add(getIsGetterName(propertyName));
+ }
+ for (String getter : getters) {
+ MethodVisitor methodVisitor = declareMethod(visitor, getter, Type.getMethodDescriptor(Type.getType(propertyTypeClass)));
+
+ putStateFieldValueOnStack(methodVisitor, generatedType);
+ putConstantOnStack(methodVisitor, propertyName);
+ invokeStateGetMethod(methodVisitor);
+ castFirstStackElement(methodVisitor, propertyTypeClass);
+ finishVisitingMethod(methodVisitor, returnCode(propertyTypeClass));
+ }
- MethodVisitor methodVisitor = declareMethod(visitor, method);
+ }
- putStateFieldValueOnStack(methodVisitor, generatedType);
- putConstantOnStack(methodVisitor, propertyName);
- invokeStateGetMethod(methodVisitor);
- castFirstStackElement(methodVisitor, method.getReturnType());
- finishVisitingMethod(methodVisitor, Opcodes.ARETURN);
+ private int returnCode(Class<?> propertyTypeClass) {
+ return selectOpcode(propertyTypeClass, Opcodes.ARETURN, Opcodes.IRETURN, Opcodes.LRETURN, Opcodes.FRETURN, Opcodes.DRETURN);
+ }
+
+ private static String getGetterName(String propertyName) {
+ return "get" + StringUtils.capitalize(propertyName);
+ }
+
+ private static String getIsGetterName(String propertyName) {
+ return "is" + StringUtils.capitalize(propertyName);
+ }
+
+ private static String getSetterName(String propertyName) {
+ return "set" + StringUtils.capitalize(propertyName);
}
private void castFirstStackElement(MethodVisitor methodVisitor, Class<?> returnType) {
- methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(returnType));
+ if (returnType.isPrimitive()) {
+ unboxType(methodVisitor, returnType);
+ } else {
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(returnType));
+ }
+ }
+
+ private void boxType(MethodVisitor methodVisitor, Class<?> primitiveType) {
+ Class<?> boxedType = BOXED_TYPES.get(primitiveType);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(boxedType), "valueOf", "(" + Type.getDescriptor(primitiveType) + ")" + Type.getDescriptor(boxedType), false);
}
- private String getPropertyName(Method method) {
- return StringUtils.uncapitalize(method.getName().substring(3));
+ private void unboxType(MethodVisitor methodVisitor, Class<?> primitiveType) {
+ // Float f = (Float) tmp
+ // f==null?0:f.floatValue()
+ Class<?> boxedType = BOXED_TYPES.get(primitiveType);
+ methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(boxedType));
+ methodVisitor.visitInsn(Opcodes.DUP);
+ Label exit = new Label();
+ Label elseValue = new Label();
+ methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, elseValue);
+ methodVisitor.visitInsn(Opcodes.POP);
+ pushDefaultValue(methodVisitor, primitiveType);
+ methodVisitor.visitJumpInsn(Opcodes.GOTO, exit);
+ methodVisitor.visitLabel(elseValue);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(boxedType), primitiveType.getSimpleName() + "Value", "()" + Type.getDescriptor(primitiveType), false);
+ methodVisitor.visitLabel(exit);
+ }
+
+ private void pushDefaultValue(MethodVisitor methodVisitor, Class<?> primitiveType) {
+ int ins = Opcodes.ICONST_0;
+ if (long.class == primitiveType) {
+ ins = Opcodes.LCONST_0;
+ } else if (double.class == primitiveType) {
+ ins = Opcodes.DCONST_0;
+ } else if (float.class == primitiveType) {
+ ins = Opcodes.FCONST_0;
+ }
+ methodVisitor.visitInsn(ins);
}
private void invokeStateGetMethod(MethodVisitor methodVisitor) {
@@ -370,6 +534,32 @@ public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
methodVisitor.visitEnd();
}
+ private void writeDelegatedMethod(ClassVisitor visitor, Type generatedType, Class<?> delegateTypeClass, Method method) {
+ MethodVisitor methodVisitor = declareMethod(visitor, method);
+ invokeDelegateMethod(methodVisitor, generatedType, delegateTypeClass, method);
+ final Class<?> returnType = method.getReturnType();
+ if (returnType == Void.TYPE) {
+ finishVisitingMethod(methodVisitor);
+ } else if (returnType == Boolean.TYPE) {
+ finishVisitingMethod(methodVisitor, Opcodes.IRETURN);
+ } else {
+ finishVisitingMethod(methodVisitor, Opcodes.ARETURN);
+ }
+ }
+
+ private void invokeDelegateMethod(MethodVisitor methodVisitor, Type generatedType, Class<?> delegateTypeClass, Method method) {
+ putDelegateFieldValueOnStack(methodVisitor, generatedType, delegateTypeClass);
+ Class<?>[] parameterTypes = method.getParameterTypes();
+ for (int paramNo = 0; paramNo < parameterTypes.length; paramNo++) {
+ if (parameterTypes[paramNo] == Boolean.TYPE) {
+ putBooleanMethodArgumentOnStack(methodVisitor, paramNo + 1);
+ } else {
+ putMethodArgumentOnStack(methodVisitor, paramNo + 1);
+ }
+ }
+ methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(delegateTypeClass), method.getName(), Type.getMethodDescriptor(method), true);
+ }
+
private void invokeSuperMethod(MethodVisitor methodVisitor, Class<?> superClass, Method method) {
putThisOnStack(methodVisitor);
methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(superClass), method.getName(), Type.getMethodDescriptor(method), false);
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedSetStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedSetStrategy.java
index 50c9897..093bb55 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedSetStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ManagedSetStrategy.java
@@ -16,23 +16,77 @@
package org.gradle.model.internal.manage.schema.extract;
+import com.google.common.base.Function;
import net.jcip.annotations.ThreadSafe;
-import org.gradle.internal.Factory;
import org.gradle.model.collection.ManagedSet;
+import org.gradle.model.internal.core.*;
+import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
+import org.gradle.model.internal.inspect.ManagedChildNodeCreatorStrategy;
+import org.gradle.model.internal.inspect.ProjectionOnlyNodeInitializer;
+import org.gradle.model.internal.manage.schema.ModelCollectionSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.type.ModelType;
-
-import java.util.Collections;
+import org.gradle.model.internal.type.ModelTypes;
@ThreadSafe
public class ManagedSetStrategy extends SetStrategy {
- public ManagedSetStrategy(Factory<String> supportedTypeDescriptions) {
+ public ManagedSetStrategy() {
super(new ModelType<ManagedSet<?>>() {
- }, supportedTypeDescriptions);
+ });
}
@Override
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.emptySet();
+ protected <T, E> Function<ModelCollectionSchema<T, E>, NodeInitializer> getNodeInitializer(final ModelSchemaStore store) {
+ return new Function<ModelCollectionSchema<T, E>, NodeInitializer>() {
+ @Override
+ public NodeInitializer apply(ModelCollectionSchema<T, E> schema) {
+ return new ProjectionOnlyNodeInitializer(
+ TypedModelProjection.of(
+ ModelTypes.managedSet(schema.getElementType()),
+ new ManagedSetModelViewFactory<E>(schema.getElementType(), store)
+ )
+ );
+ }
+ };
}
+
+ private static class ManagedSetModelViewFactory<T> implements ModelViewFactory<ManagedSet<T>> {
+ private final ModelType<T> elementType;
+ private final ModelSchemaStore store;
+
+ public ManagedSetModelViewFactory(ModelType<T> elementType, ModelSchemaStore store) {
+ this.elementType = elementType;
+ this.store = store;
+ }
+
+ @Override
+ public ModelView<ManagedSet<T>> toView(MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean writable) {
+ ModelType<ManagedSet<T>> setType = ModelTypes.managedSet(elementType);
+ DefaultModelViewState state = new DefaultModelViewState(setType, ruleDescriptor, writable, !writable);
+ NodeBackedModelSet<T> set = new NodeBackedModelSet<T>(setType.toString() + " '" + modelNode.getPath() + "'", elementType, ruleDescriptor, modelNode, state, new ManagedChildNodeCreatorStrategy<T>(store));
+ return InstanceModelView.of(modelNode.getPath(), setType, set, state.closer());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ManagedSetModelViewFactory<?> that = (ManagedSetModelViewFactory<?>) o;
+ return elementType.equals(that.elementType);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return elementType.hashCode();
+ }
+ }
+
+
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelMapStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelMapStrategy.java
index 3982eec..cee6555 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelMapStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelMapStrategy.java
@@ -16,16 +16,20 @@
package org.gradle.model.internal.manage.schema.extract;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import net.jcip.annotations.ThreadSafe;
-import org.gradle.api.Action;
-import org.gradle.model.Managed;
+import org.gradle.internal.Actions;
import org.gradle.model.ModelMap;
-import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.collection.internal.ModelMapModelProjection;
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.inspect.ManagedChildNodeCreatorStrategy;
+import org.gradle.model.internal.inspect.ProjectionOnlyNodeInitializer;
+import org.gradle.model.internal.manage.schema.ModelCollectionSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
import org.gradle.model.internal.type.ModelType;
-import java.util.Collections;
import java.util.List;
@ThreadSafe
@@ -36,7 +40,7 @@ public class ModelMapStrategy implements ModelSchemaExtractionStrategy {
// TODO extract common stuff from this and ModelSet and reuse
- public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, final ModelSchemaCache cache) {
+ public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaStore store, final ModelSchemaCache cache) {
ModelType<T> type = extractionContext.getType();
if (MODEL_MAP_MODEL_TYPE.isAssignableFrom(type)) {
if (!type.getRawClass().equals(ModelMap.class)) {
@@ -57,27 +61,22 @@ public class ModelMapStrategy implements ModelSchemaExtractionStrategy {
throw new InvalidManagedModelElementTypeException(extractionContext, String.format("%1$s cannot be used as type parameter of %1$s.", ModelMap.class.getName()));
}
- ModelSchema<T> schema = ModelSchema.collection(extractionContext.getType(), elementType);
- ModelSchemaExtractionContext<?> typeParamExtractionContext = extractionContext.child(elementType, "element type", new Action<ModelSchemaExtractionContext<?>>() {
- public void execute(ModelSchemaExtractionContext<?> context) {
- ModelType<?> elementType = context.getType();
- ModelSchema<?> typeParamSchema = cache.get(elementType);
-
- if (!typeParamSchema.getKind().isManaged()) {
- throw new InvalidManagedModelElementTypeException(context.getParent(), String.format(
- "cannot create a model map of type %s as it is not a %s type.",
- elementType, Managed.class.getName()
- ));
- }
- }
- });
- return new ModelSchemaExtractionResult<T>(schema, ImmutableList.of(typeParamExtractionContext));
+ return gettModelSchemaExtractionResult(extractionContext, cache, elementType, store);
} else {
return null;
}
}
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.singleton(MODEL_MAP_MODEL_TYPE + " of a managed type");
+ private <T, E> ModelSchemaExtractionResult<T> gettModelSchemaExtractionResult(ModelSchemaExtractionContext<T> extractionContext, final ModelSchemaCache cache, ModelType<E> elementType, final ModelSchemaStore store) {
+ ModelCollectionSchema<T, E> schema = new ModelCollectionSchema<T, E>(extractionContext.getType(), elementType, new Function<ModelCollectionSchema<T, E>, NodeInitializer>() {
+ @Override
+ public NodeInitializer apply(ModelCollectionSchema<T, E> input) {
+ final ManagedChildNodeCreatorStrategy<E> childCreator = new ManagedChildNodeCreatorStrategy<E>(store);
+ return new ProjectionOnlyNodeInitializer(ModelMapModelProjection.managed(input.getElementType(), childCreator));
+ }
+ });
+ ModelSchemaExtractionContext<?> typeParamExtractionContext = extractionContext.child(elementType, "element type", Actions.doNothing());
+ return new ModelSchemaExtractionResult<T>(schema, ImmutableList.of(typeParamExtractionContext));
}
+
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelPropertyExtractionResult.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelPropertyExtractionResult.java
new file mode 100644
index 0000000..11a1569
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelPropertyExtractionResult.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import org.gradle.api.Nullable;
+import org.gradle.model.internal.manage.schema.ModelProperty;
+
+public class ModelPropertyExtractionResult<T> {
+ private final ModelProperty<T> property;
+ private final PropertyAccessorExtractionContext getter;
+ private final PropertyAccessorExtractionContext setter;
+
+ public ModelPropertyExtractionResult(ModelProperty<T> property, PropertyAccessorExtractionContext getter, @Nullable PropertyAccessorExtractionContext setter) {
+ this.property = property;
+ this.getter = getter;
+ this.setter = setter;
+ }
+
+ public ModelProperty<T> getProperty() {
+ return property;
+ }
+
+ public PropertyAccessorExtractionContext getGetter() {
+ return getter;
+ }
+
+ @Nullable
+ public PropertyAccessorExtractionContext getSetter() {
+ return setter;
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspect.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspect.java
new file mode 100644
index 0000000..f9ff314
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspect.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+public interface ModelSchemaAspect {
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractionResult.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractionResult.java
new file mode 100644
index 0000000..a3c8408
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractionResult.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import org.gradle.api.Action;
+import org.gradle.api.Nullable;
+
+public class ModelSchemaAspectExtractionResult {
+ private final ModelSchemaAspect aspect;
+ private final Action<? super ModelSchemaExtractionContext<?>> validator;
+
+ public ModelSchemaAspectExtractionResult(ModelSchemaAspect aspect) {
+ this(aspect, null);
+ }
+
+ public ModelSchemaAspectExtractionResult(ModelSchemaAspect aspect, @Nullable Action<? super ModelSchemaExtractionContext<?>> validator) {
+ this.aspect = aspect;
+ this.validator = validator;
+ }
+
+ public ModelSchemaAspect getAspect() {
+ return aspect;
+ }
+
+ @Nullable
+ public Action<? super ModelSchemaExtractionContext<?>> getValidator() {
+ return validator;
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractionStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractionStrategy.java
new file mode 100644
index 0000000..201dcc0
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractionStrategy.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import org.gradle.api.Nullable;
+
+import java.util.List;
+
+public interface ModelSchemaAspectExtractionStrategy {
+ @Nullable
+ ModelSchemaAspectExtractionResult extract(ModelSchemaExtractionContext<?> extractionContext, List<ModelPropertyExtractionResult<?>> propertyResults);
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractor.java
new file mode 100644
index 0000000..1bfab0f
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaAspectExtractor.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.gradle.api.Action;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class ModelSchemaAspectExtractor {
+ private final List<ModelSchemaAspectExtractionStrategy> strategies;
+
+ public ModelSchemaAspectExtractor() {
+ this(Collections.<ModelSchemaAspectExtractionStrategy>emptyList());
+ }
+
+ public ModelSchemaAspectExtractor(Collection<ModelSchemaAspectExtractionStrategy> strategies) {
+ this.strategies = ImmutableList.copyOf(strategies);
+ }
+
+ public <T> List<ModelSchemaAspect> extract(ModelSchemaExtractionContext<T> extractionContext, List<ModelPropertyExtractionResult<?>> propertyResults) {
+ List<ModelSchemaAspect> aspects = Lists.newArrayList();
+ for (ModelSchemaAspectExtractionStrategy strategy : strategies) {
+ ModelSchemaAspectExtractionResult result = strategy.extract(extractionContext, propertyResults);
+ if (result != null) {
+ aspects.add(result.getAspect());
+ Action<? super ModelSchemaExtractionContext<?>> validator = result.getValidator();
+ if (validator != null) {
+ extractionContext.addValidator(validator);
+ }
+ }
+ }
+ return aspects;
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionContext.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionContext.java
index a34f878..1076f20 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionContext.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionContext.java
@@ -38,16 +38,13 @@ public class ModelSchemaExtractionContext<T> {
this.type = type;
this.description = description;
this.validators = Lists.newArrayListWithCapacity(2);
-
- validators.add(validator);
+ if (validator != null) {
+ validators.add(validator);
+ }
}
public static <T> ModelSchemaExtractionContext<T> root(ModelType<T> type) {
- return new ModelSchemaExtractionContext<T>(null, type, null, Actions.doNothing());
- }
-
- public static <T> ModelSchemaExtractionContext<T> root(ModelType<T> type, Action<? super ModelSchemaExtractionContext<T>> validator) {
- return new ModelSchemaExtractionContext<T>(null, type, null, validator);
+ return new ModelSchemaExtractionContext<T>(null, type, null, null);
}
/**
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionStrategy.java
index 09013bc..04649f7 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractionStrategy.java
@@ -17,13 +17,12 @@
package org.gradle.model.internal.manage.schema.extract;
import org.gradle.api.Nullable;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
public interface ModelSchemaExtractionStrategy {
@Nullable
- public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaCache cache);
-
- Iterable<String> getSupportedManagedTypes();
+ <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaStore store, ModelSchemaCache cache);
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractor.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractor.java
index f9f99b5..eac5ad3 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractor.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractor.java
@@ -23,36 +23,45 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import net.jcip.annotations.ThreadSafe;
-import org.gradle.internal.Factory;
import org.gradle.internal.SystemProperties;
+import org.gradle.model.Managed;
+import org.gradle.model.ModelMap;
+import org.gradle.model.ModelSet;
import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
import org.gradle.model.internal.type.ModelType;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Queue;
@ThreadSafe
-class ModelSchemaExtractor {
+public class ModelSchemaExtractor {
- private final Factory<String> supportedTypeDescriptions = new Factory<String>() {
- public String create() {
- return getSupportedTypesDescription();
- }
- };
- private final List<ModelSchemaExtractionStrategy> strategies = ImmutableList.of(
- new PrimitiveStrategy(),
- new EnumStrategy(),
- new JdkValueTypeStrategy(),
- new ModelSetStrategy(supportedTypeDescriptions),
- new ManagedSetStrategy(supportedTypeDescriptions),
- new StructStrategy(supportedTypeDescriptions),
- new SpecializedMapStrategy(),
- new ModelMapStrategy(),
- new UnmanagedStrategy()
- );
-
- public <T> ModelSchema<T> extract(ModelType<T> type, ModelSchemaCache cache) {
+ private final List<? extends ModelSchemaExtractionStrategy> strategies;
+
+ public ModelSchemaExtractor() {
+ this(Collections.<ModelSchemaExtractionStrategy>emptyList(), new ModelSchemaAspectExtractor());
+ }
+
+ public ModelSchemaExtractor(List<? extends ModelSchemaExtractionStrategy> strategies, ModelSchemaAspectExtractor aspectExtractor) {
+ this.strategies = ImmutableList.<ModelSchemaExtractionStrategy>builder()
+ .addAll(strategies)
+ .add(new PrimitiveStrategy())
+ .add(new EnumStrategy())
+ .add(new JdkValueTypeStrategy())
+ .add(new ModelSetStrategy())
+ .add(new ManagedSetStrategy())
+ .add(new SpecializedMapStrategy())
+ .add(new ModelMapStrategy())
+ .add(new ManagedImplStructStrategy(aspectExtractor))
+ .add(new UnmanagedImplStructStrategy(aspectExtractor))
+ .build();
+ }
+
+ public <T> ModelSchema<T> extract(ModelType<T> type, ModelSchemaStore store, ModelSchemaCache cache) {
ModelSchemaExtractionContext<T> context = ModelSchemaExtractionContext.root(type);
List<ModelSchemaExtractionContext<?>> validations = Lists.newLinkedList();
Queue<ModelSchemaExtractionContext<?>> unsatisfiedDependencies = Lists.newLinkedList();
@@ -60,7 +69,7 @@ class ModelSchemaExtractor {
validations.add(extractionContext);
while (extractionContext != null) {
- ModelSchemaExtractionResult<?> nextSchema = extractSchema(extractionContext, cache);
+ ModelSchemaExtractionResult<?> nextSchema = extractSchema(extractionContext, store, cache);
Iterable<? extends ModelSchemaExtractionContext<?>> dependencies = nextSchema.getDependencies();
Iterables.addAll(validations, dependencies);
pushUnsatisfiedDependencies(dependencies, unsatisfiedDependencies, cache);
@@ -82,7 +91,7 @@ class ModelSchemaExtractor {
}));
}
- private <T> ModelSchemaExtractionResult<T> extractSchema(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaCache cache) {
+ private <T> ModelSchemaExtractionResult<T> extractSchema(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaStore store, ModelSchemaCache cache) {
final ModelType<T> type = extractionContext.getType();
ModelSchema<T> cached = cache.get(type);
if (cached != null) {
@@ -90,7 +99,7 @@ class ModelSchemaExtractor {
}
for (ModelSchemaExtractionStrategy strategy : strategies) {
- ModelSchemaExtractionResult<T> result = strategy.extract(extractionContext, cache);
+ ModelSchemaExtractionResult<T> result = strategy.extract(extractionContext, store, cache);
if (result != null) {
cache.set(type, result.getSchema());
return result;
@@ -101,7 +110,7 @@ class ModelSchemaExtractor {
throw new IllegalStateException("No extraction strategy found for type: " + type);
}
- private String getSupportedTypesDescription() {
+ public static String getManageablePropertyTypesDescription() {
return Joiner.on(SystemProperties.getInstance().getLineSeparator()).join(Iterables.transform(getSupportedTypes(), new Function<String, String>() {
public String apply(String input) {
return " - " + input;
@@ -109,12 +118,18 @@ class ModelSchemaExtractor {
}));
}
- private Iterable<String> getSupportedTypes() {
- return Iterables.concat(Iterables.transform(strategies, new Function<ModelSchemaExtractionStrategy, Iterable<String>>() {
- public Iterable<String> apply(ModelSchemaExtractionStrategy input) {
- return input.getSupportedManagedTypes();
- }
- }));
+ private static Iterable<String> getSupportedTypes() {
+ return Arrays.asList(
+ "interfaces and abstract classes annotated with " + Managed.class.getName(),
+ "JDK value types: " + Joiner.on(", ").join(Iterables.transform(JdkValueTypeStrategy.TYPES, new Function<ModelType<?>, Object>() {
+ public Object apply(ModelType<?> input) {
+ return input.getRawClass().getSimpleName();
+ }
+ })),
+ "Enum types",
+ ModelMap.class.getName() + " of a managed type",
+ ModelSet.class.getName() + " of a managed type"
+ );
}
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaUtils.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaUtils.java
new file mode 100644
index 0000000..26b902c
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSchemaUtils.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.collect.*;
+import groovy.lang.GroovyObject;
+import org.gradle.api.Nullable;
+import org.gradle.internal.reflect.MethodSignatureEquivalence;
+import org.gradle.model.Managed;
+import org.gradle.util.CollectionUtils;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.*;
+
+public class ModelSchemaUtils {
+ private static final Equivalence<Method> METHOD_EQUIVALENCE = new MethodSignatureEquivalence();
+
+ private static final Set<Equivalence.Wrapper<Method>> IGNORED_METHODS = ImmutableSet.copyOf(
+ Iterables.transform(
+ Iterables.concat(
+ Arrays.asList(Object.class.getMethods()),
+ Arrays.asList(GroovyObject.class.getMethods())
+ ), new Function<Method, Equivalence.Wrapper<Method>>() {
+ public Equivalence.Wrapper<Method> apply(@Nullable Method input) {
+ return METHOD_EQUIVALENCE.wrap(input);
+ }
+ }
+ )
+ );
+
+ /**
+ * Returns all candidate methods for schema generation declared by the given type and its super-types indexed by name.
+ *
+ * <p>Overriding methods are <em>not</em> folded like in the case of {@link Class#getMethods()}. This allows
+ * the caller to identify annotations declared at different levels in the hierarchy, and also to identify all
+ * the classes declaring a certain method.</p>
+ *
+ * <p>Method candidates exclude:</p>
+ * <ul>
+ * <li>methods defined by {@link Object} and their overrides</li>
+ * <li>methods defined by {@link GroovyObject} and their overrides</li>
+ * <li>synthetic methods</li>
+ * </ul>
+ *
+ * <p>Methods are returned in the order of their specialization, most specialized methods first.</p>
+ */
+ public static Multimap<String, Method> getCandidateMethods(Class<?> clazz) {
+ final ImmutableListMultimap.Builder<String, Method> methodsBuilder = ImmutableListMultimap.builder();
+ walkTypeHierarchy(clazz, new TypeVisitor() {
+ @Override
+ public void visitType(Class<?> type) {
+ for (Method method : type.getDeclaredMethods()) {
+ int modifiers = method.getModifiers();
+ if (method.isSynthetic() || Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
+ continue;
+ }
+
+ // Ignore overrides of Object and GroovyObject methods
+ if (IGNORED_METHODS.contains(METHOD_EQUIVALENCE.wrap(method))) {
+ continue;
+ }
+
+ methodsBuilder.put(method.getName(), method);
+ }
+ }
+ });
+ return methodsBuilder.build();
+ }
+
+ /**
+ * Visits all types in a type hierarchy in breadth-first order, super-classes first and then implemented interfaces.
+ *
+ * @param clazz the type of whose type hierarchy to visit.
+ * @param visitor the visitor to call for each type in the hierarchy.
+ */
+ public static void walkTypeHierarchy(Class<?> clazz, TypeVisitor visitor) {
+ Set<Class<?>> seenInterfaces = Sets.newHashSet();
+ Queue<Class<?>> queue = new ArrayDeque<Class<?>>();
+ queue.add(clazz);
+ Class<?> type;
+ while ((type = queue.poll()) != null) {
+ // Do not process Object's or GroovyObject's methods
+ if (type.equals(Object.class) || type.equals(GroovyObject.class)) {
+ continue;
+ }
+
+ visitor.visitType(type);
+
+ Class<?> superclass = type.getSuperclass();
+ if (superclass != null) {
+ queue.add(superclass);
+ }
+ for (Class<?> iface : type.getInterfaces()) {
+ if (seenInterfaces.add(iface)) {
+ queue.add(iface);
+ }
+ }
+ }
+ }
+
+ public interface TypeVisitor {
+ void visitType(Class<?> type);
+ }
+
+ /**
+ * Tries to find the most specific declaration of a method that is not declared in a {@link Proxy} class.
+ * Mock objects generated via {@link Proxy#newProxyInstance(ClassLoader, Class[], java.lang.reflect.InvocationHandler)}
+ * lose their generic type parameters and can confuse schema extraction. This way we can ignore these
+ * declarations, and use the ones from the proxied interfaces instead.
+ *
+ * @param declaringMethods declarations of the same method from different types in the type hierarchy. They are
+ * expected to be in order of specificity, i.e. overrides preceding overridden declarations.
+ * @return the most specific declaration of the method.
+ * @throws IllegalArgumentException if no declaration can be found.
+ */
+ public static Method findMostSpecificMethod(Iterable<Method> declaringMethods) {
+ for (Method method : declaringMethods) {
+ if (Proxy.isProxyClass(method.getDeclaringClass())) {
+ continue;
+ }
+ return method;
+ }
+ throw new IllegalArgumentException("Cannot find most-specific declaration of method. Declarations checked: " + declaringMethods);
+ }
+
+ /**
+ * Returns whether the most specific of the given methods has been declared in a <code>@</code>{@link Managed} type or not.
+ */
+ public static boolean isMethodDeclaredInManagedType(Iterable<Method> declarations) {
+ Method mostSpecificDeclaration = findMostSpecificMethod(declarations);
+ return isMethodDeclaredInManagedType(mostSpecificDeclaration);
+ }
+
+ /**
+ * Returns whether the method has been declared in a <code>@</code>{@link Managed} type or not.
+ */
+ public static boolean isMethodDeclaredInManagedType(Method method) {
+ return method.getDeclaringClass().isAnnotationPresent(Managed.class);
+ }
+
+ /**
+ * Returns the different overloaded versions of a method, or null if there are no overloads.
+ */
+ @Nullable
+ public static List<Method> getOverloadedMethods(Collection<Method> methods) {
+ if (methods.size() > 1) {
+ List<Method> deduped = CollectionUtils.dedup(methods, METHOD_EQUIVALENCE);
+ if (deduped.size() > 1) {
+ return deduped;
+ }
+ }
+ return null;
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSetStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSetStrategy.java
index a2b5b72..b63d7bf 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSetStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/ModelSetStrategy.java
@@ -16,17 +16,78 @@
package org.gradle.model.internal.manage.schema.extract;
+import com.google.common.base.Function;
import net.jcip.annotations.ThreadSafe;
-import org.gradle.internal.Factory;
import org.gradle.model.ModelSet;
+import org.gradle.model.internal.core.*;
+import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
+import org.gradle.model.internal.inspect.ManagedChildNodeCreatorStrategy;
+import org.gradle.model.internal.inspect.ProjectionOnlyNodeInitializer;
+import org.gradle.model.internal.manage.schema.ModelCollectionSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.type.ModelType;
+import org.gradle.model.internal.type.ModelTypes;
@ThreadSafe
public class ModelSetStrategy extends SetStrategy {
- public ModelSetStrategy(Factory<String> supportedTypeDescriptions) {
+ public ModelSetStrategy() {
super(new ModelType<ModelSet<?>>() {
- }, supportedTypeDescriptions);
+ });
}
+ @Override
+ protected <T, E> Function<ModelCollectionSchema<T, E>, NodeInitializer> getNodeInitializer(final ModelSchemaStore store) {
+ return new Function<ModelCollectionSchema<T, E>, NodeInitializer>() {
+ @Override
+ public NodeInitializer apply(ModelCollectionSchema<T, E> schema) {
+ return new ProjectionOnlyNodeInitializer(
+ TypedModelProjection.of(
+ ModelTypes.modelSet(schema.getElementType()),
+ new ModelSetModelViewFactory<E>(schema.getElementType(), store)
+ )
+ );
+ }
+ };
+ }
+
+ private static class ModelSetModelViewFactory<T> implements ModelViewFactory<ModelSet<T>> {
+ private final ModelType<T> elementType;
+ private final ModelSchemaStore store;
+
+ public ModelSetModelViewFactory(ModelType<T> elementType, ModelSchemaStore store) {
+ this.elementType = elementType;
+ this.store = store;
+ }
+
+ @Override
+ public ModelView<ModelSet<T>> toView(MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean writable) {
+ ModelType<ModelSet<T>> setType = ModelTypes.modelSet(elementType);
+ DefaultModelViewState state = new DefaultModelViewState(setType, ruleDescriptor, writable, !writable);
+ final ManagedChildNodeCreatorStrategy<T> childCreator = new ManagedChildNodeCreatorStrategy<T>(store);
+ NodeBackedModelSet<T> set = new NodeBackedModelSet<T>(setType.toString() + " '" + modelNode.getPath() + "'", elementType, ruleDescriptor, modelNode, state, childCreator);
+ return InstanceModelView.of(modelNode.getPath(), setType, set, state.closer());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ModelSetModelViewFactory<?> that = (ModelSetModelViewFactory<?>) o;
+ return elementType.equals(that.elementType);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return elementType.hashCode();
+ }
+ }
+
+
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/PrimitiveStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/PrimitiveStrategy.java
index 9df8882..fc5b126 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/PrimitiveStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/PrimitiveStrategy.java
@@ -16,40 +16,20 @@
package org.gradle.model.internal.manage.schema.extract;
-import com.google.common.collect.ImmutableMap;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.ModelValueSchema;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
import org.gradle.model.internal.type.ModelType;
-import java.util.Collections;
-import java.util.Map;
-
public class PrimitiveStrategy implements ModelSchemaExtractionStrategy {
- private final static Map<ModelType<?>, Class<?>> BOXED_REPLACEMENTS = ImmutableMap.<ModelType<?>, Class<?>>builder()
- .put(ModelType.of(Boolean.TYPE), Boolean.class)
- .put(ModelType.of(Character.TYPE), Character.class)
- .put(ModelType.of(Float.TYPE), Double.class)
- .put(ModelType.of(Integer.TYPE), Integer.class)
- .put(ModelType.of(Long.TYPE), Long.class)
- .put(ModelType.of(Short.TYPE), Integer.class)
- .put(ModelType.of(Double.TYPE), Double.class)
- .build();
-
-
- public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaCache cache) {
+ public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaStore store, ModelSchemaCache cache) {
ModelType<T> type = extractionContext.getType();
if (type.getRawClass().isPrimitive()) {
- Class<?> replacementType = BOXED_REPLACEMENTS.get(type);
- if (replacementType != null) {
- throw new InvalidManagedModelElementTypeException(extractionContext, String.format("type is not supported, please use %s instead", replacementType.getName()));
- }
+ return new ModelSchemaExtractionResult<T>(new ModelValueSchema<T>(type));
}
return null;
}
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.emptySet();
- }
-
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/PropertyAccessorExtractionContext.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/PropertyAccessorExtractionContext.java
new file mode 100644
index 0000000..ab12828
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/PropertyAccessorExtractionContext.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import org.gradle.internal.Cast;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+public class PropertyAccessorExtractionContext {
+ private final Collection<Method> declaringMethods;
+ private final Method mostSpecificDeclaration;
+ private final boolean declaredInManagedType;
+ private final boolean declaredAsAbstract;
+ private final Map<Class<? extends Annotation>, Annotation> annotations;
+
+ public PropertyAccessorExtractionContext(Iterable<Method> declaringMethods) {
+ this.declaringMethods = ImmutableList.copyOf(declaringMethods);
+ this.mostSpecificDeclaration = ModelSchemaUtils.findMostSpecificMethod(declaringMethods);
+ this.declaredInManagedType = ModelSchemaUtils.isMethodDeclaredInManagedType(declaringMethods);
+ this.declaredAsAbstract = Modifier.isAbstract(this.mostSpecificDeclaration.getModifiers());
+ this.annotations = collectAnnotations(declaringMethods);
+ }
+
+ private Map<Class<? extends Annotation>, Annotation> collectAnnotations(Iterable<Method> methods) {
+ Map<Class<? extends Annotation>, Annotation> annotations = Maps.newLinkedHashMap();
+ for (Method method : methods) {
+ for (Annotation annotation : method.getDeclaredAnnotations()) {
+ // Make sure more specific annotation doesn't get overwritten with less specific one
+ if (!annotations.containsKey(annotation.annotationType())) {
+ annotations.put(annotation.annotationType(), annotation);
+ }
+ }
+ }
+ return Collections.unmodifiableMap(annotations);
+ }
+
+ public Collection<Method> getDeclaringMethods() {
+ return declaringMethods;
+ }
+
+ public Method getMostSpecificDeclaration() {
+ return mostSpecificDeclaration;
+ }
+
+ public boolean isDeclaredInManagedType() {
+ return declaredInManagedType;
+ }
+
+ public boolean isDeclaredAsAbstract() {
+ return declaredAsAbstract;
+ }
+
+ public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+ return annotations.containsKey(annotationType);
+ }
+
+ public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+ return Cast.uncheckedCast(annotations.get(annotationType));
+ }
+
+ public Collection<Annotation> getAnnotations() {
+ return annotations.values();
+ }
+
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SetStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SetStrategy.java
index 288417d..8f07ba0 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SetStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SetStrategy.java
@@ -16,27 +16,28 @@
package org.gradle.model.internal.manage.schema.extract;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import org.gradle.api.Action;
-import org.gradle.internal.Factory;
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.manage.schema.ManagedImplModelSchema;
+import org.gradle.model.internal.manage.schema.ModelCollectionSchema;
import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
import org.gradle.model.internal.type.ModelType;
-import java.util.Collections;
import java.util.List;
public abstract class SetStrategy implements ModelSchemaExtractionStrategy {
private final ModelType<?> modelType;
- protected final Factory<String> supportedTypeDescriptions;
- public SetStrategy(ModelType<?> modelType, Factory<String> supportedTypeDescriptions) {
+ public SetStrategy(ModelType<?> modelType) {
this.modelType = modelType;
- this.supportedTypeDescriptions = supportedTypeDescriptions;
}
- public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, final ModelSchemaCache cache) {
+ public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaStore store, final ModelSchemaCache cache) {
ModelType<T> type = extractionContext.getType();
if (modelType.isAssignableFrom(type)) {
if (!type.getRawClass().equals(modelType.getConcreteClass())) {
@@ -53,30 +54,33 @@ public abstract class SetStrategy implements ModelSchemaExtractionStrategy {
ModelType<?> elementType = typeVariables.get(0);
- if (modelType.isAssignableFrom(elementType)) {
- throw new InvalidManagedModelElementTypeException(extractionContext, String.format("%1$s cannot be used as type parameter of %1$s", modelType.getConcreteClass().getName()));
- }
-
- ModelSchema<T> schema = ModelSchema.collection(extractionContext.getType(), elementType);
- ModelSchemaExtractionContext<?> typeParamExtractionContext = extractionContext.child(elementType, "element type", new Action<ModelSchemaExtractionContext<?>>() {
- public void execute(ModelSchemaExtractionContext<?> context) {
- ModelSchema<?> typeParamSchema = cache.get(context.getType());
-
- if (!typeParamSchema.getKind().isManaged()) {
- throw new InvalidManagedModelElementTypeException(context.getParent(), String.format(
- "cannot create a managed set of type %s as it is an unmanaged type.%nSupported types:%n%s",
- context.getType(), supportedTypeDescriptions.create()
- ));
- }
- }
- });
- return new ModelSchemaExtractionResult<T>(schema, ImmutableList.of(typeParamExtractionContext));
+ return gettModelSchemaExtractionResult(extractionContext, cache, elementType, store);
} else {
return null;
}
}
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.singleton(modelType + " of a managed type");
+ private <T, E> ModelSchemaExtractionResult<T> gettModelSchemaExtractionResult(ModelSchemaExtractionContext<T> extractionContext, final ModelSchemaCache cache, ModelType<E> elementType, ModelSchemaStore store) {
+ if (modelType.isAssignableFrom(elementType)) {
+ throw new InvalidManagedModelElementTypeException(extractionContext, String.format("%1$s cannot be used as type parameter of %1$s", modelType.getConcreteClass().getName()));
+ }
+
+ ModelCollectionSchema<T, E> schema = new ModelCollectionSchema<T, E>(extractionContext.getType(), elementType, this.<T, E>getNodeInitializer(store));
+ ModelSchemaExtractionContext<?> typeParamExtractionContext = extractionContext.child(elementType, "element type", new Action<ModelSchemaExtractionContext<?>>() {
+ public void execute(ModelSchemaExtractionContext<?> context) {
+ ModelSchema<?> typeParamSchema = cache.get(context.getType());
+
+ if (!(typeParamSchema instanceof ManagedImplModelSchema)) {
+ throw new InvalidManagedModelElementTypeException(context.getParent(), String.format(
+ "cannot create a managed set of type %s as it is an unmanaged type. Only @Managed types are allowed.",
+ context.getType()
+ ));
+ }
+ }
+ });
+ return new ModelSchemaExtractionResult<T>(schema, ImmutableList.of(typeParamExtractionContext));
}
+
+ protected abstract <T, E> Function<ModelCollectionSchema<T, E>, NodeInitializer> getNodeInitializer(ModelSchemaStore store);
+
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SpecializedMapStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SpecializedMapStrategy.java
index 83e7fce..1deea4b 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SpecializedMapStrategy.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/SpecializedMapStrategy.java
@@ -19,13 +19,13 @@ package org.gradle.model.internal.manage.schema.extract;
import org.gradle.api.Nullable;
import org.gradle.model.ModelMap;
import org.gradle.model.internal.core.ModelMapGroovyDecorator;
-import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelMapSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
import org.gradle.model.internal.type.ModelType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.util.Collections;
/**
* Currently only handles interfaces with no type parameters that directly extend ModelMap.
@@ -35,7 +35,7 @@ public class SpecializedMapStrategy implements ModelSchemaExtractionStrategy {
@Nullable
@Override
- public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaCache cache) {
+ public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaStore store, ModelSchemaCache cache) {
Type type = extractionContext.getType().getType();
if (!(type instanceof Class)) {
return null;
@@ -57,11 +57,7 @@ public class SpecializedMapStrategy implements ModelSchemaExtractionStrategy {
}
ModelType<?> elementType = ModelType.of(parameterizedSuperType.getActualTypeArguments()[0]);
Class<?> proxyImpl = generator.generate(ModelMapGroovyDecorator.class, contractType);
- return new ModelSchemaExtractionResult<T>(ModelSchema.specializedMap(extractionContext.getType(), elementType, proxyImpl));
+ return new ModelSchemaExtractionResult<T>(new ModelMapSchema<T>(extractionContext.getType(), elementType, proxyImpl));
}
- @Override
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.emptySet();
- }
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/StructSchemaExtractionStrategySupport.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/StructSchemaExtractionStrategySupport.java
new file mode 100644
index 0000000..a110a13
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/StructSchemaExtractionStrategySupport.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Joiner;
+import com.google.common.collect.*;
+import org.apache.commons.lang.StringUtils;
+import org.gradle.api.Action;
+import org.gradle.api.Nullable;
+import org.gradle.model.internal.manage.schema.ModelProperty;
+import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
+import org.gradle.model.internal.method.WeaklyTypeReferencingMethod;
+import org.gradle.model.internal.type.ModelType;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.gradle.model.internal.manage.schema.extract.ModelSchemaUtils.getOverloadedMethods;
+
+public abstract class StructSchemaExtractionStrategySupport implements ModelSchemaExtractionStrategy {
+
+ private final ModelSchemaAspectExtractor aspectExtractor;
+
+ protected StructSchemaExtractionStrategySupport(ModelSchemaAspectExtractor aspectExtractor) {
+ this.aspectExtractor = aspectExtractor;
+ }
+
+ protected abstract boolean isTarget(ModelType<?> type);
+
+ public <R> ModelSchemaExtractionResult<R> extract(final ModelSchemaExtractionContext<R> extractionContext, ModelSchemaStore store, final ModelSchemaCache cache) {
+ ModelType<R> type = extractionContext.getType();
+ if (!isTarget(type)) {
+ return null;
+ }
+
+ validateTypeHierarchy(extractionContext, type);
+
+ List<ModelPropertyExtractionResult<?>> propertyExtractionResults = extractPropertySchemas(extractionContext, ModelSchemaUtils.getCandidateMethods(type.getRawClass()));
+ Iterable<ModelProperty<?>> properties = Iterables.transform(propertyExtractionResults, new Function<ModelPropertyExtractionResult<?>, ModelProperty<?>>() {
+ @Override
+ public ModelProperty<?> apply(ModelPropertyExtractionResult<?> propertyResult) {
+ return propertyResult.getProperty();
+ }
+ });
+ List<ModelSchemaAspect> aspects = aspectExtractor.extract(extractionContext, propertyExtractionResults);
+
+ ModelSchema<R> schema = createSchema(extractionContext, store, type, properties, aspects);
+ Iterable<ModelSchemaExtractionContext<?>> propertyDependencies = Iterables.transform(propertyExtractionResults, new Function<ModelPropertyExtractionResult<?>, ModelSchemaExtractionContext<?>>() {
+ public ModelSchemaExtractionContext<?> apply(ModelPropertyExtractionResult<?> propertyResult) {
+ return toPropertyExtractionContext(extractionContext, propertyResult, cache);
+ }
+ });
+
+ return new ModelSchemaExtractionResult<R>(schema, propertyDependencies);
+ }
+
+ private <R, P> ModelSchemaExtractionContext<P> toPropertyExtractionContext(ModelSchemaExtractionContext<R> parentContext, ModelPropertyExtractionResult<P> propertyResult, ModelSchemaCache modelSchemaCache) {
+ ModelProperty<P> property = propertyResult.getProperty();
+ return parentContext.child(property.getType(), propertyDescription(parentContext, property), createPropertyValidator(propertyResult, modelSchemaCache));
+ }
+
+ private <R> List<ModelPropertyExtractionResult<?>> extractPropertySchemas(ModelSchemaExtractionContext<R> extractionContext, Multimap<String, Method> methodsByName) {
+ List<ModelPropertyExtractionResult<?>> results = Lists.newArrayList();
+ Set<Method> handledMethods = Sets.newHashSet();
+
+ List<String> methodNames = Lists.newArrayList(methodsByName.keySet());
+ Collections.sort(methodNames);
+ Set<String> skippedMethodNames = Sets.newHashSet();
+ for (String methodName : methodNames) {
+ if (skippedMethodNames.contains(methodName)) {
+ continue;
+ }
+
+ Collection<Method> methods = methodsByName.get(methodName);
+
+ List<Method> overloadedMethods = getOverloadedMethods(methods);
+ if (overloadedMethods != null) {
+ handleOverloadedMethods(extractionContext, overloadedMethods);
+ continue;
+ }
+
+ int getterPrefixLen = getterPrefixLength(methodName);
+ if (getterPrefixLen >= 0) {
+ Method mostSpecificGetter = ModelSchemaUtils.findMostSpecificMethod(methods);
+
+ char getterPropertyNameFirstChar = methodName.charAt(getterPrefixLen);
+ if (!Character.isUpperCase(getterPropertyNameFirstChar)) {
+ handleInvalidGetter(extractionContext, mostSpecificGetter,
+ String.format("the %s character of the getter method name must be an uppercase character", getterPrefixLen == 2 ? "3rd" : "4th"));
+ continue;
+ }
+
+ String propertyNameCapitalized = methodName.substring(getterPrefixLen);
+ String propertyName = StringUtils.uncapitalize(propertyNameCapitalized);
+ String setterName = "set" + propertyNameCapitalized;
+ Collection<Method> setterMethods = methodsByName.get(setterName);
+ PropertyAccessorExtractionContext setterContext = !setterMethods.isEmpty() ? new PropertyAccessorExtractionContext(setterMethods) : null;
+
+ String prefix = methodName.substring(0, getterPrefixLen);
+ Iterable<Method> getterMethods = methods;
+ if (prefix.equals("get")) {
+ String isGetterName = "is" + propertyNameCapitalized;
+ Collection<Method> isGetterMethods = methodsByName.get(isGetterName);
+ if (!isGetterMethods.isEmpty()) {
+ List<Method> overloadedIsGetterMethods = getOverloadedMethods(isGetterMethods);
+ if (overloadedIsGetterMethods != null) {
+ handleOverloadedMethods(extractionContext, overloadedIsGetterMethods);
+ continue;
+ }
+
+ Method mostSpecificIsGetter = ModelSchemaUtils.findMostSpecificMethod(isGetterMethods);
+ if (mostSpecificGetter.getReturnType() != boolean.class || mostSpecificIsGetter.getReturnType() != boolean.class) {
+ handleInvalidGetter(extractionContext, mostSpecificIsGetter,
+ String.format("property '%s' has both '%s()' and '%s()' getters, but they don't both return a boolean",
+ propertyName, isGetterName, methodName));
+ continue;
+ }
+ getterMethods = Iterables.concat(getterMethods, isGetterMethods);
+ skippedMethodNames.add(isGetterName);
+ }
+ }
+
+ PropertyAccessorExtractionContext getterContext = new PropertyAccessorExtractionContext(getterMethods);
+ ModelPropertyExtractionResult<?> result = extractPropertySchema(extractionContext, propertyName, getterContext, setterContext, getterPrefixLen);
+ if (result != null) {
+ results.add(result);
+ handledMethods.addAll(getterContext.getDeclaringMethods());
+ if (setterContext != null) {
+ handledMethods.addAll(setterContext.getDeclaringMethods());
+ }
+
+ }
+ }
+ }
+
+ validateAllNecessaryMethodsHandled(extractionContext, methodsByName.values(), handledMethods);
+ return results;
+ }
+
+ private static int getterPrefixLength(String methodName) {
+ if (methodName.startsWith("get") && !"get".equals(methodName)) {
+ return 3;
+ }
+ if (methodName.startsWith("is") && !"is".equals(methodName)) {
+ return 2;
+ }
+ return -1;
+ }
+
+ @Nullable
+ private <R> ModelPropertyExtractionResult<R> extractPropertySchema(ModelSchemaExtractionContext<?> extractionContext, String propertyName, PropertyAccessorExtractionContext getterContext, PropertyAccessorExtractionContext setterContext, int getterPrefixLen) {
+ // Take the most specific declaration of the getter
+ Method mostSpecificGetter = getterContext.getMostSpecificDeclaration();
+ if (mostSpecificGetter.getParameterTypes().length != 0) {
+ handleInvalidGetter(extractionContext, mostSpecificGetter, "getter methods cannot take parameters");
+ return null;
+ }
+
+ if (mostSpecificGetter.getReturnType() != boolean.class && getterPrefixLen == 2) {
+ handleInvalidGetter(extractionContext, mostSpecificGetter, "getter method name must start with 'get'");
+ return null;
+ }
+
+ ModelProperty.StateManagementType stateManagementType = determineStateManagementType(extractionContext, getterContext);
+ ModelType<R> returnType = ModelType.returnType(mostSpecificGetter);
+
+ boolean writable = setterContext != null;
+ if (writable) {
+ validateSetter(extractionContext, returnType, getterContext, setterContext);
+ }
+
+ ImmutableSet<ModelType<?>> declaringClasses = ImmutableSet.copyOf(Iterables.transform(getterContext.getDeclaringMethods(), new Function<Method, ModelType<?>>() {
+ public ModelType<?> apply(Method input) {
+ return ModelType.of(input.getDeclaringClass());
+ }
+ }));
+
+ WeaklyTypeReferencingMethod<?, R> getterRef = WeaklyTypeReferencingMethod.of(extractionContext.getType(), returnType, getterContext.getMostSpecificDeclaration());
+ return new ModelPropertyExtractionResult<R>(
+ ModelProperty.of(returnType, propertyName, stateManagementType, writable, declaringClasses, getterRef),
+ getterContext,
+ setterContext
+ );
+ }
+
+ protected abstract void validateAllNecessaryMethodsHandled(ModelSchemaExtractionContext<?> extractionContext, Collection<Method> allMethods, final Set<Method> handledMethods);
+
+ protected abstract <R> void validateTypeHierarchy(ModelSchemaExtractionContext<R> extractionContext, ModelType<R> type);
+
+ protected abstract void handleInvalidGetter(ModelSchemaExtractionContext<?> extractionContext, Method getter, String message);
+
+ protected abstract void handleOverloadedMethods(ModelSchemaExtractionContext<?> extractionContext, Collection<Method> overloadedMethods);
+
+ protected abstract ModelProperty.StateManagementType determineStateManagementType(ModelSchemaExtractionContext<?> extractionContext, PropertyAccessorExtractionContext getterContext);
+
+ protected abstract <R> ModelSchema<R> createSchema(ModelSchemaExtractionContext<R> extractionContext, ModelSchemaStore store, ModelType<R> type, Iterable<ModelProperty<?>> properties, Iterable<ModelSchemaAspect> aspects);
+
+ protected abstract <P> Action<ModelSchemaExtractionContext<P>> createPropertyValidator(ModelPropertyExtractionResult<P> propertyResult, ModelSchemaCache modelSchemaCache);
+
+ private String propertyDescription(ModelSchemaExtractionContext<?> parentContext, ModelProperty<?> property) {
+ if (property.getDeclaredBy().size() == 1 && property.getDeclaredBy().contains(parentContext.getType())) {
+ return String.format("property '%s'", property.getName());
+ } else {
+ ImmutableSortedSet<String> declaredBy = ImmutableSortedSet.copyOf(Iterables.transform(property.getDeclaredBy(), Functions.toStringFunction()));
+ return String.format("property '%s' declared by %s", property.getName(), Joiner.on(", ").join(declaredBy));
+ }
+ }
+
+ protected abstract void validateSetter(ModelSchemaExtractionContext<?> extractionContext, ModelType<?> propertyType, PropertyAccessorExtractionContext getterContext, PropertyAccessorExtractionContext setterContext);
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/StructStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/StructStrategy.java
deleted file mode 100644
index 4cf80c8..0000000
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/StructStrategy.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.internal.manage.schema.extract;
-
-import com.google.common.base.*;
-import com.google.common.collect.*;
-import groovy.lang.GroovyObject;
-import org.apache.commons.lang.StringUtils;
-import org.gradle.api.Action;
-import org.gradle.api.Named;
-import org.gradle.api.Nullable;
-import org.gradle.internal.Factory;
-import org.gradle.internal.reflect.MethodDescription;
-import org.gradle.internal.reflect.MethodSignatureEquivalence;
-import org.gradle.model.Managed;
-import org.gradle.model.ModelMap;
-import org.gradle.model.Unmanaged;
-import org.gradle.model.internal.core.MutableModelNode;
-import org.gradle.model.internal.manage.instance.ManagedProxyFactory;
-import org.gradle.model.internal.manage.instance.ModelElementState;
-import org.gradle.model.internal.manage.schema.ModelCollectionSchema;
-import org.gradle.model.internal.manage.schema.ModelProperty;
-import org.gradle.model.internal.manage.schema.ModelSchema;
-import org.gradle.model.internal.manage.schema.ModelStructSchema;
-import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
-import org.gradle.model.internal.type.ModelType;
-import org.gradle.util.CollectionUtils;
-
-import java.lang.reflect.*;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-public class StructStrategy implements ModelSchemaExtractionStrategy {
-
- private static final NoOpModelElementState NO_OP_MODEL_ELEMENT_STATE = new NoOpModelElementState();
-
- private final Set<Equivalence.Wrapper<Method>> ignoredMethods;
-
- private final Factory<String> supportedTypeDescriptions;
- private final MethodSignatureEquivalence equivalence = new MethodSignatureEquivalence();
-
- private final ManagedProxyClassGenerator classGenerator = new ManagedProxyClassGenerator();
- private final ManagedProxyFactory proxyFactory = new ManagedProxyFactory();
-
- public StructStrategy(Factory<String> supportedTypeDescriptions) {
- this.supportedTypeDescriptions = supportedTypeDescriptions;
-
- Iterable<Method> ignoredMethods = Iterables.concat(Arrays.asList(Object.class.getMethods()), Arrays.asList(GroovyObject.class.getMethods()));
- this.ignoredMethods = ImmutableSet.copyOf(Iterables.transform(ignoredMethods, new Function<Method, Equivalence.Wrapper<Method>>() {
- public Equivalence.Wrapper<Method> apply(@Nullable Method input) {
- return equivalence.wrap(input);
- }
- }));
- }
-
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.singleton("interfaces and abstract classes annotated with " + Managed.class.getName());
- }
-
- public <R> ModelSchemaExtractionResult<R> extract(final ModelSchemaExtractionContext<R> extractionContext, final ModelSchemaCache cache) {
- ModelType<R> type = extractionContext.getType();
- Class<? super R> clazz = type.getRawClass();
- if (clazz.isAnnotationPresent(Managed.class)) {
- validateType(type, extractionContext);
-
- Iterable<Method> methods = Arrays.asList(clazz.getMethods());
- if (!clazz.isInterface()) {
- methods = filterIgnoredMethods(methods);
- }
- ImmutableListMultimap<String, Method> methodsByName = Multimaps.index(methods, new Function<Method, String>() {
- public String apply(Method method) {
- return method.getName();
- }
- });
-
- ensureNoOverloadedMethods(extractionContext, methodsByName);
-
- List<ModelProperty<?>> properties = Lists.newLinkedList();
- List<Method> handled = Lists.newArrayListWithCapacity(clazz.getMethods().length);
- ReturnTypeSpecializationOrdering returnTypeSpecializationOrdering = new ReturnTypeSpecializationOrdering();
-
- for (String methodName : methodsByName.keySet()) {
- if (methodName.startsWith("get") && !methodName.equals("get")) {
- ImmutableList<Method> getterMethods = methodsByName.get(methodName);
-
- // The overload check earlier verified that all methods for are equivalent for our purposes
- // So, taking the first one with the most specialized return type is fine.
- Method sampleMethod = returnTypeSpecializationOrdering.max(getterMethods);
-
- boolean abstractGetter = Modifier.isAbstract(sampleMethod.getModifiers());
-
- if (sampleMethod.getParameterTypes().length != 0) {
- throw invalidMethod(extractionContext, "getter methods cannot take parameters", sampleMethod);
- }
-
- Character getterPropertyNameFirstChar = methodName.charAt(3);
- if (!Character.isUpperCase(getterPropertyNameFirstChar)) {
- throw invalidMethod(extractionContext, "the 4th character of the getter method name must be an uppercase character", sampleMethod);
- }
-
- ModelType<?> returnType = ModelType.returnType(sampleMethod);
-
- String propertyNameCapitalized = methodName.substring(3);
- String propertyName = StringUtils.uncapitalize(propertyNameCapitalized);
- String setterName = "set" + propertyNameCapitalized;
- ImmutableList<Method> setterMethods = methodsByName.get(setterName);
-
- boolean isWritable = !setterMethods.isEmpty();
- if (isWritable) {
- Method setter = setterMethods.get(0);
-
- if (!abstractGetter) {
- throw invalidMethod(extractionContext, "setters are not allowed for non-abstract getters", setter);
- }
- validateSetter(extractionContext, returnType, setter);
- handled.addAll(setterMethods);
- }
-
- if (abstractGetter) {
- ImmutableSet<ModelType<?>> declaringClasses = ImmutableSet.copyOf(Iterables.transform(getterMethods, new Function<Method, ModelType<?>>() {
- public ModelType<?> apply(Method input) {
- return ModelType.of(input.getDeclaringClass());
- }
- }));
-
- boolean unmanaged = Iterables.any(getterMethods, new Predicate<Method>() {
- public boolean apply(Method input) {
- return input.getAnnotation(Unmanaged.class) != null;
- }
- });
-
- properties.add(ModelProperty.of(returnType, propertyName, isWritable, declaringClasses, unmanaged));
- }
- handled.addAll(getterMethods);
- }
- }
-
- Iterable<Method> notHandled = Iterables.filter(methodsByName.values(), Predicates.not(Predicates.in(handled)));
-
- // TODO - should call out valid getters without setters
- if (!Iterables.isEmpty(notHandled)) {
- throw invalidMethods(extractionContext, "only paired getter/setter methods are supported", notHandled);
- }
-
- Class<R> concreteClass = type.getConcreteClass();
- Class<? extends R> implClass = classGenerator.generate(concreteClass);
- final ModelStructSchema<R> schema = ModelSchema.struct(type, properties, implClass);
- extractionContext.addValidator(new Action<ModelSchemaExtractionContext<R>>() {
- @Override
- public void execute(ModelSchemaExtractionContext<R> validatorModelSchemaExtractionContext) {
- ensureCanBeInstantiated(extractionContext, schema);
- }
- });
- Iterable<ModelSchemaExtractionContext<?>> propertyDependencies = Iterables.transform(properties, new Function<ModelProperty<?>, ModelSchemaExtractionContext<?>>() {
- public ModelSchemaExtractionContext<?> apply(final ModelProperty<?> property) {
- return toPropertyExtractionContext(extractionContext, property, cache);
- }
- });
-
- return new ModelSchemaExtractionResult<R>(schema, propertyDependencies);
- } else {
- return null;
- }
- }
-
- private <R> void ensureCanBeInstantiated(ModelSchemaExtractionContext<R> extractionContext, ModelStructSchema<R> schema) {
- try {
- proxyFactory.createProxy(NO_OP_MODEL_ELEMENT_STATE, schema);
- } catch (Throwable e) {
- throw new InvalidManagedModelElementTypeException(extractionContext, "instance creation failed", e);
- }
- }
-
- private Iterable<Method> filterIgnoredMethods(Iterable<Method> methods) {
- return Iterables.filter(methods, new Predicate<Method>() {
- @Override
- public boolean apply(Method method) {
- return !method.isSynthetic() && !ignoredMethods.contains(equivalence.wrap(method));
- }
- });
- }
-
- private <R> void ensureNoOverloadedMethods(ModelSchemaExtractionContext<R> extractionContext, final ImmutableListMultimap<String, Method> methodsByName) {
- ImmutableSet<String> methodNames = methodsByName.keySet();
- for (String methodName : methodNames) {
- ImmutableList<Method> methods = methodsByName.get(methodName);
- if (methods.size() > 1) {
- List<Method> deduped = CollectionUtils.dedup(methods, equivalence);
- if (deduped.size() > 1) {
- throw invalidMethods(extractionContext, "overloaded methods are not supported", deduped);
- }
- }
- }
- }
-
- private <R, P> ModelSchemaExtractionContext<P> toPropertyExtractionContext(final ModelSchemaExtractionContext<R> parentContext, final ModelProperty<P> property, final ModelSchemaCache modelSchemaCache) {
- return parentContext.child(property.getType(), propertyDescription(parentContext, property), new Action<ModelSchemaExtractionContext<P>>() {
- public void execute(ModelSchemaExtractionContext<P> propertyExtractionContext) {
- ModelSchema<P> propertySchema = modelSchemaCache.get(property.getType());
-
- if (property.getName().equals("name") && Named.class.isAssignableFrom(parentContext.getType().getRawClass())) {
- if (property.isWritable()) {
- throw new InvalidManagedModelElementTypeException(parentContext, String.format(
- "@Managed types implementing %s must not declare a setter for the name property",
- Named.class.getName()
- ));
- } else {
- return;
- }
- }
-
- if (propertySchema.getKind().isAllowedPropertyTypeOfManagedType() && property.isUnmanaged()) {
- throw new InvalidManagedModelElementTypeException(parentContext, String.format(
- "property '%s' is marked as @Unmanaged, but is of @Managed type '%s'. Please remove the @Managed annotation.%n%s",
- property.getName(), property.getType(), supportedTypeDescriptions.create()
- ));
- }
-
- if (!propertySchema.getKind().isAllowedPropertyTypeOfManagedType() && !property.isUnmanaged()) {
- throw new InvalidManagedModelElementTypeException(parentContext, String.format(
- "type %s cannot be used for property '%s' as it is an unmanaged type (please annotate the getter with @org.gradle.model.Unmanaged if you want this property to be unmanaged).%n%s",
- property.getType(), property.getName(), supportedTypeDescriptions.create()
- ));
- }
-
- if (!property.isWritable()) {
- if (property.isUnmanaged()) {
- throw new InvalidManagedModelElementTypeException(parentContext, String.format(
- "unmanaged property '%s' cannot be read only, unmanaged properties must have setters",
- property.getName())
- );
- }
-
- if (!propertySchema.getKind().isManaged()) {
- throw new InvalidManagedModelElementTypeException(parentContext, String.format(
- "read only property '%s' has non managed type %s, only managed types can be used",
- property.getName(), property.getType()));
- }
- }
-
- if (propertySchema.getKind() == ModelSchema.Kind.COLLECTION) {
- ModelCollectionSchema<?> propertyCollectionSchema = (ModelCollectionSchema<?>) propertySchema;
- if (propertyCollectionSchema.isMap()) {
- if (property.isWritable()) {
- throw new InvalidManagedModelElementTypeException(parentContext, String.format(
- "property '%s' cannot have a setter (%s properties must be read only).",
- property.getName(), ModelMap.class.getName()));
- }
- }
- }
- }
- });
- }
-
- private String propertyDescription(ModelSchemaExtractionContext<?> parentContext, ModelProperty<?> property) {
- if (property.getDeclaredBy().size() == 1 && property.getDeclaredBy().contains(parentContext.getType())) {
- return String.format("property '%s'", property.getName());
- } else {
- ImmutableSortedSet<String> declaredBy = ImmutableSortedSet.copyOf(Iterables.transform(property.getDeclaredBy(), Functions.toStringFunction()));
- return String.format("property '%s' declared by %s", property.getName(), Joiner.on(", ").join(declaredBy));
- }
- }
-
- private void validateSetter(ModelSchemaExtractionContext<?> extractionContext, ModelType<?> propertyType, Method setter) {
- if (!Modifier.isAbstract(setter.getModifiers())) {
- throw invalidMethod(extractionContext, "non-abstract setters are not allowed", setter);
- }
-
- if (!setter.getReturnType().equals(void.class)) {
- throw invalidMethod(extractionContext, "setter method must have void return type", setter);
- }
-
- Type[] setterParameterTypes = setter.getGenericParameterTypes();
- if (setterParameterTypes.length != 1) {
- throw invalidMethod(extractionContext, "setter method must have exactly one parameter", setter);
- }
-
- ModelType<?> setterType = ModelType.paramType(setter, 0);
- if (!setterType.equals(propertyType)) {
- String message = "setter method param must be of exactly the same type as the getter returns (expected: " + propertyType + ", found: " + setterType + ")";
- throw invalidMethod(extractionContext, message, setter);
- }
- }
-
- private void validateType(ModelType<?> type, ModelSchemaExtractionContext<?> extractionContext) {
- Class<?> typeClass = type.getConcreteClass();
-
- if (!typeClass.isInterface() && !Modifier.isAbstract(typeClass.getModifiers())) {
- throw new InvalidManagedModelElementTypeException(extractionContext, "must be defined as an interface or an abstract class.");
- }
-
- if (typeClass.getTypeParameters().length > 0) {
- throw new InvalidManagedModelElementTypeException(extractionContext, "cannot be a parameterized type.");
- }
-
- Constructor<?> customConstructor = findCustomConstructor(typeClass);
- if (customConstructor != null) {
- throw invalidMethod(extractionContext, "custom constructors are not allowed", customConstructor);
- }
-
- ensureNoInstanceScopedFields(extractionContext, typeClass);
- ensureNoProtectedOrPrivateMethods(extractionContext, typeClass);
- }
-
- private void ensureNoProtectedOrPrivateMethods(ModelSchemaExtractionContext<?> extractionContext, Class<?> typeClass) {
- Class<?> superClass = typeClass.getSuperclass();
- if (superClass != null && !superClass.equals(Object.class)) {
- ensureNoProtectedOrPrivateMethods(extractionContext, superClass);
- }
-
- Iterable<Method> protectedAndPrivateMethods = Iterables.filter(Arrays.asList(typeClass.getDeclaredMethods()), new Predicate<Method>() {
- @Override
- public boolean apply(Method method) {
- int modifiers = method.getModifiers();
- return !method.isSynthetic() && (Modifier.isProtected(modifiers) || Modifier.isPrivate(modifiers));
- }
- });
-
- if (!Iterables.isEmpty(protectedAndPrivateMethods)) {
- throw invalidMethods(extractionContext, "protected and private methods are not allowed", protectedAndPrivateMethods);
- }
- }
-
- private void ensureNoInstanceScopedFields(ModelSchemaExtractionContext<?> extractionContext, Class<?> typeClass) {
- Class<?> superClass = typeClass.getSuperclass();
- if (superClass != null && !superClass.equals(Object.class)) {
- ensureNoInstanceScopedFields(extractionContext, superClass);
- }
-
- List<Field> declaredFields = Arrays.asList(typeClass.getDeclaredFields());
- Iterable<Field> instanceScopedFields = Iterables.filter(declaredFields, new Predicate<Field>() {
- public boolean apply(Field field) {
- return !Modifier.isStatic(field.getModifiers()) && !field.getName().equals("metaClass");
- }
- });
- ImmutableSortedSet<String> sortedDescriptions = ImmutableSortedSet.copyOf(Iterables.transform(instanceScopedFields, new Function<Field, String>() {
- public String apply(Field field) {
- return field.toString();
- }
- }));
- if (!sortedDescriptions.isEmpty()) {
- throw new InvalidManagedModelElementTypeException(extractionContext, "instance scoped fields are not allowed (found fields: " + Joiner.on(", ").join(sortedDescriptions) + ").");
- }
- }
-
- private Constructor<?> findCustomConstructor(Class<?> typeClass) {
- Class<?> superClass = typeClass.getSuperclass();
- if (superClass != null && !superClass.equals(Object.class)) {
- Constructor<?> customSuperConstructor = findCustomConstructor(typeClass.getSuperclass());
- if (customSuperConstructor != null) {
- return customSuperConstructor;
- }
- }
- Constructor<?>[] constructors = typeClass.getConstructors();
- if (constructors.length == 0 || (constructors.length == 1 && constructors[0].getParameterTypes().length == 0)) {
- return null;
- } else {
- for (Constructor<?> constructor : constructors) {
- if (constructor.getParameterTypes().length > 0) {
- return constructor;
- }
- }
- //this should never happen
- throw new RuntimeException(String.format("Expected a constructor taking at least one argument in %s but no such constructors were found", typeClass.getName()));
- }
- }
-
- private InvalidManagedModelElementTypeException invalidMethod(ModelSchemaExtractionContext<?> extractionContext, String message, Method method) {
- return invalidMethod(extractionContext, message, MethodDescription.of(method));
- }
-
- private InvalidManagedModelElementTypeException invalidMethod(ModelSchemaExtractionContext<?> extractionContext, String message, Constructor<?> constructor) {
- return invalidMethod(extractionContext, message, MethodDescription.of(constructor));
- }
-
- private InvalidManagedModelElementTypeException invalidMethod(ModelSchemaExtractionContext<?> extractionContext, String message, MethodDescription methodDescription) {
- return new InvalidManagedModelElementTypeException(extractionContext, message + " (invalid method: " + methodDescription.toString() + ").");
- }
-
- private InvalidManagedModelElementTypeException invalidMethods(ModelSchemaExtractionContext<?> extractionContext, String message, final Iterable<Method> methods) {
- final ImmutableSortedSet<String> descriptions = ImmutableSortedSet.copyOf(Iterables.transform(methods, new Function<Method, String>() {
- public String apply(Method method) {
- return MethodDescription.of(method).toString();
- }
- }));
- return new InvalidManagedModelElementTypeException(extractionContext, message + " (invalid methods: " + Joiner.on(", ").join(descriptions) + ").");
- }
-
- static private class ReturnTypeSpecializationOrdering extends Ordering<Method> {
-
- @Override
- public int compare(Method left, Method right) {
- Class<?> leftType = left.getReturnType();
- Class<?> rightType = right.getReturnType();
- if (leftType.equals(rightType)) {
- return 0;
- }
- if (leftType.isAssignableFrom(rightType)) {
- return -1;
- }
- if (rightType.isAssignableFrom(leftType)) {
- return 1;
- }
- throw new UnsupportedOperationException(String.format("Cannot compare two types that aren't part of an inheritance hierarchy: %s, %s", leftType, rightType));
- }
- }
-
- private static class NoOpModelElementState implements ModelElementState {
- @Override
- public MutableModelNode getBackingNode() {
- return null;
- }
-
- @Override
- public String getDisplayName() {
- return null;
- }
-
- public Object get(String name) {
- return null;
- }
-
- public void set(String name, Object value) {
- }
- }
-}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/UnmanagedImplStructStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/UnmanagedImplStructStrategy.java
new file mode 100644
index 0000000..7c4d358
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/UnmanagedImplStructStrategy.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import org.gradle.api.Action;
+import org.gradle.internal.Actions;
+import org.gradle.model.internal.manage.schema.*;
+import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
+import org.gradle.model.internal.type.ModelType;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Set;
+
+public class UnmanagedImplStructStrategy extends StructSchemaExtractionStrategySupport {
+
+ public UnmanagedImplStructStrategy(ModelSchemaAspectExtractor aspectExtractor) {
+ super(aspectExtractor);
+ }
+
+ protected <R> ModelSchema<R> createSchema(final ModelSchemaExtractionContext<R> extractionContext, final ModelSchemaStore store, ModelType<R> type, Iterable<ModelProperty<?>> properties, Iterable<ModelSchemaAspect> aspects) {
+ return new ModelUnmanagedImplStructSchema<R>(type, properties, aspects);
+ }
+
+ @Override
+ protected boolean isTarget(ModelType<?> type) {
+ // Everything is an unmanaged struct that hasn't been handled before
+ return true;
+ }
+
+ @Override
+ protected <R> void validateTypeHierarchy(ModelSchemaExtractionContext<R> extractionContext, ModelType<R> type) {
+ }
+
+ @Override
+ protected void handleOverloadedMethods(ModelSchemaExtractionContext<?> extractionContext, Collection<Method> overloadedMethods) {
+ }
+
+ @Override
+ protected void handleInvalidGetter(ModelSchemaExtractionContext<?> extractionContext, Method getter, String message) {
+ }
+
+ @Override
+ protected void validateSetter(ModelSchemaExtractionContext<?> extractionContext, ModelType<?> propertyType, PropertyAccessorExtractionContext getterContext, PropertyAccessorExtractionContext setterContext) {
+ }
+
+ @Override
+ protected ModelProperty.StateManagementType determineStateManagementType(ModelSchemaExtractionContext<?> extractionContext, PropertyAccessorExtractionContext getterContext) {
+ return ModelProperty.StateManagementType.UNMANAGED;
+ }
+
+ @Override
+ protected void validateAllNecessaryMethodsHandled(ModelSchemaExtractionContext<?> extractionContext, Collection<Method> allMethods, Set<Method> handledMethods) {
+ }
+
+ @Override
+ protected <P> Action<ModelSchemaExtractionContext<P>> createPropertyValidator(ModelPropertyExtractionResult<P> propertyResult, ModelSchemaCache modelSchemaCache) {
+ return Actions.doNothing();
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/UnmanagedStrategy.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/UnmanagedStrategy.java
deleted file mode 100644
index 261b0ac..0000000
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/manage/schema/extract/UnmanagedStrategy.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.internal.manage.schema.extract;
-
-import org.gradle.model.internal.manage.schema.ModelSchema;
-import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache;
-
-import java.util.Collections;
-
-public class UnmanagedStrategy implements ModelSchemaExtractionStrategy {
- public <T> ModelSchemaExtractionResult<T> extract(ModelSchemaExtractionContext<T> extractionContext, ModelSchemaCache cache) {
- return new ModelSchemaExtractionResult<T>(ModelSchema.unmanaged(extractionContext.getType()));
- }
-
- public Iterable<String> getSupportedManagedTypes() {
- return Collections.emptyList();
- }
-}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/DefaultModelRegistry.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/DefaultModelRegistry.java
index 9c2f39e..1df7f71 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/DefaultModelRegistry.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/DefaultModelRegistry.java
@@ -553,7 +553,7 @@ public class DefaultModelRegistry implements ModelRegistry {
}
}
- private List<BindingPredicate> mapInputs(List<ModelReference<?>> inputs, ModelPath scope) {
+ private List<BindingPredicate> mapInputs(List<? extends ModelReference<?>> inputs, ModelPath scope) {
if (inputs.isEmpty()) {
return Collections.emptyList();
}
@@ -568,164 +568,6 @@ public class DefaultModelRegistry implements ModelRegistry {
return result;
}
- private class ModelReferenceNode extends ModelNodeInternal {
- private ModelNodeInternal target;
-
- public ModelReferenceNode(CreatorRuleBinder creatorBinder) {
- super(creatorBinder);
- }
-
- @Override
- public ModelNodeInternal getTarget() {
- return target;
- }
-
- @Override
- public void setTarget(ModelNode target) {
- this.target = (ModelNodeInternal) target;
- }
-
- @Override
- public ModelNodeInternal addLink(ModelNodeInternal node) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void addLink(ModelCreator creator) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void addReference(ModelCreator creator) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void removeLink(String name) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> void applyToSelf(ModelActionRole type, ModelAction<T> action) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> void applyToAllLinks(ModelActionRole type, ModelAction<T> action) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> void applyToAllLinksTransitive(ModelActionRole type, ModelAction<T> action) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> void applyToLink(ModelActionRole type, ModelAction<T> action) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void applyToLink(String name, Class<? extends RuleSource> rules) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void applyToLinks(ModelType<?> type, Class<? extends RuleSource> rules) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void applyToAllLinksTransitive(ModelType<?> type, Class<? extends RuleSource> rules) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void applyToSelf(Class<? extends RuleSource> rules) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getLinkCount(ModelType<?> type) {
- return 0;
- }
-
- @Override
- public Set<String> getLinkNames(ModelType<?> type) {
- return Collections.emptySet();
- }
-
- @Nullable
- @Override
- public MutableModelNode getLink(String name) {
- return null;
- }
-
- @Override
- public Iterable<? extends ModelNodeInternal> getLinks() {
- return Collections.emptySet();
- }
-
- @Override
- public Iterable<? extends MutableModelNode> getLinks(ModelType<?> type) {
- return Collections.emptySet();
- }
-
- @Override
- public int getLinkCount() {
- return 0;
- }
-
- @Override
- public boolean hasLink(String name, ModelType<?> type) {
- return false;
- }
-
- @Override
- public boolean hasLink(String name) {
- return false;
- }
-
- @Override
- public <T> T getPrivateData(ModelType<T> type) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> void setPrivateData(Class<? super T> type, T object) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> void setPrivateData(ModelType<? super T> type, T object) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object getPrivateData() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public <T> T getPrivateData(Class<T> type) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void ensureUsable() {
- }
-
- @Override
- public void realize() {
-
- }
-
- @Override
- public MutableModelNode getParent() {
- return null;
- }
- }
-
private class ModelElementNode extends ModelNodeInternal {
private final Map<String, ModelNodeInternal> links = Maps.newTreeMap();
private final MutableModelNode parent;
@@ -749,6 +591,24 @@ public class DefaultModelRegistry implements ModelRegistry {
}
@Override
+ public <T> ModelView<? extends T> asReadOnly(ModelType<T> type, @Nullable ModelRuleDescriptor ruleDescriptor) {
+ ModelView<? extends T> modelView = getAdapter().asReadOnly(type, this, ruleDescriptor);
+ if (modelView == null) {
+ throw new IllegalStateException("Model node " + getPath() + " cannot be expressed as a read-only view of type " + type);
+ }
+ return modelView;
+ }
+
+ @Override
+ public <T> ModelView<? extends T> asWritable(ModelType<T> type, ModelRuleDescriptor ruleDescriptor, List<ModelView<?>> inputs) {
+ ModelView<? extends T> modelView = getAdapter().asWritable(type, this, ruleDescriptor, inputs);
+ if (modelView == null) {
+ throw new IllegalStateException("Model node " + getPath() + " cannot be expressed as a mutable view of type " + type);
+ }
+ return modelView;
+ }
+
+ @Override
public <T> T getPrivateData(Class<T> type) {
return getPrivateData(ModelType.of(type));
}
@@ -989,7 +849,7 @@ public class DefaultModelRegistry implements ModelRegistry {
if (!getPath().isDirectChild(creator.getPath())) {
throw new IllegalArgumentException(String.format("Reference element creator has a path (%s) which is not a child of this node (%s).", creator.getPath(), getPath()));
}
- registerNode(this, new ModelReferenceNode(toCreatorBinder(creator, ModelPath.ROOT)));
+ registerNode(this, new ModelReferenceNode(toCreatorBinder(creator, ModelPath.ROOT), this));
}
@Override
@@ -1008,11 +868,6 @@ public class DefaultModelRegistry implements ModelRegistry {
}
@Override
- public ModelNodeInternal getTarget() {
- return this;
- }
-
- @Override
public void setTarget(ModelNode target) {
throw new UnsupportedOperationException(String.format("This node (%s) is not a reference to another node.", getPath()));
}
@@ -1314,6 +1169,10 @@ public class DefaultModelRegistry implements ModelRegistry {
boolean doCalculateDependencies(GoalGraph graph, Collection<ModelGoal> dependencies) {
// Must graph-close each child first
for (ModelNodeInternal child : node.getLinks()) {
+ if (child.getPath().isDescendant(getPath())) {
+ // The linked node is an ancestor of this node, so is already being closed
+ continue;
+ }
dependencies.add(graph.nodeAtState(new NodeAtState(child.getPath(), GraphClosed)));
}
return true;
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/ModelNodeInternal.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/ModelNodeInternal.java
index 0a999b8..8348f80 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/ModelNodeInternal.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/ModelNodeInternal.java
@@ -23,7 +23,6 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
-import org.gradle.api.Nullable;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.type.ModelType;
@@ -51,6 +50,7 @@ abstract class ModelNodeInternal implements MutableModelNode {
private final Set<ModelNodeInternal> dependents = Sets.newHashSet();
private ModelNode.State state = ModelNode.State.Known;
private boolean hidden;
+ private final List<ModelRuleDescriptor> executedRules = Lists.newArrayList();
public ModelNodeInternal(CreatorRuleBinder creatorBinder) {
this.creatorBinder = creatorBinder;
@@ -102,12 +102,13 @@ abstract class ModelNodeInternal implements MutableModelNode {
}
public void notifyFired(RuleBinder binder) {
- assert binder.isBound();
+ assert binder.isBound() : "RuleBinder must be in a bound state";
for (ModelBinding inputBinding : binder.getInputBindings()) {
ModelNodeInternal node = inputBinding.getNode();
dependencies.add(node);
node.dependents.add(this);
}
+ executedRules.add(binder.getDescriptor());
}
public Iterable<? extends ModelNode> getDependencies() {
@@ -138,10 +139,6 @@ abstract class ModelNodeInternal implements MutableModelNode {
return state.mutable;
}
- public boolean canApply(ModelNode.State targetState) {
- return state.compareTo(targetState) < 0;
- }
-
public ModelPromise getPromise() {
return creatorBinder.getCreator().getPromise();
}
@@ -155,30 +152,10 @@ abstract class ModelNodeInternal implements MutableModelNode {
return getPath().toString();
}
- public abstract ModelNodeInternal getTarget();
-
public abstract Iterable<? extends ModelNodeInternal> getLinks();
public abstract ModelNodeInternal addLink(ModelNodeInternal node);
- @Override
- public <T> ModelView<? extends T> asReadOnly(ModelType<T> type, @Nullable ModelRuleDescriptor ruleDescriptor) {
- ModelView<? extends T> modelView = getAdapter().asReadOnly(type, this, ruleDescriptor);
- if (modelView == null) {
- throw new IllegalStateException("Model node " + getPath() + " cannot be expressed as a read-only view of type " + type);
- }
- return modelView;
- }
-
- @Override
- public <T> ModelView<? extends T> asWritable(ModelType<T> type, ModelRuleDescriptor ruleDescriptor, List<ModelView<?>> inputs) {
- ModelView<? extends T> modelView = getAdapter().asWritable(type, this, ruleDescriptor, inputs);
- if (modelView == null) {
- throw new IllegalStateException("Model node " + getPath() + " cannot be expressed as a mutable view of type " + type);
- }
- return modelView;
- }
-
public void reset() {
if (getState() != State.Known) {
setState(State.Known);
@@ -201,10 +178,28 @@ abstract class ModelNodeInternal implements MutableModelNode {
}
}
- @Nullable
@Override
public Optional<String> getValueDescription() {
this.ensureUsable();
return this.getAdapter().getValueDescription(this);
}
+
+ @Override
+ public Optional<String> getTypeDescription() {
+ this.ensureUsable();
+ ModelView<?> modelView = getAdapter().asReadOnly(ModelType.untyped(), this, null);
+ if (modelView != null) {
+ ModelType<?> type = modelView.getType();
+ if (type != null) {
+ return Optional.of(type.toString());
+ }
+ modelView.close();
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public List<ModelRuleDescriptor> getExecutedRules() {
+ return this.executedRules;
+ }
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/ModelReferenceNode.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/ModelReferenceNode.java
new file mode 100644
index 0000000..b695de6
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/ModelReferenceNode.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.registry;
+
+import org.gradle.api.Nullable;
+import org.gradle.internal.Actions;
+import org.gradle.model.RuleSource;
+import org.gradle.model.internal.core.*;
+import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
+import org.gradle.model.internal.type.ModelType;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A model node that is a reference to some other node.
+ */
+class ModelReferenceNode extends ModelNodeInternal {
+ private ModelNodeInternal target;
+ private final MutableModelNode parent;
+
+ public ModelReferenceNode(CreatorRuleBinder creatorBinder, MutableModelNode parent) {
+ super(creatorBinder);
+ this.parent = parent;
+ }
+
+ @Override
+ public void setTarget(ModelNode target) {
+ this.target = (ModelNodeInternal) target;
+ }
+
+ @Override
+ public <T> ModelView<? extends T> asWritable(ModelType<T> type, ModelRuleDescriptor ruleDescriptor, List<ModelView<?>> implicitDependencies) {
+ return target == null ? new InstanceModelView<T>(getPath(), type, null, Actions.doNothing()) : target.asWritable(type, ruleDescriptor, implicitDependencies);
+ }
+
+ @Override
+ public <T> ModelView<? extends T> asReadOnly(ModelType<T> type, @Nullable ModelRuleDescriptor ruleDescriptor) {
+ return target == null ? new InstanceModelView<T>(getPath(), type, null, Actions.doNothing()) : target.asReadOnly(type, ruleDescriptor);
+ }
+
+ @Override
+ public ModelNodeInternal addLink(ModelNodeInternal node) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addLink(ModelCreator creator) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addReference(ModelCreator creator) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeLink(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> void applyToSelf(ModelActionRole type, ModelAction<T> action) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> void applyToAllLinks(ModelActionRole type, ModelAction<T> action) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> void applyToAllLinksTransitive(ModelActionRole type, ModelAction<T> action) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> void applyToLink(ModelActionRole type, ModelAction<T> action) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void applyToLink(String name, Class<? extends RuleSource> rules) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void applyToLinks(ModelType<?> type, Class<? extends RuleSource> rules) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void applyToAllLinksTransitive(ModelType<?> type, Class<? extends RuleSource> rules) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void applyToSelf(Class<? extends RuleSource> rules) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getLinkCount(ModelType<?> type) {
+ return target == null ? 0 : target.getLinkCount(type);
+ }
+
+ @Override
+ public Set<String> getLinkNames(ModelType<?> type) {
+ return target == null ? Collections.<String>emptySet() : target.getLinkNames(type);
+ }
+
+ @Nullable
+ @Override
+ public MutableModelNode getLink(String name) {
+ return target == null ? null : target.getLink(name);
+ }
+
+ @Override
+ public Iterable<? extends ModelNodeInternal> getLinks() {
+ return target == null ? Collections.<ModelNodeInternal>emptyList() : target.getLinks();
+ }
+
+ @Override
+ public Iterable<? extends MutableModelNode> getLinks(ModelType<?> type) {
+ return target == null ? Collections.<MutableModelNode>emptyList() : target.getLinks(type);
+ }
+
+ @Override
+ public int getLinkCount() {
+ return target == null ? 0 : target.getLinkCount();
+ }
+
+ @Override
+ public boolean hasLink(String name, ModelType<?> type) {
+ return target != null && target.hasLink(name, type);
+ }
+
+ @Override
+ public boolean hasLink(String name) {
+ return target != null && target.hasLink(name);
+ }
+
+ @Override
+ public <T> T getPrivateData(ModelType<T> type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> void setPrivateData(Class<? super T> type, T object) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> void setPrivateData(ModelType<? super T> type, T object) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getPrivateData() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T getPrivateData(Class<T> type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void ensureUsable() {
+ if (target != null) {
+ target.ensureUsable();
+ }
+ }
+
+ @Override
+ public void realize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public MutableModelNode getParent() {
+ return parent;
+ }
+}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/UnboundModelRulesException.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/UnboundModelRulesException.java
index 13231c2..f61d68d 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/UnboundModelRulesException.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/registry/UnboundModelRulesException.java
@@ -26,6 +26,7 @@ import java.util.List;
public class UnboundModelRulesException extends GradleException {
+ private static final String MESSAGE = "The following model rules could not be applied due to unbound inputs and/or subjects:";
private final List<? extends UnboundRule> rules;
public UnboundModelRulesException(List<? extends UnboundRule> rules) {
@@ -36,7 +37,8 @@ public class UnboundModelRulesException extends GradleException {
private static String toMessage(Iterable<? extends UnboundRule> rules) {
StringWriter string = new StringWriter();
PrintWriter writer = new PrintWriter(string);
- writer.println("The following model rules are unbound:");
+ writer.println(MESSAGE);
+ writer.println();
new UnboundRulesReporter(writer, " ").reportOn(rules);
return string.toString();
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRuleInput.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRuleInput.java
index 32252b5..00ab889 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRuleInput.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRuleInput.java
@@ -73,11 +73,11 @@ public class UnboundRuleInput {
}
public static Builder type(Class<?> type) {
- return type(type.getName());
+ return type(ModelType.of(type));
}
public static Builder type(ModelType<?> type) {
- return type(type.toString());
+ return type(type.getSimpleName());
}
@NotThreadSafe
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRulesReporter.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRulesReporter.java
index 30b428a..ec362da 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRulesReporter.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/report/unbound/UnboundRulesReporter.java
@@ -34,57 +34,63 @@ public class UnboundRulesReporter {
}
public void reportOn(Iterable<? extends UnboundRule> rules) {
- boolean first = true;
for (UnboundRule rule : rules) {
- if (!first) {
- writer.println();
- }
- first = false;
-
writer.print(prefix);
-
- writer.print(rule.getDescriptor());
+ writer.println(rule.getDescriptor());
if (rule.getMutableInputs().size() > 0) {
- heading("Mutable:");
+ heading("subject:");
reportInputs(rule.getMutableInputs());
}
if (rule.getImmutableInputs().size() > 0) {
- heading("Immutable:");
+ heading("inputs:");
reportInputs(rule.getImmutableInputs());
}
+ writer.println();
}
+ writer.println("[*] - indicates that a model item could not be found for the path or type.");
}
private void reportInputs(Iterable<? extends UnboundRuleInput> inputs) {
for (UnboundRuleInput input : inputs) {
- item();
- writer.print(input.isBound() ? "+ " : "- ");
- String path = input.getPath() == null ? "<unspecified>" : input.getPath();
- writer.print(String.format("%s (%s)", path, input.getType()));
+ writer.print(indent(2));
+ writer.write("- ");
+ writer.write(input.getPath() == null ? "<no path>" : input.getPath());
+ writer.write(" ");
+ writer.write(input.getType() == null ? "<untyped>" : input.getType());
if (input.getDescription() != null) {
- writer.print(String.format(" %s", input.getDescription()));
+ writer.write(" ");
+ writer.write("(");
+ writer.write(input.getDescription());
+ writer.write(")");
+ }
+ if (!input.isBound()) {
+ writer.write(" ");
+ writer.write("[*]");
}
+ writer.println();
if (input.getPath() == null && input.getScope() != null) {
- writer.print(String.format(" in scope of '%s'", input.getScope()));
+ writer.write(indent(4));
+ writer.write("scope: ");
+ writer.println(input.getScope());
}
if (input.getSuggestedPaths().size() > 0) {
- writer.print(" - suggestions: ");
- writer.print(Joiner.on(", ").join(input.getSuggestedPaths()));
+ writer.write(indent(4));
+ writer.write("suggestions: ");
+ writer.println(Joiner.on(", ").join(input.getSuggestedPaths()));
}
}
}
- private void item() {
- writer.println();
- writer.print(prefix);
- writer.print(INDENT);
- writer.print(INDENT);
+ private void heading(String heading) {
+ writer.print(indent(1));
+ writer.println(heading);
}
- private void heading(String heading) {
- writer.println();
- writer.print(prefix);
- writer.print(INDENT);
- writer.print(heading);
+ private String indent(int times) {
+ StringBuffer buff = new StringBuffer(prefix);
+ for (int i = 0; i < times; i++) {
+ buff.append(INDENT);
+ }
+ return buff.toString();
}
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/type/ModelType.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/type/ModelType.java
index 4ac9fea..af97a64 100644
--- a/subprojects/model-core/src/main/java/org/gradle/model/internal/type/ModelType.java
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/type/ModelType.java
@@ -225,11 +225,19 @@ public abstract class ModelType<T> {
for (Type type : ((WildcardType) runtimeType).getUpperBounds()) {
ModelType.of(type).addAllClasses(builder);
}
+ } else if (runtimeType instanceof TypeVariable) {
+ for (Type type : ((TypeVariable) runtimeType).getBounds()) {
+ ModelType.of(type).addAllClasses(builder);
+ }
} else {
throw new IllegalArgumentException("Unable to deal with type " + runtimeType + " (" + runtimeType.getClass() + ")");
}
}
+ public String getName() {
+ return wrapper.getRepresentation(true);
+ }
+
public String getSimpleName() {
return wrapper.getRepresentation(false);
}
@@ -342,6 +350,13 @@ public abstract class ModelType<T> {
toWrappers(wildcardType.getLowerBounds()),
type.hashCode()
);
+ } else if (type instanceof TypeVariable) {
+ TypeVariable<?> typeVariable = (TypeVariable<?>) type;
+ return new TypeVariableTypeWrapper<GenericDeclaration>(
+ typeVariable.getName(),
+ toWrappers(typeVariable.getBounds()),
+ type.hashCode()
+ );
} else {
throw new IllegalArgumentException("cannot wrap type of type " + type.getClass());
}
diff --git a/subprojects/model-core/src/main/java/org/gradle/model/internal/type/TypeVariableTypeWrapper.java b/subprojects/model-core/src/main/java/org/gradle/model/internal/type/TypeVariableTypeWrapper.java
new file mode 100644
index 0000000..f55b762
--- /dev/null
+++ b/subprojects/model-core/src/main/java/org/gradle/model/internal/type/TypeVariableTypeWrapper.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.type;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.security.AccessControlException;
+import java.util.Arrays;
+
+/**
+ * Wrapper for a {@link TypeVariable}, designed to be used only to represent a type variable in a
+ * {@link org.gradle.model.internal.manage.schema.cache.WeakClassSet}. It ignores annotations on
+ * on the type variable, and throws an {@link UnsupportedOperationException} if
+ * {@link #getGenericDeclaration()} is called.
+ */
+public class TypeVariableTypeWrapper<D extends GenericDeclaration> implements TypeWrapper {
+ private static final Class<?>[] TYPE_VARIABLE_INTERFACE = {TypeVariable.class};
+
+ private final String name;
+ private final TypeWrapper[] bounds;
+ private final int hashCode;
+
+ public TypeVariableTypeWrapper(String name, TypeWrapper[] bounds, int hashCode) {
+ this.name = name;
+ this.bounds = bounds;
+ this.hashCode = hashCode;
+ }
+
+ @Override
+ public Type unwrap() {
+ return (Type) Proxy.newProxyInstance(getClass().getClassLoader(), TYPE_VARIABLE_INTERFACE, new TypeVariableInvocationHandler(this));
+ }
+
+ @Override
+ public String getRepresentation(boolean full) {
+ return name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Type[] getBounds() {
+ return ModelType.unwrap(bounds);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TypeVariable)) {
+ return false;
+ } else {
+ TypeVariable<?> var2 = (TypeVariable<?>) o;
+ return Objects.equal(this.getName(), var2.getName())
+ && Arrays.equals(this.getBounds(), var2.getBounds());
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+ return false;
+ }
+
+ public Annotation[] getDeclaredAnnotations() {
+ return new Annotation[0];
+ }
+
+ public Annotation[] getAnnotations() {
+ return new Annotation[0];
+ }
+
+ public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
+ return null;
+ }
+
+ public D getGenericDeclaration() {
+ throw new UnsupportedOperationException();
+ }
+
+ // This is taken from Google Guava: https://github.com/google/guava/blob/master/guava/src/com/google/common/reflect/Types.java
+ /*
+ * Invocation handler to work around a compatibility problem between Java 7 and Java 8.
+ *
+ * <p>Java 8 introduced a new method {@code getAnnotatedBounds()} in the {@link TypeVariable}
+ * interface, whose return type {@code AnnotatedType[]} is also new in Java 8. That means that we
+ * cannot implement that interface in source code in a way that will compile on both Java 7 and
+ * Java 8. If we include the {@code getAnnotatedBounds()} method then its return type means
+ * it won't compile on Java 7, while if we don't include the method then the compiler will
+ * complain that an abstract method is unimplemented. So instead we use a dynamic proxy to
+ * get an implementation. If the method being called on the {@code TypeVariable} instance has
+ * the same name as one of the public methods of {@link TypeVariableImpl}, the proxy calls
+ * the same method on its instance of {@code TypeVariableImpl}. Otherwise it throws {@link
+ * UnsupportedOperationException}; this should only apply to {@code getAnnotatedBounds()}. This
+ * does mean that users on Java 8 who obtain an instance of {@code TypeVariable} from {@link
+ * TypeResolver#resolveType} will not be able to call {@code getAnnotatedBounds()} on it, but that
+ * should hopefully be rare.
+ *
+ * <p>This workaround should be removed at a distant future time when we no longer support Java
+ * versions earlier than 8.
+ */
+ private static final class TypeVariableInvocationHandler implements InvocationHandler {
+ private static final ImmutableMap<String, Method> TYPE_VARIABLE_METHODS;
+
+ static {
+ ImmutableMap.Builder<String, Method> builder = ImmutableMap.builder();
+ for (Method method : TypeVariableTypeWrapper.class.getMethods()) {
+ if (method.getDeclaringClass().equals(TypeVariableTypeWrapper.class)) {
+ try {
+ method.setAccessible(true);
+ } catch (AccessControlException e) {
+ // OK: the method is accessible to us anyway. The setAccessible call is only for
+ // unusual execution environments where that might not be true.
+ }
+ builder.put(method.getName(), method);
+ }
+ }
+ TYPE_VARIABLE_METHODS = builder.build();
+ }
+
+ private final TypeVariableTypeWrapper<?> wrapper;
+
+ TypeVariableInvocationHandler(TypeVariableTypeWrapper<?> wrapper) {
+ this.wrapper = wrapper;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String methodName = method.getName();
+ Method typeVariableMethod = TYPE_VARIABLE_METHODS.get(methodName);
+ if (typeVariableMethod == null) {
+ throw new UnsupportedOperationException(methodName);
+ } else {
+ try {
+ return typeVariableMethod.invoke(wrapper, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ }
+ }
+}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedModelMapTypesTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedModelMapTypesTest.groovy
index ac14967..f8d405a 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedModelMapTypesTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedModelMapTypesTest.groovy
@@ -38,15 +38,6 @@ class ManagedModelMapTypesTest extends Specification {
noExceptionThrown()
}
- def "type must be managed struct"() {
- when:
- schemaStore.getSchema(ModelTypes.modelMap(String))
-
- then:
- def e = thrown InvalidManagedModelElementTypeException
- e.message == "Invalid managed model type $ModelMap.name<$String.name>: cannot create a model map of type $String.name as it is not a $Managed.name type."
- }
-
def "must have type param"() {
when:
schemaStore.getSchema(ModelType.of(ModelMap))
@@ -100,13 +91,30 @@ class ManagedModelMapTypesTest extends Specification {
abstract ModelMap<NamedThingInterface> getMap()
}
+ @Managed
+ static abstract class WritableSetProperty {
+ abstract void setSet(ModelSet<NamedThingInterface> set)
+
+ abstract ModelSet<NamedThingInterface> getSet()
+ }
+
def "map cannot be writable"() {
when:
schemaStore.getSchema(ModelType.of(WritableMapProperty))
then:
def e = thrown InvalidManagedModelElementTypeException
- e.message == "Invalid managed model type $WritableMapProperty.name: property 'map' cannot have a setter ($ModelMap.name properties must be read only)."
+ e.message == "Invalid managed model type org.gradle.model.ManagedModelMapTypesTest\$WritableMapProperty: property 'map' cannot have a setter (org.gradle.model.ModelMap<org.gradle.model.NamedThingInterface> properties must be read only)."
+
+
}
+ def "set cannot be writable"() {
+ when:
+ schemaStore.getSchema(ModelType.of(WritableSetProperty))
+
+ then:
+ def e = thrown InvalidManagedModelElementTypeException
+ e.message == "Invalid managed model type org.gradle.model.ManagedModelMapTypesTest\$WritableSetProperty: property 'set' cannot have a setter (org.gradle.model.ModelSet<org.gradle.model.NamedThingInterface> properties must be read only)."
+ }
}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNamedTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNamedTest.groovy
index 94254cf..7f433dc 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNamedTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNamedTest.groovy
@@ -17,8 +17,8 @@
package org.gradle.model
import org.gradle.api.Named
+import org.gradle.model.internal.core.ModelCreators
import org.gradle.model.internal.fixture.ModelRegistryHelper
-import org.gradle.model.internal.inspect.DefaultModelCreatorFactory
import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.model.internal.manage.schema.extract.InvalidManagedModelElementTypeException
import spock.lang.Specification
@@ -27,18 +27,16 @@ class ManagedNamedTest extends Specification {
def r = new ModelRegistryHelper()
def schemaStore = DefaultModelSchemaStore.getInstance()
- def creatorFactory = new DefaultModelCreatorFactory(schemaStore)
-
def "named struct has name name property populated"() {
when:
- r.create(creatorFactory.creator(r.desc("foo"), r.path("foo"), schemaStore.getSchema(NamedThingInterface)))
+ r.create(ModelCreators.of(r.path("foo"), schemaStore.getSchema(NamedThingInterface).nodeInitializer).descriptor(r.desc("foo")).build())
then:
r.realize("foo", NamedThingInterface).name == "foo"
when:
- r.create(creatorFactory.creator(r.desc("bar"), r.path("bar"), schemaStore.getSchema(NamedThingInterface)))
+ r.create(ModelCreators.of(r.path("bar"), schemaStore.getSchema(NamedThingInterface).nodeInitializer).descriptor(r.desc("bar")).build())
then:
r.realize("bar", NamedThingInterface).name == "bar"
@@ -47,12 +45,13 @@ class ManagedNamedTest extends Specification {
@Managed
static abstract class NonNamedThing {
abstract String getName()
+
abstract void setName(String name)
}
def "named struct does not have name populated if does not implement named"() {
when:
- r.create(creatorFactory.creator(r.desc("foo"), r.path("foo"), schemaStore.getSchema(NonNamedThing)))
+ r.create(ModelCreators.of(r.path("foo"), schemaStore.getSchema(NonNamedThing).nodeInitializer).descriptor(r.desc("foo")).build())
then:
r.realize("foo", NonNamedThing).name == null
@@ -74,6 +73,7 @@ class ManagedNamedTest extends Specification {
@Managed
static abstract class NamedThingWithSetter implements Named {
abstract String getName()
+
abstract void setName(String name)
}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNodeBackedModelMapTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNodeBackedModelMapTest.groovy
index 5455939..ce9ba4b 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNodeBackedModelMapTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/ManagedNodeBackedModelMapTest.groovy
@@ -18,13 +18,8 @@ package org.gradle.model
import org.gradle.api.Named
import org.gradle.api.internal.ClosureBackedAction
-import org.gradle.model.internal.core.ModelNode
-import org.gradle.model.internal.core.ModelPath
-import org.gradle.model.internal.core.ModelReference
-import org.gradle.model.internal.core.ModelRuleExecutionException
-import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor
+import org.gradle.model.internal.core.*
import org.gradle.model.internal.fixture.ModelRegistryHelper
-import org.gradle.model.internal.inspect.DefaultModelCreatorFactory
import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.model.internal.manage.schema.extract.InvalidManagedModelElementTypeException
import org.gradle.model.internal.registry.UnboundModelRulesException
@@ -43,10 +38,9 @@ class ManagedNodeBackedModelMapTest extends Specification {
def itemType = ModelType.of(NamedThingInterface)
def modelMapType = ModelTypes.modelMap(itemType)
def schemaStore = DefaultModelSchemaStore.instance
- def modelCreatorFactory = new DefaultModelCreatorFactory(schemaStore)
def setup() {
- registry.create(modelCreatorFactory.creator(new SimpleModelRuleDescriptor("creator"), path, schemaStore.getSchema(modelMapType)))
+ registry.create(ModelCreators.of(path, schemaStore.getSchema(modelMapType).nodeInitializer).descriptor("creator").build())
}
void mutate(@DelegatesTo(ModelMap) Closure<?> action) {
@@ -655,12 +649,14 @@ class ManagedNodeBackedModelMapTest extends Specification {
then:
UnboundModelRulesException e = thrown()
- normaliseLineSeparators(e.message) == """The following model rules are unbound:
- $ElementRules.name#connectElementToInput($Bean.name, $String.name)
- Mutable:
- - <unspecified> ($Bean.name) parameter 1 in scope of 'beans.element\'
- Immutable:
- - <unspecified> ($String.name) parameter 2"""
+ normaliseLineSeparators(e.message).contains('''
+ ManagedNodeBackedModelMapTest.ElementRules#connectElementToInput
+ subject:
+ - <no path> ManagedNodeBackedModelMapTest.Bean (parameter 1) [*]
+ scope: beans.element
+ inputs:
+ - <no path> String (parameter 2) [*]
+''')
}
static class SetOther extends RuleSource {
@@ -845,6 +841,7 @@ class ManagedNodeBackedModelMapTest extends Specification {
abstract static class Invalid<T> implements SpecialNamedThingInterface {
}
+
def "cannot create invalid subtype"() {
when:
mutate {
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/UnmanagedNodeBackedModelMapTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/UnmanagedNodeBackedModelMapTest.groovy
index 8581ecc..73e281c 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/UnmanagedNodeBackedModelMapTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/UnmanagedNodeBackedModelMapTest.groovy
@@ -710,12 +710,14 @@ class UnmanagedNodeBackedModelMapTest extends Specification {
then:
UnboundModelRulesException e = thrown()
- normaliseLineSeparators(e.message) == """The following model rules are unbound:
- $ElementRules.name#connectElementToInput($Bean.name, $String.name)
- Mutable:
- - <unspecified> ($Bean.name) parameter 1 in scope of 'beans.element\'
- Immutable:
- - <unspecified> ($String.name) parameter 2"""
+ normaliseLineSeparators(e.message).contains '''
+ UnmanagedNodeBackedModelMapTest.ElementRules#connectElementToInput
+ subject:
+ - <no path> UnmanagedNodeBackedModelMapTest.Bean (parameter 1) [*]
+ scope: beans.element
+ inputs:
+ - <no path> String (parameter 2) [*]
+'''
}
static class SetOther extends RuleSource {
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptorTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptorTest.groovy
index e4140f0..68810f9 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptorTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/core/rule/describe/MethodModelRuleDescriptorTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.model.internal.core.rule.describe
+import org.gradle.model.internal.type.ModelType
import spock.lang.Specification
class MethodModelRuleDescriptorTest extends Specification {
@@ -26,14 +27,23 @@ class MethodModelRuleDescriptorTest extends Specification {
MethodModelRuleDescriptor.of(getClass(), method).describeTo(sb)
then:
- sb.toString() == getClass().name + "#" + method + description
+ sb.toString() == ModelType.of(getClass()).simpleName + "#" + method
where:
- method | description
- "noArgs" | "()"
- "oneArg" | "(java.lang.String)"
- "twoArgs" | "(java.lang.String, java.lang.String)"
- "genericArgs" | "(java.util.List<java.lang.String>, java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>)"
+ method << [
+ "noArgs",
+ "oneArg",
+ "twoArgs",
+ "genericArgs"]
+ }
+
+ def "inner classes are described"() {
+ when:
+ def sb = new StringBuilder()
+ MethodModelRuleDescriptor.of(Outer.Inner, "noArgs").describeTo(sb)
+
+ then:
+ sb.toString() == 'MethodModelRuleDescriptorTest.Outer.Inner#noArgs'
}
def noArgs() {}
@@ -43,4 +53,10 @@ class MethodModelRuleDescriptorTest extends Specification {
def twoArgs(String s1, String s2) {}
def genericArgs(List<String> list, Map<Integer, List<String>> map) {}
+
+ class Outer {
+ static class Inner {
+ def noArgs() {}
+ }
+ }
}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleBindingTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleBindingTest.groovy
index b621d68..ae0c8c8 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleBindingTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleBindingTest.groovy
@@ -31,7 +31,7 @@ import spock.lang.Unroll
* Test the binding of rules by the registry.
*/
class ModelRuleBindingTest extends Specification {
- def extractor = new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.instance, new DefaultModelCreatorFactory(DefaultModelSchemaStore.instance)))
+ def extractor = new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.instance))
def modelRegistry = new DefaultModelRegistry(extractor)
static class AmbiguousBindingsInOneSource extends RuleSource {
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleExtractorTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleExtractorTest.groovy
index fb805be..0d478a9 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleExtractorTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleExtractorTest.groovy
@@ -28,16 +28,16 @@ import org.gradle.model.internal.manage.schema.extract.InvalidManagedModelElemen
import org.gradle.model.internal.registry.DefaultModelRegistry
import org.gradle.model.internal.registry.ModelRegistry
import org.gradle.model.internal.type.ModelType
+import org.gradle.test.fixtures.ConcurrentTestUtil
import org.gradle.util.TextUtil
import spock.lang.Specification
import spock.lang.Unroll
-import spock.util.concurrent.PollingConditions
import java.beans.Introspector
class ModelRuleExtractorTest extends Specification {
ModelRegistry registry = new DefaultModelRegistry(null)
- def extractor = new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.instance, new DefaultModelCreatorFactory(DefaultModelSchemaStore.instance)))
+ def extractor = new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.instance))
static class ModelThing {
final String name
@@ -148,7 +148,7 @@ class ModelRuleExtractorTest extends Specification {
then:
def e = thrown(InvalidModelRuleDeclarationException)
- e.message == "$HasMultipleRuleAnnotations.name#thing() is not a valid model rule method: can only be one of [annotated with @Model and returning a model element, @annotated with @Model and taking a managed model element, annotated with @Defaults, annotated with @Mutate, annotated with @Finalize, annotated with @Validate]"
+ e.message == "${ModelType.of(HasMultipleRuleAnnotations).simpleName}#thing is not a valid model rule method: can only be one of [annotated with @Model and returning a model element, @annotated with @Model and taking a managed model element, annotated with @Defaults, annotated with @Mutate, annotated with @Finalize, annotated with @Validate]"
}
static class ConcreteGenericModelType extends RuleSource {
@@ -334,9 +334,9 @@ class ModelRuleExtractorTest extends Specification {
then:
extractor.extract(MutationAndFinalizeRules)*.action*.descriptor == [
- MethodModelRuleDescriptor.of(MutationAndFinalizeRules, "finalize1"),
- MethodModelRuleDescriptor.of(MutationAndFinalizeRules, "mutate1"),
- MethodModelRuleDescriptor.of(MutationAndFinalizeRules, "mutate3")
+ MethodModelRuleDescriptor.of(MutationAndFinalizeRules, "finalize1"),
+ MethodModelRuleDescriptor.of(MutationAndFinalizeRules, "mutate1"),
+ MethodModelRuleDescriptor.of(MutationAndFinalizeRules, "mutate3")
]
}
@@ -368,7 +368,7 @@ class ModelRuleExtractorTest extends Specification {
then:
InvalidModelRuleDeclarationException e = thrown()
- e.message == "$RuleSetCreatingAnInterfaceThatIsNotAnnotatedWithManaged.name#bar($NonManaged.name) is not a valid model rule method: a void returning model element creation rule has to take an instance of a managed type as the first argument"
+ e.message == 'ModelRuleExtractorTest.RuleSetCreatingAnInterfaceThatIsNotAnnotatedWithManaged#bar is not a valid model rule method: a void returning model element creation rule has to take an instance of a managed type as the first argument'
}
static class RuleSourceCreatingAClassAnnotatedWithManaged extends RuleSource {
@@ -383,7 +383,7 @@ class ModelRuleExtractorTest extends Specification {
then:
InvalidModelRuleDeclarationException e = thrown()
- e.message == "Declaration of model rule $RuleSourceCreatingAClassAnnotatedWithManaged.name#bar($ManagedAnnotatedClass.name) is invalid."
+ e.message == 'Declaration of model rule ModelRuleExtractorTest.RuleSourceCreatingAClassAnnotatedWithManaged#bar is invalid.'
e.cause instanceof InvalidManagedModelElementTypeException
e.cause.message == "Invalid managed model type $ManagedAnnotatedClass.name: must be defined as an interface or an abstract class."
}
@@ -400,7 +400,7 @@ class ModelRuleExtractorTest extends Specification {
then:
InvalidModelRuleDeclarationException e = thrown()
- e.message == "$RuleSourceWithAVoidReturningNoArgumentMethod.name#bar() is not a valid model rule method: a void returning model element creation rule has to take a managed model element instance as the first argument"
+ e.message == 'ModelRuleExtractorTest.RuleSourceWithAVoidReturningNoArgumentMethod#bar is not a valid model rule method: a void returning model element creation rule has to take a managed model element instance as the first argument'
}
static class RuleSourceCreatingManagedWithNestedPropertyOfInvalidManagedType extends RuleSource {
@@ -422,7 +422,7 @@ class ModelRuleExtractorTest extends Specification {
then:
InvalidModelRuleDeclarationException e = thrown()
- e.message == "Declaration of model rule $inspected.name#bar($managedType.name) is invalid."
+ e.message == "Declaration of model rule ${getClass().simpleName}.$inspected.simpleName#bar is invalid."
e.cause instanceof InvalidManagedModelElementTypeException
e.cause.message == TextUtil.toPlatformLineSeparators("""Invalid managed model type $invalidTypeName: cannot be a parameterized type.
The type was analyzed due to the following dependencies:
@@ -450,7 +450,7 @@ ${managedType.name}
then:
InvalidModelRuleDeclarationException e = thrown()
- e.message == "Declaration of model rule $RuleSourceCreatingManagedWithNonManageableParent.name#bar($ManagedWithNonManageableParents.name) is invalid."
+ e.message == "Declaration of model rule ${ModelType.of(RuleSourceCreatingManagedWithNonManageableParent).simpleName}#bar is invalid."
e.cause instanceof InvalidManagedModelElementTypeException
e.cause.message == TextUtil.toPlatformLineSeparators("""Invalid managed model type $invalidTypeName: cannot be a parameterized type.
The type was analyzed due to the following dependencies:
@@ -511,7 +511,7 @@ ${ManagedWithNonManageableParents.name}
source = null
then:
- new PollingConditions(timeout: 10).eventually {
+ ConcurrentTestUtil.poll(10) {
System.gc()
extractor.cache.cleanUp()
extractor.cache.size() == 0
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleSourceDetectorTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleSourceDetectorTest.groovy
index 0b29f28..8941f8c 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleSourceDetectorTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/ModelRuleSourceDetectorTest.groovy
@@ -17,9 +17,9 @@
package org.gradle.model.internal.inspect
import org.gradle.model.RuleSource
+import org.gradle.test.fixtures.ConcurrentTestUtil
import spock.lang.Specification
import spock.lang.Unroll
-import spock.util.concurrent.PollingConditions
class ModelRuleSourceDetectorTest extends Specification {
@@ -86,7 +86,7 @@ class ModelRuleSourceDetectorTest extends Specification {
cl.clearCache()
then:
- new PollingConditions(timeout: 10).eventually {
+ ConcurrentTestUtil.poll(10) {
System.gc()
detector.cache.cleanUp()
detector.cache.size() == 0
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/MutationRuleExecutionOrderTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/MutationRuleExecutionOrderTest.groovy
index e97b832..4331675 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/MutationRuleExecutionOrderTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/inspect/MutationRuleExecutionOrderTest.groovy
@@ -26,7 +26,7 @@ import org.gradle.model.internal.registry.DefaultModelRegistry
import spock.lang.Specification
class MutationRuleExecutionOrderTest extends Specification {
- def extractor = new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.instance, new DefaultModelCreatorFactory(DefaultModelSchemaStore.instance)))
+ def extractor = new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.instance))
def modelRegistry = new ModelRegistryHelper(new DefaultModelRegistry(extractor))
static class MutationRecorder {
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/projection/ModelSetModelProjectionTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/projection/ModelSetModelProjectionTest.groovy
index 7f045fb..734aab7 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/projection/ModelSetModelProjectionTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/projection/ModelSetModelProjectionTest.groovy
@@ -17,16 +17,14 @@
package org.gradle.model.internal.manage.projection
import org.gradle.api.internal.ClosureBackedAction
-import org.gradle.internal.BiAction
import org.gradle.model.Managed
-import org.gradle.model.ModelViewClosedException
import org.gradle.model.ModelSet
+import org.gradle.model.ModelViewClosedException
+import org.gradle.model.internal.core.ModelCreators
import org.gradle.model.internal.core.ModelPath
import org.gradle.model.internal.core.ModelReference
import org.gradle.model.internal.core.ModelRuleExecutionException
-import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor
import org.gradle.model.internal.fixture.ModelRegistryHelper
-import org.gradle.model.internal.inspect.DefaultModelCreatorFactory
import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.model.internal.type.ModelType
import spock.lang.Specification
@@ -47,18 +45,14 @@ class ModelSetModelProjectionTest extends Specification {
def collectionPath = ModelPath.path("collection")
def collectionType = new ModelType<ModelSet<NamedThing>>() {}
def schemaStore = DefaultModelSchemaStore.instance
- def factory = new DefaultModelCreatorFactory(schemaStore)
def registry = new ModelRegistryHelper()
private ModelReference<ModelSet<NamedThing>> reference = ModelReference.of(collectionPath, new ModelType<ModelSet<NamedThing>>() {})
def setup() {
registry.create(
- factory.creator(
- new SimpleModelRuleDescriptor("define collection"),
- collectionPath,
- schemaStore.getSchema(collectionType),
- [],
- { value, inputs -> } as BiAction)
+ ModelCreators.of(collectionPath, schemaStore.getSchema(collectionType).nodeInitializer)
+ .descriptor("define collection")
+ .build()
)
}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStoreTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStoreTest.groovy
index d7d7930..497dfe6 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStoreTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/DefaultModelSchemaStoreTest.groovy
@@ -20,17 +20,17 @@ import groovy.transform.CompileStatic
import org.codehaus.groovy.reflection.ClassInfo
import org.gradle.model.Managed
import org.gradle.model.ModelSet
-import org.gradle.model.internal.manage.schema.ModelStructSchema
+import org.gradle.model.internal.manage.schema.ModelManagedImplStructSchema
import org.gradle.model.internal.type.ModelType
+import org.gradle.test.fixtures.ConcurrentTestUtil
import spock.lang.Specification
import spock.lang.Unroll
-import spock.util.concurrent.PollingConditions
import java.beans.Introspector
class DefaultModelSchemaStoreTest extends Specification {
- def store = new DefaultModelSchemaStore()
+ def store = new DefaultModelSchemaStore(new ModelSchemaExtractor());
def "can get schema"() {
// intentionally use two different “instances” of the same type
@@ -54,7 +54,7 @@ class DefaultModelSchemaStoreTest extends Specification {
cl.clearCache()
then:
- new PollingConditions(timeout: 10).eventually {
+ ConcurrentTestUtil.poll(10) {
System.gc()
store.cleanUp()
store.size() == 0
@@ -84,7 +84,7 @@ class DefaultModelSchemaStoreTest extends Specification {
forcefullyClearReferences(schema)
then:
- new PollingConditions(timeout: 10).eventually {
+ ConcurrentTestUtil.poll(10) {
System.gc()
store.cleanUp()
store.size() == 0
@@ -97,7 +97,7 @@ class DefaultModelSchemaStoreTest extends Specification {
@CompileStatic
// must be compile static to avoid call sites being created with soft class refs
- private static void forcefullyClearReferences(ModelStructSchema schema) {
+ private static void forcefullyClearReferences(ModelManagedImplStructSchema schema) {
// Remove strong internal circular ref
(schema.type.rawClass.classLoader as GroovyClassLoader).clearCache()
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGeneratorTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGeneratorTest.groovy
index 2d9f057..45754ec 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGeneratorTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ManagedProxyClassGeneratorTest.groovy
@@ -15,16 +15,25 @@
*/
package org.gradle.model.internal.manage.schema.extract
-
+import com.google.common.collect.ImmutableMap
import org.gradle.model.internal.core.MutableModelNode
import org.gradle.model.internal.manage.instance.ManagedInstance
import org.gradle.model.internal.manage.instance.ModelElementState
+import org.gradle.model.internal.manage.schema.ModelProperty
+import org.gradle.model.internal.manage.schema.ModelProperty.StateManagementType
+import org.gradle.model.internal.method.WeaklyTypeReferencingMethod
+import org.gradle.model.internal.type.ModelType
import spock.lang.Ignore
import spock.lang.Specification
+import spock.lang.Unroll
+
+import java.lang.reflect.Type
+
+import static org.gradle.model.internal.manage.schema.ModelProperty.StateManagementType.*
class ManagedProxyClassGeneratorTest extends Specification {
static def generator = new ManagedProxyClassGenerator()
- static classes = [:]
+ static Map<Class<?>, Map<Class<?>, Class<?>>> generated = [:].withDefault { [:] }
def "generates a proxy class for an interface"() {
expect:
@@ -34,15 +43,72 @@ class ManagedProxyClassGeneratorTest extends Specification {
def "mixes in ManagedInstance"() {
def node = Stub(MutableModelNode)
- def state = Stub(ModelElementState) {
+ def state = Mock(ModelElementState) {
getBackingNode() >> node
}
- expect:
- def proxyClass = generate(SomeType)
- def impl = proxyClass.newInstance(state)
+ when:
+ Class<? extends SomeType> proxyClass = generate(SomeType)
+ SomeType impl = proxyClass.newInstance(state)
+
+ then:
impl instanceof ManagedInstance
- impl.backingNode == node
+ ((ManagedInstance) impl).backingNode == node
+
+ when:
+ impl.value = 1
+ then:
+ 1 * state.set("value", 1)
+
+ when:
+ def value = impl.value
+ then:
+ value == 1
+ 1 * state.get("value") >> { 1 }
+ }
+
+ def "mixes in UnmanagedInstance"() {
+ def node = Stub(MutableModelNode)
+ def state = Mock(ModelElementState) {
+ getBackingNode() >> node
+ }
+
+ when:
+ Class<? extends ManagedSubType> proxyClass = generate(ManagedSubType, InternalUnmanagedType)
+ def unmanagedInstance = new UnmanagedImplType()
+ ManagedSubType impl = proxyClass.newInstance(state, unmanagedInstance)
+
+ then:
+ impl instanceof ManagedInstance
+ ((ManagedInstance) impl).backingNode == node
+
+ when: impl.unmanagedValue = "Lajos"
+ then: unmanagedInstance.unmanagedValue == "Lajos"
+
+ when:
+ def greeting = impl.sayHello()
+ then:
+ greeting == "Hello Lajos"
+
+ expect:
+ ((InternalUnmanagedType) impl).add(2, 3) == 5
+
+ when:
+ ((InternalUnmanagedType) impl).throwError()
+ then:
+ def ex = thrown RuntimeException
+ ex.message == "error"
+
+ when:
+ impl.managedValue = "Tibor"
+ then:
+ 1 * state.set("managedValue", "Tibor")
+
+ when:
+ def managedValue = impl.managedValue
+ then:
+ managedValue == "Tibor"
+ 1 * state.get("managedValue") >> { "Tibor" }
}
def "mixes in toString() implementation that delegates to element state"() {
@@ -78,14 +144,14 @@ class ManagedProxyClassGeneratorTest extends Specification {
@Ignore
def "reports contract type rather than implementation class when attempting to set read-only property"() {
given:
- def impl = newInstance(SomeType)
+ def impl = newInstance(SomeTypeWithReadOnly)
when:
impl.readOnly = '12'
then:
ReadOnlyPropertyException e = thrown()
- e.message == "Cannot set readonly property: readOnly for class: ${SomeType.name}"
+ e.message == "Cannot set readonly property: readOnly for class: ${SomeTypeWithReadOnly.name}"
}
def "reports contract type rather than implementation class when attempting to invoke unknown method"() {
@@ -112,25 +178,135 @@ class ManagedProxyClassGeneratorTest extends Specification {
e.message.startsWith("No signature of method: ${SomeType.name}.setValue() is applicable")
}
- def newInstance(Class<?> type) {
+ @Unroll
+ def "can read and write #value to managed property of type #primitiveType"() {
+ def loader = new GroovyClassLoader(getClass().classLoader)
+ when:
+ def interfaceWithPrimitiveProperty = loader.parseClass """
+ interface PrimitiveProperty {
+ $primitiveType.name getPrimitiveProperty()
+
+ void setPrimitiveProperty($primitiveType.name value)
+ }
+ """
+
+
+ def data = [:]
+ def state = Mock(ModelElementState)
+ state.get(_) >> { args->
+ data[args[0]]
+ }
+ state.set(_, _) >> { args ->
+ data[args[0]] = args[1]
+ }
+ def properties = [property(interfaceWithPrimitiveProperty, 'primitiveProperty', primitiveType, MANAGED, true)]
+ def proxy = generate(interfaceWithPrimitiveProperty, null, properties)
+ def instance = proxy.newInstance(state)
+
+ then:
+ new GroovyShell(loader,new Binding(instance:instance)).evaluate """
+ instance.primitiveProperty = $value
+ assert instance.primitiveProperty == $value
+ instance
+ """
+
+ where:
+ primitiveType | value
+ byte | "123"
+ boolean | "false"
+ boolean | "true"
+ char | "'c'"
+ float | "123.45f"
+ long | "123L"
+ short | "123"
+ int | "123"
+ double | "123.456d"
+ }
+
+
+ def <T> T newInstance(Class<T> type) {
def generated = generate(type)
return generated.newInstance(Stub(ModelElementState))
}
- def generate(Class<?> type) {
- def generated = classes[type]
+ def <T, M extends T, D extends T> Class<? extends T> generate(Class<T> managedType, Class<D> delegateType = null, Collection<ModelProperty<?>> properties = managedProperties[managedType]) {
+ Map<Class<?>, Class<?>> generatedForDelegateType = generated[managedType]
+ Class<? extends T> generated = generatedForDelegateType[delegateType] as Class<? extends T>
if (generated == null) {
- generated = generator.generate(type)
- classes[type] = generated
+ generated = generator.generate(managedType, delegateType, properties)
+ generatedForDelegateType[delegateType] = generated
}
return generated
}
- interface SomeType {
- Integer getValue()
+ private static def property(Class<?> parentType, String name, Type type, StateManagementType stateManagementType, boolean writable = true) {
+ def getter = parentType.getMethod("get" + name.capitalize());
+ def getterRef = new WeaklyTypeReferencingMethod(ModelType.of(parentType), ModelType.of(type), getter)
+ return ModelProperty.of(ModelType.of(type), name, stateManagementType, writable, Collections.emptySet(), getterRef)
+ }
+ static interface SomeType {
+ Integer getValue()
void setValue(Integer value)
+ }
+
+ static abstract class SomeTypeWithReadOnly {
+ abstract Integer getValue()
+ abstract void setValue(Integer value)
+ String getReadOnly() {
+ return "read-only"
+ }
+ }
+
+ static interface PublicUnmanagedType {
+ String getUnmanagedValue()
+ void setUnmanagedValue(String unmanagedValue)
+ String sayHello()
+ }
+
+ static interface InternalUnmanagedType extends PublicUnmanagedType {
+ Integer add(Integer a, Integer b)
+ void throwError()
+ }
- String getReadOnly()
+ static class UnmanagedImplType implements InternalUnmanagedType {
+ String unmanagedValue
+
+ @Override
+ Integer add(Integer a, Integer b) {
+ return a + b
+ }
+
+ @Override
+ String sayHello() {
+ return "Hello ${unmanagedValue}"
+ }
+
+ @Override
+ void throwError() {
+ throw new RuntimeException("error")
+ }
+ }
+
+ static interface ManagedSubType extends PublicUnmanagedType {
+ String getManagedValue()
+ void setManagedValue(String managedValue)
}
+
+ static Map<Class<?>, Collection<ModelProperty<?>>> managedProperties = ImmutableMap.builder()
+ .put(SomeType, [
+ property(SomeType, "value", Integer, MANAGED)
+ ])
+ .put(SomeTypeWithReadOnly, [
+ property(SomeTypeWithReadOnly, "value", Integer, MANAGED),
+ property(SomeTypeWithReadOnly, "readOnly", String, UNMANAGED)
+ ])
+ .put(PublicUnmanagedType, [
+ property(PublicUnmanagedType, "unmanagedValue", String, UNMANAGED)
+ ])
+ .put(ManagedSubType, [
+ property(ManagedSubType, "unmanagedValue", String, DELEGATED),
+ property(ManagedSubType, "managedValue", String, MANAGED)
+ ])
+ .build()
}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractorTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractorTest.groovy
index afee47c..ec76e9a 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractorTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ModelSchemaExtractorTest.groovy
@@ -16,13 +16,13 @@
package org.gradle.model.internal.manage.schema.extract
+import org.gradle.api.Action
import org.gradle.internal.reflect.MethodDescription
import org.gradle.model.Managed
import org.gradle.model.ModelMap
import org.gradle.model.ModelSet
import org.gradle.model.Unmanaged
-import org.gradle.model.internal.manage.schema.ModelMapSchema
-import org.gradle.model.internal.manage.schema.ModelSchema
+import org.gradle.model.internal.manage.schema.*
import org.gradle.model.internal.manage.schema.cache.ModelSchemaCache
import org.gradle.model.internal.type.ModelType
import org.gradle.util.TextUtil
@@ -30,20 +30,24 @@ import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
+import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
import java.util.regex.Pattern
+import static org.gradle.model.internal.manage.schema.ModelProperty.StateManagementType.*
+
+ at SuppressWarnings("GroovyPointlessBoolean")
class ModelSchemaExtractorTest extends Specification {
def classLoader = new GroovyClassLoader(getClass().classLoader)
- def store = new ModelSchemaExtractor()
@Shared
- def cache = new ModelSchemaCache()
+ def store = DefaultModelSchemaStore.getInstance()
static interface NotAnnotatedInterface {}
def "unmanaged type"() {
expect:
- extract(NotAnnotatedInterface).kind == ModelSchema.Kind.UNMANAGED
+ extract(NotAnnotatedInterface) instanceof ModelUnmanagedImplStructSchema
}
@Managed
@@ -104,8 +108,8 @@ class ModelSchemaExtractorTest extends Specification {
def properties = extract(SingleStringNameProperty).properties
then:
- properties.size() == 1
- properties.name.type == ModelType.of(String)
+ properties*.name == ["name"]
+ properties*.type == [ModelType.of(String)]
}
@Managed
@@ -182,44 +186,73 @@ class ModelSchemaExtractorTest extends Specification {
type << [NonStringProperty, ClassWithExtendedFileType]
}
- @Managed
- static interface BytePrimitiveProperty {
- byte getByteProperty()
+ @Unroll
+ def "primitive types are supported - #primitiveType"() {
+ when:
+ def interfaceWithPrimitiveProperty = new GroovyClassLoader(getClass().classLoader).parseClass """
+ import org.gradle.model.Managed
- void setByteProperty(byte value)
- }
+ @Managed
+ interface PrimitiveProperty {
+ $primitiveType.name getPrimitiveProperty()
- def "byte property types are not allowed and there is no suggested replacement"() {
- expect:
- fail BytePrimitiveProperty, Pattern.quote("an unmanaged type")
+ void setPrimitiveProperty($primitiveType.name value)
+ }
+ """
+
+ def properties = extract(interfaceWithPrimitiveProperty).properties
+
+ then:
+ properties*.name == ["primitiveProperty"]
+ properties*.type == [ModelType.of(primitiveType)]
+
+ where:
+ primitiveType << [
+ byte,
+ boolean,
+ char,
+ float,
+ long,
+ short,
+ int,
+ double]
}
@Unroll
- def "boxed types are suggested when primitive types are being used - #primitiveType"() {
+ def "Misaligned types #firstType and #secondType"() {
when:
def interfaceWithPrimitiveProperty = new GroovyClassLoader(getClass().classLoader).parseClass """
import org.gradle.model.Managed
@Managed
interface PrimitiveProperty {
- $primitiveType.name getPrimitiveProperty()
+ $firstType.name getPrimitiveProperty()
- void setPrimitiveProperty($primitiveType.name value)
+ void setPrimitiveProperty($secondType.name value)
}
"""
then:
- fail interfaceWithPrimitiveProperty, primitiveType, Pattern.quote("type is not supported, please use $boxedType.name instead")
+ fail(interfaceWithPrimitiveProperty, "(expected: ${firstType.name}, found: ${secondType.name})")
where:
- primitiveType | boxedType
- boolean.class | Boolean
- char.class | Character
- float.class | Double
- long.class | Long
- short.class | Integer
- int.class | Integer
- double.class | Double
+ firstType | secondType
+ byte | Byte
+ boolean | Boolean
+ char | Character
+ float | Float
+ long | Long
+ short | Short
+ int | Integer
+ double | Double
+ Byte | byte
+ Boolean | boolean
+ Character | char
+ Float | float
+ Long | long
+ Short | short
+ Integer | int
+ Double | double
}
@Managed
@@ -239,7 +272,7 @@ class ModelSchemaExtractorTest extends Specification {
def "multiple properties"() {
when:
- def properties = extract(MultipleProps).properties.values()
+ def properties = extract(MultipleProps).properties
then:
properties*.name == ["prop1", "prop2", "prop3"]
@@ -253,7 +286,7 @@ class ModelSchemaExtractorTest extends Specification {
def "can extract self referencing type"() {
expect:
- extract(SelfReferencing).properties.self.type == ModelType.of(SelfReferencing)
+ extract(SelfReferencing).getProperty("self").type == ModelType.of(SelfReferencing)
}
@Managed
@@ -302,10 +335,10 @@ class ModelSchemaExtractorTest extends Specification {
def "can extract incestuous nest"() {
expect:
- extract(type).properties.a.type == extract(A1).type
- extract(type).properties.b.type == extract(B1).type
- extract(type).properties.c.type == extract(C1).type
- extract(type).properties.d.type == extract(D1).type
+ extract(type).getProperty("a").type == extract(A1).type
+ extract(type).getProperty("b").type == extract(B1).type
+ extract(type).getProperty("c").type == extract(C1).type
+ extract(type).getProperty("d").type == extract(D1).type
where:
type << [A1, B1, C1, D1]
@@ -320,12 +353,13 @@ class ModelSchemaExtractorTest extends Specification {
def "extracts inherited properties"() {
when:
- def properties = extract(WithInheritedProperties).properties.values()
+ def properties = extract(WithInheritedProperties).properties
then:
properties*.name == ["count", "name"]
}
+ @Managed
static interface SingleIntegerValueProperty {
Integer getValue()
@@ -338,7 +372,7 @@ class ModelSchemaExtractorTest extends Specification {
def "extracts properties from multiple parents"() {
when:
- def properties = extract(WithMultipleParents).properties.values()
+ def properties = extract(WithMultipleParents).properties
then:
properties*.name == ["name", "value"]
@@ -359,13 +393,12 @@ class ModelSchemaExtractorTest extends Specification {
def "extracts properties from multiple levels of inheritance"() {
when:
- def properties = extract(WithInheritedPropertiesFromGrandparent).properties.values()
+ def properties = extract(WithInheritedPropertiesFromGrandparent).properties
then:
properties*.name == ["count", "flag", "name"]
}
- @Managed
static interface WithInheritedPropertiesFromNotAnnotated extends SinglePropertyNotAnnotated {
Integer getCount()
@@ -374,7 +407,7 @@ class ModelSchemaExtractorTest extends Specification {
def "can extract inherited properties from an interface not annotated with @Managed"() {
when:
- def properties = extract(WithInheritedPropertiesFromNotAnnotated).properties.values()
+ def properties = extract(WithInheritedPropertiesFromNotAnnotated).properties
then:
properties*.name == ["count", "name"]
@@ -387,6 +420,7 @@ class ModelSchemaExtractorTest extends Specification {
void setValue(String value)
}
+ @Managed
static interface SingleFloatValueProperty {
Float getValue()
@@ -410,6 +444,7 @@ class ModelSchemaExtractorTest extends Specification {
fail ConflictingPropertiesInParents, message
}
+ @Managed
static interface AnotherSingleStringValueProperty {
String getValue()
@@ -422,12 +457,13 @@ class ModelSchemaExtractorTest extends Specification {
def "exact same properties defined in multiple types of the hierarchy are allowed"() {
when:
- def properties = extract(SamePropertyInMultipleTypes).properties.values()
+ def properties = extract(SamePropertyInMultipleTypes).properties
then:
properties*.name == ["value"]
}
+ @Managed
static interface ReadOnlyProperty {
SingleStringValueProperty getSingleStringValueProperty()
}
@@ -439,7 +475,7 @@ class ModelSchemaExtractorTest extends Specification {
def "read only property of a super type can be made writable"() {
when:
- def properties = extract(WritableProperty).properties.values()
+ def properties = extract(WritableProperty).properties
then:
properties*.writable == [true]
@@ -472,6 +508,7 @@ class ModelSchemaExtractorTest extends Specification {
@Managed
interface SpecialThing extends Thing {}
+ @Managed
interface SimpleModel {
Thing getThing()
}
@@ -485,10 +522,10 @@ class ModelSchemaExtractorTest extends Specification {
def "a subclass may specialize a property type"() {
when:
- def properties = extract(SpecialModel).properties.values()
+ def schema = extract(SpecialModel)
then:
- properties*.type == [ModelType.of(SpecialThing)]
+ schema.properties*.type == [ModelType.of(SpecialThing)]
}
@Unroll
@@ -513,13 +550,7 @@ class ModelSchemaExtractorTest extends Specification {
then:
InvalidManagedModelElementTypeException e = thrown()
- e.message == TextUtil.toPlatformLineSeparators("""Invalid managed model type ${new ModelType<ModelSet<Object>>() {}}: cannot create a managed set of type $Object.name as it is an unmanaged type.
-Supported types:
- - enum types
- - JDK value types: String, Boolean, Character, Integer, Long, Double, BigInteger, BigDecimal, File
- - org.gradle.model.ModelSet<?> of a managed type
- - interfaces and abstract classes annotated with org.gradle.model.Managed
- - org.gradle.model.ModelMap<?> of a managed type""")
+ e.message == "Invalid managed model type ${new ModelType<ModelSet<Object>>() {}}: cannot create a managed set of type $Object.name as it is an unmanaged type. Only @Managed types are allowed."
}
def "type argument of a managed set has to be a valid managed type"() {
@@ -578,7 +609,7 @@ $type
def "can extract enum"() {
expect:
- extract(MyEnum).kind == ModelSchema.Kind.VALUE
+ extract(MyEnum) instanceof ModelValueSchema
}
@Managed
@@ -601,7 +632,7 @@ $type
void setThing(InputStream inputStream);
}
- def "unamanaged types must be annotated with unmanaged"() {
+ def "unmanaged types must be annotated with unmanaged"() {
expect:
fail MissingUnmanaged, Pattern.quote("it is an unmanaged type (please annotate the getter with @org.gradle.model.Unmanaged if you want this property to be unmanaged)")
}
@@ -620,7 +651,7 @@ $type
def "subtype can declare property unmanaged"() {
expect:
- extract(ExtendsMissingUnmanaged).properties.get("thing").type.rawClass == InputStream
+ extract(ExtendsMissingUnmanaged).getProperty("thing").type.rawClass == InputStream
}
@Managed
@@ -641,7 +672,7 @@ $type
def "subtype can add unmanaged setter"() {
expect:
- extract(AddsSetterToNoSetterForUnmanaged).properties.get("thing").type.rawClass == InputStream
+ extract(AddsSetterToNoSetterForUnmanaged).getProperty("thing").type.rawClass == InputStream
}
@Managed
@@ -819,7 +850,7 @@ $type
}
private ModelSchema<?> extract(ModelType<?> modelType) {
- store.extract(modelType, cache)
+ store.getSchema(modelType)
}
private ModelSchema<?> extract(Class<?> clazz) {
@@ -895,4 +926,385 @@ interface Managed${typeName} {
}
""")
}
+
+ static class CustomThing {}
+
+ static class UnmanagedThing {}
+
+ def "can register custom strategy"() {
+ when:
+ def strategy = Mock(ModelSchemaExtractionStrategy) {
+ extract(_, _, _) >> { ModelSchemaExtractionContext extractionContext, ModelSchemaStore store, ModelSchemaCache schemaCache ->
+ if (extractionContext.type.rawClass == CustomThing) {
+ return new ModelSchemaExtractionResult(new ModelValueSchema<?>(extractionContext.type))
+ } else {
+ return null
+ }
+ }
+ }
+ def extractor = new ModelSchemaExtractor([strategy], new ModelSchemaAspectExtractor())
+ def store = new DefaultModelSchemaStore(extractor)
+
+ then:
+ store.getSchema(CustomThing) instanceof ModelValueSchema
+ store.getSchema(UnmanagedThing) instanceof ModelUnmanagedImplStructSchema
+ }
+
+ @Managed
+ static abstract class UnmanagedModelMapInManagedType {
+ abstract ModelMap<InputStream> getThings()
+ }
+
+ def "model map type must be managed in a managed type"() {
+ expect:
+ fail UnmanagedModelMapInManagedType, "property 'things' cannot be a model map of type $InputStream.name as it is not a $Managed.name type."
+ }
+
+ static abstract class UnmanagedModelMapInUnmanagedType {
+ ModelMap<InputStream> getThings() { null }
+ }
+
+ def "model map type doesn't have to be managed type in an unmanaged type"() {
+ expect:
+ extract(UnmanagedModelMapInUnmanagedType).getProperty("things").type.rawClass == ModelMap
+ }
+
+ static class SimpleUnmanagedType {
+ String prop
+ String getCalculatedProp() {
+ "calc"
+ }
+ }
+
+ def "can retrieve property value"() {
+ def instance = new SimpleUnmanagedType(prop: "12")
+
+ when:
+ def schema = extract(SimpleUnmanagedType)
+
+ then:
+ assert schema instanceof ModelUnmanagedImplStructSchema
+ schema.getProperty("prop").getPropertyValue(instance) == "12"
+ schema.getProperty("calculatedProp").getPropertyValue(instance) == "calc"
+ }
+
+ static abstract class SimpleUnmanagedTypeWithAnnotations {
+ @CustomTestAnnotation("unmanaged")
+ abstract String getUnmanagedProp()
+
+ @CustomTestAnnotation("unmanagedSetter")
+ abstract void setUnmanagedProp(String value)
+
+ @CustomTestAnnotation("unmanagedCalculated")
+ String getUnmanagedCalculatedProp() {
+ return "unmanaged-calculated"
+ }
+
+ boolean isBuildable() { true }
+
+ int getTime() { 0 }
+ }
+
+ def "properties are extracted from unmanaged type"() {
+ when:
+ def schema = extract(SimpleUnmanagedTypeWithAnnotations)
+
+ then:
+ assert schema instanceof ModelUnmanagedImplStructSchema
+ schema.properties*.name == ["buildable","time", "unmanagedCalculatedProp", "unmanagedProp"]
+
+ schema.getProperty("unmanagedProp").stateManagementType == UNMANAGED
+ schema.getProperty("unmanagedProp").isWritable() == true
+ schema.getProperty("unmanagedCalculatedProp").stateManagementType == UNMANAGED
+ schema.getProperty("unmanagedCalculatedProp").isWritable() == false
+ schema.getProperty("buildable").stateManagementType == UNMANAGED
+ schema.getProperty("buildable").isWritable() == false
+ schema.getProperty("time").stateManagementType == UNMANAGED
+ schema.getProperty("time").isWritable() == false
+ }
+
+ static interface UnmanagedSuperType {
+ @CustomTestAnnotation("unmanaged")
+ abstract String getUnmanagedProp()
+
+ @CustomTestAnnotation("unmanagedSetter")
+ abstract void setUnmanagedProp(String value)
+
+ @CustomTestAnnotation("unmanagedCalculated")
+ String getUnmanagedCalculatedProp()
+
+ boolean isBuildable()
+
+ int getTime()
+ }
+
+ @Managed
+ static abstract class ManagedTypeWithAnnotationsExtendingUnmanagedType implements UnmanagedSuperType {
+ @CustomTestAnnotation("managed")
+ abstract String getManagedProp()
+
+ @CustomTestAnnotation("managedSetter")
+ abstract void setManagedProp(String managedProp)
+
+ @CustomTestAnnotation("managedCalculated")
+ String getManagedCalculatedProp() {
+ return "calc"
+ }
+ }
+
+ def "properties are extracted from unmanaged type with managed super-type"() {
+ def extractor = new ModelSchemaExtractor([
+ new TestUnmanagedTypeWithManagedSuperTypeExtractionStrategy(UnmanagedSuperType)
+ ], new ModelSchemaAspectExtractor())
+ def store = new DefaultModelSchemaStore(extractor)
+
+ when:
+ def schema = store.getSchema(ManagedTypeWithAnnotationsExtendingUnmanagedType)
+
+ then:
+ assert schema instanceof ModelManagedImplStructSchema
+ schema.properties*.name == ["buildable", "managedCalculatedProp", "managedProp", "time", "unmanagedCalculatedProp", "unmanagedProp"]
+
+ schema.getProperty("unmanagedProp").stateManagementType == DELEGATED
+ schema.getProperty("unmanagedProp").isWritable() == true
+
+ schema.getProperty("unmanagedCalculatedProp").stateManagementType == DELEGATED
+ schema.getProperty("unmanagedCalculatedProp").isWritable() == false
+
+ schema.getProperty("managedProp").stateManagementType == MANAGED
+ schema.getProperty("managedProp").isWritable() == true
+
+ schema.getProperty("managedCalculatedProp").stateManagementType == UNMANAGED
+ schema.getProperty("managedCalculatedProp").isWritable() == false
+
+ schema.getProperty("buildable").stateManagementType == DELEGATED
+ schema.getProperty("buildable").isWritable() == false
+
+ schema.getProperty("time").stateManagementType == DELEGATED
+ schema.getProperty("time").isWritable() == false
+ }
+
+ @Managed
+ static abstract class SimplePurelyManagedType {
+ @CustomTestAnnotation("managed")
+ abstract String getManagedProp()
+
+ @CustomTestAnnotation("managedSetter")
+ abstract void setManagedProp(String managedProp)
+
+ @CustomTestAnnotation("managedCalculated")
+ String getManagedCalculatedProp() {
+ return "calc"
+ }
+ }
+
+ def "properties are extracted from managed type"() {
+ when:
+ def schema = extract(SimplePurelyManagedType)
+
+ then:
+ assert schema instanceof ModelManagedImplStructSchema
+ schema.properties*.name == ["managedCalculatedProp", "managedProp"]
+
+ schema.getProperty("managedProp").stateManagementType == MANAGED
+ schema.getProperty("managedProp").isWritable() == true
+
+ schema.getProperty("managedCalculatedProp").stateManagementType == UNMANAGED
+ schema.getProperty("managedCalculatedProp").isWritable() == false
+ }
+
+ @Managed
+ static abstract class OverridingManagedSubtype extends SimplePurelyManagedType {
+ @Override
+ @CustomTestAnnotation("overriddenManaged")
+ @CustomTestAnnotation2
+ abstract String getManagedProp()
+
+ @Override
+ @CustomTestAnnotation2
+ String getManagedCalculatedProp() { return "overridden " }
+ }
+
+ def "property annotations when overridden retain most significant value"() {
+ when:
+ def schema = extract(OverridingManagedSubtype)
+
+ then:
+ assert schema instanceof ModelManagedImplStructSchema
+ schema.properties*.name == ["managedCalculatedProp", "managedProp"]
+
+ schema.getProperty("managedProp").stateManagementType == MANAGED
+ schema.getProperty("managedProp").isWritable() == true
+
+ schema.getProperty("managedCalculatedProp").stateManagementType == UNMANAGED
+ schema.getProperty("managedCalculatedProp").isWritable() == false
+ }
+
+ class MyAspect implements ModelSchemaAspect {}
+
+ @Managed
+ static abstract class MyTypeOfAspect {
+ abstract String getProp()
+ abstract void setProp(String prop)
+ String getCalculatedProp() {
+ return "calc"
+ }
+ }
+
+ def "aspects can be extracted"() {
+ def aspect = new MyAspect()
+ def aspectValidator = Mock(Action)
+ def aspectExtractionStrategy = Mock(ModelSchemaAspectExtractionStrategy)
+ def extractor = new ModelSchemaExtractor([], new ModelSchemaAspectExtractor([aspectExtractionStrategy]))
+ def store = new DefaultModelSchemaStore(extractor)
+
+ when:
+ def resultSchema = store.getSchema(MyTypeOfAspect)
+
+ then:
+ assert resultSchema instanceof ModelStructSchema
+ resultSchema.hasAspect(MyAspect)
+ resultSchema.getAspect(MyAspect) == aspect
+
+ 1 * aspectExtractionStrategy.extract(_, _) >> { ModelSchemaExtractionContext<?> extractionContext, List<ModelPropertyExtractionResult> propertyResults ->
+ assert propertyResults*.property*.name == ["calculatedProp", "prop"]
+ return new ModelSchemaAspectExtractionResult(aspect, aspectValidator)
+ }
+ 1 * aspectValidator.execute(_) >> { ModelSchemaExtractionContext<?> extractionContext ->
+ assert extractionContext.type.rawClass == MyTypeOfAspect
+ }
+ 0 * _
+ }
+
+ @Managed
+ interface HasIsTypeGetter {
+ boolean isRedundant()
+
+ void setRedundant(boolean redundant)
+ }
+
+ @Managed
+ interface HasGetTypeGetter {
+ boolean getRedundant()
+
+ void setRedundant(boolean redundant)
+ }
+
+ def "supports a boolean property with a get style getter"() {
+ expect:
+ store.getSchema(ModelType.of(HasGetTypeGetter))
+ }
+
+ @Managed
+ interface HasDualGetter {
+ boolean isRedundant()
+
+ boolean getRedundant()
+
+ void setRedundant(boolean redundant)
+ }
+
+ def "allows both is and get style getters"() {
+ expect:
+ store.getSchema(HasDualGetter)
+ }
+
+ @Managed
+ static interface OnlyGetGetter {
+ boolean getThing()
+ }
+
+ @Managed
+ static interface OnlyIsGetter {
+ boolean isThing()
+ }
+
+ @Managed
+ interface IsNotAllowedForOtherTypeThanBoolean {
+ String isThing()
+ void setThing(String thing)
+ }
+
+ @Managed
+ interface IsNotAllowedForOtherTypeThanBooleanWithBoxedBoolean {
+ Boolean isThing()
+ void setThing(Boolean thing)
+ }
+
+ @Unroll
+ def "must have a setter - #managedType.simpleName"() {
+ when:
+ store.getSchema(managedType)
+
+ then:
+ def ex = thrown(InvalidManagedModelElementTypeException)
+ ex.message =~ "read only property 'thing' has non managed type boolean, only managed types can be used"
+
+ where:
+ managedType << [OnlyIsGetter, OnlyGetGetter]
+ }
+
+ def "supports a boolean property with an is style getter"() {
+ expect:
+ store.getSchema(ModelType.of(HasIsTypeGetter))
+ }
+
+ @Unroll
+ def "should not allow 'is' as a prefix for getter on non primitive boolean"() {
+ when:
+ store.getSchema(IsNotAllowedForOtherTypeThanBoolean)
+
+ then:
+ def ex = thrown(InvalidManagedModelElementTypeException)
+ ex.message =~ /getter method name must start with 'get'/
+
+ where:
+ managedType << [IsNotAllowedForOtherTypeThanBoolean, IsNotAllowedForOtherTypeThanBooleanWithBoxedBoolean]
+ }
+
+ abstract class HasStaticProperties {
+ static String staticValue
+ String value
+ }
+
+ def "does not extract static properties"() {
+ def schema = store.getSchema(HasStaticProperties)
+ expect:
+ schema.properties*.name == ["value"]
+ }
+
+ abstract class HasProtectedAndPrivateProperties {
+ String value
+ protected String protectedValue
+ private String privateValue
+ }
+
+ def "does not extract protected and private properties"() {
+ def schema = store.getSchema(HasProtectedAndPrivateProperties)
+ expect:
+ schema.properties*.name == ["value"]
+ }
+
+ @Managed
+ interface HasIsAndGetPropertyWithDifferentTypes {
+ boolean isValue()
+ String getValue()
+ }
+
+ def "handles is/get property with non-matching type"() {
+ when:
+ store.getSchema(HasIsAndGetPropertyWithDifferentTypes)
+
+ then:
+ def ex = thrown InvalidManagedModelElementTypeException
+ ex.message.contains "property 'value' has both 'isValue()' and 'getValue()' getters, but they don't both return a boolean"
+ }
}
+
+ at Retention(RetentionPolicy.RUNTIME)
+ at interface CustomTestAnnotation {
+ String value();
+}
+
+ at Retention(RetentionPolicy.RUNTIME)
+ at interface CustomTestAnnotation2 {}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ModelSchemaUtilsTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ModelSchemaUtilsTest.groovy
new file mode 100644
index 0000000..2237436
--- /dev/null
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ModelSchemaUtilsTest.groovy
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract
+
+import org.gradle.api.Incubating
+import org.gradle.api.Nullable
+import org.gradle.model.Managed
+import spock.lang.Specification
+
+ at SuppressWarnings("GroovyPointlessBoolean")
+class ModelSchemaUtilsTest extends Specification {
+ def "base object types have no candidate methods"() {
+ expect:
+ ModelSchemaUtils.getCandidateMethods(Object).isEmpty()
+ ModelSchemaUtils.getCandidateMethods(GroovyObject).isEmpty()
+ }
+
+ def "base object types are not visited"() {
+ when: ModelSchemaUtils.walkTypeHierarchy(Object, Mock(ModelSchemaUtils.TypeVisitor))
+ then: 0 * _
+
+ when: ModelSchemaUtils.walkTypeHierarchy(GroovyObject, Mock(ModelSchemaUtils.TypeVisitor))
+ then: 0 * _
+ }
+
+ class Base {
+ @Incubating
+ Object doSomething() { null }
+ }
+
+ class Child extends Base implements Serializable {
+ @Nullable
+ Object doSomething() { null }
+ }
+
+ def "walking type hierarchy happens breadth-first"() {
+ def visitor = Mock(ModelSchemaUtils.TypeVisitor)
+ when:
+ ModelSchemaUtils.walkTypeHierarchy(Child, visitor)
+
+ then: 1 * visitor.visitType(Child)
+ then: 1 * visitor.visitType(Base)
+ then: 1 * visitor.visitType(Serializable)
+ then: 0 * _
+
+ }
+
+ def "overridden methods retain annotations"() {
+ when:
+ def methods = ModelSchemaUtils.getCandidateMethods(Child)
+
+ then:
+ methods.keySet() == (["doSomething"] as Set)
+ methods.values()*.name == ["doSomething", "doSomething"]
+ methods.values()*.declaringClass == [Child, Base]
+ methods.values()*.declaredAnnotations.flatten()*.annotationType() == [Nullable, Incubating]
+ }
+
+ @Managed
+ abstract class ManagedType {
+ abstract String getValue()
+ abstract void setValue(String value)
+ }
+
+ def "detects managed property"() {
+ expect:
+ ModelSchemaUtils.isMethodDeclaredInManagedType(ModelSchemaUtils.getCandidateMethods(ManagedType).get("getValue")) == true
+ }
+
+ class UnmanagedType {
+ String value
+ }
+
+ def "detects unmanaged property"() {
+ expect:
+ ModelSchemaUtils.isMethodDeclaredInManagedType(ModelSchemaUtils.getCandidateMethods(UnmanagedType).get("getValue")) == false
+ }
+}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ScalarTypesInManagedModelTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ScalarTypesInManagedModelTest.groovy
new file mode 100644
index 0000000..88827e0
--- /dev/null
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/ScalarTypesInManagedModelTest.groovy
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract
+
+import org.gradle.api.artifacts.Configuration
+import spock.lang.Shared
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class ScalarTypesInManagedModelTest extends Specification {
+
+ @Shared
+ def store = DefaultModelSchemaStore.getInstance()
+
+ def classloader = new GroovyClassLoader(this.class.classLoader)
+
+ @Unroll
+ def "cannot have read only property of scalar type #someType.simpleName"() {
+ given:
+ def clazz = classloader.parseClass """
+ import org.gradle.api.artifacts.Configuration.State
+ import org.gradle.model.Managed
+
+ @Managed
+ interface ManagedType {
+ $someType.canonicalName getManagedProperty()
+ }
+
+ """
+
+ when:
+ store.getSchema(clazz)
+
+ then:
+ def ex = thrown(InvalidManagedModelElementTypeException)
+ String expectedMessage = "Invalid managed model type ManagedType: read only property 'managedProperty' has non managed type ${someType.name}, only managed types can be used"
+ ex.message == expectedMessage
+
+ where:
+ someType << [
+ byte, Byte,
+ boolean, Boolean,
+ char, Character,
+ float, Float,
+ long, Long,
+ short, Short,
+ int, Integer,
+ double, Double,
+ String,
+ BigDecimal,
+ BigInteger,
+ Configuration.State,
+ File]
+ }
+}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/TestUnmanagedTypeWithManagedSuperTypeExtractionStrategy.java b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/TestUnmanagedTypeWithManagedSuperTypeExtractionStrategy.java
new file mode 100644
index 0000000..0ee4b3e
--- /dev/null
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/manage/schema/extract/TestUnmanagedTypeWithManagedSuperTypeExtractionStrategy.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.manage.schema.extract;
+
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.manage.schema.ModelManagedImplStructSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+
+public class TestUnmanagedTypeWithManagedSuperTypeExtractionStrategy extends ManagedImplStructSchemaExtractionStrategySupport {
+ public TestUnmanagedTypeWithManagedSuperTypeExtractionStrategy(Class<?> delegateType) {
+ this(delegateType, new ModelSchemaAspectExtractor());
+ }
+
+ public TestUnmanagedTypeWithManagedSuperTypeExtractionStrategy(Class<?> delegateType, ModelSchemaAspectExtractor aspectExtractor) {
+ super(aspectExtractor, delegateType, delegateType);
+ }
+
+ @Override
+ protected <R> NodeInitializer createNodeInitializer(ModelManagedImplStructSchema<R> schema, ModelSchemaStore store) {
+ return null;
+ }
+}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/DefaultModelRegistryTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/DefaultModelRegistryTest.groovy
index b8c0074..d31467b 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/DefaultModelRegistryTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/DefaultModelRegistryTest.groovy
@@ -75,10 +75,11 @@ class DefaultModelRegistryTest extends Specification {
then:
UnboundModelRulesException e = thrown()
- normaliseLineSeparators(e.message) == """The following model rules are unbound:
+ normaliseLineSeparators(e.message).contains '''
foo creator
- Immutable:
- - other (java.lang.Object)"""
+ inputs:
+ - other Object [*]
+'''
}
def "cannot get element for which creator by-type input does not exist"() {
@@ -90,10 +91,11 @@ class DefaultModelRegistryTest extends Specification {
then:
UnboundModelRulesException e = thrown()
- normaliseLineSeparators(e.message) == """The following model rules are unbound:
+ normaliseLineSeparators(e.message).contains '''
foo creator
- Immutable:
- - <unspecified> (java.lang.Long)"""
+ inputs:
+ - <no path> Long [*]
+'''
}
def "cannot register creator when by-type input is ambiguous"() {
@@ -232,14 +234,13 @@ class DefaultModelRegistryTest extends Specification {
def action = Mock(Action)
given:
- def actionImpl = registry.action().path("foo").type(Bean).action(action)
registry
- .create("foo", new Bean(), action)
- .configure(ModelActionRole.Defaults, actionImpl)
- .configure(ModelActionRole.Initialize, actionImpl)
- .configure(ModelActionRole.Mutate, actionImpl)
- .configure(ModelActionRole.Finalize, actionImpl)
- .configure(ModelActionRole.Validate, actionImpl)
+ .create("foo", new Bean(), action)
+ .configure(ModelActionRole.Defaults, registry.action().path("foo").type(Bean).action(action))
+ .configure(ModelActionRole.Initialize, registry.action().path("foo").type(Bean).action(action))
+ .configure(ModelActionRole.Mutate, registry.action().path("foo").type(Bean).action(action))
+ .configure(ModelActionRole.Finalize, registry.action().path("foo").type(Bean).action(action))
+ .configure(ModelActionRole.Validate, registry.action().path("foo").type(Bean).action(action))
when:
def value = registry.realize(ModelPath.path("foo"), ModelType.of(Bean)).value
@@ -336,18 +337,26 @@ class DefaultModelRegistryTest extends Specification {
given:
registry.createInstance("a", new Bean())
registry.createInstance("b", new Bean())
- registry.configure(ModelActionRole.Finalize) { it.path("b").action(ModelReference.of(ModelPath.path("a"), ModelType.of(Bean), ModelNode.State.DefaultsApplied)) { Bean b, Bean a ->
- b.value = "$b.value $a.value"
- }}
- registry.configure(ModelActionRole.Mutate) { it.path("b").action { Bean b ->
- b.value = "b-mutate"
- }}
- registry.configure(ModelActionRole.Mutate) { it.path("a").action { Bean a ->
- a.value = "a-mutate"
- }}
- registry.configure(ModelActionRole.Defaults) { it.path("a").action { Bean a ->
- a.value = "a-defaults"
- }}
+ registry.configure(ModelActionRole.Finalize) {
+ it.path("b").action(ModelReference.of(ModelPath.path("a"), ModelType.of(Bean), ModelNode.State.DefaultsApplied)) { Bean b, Bean a ->
+ b.value = "$b.value $a.value"
+ }
+ }
+ registry.configure(ModelActionRole.Mutate) {
+ it.path("b").action { Bean b ->
+ b.value = "b-mutate"
+ }
+ }
+ registry.configure(ModelActionRole.Mutate) {
+ it.path("a").action { Bean a ->
+ a.value = "a-mutate"
+ }
+ }
+ registry.configure(ModelActionRole.Defaults) {
+ it.path("a").action { Bean a ->
+ a.value = "a-defaults"
+ }
+ }
expect:
registry.realize(ModelPath.path("a"), ModelType.of(Bean)).value == "a-mutate"
@@ -358,18 +367,26 @@ class DefaultModelRegistryTest extends Specification {
given:
registry.createInstance("a", new Bean())
registry.createInstance("b", new Bean())
- registry.configure(ModelActionRole.Finalize) { it.path("b").action(ModelReference.of(ModelPath.path("a"), ModelType.of(Bean), ModelNode.State.DefaultsApplied)) { Bean b, Bean a ->
- b.value = "$b.value $a.value"
- }}
- registry.configure(ModelActionRole.Mutate) { it.path("b").action { Bean b ->
- b.value = "b-mutate"
- }}
- registry.configure(ModelActionRole.Mutate) { it.path("a").action { Bean a ->
- a.value = "a-mutate"
- }}
- registry.configure(ModelActionRole.Defaults) { it.path("a").action { Bean a ->
- a.value = "a-defaults"
- }}
+ registry.configure(ModelActionRole.Finalize) {
+ it.path("b").action(ModelReference.of(ModelPath.path("a"), ModelType.of(Bean), ModelNode.State.DefaultsApplied)) { Bean b, Bean a ->
+ b.value = "$b.value $a.value"
+ }
+ }
+ registry.configure(ModelActionRole.Mutate) {
+ it.path("b").action { Bean b ->
+ b.value = "b-mutate"
+ }
+ }
+ registry.configure(ModelActionRole.Mutate) {
+ it.path("a").action { Bean a ->
+ a.value = "a-mutate"
+ }
+ }
+ registry.configure(ModelActionRole.Defaults) {
+ it.path("a").action { Bean a ->
+ a.value = "a-defaults"
+ }
+ }
expect:
registry.realize(ModelPath.path("b"), ModelType.of(Bean)).value == "b-mutate a-defaults"
@@ -524,7 +541,7 @@ class DefaultModelRegistryTest extends Specification {
given:
registry.createInstance("thing", "value")
- .configure(fromRole) { it.path("thing").node(action) }
+ .configure(fromRole) { it.path("thing").node(action) }
action.execute(_) >> { MutableModelNode node -> registry.configure(targetRole) { it.path("thing").type(String).descriptor("X").action {} } }
when:
@@ -555,8 +572,8 @@ class DefaultModelRegistryTest extends Specification {
given:
registry.createInstance("thing", "value")
- .createInstance("another", "value")
- .configure(ModelActionRole.Mutate) {
+ .createInstance("another", "value")
+ .configure(ModelActionRole.Mutate) {
it.path("another").node(action)
}
action.execute(_) >> {
@@ -632,17 +649,17 @@ class DefaultModelRegistryTest extends Specification {
given:
registry.createInstance("thing", new Bean(value: "initial"))
.configure(targetRole) {
- it.path("thing").node { MutableModelNode node ->
- registry.configure(targetRole) {
- it.path("thing").type(Bean).action("other", ModelType.of(Bean)) { subject, dep ->
- subject.value = dep.value
+ it.path("thing").node { MutableModelNode node ->
+ registry.configure(targetRole) {
+ it.path("thing").type(Bean).action("other", ModelType.of(Bean)) { subject, dep ->
+ subject.value = dep.value
}
}
}
}
// Include a dependency
registry.createInstance("other", new Bean())
- .mutate { it.path("other").type(Bean).action { it.value = "input value"} }
+ .mutate { it.path("other").type(Bean).action { it.value = "input value" } }
when:
def thing = registry.realize(ModelPath.path("thing"), ModelType.of(Bean))
@@ -659,8 +676,8 @@ class DefaultModelRegistryTest extends Specification {
given:
registry.createInstance("thing", "value")
- .createInstance("another", "value")
- .configure(ModelActionRole.Mutate) {
+ .createInstance("another", "value")
+ .configure(ModelActionRole.Mutate) {
it.path("another").node(action)
}
action.execute(_) >> {
@@ -748,8 +765,8 @@ class DefaultModelRegistryTest extends Specification {
def mmType = ModelTypes.modelMap(Bean)
registry
- .modelMap("things", Bean) { it.registerFactory(Bean) { new Bean(name: it) } }
- .mutate {
+ .modelMap("things", Bean) { it.registerFactory(Bean) { new Bean(name: it) } }
+ .mutate {
it.path "things" type mmType action { c ->
events << "collection mutated"
c.create("c1") { events << "$it.name created" }
@@ -871,16 +888,19 @@ class DefaultModelRegistryTest extends Specification {
then:
UnboundModelRulesException e = thrown()
- normaliseLineSeparators(e.message) == '''The following model rules are unbound:
+ normaliseLineSeparators(e.message).contains '''
by-path
- Mutable:
- - a.b (java.lang.Object)
+ subject:
+ - a.b Object [*]
+
by-path-and-type
- Mutable:
- - missing (java.lang.String)
+ subject:
+ - missing String [*]
+
by-type
- Mutable:
- - <unspecified> (java.lang.Long)'''
+ subject:
+ - <no path> Long [*]
+'''
}
def "reports unbound inputs"() {
@@ -894,39 +914,46 @@ class DefaultModelRegistryTest extends Specification {
then:
UnboundModelRulesException e = thrown()
- normaliseLineSeparators(e.message) == '''The following model rules are unbound:
+ normaliseLineSeparators(e.message).contains '''
by-path
- Mutable:
- + foo (java.lang.Object)
- Immutable:
- - other.thing (java.lang.String) java.lang.String
+ subject:
+ - foo Object
+ inputs:
+ - other.thing String (java.lang.String) [*]
+
by-type
- Mutable:
- - <unspecified> (java.lang.Runnable)
- Immutable:
- - <unspecified> (java.lang.String) java.lang.String
+ subject:
+ - <no path> Runnable [*]
+ inputs:
+ - <no path> String (java.lang.String) [*]
+
creator
- Immutable:
- - a.b (java.lang.Object) a.b'''
+ inputs:
+ - a.b Object (a.b) [*]
+'''
}
def "closes elements as required to bind all subjects and inputs"() {
given:
registry.mutate { it.path("a.1.2").action(ModelPath.path("b.1.2"), ModelType.of(String)) {} }
registry.create("a") { it.unmanaged("a") }
- registry.mutate { it.path("a").node {
- it.addLink(registry.creator("a.1").unmanaged("a.1"))
- it.applyToLink(ModelActionRole.Finalize, registry.action().path("a.1").node {
- it.addLink(registry.creator("a.1.2").unmanaged("a.1.2"))
- })
- } }
+ registry.mutate {
+ it.path("a").node {
+ it.addLink(registry.creator("a.1").unmanaged("a.1"))
+ it.applyToLink(ModelActionRole.Finalize, registry.action().path("a.1").node {
+ it.addLink(registry.creator("a.1.2").unmanaged("a.1.2"))
+ })
+ }
+ }
registry.create("b") { it.unmanaged("b") }
- registry.mutate { it.path("b").node {
- it.addLink(registry.creator("b.1").unmanaged("b.1"))
- it.applyToLink(ModelActionRole.Finalize, registry.action().path("b.1").node {
- it.addLink(registry.creator("b.1.2").unmanaged("b.1.2"))
- })
- } }
+ registry.mutate {
+ it.path("b").node {
+ it.addLink(registry.creator("b.1").unmanaged("b.1"))
+ it.applyToLink(ModelActionRole.Finalize, registry.action().path("b.1").node {
+ it.addLink(registry.creator("b.1.2").unmanaged("b.1.2"))
+ })
+ }
+ }
when:
registry.bindAllReferences()
@@ -940,16 +967,16 @@ class DefaultModelRegistryTest extends Specification {
def mmType = ModelTypes.modelMap(Bean)
registry
- .createInstance("foo", new Bean())
- .mutate {
+ .createInstance("foo", new Bean())
+ .mutate {
it.descriptor("non-bindable").path("foo").type(Bean).action("emptyBeans.element", ModelType.of(Bean), null, {})
}
.mutate {
it.descriptor("bindable").path("foo").type(Bean).action("beans.element", ModelType.of(Bean)) {
}
}
- .modelMap("beans", Bean) { it.registerFactory(Bean) { new Bean(name: it) } }
- .mutate {
+ .modelMap("beans", Bean) { it.registerFactory(Bean) { new Bean(name: it) } }
+ .mutate {
it.path "beans" type mmType action { c ->
c.create("element")
}
@@ -961,17 +988,18 @@ class DefaultModelRegistryTest extends Specification {
then:
UnboundModelRulesException e = thrown()
- normaliseLineSeparators(e.message) == '''The following model rules are unbound:
+ normaliseLineSeparators(e.message).contains '''
non-bindable
- Mutable:
- + foo (org.gradle.model.internal.registry.DefaultModelRegistryTest$Bean)
- Immutable:
- - emptyBeans.element (org.gradle.model.internal.registry.DefaultModelRegistryTest$Bean)'''
+ subject:
+ - foo DefaultModelRegistryTest.Bean
+ inputs:
+ - emptyBeans.element DefaultModelRegistryTest.Bean [*]
+'''
}
def "does not report unbound creators of removed nodes"() {
given:
- registry.create(ModelPath.path("unused")) { it.unmanaged(String, "unknown") { }}
+ registry.create(ModelPath.path("unused")) { it.unmanaged(String, "unknown") {} }
registry.remove(ModelPath.path("unused"))
when:
@@ -984,9 +1012,9 @@ class DefaultModelRegistryTest extends Specification {
def "two element mutation rule based configuration cycles are detected"() {
given:
registry.createInstance("foo", "foo")
- .createInstance("bar", "bar")
- .mutate { it.path("foo").descriptor("foo mutator").type(String).action("bar", ModelType.of(String), "parameter 1", {}) }
- .mutate { it.path("bar").descriptor("bar mutator").type(String).action("foo", ModelType.of(String), null, {}) }
+ .createInstance("bar", "bar")
+ .mutate { it.path("foo").descriptor("foo mutator").type(String).action("bar", ModelType.of(String), "parameter 1", {}) }
+ .mutate { it.path("bar").descriptor("bar mutator").type(String).action("foo", ModelType.of(String), null, {}) }
when:
registry.get("foo")
@@ -1003,11 +1031,11 @@ foo
def "multiple element configuration cycles are detected"() {
registry.create("foo") { it.unmanaged(String, "bar") { "foo" } }
- .create("bar") { it.unmanaged(String, "fizz") { "bar" } }
- .createInstance("fizz", "fizz")
- .mutate { it.path("fizz").descriptor("fizz mutator").type(String).action("buzz", ModelType.of(String), {}) }
- .createInstance("buzz", "buzz")
- .mutate { it.path("buzz").descriptor("buzz mutator").type(String).action("foo", ModelType.of(String), {}) }
+ .create("bar") { it.unmanaged(String, "fizz") { "bar" } }
+ .createInstance("fizz", "fizz")
+ .mutate { it.path("fizz").descriptor("fizz mutator").type(String).action("buzz", ModelType.of(String), {}) }
+ .createInstance("buzz", "buzz")
+ .mutate { it.path("buzz").descriptor("buzz mutator").type(String).action("foo", ModelType.of(String), {}) }
when:
registry.get("foo")
@@ -1029,7 +1057,7 @@ foo
def "one element configuration cycles are detected"() {
given:
registry.createInstance("foo", "foo")
- .mutate { it.path("foo").descriptor("foo mutator").type(String).action(String) {} }
+ .mutate { it.path("foo").descriptor("foo mutator").type(String).action(String) {} }
when:
registry.get("foo")
@@ -1045,11 +1073,11 @@ foo
def "only the elements actually forming the cycle are reported when configuration cycles are detected"() {
given:
registry.create("foo") { it.unmanaged(Long, "bar") { 12 } }
- .create("bar") { it.unmanaged(String, "fizz") { "bar" } }
- .mutate { it.path("foo").action(String) {} }
- .create("fizz") { it.unmanaged(Boolean, "buzz") { "buzz" } }
- .mutate { it.path("fizz").descriptor("fizz mutator").action("bar", ModelType.of(String), {}) }
- .createInstance("buzz", Long)
+ .create("bar") { it.unmanaged(String, "fizz") { "bar" } }
+ .mutate { it.path("foo").action(String) {} }
+ .create("fizz") { it.unmanaged(Boolean, "buzz") { "buzz" } }
+ .mutate { it.path("fizz").descriptor("fizz mutator").action("bar", ModelType.of(String), {}) }
+ .createInstance("buzz", Long)
when:
registry.get("foo")
@@ -1067,8 +1095,8 @@ bar
def "implicit cycle when node depends on parent is detected"() {
given:
registry.createInstance("foo", "foo")
- .mutate { it.path("foo").descriptor("foo mutator").node { it.addLink(registry.creator("foo.bar").unmanaged(Number, 12))} }
- .mutate { it.path("foo.bar").descriptor("bar mutator").action(String) {} }
+ .mutate { it.path("foo").descriptor("foo mutator").node { it.addLink(registry.creator("foo.bar").unmanaged(Number, 12)) } }
+ .mutate { it.path("foo.bar").descriptor("bar mutator").action(String) {} }
when:
registry.get("foo")
@@ -1085,9 +1113,9 @@ foo
def "implicit cycle when node depends on ancestor is detected"() {
given:
registry.createInstance("foo", "foo")
- .mutate { it.path("foo").descriptor("foo mutator").node { it.addLink(registry.creator("foo.bar").unmanaged(Number, 12))} }
- .mutate { it.path("foo.bar").descriptor("bar mutator").node { it.addLink(registry.creator("foo.bar.baz").unmanaged(Number, 107))} }
- .mutate { it.path("foo.bar.baz").descriptor("baz mutator").action(ModelType.of(String)) {} }
+ .mutate { it.path("foo").descriptor("foo mutator").node { it.addLink(registry.creator("foo.bar").unmanaged(Number, 12)) } }
+ .mutate { it.path("foo.bar").descriptor("bar mutator").node { it.addLink(registry.creator("foo.bar.baz").unmanaged(Number, 107)) } }
+ .mutate { it.path("foo.bar.baz").descriptor("baz mutator").action(ModelType.of(String)) {} }
when:
registry.get("foo")
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/ModelNodeInternalTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/ModelNodeInternalTest.groovy
new file mode 100644
index 0000000..c26a926
--- /dev/null
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/ModelNodeInternalTest.groovy
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.registry
+
+import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor
+import spock.lang.Unroll
+
+class ModelNodeInternalTest extends RegistrySpec {
+ CreatorRuleBinder creatorRuleBinder = Mock()
+
+ def "should have zero executed rules initially"() {
+ expect:
+ new TestNode(creatorRuleBinder).getExecutedRules().size() == 0
+ }
+
+ @Unroll
+ def "should record executed rules when notify fired #fireCount time(s)"() {
+ ModelRuleDescriptor descriptor = Mock()
+ ModelNodeInternal modelNode = new TestNode(creatorRuleBinder)
+ MutatorRuleBinder executionBinder = Mock()
+ executionBinder.isBound() >> true
+ executionBinder.getInputBindings() >> []
+ executionBinder.getDescriptor() >> descriptor
+
+ when:
+ fireCount.times {
+ modelNode.notifyFired(executionBinder)
+ }
+
+ then:
+ modelNode.executedRules.size() == fireCount
+ modelNode.executedRules[0] == descriptor
+
+ where:
+ fireCount << [1, 2]
+ }
+
+ def "should not fire for unbound binders"() {
+ setup:
+ ModelNodeInternal modelNode = new TestNode(creatorRuleBinder)
+ MutatorRuleBinder executionBinder = Mock()
+ executionBinder.isBound() >> false
+
+ when:
+ modelNode.notifyFired(executionBinder)
+
+ then:
+ AssertionError e = thrown()
+ e.message == 'RuleBinder must be in a bound state'
+ }
+}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/RegistrySpec.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/RegistrySpec.groovy
index 43e3309..a2ffe0a 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/RegistrySpec.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/RegistrySpec.groovy
@@ -33,6 +33,10 @@ class RegistrySpec extends Specification {
super(toBinder(creationPath, type))
}
+ TestNode(CreatorRuleBinder creatorBinder) {
+ super(creatorBinder)
+ }
+
private static CreatorRuleBinder toBinder(String creationPath, Class<?> type) {
def creator = ModelCreators.of(ModelPath.path(creationPath), BiActions.doNothing()).descriptor("test").withProjection(new UnmanagedModelProjection(ModelType.of(type))).build()
def subject = new BindingPredicate()
@@ -40,10 +44,6 @@ class RegistrySpec extends Specification {
binder
}
- @Override
- ModelNodeInternal getTarget() {
- return this
- }
@Override
Iterable<? extends ModelNodeInternal> getLinks() {
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/ScopedRuleTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/ScopedRuleTest.groovy
index 8fd87de..a1d0363 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/ScopedRuleTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/registry/ScopedRuleTest.groovy
@@ -18,17 +18,12 @@ package org.gradle.model.internal.registry
import org.gradle.api.Plugin
import org.gradle.api.Project
-import org.gradle.model.InvalidModelRuleDeclarationException
-import org.gradle.model.Model
-import org.gradle.model.Mutate
-import org.gradle.model.Path
-import org.gradle.model.RuleSource
+import org.gradle.model.*
import org.gradle.model.internal.core.DependencyOnlyExtractedModelRule
import org.gradle.model.internal.core.ExtractedModelRule
import org.gradle.model.internal.core.ModelRuleExecutionException
import org.gradle.model.internal.fixture.ModelRegistryHelper
import org.gradle.model.internal.inspect.AbstractAnnotationDrivenModelRuleExtractor
-import org.gradle.model.internal.inspect.DefaultModelCreatorFactory
import org.gradle.model.internal.inspect.MethodModelRuleExtractors
import org.gradle.model.internal.inspect.MethodRuleDefinition
import org.gradle.model.internal.inspect.ModelRuleExtractor
@@ -37,7 +32,7 @@ import spock.lang.Specification
class ScopedRuleTest extends Specification {
- def extractors = [new DependencyAddingModelRuleExtractor()] + MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.getInstance(), new DefaultModelCreatorFactory(DefaultModelSchemaStore.getInstance()))
+ def extractors = [new DependencyAddingModelRuleExtractor()] + MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.getInstance())
def registry = new ModelRegistryHelper(new DefaultModelRegistry(new ModelRuleExtractor(extractors)))
static class RuleSourceUsingRuleWithDependencies extends RuleSource {
@@ -59,7 +54,7 @@ class ScopedRuleTest extends Specification {
def "cannot apply a scoped rule that has dependencies"() {
registry.createInstance("values", "foo")
- .apply("values", RuleSourceUsingRuleWithDependencies)
+ .apply("values", RuleSourceUsingRuleWithDependencies)
when:
registry.get("values")
@@ -80,7 +75,7 @@ class ScopedRuleTest extends Specification {
def "cannot apply creator rules in scope other than root"() {
given:
registry.createInstance("values", "foo")
- .apply("values", CreatorRule)
+ .apply("values", CreatorRule)
when:
registry.get("values")
@@ -88,7 +83,7 @@ class ScopedRuleTest extends Specification {
then:
ModelRuleExecutionException e = thrown()
e.cause.class == InvalidModelRuleDeclarationException
- e.cause.message == "Rule org.gradle.model.internal.registry.ScopedRuleTest\$CreatorRule#string() cannot be applied at the scope of model element values as creation rules cannot be used when applying rule sources to particular elements"
+ e.cause.message == "Rule ScopedRuleTest.CreatorRule#string cannot be applied at the scope of model element values as creation rules cannot be used when applying rule sources to particular elements"
}
static class ByPathBoundInputsChildRule extends RuleSource {
@@ -110,10 +105,10 @@ class ScopedRuleTest extends Specification {
def "by-path bindings of scoped rules are bound to inner scope"() {
given:
registry.createInstance("first", new MutableValue())
- .createInstance("second", new MutableValue())
- .createInstance("values", "foo")
- .apply("values", ByPathBoundInputsChildRule)
- .mutate {
+ .createInstance("second", new MutableValue())
+ .createInstance("values", "foo")
+ .apply("values", ByPathBoundInputsChildRule)
+ .mutate {
it.path "values" node {
it.addLink(registry.instanceCreator("values.first", new MutableValue()))
it.addLink(registry.instanceCreator("values.second", new MutableValue()))
@@ -140,8 +135,8 @@ class ScopedRuleTest extends Specification {
def "can bind subject by type to a child of rule scope"() {
given:
registry.createInstance("values", "foo")
- .apply("values", ByTypeSubjectBoundToScopeChildRule)
- .mutate {
+ .apply("values", ByTypeSubjectBoundToScopeChildRule)
+ .mutate {
it.path "values" node {
it.addLink(registry.instanceCreator("values.mutable", new MutableValue()))
}
@@ -164,10 +159,10 @@ class ScopedRuleTest extends Specification {
def "by-type subject bindings are scoped to the scope of an inner rule"() {
given:
registry.createInstance("element", new MutableValue())
- .createInstance("input", 10)
- .createInstance("values", "foo")
- .apply("values", ByTypeBindingSubjectRule)
- .mutate {
+ .createInstance("input", 10)
+ .createInstance("values", "foo")
+ .apply("values", ByTypeBindingSubjectRule)
+ .mutate {
it.path "values" node {
it.addLink(registry.instanceCreator("values.element", new MutableValue()))
}
@@ -191,9 +186,9 @@ class ScopedRuleTest extends Specification {
def "by-type input bindings are scoped to the outer scope"() {
given:
registry.createInstance("values", "foo")
- .apply("values", ByTypeBindingInputRule)
- .createInstance("element", new MutableValue(value: "outer"))
- .mutate {
+ .apply("values", ByTypeBindingInputRule)
+ .createInstance("element", new MutableValue(value: "outer"))
+ .mutate {
it.path "values" node {
it.addLink(registry.instanceCreator("values.element", new MutableValue()))
}
diff --git a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/report/unbound/UnboundRulesReporterTest.groovy b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/report/unbound/UnboundRulesReporterTest.groovy
index b026f75..e890f7f 100644
--- a/subprojects/model-core/src/test/groovy/org/gradle/model/internal/report/unbound/UnboundRulesReporterTest.groovy
+++ b/subprojects/model-core/src/test/groovy/org/gradle/model/internal/report/unbound/UnboundRulesReporterTest.groovy
@@ -22,6 +22,7 @@ import spock.lang.Specification
class UnboundRulesReporterTest extends Specification {
def output = new StringWriter()
+
def reporter = new UnboundRulesReporter(new PrintWriter(output), "> ")
def "reports on unbound rules"() {
@@ -38,13 +39,19 @@ class UnboundRulesReporterTest extends Specification {
then:
output.toString() == TextUtil.toPlatformLineSeparators("""> r1
-> Mutable:
-> - parent.p1 (java.lang.String)
-> - <unspecified> (java.lang.String) in scope of 'some.scope'
-> + parent.p3 (java.lang.Integer)
-> Immutable:
-> - parent.p4 (java.lang.Number) - suggestions: parent.p31, parent.p32
-> - <unspecified> (java.lang.Number)
-> + parent.p6 (java.lang.Number)""")
+> subject:
+> - parent.p1 String [*]
+> - <no path> String [*]
+> scope: some.scope
+> - parent.p3 Integer
+> inputs:
+> - parent.p4 Number [*]
+> suggestions: parent.p31, parent.p32
+> - <no path> Number [*]
+> - parent.p6 Number
+
+[*] - indicates that a model item could not be found for the path or type.
+""")
}
}
+
diff --git a/subprojects/model-core/src/testFixtures/groovy/org/gradle/model/internal/fixture/ModelRegistryHelper.java b/subprojects/model-core/src/testFixtures/groovy/org/gradle/model/internal/fixture/ModelRegistryHelper.java
index d95132d..86552da 100644
--- a/subprojects/model-core/src/testFixtures/groovy/org/gradle/model/internal/fixture/ModelRegistryHelper.java
+++ b/subprojects/model-core/src/testFixtures/groovy/org/gradle/model/internal/fixture/ModelRegistryHelper.java
@@ -29,7 +29,6 @@ import org.gradle.model.RuleSource;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor;
-import org.gradle.model.internal.inspect.DefaultModelCreatorFactory;
import org.gradle.model.internal.inspect.MethodModelRuleExtractors;
import org.gradle.model.internal.inspect.ModelRuleExtractor;
import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore;
@@ -58,7 +57,7 @@ public class ModelRegistryHelper implements ModelRegistry {
private final ModelRegistry modelRegistry;
public ModelRegistryHelper() {
- this(new DefaultModelRegistry(new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.getInstance(), new DefaultModelCreatorFactory(DefaultModelSchemaStore.getInstance())))));
+ this(new DefaultModelRegistry(new ModelRuleExtractor(MethodModelRuleExtractors.coreExtractors(DefaultModelSchemaStore.getInstance()))));
}
public ModelRegistryHelper(ModelRegistryScope modelRegistryScope) {
diff --git a/subprojects/model-core/src/testFixtures/groovy/org/gradle/model/report/unbound/UnboundRulesReportMatchers.groovy b/subprojects/model-core/src/testFixtures/groovy/org/gradle/model/report/unbound/UnboundRulesReportMatchers.groovy
deleted file mode 100644
index 9a10091..0000000
--- a/subprojects/model-core/src/testFixtures/groovy/org/gradle/model/report/unbound/UnboundRulesReportMatchers.groovy
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.report.unbound
-
-import org.gradle.model.internal.report.unbound.UnboundRule
-import org.gradle.model.internal.report.unbound.UnboundRulesReporter
-import org.hamcrest.Matcher
-
-import static org.gradle.util.Matchers.normalizedLineSeparators
-import static org.gradle.util.TextUtil.normaliseLineSeparators
-import static org.hamcrest.Matchers.equalTo
-
-class UnboundRulesReportMatchers {
-
- static Matcher<String> unbound(UnboundRule.Builder... rules) {
- def string = new StringWriter()
- def writer = new PrintWriter(string)
- writer.println("The following model rules are unbound:")
- def reporter = new UnboundRulesReporter(writer, " ")
- reporter.reportOn(rules.toList()*.build())
-
- normalizedLineSeparators(equalTo(normaliseLineSeparators(string.toString())))
- }
-}
diff --git a/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/ModelDslCreationIntegrationTest.groovy b/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/ModelDslCreationIntegrationTest.groovy
index 4eca43d..5d20c50 100644
--- a/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/ModelDslCreationIntegrationTest.groovy
+++ b/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/ModelDslCreationIntegrationTest.groovy
@@ -206,8 +206,7 @@ class ModelDslCreationIntegrationTest extends AbstractIntegrationSpec {
then:
fails "dependencies" // something that doesn't actually require thing1 to be built
- failure.assertThatCause(containsText("model.thing1 @ build file"))
+ failure.assertThatCause(containsText("model.thing1 @ build.gradle"))
failure.assertThatCause(containsText("Cannot create an element of type Thing as it is not a managed type"))
}
-
}
diff --git a/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/internal/transform/ModelDslRuleInputDetectionIntegrationSpec.groovy b/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/internal/transform/ModelDslRuleInputDetectionIntegrationSpec.groovy
index 74a490a..18cf60e 100644
--- a/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/internal/transform/ModelDslRuleInputDetectionIntegrationSpec.groovy
+++ b/subprojects/model-groovy/src/integTest/groovy/org/gradle/model/dsl/internal/transform/ModelDslRuleInputDetectionIntegrationSpec.groovy
@@ -102,6 +102,7 @@ class ModelDslRuleInputDetectionIntegrationSpec extends AbstractIntegrationSpec
and:
output.contains "thing.value: foo-bar"
}
+
@Unroll
def "only literal strings can be given to dollar - #code"() {
when:
@@ -121,14 +122,14 @@ class ModelDslRuleInputDetectionIntegrationSpec extends AbstractIntegrationSpec
where:
code << [
- '$(1)',
- '$("$name")',
- '$("a" + "b")',
- 'def a = "foo"; $(a)',
- '$("foo", "bar")',
- '$()',
- '$(null)',
- '$("")'
+ '$(1)',
+ '$("$name")',
+ '$("a" + "b")',
+ 'def a = "foo"; $(a)',
+ '$("foo", "bar")',
+ '$()',
+ '$(null)',
+ '$("")'
]
}
@@ -159,7 +160,7 @@ class ModelDslRuleInputDetectionIntegrationSpec extends AbstractIntegrationSpec
where:
code << [
- 'something.$(1)',
+ 'something.$(1)',
// 'this.$("$name")',
// 'foo.bar().$("a" + "b")',
]
@@ -210,15 +211,15 @@ class ModelDslRuleInputDetectionIntegrationSpec extends AbstractIntegrationSpec
where:
code << [
- 'if (true) { add $("foo") }',
- 'if (false) {} else if (true) { add $("foo") }',
- 'if (false) {} else { add $("foo") }',
- 'def i = true; while(i) { add $("foo"); i = false }',
- '[1].each { add $("foo") }',
- 'add "${$("foo")}"',
- 'def v = $("foo"); add(v)',
- 'add($("foo"))',
- 'add($("foo").toString())',
+ 'if (true) { add $("foo") }',
+ 'if (false) {} else if (true) { add $("foo") }',
+ 'if (false) {} else { add $("foo") }',
+ 'def i = true; while(i) { add $("foo"); i = false }',
+ '[1].each { add $("foo") }',
+ 'add "${$("foo")}"',
+ 'def v = $("foo"); add(v)',
+ 'add($("foo"))',
+ 'add($("foo").toString())',
]
}
@@ -281,16 +282,22 @@ class ModelDslRuleInputDetectionIntegrationSpec extends AbstractIntegrationSpec
fails "tasks"
then:
- failure.assertHasCause("""The following model rules are unbound:
- model.fooar @ build file '${buildFile}' line 20, column 17
- Mutable:
- - fooar (java.lang.Object) - suggestions: foobar
- model.foobah @ build file '${buildFile}' line 18, column 17
- Mutable:
- - foobah (java.lang.Object) - suggestions: foobar
- model.foonar @ build file '${buildFile}' line 16, column 17
- Mutable:
- - foonar (java.lang.Object) - suggestions: foobar""")
+ failureCauseContains('''
+ model.fooar @ build.gradle line 20, column 17
+ subject:
+ - fooar Object [*]
+ suggestions: foobar
+
+ model.foobah @ build.gradle line 18, column 17
+ subject:
+ - foobah Object [*]
+ suggestions: foobar
+
+ model.foonar @ build.gradle line 16, column 17
+ subject:
+ - foonar Object [*]
+ suggestions: foobar
+''')
}
def "location and suggestions are provided for unbound rule inputs specified using a name"() {
@@ -321,14 +328,18 @@ class ModelDslRuleInputDetectionIntegrationSpec extends AbstractIntegrationSpec
fails "tasks"
then:
- failure.assertHasCause("""The following model rules are unbound:
- model.tasks.raboof @ build file '${buildFile}' line 15, column 17
- Mutable:
- + tasks.raboof (java.lang.Object)
- Immutable:
- - tasks.foonar (java.lang.Object) @ line 16 - suggestions: tasks.foobar
- - tasks.fooar (java.lang.Object) @ line 17 - suggestions: tasks.foobar
- - tasks.foobarr (java.lang.Object) @ line 18 - suggestions: tasks.foobar""")
+ failureCauseContains('''
+ model.tasks.raboof @ build.gradle line 15, column 17
+ subject:
+ - tasks.raboof Object
+ inputs:
+ - tasks.foonar Object (@ line 16) [*]
+ suggestions: tasks.foobar
+ - tasks.fooar Object (@ line 17) [*]
+ suggestions: tasks.foobar
+ - tasks.foobarr Object (@ line 18) [*]
+ suggestions: tasks.foobar
+''')
}
def "can not access project or script from rule"() {
@@ -352,4 +363,5 @@ class ModelDslRuleInputDetectionIntegrationSpec extends AbstractIntegrationSpec
then:
succeeds "tasks"
}
+
}
diff --git a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/NonTransformedModelDslBacking.java b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/NonTransformedModelDslBacking.java
index c5781b8..1cbe305 100644
--- a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/NonTransformedModelDslBacking.java
+++ b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/NonTransformedModelDslBacking.java
@@ -27,6 +27,7 @@ import org.gradle.model.InvalidModelRuleDeclarationException;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor;
+import org.gradle.model.internal.manage.schema.ManagedImplModelSchema;
import org.gradle.model.internal.manage.schema.ModelSchema;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.registry.ModelRegistry;
@@ -43,42 +44,45 @@ public class NonTransformedModelDslBacking extends GroovyObjectSupport {
private final ModelPath modelPath;
private final ModelRegistry modelRegistry;
private final ModelSchemaStore modelSchemaStore;
- private final ModelCreatorFactory modelCreatorFactory;
private AtomicBoolean executingDsl;
- public NonTransformedModelDslBacking(ModelRegistry modelRegistry, ModelSchemaStore modelSchemaStore, ModelCreatorFactory modelCreatorFactory) {
- this(new AtomicBoolean(), null, modelRegistry, modelSchemaStore, modelCreatorFactory);
+ public NonTransformedModelDslBacking(ModelRegistry modelRegistry, ModelSchemaStore modelSchemaStore) {
+ this(new AtomicBoolean(), null, modelRegistry, modelSchemaStore);
}
- private NonTransformedModelDslBacking(AtomicBoolean executingDsl, ModelPath modelPath, ModelRegistry modelRegistry, ModelSchemaStore modelSchemaStore, ModelCreatorFactory modelCreatorFactory) {
+ private NonTransformedModelDslBacking(AtomicBoolean executingDsl, ModelPath modelPath, ModelRegistry modelRegistry, ModelSchemaStore modelSchemaStore) {
this.executingDsl = executingDsl;
this.modelPath = modelPath;
this.modelRegistry = modelRegistry;
this.modelSchemaStore = modelSchemaStore;
- this.modelCreatorFactory = modelCreatorFactory;
}
private NonTransformedModelDslBacking getChildPath(String name) {
ModelPath path = modelPath == null ? ModelPath.path(name) : modelPath.child(name);
- return new NonTransformedModelDslBacking(executingDsl, path, modelRegistry, modelSchemaStore, modelCreatorFactory);
+ return new NonTransformedModelDslBacking(executingDsl, path, modelRegistry, modelSchemaStore);
}
private void registerConfigurationAction(final Closure<?> action) {
modelRegistry.configure(ModelActionRole.Mutate,
- new NoInputsModelAction<Object>(
- ModelReference.untyped(modelPath),
- new SimpleModelRuleDescriptor("model." + modelPath), new ClosureBackedAction<Object>(action)
- ));
+ new NoInputsModelAction<Object>(
+ ModelReference.untyped(modelPath),
+ new SimpleModelRuleDescriptor("model." + modelPath), new ClosureBackedAction<Object>(action)
+ ));
}
private <T> void registerCreator(Class<T> type, Closure<?> closure) {
ModelRuleDescriptor descriptor = new SimpleModelRuleDescriptor("model." + modelPath);
ModelSchema<T> schema = modelSchemaStore.getSchema(ModelType.of(type));
- if (!schema.getKind().isManaged()) {
+ if (!(schema instanceof ManagedImplModelSchema)) {
throw new InvalidModelRuleDeclarationException(descriptor, "Cannot create an element of type " + type.getName() + " as it is not a managed type");
}
- modelRegistry.create(modelCreatorFactory.creator(descriptor, modelPath, schema, new ClosureBackedAction<T>(closure)));
+ modelRegistry.create(
+ ModelCreators.of(modelPath, ((ManagedImplModelSchema<T>)schema).getNodeInitializer())
+ .descriptor(descriptor)
+ .action(ModelActionRole.Initialize, NoInputsModelAction.of(ModelReference.of(modelPath, type), descriptor, new ClosureBackedAction<T>(closure)))
+ .build()
+ );
}
public void configure(Closure<?> action) {
diff --git a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/TransformedModelDslBacking.java b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/TransformedModelDslBacking.java
index 5d6f406..e8efff1 100644
--- a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/TransformedModelDslBacking.java
+++ b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/TransformedModelDslBacking.java
@@ -24,6 +24,7 @@ import org.gradle.api.Action;
import org.gradle.api.Transformer;
import org.gradle.api.internal.ClosureBackedAction;
import org.gradle.internal.BiAction;
+import org.gradle.internal.file.RelativeFilePathResolver;
import org.gradle.model.InvalidModelRuleDeclarationException;
import org.gradle.model.dsl.internal.inputs.RuleInputAccessBacking;
import org.gradle.model.dsl.internal.transform.InputReferences;
@@ -32,11 +33,13 @@ import org.gradle.model.dsl.internal.transform.RulesBlock;
import org.gradle.model.dsl.internal.transform.SourceLocation;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
+import org.gradle.model.internal.manage.schema.ManagedImplModelSchema;
import org.gradle.model.internal.manage.schema.ModelSchema;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.model.internal.type.ModelType;
+import java.net.URI;
import java.util.List;
@ThreadSafe
@@ -52,28 +55,18 @@ public class TransformedModelDslBacking {
}
};
- private static final Transformer<SourceLocation, Closure<?>> RULE_LOCATION_EXTRACTOR = new Transformer<SourceLocation, Closure<?>>() {
- public SourceLocation transform(Closure<?> closure) {
- RuleMetadata ruleMetadata = getRuleMetadata(closure);
- return new SourceLocation(ruleMetadata.scriptSourceDescription(), ruleMetadata.lineNumber(), ruleMetadata.columnNumber());
- }
- };
-
private final ModelRegistry modelRegistry;
private final Transformer<? extends InputReferences, ? super Closure<?>> inputPathsExtractor;
private final Transformer<SourceLocation, ? super Closure<?>> ruleLocationExtractor;
private final ModelSchemaStore schemaStore;
- private final ModelCreatorFactory modelCreatorFactory;
- public TransformedModelDslBacking(ModelRegistry modelRegistry, ModelSchemaStore schemaStore, ModelCreatorFactory modelCreatorFactory) {
- this(modelRegistry, schemaStore, modelCreatorFactory, INPUT_PATHS_EXTRACTOR, RULE_LOCATION_EXTRACTOR);
+ public TransformedModelDslBacking(ModelRegistry modelRegistry, ModelSchemaStore schemaStore, RelativeFilePathResolver relativeFilePathResolver) {
+ this(modelRegistry, schemaStore, INPUT_PATHS_EXTRACTOR, new RelativePathSourceLocationTransformer(relativeFilePathResolver));
}
- TransformedModelDslBacking(ModelRegistry modelRegistry, ModelSchemaStore schemaStore, ModelCreatorFactory modelCreatorFactory, Transformer<? extends InputReferences, ? super Closure<?>> inputPathsExtractor,
- Transformer<SourceLocation, ? super Closure<?>> ruleLocationExtractor) {
+ TransformedModelDslBacking(ModelRegistry modelRegistry, ModelSchemaStore schemaStore, Transformer<? extends InputReferences, ? super Closure<?>> inputPathsExtractor, Transformer<SourceLocation, ? super Closure<?>> ruleLocationExtractor) {
this.modelRegistry = modelRegistry;
this.schemaStore = schemaStore;
- this.modelCreatorFactory = modelCreatorFactory;
this.inputPathsExtractor = inputPathsExtractor;
this.ruleLocationExtractor = ruleLocationExtractor;
}
@@ -90,11 +83,10 @@ public class TransformedModelDslBacking {
ModelPath modelPath = ModelPath.path(modelPathString);
ModelSchema<T> schema = schemaStore.getSchema(ModelType.of(type));
ModelRuleDescriptor descriptor = toDescriptor(sourceLocation, modelPath);
- if (!schema.getKind().isManaged()) {
+ if (!(schema instanceof ManagedImplModelSchema)) {
throw new InvalidModelRuleDeclarationException(descriptor, "Cannot create an element of type " + type.getName() + " as it is not a managed type");
}
- ModelCreator creator = modelCreatorFactory.creator(descriptor, modelPath, schema);
- modelRegistry.create(creator);
+ modelRegistry.create(ModelCreators.of(modelPath, ((ManagedImplModelSchema<T>) schema).getNodeInitializer()).descriptor(descriptor).build());
registerAction(modelPath, type, descriptor, ModelActionRole.Initialize, closure);
}
@@ -159,4 +151,30 @@ public class TransformedModelDslBacking {
});
}
}
+
+ private static class RelativePathSourceLocationTransformer implements Transformer<SourceLocation, Closure<?>> {
+ private final RelativeFilePathResolver relativeFilePathResolver;
+
+ public RelativePathSourceLocationTransformer(RelativeFilePathResolver relativeFilePathResolver) {
+ this.relativeFilePathResolver = relativeFilePathResolver;
+ }
+
+ // TODO given that all the closures are from the same file, we should do the relativising once.
+ // that would entail adding location information to the model {} outer closure.
+ @Override
+ public SourceLocation transform(Closure<?> closure) {
+ RuleMetadata ruleMetadata = getRuleMetadata(closure);
+ URI uri = URI.create(ruleMetadata.absoluteScriptSourceLocation());
+ String scheme = uri.getScheme();
+ String description;
+
+ if ("file".equalsIgnoreCase(scheme)) {
+ description = relativeFilePathResolver.resolveAsRelativePath(ruleMetadata.absoluteScriptSourceLocation());
+ } else {
+ description = uri.toString();
+ }
+
+ return new SourceLocation(uri.toString(), description, ruleMetadata.lineNumber(), ruleMetadata.columnNumber());
+ }
+ }
}
diff --git a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleMetadata.java b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleMetadata.java
index 88a8c19..135bb53 100644
--- a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleMetadata.java
+++ b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleMetadata.java
@@ -43,4 +43,6 @@ public @interface RuleMetadata {
int lineNumber();
int columnNumber();
+
+ String absoluteScriptSourceLocation();
}
diff --git a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleVisitor.java b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleVisitor.java
index 00b97c4..0ba7d6c 100644
--- a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleVisitor.java
+++ b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RuleVisitor.java
@@ -73,6 +73,7 @@ public class RuleVisitor extends ExpressionReplacingVisitorSupport {
AnnotationNode metadataAnnotation = new AnnotationNode(ANNOTATION_CLASS_NODE);
metadataAnnotation.addMember("scriptSourceDescription", new ConstantExpression(sourceLocation.getScriptSourceDescription()));
+ metadataAnnotation.addMember("absoluteScriptSourceLocation", new ConstantExpression(sourceLocation.getUri()));
metadataAnnotation.addMember("lineNumber", new ConstantExpression(sourceLocation.getLineNumber()));
metadataAnnotation.addMember("columnNumber", new ConstantExpression(sourceLocation.getColumnNumber()));
diff --git a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RulesVisitor.java b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RulesVisitor.java
index cf404e6..e297c43 100644
--- a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RulesVisitor.java
+++ b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/RulesVisitor.java
@@ -28,7 +28,7 @@ import org.codehaus.groovy.control.SourceUnit;
import org.gradle.api.Nullable;
import org.gradle.groovy.scripts.internal.AstUtils;
import org.gradle.groovy.scripts.internal.RestrictiveCodeVisitor;
-import org.gradle.groovy.scripts.internal.ScriptSourceDescriptionTransformer;
+import org.gradle.groovy.scripts.internal.ScriptSourceTransformer;
import org.gradle.internal.Pair;
import org.gradle.model.internal.core.ModelPath;
@@ -40,7 +40,6 @@ public class RulesVisitor extends RestrictiveCodeVisitor {
private static final String AST_NODE_METADATA_KEY = RulesVisitor.class.getName();
private static final ClassNode ANNOTATION_CLASS_NODE = new ClassNode(RulesBlock.class);
-
// TODO - have to do much better here
public static final String INVALID_STATEMENT = "illegal rule";
public static final String INVALID_RULE_SIGNATURE = "Rule must follow the pattern '«name»(«type») {}' for a creator, and '«name» {}' for an action";
@@ -115,7 +114,7 @@ public class RulesVisitor extends RestrictiveCodeVisitor {
call.setImplicitThis(true);
call.setObjectExpression(new MethodCallExpression(VariableExpression.THIS_EXPRESSION, "getDelegate", ArgumentListExpression.EMPTY_ARGUMENTS));
- SourceLocation sourceLocation = new SourceLocation(getScriptSourceDescription(), call.getLineNumber(), call.getColumnNumber());
+ SourceLocation sourceLocation = new SourceLocation(getScriptSourceLocation(), getScriptSourceDescription(), call.getLineNumber(), call.getColumnNumber());
closureExpression.getCode().setNodeMetaData(RuleVisitor.AST_NODE_METADATA_LOCATION_KEY, sourceLocation);
closureExpression.visit(ruleVisitor);
@@ -132,14 +131,18 @@ public class RulesVisitor extends RestrictiveCodeVisitor {
call.setImplicitThis(true);
call.setObjectExpression(new MethodCallExpression(VariableExpression.THIS_EXPRESSION, "getDelegate", ArgumentListExpression.EMPTY_ARGUMENTS));
- SourceLocation sourceLocation = new SourceLocation(getScriptSourceDescription(), call.getLineNumber(), call.getColumnNumber());
+ SourceLocation sourceLocation = new SourceLocation(getScriptSourceLocation(), getScriptSourceDescription(), call.getLineNumber(), call.getColumnNumber());
closureExpression.getCode().setNodeMetaData(RuleVisitor.AST_NODE_METADATA_LOCATION_KEY, sourceLocation);
closureExpression.visit(ruleVisitor);
}
private String getScriptSourceDescription() {
- return sourceUnit.getAST().getNodeMetaData(ScriptSourceDescriptionTransformer.AST_NODE_METADATA_KEY);
+ return sourceUnit.getAST().getNodeMetaData(ScriptSourceTransformer.AST_NODE_DESCRIPTION_METADATA_KEY);
+ }
+
+ private String getScriptSourceLocation() {
+ return sourceUnit.getAST().getNodeMetaData(ScriptSourceTransformer.AST_NODE_LOCATION_METADATA_KEY);
}
@Nullable // if the target was invalid
diff --git a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/SourceLocation.java b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/SourceLocation.java
index e90955d..a4cadf1 100644
--- a/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/SourceLocation.java
+++ b/subprojects/model-groovy/src/main/java/org/gradle/model/dsl/internal/transform/SourceLocation.java
@@ -22,11 +22,13 @@ import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor;
@ThreadSafe
public class SourceLocation {
+ private final String uri;
private final String scriptSourceDescription;
private final int lineNumber;
private final int columnNumber;
- public SourceLocation(String scriptSourceDescription, int lineNumber, int columnNumber) {
+ public SourceLocation(String uri, String scriptSourceDescription, int lineNumber, int columnNumber) {
+ this.uri = uri;
this.scriptSourceDescription = scriptSourceDescription;
this.lineNumber = lineNumber;
this.columnNumber = columnNumber;
@@ -44,6 +46,9 @@ public class SourceLocation {
return scriptSourceDescription;
}
+ public String getUri() {
+ return uri;
+ }
@Override
public String toString() {
return String.format("%s line %d, column %d", scriptSourceDescription, lineNumber, columnNumber);
diff --git a/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/NonTransformedModelDslBackingTest.groovy b/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/NonTransformedModelDslBackingTest.groovy
index bad4c90..5197ef9 100644
--- a/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/NonTransformedModelDslBackingTest.groovy
+++ b/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/NonTransformedModelDslBackingTest.groovy
@@ -24,7 +24,6 @@ import org.gradle.model.internal.core.ModelPath
import org.gradle.model.internal.core.ModelReference
import org.gradle.model.internal.core.ModelRuleExecutionException
import org.gradle.model.internal.fixture.ModelRegistryHelper
-import org.gradle.model.internal.inspect.DefaultModelCreatorFactory
import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.model.internal.type.ModelType
import spock.lang.Specification
@@ -33,8 +32,7 @@ class NonTransformedModelDslBackingTest extends Specification {
def modelRegistry = new ModelRegistryHelper()
def schemaStore = DefaultModelSchemaStore.instance
- def creatorFactory = new DefaultModelCreatorFactory(schemaStore)
- def modelDsl = new NonTransformedModelDslBacking(getModelRegistry(), schemaStore, creatorFactory)
+ def modelDsl = new NonTransformedModelDslBacking(getModelRegistry(), schemaStore)
void register(String pathString, Object element) {
modelRegistry.create(ModelCreators.bridgedInstance(ModelReference.of(pathString, element.class), element).descriptor("register").build())
diff --git a/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/TransformedModelDslBackingTest.groovy b/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/TransformedModelDslBackingTest.groovy
index cc2b5ea..bba1a8c 100644
--- a/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/TransformedModelDslBackingTest.groovy
+++ b/subprojects/model-groovy/src/test/groovy/org/gradle/model/dsl/internal/TransformedModelDslBackingTest.groovy
@@ -26,7 +26,6 @@ import org.gradle.model.internal.core.ModelCreators
import org.gradle.model.internal.core.ModelPath
import org.gradle.model.internal.core.ModelReference
import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor
-import org.gradle.model.internal.inspect.DefaultModelCreatorFactory
import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.model.internal.registry.DefaultModelRegistry
import org.gradle.model.internal.type.ModelType
@@ -38,8 +37,7 @@ class TransformedModelDslBackingTest extends Specification {
Transformer<List<ModelReference<?>>, Closure<?>> referenceExtractor = Mock()
Transformer<SourceLocation, Closure<?>> locationExtractor = Mock()
def schemaStore = DefaultModelSchemaStore.instance
- def creator = new DefaultModelCreatorFactory(schemaStore)
- def modelDsl = new TransformedModelDslBacking(getModelRegistry(), schemaStore, creator, referenceExtractor, locationExtractor)
+ def modelDsl = new TransformedModelDslBacking(getModelRegistry(), schemaStore, referenceExtractor, locationExtractor)
void register(String pathString, Object element) {
modelRegistry.create(ModelCreators.bridgedInstance(ModelReference.of(pathString, element.class), element).descriptor("register").build())
@@ -123,6 +121,5 @@ class TransformedModelDslBackingTest extends Specification {
then:
modelRegistry.realize(ModelPath.path("foo"), ModelType.of(List)) == ["123"]
}
-
}
diff --git a/subprojects/native/src/main/java/org/gradle/internal/nativeintegration/services/NativeServices.java b/subprojects/native/src/main/java/org/gradle/internal/nativeintegration/services/NativeServices.java
index 90cda3d..e28d6a3 100755
--- a/subprojects/native/src/main/java/org/gradle/internal/nativeintegration/services/NativeServices.java
+++ b/subprojects/native/src/main/java/org/gradle/internal/nativeintegration/services/NativeServices.java
@@ -50,6 +50,8 @@ public class NativeServices extends DefaultServiceRegistry implements ServiceReg
private static final NativeServices INSTANCE = new NativeServices();
private static boolean initialized;
+ public static final String NATIVE_DIR_OVERRIDE = "org.gradle.native.dir";
+
/**
* Initializes the native services to use the given user home directory to store native libs and other resources. Does nothing if already initialized. Will be implicitly initialized on first usage
* of a native service. Also initializes the Native-Platform library using the given user home directory.
@@ -59,7 +61,13 @@ public class NativeServices extends DefaultServiceRegistry implements ServiceReg
}
public static synchronized void initialize(File userHomeDir, boolean initializeJNA) {
- File nativeDir = new File(userHomeDir, "native");
+ String overrideProperty = System.getProperty(NATIVE_DIR_OVERRIDE);
+ File nativeDir;
+ if (overrideProperty == null) {
+ nativeDir = new File(userHomeDir, "native");
+ } else {
+ nativeDir = new File(overrideProperty);
+ }
if (useNativePlatform) {
try {
net.rubygrapefruit.platform.Native.init(nativeDir);
diff --git a/subprojects/native/src/test/groovy/org/gradle/internal/nativeintegration/console/NativePlatformConsoleDetectorTest.groovy b/subprojects/native/src/test/groovy/org/gradle/internal/nativeintegration/console/NativePlatformConsoleDetectorTest.groovy
index fea96d6..27291e7 100644
--- a/subprojects/native/src/test/groovy/org/gradle/internal/nativeintegration/console/NativePlatformConsoleDetectorTest.groovy
+++ b/subprojects/native/src/test/groovy/org/gradle/internal/nativeintegration/console/NativePlatformConsoleDetectorTest.groovy
@@ -16,8 +16,10 @@
package org.gradle.internal.nativeintegration.console
-import spock.lang.Specification
import net.rubygrapefruit.platform.Terminals
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import spock.lang.Specification
class NativePlatformConsoleDetectorTest extends Specification {
private Terminals terminals = Mock()
@@ -32,6 +34,7 @@ class NativePlatformConsoleDetectorTest extends Specification {
detector.console == null
}
+ @Requires(TestPrecondition.SMART_TERMINAL)
def "returns metadata when stdout and stderr are attached to console"() {
given:
terminals.isTerminal(Terminals.Output.Stdout) >> true
@@ -43,6 +46,7 @@ class NativePlatformConsoleDetectorTest extends Specification {
detector.console.stdErr
}
+ @Requires(TestPrecondition.SMART_TERMINAL)
def "returns metadata when only stdout is attached to console"() {
given:
terminals.isTerminal(Terminals.Output.Stdout) >> true
@@ -54,6 +58,7 @@ class NativePlatformConsoleDetectorTest extends Specification {
!detector.console.stdErr
}
+ @Requires(TestPrecondition.SMART_TERMINAL)
def "returns metadata when only stderr is attached to console"() {
given:
terminals.isTerminal(Terminals.Output.Stdout) >> false
diff --git a/subprojects/performance/performance.gradle b/subprojects/performance/performance.gradle
index 8421611..ba896dc 100644
--- a/subprojects/performance/performance.gradle
+++ b/subprojects/performance/performance.gradle
@@ -331,7 +331,7 @@ task multiNative(type: ProjectGeneratorTask) {
}
task manyProjectsNative(type: ProjectGeneratorTask) {
- projects = 500
+ projects = 100
sourceFiles = 1
nativeProject = true
templateArgs = [
@@ -428,3 +428,9 @@ integTest {
excludeCategories 'org.gradle.performance.PerformanceTest'
}
}
+
+java9IntegTest {
+ options {
+ excludeCategories 'org.gradle.performance.PerformanceTest'
+ }
+}
diff --git a/subprojects/performance/src/integTest/groovy/org/gradle/performance/OldJavaPluginBigProjectPerformanceTest.groovy b/subprojects/performance/src/integTest/groovy/org/gradle/performance/OldJavaPluginBigProjectPerformanceTest.groovy
index 22d5fe2..8615e94 100644
--- a/subprojects/performance/src/integTest/groovy/org/gradle/performance/OldJavaPluginBigProjectPerformanceTest.groovy
+++ b/subprojects/performance/src/integTest/groovy/org/gradle/performance/OldJavaPluginBigProjectPerformanceTest.groovy
@@ -30,8 +30,8 @@ class OldJavaPluginBigProjectPerformanceTest extends AbstractCrossVersionPerform
runner.testProject = "bigOldJavaMoreSource"
runner.useDaemon = true
runner.tasksToRun = tasks
- runner.maxExecutionTimeRegression = millis(200)
- runner.maxMemoryRegression = mbytes(100)
+ runner.maxExecutionTimeRegression = millis(500)
+ runner.maxMemoryRegression = mbytes(200)
runner.targetVersions = ['2.0', '2.2.1', '2.4', 'last']
runner.gradleOpts = ["-Xmx1024m", "-XX:MaxPermSize=256m"]
diff --git a/subprojects/performance/src/integTest/groovy/org/gradle/performance/ProjectDependenciesPerformanceTest.groovy b/subprojects/performance/src/integTest/groovy/org/gradle/performance/ProjectDependenciesPerformanceTest.groovy
index cc457df..8ce84fa 100644
--- a/subprojects/performance/src/integTest/groovy/org/gradle/performance/ProjectDependenciesPerformanceTest.groovy
+++ b/subprojects/performance/src/integTest/groovy/org/gradle/performance/ProjectDependenciesPerformanceTest.groovy
@@ -16,9 +16,6 @@
package org.gradle.performance
-import org.junit.experimental.categories.Category
-
- at Category(Experiment)
class ProjectDependenciesPerformanceTest extends AbstractCrossVersionPerformanceTest {
def "resolving dependencies"() {
diff --git a/subprojects/performance/src/integTest/groovy/org/gradle/performance/VariantsPerformanceTest.groovy b/subprojects/performance/src/integTest/groovy/org/gradle/performance/VariantsPerformanceTest.groovy
index 69718fe..faf0236 100644
--- a/subprojects/performance/src/integTest/groovy/org/gradle/performance/VariantsPerformanceTest.groovy
+++ b/subprojects/performance/src/integTest/groovy/org/gradle/performance/VariantsPerformanceTest.groovy
@@ -17,10 +17,19 @@
package org.gradle.performance
+import org.gradle.performance.fixture.BuildExperimentSpec
+import org.junit.experimental.categories.Category
import spock.lang.Unroll
+ at Category(Experiment)
class VariantsPerformanceTest extends AbstractCrossBuildPerformanceTest {
+ @Override
+ protected void defaultSpec(BuildExperimentSpec.Builder builder) {
+ builder.invocation.gradleOpts("-Xmx1024m", "-XX:MaxPermSize=256m")
+ super.defaultSpec(builder)
+ }
+
@Unroll
def "#size project using variants #scenario build"() {
when:
@@ -125,6 +134,7 @@ class VariantsPerformanceTest extends AbstractCrossBuildPerformanceTest {
scenario | tasks
"single variant" | [":project1:flavour1type1_t1"]
"all variants single project" | [":project1:allVariants"]
- "all variants all projects" | ["allVariants"]
+ // This is causing the performance test process to die and the build to hang: disabling for now.
+// "all variants all projects" | ["allVariants"]
}
}
diff --git a/subprojects/performance/src/templates/native-pch-source/pch.h b/subprojects/performance/src/templates/native-pch-source/pch.h
index dab4c2d..5fbd0ec 100644
--- a/subprojects/performance/src/templates/native-pch-source/pch.h
+++ b/subprojects/performance/src/templates/native-pch-source/pch.h
@@ -3,8 +3,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
-#include <sys/socket.h>
-#include <unistd.h>
+#include <math.h>
+#include <stdarg.h>
#include <signal.h>
-#include <getopt.h>
-#endif
\ No newline at end of file
+#include <stddef.h>
+#include <errno.h>
+#include <time.h>
+#endif
diff --git a/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/CrossVersionPerformanceTestRunnerTest.groovy b/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/CrossVersionPerformanceTestRunnerTest.groovy
index b97e0fc..e3f22ec 100644
--- a/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/CrossVersionPerformanceTestRunnerTest.groovy
+++ b/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/CrossVersionPerformanceTestRunnerTest.groovy
@@ -22,6 +22,8 @@ import org.gradle.performance.ResultSpecification
import org.gradle.performance.measure.DataAmount
import org.gradle.performance.measure.Duration
import org.gradle.util.GradleVersion
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
class CrossVersionPerformanceTestRunnerTest extends ResultSpecification {
final experimentRunner = Mock(BuildExperimentRunner)
@@ -31,6 +33,7 @@ class CrossVersionPerformanceTestRunnerTest extends ResultSpecification {
final mostRecentRelease = new ReleasedVersionDistributions().mostRecentFinalRelease.version.version
final currentVersionBase = GradleVersion.current().baseVersion.version
+ @Requires(TestPrecondition.NOT_PULL_REQUEST_BUILD)
def "runs test and builds results"() {
given:
def runner = runner()
@@ -75,6 +78,7 @@ class CrossVersionPerformanceTestRunnerTest extends ResultSpecification {
0 * reporter._
}
+ @Requires(TestPrecondition.NOT_PULL_REQUEST_BUILD)
def "can use 'last' baseline version to refer to most recently released version"() {
given:
def runner = runner()
@@ -87,6 +91,7 @@ class CrossVersionPerformanceTestRunnerTest extends ResultSpecification {
results.baselineVersions*.version == ['1.0', mostRecentRelease]
}
+ @Requires(TestPrecondition.NOT_PULL_REQUEST_BUILD)
def "ignores baseline version if it has the same base as the version under test"() {
given:
def runner = runner()
diff --git a/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/GCLoggingCollectorTest.groovy b/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/GCLoggingCollectorTest.groovy
index 181c731..d838bb1 100644
--- a/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/GCLoggingCollectorTest.groovy
+++ b/subprojects/performance/src/test/groovy/org/gradle/performance/fixture/GCLoggingCollectorTest.groovy
@@ -39,7 +39,7 @@ class GCLoggingCollectorTest extends Specification {
resources.getResource(logName).copyTo(projectDir.file("gc.txt"))
when:
- collector.getAdditionalGradleOpts(projectDir)
+ collector.getAdditionalJvmOpts(projectDir)
collector.collect(operation, locale)
then:
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildEventTimestampCollector.java b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildEventTimestampCollector.java
index de1316c..25f5c4f 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildEventTimestampCollector.java
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildEventTimestampCollector.java
@@ -34,7 +34,7 @@ public class BuildEventTimestampCollector implements DataCollector {
}
@Override
- public List<String> getAdditionalGradleOpts(File workingDir) {
+ public List<String> getAdditionalJvmOpts(File workingDir) {
return Collections.emptyList();
}
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildExperimentRunner.java b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildExperimentRunner.java
index 8b9c722..1e3160a 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildExperimentRunner.java
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/BuildExperimentRunner.java
@@ -42,10 +42,10 @@ public class BuildExperimentRunner {
System.out.println();
File workingDirectory = experiment.getInvocation().getWorkingDirectory();
- final List<String> additionalGradleOpts = dataCollector.getAdditionalGradleOpts(workingDirectory);
+ final List<String> additionalJvmOpts = dataCollector.getAdditionalJvmOpts(workingDirectory);
final List<String> additionalArgs = dataCollector.getAdditionalArgs(workingDirectory);
- GradleInvocationSpec buildSpec = experiment.getInvocation().withAdditionalGradleOpts(additionalGradleOpts).withAdditionalArgs(additionalArgs);
+ GradleInvocationSpec buildSpec = experiment.getInvocation().withAdditionalJvmOpts(additionalJvmOpts).withAdditionalArgs(additionalArgs);
GradleSession session = executerProvider.session(buildSpec);
session.prepare();
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/CompositeDataCollector.java b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/CompositeDataCollector.java
index f3dc713..779391f 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/CompositeDataCollector.java
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/CompositeDataCollector.java
@@ -31,10 +31,10 @@ public class CompositeDataCollector implements DataCollector {
}
@Override
- public List<String> getAdditionalGradleOpts(File workingDir) {
+ public List<String> getAdditionalJvmOpts(File workingDir) {
List<String> additional = Lists.newLinkedList();
for (DataCollector collector : collectors) {
- additional.addAll(collector.getAdditionalGradleOpts(workingDir));
+ additional.addAll(collector.getAdditionalJvmOpts(workingDir));
}
return additional;
}
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/DataCollector.java b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/DataCollector.java
index 423d99d..7cb163d 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/DataCollector.java
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/DataCollector.java
@@ -22,7 +22,7 @@ import java.io.File;
import java.util.List;
public interface DataCollector {
- List<String> getAdditionalGradleOpts(File workingDir);
+ List<String> getAdditionalJvmOpts(File workingDir);
List<String> getAdditionalArgs(File workingDir);
void collect(File testProjectDir, MeasuredOperation operation);
}
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GCLoggingCollector.java b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GCLoggingCollector.java
index 128b3c3..958238f 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GCLoggingCollector.java
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GCLoggingCollector.java
@@ -37,7 +37,7 @@ public class GCLoggingCollector implements DataCollector {
private File logFile;
@Override
- public List<String> getAdditionalGradleOpts(File workingDir) {
+ public List<String> getAdditionalJvmOpts(File workingDir) {
logFile = new File(workingDir, "gc.txt");
return Arrays.asList(
"-verbosegc",
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/Git.groovy b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/Git.groovy
index 7fd66c5..12c611c 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/Git.groovy
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/Git.groovy
@@ -34,7 +34,7 @@ class Git {
def repository = new FileRepositoryBuilder().findGitDir().build()
try {
branchName = repository.branch
- commitId = repository.getRef(repository.fullBranch).objectId.name
+ commitId = repository.resolve(repository.fullBranch).name
} finally {
repository.close()
}
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleExecuterBackedSession.groovy b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleExecuterBackedSession.groovy
index 8e585d3..b225e1f 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleExecuterBackedSession.groovy
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleExecuterBackedSession.groovy
@@ -60,17 +60,13 @@ class GradleExecuterBackedSession implements GradleSession {
withTasks(invocation.tasksToRun)
if (withGradleOpts) {
- if (invocation.useDaemon) {
- executer.withGradleOpts("-Dorg.gradle.jvmargs=" + invocation.gradleOpts.join(" "))
- } else {
- executer.withGradleOpts(invocation.gradleOpts as String[])
- }
+ executer.withBuildJvmOpts(invocation.jvmOpts)
}
invocation.args.each { executer.withArgument(it) }
if (invocation.useDaemon) {
- executer.withArgument('--daemon')
+ executer.requireDaemon()
}
executer
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleInvocationSpec.groovy b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleInvocationSpec.groovy
index 4f1284e..127e494 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleInvocationSpec.groovy
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/GradleInvocationSpec.groovy
@@ -31,16 +31,16 @@ class GradleInvocationSpec {
final File workingDirectory
final List<String> tasksToRun
final List<String> args
- final List<String> gradleOpts
+ final List<String> jvmOpts
final boolean useDaemon
final boolean useToolingApi
- GradleInvocationSpec(GradleDistribution gradleDistribution, File workingDirectory, List<String> tasksToRun, List<String> args, List<String> gradleOpts, boolean useDaemon, boolean useToolingApi) {
+ GradleInvocationSpec(GradleDistribution gradleDistribution, File workingDirectory, List<String> tasksToRun, List<String> args, List<String> jvmOpts, boolean useDaemon, boolean useToolingApi) {
this.gradleDistribution = gradleDistribution
this.workingDirectory = workingDirectory
this.tasksToRun = tasksToRun
this.args = args
- this.gradleOpts = gradleOpts
+ this.jvmOpts = jvmOpts
this.useDaemon = useDaemon
this.useToolingApi = useToolingApi
}
@@ -49,12 +49,12 @@ class GradleInvocationSpec {
return new Builder()
}
- GradleInvocationSpec withAdditionalGradleOpts(List<String> additionalGradleOpts) {
- return new GradleInvocationSpec(gradleDistribution, workingDirectory, tasksToRun, args, ImmutableList.builder().addAll(gradleOpts).addAll(additionalGradleOpts).build(), useDaemon, useToolingApi)
+ GradleInvocationSpec withAdditionalJvmOpts(List<String> additionalJvmOpts) {
+ return new GradleInvocationSpec(gradleDistribution, workingDirectory, tasksToRun, args, ImmutableList.builder().addAll(jvmOpts).addAll(additionalJvmOpts).build(), useDaemon, useToolingApi)
}
GradleInvocationSpec withAdditionalArgs(List<String> additionalArgs) {
- return new GradleInvocationSpec(gradleDistribution, workingDirectory, tasksToRun, ImmutableList.builder().addAll(args).addAll(additionalArgs).build(), gradleOpts, useDaemon, useToolingApi)
+ return new GradleInvocationSpec(gradleDistribution, workingDirectory, tasksToRun, ImmutableList.builder().addAll(args).addAll(additionalArgs).build(), jvmOpts, useDaemon, useToolingApi)
}
static class Builder {
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/MemoryInfoCollector.groovy b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/MemoryInfoCollector.groovy
index 2bbd825..0318c6d 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/MemoryInfoCollector.groovy
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/MemoryInfoCollector.groovy
@@ -23,7 +23,7 @@ public class MemoryInfoCollector implements DataCollector {
String outputFileName
@Override
- List<String> getAdditionalGradleOpts(File workingDir) {
+ List<String> getAdditionalJvmOpts(File workingDir) {
return Collections.emptyList();
}
diff --git a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/ToolingApiBackedGradleSession.groovy b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/ToolingApiBackedGradleSession.groovy
index d2b74ed..cdec3af 100644
--- a/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/ToolingApiBackedGradleSession.groovy
+++ b/subprojects/performance/src/testFixtures/groovy/org/gradle/performance/fixture/ToolingApiBackedGradleSession.groovy
@@ -53,7 +53,7 @@ class ToolingApiBackedGradleSession implements GradleSession {
buildLauncher = projectConnection.newBuild()
.withArguments(invocation.args + ["-u"] as String[])
.forTasks(invocation.tasksToRun as String[])
- .setJvmArguments(invocation.gradleOpts as String[])
+ .setJvmArguments(invocation.jvmOpts as String[])
.setStandardOutput(System.out)
.setStandardError(System.err)
}
diff --git a/subprojects/platform-base/platform-base.gradle b/subprojects/platform-base/platform-base.gradle
index b309db5..b847f23 100644
--- a/subprojects/platform-base/platform-base.gradle
+++ b/subprojects/platform-base/platform-base.gradle
@@ -1,6 +1,7 @@
dependencies {
compile libraries.groovy
compile project(":core")
+ compile project(":dependencyManagement")
testFixturesCompile project(path: ":modelCore", configuration: "testFixturesUsageRuntime")
}
diff --git a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/ComponentModelIntegrationTest.groovy b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/ComponentModelIntegrationTest.groovy
index 3550671..6a12d68 100644
--- a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/ComponentModelIntegrationTest.groovy
+++ b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/ComponentModelIntegrationTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.language.base
+import org.gradle.api.reporting.model.ModelReportOutput
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.EnableModelDsl
import org.gradle.util.TextUtil
@@ -25,7 +26,6 @@ class ComponentModelIntegrationTest extends AbstractIntegrationSpec {
def "setup"() {
EnableModelDsl.enable(executer)
-
buildScript """
interface CustomComponent extends ComponentSpec {}
class DefaultCustomComponent extends BaseComponentSpec implements CustomComponent {}
@@ -125,6 +125,7 @@ class ComponentModelIntegrationTest extends AbstractIntegrationSpec {
import org.gradle.language.base.internal.*
import org.gradle.language.base.*
import org.gradle.internal.reflect.*
+ import org.gradle.internal.service.*
class CustomLanguageTransformation implements LanguageTransform {
@@ -150,7 +151,7 @@ class ComponentModelIntegrationTest extends AbstractIntegrationSpec {
DefaultTask
}
- void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet) {
+ void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry) {
}
}
}
@@ -230,11 +231,14 @@ model {
succeeds "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- components
- main
- binaries
- sources"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ main {
+ binaries()
+ sources()
+ }
+ }
+ }
}
def "can reference sources container for a component in a rule"() {
@@ -289,21 +293,29 @@ model {
succeeds "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- components
- foo
- binaries
- sources
- bar = DefaultCustomLanguageSourceSet 'foo:bar'
- main
- binaries
- sources
- main = DefaultCustomLanguageSourceSet 'main:main'
- test = DefaultCustomLanguageSourceSet 'main:test'
- test
- binaries
- sources
- test = DefaultCustomLanguageSourceSet 'test:test'"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ foo {
+ binaries()
+ sources {
+ bar(nodeValue: "DefaultCustomLanguageSourceSet 'foo:bar'")
+ }
+ }
+ main {
+ binaries()
+ sources {
+ main()
+ test()
+ }
+ }
+ test {
+ binaries()
+ sources {
+ test()
+ }
+ }
+ }
+ }
}
def "can reference sources container elements in a rule"() {
@@ -394,15 +406,18 @@ model {
succeeds "model"
and:
- output.contains(TextUtil.toPlatformLineSeparators(""" components
- main
- binaries
- sources
- someCustomComponent
- binaries
- sources
-"""))
-
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ main {
+ binaries()
+ sources()
+ }
+ someCustomComponent {
+ binaries()
+ sources()
+ }
+ }
+ }
}
def "plugin can configure component with given name"() {
@@ -427,12 +442,18 @@ model {
succeeds "model"
and:
- output.contains(TextUtil.toPlatformLineSeparators(""" components
- main
- binaries
- sources
- bar = DefaultCustomLanguageSourceSet 'main:bar'
- main = DefaultCustomLanguageSourceSet 'main:main'"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ main {
+ binaries()
+ sources {
+ bar()
+ main()
+ }
+ }
+ }
+
+ }
}
def "plugin can apply component beforeEach / afterEach"() {
@@ -458,7 +479,9 @@ model {
succeeds "tasks"
and:
- output.contains(TextUtil.toPlatformLineSeparators("""beforeEach DefaultCustomComponent 'newComponent'
+ output.contains(TextUtil.toPlatformLineSeparators("""beforeEach DefaultCustomComponent 'main'
+afterEach DefaultCustomComponent 'main'
+beforeEach DefaultCustomComponent 'newComponent'
creating DefaultCustomComponent 'newComponent'
afterEach DefaultCustomComponent 'newComponent'"""))
@@ -485,13 +508,17 @@ afterEach DefaultCustomComponent 'newComponent'"""))
succeeds "model"
and:
- output.contains(TextUtil.toPlatformLineSeparators(""" components
- main
- binaries
- sources
- bar = DefaultCustomLanguageSourceSet 'main:bar'
- main = DefaultCustomLanguageSourceSet 'main:main'"""))
-
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ main {
+ binaries()
+ sources {
+ bar()
+ main()
+ }
+ }
+ }
+ }
}
def "buildscript can create component"() {
@@ -507,10 +534,12 @@ afterEach DefaultCustomComponent 'newComponent'"""))
succeeds "model"
and:
- output.contains(TextUtil.toPlatformLineSeparators("""
- someCustomComponent
- binaries
- sources"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ someCustomComponent {
+ binaries()
+ sources()
+ }
+ }
}
@@ -535,17 +564,21 @@ afterEach DefaultCustomComponent 'newComponent'"""))
succeeds "model"
and:
- output.contains(TextUtil.toPlatformLineSeparators(""" components
- main
- binaries
- sources
- bar = DefaultCustomLanguageSourceSet 'main:bar'
- main = DefaultCustomLanguageSourceSet 'main:main'
- test
- binaries
- sources
-"""))
-
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ main {
+ binaries()
+ sources {
+ bar()
+ main()
+ }
+ }
+ test {
+ binaries()
+ sources()
+ }
+ }
+ }
}
def "buildscript can apply component beforeEach / afterEach"() {
@@ -572,7 +605,9 @@ afterEach DefaultCustomComponent 'newComponent'"""))
succeeds "tasks"
and:
- output.contains(TextUtil.toPlatformLineSeparators("""beforeEach DefaultCustomComponent 'newComponent'
+ output.contains(TextUtil.toPlatformLineSeparators("""beforeEach DefaultCustomComponent 'main'
+afterEach DefaultCustomComponent 'main'
+beforeEach DefaultCustomComponent 'newComponent'
creating DefaultCustomComponent 'newComponent'
afterEach DefaultCustomComponent 'newComponent'"""))
@@ -597,13 +632,15 @@ afterEach DefaultCustomComponent 'newComponent'"""))
succeeds "model"
and:
- output.contains(TextUtil.toPlatformLineSeparators(""" components
- main
- binaries
- sources
- bar = DefaultCustomLanguageSourceSet 'main:bar'
- main = DefaultCustomLanguageSourceSet 'main:main'"""))
-
+ ModelReportOutput.from(output).hasNodeStructure {
+ main {
+ binaries()
+ sources {
+ bar(nodeValue: "DefaultCustomLanguageSourceSet 'main:bar'")
+ main(nodeValue: "DefaultCustomLanguageSourceSet 'main:main'")
+ }
+ }
+ }
}
def "reasonable error message when creating component with default implementation"() {
@@ -695,7 +732,7 @@ afterEach DefaultCustomComponent 'newComponent'"""))
when:
fails "tasks"
then:
- failureHasCause "Attempt to mutate closed view of model of type '$fullQualified' given to rule 'ComponentSpecContainerRules#addComponentTasks(org.gradle.api.tasks.TaskContainer, $fullQualified)'"
+ failureHasCause "Attempt to mutate closed view of model of type '$fullQualified' given to rule 'ComponentSpecContainerRules#addComponentTasks'"
where:
projectionType | fullQualified
@@ -712,22 +749,32 @@ afterEach DefaultCustomComponent 'newComponent'"""))
succeeds "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- components
- main
- binaries
- main
- tasks = []
- test
- tasks = []
- sources
- test
- binaries
- main
- tasks = []
- test
- tasks = []
- sources"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ main {
+ binaries {
+ main {
+ tasks()
+ }
+ test {
+ tasks()
+ }
+ }
+ sources()
+ }
+ test {
+ binaries {
+ main {
+ tasks()
+ }
+ test {
+ tasks()
+ }
+ }
+ sources()
+ }
+ }
+ }
}
def "can reference binaries container for a component in a rule"() {
diff --git a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomBinaryIntegrationTest.groovy b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomBinaryIntegrationTest.groovy
index ee435dc..8606221 100644
--- a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomBinaryIntegrationTest.groovy
+++ b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomBinaryIntegrationTest.groovy
@@ -218,7 +218,7 @@ model {
then:
failure.assertHasDescription "A problem occurred evaluating root project 'custom-binary'."
failure.assertHasCause "Failed to apply plugin [class 'MySamplePlugin']"
- failure.assertHasCause "MySamplePlugin\$Rules#register(org.gradle.platform.base.BinaryTypeBuilder<SampleBinary>, java.lang.String) is not a valid binary model rule method."
+ failure.assertHasCause "MySamplePlugin.Rules#register is not a valid binary model rule method."
failure.assertHasCause "Method annotated with @BinaryType must have a single parameter of type 'org.gradle.platform.base.BinaryTypeBuilder'."
}
@@ -244,8 +244,8 @@ model {
fails "tasks"
then:
failure.assertHasDescription "A problem occurred configuring root project 'custom-binary'."
- failure.assertHasCause "Exception thrown while executing model rule: MyOtherPlugin\$Rules1#register(org.gradle.platform.base.BinaryTypeBuilder<SampleBinary>)"
- failure.assertHasCause "Cannot register a factory for type SampleBinary because a factory for this type was already registered by MySamplePlugin\$Rules#register(org.gradle.platform.base.BinaryTypeBuilder<SampleBinary>)."
+ failure.assertHasCause "Exception thrown while executing model rule: MyOtherPlugin.Rules1#register"
+ failure.assertHasCause "Cannot register a factory for type SampleBinary because a factory for this type was already registered by MySamplePlugin.Rules#register."
}
def "additional binaries listed in components report"() {
diff --git a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentBinariesIntegrationTest.groovy b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentBinariesIntegrationTest.groovy
index 09e3082..587e5cf 100644
--- a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentBinariesIntegrationTest.groovy
+++ b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentBinariesIntegrationTest.groovy
@@ -134,8 +134,8 @@ Binaries
buildFile << withSimpleComponentBinaries()
buildFile << """
task checkSourceSets << {
- def sampleBinarySourceSet = project.binaries.sampleLibBinary.source.toList()[0]
- def othersSampleBinarySourceSet = project.binaries.sampleLibOtherBinary.source.toList()[0]
+ def sampleBinarySourceSet = project.binaries.sampleLibBinary.inputs.toList()[0]
+ def othersSampleBinarySourceSet = project.binaries.sampleLibOtherBinary.inputs.toList()[0]
assert sampleBinarySourceSet instanceof DefaultLibrarySourceSet
assert sampleBinarySourceSet.displayName == "DefaultLibrarySourceSet 'sampleLib:librarySource'"
assert othersSampleBinarySourceSet instanceof DefaultLibrarySourceSet
diff --git a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentPluginIntegrationTest.groovy b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentPluginIntegrationTest.groovy
index 19da53c..a133fad 100644
--- a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentPluginIntegrationTest.groovy
+++ b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentPluginIntegrationTest.groovy
@@ -300,7 +300,7 @@ BUILD SUCCESSFUL"""))
then:
failure.assertHasDescription "A problem occurred evaluating root project 'custom-component'."
failure.assertHasCause "Failed to apply plugin [class 'MySamplePlugin']"
- failure.assertHasCause "MySamplePlugin#register(org.gradle.platform.base.ComponentTypeBuilder<SampleComponent>, java.lang.String) is not a valid component model rule method."
+ failure.assertHasCause "MySamplePlugin#register is not a valid component model rule method."
failure.assertHasCause "Method annotated with @ComponentType must have a single parameter of type 'org.gradle.platform.base.ComponentTypeBuilder'."
}
@@ -325,8 +325,8 @@ BUILD SUCCESSFUL"""))
then:
failure.assertHasDescription "A problem occurred configuring root project 'custom-component'."
- failure.assertHasCause "Exception thrown while executing model rule: MyOtherPlugin#register(org.gradle.platform.base.ComponentTypeBuilder<SampleComponent>)"
- failure.assertHasCause "Cannot register a factory for type SampleComponent because a factory for this type was already registered by MySamplePlugin#register(org.gradle.platform.base.ComponentTypeBuilder<SampleComponent>)."
+ failure.assertHasCause "Exception thrown while executing model rule: MyOtherPlugin#register"
+ failure.assertHasCause "Cannot register a factory for type SampleComponent because a factory for this type was already registered by MySamplePlugin#register."
}
def buildWithCustomComponentPlugin() {
diff --git a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentSourceSetIntegrationTest.groovy b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentSourceSetIntegrationTest.groovy
new file mode 100644
index 0000000..7a08935
--- /dev/null
+++ b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/CustomComponentSourceSetIntegrationTest.groovy
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+
+class CustomComponentSourceSetIntegrationTest extends AbstractIntegrationSpec {
+
+ def "setup"() {
+ buildFile << """
+interface SampleBinary extends BinarySpec {}
+
+interface LibrarySourceSet extends LanguageSourceSet {}
+
+class DefaultLibrarySourceSet extends BaseLanguageSourceSet implements LibrarySourceSet { }
+
+class DefaultSampleBinary extends BaseBinarySpec implements SampleBinary {}
+
+interface SampleLibrary extends ComponentSpec {}
+
+class DefaultSampleLibrary extends BaseComponentSpec implements SampleLibrary {}
+
+ class MyBinaryDeclarationModel implements Plugin<Project> {
+ void apply(final Project project) {}
+
+ static class ComponentModel extends RuleSource {
+ @ComponentType
+ void register(ComponentTypeBuilder<SampleLibrary> builder) {
+ builder.defaultImplementation(DefaultSampleLibrary)
+ }
+
+ @BinaryType
+ void register(BinaryTypeBuilder<SampleBinary> builder) {
+ builder.defaultImplementation(DefaultSampleBinary)
+ }
+
+ @LanguageType
+ void registerSourceSet(LanguageTypeBuilder<LibrarySourceSet> builder) {
+ builder.setLanguageName("librarySource")
+ builder.defaultImplementation(DefaultLibrarySourceSet)
+ }
+ }
+ }
+
+ apply plugin:MyBinaryDeclarationModel
+"""
+ }
+
+ def "source order is retained"() {
+ buildFile << """
+class Dump extends RuleSource {
+
+ @Validate
+ void checkBinaries(BinaryContainer binaries) {
+ binaries.each { binary ->
+ println "Binary sources: \${binary.sources.values()}"
+ println "Binary inputs: \${binary.inputs}"
+ }
+ }
+}
+
+apply plugin: Dump
+
+model {
+ components {
+ sampleLib(SampleLibrary) {
+ sources {
+ compA(LibrarySourceSet) {
+ source.srcDir "src/main/comp-a"
+ }
+ compB(LibrarySourceSet) {
+ source.srcDir "src/main/comp-b"
+ }
+ }
+ binaries {
+ bin(SampleBinary) {
+ sources {
+ binaryA(LibrarySourceSet) {
+ source.srcDir "src/main/binary-a"
+ }
+ binaryB(LibrarySourceSet) {
+ source.srcDir "src/main/binary-b"
+ }
+ }
+ }
+ }
+ sources {
+ compC(LibrarySourceSet) {
+ source.srcDir "src/main/comp-c"
+ }
+ }
+ binaries {
+ bin {
+ sources {
+ binaryC(LibrarySourceSet) {
+ source.srcDir "src/main/binary-c"
+ }
+ }
+ }
+ }
+ }
+ }
+ components {
+ sampleLib {
+ sources {
+ compD(LibrarySourceSet) {
+ source.srcDir "src/main/comp-d"
+ }
+ }
+ binaries {
+ bin {
+ sources {
+ binaryD(LibrarySourceSet) {
+ source.srcDir "src/main/binary-d"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+"""
+ expect:
+ succeeds "components"
+ output.contains """Binary sources: [DefaultLibrarySourceSet 'sampleLib:binaryA', DefaultLibrarySourceSet 'sampleLib:binaryB', DefaultLibrarySourceSet 'sampleLib:binaryC', DefaultLibrarySourceSet 'sampleLib:binaryD']"""
+ output.contains """Binary inputs: [DefaultLibrarySourceSet 'sampleLib:compA', DefaultLibrarySourceSet 'sampleLib:compB', DefaultLibrarySourceSet 'sampleLib:compC', DefaultLibrarySourceSet 'sampleLib:compD', DefaultLibrarySourceSet 'sampleLib:binaryA', DefaultLibrarySourceSet 'sampleLib:binaryB', DefaultLibrarySourceSet 'sampleLib:binaryC', DefaultLibrarySourceSet 'sampleLib:binaryD']"""
+ }
+
+ def "fail when multiple source sets are registered with the same name"() {
+ buildFile << """
+model {
+ components {
+ sampleLib(SampleLibrary) {
+ binaries {
+ bin(SampleBinary) {
+ sources {
+ main(LibrarySourceSet) {
+ source.srcDir "src/main/lib"
+ }
+ main(LibrarySourceSet) {
+ source.srcDir "src/main/lib"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+"""
+ when:
+ def failure = fails("components")
+
+ then:
+ failure.assertHasCause "Entry with name already exists: main"
+ }
+}
diff --git a/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/VariantAspectExtractionIntegrationTest.groovy b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/VariantAspectExtractionIntegrationTest.groovy
new file mode 100644
index 0000000..85a28db
--- /dev/null
+++ b/subprojects/platform-base/src/integTest/groovy/org/gradle/language/base/VariantAspectExtractionIntegrationTest.groovy
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import spock.lang.Unroll
+
+class VariantAspectExtractionIntegrationTest extends AbstractIntegrationSpec {
+ def "variant annotation on property with illegal type type raises error"() {
+ buildFile << """
+ interface SampleBinary extends BinarySpec {
+ @Variant
+ Integer getVariantProp()
+ void setVariantProp(Integer variant)
+ }
+ class DefaultSampleBinary extends BaseBinarySpec implements SampleBinary {
+ Integer variantProp
+ }
+ class Rules extends RuleSource {
+ @BinaryType
+ void register(BinaryTypeBuilder<SampleBinary> builder) {
+ builder.defaultImplementation(DefaultSampleBinary)
+ }
+ }
+ apply plugin: Rules
+ """
+
+ expect:
+ fails "components"
+ failure.assertHasCause "Invalid managed model type SampleBinary: @Variant annotation only allowed for properties of type String and org.gradle.api.Named, but property has type java.lang.Integer (invalid property: variantProp)"
+ }
+
+ def "variant annotation on property with primitive type type raises error"() {
+ buildFile << """
+ interface SampleBinary extends BinarySpec {
+ @Variant
+ int getVariantProp()
+ void setVariantProp(int variant)
+ }
+ class DefaultSampleBinary extends BaseBinarySpec implements SampleBinary {
+ int variantProp
+ }
+ class Rules extends RuleSource {
+ @BinaryType
+ void register(BinaryTypeBuilder<SampleBinary> builder) {
+ builder.defaultImplementation(DefaultSampleBinary)
+ }
+ }
+ apply plugin: Rules
+ """
+
+ expect:
+ fails "components"
+ failure.assertHasCause "Invalid managed model type SampleBinary: @Variant annotation only allowed for properties of type String and org.gradle.api.Named, but property has type int (invalid property: variantProp)"
+ }
+
+ @Unroll
+ def "variant annotation on property with boolean type and #getterDesc getter raises error"() {
+ buildFile << """
+ interface SampleBinary extends BinarySpec {
+ $getter
+ void setVariantProp(boolean variant)
+ }
+ class DefaultSampleBinary extends BaseBinarySpec implements SampleBinary {
+ boolean variantProp
+ }
+ class Rules extends RuleSource {
+ @BinaryType
+ void register(BinaryTypeBuilder<SampleBinary> builder) {
+ builder.defaultImplementation(DefaultSampleBinary)
+ }
+ }
+ apply plugin: Rules
+ """
+
+ expect:
+ fails "components"
+ failure.assertHasCause "Invalid managed model type SampleBinary: @Variant annotation only allowed for properties of type String and org.gradle.api.Named, but property has type boolean (invalid property: variantProp)"
+
+ where:
+ getterDesc | getter
+ 'get' | '@Variant boolean getVariantProp()'
+ 'is' | '@Variant boolean isVariantProp()'
+ 'both (annotation on is)' | '@Variant boolean isVariantProp(); boolean getVariantProp()'
+ 'both (annotation on get)' | 'boolean isVariantProp(); @Variant boolean getVariantProp()'
+ 'both (annotation on both)' | '@Variant boolean isVariantProp(); @Variant boolean getVariantProp()'
+ }
+
+ def "variant annotation on setter raises error"() {
+ buildFile << """
+ interface SampleBinary extends BinarySpec {
+ String getVariantProp()
+ @Variant
+ void setVariantProp(String variant)
+ }
+ class DefaultSampleBinary extends BaseBinarySpec implements SampleBinary {
+ String variantProp
+ }
+ class Rules extends RuleSource {
+ @BinaryType
+ void register(BinaryTypeBuilder<SampleBinary> builder) {
+ builder.defaultImplementation(DefaultSampleBinary)
+ }
+ }
+ apply plugin: Rules
+ """
+
+ expect:
+ fails "components"
+ failure.assertHasCause "Invalid managed model type SampleBinary: @Variant annotation is only allowed on getter methods (invalid property: variantProp)"
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/AbstractLocalLibraryDependencyResolver.java b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/AbstractLocalLibraryDependencyResolver.java
new file mode 100644
index 0000000..e4069fe
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/AbstractLocalLibraryDependencyResolver.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.resolve;
+
+import com.google.common.base.Predicate;
+import org.gradle.api.UnknownProjectException;
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
+import org.gradle.api.artifacts.component.LibraryComponentSelector;
+import org.gradle.api.internal.component.ArtifactType;
+import org.gradle.api.internal.tasks.DefaultTaskDependency;
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.local.model.LocalComponentMetaData;
+import org.gradle.internal.component.local.model.PublishArtifactLocalArtifactMetaData;
+import org.gradle.internal.component.model.*;
+import org.gradle.internal.resolve.ArtifactResolveException;
+import org.gradle.internal.resolve.ModuleVersionResolveException;
+import org.gradle.internal.resolve.resolver.ArtifactResolver;
+import org.gradle.internal.resolve.resolver.ComponentMetaDataResolver;
+import org.gradle.internal.resolve.resolver.DependencyToComponentIdResolver;
+import org.gradle.internal.resolve.result.BuildableArtifactResolveResult;
+import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
+import org.gradle.internal.resolve.result.BuildableComponentIdResolveResult;
+import org.gradle.internal.resolve.result.BuildableComponentResolveResult;
+import org.gradle.language.base.internal.model.VariantDimensionSelectorFactory;
+import org.gradle.language.base.internal.model.VariantsMetaData;
+import org.gradle.language.base.internal.resolve.LibraryResolveException;
+import org.gradle.model.ModelMap;
+import org.gradle.model.internal.core.ModelPath;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.registry.ModelRegistry;
+import org.gradle.model.internal.type.ModelType;
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.ComponentSpecContainer;
+import org.gradle.platform.base.LibrarySpec;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public abstract class AbstractLocalLibraryDependencyResolver<T extends BinarySpec> implements DependencyToComponentIdResolver, ComponentMetaDataResolver, ArtifactResolver {
+ private final ProjectModelResolver projectModelResolver;
+ private final VariantsMetaData variantsMetaData;
+ private final VariantsMatcher matcher;
+ private final LibraryResolutionErrorMessageBuilder errorMessageBuilder;
+ private final Class<? extends BinarySpec> binaryType;
+ private final Predicate<LibrarySpec> binarySpecPredicate;
+
+ public AbstractLocalLibraryDependencyResolver(
+ Class<T> binarySpecType,
+ ProjectModelResolver projectModelResolver,
+ List<VariantDimensionSelectorFactory> selectorFactories,
+ VariantsMetaData variantsMetaData,
+ LibraryResolutionErrorMessageBuilder errorMessageBuilder, ModelSchemaStore schemaStore) {
+ this.projectModelResolver = projectModelResolver;
+ this.matcher = new VariantsMatcher(selectorFactories, binarySpecType, schemaStore);
+ this.errorMessageBuilder = errorMessageBuilder;
+ this.variantsMetaData = variantsMetaData;
+ this.binaryType = binarySpecType;
+ this.binarySpecPredicate = new Predicate<LibrarySpec>() {
+ @Override
+ public boolean apply(LibrarySpec input) {
+ return !input.getBinaries().withType(binaryType).isEmpty();
+ }
+ };
+ }
+
+ @Override
+ public void resolve(DependencyMetaData dependency, final BuildableComponentIdResolveResult result) {
+ if (dependency.getSelector() instanceof LibraryComponentSelector) {
+ LibraryComponentSelector selector = (LibraryComponentSelector) dependency.getSelector();
+ final String selectorProjectPath = selector.getProjectPath();
+ final String libraryName = selector.getLibraryName();
+ LibraryResolutionErrorMessageBuilder.LibraryResolutionResult resolutionResult = doResolve(selectorProjectPath, libraryName);
+ LibrarySpec selectedLibrary = resolutionResult.getSelectedLibrary();
+ if (selectedLibrary != null) {
+ Collection<BinarySpec> allBinaries = selectedLibrary.getBinaries().values();
+ Collection<? extends BinarySpec> compatibleBinaries = matcher.filterBinaries(variantsMetaData, allBinaries);
+ if (!allBinaries.isEmpty() && compatibleBinaries.isEmpty()) {
+ // no compatible variant found
+ result.failed(new ModuleVersionResolveException(selector, errorMessageBuilder.noCompatibleBinaryErrorMessage(libraryName, allBinaries)));
+ } else if (compatibleBinaries.size() > 1) {
+ result.failed(new ModuleVersionResolveException(selector, errorMessageBuilder.multipleBinariesForSameVariantErrorMessage(libraryName, compatibleBinaries)));
+ } else {
+ BinarySpec selectedBinary = compatibleBinaries.iterator().next();
+ DefaultTaskDependency buildDependencies = new DefaultTaskDependency();
+ buildDependencies.add(selectedBinary);
+ LocalComponentMetaData metaData = createLocalComponentMetaData(selectedBinary, buildDependencies);
+ result.resolved(metaData);
+ }
+ }
+ if (!result.hasResult()) {
+ String message = resolutionResult.toResolutionErrorMessage(binaryType, selector);
+ ModuleVersionResolveException failure = new ModuleVersionResolveException(selector, new LibraryResolveException(message));
+ result.failed(failure);
+ }
+ }
+ }
+
+ private LibraryResolutionErrorMessageBuilder.LibraryResolutionResult doResolve(String projectPath,
+ String libraryName) {
+ try {
+ ModelRegistry projectModel = projectModelResolver.resolveProjectModel(projectPath);
+ ComponentSpecContainer components = projectModel.find(
+ ModelPath.path("components"),
+ ModelType.of(ComponentSpecContainer.class));
+ if (components != null) {
+ ModelMap<? extends LibrarySpec> libraries = components.withType(LibrarySpec.class);
+ return LibraryResolutionErrorMessageBuilder.LibraryResolutionResult.of(libraries.values(), libraryName, binarySpecPredicate);
+ } else {
+ return LibraryResolutionErrorMessageBuilder.LibraryResolutionResult.emptyResolutionResult();
+ }
+ } catch (UnknownProjectException e) {
+ return LibraryResolutionErrorMessageBuilder.LibraryResolutionResult.projectNotFound();
+ }
+ }
+
+ @Override
+ public void resolve(ComponentIdentifier identifier, ComponentOverrideMetadata componentOverrideMetadata, BuildableComponentResolveResult result) {
+ if (isLibrary(identifier)) {
+ throw new RuntimeException("Not yet implemented");
+ }
+ }
+
+ private boolean isLibrary(ComponentIdentifier identifier) {
+ return identifier instanceof LibraryBinaryIdentifier;
+ }
+
+ @Override
+ public void resolveModuleArtifacts(ComponentResolveMetaData component, ComponentUsage usage, BuildableArtifactSetResolveResult result) {
+ ComponentIdentifier componentId = component.getComponentId();
+ if (isLibrary(componentId)) {
+ ConfigurationMetaData configuration = component.getConfiguration(usage.getConfigurationName());
+ if (configuration != null) {
+ Set<ComponentArtifactMetaData> artifacts = configuration.getArtifacts();
+ result.resolved(artifacts);
+ }
+ if (!result.hasResult()) {
+ result.failed(new ArtifactResolveException(String.format("Unable to resolve artifact for %s", componentId)));
+ }
+ }
+ }
+
+ @Override
+ public void resolveModuleArtifacts(ComponentResolveMetaData component, ArtifactType artifactType, BuildableArtifactSetResolveResult result) {
+ if (isLibrary(component.getComponentId())) {
+ result.resolved(Collections.<ComponentArtifactMetaData>emptyList());
+ }
+ }
+
+ @Override
+ public void resolveArtifact(ComponentArtifactMetaData artifact, ModuleSource moduleSource, BuildableArtifactResolveResult result) {
+ if (isLibrary(artifact.getComponentId())) {
+ if (artifact instanceof PublishArtifactLocalArtifactMetaData) {
+ result.resolved(((PublishArtifactLocalArtifactMetaData) artifact).getFile());
+ } else {
+ result.failed(new ArtifactResolveException("Unsupported artifact metadata type: " + artifact));
+ }
+ }
+ }
+
+ protected abstract LocalComponentMetaData createLocalComponentMetaData(BinarySpec selectedBinary, TaskDependency buildDependencies);
+
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/DefaultProjectModelResolver.java b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/DefaultProjectModelResolver.java
new file mode 100644
index 0000000..07d0af2
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/DefaultProjectModelResolver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.resolve;
+
+import org.gradle.api.UnknownProjectException;
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.project.ProjectRegistry;
+import org.gradle.model.internal.registry.ModelRegistry;
+
+public class DefaultProjectModelResolver implements ProjectModelResolver {
+ private final ProjectRegistry<ProjectInternal> delegate;
+
+ public DefaultProjectModelResolver(ProjectRegistry<ProjectInternal> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public ModelRegistry resolveProjectModel(String path) {
+ ProjectInternal projectInternal = delegate.getProject(path);
+ if (projectInternal == null) {
+ throw new UnknownProjectException("Project with path '" + path + "' not found.");
+ }
+
+ // TODO This is a brain-dead way to ensure that the reference project's model is ready to access
+ projectInternal.evaluate();
+ projectInternal.getTasks().discoverTasks();
+ return projectInternal.getModelRegistry();
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/LibraryResolutionErrorMessageBuilder.java b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/LibraryResolutionErrorMessageBuilder.java
new file mode 100644
index 0000000..056dda3
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/LibraryResolutionErrorMessageBuilder.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.resolve;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
+import org.gradle.api.artifacts.component.LibraryComponentSelector;
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.LibrarySpec;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public interface LibraryResolutionErrorMessageBuilder {
+ String multipleBinariesForSameVariantErrorMessage(String libraryName, Collection<? extends BinarySpec> binaries);
+
+ String noCompatibleBinaryErrorMessage(String libraryName, Collection<BinarySpec> allBinaries);
+
+ /**
+ * Intermediate data structure used to store the result of a resolution and help at building an understandable error message in case resolution fails.
+ */
+ class LibraryResolutionResult {
+ private static final LibraryResolutionResult EMPTY = new LibraryResolutionResult();
+ private static final LibraryResolutionResult PROJECT_NOT_FOUND = new LibraryResolutionResult();
+ private final Map<String, LibrarySpec> libsMatchingRequirements;
+ private final Map<String, LibrarySpec> libsNotMatchingRequirements;
+
+ private LibrarySpec selectedLibrary;
+ private LibrarySpec nonMatchingLibrary;
+
+ private LibraryResolutionResult() {
+ this.libsMatchingRequirements = Maps.newHashMap();
+ this.libsNotMatchingRequirements = Maps.newHashMap();
+ }
+
+ private LibrarySpec getSingleMatchingLibrary() {
+ if (libsMatchingRequirements.size() == 1) {
+ return libsMatchingRequirements.values().iterator().next();
+ }
+ return null;
+ }
+
+ private void resolve(String libraryName) {
+ if (libraryName == null) {
+ LibrarySpec singleMatchingLibrary = getSingleMatchingLibrary();
+ if (singleMatchingLibrary == null) {
+ return;
+ }
+ libraryName = singleMatchingLibrary.getName();
+ }
+
+ selectedLibrary = libsMatchingRequirements.get(libraryName);
+ nonMatchingLibrary = libsNotMatchingRequirements.get(libraryName);
+ }
+
+ public boolean isProjectNotFound() {
+ return PROJECT_NOT_FOUND == this;
+ }
+
+ public boolean hasLibraries() {
+ return !libsMatchingRequirements.isEmpty() || !libsNotMatchingRequirements.isEmpty();
+ }
+
+ public LibrarySpec getSelectedLibrary() {
+ return selectedLibrary;
+ }
+
+ public LibrarySpec getNonMatchingLibrary() {
+ return nonMatchingLibrary;
+ }
+
+ public List<String> getCandidateLibraries() {
+ return Lists.newArrayList(libsMatchingRequirements.keySet());
+ }
+
+ public String toResolutionErrorMessage(
+ Class<? extends BinarySpec> binaryType,
+ LibraryComponentSelector selector) {
+ List<String> candidateLibraries = formatLibraryNames(getCandidateLibraries());
+ String projectPath = selector.getProjectPath();
+ String libraryName = selector.getLibraryName();
+
+ StringBuilder sb = new StringBuilder("Project '").append(projectPath).append("'");
+ if (libraryName == null || !hasLibraries()) {
+ if (isProjectNotFound()) {
+ sb.append(" not found.");
+ } else if (!hasLibraries()) {
+ sb.append(" doesn't define any library.");
+ } else {
+ sb.append(" contains more than one library. Please select one of ");
+ Joiner.on(", ").appendTo(sb, candidateLibraries);
+ }
+ } else {
+ LibrarySpec notMatchingRequirements = getNonMatchingLibrary();
+ if (notMatchingRequirements != null) {
+ sb.append(" contains a library named '").append(libraryName)
+ .append("' but it doesn't have any binary of type ")
+ .append(binaryType.getSimpleName());
+ } else {
+ sb.append(" does not contain library '").append(libraryName).append("'. Did you want to use ");
+ if (candidateLibraries.size() == 1) {
+ sb.append(candidateLibraries.get(0));
+ } else {
+ sb.append("one of ");
+ Joiner.on(", ").appendTo(sb, candidateLibraries);
+ }
+ sb.append("?");
+ }
+ }
+ return sb.toString();
+ }
+
+ public static LibraryResolutionResult of(Collection<? extends LibrarySpec> libraries, String libraryName, Predicate<? super LibrarySpec> libraryFilter) {
+ LibraryResolutionResult result = new LibraryResolutionResult();
+ for (LibrarySpec librarySpec : libraries) {
+ if (libraryFilter.apply(librarySpec)) {
+ result.libsMatchingRequirements.put(librarySpec.getName(), librarySpec);
+ } else {
+ result.libsNotMatchingRequirements.put(librarySpec.getName(), librarySpec);
+ }
+ }
+ result.resolve(libraryName);
+ return result;
+ }
+
+ public static LibraryResolutionResult projectNotFound() {
+ return LibraryResolutionResult.PROJECT_NOT_FOUND;
+ }
+
+ public static LibraryResolutionResult emptyResolutionResult() {
+ return LibraryResolutionResult.EMPTY;
+ }
+
+ private static List<String> formatLibraryNames(List<String> libs) {
+ List<String> list = Lists.transform(libs, new Function<String, String>() {
+ @Override
+ public String apply(String input) {
+ return String.format("'%s'", input);
+ }
+ });
+ return Ordering.natural().sortedCopy(list);
+ }
+ }
+
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/ProjectModelResolver.java b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/ProjectModelResolver.java
new file mode 100644
index 0000000..7b14703
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/ProjectModelResolver.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.resolve;
+
+import org.gradle.api.UnknownProjectException;
+import org.gradle.model.internal.registry.ModelRegistry;
+
+/**
+ * Locates another project within the multi-project build, and provides access to it's model registry in a usable state.
+ */
+public interface ProjectModelResolver {
+ ModelRegistry resolveProjectModel(String path) throws UnknownProjectException;
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/VariantsMatcher.java b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/VariantsMatcher.java
new file mode 100644
index 0000000..73a2ba2
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/api/internal/resolve/VariantsMatcher.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.resolve;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.common.collect.TreeMultimap;
+import org.gradle.api.Named;
+import org.gradle.internal.Cast;
+import org.gradle.language.base.internal.model.*;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.platform.base.BinarySpec;
+
+import java.util.*;
+
+public class VariantsMatcher {
+ private static final Comparator<VariantValue> SPEC_COMPARATOR = new Comparator<VariantValue>() {
+ @Override
+ public int compare(VariantValue o1, VariantValue o2) {
+ return o1.spec.getDisplayName().compareTo(o2.spec.getDisplayName());
+ }
+ };
+
+ private final List<VariantDimensionSelectorFactory> factories;
+ private final Class<? extends BinarySpec> binarySpecType;
+ private final ModelSchemaStore schemaStore;
+
+ public VariantsMatcher(List<VariantDimensionSelectorFactory> factories, Class<? extends BinarySpec> binarySpecType, ModelSchemaStore schemaStore) {
+ this.factories = factories;
+ this.binarySpecType = binarySpecType;
+ this.schemaStore = schemaStore;
+ }
+
+ private VariantDimensionSelector<Object> createSelector(Object o) {
+ for (VariantDimensionSelectorFactory factory : factories) {
+ @SuppressWarnings("unchecked")
+ VariantDimensionSelector<Object> selector = factory.getVariantDimensionSelector(o);
+ if (selector != null) {
+ return selector;
+ }
+ }
+ return new DefaultVariantDimensionSelector();
+ }
+
+ public Collection<? extends BinarySpec> filterBinaries(VariantsMetaData variantsMetaData, Collection<BinarySpec> binaries) {
+ if (binaries.isEmpty()) {
+ return binaries;
+ }
+ Set<String> resolveDimensions = variantsMetaData.getNonNullDimensions();
+ TreeMultimap<String, VariantValue> selectedVariants = TreeMultimap.create(String.CASE_INSENSITIVE_ORDER, SPEC_COMPARATOR);
+ Set<BinarySpec> removedSpecs = Sets.newHashSet();
+ for (BinarySpec binarySpec : binaries) {
+ if (binarySpecType.isAssignableFrom(binarySpec.getClass())) {
+ VariantsMetaData binaryVariants = DefaultVariantsMetaData.extractFrom(binarySpec, schemaStore);
+ Set<String> commonsDimensions = Sets.intersection(resolveDimensions, binaryVariants.getNonNullDimensions());
+ Set<String> incompatibleDimensionTypes = VariantsMetaDataHelper.incompatibleDimensionTypes(variantsMetaData, binaryVariants, commonsDimensions);
+ if (incompatibleDimensionTypes.isEmpty()) {
+ for (String dimension : commonsDimensions) {
+ Class<?> dimensionType = variantsMetaData.getDimensionType(dimension).getConcreteClass();
+ boolean isStringType = String.class == dimensionType;
+ Object requestedValue = isStringType ? variantsMetaData.getValueAsString(dimension) : variantsMetaData.getValueAsType(Cast.<Class<? extends Named>>uncheckedCast(dimensionType), dimension);
+ Object binaryValue = isStringType ? binaryVariants.getValueAsString(dimension) : binaryVariants.getValueAsType(Cast.<Class<? extends Named>>uncheckedCast(dimensionType), dimension);
+ VariantDimensionSelector<Object> selector = createSelector(requestedValue);
+ if (selector.isCompatibleWithRequirement(requestedValue, binaryValue)) {
+ VariantValue value = new VariantValue(binaryValue, binarySpec);
+ SortedSet<VariantValue> variantValues = selectedVariants.get(dimension);
+ for (VariantValue variantValue : variantValues) {
+ // all the values are equal, but we store all the binaries that match that value
+ // and incrementally build a list of binaries which are excluded because of a better match
+ if (selector.betterFit(requestedValue, variantValue.value, binaryValue)) {
+ // the new value is a better fit than the old one
+ removedSpecs.add(variantValue.spec);
+ } else if (selector.betterFit(requestedValue, binaryValue, variantValue.value)) {
+ // the old value is a better fit than the new one, let's ignore the new one altogether
+ removedSpecs.add(value.spec);
+ }
+ }
+ selectedVariants.put(dimension, value);
+ } else {
+ removedSpecs.add(binarySpec);
+ }
+ }
+ }
+ }
+ }
+
+ Set<BinarySpec> union = null;
+ for (String dimension : selectedVariants.keySet()) {
+ Set<BinarySpec> variantValues = ImmutableSet.copyOf(Iterables.transform(selectedVariants.get(dimension), VariantValue.SPEC_FUNCTION));
+ union = union == null ? variantValues : Sets.union(union, variantValues);
+ }
+ return union == null ? Collections.<BinarySpec>emptySet() : Sets.difference(union, removedSpecs);
+ }
+
+ private static class VariantValue {
+ public static final Function<VariantValue, BinarySpec> SPEC_FUNCTION = new Function<VariantValue, BinarySpec>() {
+ @Override
+ public BinarySpec apply(VariantValue input) {
+ return input.spec;
+ }
+ };
+
+ final Object value;
+ final BinarySpec spec;
+
+ private VariantValue(Object value, BinarySpec spec) {
+ this.value = value;
+ this.spec = spec;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("VariantValue{");
+ sb.append("spec=").append(spec);
+ sb.append(", value=").append(value);
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/FunctionalSourceSet.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/FunctionalSourceSet.java
index e72d133..9a2f92e 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/FunctionalSourceSet.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/FunctionalSourceSet.java
@@ -24,7 +24,5 @@ import org.gradle.api.internal.ExtensiblePolymorphicDomainObjectContainerInterna
* (production code, test code, etc.).
*/
@Incubating
-// TODO:DAZ Make this internal
public interface FunctionalSourceSet extends ExtensiblePolymorphicDomainObjectContainerInternal<LanguageSourceSet>, Named {
- FunctionalSourceSet copy(String name);
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DefaultFunctionalSourceSet.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DefaultFunctionalSourceSet.java
index d99d3a2..26847e6 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DefaultFunctionalSourceSet.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DefaultFunctionalSourceSet.java
@@ -24,12 +24,10 @@ import org.gradle.language.base.ProjectSourceSet;
public class DefaultFunctionalSourceSet extends AddOnlyRuleAwarePolymorphicDomainObjectContainer<LanguageSourceSet> implements FunctionalSourceSet {
private final String name;
- private final ProjectSourceSet projectSourceSet;
public DefaultFunctionalSourceSet(String name, Instantiator instantiator, final ProjectSourceSet projectSourceSet) {
super(LanguageSourceSet.class, instantiator);
this.name = name;
- this.projectSourceSet = projectSourceSet;
whenObjectAdded(new Action<LanguageSourceSet>() {
public void execute(LanguageSourceSet languageSourceSet) {
projectSourceSet.add(languageSourceSet);
@@ -45,13 +43,4 @@ public class DefaultFunctionalSourceSet extends AddOnlyRuleAwarePolymorphicDomai
public String getName() {
return name;
}
-
- // TODO:DAZ This needs unit testing
- // TODO:DAZ Perhaps we should pull out a LanguageSourceSet 'factory-for-type' so we only register the languages once
- public FunctionalSourceSet copy(String name) {
- DefaultFunctionalSourceSet copy = getInstantiator().newInstance(DefaultFunctionalSourceSet.class, name, getInstantiator(), projectSourceSet);
- copy.namedEntityInstantiator.copyFactoriesFrom(namedEntityInstantiator);
- copy.addAll(this);
- return copy;
- }
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DependentSourceSetInternal.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DependentSourceSetInternal.java
index 8c75c9b..169485a 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DependentSourceSetInternal.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/DependentSourceSetInternal.java
@@ -18,7 +18,7 @@ package org.gradle.language.base.internal;
import org.gradle.api.Action;
import org.gradle.platform.base.DependencySpecContainer;
-public interface DependentSourceSetInternal {
+public interface DependentSourceSetInternal extends LanguageSourceSetInternal {
DependencySpecContainer getDependencies();
DependencySpecContainer dependencies(Action<? super DependencySpecContainer> configureAction);
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/LanguageSourceSetContainer.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/LanguageSourceSetContainer.java
deleted file mode 100644
index b5fdc3c..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/LanguageSourceSetContainer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.language.base.internal;
-
-import org.gradle.api.DomainObjectSet;
-import org.gradle.api.internal.CompositeDomainObjectSet;
-import org.gradle.api.internal.DefaultDomainObjectSet;
-import org.gradle.internal.typeconversion.NotationParser;
-import org.gradle.language.base.FunctionalSourceSet;
-import org.gradle.language.base.LanguageSourceSet;
-
-import java.util.Set;
-
-public class LanguageSourceSetContainer {
- private final NotationParser<Object, Set<LanguageSourceSet>> sourcesNotationParser = SourceSetNotationParser.parser();
- private FunctionalSourceSet mainSources;
- private DefaultDomainObjectSet<LanguageSourceSet> additionalSources = new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet.class);
-
- public void setMainSources(FunctionalSourceSet mainSources) {
- this.mainSources = mainSources;
- }
-
- public void source(Object sources) {
- additionalSources.addAll(sourcesNotationParser.parseNotation(sources));
- }
-
- public FunctionalSourceSet getMainSources() {
- return mainSources;
- }
-
- public DomainObjectSet<LanguageSourceSet> getSources() {
- @SuppressWarnings("unchecked")
- DomainObjectSet<LanguageSourceSet> sources = CompositeDomainObjectSet.create(LanguageSourceSet.class, mainSources, additionalSources);
- return sources;
- }
-}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/SourceSetNotationParser.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/SourceSetNotationParser.java
deleted file mode 100644
index f96d928..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/SourceSetNotationParser.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.language.base.internal;
-
-import org.gradle.internal.typeconversion.*;
-import org.gradle.language.base.FunctionalSourceSet;
-import org.gradle.language.base.LanguageSourceSet;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-public class SourceSetNotationParser {
- public static NotationParser<Object, Set<LanguageSourceSet>> parser() {
- return NotationParserBuilder
- .toType(new TypeInfo<Set<LanguageSourceSet>>(Set.class))
- .converter(new FunctionalSourceSetConverter())
- .converter(new SingleLanguageSourceSetConverter())
- .converter(new LanguageSourceSetCollectionConverter())
- .toComposite();
- }
-
- private static class FunctionalSourceSetConverter extends TypedNotationConverter<FunctionalSourceSet, Set<LanguageSourceSet>> {
- private FunctionalSourceSetConverter() {
- super(FunctionalSourceSet.class);
- }
-
- @Override
- protected Set<LanguageSourceSet> parseType(FunctionalSourceSet notation) {
- return notation;
- }
- }
-
- private static class SingleLanguageSourceSetConverter extends TypedNotationConverter<LanguageSourceSet, Set<LanguageSourceSet>> {
- private SingleLanguageSourceSetConverter() {
- super(LanguageSourceSet.class);
- }
-
- @Override
- protected Set<LanguageSourceSet> parseType(LanguageSourceSet notation) {
- return Collections.singleton(notation);
- }
- }
-
- private static class LanguageSourceSetCollectionConverter extends TypedNotationConverter<Collection<LanguageSourceSet>, Set<LanguageSourceSet>> {
- private LanguageSourceSetCollectionConverter() {
- super(new TypeInfo<Collection<LanguageSourceSet>>(Collection.class));
- }
-
- @Override
- protected Set<LanguageSourceSet> parseType(Collection<LanguageSourceSet> notation) {
- return new LinkedHashSet<LanguageSourceSet>(notation);
- }
- }
-}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/SourceTransformTaskConfig.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/SourceTransformTaskConfig.java
index b7999b3..91bcf9b 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/SourceTransformTaskConfig.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/SourceTransformTaskConfig.java
@@ -18,11 +18,13 @@ package org.gradle.language.base.internal;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
+import org.gradle.internal.service.ServiceRegistry;
import org.gradle.language.base.LanguageSourceSet;
import org.gradle.platform.base.BinarySpec;
public interface SourceTransformTaskConfig {
String getTaskPrefix();
Class<? extends DefaultTask> getTaskType();
- void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet);
+ // TODO:DAZ This should create a RuleSource instance to configure the task, rather than being imperative
+ void configureTask(Task task, BinarySpec binary, LanguageSourceSet sourceSet, ServiceRegistry serviceRegistry);
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/ComponentBinaryRules.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/ComponentBinaryRules.java
new file mode 100644
index 0000000..8768609
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/ComponentBinaryRules.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model;
+
+import org.gradle.api.Action;
+import org.gradle.api.NamedDomainObjectFactory;
+import org.gradle.language.base.LanguageSourceSet;
+import org.gradle.language.base.internal.registry.LanguageRegistration;
+import org.gradle.language.base.internal.registry.LanguageRegistry;
+import org.gradle.model.Defaults;
+import org.gradle.model.RuleSource;
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.ComponentSpec;
+import org.gradle.platform.base.internal.BinarySpecInternal;
+
+/**
+ * Initializes binaries as they are added to components.
+ *
+ * Note: It's applied to components instead of binaries straight, because binaries are accessible
+ * via multiple paths, and thus rules are applied to them multiple times.
+ */
+ at SuppressWarnings("unused")
+public class ComponentBinaryRules extends RuleSource {
+
+ @Defaults
+ void initializeBinarySourceSets(final ComponentSpec component, final LanguageRegistry languageRegistry) {
+ component.getBinaries().beforeEach(new Action<BinarySpec>() {
+ @Override
+ public void execute(BinarySpec binary) {
+ for (LanguageRegistration<?> languageRegistration : languageRegistry) {
+ // TODO - allow view as internal type and remove the cast
+ registerLanguageSourceSets((BinarySpecInternal) binary, component.getName(), languageRegistration);
+ }
+ addComponentSourceSetsToBinaryInputs(binary, component);
+ }
+
+ private <U extends LanguageSourceSet> void registerLanguageSourceSets(BinarySpecInternal binary, String componentName, LanguageRegistration<U> languageRegistration) {
+ NamedDomainObjectFactory<? extends U> sourceSetFactory = languageRegistration.getSourceSetFactory(componentName);
+ binary.getEntityInstantiator().registerFactory(languageRegistration.getSourceSetType(), sourceSetFactory);
+ }
+
+ private void addComponentSourceSetsToBinaryInputs(BinarySpec binary, ComponentSpec component) {
+ binary.getInputs().addAll(component.getSources().values());
+ }
+ });
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/ComponentRules.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/ComponentRules.java
index 9951efa..91cec1e 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/ComponentRules.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/ComponentRules.java
@@ -45,10 +45,10 @@ public class ComponentRules extends RuleSource {
@Defaults
void applyDefaultSourceConventions(final ComponentSpec component) {
- component.getSource().afterEach(new AddDefaultSourceLocation(component.getName()));
+ component.getSources().afterEach(new AddDefaultSourceLocation(component.getName()));
}
- // TODO:DAZ Needs to be a separate action since can't have parameterized utility methods in a RuleSource
+ // Currently needs to be a separate action since can't have parameterized utility methods in a RuleSource
private static class ComponentSourcesRegistrationAction<U extends LanguageSourceSet> implements Action<ComponentSpecInternal> {
private final LanguageRegistration<U> languageRegistration;
private final LanguageTransformContainer languageTransforms;
@@ -68,18 +68,17 @@ public class ComponentRules extends RuleSource {
}
void registerLanguageSourceSetFactory(final ComponentSpecInternal component) {
- final FunctionalSourceSet functionalSourceSet = component.getSources();
+ final FunctionalSourceSet functionalSourceSet = component.getFunctionalSourceSet();
NamedDomainObjectFactory<? extends U> sourceSetFactory = languageRegistration.getSourceSetFactory(functionalSourceSet.getName());
functionalSourceSet.registerFactory(languageRegistration.getSourceSetType(), sourceSetFactory);
}
// If there is a transform for the language into one of the component inputs, add a default source set
void createDefaultSourceSetForComponents(final ComponentSpecInternal component) {
- final FunctionalSourceSet functionalSourceSet = component.getSources();
for (LanguageTransform<?, ?> languageTransform : languageTransforms) {
if (languageTransform.getSourceSetType().equals(languageRegistration.getSourceSetType())
&& component.getInputTypes().contains(languageTransform.getOutputType())) {
- functionalSourceSet.maybeCreate(languageRegistration.getName(), languageRegistration.getSourceSetType());
+ component.getSources().create(languageRegistration.getName(), languageRegistration.getSourceSetType());
return;
}
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultLibraryLocalComponentMetaData.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultLibraryLocalComponentMetaData.java
new file mode 100644
index 0000000..3c61808
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultLibraryLocalComponentMetaData.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.component.ComponentIdentifier;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
+import org.gradle.api.internal.artifacts.DefaultModuleVersionIdentifier;
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier;
+import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData;
+
+import java.util.Collections;
+
+public class DefaultLibraryLocalComponentMetaData extends DefaultLocalComponentMetaData {
+ private final static String VERSION = "<local component>";
+
+ private DefaultLibraryLocalComponentMetaData(ModuleVersionIdentifier id, ComponentIdentifier componentIdentifier) {
+ super(id, componentIdentifier, Project.DEFAULT_STATUS);
+ }
+
+ public static DefaultLibraryLocalComponentMetaData newMetaData(LibraryBinaryIdentifier componentId, TaskDependency buildDependencies) {
+ ModuleVersionIdentifier id = new DefaultModuleVersionIdentifier(
+ componentId.getProjectPath(), componentId.getLibraryName(), VERSION
+ );
+ DefaultLibraryLocalComponentMetaData metaData = new DefaultLibraryLocalComponentMetaData(id, componentId);
+ metaData.addConfiguration(
+ DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME,
+ String.format("Request metadata: %s", componentId.getDisplayName()),
+ Collections.<String>emptySet(),
+ Collections.singleton(DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME),
+ true,
+ true,
+ buildDependencies);
+ return metaData;
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantDimensionSelector.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantDimensionSelector.java
new file mode 100644
index 0000000..e7c9a1f
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantDimensionSelector.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+import org.gradle.api.Named;
+
+public class DefaultVariantDimensionSelector implements VariantDimensionSelector<Object> {
+ @Override
+ public boolean isCompatibleWithRequirement(Object requirement, Object value) {
+ if (requirement instanceof String) {
+ return requirement.equals(value);
+ } else if (requirement instanceof Named) {
+ return ((Named) requirement).getName().equals(((Named) value).getName());
+ }
+ return false;
+ }
+
+ @Override
+ public boolean betterFit(Object requirement, Object oldValue, Object newValue) {
+ return false;
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantDimensionSelectorFactory.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantDimensionSelectorFactory.java
new file mode 100644
index 0000000..9ccce08
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantDimensionSelectorFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+import org.gradle.internal.Cast;
+
+public class DefaultVariantDimensionSelectorFactory implements VariantDimensionSelectorFactory {
+ private final Class<?> predicate;
+ private final VariantDimensionSelector<?> selector;
+
+ public static <T> DefaultVariantDimensionSelectorFactory of(Class<T> clazz, VariantDimensionSelector<T> selector) {
+ return new DefaultVariantDimensionSelectorFactory(clazz, selector);
+ }
+
+ private DefaultVariantDimensionSelectorFactory(Class<?> clazz, VariantDimensionSelector<?> selector) {
+ this.predicate = clazz;
+ this.selector = selector;
+ }
+
+
+ @Override
+ public <T> VariantDimensionSelector<T> getVariantDimensionSelector(T o) {
+ if (o!=null && predicate.isAssignableFrom(o.getClass())) {
+ return Cast.uncheckedCast(selector);
+ }
+ return null;
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantsMetaData.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantsMetaData.java
new file mode 100644
index 0000000..dc49719
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/DefaultVariantsMetaData.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import org.gradle.api.Named;
+import org.gradle.api.internal.plugins.DslObject;
+import org.gradle.model.internal.manage.schema.*;
+import org.gradle.model.internal.type.ModelType;
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.internal.VariantAspect;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+public class DefaultVariantsMetaData implements VariantsMetaData {
+ private final Map<String, Object> variants;
+ private final Set<String> allVariantDimensions;
+ private final Set<String> nonNullVariantDimensions;
+ private final Map<String, ModelType<?>> variantDimensionTypes;
+
+ private DefaultVariantsMetaData(Map<String, Object> variants, Map<String, ModelType<?>> variantDimensionTypes) {
+ this.variants = variants;
+ this.allVariantDimensions = variants.keySet();
+ this.nonNullVariantDimensions = ImmutableSet.copyOf(Maps.filterEntries(variants, new Predicate<Map.Entry<String, Object>>() {
+ @Override
+ public boolean apply(Map.Entry<String, Object> input) {
+ return input.getValue()!=null;
+ }
+ }).keySet());
+ this.variantDimensionTypes = variantDimensionTypes;
+ }
+
+ public static VariantsMetaData extractFrom(BinarySpec spec, ModelSchemaStore schemaStore) {
+ Map<String, Object> variants = Maps.newLinkedHashMap();
+ ImmutableMap.Builder<String, ModelType<?>> dimensionTypesBuilder = ImmutableMap.builder();
+ Class<?> specType = new DslObject(spec).getDeclaredType();
+ ModelSchema<?> schema = schemaStore.getSchema(specType);
+ if (schema instanceof ModelStructSchema) {
+ VariantAspect variantAspect = ((ModelStructSchema<?>) schema).getAspect(VariantAspect.class);
+ if (variantAspect != null) {
+ for (ModelProperty<?> property : variantAspect.getDimensions()) {
+ // note: it's not the role of this class to validate that the annotation is properly used, that
+ // is to say only on a getter returning String or a Named instance, so we trust the result of
+ // the call
+ Object value = property.getPropertyValue(spec);
+ variants.put(property.getName(), value);
+ dimensionTypesBuilder.put(property.getName(), property.getType());
+ }
+ }
+ }
+ return new DefaultVariantsMetaData(Collections.unmodifiableMap(variants), dimensionTypesBuilder.build());
+ }
+
+ @Override
+ public Set<String> getAllDimensions() {
+ return allVariantDimensions;
+ }
+
+ @Override
+ public Set<String> getNonNullDimensions() {
+ return nonNullVariantDimensions;
+ }
+
+ @Override
+ public String getValueAsString(String dimension) {
+ Object o = variants.get(dimension);
+ if (o instanceof Named) {
+ return ((Named) o).getName();
+ }
+ if (o instanceof String) {
+ return (String) o;
+ }
+ return o == null ? null : o.toString();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends Named> T getValueAsType(Class<T> clazz, String dimension) {
+ return (T) variants.get(dimension);
+ }
+
+ @Override
+ public ModelType<?> getDimensionType(String dimension) {
+ return variantDimensionTypes.get(dimension);
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantDimensionSelector.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantDimensionSelector.java
new file mode 100644
index 0000000..c431a91
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantDimensionSelector.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+public interface VariantDimensionSelector<T> {
+ /**
+ * Should return true if a variant value is compatible with the requirement.
+ * @param requirement the value of a variant, expressing a specific requirement
+ * @param value the value of the variant we want to check the compatibility for
+ * @return true if the value is compatible with the requirement
+ */
+ boolean isCompatibleWithRequirement(T requirement, T value);
+
+ /**
+ * Should return true if a variant value is a better fit than an old value for a specific requirement.
+ * For example, two variant values may be compatible, but one may be a better fit than the other. In
+ * that case, we compare two compatible variant values, and must return true if and only if the second
+ * one is a better fit than the first one.
+ *
+ * @param requirement the value of a variant, expressing a specific requirement
+ * @param first the first value of a variant
+ * @param second another value of the variant
+ * @return true if the second value is a better fit than the first one
+ */
+ boolean betterFit(T requirement, T first, T second);
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantDimensionSelectorFactory.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantDimensionSelectorFactory.java
new file mode 100644
index 0000000..172ad86
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantDimensionSelectorFactory.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+public interface VariantDimensionSelectorFactory {
+ <T> VariantDimensionSelector<T> getVariantDimensionSelector(T o);
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantsMetaData.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantsMetaData.java
new file mode 100644
index 0000000..71e045e
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantsMetaData.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+import org.gradle.api.Named;
+import org.gradle.model.internal.type.ModelType;
+
+import java.util.Set;
+
+public interface VariantsMetaData {
+
+ Set<String> getAllDimensions();
+
+ Set<String> getNonNullDimensions();
+
+ String getValueAsString(String dimension);
+
+ <T extends Named> T getValueAsType(Class<T> clazz, String dimension);
+
+ ModelType<?> getDimensionType(String dimension);
+
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantsMetaDataHelper.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantsMetaDataHelper.java
new file mode 100644
index 0000000..88a7e6a
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/model/VariantsMetaDataHelper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.model;
+
+import com.google.common.collect.Sets;
+import org.gradle.model.internal.type.ModelType;
+
+import java.util.Set;
+
+public class VariantsMetaDataHelper {
+ public static Set<String> incompatibleDimensionTypes(VariantsMetaData reference, VariantsMetaData candidate, Set<String> testedDimensions) {
+ Set<String> result = Sets.newHashSet();
+ for (String commonDimension : testedDimensions) {
+ ModelType<?> resolveType = reference.getDimensionType(commonDimension);
+ ModelType<?> binaryVariantType = candidate.getDimensionType(commonDimension);
+ if (binaryVariantType != null && !resolveType.isAssignableFrom(binaryVariantType)) {
+ result.add(commonDimension);
+ }
+ }
+ return result;
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/DependentSourceSetLocalComponentConverter.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/DependentSourceSetLocalComponentConverter.java
new file mode 100644
index 0000000..ee87911
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/DependentSourceSetLocalComponentConverter.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.resolve;
+
+import com.google.common.base.Strings;
+import org.apache.ivy.core.module.descriptor.ExcludeRule;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.component.ComponentSelector;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
+import org.gradle.api.internal.artifacts.DefaultModuleVersionSelector;
+import org.gradle.api.internal.artifacts.ivyservice.LocalComponentConverter;
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier;
+import org.gradle.internal.component.local.model.DefaultLibraryComponentSelector;
+import org.gradle.internal.component.local.model.DefaultLocalComponentMetaData;
+import org.gradle.internal.component.model.IvyArtifactName;
+import org.gradle.internal.component.model.LocalComponentDependencyMetaData;
+import org.gradle.language.base.internal.DependentSourceSetInternal;
+import org.gradle.language.base.internal.model.DefaultLibraryLocalComponentMetaData;
+import org.gradle.platform.base.DependencySpec;
+import org.gradle.platform.base.DependencySpecContainer;
+
+import java.util.Collections;
+
+public class DependentSourceSetLocalComponentConverter implements LocalComponentConverter {
+
+ private static final ExcludeRule[] EXCLUDE_RULES = new ExcludeRule[0];
+
+ @Override
+ public boolean canConvert(Object source) {
+ return source instanceof DependentSourceSetResolveContext;
+ }
+
+ @Override
+ public DefaultLibraryLocalComponentMetaData convert(Object source) {
+ DependentSourceSetResolveContext context = (DependentSourceSetResolveContext) source;
+ LibraryBinaryIdentifier libraryBinaryIdentifier = context.getComponentId();
+ DependentSourceSetInternal sourceSet = context.getSourceSet();
+ TaskDependency buildDependencies = context.getSourceSet().getBuildDependencies();
+ DefaultLibraryLocalComponentMetaData metaData = DefaultLibraryLocalComponentMetaData.newMetaData(libraryBinaryIdentifier, buildDependencies);
+ addDependencies(libraryBinaryIdentifier.getProjectPath(), metaData, sourceSet.getDependencies());
+ return metaData;
+ }
+
+ private void addDependencies(String defaultProject, DefaultLocalComponentMetaData metaData, DependencySpecContainer allDependencies) {
+ ModuleVersionIdentifier mvi = metaData.getId();
+ for (DependencySpec dependency : allDependencies.getDependencies()) {
+
+ String projectPath = dependency.getProjectPath();
+ if (Strings.isNullOrEmpty(projectPath)) {
+ projectPath = defaultProject;
+ }
+ String libraryName = dependency.getLibraryName();
+ // currently we use "null" as variant value, because there's only one variant: API
+ ComponentSelector selector = new DefaultLibraryComponentSelector(projectPath, libraryName);
+ DefaultModuleVersionSelector requested = new DefaultModuleVersionSelector(
+ Strings.nullToEmpty(projectPath), Strings.nullToEmpty(libraryName), mvi.getVersion());
+ LocalComponentDependencyMetaData localComponentDependencyMetaData = new LocalComponentDependencyMetaData(
+ selector,
+ requested,
+ DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME,
+ DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME,
+ Collections.<IvyArtifactName>emptySet(),
+ EXCLUDE_RULES,
+ false,
+ false,
+ true);
+ metaData.addDependency(localComponentDependencyMetaData);
+ }
+ }
+
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/DependentSourceSetResolveContext.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/DependentSourceSetResolveContext.java
new file mode 100644
index 0000000..fc7ca51
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/DependentSourceSetResolveContext.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.language.base.internal.resolve;
+
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.artifacts.DependencySet;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
+import org.gradle.api.internal.DefaultDomainObjectSet;
+import org.gradle.api.internal.artifacts.DefaultDependencySet;
+import org.gradle.api.internal.artifacts.ResolveContext;
+import org.gradle.api.internal.artifacts.configurations.ResolutionStrategyInternal;
+import org.gradle.api.internal.artifacts.ivyservice.resolutionstrategy.DefaultResolutionStrategy;
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier;
+import org.gradle.language.base.internal.DependentSourceSetInternal;
+import org.gradle.language.base.internal.model.VariantsMetaData;
+
+public class DependentSourceSetResolveContext implements ResolveContext {
+ private final LibraryBinaryIdentifier binaryId;
+ private final DependentSourceSetInternal sourceSet;
+ private final ResolutionStrategyInternal resolutionStrategy = new DefaultResolutionStrategy();
+ private final VariantsMetaData variants;
+
+ public DependentSourceSetResolveContext(LibraryBinaryIdentifier binaryId, DependentSourceSetInternal sourceSet, VariantsMetaData variants) {
+ this.binaryId = binaryId;
+ this.sourceSet = sourceSet;
+ this.variants = variants;
+ }
+
+ @Override
+ public String getName() {
+ return DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return sourceSet.getDisplayName();
+ }
+
+ public LibraryBinaryIdentifier getComponentId() {
+ return binaryId;
+ }
+
+ public DependentSourceSetInternal getSourceSet() {
+ return sourceSet;
+ }
+
+ public VariantsMetaData getVariants() {
+ return variants;
+ }
+
+ @Override
+ public ResolutionStrategyInternal getResolutionStrategy() {
+ return resolutionStrategy;
+ }
+
+ @Override
+ public DependencySet getDependencies() {
+ DefaultDomainObjectSet<Dependency> backingSet = new DefaultDomainObjectSet<Dependency>(Dependency.class);
+ return new DefaultDependencySet(String.format("%s dependencies", this.getName()), backingSet);
+ }
+
+ @Override
+ public DependencySet getAllDependencies() {
+ return new DefaultDependencySet(String.format("%s dependencies", this.getName()), new DefaultDomainObjectSet<Dependency>(Dependency.class));
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/LibraryResolveException.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/LibraryResolveException.java
new file mode 100644
index 0000000..8fe4b3b
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/internal/resolve/LibraryResolveException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.resolve;
+
+import org.gradle.internal.exceptions.Contextual;
+import org.gradle.internal.exceptions.DefaultMultiCauseException;
+
+ at Contextual
+public class LibraryResolveException extends DefaultMultiCauseException {
+
+ public LibraryResolveException(String message) {
+ super(message);
+ }
+
+ public LibraryResolveException(String message, Iterable<? extends Throwable> causes) {
+ super(message, causes);
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/ComponentModelBasePlugin.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/ComponentModelBasePlugin.java
index 512f5db..5502831 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/ComponentModelBasePlugin.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/ComponentModelBasePlugin.java
@@ -15,7 +15,10 @@
*/
package org.gradle.language.base.plugins;
-import org.gradle.api.*;
+import org.gradle.api.Incubating;
+import org.gradle.api.NamedDomainObjectFactory;
+import org.gradle.api.Plugin;
+import org.gradle.api.Task;
import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.api.internal.rules.ModelMapCreators;
import org.gradle.api.internal.rules.NamedDomainObjectFactoryRegistry;
@@ -25,10 +28,10 @@ import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.util.BiFunction;
import org.gradle.language.base.LanguageSourceSet;
-import org.gradle.language.base.ProjectSourceSet;
import org.gradle.language.base.internal.LanguageSourceSetInternal;
import org.gradle.language.base.internal.SourceTransformTaskConfig;
import org.gradle.language.base.internal.model.BinarySpecFactoryRegistry;
+import org.gradle.language.base.internal.model.ComponentBinaryRules;
import org.gradle.language.base.internal.model.ComponentRules;
import org.gradle.language.base.internal.registry.*;
import org.gradle.model.*;
@@ -69,7 +72,7 @@ public class ComponentModelBasePlugin implements Plugin<ProjectInternal> {
public void apply(final ProjectInternal project) {
project.getPluginManager().apply(LanguageBasePlugin.class);
- SimpleModelRuleDescriptor descriptor = new SimpleModelRuleDescriptor(ComponentModelBasePlugin.class.getName() + ".apply()");
+ SimpleModelRuleDescriptor descriptor = new SimpleModelRuleDescriptor(ComponentModelBasePlugin.class.getSimpleName() + ".apply()");
ModelMapSchema<ComponentSpecContainer> schema = (ModelMapSchema<ComponentSpecContainer>) schemaStore.getSchema(ModelType.of(ComponentSpecContainer.class));
ModelPath components = ModelPath.path("components");
@@ -83,6 +86,7 @@ public class ComponentModelBasePlugin implements Plugin<ProjectInternal> {
);
modelRegistry.create(componentsCreator);
modelRegistry.getRoot().applyToAllLinksTransitive(ModelType.of(ComponentSpec.class), ComponentRules.class);
+ modelRegistry.getRoot().applyToAllLinksTransitive(ModelType.of(ComponentSpec.class), ComponentBinaryRules.class);
}
@SuppressWarnings("UnusedDeclaration")
@@ -109,7 +113,7 @@ public class ComponentModelBasePlugin implements Plugin<ProjectInternal> {
// Finalizing here, as we need this to run after any 'assembling' task (jar, link, etc) is created.
@Finalize
- void createSourceTransformTasks(final TaskContainer tasks, final BinaryContainer binaries, LanguageTransformContainer languageTransforms) {
+ void createSourceTransformTasks(final TaskContainer tasks, final BinaryContainer binaries, LanguageTransformContainer languageTransforms, ServiceRegistry serviceRegistry) {
for (LanguageTransform<?, ?> language : languageTransforms) {
for (final BinarySpecInternal binary : binaries.withType(BinarySpecInternal.class)) {
if (binary.isLegacyBinary() || !language.applyToBinary(binary)) {
@@ -117,30 +121,21 @@ public class ComponentModelBasePlugin implements Plugin<ProjectInternal> {
}
final SourceTransformTaskConfig taskConfig = language.getTransformTask();
- binary.getSource().withType(language.getSourceSetType(), new Action<LanguageSourceSet>() {
- public void execute(LanguageSourceSet languageSourceSet) {
- LanguageSourceSetInternal sourceSet = (LanguageSourceSetInternal) languageSourceSet;
- if (sourceSet.getMayHaveSources()) {
- String taskName = taskConfig.getTaskPrefix() + capitalize(binary.getName()) + capitalize(sourceSet.getFullName());
- Task task = tasks.create(taskName, taskConfig.getTaskType());
-
- taskConfig.configureTask(task, binary, sourceSet);
-
- task.dependsOn(sourceSet);
- binary.getTasks().add(task);
- }
+ for (LanguageSourceSet languageSourceSet : binary.getInputs()) {
+ LanguageSourceSetInternal sourceSet = (LanguageSourceSetInternal) languageSourceSet;
+ if (language.getSourceSetType().isInstance(sourceSet) && sourceSet.getMayHaveSources()) {
+ String taskName = taskConfig.getTaskPrefix() + capitalize(binary.getName()) + capitalize(sourceSet.getFullName());
+ Task task = tasks.create(taskName, taskConfig.getTaskType());
+ taskConfig.configureTask(task, binary, sourceSet, serviceRegistry);
+
+ task.dependsOn(sourceSet);
+ binary.getTasks().add(task);
}
- });
+ }
}
}
}
- // TODO:DAZ Work out why this is required
- @Mutate
- void closeSourcesForBinaries(BinaryContainer binaries, ProjectSourceSet sources) {
- // Only required because sources aren't fully integrated into model
- }
-
@Model
PlatformContainer platforms(ServiceRegistry serviceRegistry) {
Instantiator instantiator = serviceRegistry.get(Instantiator.class);
@@ -192,5 +187,16 @@ public class ComponentModelBasePlugin implements Plugin<ProjectInternal> {
}
}
}
+
+ // TODO:LPTR This should be done on the binary itself when transitive rules don't fire multiple times anymore
+ @Finalize
+ void addSourceSetsOwnedByBinariesToTheirInputs(BinaryContainer binarySpecs) {
+ for (BinarySpec binary : binarySpecs) {
+ if (((BinarySpecInternal) binary).isLegacyBinary()) {
+ continue;
+ }
+ binary.getInputs().addAll(binary.getSources().values());
+ }
+ }
}
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/LanguageBasePlugin.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/LanguageBasePlugin.java
index 7a35fb2..ac8e352 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/LanguageBasePlugin.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/plugins/LanguageBasePlugin.java
@@ -75,7 +75,7 @@ public class LanguageBasePlugin implements Plugin<Project> {
}
private static void applyRules(ModelRegistry modelRegistry, DefaultBinaryContainer binaries) {
- final String descriptor = LanguageBasePlugin.class.getName() + ".apply()";
+ final String descriptor = LanguageBasePlugin.class.getSimpleName() + ".apply()";
final ModelRuleDescriptor ruleDescriptor = new SimpleModelRuleDescriptor(descriptor);
ModelPath binariesPath = ModelPath.path("binaries");
diff --git a/subprojects/platform-base/src/main/java/org/gradle/language/base/sources/BaseLanguageSourceSet.java b/subprojects/platform-base/src/main/java/org/gradle/language/base/sources/BaseLanguageSourceSet.java
index 24b856b..9b8d961 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/language/base/sources/BaseLanguageSourceSet.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/language/base/sources/BaseLanguageSourceSet.java
@@ -40,7 +40,7 @@ public abstract class BaseLanguageSourceSet extends AbstractBuildableModelElemen
private boolean generated;
private Task generatorTask;
- // TODO:DAZ This is only here as a convenience for subclasses to create additional SourceDirectorySets
+ // This is here as a convenience for subclasses to create additional SourceDirectorySets
protected FileResolver fileResolver;
public String getName() {
diff --git a/subprojects/platform-base/src/main/java/org/gradle/model/internal/core/DomainObjectCollectionBackedModelMap.java b/subprojects/platform-base/src/main/java/org/gradle/model/internal/core/DomainObjectCollectionBackedModelMap.java
new file mode 100644
index 0000000..32e5597
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/model/internal/core/DomainObjectCollectionBackedModelMap.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.core;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import org.gradle.api.*;
+import org.gradle.api.specs.Spec;
+import org.gradle.internal.Actions;
+import org.gradle.internal.Cast;
+import org.gradle.internal.Specs;
+import org.gradle.model.ModelMap;
+import org.gradle.model.RuleSource;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import static org.gradle.internal.Cast.uncheckedCast;
+
+public class DomainObjectCollectionBackedModelMap<T> implements ModelMap<T> {
+
+ private final Class<T> elementType;
+ private final DomainObjectCollection<T> collection;
+ private final NamedEntityInstantiator<T> instantiator;
+ private final Namer<? super T> namer;
+ private final Action<? super T> onCreateAction;
+
+ public DomainObjectCollectionBackedModelMap(Class<T> elementType, DomainObjectCollection<T> backingCollection, NamedEntityInstantiator<T> instantiator, Namer<? super T> namer, Action<? super T> onCreateAction) {
+ this.elementType = elementType;
+ this.collection = backingCollection;
+ this.instantiator = instantiator;
+ this.namer = namer;
+ this.onCreateAction = onCreateAction;
+ }
+
+ private <S> ModelMap<S> toNonSubtypeMap(Class<S> type) {
+ DomainObjectCollection<S> cast = toNonSubtype(type);
+ Namer<S> castNamer = Cast.uncheckedCast(namer);
+ return DomainObjectCollectionBackedModelMap.wrap(type, cast, NamedEntityInstantiators.nonSubtype(type, elementType), castNamer, Actions.doNothing());
+ }
+
+ private <S> DomainObjectSet<S> toNonSubtype(final Class<S> type) {
+ return uncheckedCast(collection.matching(Specs.isInstance(type)));
+ }
+
+ private <S extends T> ModelMap<S> toSubtypeMap(Class<S> itemSubtype) {
+ NamedEntityInstantiator<S> instantiator = uncheckedCast(this.instantiator);
+ return DomainObjectCollectionBackedModelMap.wrap(itemSubtype, collection.withType(itemSubtype), instantiator, namer, onCreateAction);
+ }
+
+ @Nullable
+ @Override
+ public T get(String name) {
+ return Iterables.find(collection, new HasNamePredicate<T>(name, namer), null);
+ }
+
+ @Override
+ public Set<String> keySet() {
+ return Sets.newHashSet(Iterables.transform(collection, new ToName<T>(namer)));
+ }
+
+ @Override
+ public <S> void withType(Class<S> type, Action<? super S> configAction) {
+ toNonSubtype(type).all(configAction);
+ }
+
+ private static class HasNamePredicate<T> implements Predicate<T> {
+ private final String name;
+ private final Namer<? super T> namer;
+
+ public HasNamePredicate(String name, Namer<? super T> namer) {
+ this.name = name;
+ this.namer = namer;
+ }
+
+ @Override
+ public boolean apply(@Nullable T input) {
+ return namer.determineName(input).equals(name);
+ }
+ }
+
+ private static class ToName<T> implements Function<T, String> {
+ private final Namer<? super T> namer;
+
+ public ToName(Namer<? super T> namer) {
+ this.namer = namer;
+ }
+
+ @Override
+ public String apply(@Nullable T input) {
+ return namer.determineName(input);
+ }
+ }
+
+ public static <T> DomainObjectCollectionBackedModelMap<T> wrap(Class<T> elementType, DomainObjectCollection<T> domainObjectSet, NamedEntityInstantiator<T> instantiator, Namer<? super T> namer, Action<? super T> onCreate) {
+ return new DomainObjectCollectionBackedModelMap<T>(elementType, domainObjectSet, instantiator, namer, onCreate);
+ }
+
+ @Override
+ public int size() {
+ return collection.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return collection.isEmpty();
+ }
+
+ @Nullable
+ @Override
+ public T get(Object name) {
+ return get(name.toString());
+ }
+
+ @Override
+ public boolean containsKey(Object name) {
+ return keySet().contains(name.toString());
+ }
+
+ @Override
+ public boolean containsValue(Object item) {
+ //noinspection SuspiciousMethodCalls
+ return collection.contains(item);
+ }
+
+ @Override
+ public void create(String name) {
+ create(name, elementType, Actions.doNothing());
+ }
+
+ @Override
+ public void create(String name, Action<? super T> configAction) {
+ create(name, elementType, configAction);
+ }
+
+ @Override
+ public <S extends T> void create(String name, Class<S> type) {
+ create(name, type, Actions.doNothing());
+ }
+
+ @Override
+ public <S extends T> void create(String name, Class<S> type, Action<? super S> configAction) {
+ if (containsKey(name)) {
+ throw new IllegalStateException("Entry with name already exists: " + name);
+ }
+ S s = instantiator.create(name, type);
+ configAction.execute(s);
+ onCreateAction.execute(s);
+ collection.add(s);
+ }
+
+ @Override
+ public void named(String name, Class<? extends RuleSource> ruleSource) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void all(Action<? super T> configAction) {
+ collection.all(configAction);
+ }
+
+ @Override
+ public void beforeEach(Action<? super T> configAction) {
+ all(configAction);
+ }
+
+ @Override
+ public <S> void withType(Class<S> type, Class<? extends RuleSource> rules) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void afterEach(Action<? super T> configAction) {
+ all(configAction);
+ }
+
+ @Override
+ public Collection<T> values() {
+ return collection;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return collection.iterator();
+ }
+
+ @Override
+ public <S> void beforeEach(Class<S> type, Action<? super S> configAction) {
+ withType(type, configAction);
+ }
+
+ @Override
+ public <S> void afterEach(Class<S> type, Action<? super S> configAction) {
+ withType(type, configAction);
+ }
+
+ @Override
+ public void named(final String name, Action<? super T> configAction) {
+ collection.matching(new Spec<T>() {
+ @Override
+ public boolean isSatisfiedBy(T element) {
+ return get(name) == element;
+ }
+ }).all(configAction);
+ }
+
+ @Override
+ public <S> ModelMap<S> withType(final Class<S> type) {
+ if (type.equals(elementType)) {
+ return uncheckedCast(this);
+ }
+
+ if (elementType.isAssignableFrom(type)) {
+ Class<? extends T> castType = uncheckedCast(type);
+ ModelMap<? extends T> subType = toSubtypeMap(castType);
+ return uncheckedCast(subType);
+ }
+
+ return toNonSubtypeMap(type);
+ }
+
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/model/internal/core/DomainObjectSetBackedModelMap.java b/subprojects/platform-base/src/main/java/org/gradle/model/internal/core/DomainObjectSetBackedModelMap.java
deleted file mode 100644
index 82d99c0..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/model/internal/core/DomainObjectSetBackedModelMap.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.model.internal.core;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import org.gradle.api.Action;
-import org.gradle.api.DomainObjectSet;
-import org.gradle.api.Namer;
-import org.gradle.api.Nullable;
-import org.gradle.api.specs.Spec;
-import org.gradle.internal.Actions;
-import org.gradle.internal.Cast;
-import org.gradle.internal.Specs;
-import org.gradle.model.ModelMap;
-import org.gradle.model.RuleSource;
-
-import java.util.Collection;
-import java.util.Set;
-
-import static org.gradle.internal.Cast.uncheckedCast;
-
-public class DomainObjectSetBackedModelMap<T> implements ModelMap<T> {
-
- private final Class<T> elementType;
- private final DomainObjectSet<T> set;
- private final NamedEntityInstantiator<T> instantiator;
- private final Namer<? super T> namer;
- private final Action<? super T> onCreateAction;
-
- public DomainObjectSetBackedModelMap(Class<T> elementType, DomainObjectSet<T> backingSet, NamedEntityInstantiator<T> instantiator, Namer<? super T> namer, Action<? super T> onCreateAction) {
- this.elementType = elementType;
- this.set = backingSet;
- this.instantiator = instantiator;
- this.namer = namer;
- this.onCreateAction = onCreateAction;
- }
-
- private <S> ModelMap<S> toNonSubtypeMap(Class<S> type) {
- DomainObjectSet<S> cast = toNonSubtype(type);
- Namer<S> castNamer = Cast.uncheckedCast(namer);
- return DomainObjectSetBackedModelMap.wrap(type, cast, NamedEntityInstantiators.nonSubtype(type, elementType), castNamer, Actions.doNothing());
- }
-
- private <S> DomainObjectSet<S> toNonSubtype(final Class<S> type) {
- return uncheckedCast(set.matching(Specs.isInstance(type)));
- }
-
- private <S extends T> ModelMap<S> toSubtypeMap(Class<S> itemSubtype) {
- NamedEntityInstantiator<S> instantiator = uncheckedCast(this.instantiator);
- return DomainObjectSetBackedModelMap.wrap(itemSubtype, set.withType(itemSubtype), instantiator, namer, onCreateAction);
- }
-
- @Nullable
- @Override
- public T get(String name) {
- return Iterables.find(set, new HasNamePredicate<T>(name, namer), null);
- }
-
- @Override
- public Set<String> keySet() {
- return Sets.newHashSet(Iterables.transform(set, new ToName<T>(namer)));
- }
-
- @Override
- public <S> void withType(Class<S> type, Action<? super S> configAction) {
- toNonSubtype(type).all(configAction);
- }
-
- private static class HasNamePredicate<T> implements Predicate<T> {
- private final String name;
- private final Namer<? super T> namer;
-
- public HasNamePredicate(String name, Namer<? super T> namer) {
- this.name = name;
- this.namer = namer;
- }
-
- @Override
- public boolean apply(@Nullable T input) {
- return namer.determineName(input).equals(name);
- }
- }
-
- private static class ToName<T> implements Function<T, String> {
- private final Namer<? super T> namer;
-
- public ToName(Namer<? super T> namer) {
- this.namer = namer;
- }
-
- @Override
- public String apply(@Nullable T input) {
- return namer.determineName(input);
- }
- }
-
- public static <T> DomainObjectSetBackedModelMap<T> wrap(Class<T> elementType, DomainObjectSet<T> domainObjectSet, NamedEntityInstantiator<T> instantiator, Namer<? super T> namer, Action<? super T> onCreate) {
- return new DomainObjectSetBackedModelMap<T>(elementType, domainObjectSet, instantiator, namer, onCreate);
- }
-
- @Override
- public int size() {
- return set.size();
- }
-
- @Override
- public boolean isEmpty() {
- return set.isEmpty();
- }
-
- @Nullable
- @Override
- public T get(Object name) {
- return get(name.toString());
- }
-
- @Override
- public boolean containsKey(Object name) {
- return keySet().contains(name.toString());
- }
-
- @Override
- public boolean containsValue(Object item) {
- //noinspection SuspiciousMethodCalls
- return set.contains(item);
- }
-
- @Override
- public void create(String name) {
- create(name, elementType, Actions.doNothing());
- }
-
- @Override
- public void create(String name, Action<? super T> configAction) {
- create(name, elementType, configAction);
- }
-
- @Override
- public <S extends T> void create(String name, Class<S> type) {
- create(name, type, Actions.doNothing());
- }
-
- @Override
- public <S extends T> void create(String name, Class<S> type, Action<? super S> configAction) {
- S s = instantiator.create(name, type);
- configAction.execute(s);
- onCreateAction.execute(s);
- }
-
- @Override
- public void named(String name, Class<? extends RuleSource> ruleSource) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void all(Action<? super T> configAction) {
- set.all(configAction);
- }
-
- @Override
- public void beforeEach(Action<? super T> configAction) {
- all(configAction);
- }
-
- @Override
- public <S> void withType(Class<S> type, Class<? extends RuleSource> rules) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void afterEach(Action<? super T> configAction) {
- all(configAction);
- }
-
- @Override
- public Collection<T> values() {
- return set;
- }
-
- @Override
- public <S> void beforeEach(Class<S> type, Action<? super S> configAction) {
- withType(type, configAction);
- }
-
- @Override
- public <S> void afterEach(Class<S> type, Action<? super S> configAction) {
- withType(type, configAction);
- }
-
- @Override
- public void named(final String name, Action<? super T> configAction) {
- set.matching(new Spec<T>() {
- @Override
- public boolean isSatisfiedBy(T element) {
- return get(name) == element;
- }
- }).all(configAction);
- }
-
- @Override
- public <S> ModelMap<S> withType(final Class<S> type) {
- if (type.equals(elementType)) {
- return uncheckedCast(this);
- }
-
- if (elementType.isAssignableFrom(type)) {
- Class<? extends T> castType = uncheckedCast(type);
- ModelMap<? extends T> subType = toSubtypeMap(castType);
- return uncheckedCast(subType);
- }
-
- return toNonSubtypeMap(type);
- }
-
-}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/BinarySpec.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/BinarySpec.java
index 286c872..8951cb4 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/BinarySpec.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/BinarySpec.java
@@ -19,12 +19,12 @@ package org.gradle.platform.base;
import org.gradle.api.*;
import org.gradle.internal.HasInternalProtocol;
import org.gradle.language.base.LanguageSourceSet;
+import org.gradle.model.ModelMap;
/**
* Represents a binary artifact that is the result of building a project component.
*/
- at Incubating
- at HasInternalProtocol
+ at Incubating @HasInternalProtocol
public interface BinarySpec extends BuildableModelElement, Named {
/**
* Returns a human-consumable display name for this binary.
@@ -37,23 +37,33 @@ public interface BinarySpec extends BuildableModelElement, Named {
boolean isBuildable();
/**
- * Adds one or more {@link org.gradle.language.base.LanguageSourceSet}s that are used to compile this binary. <p/> This method accepts the following types:
+ * The source sets used to compile this binary.
*
- * <ul> <li>A {@link org.gradle.language.base.FunctionalSourceSet}</li> <li>A {@link org.gradle.language.base.LanguageSourceSet}</li> <li>A Collection of {@link
- * org.gradle.language.base.LanguageSourceSet}s</li> </ul>
+ * @deprecated This method is replaced with {@link #getInputs()}.
*/
- // TODO:DAZ Remove this
- void source(Object source);
+ @Deprecated
+ DomainObjectSet<LanguageSourceSet> getSource();
/**
- * The source sets used to compile this binary.
+ * The sources owned by this binary.
+ *
+ * @return the sources owned by the binary.
*/
- DomainObjectSet<LanguageSourceSet> getSource();
+ ModelMap<LanguageSourceSet> getSources();
+
+ /**
+ * Returns all inputs of the binary. This includes source sets owned by the binary,
+ * and other source sets created elsewhere (e.g. inherited from the binary's component).
+ *
+ * @return all inputs of the binary.
+ */
+ DomainObjectSet<LanguageSourceSet> getInputs();
/**
* Configures the source sets used to build this binary.
+ * @param action The configuration action to execute for each owned source set.
*/
- void sources(Action<? super PolymorphicDomainObjectContainer<LanguageSourceSet>> action);
+ void sources(Action<? super ModelMap<LanguageSourceSet>> action);
/**
* The set of tasks associated with this binary.
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/ComponentSpec.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/ComponentSpec.java
index fcb4ddc..f0cf7d3 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/ComponentSpec.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/ComponentSpec.java
@@ -39,10 +39,18 @@ public interface ComponentSpec extends Named {
/**
* The source sets that are used to build this component.
+ *
+ * @deprecated This method is replaced with {@link #getSources()}.
*/
+ @Deprecated
ModelMap<LanguageSourceSet> getSource();
/**
+ * The source sets that are used to build this component.
+ */
+ ModelMap<LanguageSourceSet> getSources();
+
+ /**
* Configures the source sets used to build this component.
*/
void sources(Action<? super ModelMap<LanguageSourceSet>> action);
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/DependencySpecContainer.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/DependencySpecContainer.java
index a7ff269..e5be416 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/DependencySpecContainer.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/DependencySpecContainer.java
@@ -18,13 +18,13 @@ package org.gradle.platform.base;
import org.gradle.api.Incubating;
-import java.util.Set;
+import java.util.Collection;
/**
* A container for dependency specifications.
*/
@Incubating
-public interface DependencySpecContainer extends Set<DependencySpec> {
+public interface DependencySpecContainer {
/**
* Defines a new dependency, based on a project path. The returned dependency can be mutated.
*
@@ -32,7 +32,7 @@ public interface DependencySpecContainer extends Set<DependencySpec> {
*
* @return a mutable dependency, added to this container
*/
- DependencySpec project(String path);
+ DependencySpecBuilder project(String path);
/**
* Defines a new dependency, based on a library name. The returned dependency can be mutated.
@@ -41,6 +41,20 @@ public interface DependencySpecContainer extends Set<DependencySpec> {
*
* @return a mutable dependency, added to this container
*/
- DependencySpec library(String name);
+ DependencySpecBuilder library(String name);
+
+ /**
+ * Returns an immutable view of dependencies stored in this container.
+ *
+ * @return an immutable view of dependencies. Each dependency in the collection is itself immutable.
+ */
+ Collection<DependencySpec> getDependencies();
+
+ /**
+ * Returns true if this container doesn't hold any dependency.
+ *
+ * @return true if this container doesn't contain any dependency specification.
+ */
+ boolean isEmpty();
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/PlatformAwareComponentSpec.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/PlatformAwareComponentSpec.java
index fb29d29..e4a592e 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/PlatformAwareComponentSpec.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/PlatformAwareComponentSpec.java
@@ -27,5 +27,5 @@ public interface PlatformAwareComponentSpec extends ComponentSpec {
/**
* Specifies a platform that this component should be built be for.
*/
- public void targetPlatform(String targetPlatform);
+ void targetPlatform(String targetPlatform);
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/Variant.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/Variant.java
new file mode 100644
index 0000000..73cfca6
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/Variant.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.platform.base;
+
+import org.gradle.api.Incubating;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Declares that a property represents a variant dimension. Variants are used in dependency
+ * resolution to discriminate between various binaries that may match the requirements (such
+ * as a platform, a build type, ...).
+ *
+ * This annotation must be set on a getter. The return type of the getter must either be
+ * a {@link String} or a class implementing {@link org.gradle.api.Named}.
+ *
+ * @since 2.6
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.METHOD)
+ at Incubating
+public @interface Variant {
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java
index 59de47b..57e683f 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java
@@ -19,29 +19,41 @@ package org.gradle.platform.base.binary;
import org.gradle.api.Action;
import org.gradle.api.DomainObjectSet;
import org.gradle.api.Incubating;
-import org.gradle.api.PolymorphicDomainObjectContainer;
import org.gradle.api.internal.AbstractBuildableModelElement;
+import org.gradle.api.internal.DefaultDomainObjectSet;
+import org.gradle.api.internal.DefaultPolymorphicNamedEntityInstantiator;
import org.gradle.api.internal.project.taskfactory.ITaskFactory;
+import org.gradle.api.internal.rules.NamedDomainObjectFactoryRegistry;
+import org.gradle.internal.Actions;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.reflect.ObjectInstantiationException;
-import org.gradle.language.base.FunctionalSourceSet;
import org.gradle.language.base.LanguageSourceSet;
-import org.gradle.language.base.internal.LanguageSourceSetContainer;
+import org.gradle.model.ModelMap;
+import org.gradle.model.internal.core.DomainObjectCollectionBackedModelMap;
+import org.gradle.model.internal.core.ModelMapGroovyDecorator;
import org.gradle.platform.base.BinaryTasksCollection;
import org.gradle.platform.base.ModelInstantiationException;
import org.gradle.platform.base.internal.BinaryBuildAbility;
import org.gradle.platform.base.internal.BinarySpecInternal;
import org.gradle.platform.base.internal.DefaultBinaryTasksCollection;
import org.gradle.platform.base.internal.FixedBuildAbility;
+import org.gradle.util.DeprecationLogger;
/**
- * Base class for custom binary implementations. A custom implementation of {@link org.gradle.platform.base.BinarySpec} must extend this type.
+ * Base class for custom binary implementations.
+ * A custom implementation of {@link org.gradle.platform.base.BinarySpec} must extend this type.
+ *
+ * TODO at the moment leaking BinarySpecInternal here to generate lifecycleTask in
+ * LanguageBasePlugin$createLifecycleTaskForBinary#createLifecycleTaskForBinary rule
*
- * TODO at the moment leaking BinarySpecInternal here to generate lifecycleTask in LanguageBasePlugin$createLifecycleTaskForBinary#createLifecycleTaskForBinary rule
*/
@Incubating
+// Needs to be here instead of the specific methods, because Java 6 and 7 will throw warnings otherwise
+ at SuppressWarnings("deprecation")
public abstract class BaseBinarySpec extends AbstractBuildableModelElement implements BinarySpecInternal {
- private final LanguageSourceSetContainer sourceSets = new LanguageSourceSetContainer();
+ private final NamedDomainObjectFactoryRegistry<LanguageSourceSet> entityInstantiator;
+ private final ModelMap<LanguageSourceSet> ownedSourceSets;
+ private final DomainObjectSet<LanguageSourceSet> inputSourceSets = new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet.class);
private static ThreadLocal<BinaryInfo> nextBinaryInfo = new ThreadLocal<BinaryInfo>();
private final BinaryTasksCollection tasks;
@@ -78,6 +90,14 @@ public abstract class BaseBinarySpec extends AbstractBuildableModelElement imple
this.name = info.name;
this.typeName = info.typeName;
this.tasks = info.instantiator.newInstance(DefaultBinaryTasksCollection.class, this, info.taskFactory);
+ DefaultPolymorphicNamedEntityInstantiator<LanguageSourceSet> entityInstantiator = new DefaultPolymorphicNamedEntityInstantiator<LanguageSourceSet>(LanguageSourceSet.class, "owned sources");
+ this.entityInstantiator = entityInstantiator;
+ this.ownedSourceSets = new DomainObjectCollectionBackedModelMap<LanguageSourceSet>(
+ LanguageSourceSet.class,
+ new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet.class),
+ entityInstantiator,
+ new Namer(),
+ Actions.doNothing());
}
protected String getTypeName() {
@@ -101,27 +121,29 @@ public abstract class BaseBinarySpec extends AbstractBuildableModelElement imple
return getBuildAbility().isBuildable();
}
- public FunctionalSourceSet getBinarySources() {
- return sourceSets.getMainSources();
+ @Override
+ public DomainObjectSet<LanguageSourceSet> getSource() {
+ DeprecationLogger.nagUserOfReplacedProperty("source", "inputs");
+ return getInputs();
}
- public void setBinarySources(FunctionalSourceSet sources) {
- sourceSets.setMainSources(sources);
+ public void sources(Action<? super ModelMap<LanguageSourceSet>> action) {
+ action.execute(getSources());
}
@Override
- public DomainObjectSet<LanguageSourceSet> getSource() {
- return sourceSets.getSources();
+ public NamedDomainObjectFactoryRegistry<LanguageSourceSet> getEntityInstantiator() {
+ return entityInstantiator;
}
-
- public void sources(Action<? super PolymorphicDomainObjectContainer<LanguageSourceSet>> action) {
- action.execute(sourceSets.getMainSources());
+ @Override
+ public DomainObjectSet<LanguageSourceSet> getInputs() {
+ return inputSourceSets;
}
- // TODO:DAZ Remove this
- public void source(Object source) {
- sourceSets.source(source);
+ @Override
+ public ModelMap<LanguageSourceSet> getSources() {
+ return ModelMapGroovyDecorator.wrap(ownedSourceSets);
}
public BinaryTasksCollection getTasks() {
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/component/BaseComponentSpec.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/component/BaseComponentSpec.java
index 7959c52..f2e0108 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/component/BaseComponentSpec.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/component/BaseComponentSpec.java
@@ -21,8 +21,6 @@ import org.gradle.api.Incubating;
import org.gradle.api.Named;
import org.gradle.api.Transformer;
import org.gradle.internal.Actions;
-import org.gradle.internal.Cast;
-import org.gradle.internal.TriAction;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.reflect.ObjectInstantiationException;
import org.gradle.language.base.FunctionalSourceSet;
@@ -35,6 +33,7 @@ import org.gradle.model.collection.internal.PolymorphicModelMapProjection;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.core.rule.describe.NestedModelRuleDescriptor;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.registry.RuleContext;
import org.gradle.model.internal.type.ModelType;
import org.gradle.model.internal.type.ModelTypes;
@@ -42,27 +41,19 @@ import org.gradle.platform.base.*;
import org.gradle.platform.base.internal.BinarySpecFactory;
import org.gradle.platform.base.internal.BinarySpecInternal;
import org.gradle.platform.base.internal.ComponentSpecInternal;
+import org.gradle.util.DeprecationLogger;
import java.util.Collections;
-import java.util.List;
import java.util.Set;
/**
* Base class for custom component implementations. A custom implementation of {@link ComponentSpec} must extend this type.
*/
@Incubating
+// Needs to be here instead of the specific methods, because Java 6 and 7 will throw warnings otherwise
+ at SuppressWarnings("deprecation")
public abstract class BaseComponentSpec implements ComponentSpecInternal {
- private static final TriAction<MutableModelNode, BinarySpec, List<ModelView<?>>> CREATE_BINARY_SOURCE_SET = new TriAction<MutableModelNode, BinarySpec, List<ModelView<?>>>() {
- @Override
- public void execute(MutableModelNode modelNode, BinarySpec binarySpec, List<ModelView<?>> views) {
- FunctionalSourceSet componentSources = ModelViews.getInstance(views.get(0), FunctionalSourceSet.class);
- BinarySpecInternal binarySpecInternal = Cast.uncheckedCast(binarySpec);
- FunctionalSourceSet binarySources = componentSources.copy(binarySpec.getName());
- binarySpecInternal.setBinarySources(binarySources);
- }
- };
-
private static final Transformer<FunctionalSourceSet, MutableModelNode> PUSH_FUNCTIONAL_SOURCE_SET_TO_NODE = new Transformer<FunctionalSourceSet, MutableModelNode>() {
@Override
public FunctionalSourceSet transform(MutableModelNode modelNode) {
@@ -95,11 +86,11 @@ public abstract class BaseComponentSpec implements ComponentSpecInternal {
private final MutableModelNode sources;
private MutableModelNode modelNode;
- public static <T extends BaseComponentSpec> T create(Class<T> type, ComponentSpecIdentifier identifier, MutableModelNode modelNode, FunctionalSourceSet mainSourceSet, Instantiator instantiator) {
+ public static <T extends BaseComponentSpec> T create(Class<T> type, ComponentSpecIdentifier identifier, MutableModelNode modelNode, FunctionalSourceSet mainSourceSet, Instantiator instantiator, ModelSchemaStore schemaStore) {
if (type.equals(BaseComponentSpec.class)) {
throw new ModelInstantiationException("Cannot create instance of abstract class BaseComponentSpec.");
}
- nextComponentInfo.set(new ComponentInfo(identifier, modelNode, type.getSimpleName(), mainSourceSet, instantiator));
+ nextComponentInfo.set(new ComponentInfo(identifier, modelNode, type.getSimpleName(), mainSourceSet, instantiator, schemaStore));
try {
try {
return instantiator.newInstance(type);
@@ -132,7 +123,7 @@ public abstract class BaseComponentSpec implements ComponentSpecInternal {
.withProjection(
ModelMapModelProjection.unmanaged(
BinarySpec.class,
- NodeBackedModelMap.createUsingFactory(ModelReference.of(BinarySpecFactory.class))
+ NodeBackedModelMap.createManagedOrUsingFactory(info.schemaStore, ModelReference.of(BinarySpecFactory.class))
)
)
.build()
@@ -141,13 +132,6 @@ public abstract class BaseComponentSpec implements ComponentSpecInternal {
assert binaries != null;
final ModelPath sourcesNodePath = modelNode.getPath().child("sources");
- binaries.applyToAllLinks(ModelActionRole.Defaults, DirectNodeInputUsingModelAction.of(
- ModelReference.of(BinarySpecInternal.PUBLIC_MODEL_TYPE),
- new NestedModelRuleDescriptor(modelNode.getDescriptor(), ".sources"),
- Collections.<ModelReference<?>>singletonList(ModelReference.of(sourcesNodePath, FunctionalSourceSet.class)),
- CREATE_BINARY_SOURCE_SET
- ));
-
ModelRuleDescriptor sourcesDescriptor = new NestedModelRuleDescriptor(modelNode.getDescriptor(), ".sources");
modelNode.addLink(
BridgedCollections
@@ -195,6 +179,12 @@ public abstract class BaseComponentSpec implements ComponentSpecInternal {
@Override
public ModelMap<LanguageSourceSet> getSource() {
+ DeprecationLogger.nagUserOfReplacedProperty("source", "sources");
+ return getSources();
+ }
+
+ @Override
+ public ModelMap<LanguageSourceSet> getSources() {
sources.ensureUsable();
return sources.asWritable(
ModelTypes.modelMap(LanguageSourceSet.class),
@@ -205,7 +195,7 @@ public abstract class BaseComponentSpec implements ComponentSpecInternal {
@Override
public void sources(Action<? super ModelMap<LanguageSourceSet>> action) {
- action.execute(getSource());
+ action.execute(getSources());
}
@Override
@@ -223,11 +213,11 @@ public abstract class BaseComponentSpec implements ComponentSpecInternal {
action.execute(getBinaries());
}
- public FunctionalSourceSet getSources() {
+ public FunctionalSourceSet getFunctionalSourceSet() {
return mainSourceSet;
}
- public Set<Class<? extends TransformationFileType>> getInputTypes() {
+ public Set<? extends Class<? extends TransformationFileType>> getInputTypes() {
return Collections.emptySet();
}
@@ -237,19 +227,22 @@ public abstract class BaseComponentSpec implements ComponentSpecInternal {
final String typeName;
final FunctionalSourceSet sourceSets;
final Instantiator instantiator;
+ final ModelSchemaStore schemaStore;
private ComponentInfo(
ComponentSpecIdentifier componentIdentifier,
MutableModelNode modelNode,
String typeName,
FunctionalSourceSet sourceSets,
- Instantiator instantiator
+ Instantiator instantiator,
+ ModelSchemaStore schemaStore
) {
this.componentIdentifier = componentIdentifier;
this.modelNode = modelNode;
this.typeName = typeName;
this.sourceSets = sourceSets;
this.instantiator = instantiator;
+ this.schemaStore = schemaStore;
}
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinaryNamingScheme.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinaryNamingScheme.java
index 78ad0d1..214f37c 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinaryNamingScheme.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinaryNamingScheme.java
@@ -20,11 +20,6 @@ import org.gradle.api.Nullable;
import java.util.List;
-// TODO:DAZ Split data from behaviour
-// data: fullName + component parts [typeName, dimensions, baseName?]
-// Can determine baseName
-
-// behaviour: composing these
public interface BinaryNamingScheme {
String getBaseName();
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinarySpecInternal.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinarySpecInternal.java
index ee80a85..f8d97e3 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinarySpecInternal.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/BinarySpecInternal.java
@@ -16,21 +16,19 @@
package org.gradle.platform.base.internal;
-import org.gradle.language.base.FunctionalSourceSet;
+import org.gradle.api.internal.rules.NamedDomainObjectFactoryRegistry;
+import org.gradle.language.base.LanguageSourceSet;
import org.gradle.model.internal.type.ModelType;
import org.gradle.platform.base.BinarySpec;
public interface BinarySpecInternal extends BinarySpec {
-
ModelType<BinarySpec> PUBLIC_MODEL_TYPE = ModelType.of(BinarySpec.class);
- FunctionalSourceSet getBinarySources();
-
- void setBinarySources(FunctionalSourceSet sources);
-
void setBuildable(boolean buildable);
BinaryBuildAbility getBuildAbility();
boolean isLegacyBinary();
+
+ NamedDomainObjectFactoryRegistry<LanguageSourceSet> getEntityInstantiator();
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/ComponentSpecInternal.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/ComponentSpecInternal.java
index 6e17bbd..859f963 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/ComponentSpecInternal.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/ComponentSpecInternal.java
@@ -24,8 +24,8 @@ import java.util.Set;
public interface ComponentSpecInternal extends ComponentSpec {
- FunctionalSourceSet getSources();
+ FunctionalSourceSet getFunctionalSourceSet();
- Set<Class<? extends TransformationFileType>> getInputTypes();
+ Set<? extends Class<? extends TransformationFileType>> getInputTypes();
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/DefaultDependencySpecContainer.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/DefaultDependencySpecContainer.java
index 55f8f19..d214d6a 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/DefaultDependencySpecContainer.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/DefaultDependencySpecContainer.java
@@ -16,13 +16,18 @@
package org.gradle.platform.base.internal;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import org.gradle.api.Action;
import org.gradle.platform.base.DependencySpec;
import org.gradle.platform.base.DependencySpecBuilder;
import org.gradle.platform.base.DependencySpecContainer;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
public class DefaultDependencySpecContainer implements DependencySpecContainer {
@@ -48,15 +53,16 @@ public class DefaultDependencySpecContainer implements DependencySpecContainer {
});
}
- private Collection<DependencySpec> getDependencies() {
+ public Collection<DependencySpec> getDependencies() {
if (builders.isEmpty()) {
return Collections.emptySet();
}
- ArrayList<DependencySpec> specs = new ArrayList<DependencySpec>(builders.size());
- for (DefaultDependencySpec.Builder builder : builders) {
- specs.add(builder.build());
- }
- return ImmutableSet.copyOf(specs);
+ return ImmutableSet.copyOf(Lists.transform(builders, new Function<DefaultDependencySpec.Builder, DependencySpec>() {
+ @Override
+ public DependencySpec apply(DefaultDependencySpec.Builder builder) {
+ return builder.build();
+ }
+ }));
}
private DefaultDependencySpec.Builder doCreate(Action<? super DefaultDependencySpec.Builder> action) {
@@ -67,68 +73,7 @@ public class DefaultDependencySpecContainer implements DependencySpecContainer {
}
@Override
- public boolean add(DependencySpec dependencySpec) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int size() {
- return getDependencies().size();
- }
-
- @Override
public boolean isEmpty() {
return builders.isEmpty();
}
-
- @Override
- public boolean contains(Object o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Iterator<DependencySpec> iterator() {
- return getDependencies().iterator();
- }
-
- @Override
- public Object[] toArray() {
- return getDependencies().toArray();
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <T> T[] toArray(T[] a) {
- return (T[]) getDependencies().toArray((DefaultDependencySpec[])a);
- }
-
- @Override
- public boolean remove(Object o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean containsAll(Collection<?> c) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(Collection<? extends DependencySpec> c) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException();
- }
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/VariantAspect.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/VariantAspect.java
new file mode 100644
index 0000000..89f8427
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/VariantAspect.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.platform.base.internal;
+
+import com.google.common.collect.ImmutableSet;
+import org.gradle.model.internal.manage.schema.ModelProperty;
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspect;
+
+import java.util.Set;
+
+public class VariantAspect implements ModelSchemaAspect {
+ private final Set<ModelProperty<?>> dimensions;
+
+ public VariantAspect(Set<ModelProperty<?>> dimensions) {
+ this.dimensions = ImmutableSet.copyOf(dimensions);
+ }
+
+ public Set<ModelProperty<?>> getDimensions() {
+ return dimensions;
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/VariantAspectExtractionStrategy.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/VariantAspectExtractionStrategy.java
new file mode 100644
index 0000000..d68f1d0
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/VariantAspectExtractionStrategy.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.platform.base.internal;
+
+import com.google.common.collect.ImmutableSet;
+import org.gradle.api.Named;
+import org.gradle.api.Nullable;
+import org.gradle.model.internal.manage.schema.ModelProperty;
+import org.gradle.model.internal.manage.schema.extract.*;
+import org.gradle.platform.base.Variant;
+
+import java.util.List;
+
+public class VariantAspectExtractionStrategy implements ModelSchemaAspectExtractionStrategy {
+ @Nullable
+ @Override
+ public ModelSchemaAspectExtractionResult extract(ModelSchemaExtractionContext<?> extractionContext, final List<ModelPropertyExtractionResult<?>> propertyResults) {
+ ImmutableSet.Builder<ModelProperty<?>> dimensionsBuilder = ImmutableSet.builder();
+ for (ModelPropertyExtractionResult<?> propertyResult : propertyResults) {
+ ModelProperty<?> property = propertyResult.getProperty();
+ if (propertyResult.getGetter().isAnnotationPresent(Variant.class)) {
+ Class<?> propertyType = property.getType().getRawClass();
+ if (!String.class.equals(propertyType) && !Named.class.isAssignableFrom(propertyType)) {
+ throw invalidProperty(extractionContext, property, String.format("@Variant annotation only allowed for properties of type String and %s, but property has type %s", Named.class.getName(), propertyType.getName()));
+ }
+ dimensionsBuilder.add(property);
+ }
+ if (propertyResult.getSetter() != null && propertyResult.getSetter().isAnnotationPresent(Variant.class)) {
+ throw invalidProperty(extractionContext, property, "@Variant annotation is only allowed on getter methods");
+ }
+ }
+ ImmutableSet<ModelProperty<?>> dimensions = dimensionsBuilder.build();
+ if (dimensions.isEmpty()) {
+ return null;
+ }
+ return new ModelSchemaAspectExtractionResult(new VariantAspect(dimensions));
+ }
+
+ protected InvalidManagedModelElementTypeException invalidProperty(ModelSchemaExtractionContext<?> extractionContext, ModelProperty<?> property, String message) {
+ return new InvalidManagedModelElementTypeException(extractionContext, String.format("%s (invalid property: %s)", message, property.getName()));
+ }
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/builder/TypeBuilderFactory.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/builder/TypeBuilderFactory.java
new file mode 100644
index 0000000..7c4f615
--- /dev/null
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/builder/TypeBuilderFactory.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.platform.base.internal.builder;
+
+import org.gradle.model.internal.manage.schema.ModelSchema;
+
+public interface TypeBuilderFactory<T> {
+ TypeBuilderInternal<T> create(ModelSchema<? extends T> schema);
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/AbstractTypeBuilder.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/AbstractTypeBuilder.java
index bceaa7d..d0ad70c 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/AbstractTypeBuilder.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/AbstractTypeBuilder.java
@@ -16,18 +16,26 @@
package org.gradle.platform.base.internal.registry;
+import org.gradle.model.internal.manage.schema.ManagedImplModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchema;
import org.gradle.platform.base.InvalidModelException;
import org.gradle.platform.base.internal.builder.TypeBuilderInternal;
public abstract class AbstractTypeBuilder<T> implements TypeBuilderInternal<T> {
private final Class<?> markerAnnotation;
- Class<? extends T> implementation;
+ private final ModelSchema<? extends T> schema;
+ private Class<? extends T> implementation;
- public AbstractTypeBuilder(Class<?> markerAnnotation){
+ public AbstractTypeBuilder(Class<?> markerAnnotation, ModelSchema<? extends T> schema) {
this.markerAnnotation = markerAnnotation;
+ this.schema = schema;
}
+ @Override
public TypeBuilderInternal<T> defaultImplementation(Class<? extends T> implementation) {
+ if (this.schema instanceof ManagedImplModelSchema) {
+ throw new InvalidModelException(String.format("Method annotated with @%s cannot set default implementation for managed type %s.", markerAnnotation.getSimpleName(), schema.getType().getName()));
+ }
if (this.implementation != null) {
throw new InvalidModelException(String.format("Method annotated with @%s cannot set default implementation multiple times.", markerAnnotation.getSimpleName()));
}
@@ -35,6 +43,7 @@ public abstract class AbstractTypeBuilder<T> implements TypeBuilderInternal<T> {
return this;
}
+ @Override
public Class<? extends T> getDefaultImplementation() {
return this.implementation;
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractor.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractor.java
index b6dfe01..4fe1659 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractor.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractor.java
@@ -94,7 +94,7 @@ public class BinaryTasksModelRuleExtractor extends AbstractAnnotationDrivenCompo
public void execute(final MutableModelNode modelNode, final T binary, List<ModelView<?>> inputs) {
NamedEntityInstantiator<Task> taskFactory = Cast.uncheckedCast(ModelViews.getInstance(inputs.get(0), ITaskFactory.class));
- ModelMap<Task> cast = DomainObjectSetBackedModelMap.wrap(
+ ModelMap<Task> cast = DomainObjectCollectionBackedModelMap.wrap(
Task.class,
binary.getTasks(),
taskFactory,
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractor.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractor.java
index ead55bf..e13fb03 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractor.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractor.java
@@ -19,20 +19,21 @@ package org.gradle.platform.base.internal.registry;
import com.google.common.collect.ImmutableList;
import org.gradle.api.NamedDomainObjectFactory;
import org.gradle.api.internal.project.taskfactory.ITaskFactory;
-import org.gradle.internal.reflect.DirectInstantiator;
import org.gradle.internal.reflect.Instantiator;
-import org.gradle.internal.reflect.JavaReflectionUtil;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.language.base.internal.model.BinarySpecFactoryRegistry;
import org.gradle.language.base.plugins.ComponentModelBasePlugin;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.inspect.MethodRuleDefinition;
+import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.type.ModelType;
import org.gradle.platform.base.BinarySpec;
import org.gradle.platform.base.BinaryType;
import org.gradle.platform.base.BinaryTypeBuilder;
import org.gradle.platform.base.binary.BaseBinarySpec;
+import org.gradle.platform.base.internal.builder.TypeBuilderFactory;
import org.gradle.platform.base.internal.builder.TypeBuilderInternal;
import java.util.Arrays;
@@ -41,8 +42,13 @@ import java.util.List;
import static org.gradle.internal.Cast.uncheckedCast;
public class BinaryTypeModelRuleExtractor extends TypeModelRuleExtractor<BinaryType, BinarySpec, BaseBinarySpec> {
- public BinaryTypeModelRuleExtractor() {
- super("binary", BinarySpec.class, BaseBinarySpec.class, BinaryTypeBuilder.class, JavaReflectionUtil.factory(DirectInstantiator.INSTANCE, DefaultBinaryTypeBuilder.class));
+ public BinaryTypeModelRuleExtractor(ModelSchemaStore schemaStore) {
+ super("binary", BinarySpec.class, BaseBinarySpec.class, BinaryTypeBuilder.class, schemaStore, new TypeBuilderFactory<BinarySpec>() {
+ @Override
+ public TypeBuilderInternal<BinarySpec> create(ModelSchema<? extends BinarySpec> schema) {
+ return new DefaultBinaryTypeBuilder(schema);
+ }
+ });
}
@Override
@@ -57,8 +63,8 @@ public class BinaryTypeModelRuleExtractor extends TypeModelRuleExtractor<BinaryT
}
public static class DefaultBinaryTypeBuilder extends AbstractTypeBuilder<BinarySpec> implements BinaryTypeBuilder<BinarySpec> {
- public DefaultBinaryTypeBuilder() {
- super(BinaryType.class);
+ public DefaultBinaryTypeBuilder(ModelSchema<? extends BinarySpec> schema) {
+ super(BinaryType.class, schema);
}
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentModelBaseServiceRegistry.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentModelBaseServiceRegistry.java
index bbf6f1b..a83eadb 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentModelBaseServiceRegistry.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentModelBaseServiceRegistry.java
@@ -16,14 +16,17 @@
package org.gradle.platform.base.internal.registry;
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.project.ProjectRegistry;
+import org.gradle.api.internal.resolve.DefaultProjectModelResolver;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
import org.gradle.internal.service.ServiceRegistration;
-import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.service.scopes.PluginServiceRegistry;
+import org.gradle.language.base.internal.resolve.DependentSourceSetLocalComponentConverter;
import org.gradle.model.internal.inspect.MethodModelRuleExtractor;
-import org.gradle.platform.base.Platform;
-import org.gradle.platform.base.internal.toolchain.DefaultToolResolver;
-import org.gradle.platform.base.internal.toolchain.ToolChainInternal;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractionStrategy;
+import org.gradle.platform.base.internal.VariantAspectExtractionStrategy;
public class ComponentModelBaseServiceRegistry implements PluginServiceRegistry {
@@ -31,38 +34,41 @@ public class ComponentModelBaseServiceRegistry implements PluginServiceRegistry
registration.addProvider(new GlobalScopeServices());
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+
+ }
+
public void registerBuildServices(ServiceRegistration registration){
+ registration.addProvider(new BuildScopeServices());
}
public void registerGradleServices(ServiceRegistration registration) {
}
public void registerProjectServices(ServiceRegistration registration) {
- registration.addProvider(new ProjectScopeServices());
}
- private static class ProjectScopeServices {
- ToolResolver createToolResolver(ServiceRegistry services) {
- DefaultToolResolver toolResolver = new DefaultToolResolver();
- for (ToolChainInternal<?> toolChain : services.getAll(ToolChainInternal.class)) {
- @SuppressWarnings("unchecked") ToolChainInternal<? extends Platform> converted = toolChain;
- toolResolver.registerToolChain(converted);
- }
- return toolResolver;
+ private static class BuildScopeServices {
+ DependentSourceSetLocalComponentConverter createLocalComponentFactory() {
+ return new DependentSourceSetLocalComponentConverter();
+ }
+
+ ProjectModelResolver createProjectLocator(final ProjectRegistry<ProjectInternal> projectRegistry) {
+ return new DefaultProjectModelResolver(projectRegistry);
}
}
private static class GlobalScopeServices {
- MethodModelRuleExtractor createLanguageTypePluginInspector() {
- return new LanguageTypeModelRuleExtractor();
+ MethodModelRuleExtractor createLanguageTypePluginInspector(ModelSchemaStore schemaStore) {
+ return new LanguageTypeModelRuleExtractor(schemaStore);
}
- MethodModelRuleExtractor createComponentModelPluginInspector() {
- return new ComponentTypeModelRuleExtractor();
+ MethodModelRuleExtractor createComponentModelPluginInspector(ModelSchemaStore schemaStore) {
+ return new ComponentTypeModelRuleExtractor(schemaStore);
}
- MethodModelRuleExtractor createBinaryTypeModelPluginInspector() {
- return new BinaryTypeModelRuleExtractor();
+ MethodModelRuleExtractor createBinaryTypeModelPluginInspector(ModelSchemaStore schemaStore) {
+ return new BinaryTypeModelRuleExtractor(schemaStore);
}
MethodModelRuleExtractor createComponentBinariesPluginInspector() {
@@ -71,5 +77,9 @@ public class ComponentModelBaseServiceRegistry implements PluginServiceRegistry
MethodModelRuleExtractor createBinaryTaskPluginInspector() {
return new BinaryTasksModelRuleExtractor();
}
+
+ ModelSchemaAspectExtractionStrategy createVariantAspectExtractionStrategy() {
+ return new VariantAspectExtractionStrategy();
+ }
}
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentTypeModelRuleExtractor.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentTypeModelRuleExtractor.java
index 0c07100..1958c54 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentTypeModelRuleExtractor.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/ComponentTypeModelRuleExtractor.java
@@ -18,9 +18,7 @@ package org.gradle.platform.base.internal.registry;
import com.google.common.collect.ImmutableList;
import org.gradle.api.internal.project.ProjectIdentifier;
-import org.gradle.internal.reflect.DirectInstantiator;
import org.gradle.internal.reflect.Instantiator;
-import org.gradle.internal.reflect.JavaReflectionUtil;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.internal.util.BiFunction;
import org.gradle.language.base.FunctionalSourceSet;
@@ -30,6 +28,8 @@ import org.gradle.language.base.plugins.ComponentModelBasePlugin;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.inspect.MethodRuleDefinition;
+import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.type.ModelType;
import org.gradle.platform.base.ComponentSpec;
import org.gradle.platform.base.ComponentSpecIdentifier;
@@ -38,14 +38,20 @@ import org.gradle.platform.base.ComponentTypeBuilder;
import org.gradle.platform.base.component.BaseComponentSpec;
import org.gradle.platform.base.internal.ComponentSpecFactory;
import org.gradle.platform.base.internal.DefaultComponentSpecIdentifier;
+import org.gradle.platform.base.internal.builder.TypeBuilderFactory;
import org.gradle.platform.base.internal.builder.TypeBuilderInternal;
import java.util.Arrays;
import java.util.List;
public class ComponentTypeModelRuleExtractor extends TypeModelRuleExtractor<ComponentType, ComponentSpec, BaseComponentSpec> {
- public ComponentTypeModelRuleExtractor() {
- super("component", ComponentSpec.class, BaseComponentSpec.class, ComponentTypeBuilder.class, JavaReflectionUtil.factory(DirectInstantiator.INSTANCE, DefaultComponentTypeBuilder.class));
+ public ComponentTypeModelRuleExtractor(ModelSchemaStore schemaStore) {
+ super("component", ComponentSpec.class, BaseComponentSpec.class, ComponentTypeBuilder.class, schemaStore, new TypeBuilderFactory<ComponentSpec>() {
+ @Override
+ public TypeBuilderInternal<ComponentSpec> create(ModelSchema<? extends ComponentSpec> schema) {
+ return new DefaultComponentTypeBuilder(schema);
+ }
+ });
}
@Override
@@ -60,8 +66,8 @@ public class ComponentTypeModelRuleExtractor extends TypeModelRuleExtractor<Comp
}
public static class DefaultComponentTypeBuilder extends AbstractTypeBuilder<ComponentSpec> implements ComponentTypeBuilder<ComponentSpec> {
- public DefaultComponentTypeBuilder() {
- super(ComponentType.class);
+ public DefaultComponentTypeBuilder(ModelSchema<? extends ComponentSpec> schema) {
+ super(ComponentType.class, schema);
}
}
@@ -99,6 +105,7 @@ public class ComponentTypeModelRuleExtractor extends TypeModelRuleExtractor<Comp
final Instantiator instantiator = serviceRegistry.get(Instantiator.class);
final ProjectIdentifier projectIdentifier = ModelViews.assertType(inputs.get(1), ModelType.of(ProjectIdentifier.class)).getInstance();
final ProjectSourceSet projectSourceSet = ModelViews.assertType(inputs.get(2), ModelType.of(ProjectSourceSet.class)).getInstance();
+ final ModelSchemaStore schemaStore = serviceRegistry.get(ModelSchemaStore.class);
@SuppressWarnings("unchecked")
Class<ComponentSpec> publicClass = (Class<ComponentSpec>) publicType.getConcreteClass();
components.register(publicClass, descriptor, new BiFunction<ComponentSpec, String, MutableModelNode>() {
@@ -106,7 +113,7 @@ public class ComponentTypeModelRuleExtractor extends TypeModelRuleExtractor<Comp
public ComponentSpec apply(String name, MutableModelNode modelNode) {
FunctionalSourceSet componentSourceSet = instantiator.newInstance(DefaultFunctionalSourceSet.class, name, instantiator, projectSourceSet);
ComponentSpecIdentifier id = new DefaultComponentSpecIdentifier(projectIdentifier.getPath(), name);
- return BaseComponentSpec.create(implementationType.getConcreteClass(), id, modelNode, componentSourceSet, instantiator);
+ return BaseComponentSpec.create(implementationType.getConcreteClass(), id, modelNode, componentSourceSet, instantiator, schemaStore);
}
});
}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/LanguageTypeModelRuleExtractor.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/LanguageTypeModelRuleExtractor.java
index 4787006..e07bd23 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/LanguageTypeModelRuleExtractor.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/LanguageTypeModelRuleExtractor.java
@@ -18,9 +18,7 @@ package org.gradle.platform.base.internal.registry;
import com.google.common.collect.ImmutableList;
import org.gradle.api.internal.file.FileResolver;
-import org.gradle.internal.reflect.DirectInstantiator;
import org.gradle.internal.reflect.Instantiator;
-import org.gradle.internal.reflect.JavaReflectionUtil;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.language.base.LanguageSourceSet;
import org.gradle.language.base.internal.registry.LanguageRegistry;
@@ -30,10 +28,13 @@ import org.gradle.language.base.sources.BaseLanguageSourceSet;
import org.gradle.model.internal.core.*;
import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor;
import org.gradle.model.internal.inspect.MethodRuleDefinition;
+import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.type.ModelType;
import org.gradle.platform.base.LanguageType;
import org.gradle.platform.base.LanguageTypeBuilder;
import org.gradle.platform.base.internal.builder.LanguageTypeBuilderInternal;
+import org.gradle.platform.base.internal.builder.TypeBuilderFactory;
import org.gradle.platform.base.internal.builder.TypeBuilderInternal;
import org.gradle.platform.base.internal.util.ImplementationTypeDetermer;
@@ -42,8 +43,13 @@ import java.util.List;
public class LanguageTypeModelRuleExtractor extends TypeModelRuleExtractor<LanguageType, LanguageSourceSet, BaseLanguageSourceSet> {
public ImplementationTypeDetermer<LanguageSourceSet, BaseLanguageSourceSet> implementationTypeDetermer = new ImplementationTypeDetermer<LanguageSourceSet, BaseLanguageSourceSet>("language", BaseLanguageSourceSet.class);
- public LanguageTypeModelRuleExtractor() {
- super("language", LanguageSourceSet.class, BaseLanguageSourceSet.class, LanguageTypeBuilder.class, JavaReflectionUtil.factory(DirectInstantiator.INSTANCE, DefaultLanguageTypeBuilder.class));
+ public LanguageTypeModelRuleExtractor(ModelSchemaStore schemaStore) {
+ super("language", LanguageSourceSet.class, BaseLanguageSourceSet.class, LanguageTypeBuilder.class, schemaStore, new TypeBuilderFactory<LanguageSourceSet>() {
+ @Override
+ public TypeBuilderInternal<LanguageSourceSet> create(ModelSchema<? extends LanguageSourceSet> schema) {
+ return new DefaultLanguageTypeBuilder(schema);
+ }
+ });
}
@Override
@@ -60,8 +66,8 @@ public class LanguageTypeModelRuleExtractor extends TypeModelRuleExtractor<Langu
public static class DefaultLanguageTypeBuilder extends AbstractTypeBuilder<LanguageSourceSet> implements LanguageTypeBuilderInternal<LanguageSourceSet> {
private String languageName;
- public DefaultLanguageTypeBuilder() {
- super(LanguageType.class);
+ public DefaultLanguageTypeBuilder(ModelSchema<? extends LanguageSourceSet> schema) {
+ super(LanguageType.class, schema);
}
@Override
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/TypeModelRuleExtractor.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/TypeModelRuleExtractor.java
index 714b37a..a56eb70 100644
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/TypeModelRuleExtractor.java
+++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/registry/TypeModelRuleExtractor.java
@@ -18,13 +18,15 @@ package org.gradle.platform.base.internal.registry;
import org.apache.commons.lang.StringUtils;
import org.gradle.api.Nullable;
-import org.gradle.internal.Factory;
import org.gradle.model.InvalidModelRuleDeclarationException;
-import org.gradle.model.internal.core.ModelReference;
import org.gradle.model.internal.core.ExtractedModelRule;
+import org.gradle.model.internal.core.ModelReference;
import org.gradle.model.internal.inspect.MethodRuleDefinition;
+import org.gradle.model.internal.manage.schema.ModelSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.type.ModelType;
import org.gradle.platform.base.InvalidModelException;
+import org.gradle.platform.base.internal.builder.TypeBuilderFactory;
import org.gradle.platform.base.internal.builder.TypeBuilderInternal;
import java.lang.annotation.Annotation;
@@ -35,10 +37,12 @@ public abstract class TypeModelRuleExtractor<A extends Annotation, T, U extends
private final ModelType<T> baseInterface;
private final ModelType<U> baseImplementation;
private final ModelType<?> builderInterface;
- private final Factory<? extends TypeBuilderInternal<T>> typeBuilderFactory;
+ private final ModelSchemaStore schemaStore;
+ private final TypeBuilderFactory<T> typeBuilderFactory;
- public TypeModelRuleExtractor(String modelName, Class<T> baseInterface, Class<U> baseImplementation, Class<?> builderInterface, Factory<? extends TypeBuilderInternal<T>> typeBuilderFactory) {
+ public TypeModelRuleExtractor(String modelName, Class<T> baseInterface, Class<U> baseImplementation, Class<?> builderInterface, ModelSchemaStore schemaStore, TypeBuilderFactory<T> typeBuilderFactory) {
this.modelName = modelName;
+ this.schemaStore = schemaStore;
this.typeBuilderFactory = typeBuilderFactory;
this.baseInterface = ModelType.of(baseInterface);
this.baseImplementation = ModelType.of(baseImplementation);
@@ -48,7 +52,8 @@ public abstract class TypeModelRuleExtractor<A extends Annotation, T, U extends
public <R, S> ExtractedModelRule registration(MethodRuleDefinition<R, S> ruleDefinition) {
try {
ModelType<? extends T> type = readType(ruleDefinition);
- TypeBuilderInternal<T> builder = typeBuilderFactory.create();
+ ModelSchema<? extends T> schema = schemaStore.getSchema(type);
+ TypeBuilderInternal<T> builder = typeBuilderFactory.create(schema);
ruleDefinition.getRuleInvoker().invoke(builder);
return createRegistration(ruleDefinition, type, builder);
} catch (InvalidModelException e) {
@@ -118,4 +123,4 @@ public abstract class TypeModelRuleExtractor<A extends Annotation, T, U extends
return asSubclass;
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultResolvedCompiler.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultResolvedCompiler.java
deleted file mode 100644
index 9dda1be..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultResolvedCompiler.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.platform.base.internal.toolchain;
-
-import org.gradle.language.base.internal.compile.*;
-import org.gradle.language.base.internal.compile.Compiler;
-import org.gradle.util.TreeVisitor;
-
-public class DefaultResolvedCompiler<C extends CompileSpec> implements ResolvedTool<org.gradle.language.base.internal.compile.Compiler<C>> {
- private final ToolProvider provider;
- private final Class<C> specType;
-
- public DefaultResolvedCompiler(ToolProvider provider, Class<C> specType) {
- this.provider = provider;
- this.specType = specType;
- }
-
- @Override
- public Compiler<C> get() {
- return provider.newCompiler(specType);
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public void explain(TreeVisitor<? super String> visitor) {
- }
-}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultResolvedTool.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultResolvedTool.java
deleted file mode 100644
index 6cce4fb..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultResolvedTool.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.platform.base.internal.toolchain;
-
-import org.gradle.util.TreeVisitor;
-
-public class DefaultResolvedTool<T> implements ResolvedTool<T> {
- private final ToolProvider provider;
- private final Class<T> toolType;
-
- public DefaultResolvedTool(ToolProvider provider, Class<T> toolType) {
- this.provider = provider;
- this.toolType = toolType;
- }
-
- @Override
- public T get() {
- return provider.get(toolType);
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public void explain(TreeVisitor<? super String> visitor) {
- }
-}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultToolResolver.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultToolResolver.java
deleted file mode 100644
index e4822a2..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/DefaultToolResolver.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.platform.base.internal.toolchain;
-
-import com.google.common.collect.Sets;
-
-import org.gradle.api.GradleException;
-import org.gradle.internal.text.TreeFormatter;
-import org.gradle.language.base.internal.compile.CompileSpec;
-import org.gradle.language.base.internal.compile.Compiler;
-import org.gradle.platform.base.Platform;
-import org.gradle.util.TreeVisitor;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Set;
-
-public class DefaultToolResolver implements ToolResolver {
- private Set<ToolChainInternal<? extends Platform>> toolChains;
-
- public DefaultToolResolver() {
- this.toolChains = Sets.newHashSet();
- }
-
- public void registerToolChain(ToolChainInternal<? extends Platform> toolChain) {
- toolChains.add(toolChain);
- }
-
- /**
- * Finds the most inherited Platform parameter type of the select method on a toolchain. It assumes that
- * a ToolChainInternal has only one public declared select method.
- */
- private Class<? extends Platform> getPlatformType(ToolChainInternal<? extends Platform> toolChain) {
- //TODO Do we want to support ToolChains with select methods for multiple platform types?
- Class<?> toolChainClass = toolChain.getClass();
- Class<? extends Platform> platformType = null;
- for (Method method : toolChainClass.getMethods()) {
- if (method.getName().equals("select") && Modifier.isPublic(method.getModifiers())) {
- Class<?>[] parameterTypes = method.getParameterTypes();
- if (parameterTypes.length == 1 && Platform.class.isAssignableFrom(parameterTypes[0])) {
- @SuppressWarnings("unchecked") Class<? extends Platform> converted = (Class<? extends Platform>) parameterTypes[0];
- // Check to see if this type is more inherited than what has already been found
- // This filters out any methods from parent classes/interfaces
- if (platformType == null || platformType.isAssignableFrom(converted)) {
- platformType = converted;
- }
- }
- }
- }
- return platformType;
- }
-
- /**
- * Filters the list of toolchains for only those that support the given platform
- */
- private <P extends Platform> Set<ToolChainInternal<P>> filterToolChains(P platform) {
- Set<ToolChainInternal<P>> platformToolChains = Sets.newHashSet();
- for (ToolChainInternal<? extends Platform> raw : toolChains) {
- if (getPlatformType(raw).isAssignableFrom(platform.getClass())) {
- @SuppressWarnings("unchecked") ToolChainInternal<P> converted = (ToolChainInternal<P>) raw;
- platformToolChains.add(converted);
- }
- }
- return platformToolChains;
- }
-
- protected <P extends Platform> ToolSearchResult findToolProvider(P requirement) {
- ToolSearchFailure notAvailableResult = new ToolSearchFailure("No tool chains can satisfy the requirement");
- for (ToolChainInternal<P> toolChain : filterToolChains(requirement)) {
- ToolSearchResult result = toolChain.select(requirement);
- if (result.isAvailable()) {
- return result;
- } else {
- notAvailableResult.addResult(result);
- }
- }
- return notAvailableResult;
- }
-
- @Override
- public <P extends Platform> ToolSearchResult checkToolAvailability(P requirement) {
- return findToolProvider(requirement);
- }
-
- @Override
- public <T, P extends Platform> ResolvedTool<T> resolve(Class<T> toolType, P requirement) {
- ToolSearchResult toolProvider = findToolProvider(requirement);
- if (toolProvider.isAvailable()) {
- return new DefaultResolvedTool<T>((ToolProvider)toolProvider, toolType);
- } else {
- ResolvedToolSearchFailure<T> notAvailableResult = new ResolvedToolSearchFailure<T>(String.format("No tool chains can provide a tool of type %s", toolType.getSimpleName()));
- notAvailableResult.addResult(toolProvider);
- return notAvailableResult;
- }
- }
-
- @Override
- public <C extends CompileSpec, P extends Platform> ResolvedTool<Compiler<C>> resolveCompiler(Class<C> specType, P requirement) {
- ToolSearchResult toolProvider = findToolProvider(requirement);
- if (toolProvider.isAvailable()) {
- return new DefaultResolvedCompiler<C>((ToolProvider)toolProvider, specType);
- } else {
- CompilerSearchFailure<C> notAvailableResult = new CompilerSearchFailure<C>(String.format("No tool chains can provide a compiler for type %s", specType.getSimpleName()));
- notAvailableResult.addResult(toolProvider);
- return notAvailableResult;
- }
- }
-
- private static class ResolvedToolSearchFailure<T> extends ToolSearchFailure implements ResolvedTool<T> {
- public ResolvedToolSearchFailure(String message) {
- super(message);
- }
-
- @Override
- public T get() {
- throw failure();
- }
- }
-
- private static class CompilerSearchFailure<T extends CompileSpec> extends ToolSearchFailure implements ResolvedTool<Compiler<T>> {
- public CompilerSearchFailure(String message) {
- super(message);
- }
-
- @Override
- public Compiler<T> get() {
- throw failure();
- }
- }
-
- private static class ToolSearchFailure implements ToolSearchResult {
- private final String message;
- Set<ToolSearchResult> results = Sets.newHashSet();
-
- public ToolSearchFailure(String message) {
- this.message = message;
- }
-
- @Override
- public boolean isAvailable() {
- return false;
- }
-
- @Override
- public void explain(TreeVisitor<? super String> visitor) {
- visitor.node(message);
- visitor.startChildren();
- for (ToolSearchResult result : results) {
- result.explain(visitor);
- }
- visitor.endChildren();
- }
-
- RuntimeException failure() {
- TreeFormatter formatter = new TreeFormatter();
- explain(formatter);
- return new GradleException(formatter.toString());
- }
-
- void addResult(ToolSearchResult result) {
- results.add(result);
- }
- }
-}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/ResolvedTool.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/ResolvedTool.java
deleted file mode 100644
index 0eeb10d..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/ResolvedTool.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.platform.base.internal.toolchain;
-
-public interface ResolvedTool<T> extends ToolSearchResult {
- public T get();
-}
diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/ToolResolver.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/ToolResolver.java
deleted file mode 100644
index c982b7e..0000000
--- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/internal/toolchain/ToolResolver.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.platform.base.internal.toolchain;
-
-import org.gradle.language.base.internal.compile.CompileSpec;
-import org.gradle.platform.base.Platform;
-import org.gradle.language.base.internal.compile.Compiler;
-
-public interface ToolResolver {
- <P extends Platform> ToolSearchResult checkToolAvailability(P requirement);
-
- <T, P extends Platform> ResolvedTool<T> resolve(Class<T> toolType, P requirement);
-
- <C extends CompileSpec, P extends Platform> ResolvedTool<Compiler<C>> resolveCompiler(Class<C> specType, P requirement);
-}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/api/internal/resolve/VariantsMatcherTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/api/internal/resolve/VariantsMatcherTest.groovy
new file mode 100644
index 0000000..b0c1532
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/api/internal/resolve/VariantsMatcherTest.groovy
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.resolve
+import org.gradle.api.Named
+import org.gradle.language.base.internal.model.DefaultVariantDimensionSelectorFactory
+import org.gradle.language.base.internal.model.DefaultVariantsMetaData
+import org.gradle.language.base.internal.model.VariantDimensionSelector
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractor
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaExtractor
+import org.gradle.platform.base.BinarySpec
+import org.gradle.platform.base.Platform
+import org.gradle.platform.base.Variant
+import org.gradle.platform.base.internal.VariantAspectExtractionStrategy
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class VariantsMatcherTest extends Specification {
+ def schemaStore = new DefaultModelSchemaStore(new ModelSchemaExtractor([], new ModelSchemaAspectExtractor([new VariantAspectExtractionStrategy()])))
+
+ @Unroll
+ def "should filter binaries based on requirements"() {
+ given: "a library binary with some requirements"
+
+ def factories = [DefaultVariantDimensionSelectorFactory.of(MyPlatform, new MySelector())]
+ def matcher = new VariantsMatcher(factories, CustomSpecBase, schemaStore)
+ def reference = DefaultVariantsMetaData.extractFrom(spec, schemaStore)
+
+ when: "we filter binaries based on requirements"
+ def filtered = matcher.filterBinaries(reference, binaries)
+
+ then: "only the expected binaries are returned"
+ filtered as Set == expected as Set
+
+ where:
+ spec | binaries | expected
+ refSpec() | [] | []
+ refSpec() | [Mock(CustomSpecBase)] | []
+ refSpec() | [refSpec()] | [refSpec()]
+ refSpec('1.7') | [refSpec('1.6')] | [refSpec('1.6')]
+ refSpec('1.6') | [refSpec('1.7')] | []
+ refSpec('1.6') | [refSpec('1.5'), refSpec('1.6'), refSpec('1.7')] | [refSpec('1.6')]
+ refSpec() | [customSpec1()] | [customSpec1()]
+ customSpec1() | [customSpec1()] | [customSpec1()]
+ refSpec() | [customSpec1(), customSpec1('1.7', 'paid')] | [customSpec1(), customSpec1('1.7', 'paid')]
+ customSpec1() | [customSpec1(), customSpec1('1.7', 'paid')] | [customSpec1()]
+ customSpec1('1.7', null) | [customSpec1(), customSpec1('1.7', 'paid')] | [customSpec1(), customSpec1('1.7', 'paid')]
+ customSpec1('1.7', 'paid') | [customSpec1(), customSpec1('1.7', 'paid')] | [customSpec1('1.7', 'paid')]
+ customSpec1('1.6', 'paid') | [customSpec1(), customSpec1('1.7', 'paid'), customSpec1('1.6', 'paid')] | [customSpec1('1.6', 'paid')]
+ customSpec1('1.7', 'paid') | [customSpec1(), customSpec1('1.7', 'paid'), customSpec1('1.6', 'paid')] | [customSpec1('1.7', 'paid')]
+ customSpec1('1.7', 'paid') | [customSpec2(), customSpec1('1.6', 'free'), customSpec1('1.7', 'paid'), customSpec1('1.6', 'paid')] | [customSpec1('1.7', 'paid')]
+ customSpec1() | [customSpec2()] | [customSpec2()]
+ customSpec2('1.7', null, null) | [refSpec()] | [refSpec()]
+ customSpec2('1.7', 'free', null) | [customSpec1()] | [customSpec1()]
+ customSpec2() | [customSpec2()] | [customSpec2()]
+ customSpec2('1.7', 'paid', 'debug') | [customSpec2()] | []
+ customSpec2('1.7', 'paid', 'debug') | [customSpec2('1.7', null, 'debug')] | [customSpec2('1.7', null, 'debug')]
+ customSpec2('1.7', 'paid', 'debug') | [customSpec2('1.6', 'paid', null), customSpec2('1.6', null, 'debug')] | [customSpec2('1.6', 'paid', null), customSpec2('1.6', null, 'debug')]
+ customSpec2('1.7', 'paid', 'debug') | [customSpec2('1.6', 'paid', null), customSpec2('1.6', null, 'debug'), customSpec2('1.7', null, null)] | [customSpec2('1.7', null, null)]
+ customSpec2('1.7', 'paid', 'debug') | [customSpec2('1.6', 'paid', null), customSpec2('1.6', null, 'debug'), customSpec2('1.7', null, 'debug'), customSpec2('1.7', 'paid', 'debug')] | [customSpec2('1.7', null, 'debug'), customSpec2('1.7', 'paid', 'debug')]
+ customSpec2() | [customSpec3()] | [customSpec3()]
+ customSpec3() | [customSpec2()] | []
+ customSpec2('1.6', 'paid', 'debug') | [customSpec2('1.6', 'paid', 'debug'), customSpec3('1.6', 'paid', 'debug', 'bar')] | [customSpec2('1.6', 'paid', 'debug'), customSpec3('1.6', 'paid', 'debug', 'bar')]
+ customSpec2('1.6', 'paid', 'debug') | [customSpec3('1.6', 'paid', 'debug', 'foo'), customSpec3('1.6', 'paid', 'debug', 'bar')] | [customSpec3('1.6', 'paid', 'debug', 'foo'), customSpec3('1.6', 'paid', 'debug', 'bar')]
+ }
+
+ @Unroll
+ def "can use a custom variant comparator"() {
+ def factories = [
+ DefaultVariantDimensionSelectorFactory.of(MyPlatform, new MySelector()),
+ DefaultVariantDimensionSelectorFactory.of(BuildType, new VariantDimensionSelector<BuildType>() {
+ @Override
+ boolean isCompatibleWithRequirement(BuildType requirement, BuildType value) {
+ requirement.name.length() == value.name.length()
+ }
+
+ @Override
+ boolean betterFit(BuildType requirement, BuildType first, BuildType second) {
+ second.name == requirement.name
+ }
+ })
+ ]
+ def matcher = new VariantsMatcher(factories, CustomSpecBase, schemaStore)
+ def reference = DefaultVariantsMetaData.extractFrom(spec, schemaStore)
+
+ when: "we filter binaries based on requirements"
+ def filtered = matcher.filterBinaries(reference, binaries)
+
+ then: "only the expected binaries are returned"
+ filtered as Set == expected as Set
+
+ where:
+ spec | binaries | expected
+ customSpec2() | [customSpec2()] | [customSpec2()]
+ customSpec2('1.7', 'paid', 'XXX') | [customSpec2('1.7', 'paid', 'XXX')] | [customSpec2('1.7', 'paid', 'XXX')]
+ customSpec2('1.7', 'paid', 'XXX') | [customSpec2('1.7', 'paid', 'YYY')] | [customSpec2('1.7', 'paid', 'YYY')]
+ customSpec2('1.7', 'paid', 'XXX') | [customSpec2('1.7', 'paid', 'YYYY')] | []
+ customSpec2('1.7', 'paid', null) | [customSpec2('1.7', 'paid', 'YYYY')] | [customSpec2('1.7', 'paid', 'YYYY')]
+ customSpec2('1.7', 'paid', 'XXX') | [customSpec2('1.7', 'paid', null)] | [customSpec2('1.7', 'paid', null)]
+ customSpec2('1.7', 'paid', 'XXX') | [customSpec2('1.7', 'paid', 'XXX'), customSpec2('1.7', 'paid', 'YYY')] | [customSpec2('1.7', 'paid', 'XXX')]
+ customSpec2('1.7', 'paid', 'XXX') | [customSpec2('1.7', 'paid', 'ZZZ'), customSpec2('1.7', 'paid', 'YYY')] | [customSpec2('1.7', 'paid', 'YYY'), customSpec2('1.7', 'paid', 'ZZZ')]
+
+ }
+
+ private CustomSpecBase refSpec(String version = '1.7') {
+ def spec = Mock(CustomSpecBase)
+ spec.targetPlatform >> new MyPlatform(name:version)
+ spec.displayName >> { "CustomBinarySpec ($spec.targetPlatform)" }
+ spec.equals(_) >> { args -> spec.displayName == args[0].displayName }
+ spec.hashCode() >> { spec.displayName.hashCode() }
+ spec.toString() >> { spec.displayName }
+ spec
+ }
+
+ private CustomSpec1 customSpec1(String version = '1.7', String flavor = 'free') {
+ def spec = Mock(CustomSpec1)
+ spec.targetPlatform >> new MyPlatform(name:version)
+ spec.flavor >> flavor
+ spec.displayName >> { "CustomSpec1 ($version, $flavor)" }
+ spec.equals(_) >> { args -> spec.displayName == args[0].displayName }
+ spec.hashCode() >> { spec.displayName.hashCode() }
+ spec.toString() >> { spec.displayName }
+ spec
+ }
+
+ private CustomSpec2 customSpec2(String version = '1.7', String flavor = 'free', String buildType = 'release') {
+ def spec = Mock(CustomSpec2)
+ spec.targetPlatform >> new MyPlatform(name:version)
+ spec.flavor >> flavor
+ spec.buildType >> { buildType ? new BuildType(name: buildType) : null }
+ spec.displayName >> { "CustomSpec2 ($version, $flavor, $buildType)" }
+ spec.equals(_) >> { args -> spec.displayName == args[0].displayName }
+ spec.hashCode() >> { spec.displayName.hashCode() }
+ spec.toString() >> { spec.displayName }
+ spec
+ }
+
+ private CustomSpec3 customSpec3(String version = '1.7', String flavor = 'free', String buildType = 'release', String customValue = 'foo') {
+ def spec = Mock(CustomSpec3)
+ spec.targetPlatform >> new MyPlatform(name:version)
+ spec.flavor >> flavor
+ spec.buildType >> { buildType ? new BuildType2(name: buildType, customValue: customValue) : null }
+ spec.displayName >> { "CustomSpec3 ($version, $flavor, $buildType, $customValue)" }
+ spec.equals(_) >> { args -> spec.displayName == args[0].displayName }
+ spec.hashCode() >> { spec.displayName.hashCode() }
+ spec.toString() >> { spec.displayName }
+ spec
+ }
+
+ static interface CustomSpecBase extends BinarySpec {
+ @Variant
+ Platform getTargetPlatform()
+ }
+
+ static interface CustomSpec1 extends CustomSpecBase {
+ @Variant
+ String getFlavor()
+ }
+
+ static interface CustomSpec2 extends CustomSpecBase {
+ @Variant
+ String getFlavor()
+
+ @Variant
+ BuildType getBuildType()
+ }
+
+ static interface CustomSpec3 extends CustomSpecBase {
+ @Variant
+ String getFlavor()
+
+ @Variant
+ BuildType2 getBuildType()
+ }
+
+ static class BuildType implements Named {
+ String name
+ }
+
+ static class BuildType2 extends BuildType {
+ String customValue
+ }
+
+ static class MyPlatform implements Platform {
+ String name
+
+ @Override
+ String getDisplayName() {
+ "Java $name"
+ }
+
+ @Override
+ String getName() {
+ name
+ }
+
+
+ @Override
+ public String toString() {
+ displayName
+ }
+ }
+
+ static class MySelector implements VariantDimensionSelector<MyPlatform> {
+ private static int v(MyPlatform platform) {
+ Integer.valueOf(platform.name.replaceAll(/\./,''))
+ }
+
+ @Override
+ boolean isCompatibleWithRequirement(MyPlatform requirement, MyPlatform value) {
+ v(requirement) >= v(value)
+ }
+
+ @Override
+ boolean betterFit(MyPlatform requirement, MyPlatform first, MyPlatform second) {
+ v(first) < v(second)
+ }
+ }
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/ComponentTypeModelRuleExtractorTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/ComponentTypeModelRuleExtractorTest.groovy
index c3d97c4..d6a8a20 100644
--- a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/ComponentTypeModelRuleExtractorTest.groovy
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/ComponentTypeModelRuleExtractorTest.groovy
@@ -15,12 +15,14 @@
*/
package org.gradle.language.base.internal
-
+import org.gradle.language.base.internal.testinterfaces.NotComponentSpec
+import org.gradle.language.base.internal.testinterfaces.SomeComponentSpec
import org.gradle.language.base.plugins.ComponentModelBasePlugin
import org.gradle.model.InvalidModelRuleDeclarationException
import org.gradle.model.internal.core.ExtractedModelRule
import org.gradle.model.internal.core.ModelActionRole
import org.gradle.model.internal.core.ModelReference
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.model.internal.type.ModelType
import org.gradle.platform.base.*
import org.gradle.platform.base.component.BaseComponentSpec
@@ -33,7 +35,7 @@ import java.lang.annotation.Annotation
class ComponentTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtractorTest {
final static ModelType<ComponentSpecFactory> FACTORY_REGISTRY_TYPE = ModelType.of(ComponentSpecFactory)
- ComponentTypeModelRuleExtractor ruleHandler = new ComponentTypeModelRuleExtractor()
+ ComponentTypeModelRuleExtractor ruleHandler = new ComponentTypeModelRuleExtractor(DefaultModelSchemaStore.getInstance())
@Override
Class<? extends Annotation> getAnnotation() { return ComponentType }
@@ -91,14 +93,12 @@ class ComponentTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExt
"noDefaultConstructor" | "Component implementation '${NoDefaultConstructor.name}' must have public default constructor." | "implementation with no public default constructor"
}
- interface SomeComponentSpec extends ComponentSpec {}
+
static class SomeComponentSpecImpl extends BaseComponentSpec implements SomeComponentSpec {}
static class SomeComponentSpecOtherImpl extends SomeComponentSpecImpl {}
- interface NotComponentSpec {}
-
static class NotImplementingCustomComponent extends BaseComponentSpec implements ComponentSpec {}
abstract static class NotExtendingBaseComponentSpec implements SomeComponentSpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/SourceSetNotationParserTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/SourceSetNotationParserTest.groovy
deleted file mode 100644
index 8cd7b45..0000000
--- a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/SourceSetNotationParserTest.groovy
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.language.base.internal
-import org.gradle.internal.reflect.DirectInstantiator
-import org.gradle.language.base.LanguageSourceSet
-import org.gradle.language.base.ProjectSourceSet
-import spock.lang.Specification
-
-class SourceSetNotationParserTest extends Specification {
- def projectSources = Mock(ProjectSourceSet)
- def parser = SourceSetNotationParser.parser()
- def languageSourceSet1 = languageSourceSet("lss1")
- def languageSourceSet2 = languageSourceSet("lss2")
-
- def "translates single LanguageSourceSet"() {
- expect:
- parser.parseNotation(languageSourceSet1) as List == [languageSourceSet1]
- }
-
- def "collects all LanguageSourceSets for a FunctionalSourceSet"() {
- when:
- def functionalSourceSet = new DefaultFunctionalSourceSet("func", DirectInstantiator.INSTANCE, projectSources)
- functionalSourceSet.add(languageSourceSet1)
- functionalSourceSet.add(languageSourceSet2)
-
- then:
- parser.parseNotation(functionalSourceSet) as List == [languageSourceSet1, languageSourceSet2]
- }
-
- def "collects all LanguageSourceSets in a collection"() {
- expect:
- parser.parseNotation([languageSourceSet1, languageSourceSet2]) as List == [languageSourceSet1, languageSourceSet2]
- parser.parseNotation([languageSourceSet2, languageSourceSet1]) as List == [languageSourceSet2, languageSourceSet1]
- }
-
- private LanguageSourceSet languageSourceSet(def name) {
- Stub(LanguageSourceSet) {
- getName() >> name
- }
- }
-}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/DefaultVariantsMetaDataTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/DefaultVariantsMetaDataTest.groovy
new file mode 100644
index 0000000..481f5d0
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/DefaultVariantsMetaDataTest.groovy
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model
+import org.gradle.api.Named
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractor
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaExtractor
+import org.gradle.platform.base.BinarySpec
+import org.gradle.platform.base.Variant
+import org.gradle.platform.base.internal.VariantAspectExtractionStrategy
+import spock.lang.Specification
+
+class DefaultVariantsMetaDataTest extends Specification {
+ def schemaStore = new DefaultModelSchemaStore(new ModelSchemaExtractor([], new ModelSchemaAspectExtractor([new VariantAspectExtractionStrategy()])))
+
+ def "should extract variants from a binary spec"() {
+ given:
+ def spec = Mock(MyBinarySpec)
+
+ when:
+ spec.platform >> platform
+ spec.flavor >> flavor
+ spec.buildType >> buildType
+ spec.notVariantDimension >> notVariantDimension
+ def variants = DefaultVariantsMetaData.extractFrom(spec, schemaStore)
+
+ then:
+ variants.nonNullDimensions == (nonNullDimensions as Set)
+ variants.allDimensions == (allDimensions as Set)
+ variants.getValueAsString('platform') == platform
+ variants.getValueAsString('flavor') == flavor
+ variants.getValueAsString('buildType') == buildType?.name
+ variants.getValueAsType(BuildType, 'buildType') == buildType
+ variants.getValueAsString('notVariantDimension') == null
+
+ where:
+ platform | flavor | buildType | notVariantDimension | nonNullDimensions | allDimensions
+ 'java6' | null | null | null | ['platform'] | ['platform', 'flavor', 'buildType']
+ 'java6' | null | null | 'foo' | ['platform'] | ['platform', 'flavor', 'buildType']
+ 'java6' | 'debug' | null | null | ['platform', 'flavor'] | ['platform', 'flavor', 'buildType']
+ 'java6' | 'debug' | Mock(BuildType) | null | ['platform', 'flavor', 'buildType'] | ['platform', 'flavor', 'buildType']
+
+ }
+
+ private static interface MyBinarySpec extends BinarySpec {
+ @Variant
+ String getPlatform()
+
+ @Variant
+ String getFlavor()
+
+ @Variant
+ BuildType getBuildType()
+
+ String getNotVariantDimension()
+ }
+
+ private static interface BuildType extends Named {}
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedBinaryString.java b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedBinaryString.java
new file mode 100644
index 0000000..7ae46f5
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedBinaryString.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model;
+
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.Variant;
+
+// Separate Java class because IBM JDK 6
+public interface ParametrizedBinaryString extends BinarySpec {
+ @Variant
+ ParametrizedVariant<String> getVariant();
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedBinaryVariantDimension1.java b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedBinaryVariantDimension1.java
new file mode 100644
index 0000000..9dc923e
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedBinaryVariantDimension1.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model;
+
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.Variant;
+
+// Separate Java class because IBM JDK 6
+public interface ParametrizedBinaryVariantDimension1 extends BinarySpec {
+ @Variant
+ ParametrizedVariant<VariantDimension1> getVariant();
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedVariant.java b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedVariant.java
new file mode 100644
index 0000000..907e65f
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/ParametrizedVariant.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model;
+
+import org.gradle.api.Named;
+
+// Separate Java class because IBM JDK 6
+public interface ParametrizedVariant<T> extends Named {
+ T blah();
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension1.java b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension1.java
new file mode 100644
index 0000000..951ce93
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension1.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model;
+
+import org.gradle.api.Named;
+
+// Separate Java class because IBM JDK 6
+public interface VariantDimension1 extends Named {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension2.java b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension2.java
new file mode 100644
index 0000000..7d1cbc4
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension2.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model;
+
+import org.gradle.api.Named;
+
+// Separate Java class because IBM JDK 6
+public interface VariantDimension2 extends Named {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension3.java b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension3.java
new file mode 100644
index 0000000..eb3829e
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantDimension3.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model;
+
+// Separate Java class because IBM JDK 6
+public interface VariantDimension3 extends VariantDimension1 {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantsMetaDataHelperTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantsMetaDataHelperTest.groovy
new file mode 100644
index 0000000..b3e66c4
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/model/VariantsMetaDataHelperTest.groovy
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.model
+
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractor
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaExtractor
+import org.gradle.platform.base.BinarySpec
+import org.gradle.platform.base.Platform
+import org.gradle.platform.base.Variant
+import org.gradle.platform.base.internal.VariantAspectExtractionStrategy
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class VariantsMetaDataHelperTest extends Specification {
+
+ def schemaStore = new DefaultModelSchemaStore(new ModelSchemaExtractor([], new ModelSchemaAspectExtractor([new VariantAspectExtractionStrategy()])))
+
+ @Unroll("Incompatible variant dimensions for #referenceClass.simpleName(#dimensions) onto #candidateClass.simpleName are #expectedIncompatible")
+ def "computes the set of incompatible variant dimensions"() {
+ given:
+ def reference = DefaultVariantsMetaData.extractFrom(Mock(referenceClass), schemaStore)
+ def candidate = DefaultVariantsMetaData.extractFrom(Mock(candidateClass), schemaStore)
+
+ when:
+ def incompatibleDimensions = VariantsMetaDataHelper.incompatibleDimensionTypes(reference, candidate, dimensions as Set)
+
+ then:
+ incompatibleDimensions == (expectedIncompatible as Set)
+
+ where:
+ referenceClass | candidateClass | dimensions | expectedIncompatible
+ Binary1 | Binary1 | ['variant1', 'variant2', 'platform'] | []
+ Binary1 | Binary1 | ['variant1'] | []
+ Binary1 | Binary2 | ['variant1', 'variant2', 'platform'] | ['variant2']
+ Binary2 | Binary3 | ['variant1', 'variant2', 'platform'] | ['variant2']
+ Binary2 | Binary4 | ['variant1', 'variant2', 'platform'] | []
+ ParametrizedBinaryString | ParametrizedBinaryString | ['variant'] | []
+ ParametrizedBinaryVariantDimension1 | ParametrizedBinaryVariantDimension1 | ['variant'] | []
+ ParametrizedBinaryString | ParametrizedBinaryVariantDimension1 | ['variant'] | ['variant']
+ }
+
+ public static interface Binary1 extends BinarySpec {
+ @Variant
+ String getVariant1()
+
+ @Variant
+ String getVariant2()
+
+ @Variant
+ Platform getPlatform()
+ }
+
+ public static interface Binary2 extends BinarySpec {
+ @Variant
+ String getVariant1()
+
+ @Variant
+ VariantDimension1 getVariant2()
+
+ @Variant
+ Platform getPlatform()
+ }
+
+ public static interface Binary3 extends BinarySpec {
+ @Variant
+ String getVariant1()
+
+ @Variant
+ VariantDimension2 getVariant2()
+
+ @Variant
+ Platform getPlatform()
+ }
+
+ public static interface Binary4 extends BinarySpec {
+ @Variant
+ String getVariant1()
+
+ @Variant
+ VariantDimension3 getVariant2()
+
+ @Variant
+ Platform getPlatform()
+ }
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/registry/LanguageTypeModelRuleExtractorTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/registry/LanguageTypeModelRuleExtractorTest.groovy
index 23883a2..bf8b8c5 100644
--- a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/registry/LanguageTypeModelRuleExtractorTest.groovy
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/registry/LanguageTypeModelRuleExtractorTest.groovy
@@ -20,12 +20,14 @@ import org.gradle.api.Task
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.internal.AbstractBuildableModelElement
import org.gradle.language.base.LanguageSourceSet
+import org.gradle.language.base.internal.testinterfaces.CustomLanguageSourceSet
import org.gradle.language.base.plugins.ComponentModelBasePlugin
import org.gradle.language.base.sources.BaseLanguageSourceSet
import org.gradle.model.InvalidModelRuleDeclarationException
import org.gradle.model.internal.core.ExtractedModelRule
import org.gradle.model.internal.core.ModelActionRole
import org.gradle.model.internal.core.ModelReference
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.platform.base.InvalidModelException
import org.gradle.platform.base.LanguageType
import org.gradle.platform.base.LanguageTypeBuilder
@@ -39,7 +41,7 @@ class LanguageTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtr
Class<?> ruleClass = Rules
- LanguageTypeModelRuleExtractor ruleHandler = new LanguageTypeModelRuleExtractor()
+ LanguageTypeModelRuleExtractor ruleHandler = new LanguageTypeModelRuleExtractor(DefaultModelSchemaStore.getInstance())
@Override
Class<? extends Annotation> getAnnotation() {
@@ -93,8 +95,6 @@ class LanguageTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtr
registration.type == ExtractedModelRule.Type.DEPENDENCIES
}
- interface CustomLanguageSourceSet extends LanguageSourceSet {}
-
static class ImplementingCustomLanguageSourceSet extends BaseLanguageSourceSet implements CustomLanguageSourceSet {
}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/resolve/DependentSourceSetLocalComponentConverterTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/resolve/DependentSourceSetLocalComponentConverterTest.groovy
new file mode 100644
index 0000000..053d9d1
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/resolve/DependentSourceSetLocalComponentConverterTest.groovy
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.resolve
+import org.gradle.api.artifacts.ModuleVersionIdentifier
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier
+import org.gradle.internal.component.model.ComponentResolveMetaData
+import org.gradle.language.base.internal.DependentSourceSetInternal
+import org.gradle.language.base.internal.model.VariantsMetaData
+import org.gradle.platform.base.DependencySpecContainer
+import org.gradle.platform.base.internal.DefaultDependencySpec
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class DependentSourceSetLocalComponentConverterTest extends Specification {
+
+ def "can convert dependent source set resolve context"() {
+ given:
+ def context = createContext(':foo', 'myLib', 'api', Mock(DependentSourceSetInternal), Mock(VariantsMetaData))
+
+ when:
+ def factory = new DependentSourceSetLocalComponentConverter()
+
+ then:
+ factory.canConvert(context)
+ }
+
+ def "can convert a simple component"() {
+ given: "a dependent sourceset that doesn't define any dependency"
+ def sourceSet = Mock(DependentSourceSetInternal)
+ def dependencySpecs = Mock(DependencySpecContainer)
+ dependencySpecs.dependencies >> { [] as Set }
+ def project = ':myPath'
+
+ dependencySpecs.iterator() >> { [].iterator() }
+ sourceSet.dependencies >> dependencySpecs
+
+ def context = createContext(project, 'myLib', 'api', sourceSet, Mock(VariantsMetaData))
+
+ when: "we create a local component factory"
+ def factory = new DependentSourceSetLocalComponentConverter()
+
+ then: "the factory can convert the resolve context"
+ factory.canConvert(context)
+
+ when: "we convert the context to a local component"
+ def component = factory.convert(context)
+
+ then: "component metadata reflects the library configuration"
+ component.id instanceof ModuleVersionIdentifier
+ component.id.group == ':myPath'
+ component.id.name == 'myLib'
+ component.id.version == '<local component>'
+ component.id.toString() == ':myPath:myLib:<local component>'
+
+ and: "metadata reflects the appropriate library information"
+ component.componentId instanceof LibraryBinaryIdentifier
+ component.componentId.displayName == /project ':myPath' library 'myLib' variant 'api'/
+ component.dependencies.empty
+ !component.changing
+ component.configurationNames == [DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME] as Set
+ component.source == null
+ }
+
+ @Unroll
+ def "can convert a dependent component with #dependenciesDescriptor"() {
+ given: "a dependent sourceset that defines dependencies"
+ def sourceSet = Mock(DependentSourceSetInternal)
+ def dependencySpecs = Mock(DependencySpecContainer)
+ def project = ':myPath'
+
+ sourceSet.dependencies >> dependencySpecs
+
+ def context = createContext(project, 'myLib', 'api', sourceSet, Mock(VariantsMetaData))
+
+ when: "we create a local component factory"
+ def factory = new DependentSourceSetLocalComponentConverter()
+
+ then: "the factory can convert the resolve context"
+ factory.canConvert(context)
+
+ when: "we convert the context to a local component"
+ dependencySpecs.dependencies >> dependencies
+ def component = factory.convert(context)
+
+ then: "component metadata reflects the library configuration"
+ component.id instanceof ModuleVersionIdentifier
+ component.id.group == ':myPath'
+ component.id.name == 'myLib'
+ component.id.version == '<local component>'
+ component.id.toString() == ':myPath:myLib:<local component>'
+
+ and: "metadata reflects the appropriate library information"
+ component instanceof ComponentResolveMetaData
+ component.componentId instanceof LibraryBinaryIdentifier
+ component.componentId.displayName == /project ':myPath' library 'myLib' variant 'api'/
+ !component.changing
+ component.configurationNames == [DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME] as Set
+ component.source == null
+
+ and: "component metadata dependencies correspond to the defined dependencies"
+ component.dependencies.size() == dependencies.size()
+ dependencies.eachWithIndex { spec, i ->
+ def componentDep = component.dependencies[i]
+ assert componentDep.requested.group == spec.projectPath?:project
+ assert componentDep.requested.name == spec.libraryName
+ assert componentDep.requested.version == '<local component>'
+ }
+
+ where:
+ dependencies | dependenciesDescriptor
+ [new DefaultDependencySpec('someLib', ':myPath')] | 'single dependency with explicit project'
+ [new DefaultDependencySpec('someLib', ':myPath'), new DefaultDependencySpec('someLib2', ':myPath')] | '2 deps on the same project'
+ [new DefaultDependencySpec('someLib', ':myPath'), new DefaultDependencySpec('someLib', ':myPath2')] | '2 deps on 2 different projects'
+ [new DefaultDependencySpec('someLib', null)] | 'a single dependency on the current project'
+
+ }
+
+ private static createContext(String path, String library, String variant, DependentSourceSetInternal dependentSourceSetInternal, VariantsMetaData variantsMetaData) {
+ return new DependentSourceSetResolveContext(new DefaultLibraryBinaryIdentifier(path, library, variant), dependentSourceSetInternal, variantsMetaData)
+ }
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/resolve/DependentSourceSetResolveContextTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/resolve/DependentSourceSetResolveContextTest.groovy
new file mode 100644
index 0000000..3715620
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/resolve/DependentSourceSetResolveContextTest.groovy
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.resolve
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier
+import org.gradle.language.base.internal.DependentSourceSetInternal
+import org.gradle.language.base.internal.model.VariantsMetaData
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class DependentSourceSetResolveContextTest extends Specification {
+ private final static String COMPONENT_NAME = 'lib'
+ private final static String VARIANT = 'api'
+
+ def "resolve context can be created from a java source set"() {
+ given:
+ def project = ':foo'
+ def sourceset = Mock(DependentSourceSetInternal)
+ def id = new DefaultLibraryBinaryIdentifier(project, COMPONENT_NAME, VARIANT)
+
+ when:
+ def context = new DependentSourceSetResolveContext(id, sourceset, Mock(VariantsMetaData))
+
+ then:
+ context.componentId.projectPath == project
+ context.dependencies.empty
+ context.allDependencies.empty
+ }
+
+ @Unroll
+ def "context name for project #path and library #library is #contextName"() {
+ // keeping this test in case we need to change the context name again
+ given:
+ def sourceset = Mock(DependentSourceSetInternal)
+ def id = new DefaultLibraryBinaryIdentifier(path, COMPONENT_NAME, VARIANT)
+
+ when:
+ sourceset.parentName >> library
+ def context = new DependentSourceSetResolveContext(id, sourceset, Mock(VariantsMetaData))
+
+ then:
+ context.componentId.projectPath == path
+ context.name == contextName
+
+ where:
+ path | library | contextName
+ ':myPath' | 'myLib' | DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME
+ ':myPath' | 'myLib2' | DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME
+ ':myPath2' | 'myLib' | DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME
+ }
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/CustomLanguageSourceSet.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/CustomLanguageSourceSet.groovy
new file mode 100644
index 0000000..f799044
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/CustomLanguageSourceSet.groovy
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+import org.gradle.language.base.LanguageSourceSet
+
+interface CustomLanguageSourceSet extends LanguageSourceSet {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/NotBinarySpec.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/NotBinarySpec.groovy
new file mode 100644
index 0000000..8307691
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/NotBinarySpec.groovy
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+interface NotBinarySpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/NotComponentSpec.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/NotComponentSpec.groovy
new file mode 100644
index 0000000..6c7764e
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/NotComponentSpec.groovy
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+interface NotComponentSpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/RawLibrary.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/RawLibrary.groovy
new file mode 100644
index 0000000..8999f11
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/RawLibrary.groovy
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+import org.gradle.platform.base.ComponentSpec
+
+interface RawLibrary extends ComponentSpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeBinarySpec.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeBinarySpec.groovy
new file mode 100644
index 0000000..7c718a3
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeBinarySpec.groovy
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+import org.gradle.platform.base.BinarySpec
+
+interface SomeBinarySpec extends BinarySpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeBinarySubType.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeBinarySubType.groovy
new file mode 100644
index 0000000..f014f96
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeBinarySubType.groovy
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+interface SomeBinarySubType extends SomeBinarySpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeComponentSpec.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeComponentSpec.groovy
new file mode 100644
index 0000000..7202f5f
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeComponentSpec.groovy
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+import org.gradle.platform.base.ComponentSpec
+
+interface SomeComponentSpec extends ComponentSpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeLibrary.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeLibrary.groovy
new file mode 100644
index 0000000..e722353
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/language/base/internal/testinterfaces/SomeLibrary.groovy
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.language.base.internal.testinterfaces
+
+import org.gradle.platform.base.ComponentSpec
+
+interface SomeLibrary extends ComponentSpec {}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/model/internal/core/DomainObjectCollectionBackedModelMapTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/model/internal/core/DomainObjectCollectionBackedModelMapTest.groovy
new file mode 100644
index 0000000..dd35657
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/model/internal/core/DomainObjectCollectionBackedModelMapTest.groovy
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.model.internal.core
+
+import com.google.common.collect.Iterators
+import org.gradle.api.DomainObjectCollection
+import org.gradle.api.Named
+import org.gradle.internal.Actions
+import spock.lang.Specification
+
+class DomainObjectCollectionBackedModelMapTest extends Specification {
+ def "created items get added to the backing collection"() {
+ given:
+ def backingCollection = Mock(DomainObjectCollection)
+ def instantiator = Mock(NamedEntityInstantiator)
+ def modelMap = DomainObjectCollectionBackedModelMap.wrap(Item, backingCollection, instantiator, new Named.Namer(), Actions.doNothing())
+
+ when:
+ modelMap.create("alma")
+
+ then:
+ 1 * instantiator.create("alma", Item) >> { new Item(name: "alma") }
+ 1 * backingCollection.add({ item -> item.name == "alma" })
+ 1 * backingCollection.iterator() >> { Iterators.emptyIterator() }
+ 0 * _
+ }
+
+ class Item implements Named {
+ String name
+ }
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/binary/BaseBinarySpecTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/binary/BaseBinarySpecTest.groovy
index ef4753b..3f6c635 100644
--- a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/binary/BaseBinarySpecTest.groovy
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/binary/BaseBinarySpecTest.groovy
@@ -16,8 +16,12 @@
package org.gradle.platform.base.binary
+import org.gradle.api.NamedDomainObjectFactory
+import org.gradle.api.internal.file.FileResolver
import org.gradle.api.internal.project.taskfactory.ITaskFactory
import org.gradle.internal.reflect.DirectInstantiator
+import org.gradle.language.base.LanguageSourceSet
+import org.gradle.language.base.sources.BaseLanguageSourceSet
import org.gradle.platform.base.ModelInstantiationException
import spock.lang.Specification
@@ -62,9 +66,47 @@ class BaseBinarySpecTest extends Specification {
e.cause.message.startsWith "Could not find any public constructor for class"
}
+ def "can own source sets"() {
+ def fileResolver = Mock(FileResolver)
+ def binary = BaseBinarySpec.create(MySampleBinary, "sampleBinary", instantiator, Mock(ITaskFactory))
+ binary.entityInstantiator.registerFactory(CustomSourceSet, new NamedDomainObjectFactory<CustomSourceSet>() {
+ @Override
+ CustomSourceSet create(String name) {
+ return BaseLanguageSourceSet.create(CustomSourceSet, name, "test-parent", fileResolver, instantiator)
+ }
+ })
+
+ def inputSourceSet = Stub(LanguageSourceSet) {
+ getName() >> "input"
+ }
+
+ when:
+ binary.sources.create("custom", CustomSourceSet)
+
+ then:
+ binary.sources.values()*.name == ["custom"]
+
+ when:
+ binary.inputs.add inputSourceSet
+
+ then:
+ binary.sources.values()*.name == ["custom"]
+ binary.inputs*.name == ["input"]
+ }
+
+ def "source property is the same as inputs property"() {
+ given:
+ def binary = BaseBinarySpec.create(MySampleBinary, "sampleBinary", instantiator, Mock(ITaskFactory))
+
+ expect:
+ binary.source == binary.inputs
+ }
+
static class MySampleBinary extends BaseBinarySpec {
}
static class MyConstructedBinary extends BaseBinarySpec {
MyConstructedBinary(String arg) {}
}
+
+ static class CustomSourceSet extends BaseLanguageSourceSet {}
}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/component/BaseComponentSpecTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/component/BaseComponentSpecTest.groovy
index 2775009..a9cc6ec 100644
--- a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/component/BaseComponentSpecTest.groovy
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/component/BaseComponentSpecTest.groovy
@@ -94,7 +94,19 @@ class BaseComponentSpecTest extends Specification {
functionalSourceSet.add(lss2)
then:
- component.getSource().values() as List == [lss1, lss2]
+ component.sources as List == [lss1, lss2]
+ }
+
+ def "source property is the same as sources property"() {
+ when:
+ def lss1 = languageSourceSet("lss1")
+ functionalSourceSet.add(lss1)
+
+ def component = create(MySampleComponent)
+
+ then:
+ component.source.values() == [lss1]
+ component.sources.values() == [lss1]
}
def languageSourceSet(String name) {
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinarySpecSpecializationSchemaExtractionStrategy.java b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinarySpecSpecializationSchemaExtractionStrategy.java
new file mode 100644
index 0000000..abd738b
--- /dev/null
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinarySpecSpecializationSchemaExtractionStrategy.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.platform.base.internal.registry;
+
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.manage.schema.ModelManagedImplStructSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.extract.ManagedImplStructSchemaExtractionStrategySupport;
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractor;
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.internal.BinarySpecInternal;
+
+// Needed as a separate Java class because Groovy compiler won't recognize type parameter <R>
+public class BinarySpecSpecializationSchemaExtractionStrategy extends ManagedImplStructSchemaExtractionStrategySupport {
+
+ protected BinarySpecSpecializationSchemaExtractionStrategy(ModelSchemaAspectExtractor aspectExtractor) {
+ super(aspectExtractor, BinarySpecInternal.class, BinarySpec.class);
+ }
+
+ @Override
+ protected <R> NodeInitializer createNodeInitializer(ModelManagedImplStructSchema<R> schema, ModelSchemaStore store) {
+ return null;
+ }
+}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractorTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractorTest.groovy
index a42c86a..0ff2322 100644
--- a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractorTest.groovy
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTasksModelRuleExtractorTest.groovy
@@ -15,15 +15,14 @@
*/
package org.gradle.platform.base.internal.registry
-
import org.gradle.api.Task
+import org.gradle.language.base.internal.testinterfaces.SomeBinarySpec
import org.gradle.language.base.plugins.ComponentModelBasePlugin
import org.gradle.model.InvalidModelRuleDeclarationException
import org.gradle.model.ModelMap
import org.gradle.model.internal.core.ExtractedModelRule
import org.gradle.model.internal.core.ModelActionRole
import org.gradle.model.internal.core.ModelReference
-import org.gradle.platform.base.BinarySpec
import org.gradle.platform.base.BinaryTasks
import org.gradle.platform.base.InvalidModelException
import spock.lang.Unroll
@@ -76,12 +75,10 @@ class BinaryTasksModelRuleExtractorTest extends AbstractAnnotationModelRuleExtra
registration.action.subject == ModelReference.of("binaries")
}
- interface SomeBinary extends BinarySpec {}
-
- static class Rules {
+ class Rules {
@BinaryTasks
- static String returnValue(ModelMap<Task> builder, SomeBinary binary) {
+ static String returnValue(ModelMap<Task> builder, SomeBinarySpec binary) {
}
@BinaryTasks
@@ -93,7 +90,7 @@ class BinaryTasksModelRuleExtractorTest extends AbstractAnnotationModelRuleExtra
}
@BinaryTasks
- static void rawModelMap(ModelMap tasks, SomeBinary binary) {
+ static void rawModelMap(ModelMap tasks, SomeBinarySpec binary) {
}
@BinaryTasks
@@ -101,7 +98,7 @@ class BinaryTasksModelRuleExtractorTest extends AbstractAnnotationModelRuleExtra
}
@BinaryTasks
- static void validTypeRule(ModelMap<Task> tasks, SomeBinary binary) {
+ static void validTypeRule(ModelMap<Task> tasks, SomeBinarySpec binary) {
tasks.create("create${binary.getName()}")
}
}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractorTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractorTest.groovy
index b848f4a..f66c446 100644
--- a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractorTest.groovy
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/BinaryTypeModelRuleExtractorTest.groovy
@@ -15,13 +15,18 @@
*/
package org.gradle.platform.base.internal.registry
-
import org.gradle.language.base.internal.model.BinarySpecFactoryRegistry
+import org.gradle.language.base.internal.testinterfaces.NotBinarySpec
+import org.gradle.language.base.internal.testinterfaces.SomeBinarySpec
import org.gradle.language.base.plugins.ComponentModelBasePlugin
import org.gradle.model.InvalidModelRuleDeclarationException
+import org.gradle.model.Managed
import org.gradle.model.internal.core.ExtractedModelRule
import org.gradle.model.internal.core.ModelActionRole
import org.gradle.model.internal.core.ModelReference
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractor
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaExtractor
import org.gradle.model.internal.type.ModelType
import org.gradle.platform.base.BinarySpec
import org.gradle.platform.base.BinaryType
@@ -33,7 +38,14 @@ import spock.lang.Unroll
import java.lang.annotation.Annotation
class BinaryTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtractorTest {
- BinaryTypeModelRuleExtractor ruleHandler = new BinaryTypeModelRuleExtractor()
+ def aspectExtractor = new ModelSchemaAspectExtractor()
+ BinaryTypeModelRuleExtractor ruleHandler = new BinaryTypeModelRuleExtractor(
+ new DefaultModelSchemaStore(
+ new ModelSchemaExtractor([
+ new BinarySpecSpecializationSchemaExtractionStrategy(aspectExtractor)
+ ], aspectExtractor)
+ )
+ )
@Override
Class<? extends Annotation> getAnnotation() {
@@ -53,9 +65,9 @@ class BinaryTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtrac
registration.action.subject == ModelReference.of(ModelType.of(BinarySpecFactoryRegistry))
}
- def "applies ComponentModelBasePlugin only when implementation not set"() {
+ def "applies ComponentModelBasePlugin only when implementation not set for unmanaged binary spec"() {
when:
- def registration = ruleHandler.registration(ruleDefinitionForMethod("noImplementationSet"))
+ def registration = ruleHandler.registration(ruleDefinitionForMethod("noImplementationSetForUnmanagedBinarySpec"))
then:
registration.ruleDependencies == [ComponentModelBasePlugin]
@@ -81,6 +93,7 @@ class BinaryTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtrac
"extraParameter" | "Method annotated with @BinaryType must have a single parameter of type '${BinaryTypeBuilder.name}'." | "additional rule parameter"
"returnValue" | "Method annotated with @BinaryType must not have a return value." | "method with return type"
"implementationSetMultipleTimes" | "Method annotated with @BinaryType cannot set default implementation multiple times." | "implementation set multiple times"
+ "implementationSetForManagedType" | "Method annotated with @BinaryType cannot set default implementation for managed type ${ManagedBinarySpec.name}." | "implementation set for managed type"
"noTypeParam" | "Parameter of type '${BinaryTypeBuilder.name}' must declare a type parameter." | "missing type parameter"
"notBinarySpec" | "Binary type '${NotBinarySpec.name}' is not a subtype of '${BinarySpec.name}'." | "type not extending BinarySpec"
"notCustomBinary" | "Binary type '${BinarySpec.name}' is not a subtype of '${BinarySpec.name}'." | "type is BinarySpec"
@@ -92,23 +105,23 @@ class BinaryTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtrac
"noDefaultConstructor" | "Binary implementation '${NoDefaultConstructor.name}' must have public default constructor." | "implementation with no public default constructor"
}
- interface SomeBinarySpec extends BinarySpec {}
static class SomeBinarySpecImpl extends BaseBinarySpec implements SomeBinarySpec {}
static class SomeBinarySpecOtherImpl extends SomeBinarySpecImpl {}
- interface NotBinarySpec {}
-
static class NotImplementingCustomBinary extends BaseBinarySpec implements BinarySpec {}
- abstract static class NotExtendingBaseBinarySpec implements BinaryTypeModelRuleExtractorTest.SomeBinarySpec {}
+ abstract static class NotExtendingBaseBinarySpec implements SomeBinarySpec {}
static class NoDefaultConstructor extends BaseBinarySpec implements SomeBinarySpec {
NoDefaultConstructor(String arg) {
}
}
+ @Managed
+ static abstract class ManagedBinarySpec implements BinarySpec {}
+
static class Rules {
@BinaryType
static void validTypeRule(BinaryTypeBuilder<SomeBinarySpec> builder) {
@@ -124,7 +137,7 @@ class BinaryTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtrac
}
@BinaryType
- static void noImplementationSet(BinaryTypeBuilder<SomeBinarySpec> builder) {
+ static void noImplementationSetForUnmanagedBinarySpec(BinaryTypeBuilder<SomeBinarySpec> builder) {
}
@BinaryType
@@ -134,6 +147,11 @@ class BinaryTypeModelRuleExtractorTest extends AbstractAnnotationModelRuleExtrac
}
@BinaryType
+ static void implementationSetForManagedType(BinaryTypeBuilder<ManagedBinarySpec> builder) {
+ builder.defaultImplementation(ManagedBinarySpec)
+ }
+
+ @BinaryType
static void noTypeParam(BinaryTypeBuilder builder) {
}
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/ComponentBinariesModelRuleExtractorTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/ComponentBinariesModelRuleExtractorTest.groovy
index 3158e5f..ad4cce4 100644
--- a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/ComponentBinariesModelRuleExtractorTest.groovy
+++ b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/registry/ComponentBinariesModelRuleExtractorTest.groovy
@@ -16,6 +16,10 @@
package org.gradle.platform.base.internal.registry
+import org.gradle.language.base.internal.testinterfaces.RawLibrary
+import org.gradle.language.base.internal.testinterfaces.SomeBinarySpec
+import org.gradle.language.base.internal.testinterfaces.SomeBinarySubType
+import org.gradle.language.base.internal.testinterfaces.SomeLibrary
import org.gradle.language.base.plugins.ComponentModelBasePlugin
import org.gradle.model.InvalidModelRuleDeclarationException
import org.gradle.model.ModelMap
@@ -81,14 +85,6 @@ class ComponentBinariesModelRuleExtractorTest extends AbstractAnnotationModelRul
"rawModelMap" | "Parameter of type '${ModelMap.simpleName}' must declare a type parameter extending 'BinarySpec'." | "non typed ModelMap parameter"
}
- interface SomeBinarySpec extends BinarySpec {}
-
- interface SomeLibrary extends ComponentSpec {}
-
- interface RawLibrary extends ComponentSpec {}
-
- interface SomeBinarySubType extends SomeBinarySpec {}
-
static class Rules {
@ComponentBinaries
static void noParams() {
diff --git a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/toolchain/DefaultToolResolverTest.groovy b/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/toolchain/DefaultToolResolverTest.groovy
deleted file mode 100644
index 25d4f27..0000000
--- a/subprojects/platform-base/src/test/groovy/org/gradle/platform/base/internal/toolchain/DefaultToolResolverTest.groovy
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.platform.base.internal.toolchain
-
-import org.gradle.language.base.internal.compile.CompileSpec
-import org.gradle.language.base.internal.compile.Compiler
-import org.gradle.platform.base.Platform
-import org.gradle.util.TreeVisitor
-import spock.lang.Specification
-
-class DefaultToolResolverTest extends Specification {
- def "can find an available toolchain" () {
- def toolChains = [
- Mock(ToolChainInternal) {
- select(_) >> Mock(ToolProvider) {
- isAvailable() >> response1
- }
- },
- Mock(ToolChainInternal) {
- select(_) >> Mock(ToolProvider) {
- isAvailable() >> response2
- }
- }
- ]
- DefaultToolResolver resolver = new DefaultToolResolver()
- toolChains.each { resolver.registerToolChain(it) }
-
- expect:
- resolver.checkToolAvailability(Stub(Platform)).available == availability
-
- where:
- response1 | response2 | availability
- false | true | true
- true | false | true
- false | false | false
- }
-
- def "no available toolchains explains all ToolSearchResults" () {
- def provider1 = Mock(ToolProvider) {
- isAvailable() >> false
- }
- def toolChain1 = Mock(ToolChainInternal) {
- select(_) >> provider1
- }
- def provider2 = Mock(ToolProvider) {
- isAvailable() >> false
- }
- def toolChain2 = Mock(ToolChainInternal) {
- select(_) >> provider2
- }
-
- DefaultToolResolver resolver = new DefaultToolResolver()
- resolver.registerToolChain(toolChain1)
- resolver.registerToolChain(toolChain2)
- ToolSearchResult result = resolver.checkToolAvailability(Stub(Platform))
- TreeVisitor visitor = Stub(TreeVisitor)
-
- when:
- result.explain(visitor)
-
- then:
- provider1.explain(visitor)
- provider2.explain(visitor)
- }
-
- def "can resolve an available compiler" () {
- def compileSpec = new TestCompileSpec() {}
- def provider = Mock(ToolProvider) {
- isAvailable() >> true
- }
- def toolChain = Mock(ToolChainInternal) {
- select(_) >> provider
- }
- DefaultToolResolver resolver = new DefaultToolResolver()
- resolver.registerToolChain(toolChain)
-
- when:
- ResolvedTool<Compiler<TestCompileSpec>> tool = resolver.resolveCompiler(TestCompileSpec.class, Stub(Platform))
-
- then:
- tool.available
-
- when:
- tool.get()
-
- then:
- 1 * provider.newCompiler(TestCompileSpec.class)
- }
-
- def "can resolve an available tool" () {
- def provider = Mock(ToolProvider) {
- isAvailable() >> true
- }
- def toolChain = Mock(ToolChainInternal) {
- select(_) >> provider
- }
- DefaultToolResolver resolver = new DefaultToolResolver()
- resolver.registerToolChain(toolChain)
-
- when:
- ResolvedTool<String> tool = resolver.resolve(String.class, Stub(Platform))
-
- then:
- tool.available
-
- when:
- tool.get()
-
- then:
- 1 * provider.get(String.class)
- }
-
- private static interface TestCompileSpec extends CompileSpec {}
-}
diff --git a/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/component/BaseComponentFixtures.groovy b/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/component/BaseComponentFixtures.groovy
index 3399ce8..6b970f6 100644
--- a/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/component/BaseComponentFixtures.groovy
+++ b/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/component/BaseComponentFixtures.groovy
@@ -15,7 +15,6 @@
*/
package org.gradle.platform.base.component
-
import org.gradle.internal.reflect.Instantiator
import org.gradle.language.base.FunctionalSourceSet
import org.gradle.model.internal.core.ModelCreators
@@ -23,15 +22,20 @@ import org.gradle.model.internal.core.ModelNode
import org.gradle.model.internal.core.ModelReference
import org.gradle.model.internal.core.ModelRuleExecutionException
import org.gradle.model.internal.fixture.ModelRegistryHelper
+import org.gradle.model.internal.manage.schema.ModelSchemaStore
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
import org.gradle.platform.base.ComponentSpecIdentifier
class BaseComponentFixtures {
- static <T extends BaseComponentSpec> T create(Class<T> type, ModelRegistryHelper modelRegistry, ComponentSpecIdentifier componentId, FunctionalSourceSet functionalSourceSet, Instantiator instantiator) {
+ static <T extends BaseComponentSpec> T create(Class<T> type, ModelRegistryHelper modelRegistry, ComponentSpecIdentifier componentId, FunctionalSourceSet functionalSourceSet, Instantiator instantiator, ModelSchemaStore schemaStore = null) {
+ if (schemaStore == null) {
+ schemaStore = DefaultModelSchemaStore.getInstance()
+ }
try {
modelRegistry.create(
ModelCreators.unmanagedInstanceOf(ModelReference.of(componentId.name, type), {
- BaseComponentSpec.create(type, componentId, it, functionalSourceSet, instantiator)
+ BaseComponentSpec.create(type, componentId, it, functionalSourceSet, instantiator, schemaStore)
})
.descriptor(componentId.name)
.build()
diff --git a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/ComponentReportIntegrationTest.groovy b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/ComponentReportIntegrationTest.groovy
index c8ecdc9..f350bec 100644
--- a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/ComponentReportIntegrationTest.groovy
+++ b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/ComponentReportIntegrationTest.groovy
@@ -177,7 +177,7 @@ Binaries
platform: java9
tool chain: $currentJdk
Jar file: build/jars/java9MyLibJar/myLib.jar
- No tool chains can satisfy the requirement: Could not target platform: 'Java SE 9' using tool chain: '${currentJdk}'.
+ Could not target platform: 'Java SE 9' using tool chain: '${currentJdk}'.
JVM library 'myLib2'
--------------------
@@ -197,4 +197,68 @@ Binaries
Disabled by user
"""
}
+
+ def "shows owned sources of a Jar binary"() {
+ given:
+ buildFile << """
+plugins {
+ id 'jvm-component'
+ id 'java-lang'
+}
+
+model {
+ components {
+ someLib(JvmLibrarySpec) {
+ targetPlatform "java5"
+ targetPlatform "java6"
+ binaries {
+ all {
+ if (targetPlatform.name == "java5") {
+ sources {
+ java2(JavaSourceSet) {
+ source.srcDir "src/main/java2"
+ dependencies {
+ library 'some-library'
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+"""
+ when:
+ succeeds "components"
+
+ then:
+ outputMatches output, """
+JVM library 'someLib'
+---------------------
+
+Source sets
+ Java source 'someLib:java'
+ srcDir: src/someLib/java
+ JVM resources 'someLib:resources'
+ srcDir: src/someLib/resources
+
+Binaries
+ Jar 'java5SomeLibJar'
+ build using task: :java5SomeLibJar
+ platform: java5
+ tool chain: $currentJdk
+ Jar file: build/jars/java5SomeLibJar/someLib.jar
+ source sets:
+ Java source 'someLib:java2'
+ srcDir: src/main/java2
+ dependencies
+ library 'some-library'
+ Jar 'java6SomeLibJar'
+ build using task: :java6SomeLibJar
+ platform: java6
+ tool chain: $currentJdk
+ Jar file: build/jars/java6SomeLibJar/someLib.jar
+"""
+ }
}
diff --git a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/CustomJarBinarySpecSubtypeIntegrationTest.groovy b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/CustomJarBinarySpecSubtypeIntegrationTest.groovy
new file mode 100644
index 0000000..7129614
--- /dev/null
+++ b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/CustomJarBinarySpecSubtypeIntegrationTest.groovy
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.jvm
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.test.fixtures.archive.JarTestFixture
+
+class CustomJarBinarySpecSubtypeIntegrationTest extends AbstractIntegrationSpec {
+ def setup() {
+ buildFile << """
+ plugins {
+ id 'jvm-component'
+ }
+ """
+ }
+
+ def "can create a Jar from a managed JarBinarySpec subtype"() {
+ given:
+ buildFile << """
+ ${registerCustomJarBinaryType()}
+
+ model {
+ components {
+ sampleLib(JvmLibrarySpec) {
+ binaries {
+ customJar(CustomJarBinarySpec) { binary ->
+ binary.value = "12"
+ assert binary.value == "12"
+ }
+ }
+ }
+ }
+ }
+ """
+
+ expect:
+ succeeds "assemble"
+ new JarTestFixture(file("build/jars/sampleLibJar/sampleLib.jar")).isManifestPresentAndFirstEntry()
+ new JarTestFixture(file("build/jars/customJar/sampleLib.jar")).isManifestPresentAndFirstEntry()
+ }
+
+ def "managed JarBinarySpec subtypes can have further subtypes"() {
+ given:
+ buildFile << """
+ ${registerCustomJarBinaryType()}
+
+ @Managed
+ interface CustomParentJarBinarySpec extends CustomJarBinarySpec {
+ String getParentValue()
+ void setParentValue(String value)
+ }
+
+ @Managed
+ interface CustomChildJarBinarySpec extends CustomParentJarBinarySpec {
+ String getChildValue()
+ void setChildValue(String value)
+ }
+
+ ${registerBinaryType("CustomChildJarBinarySpec")}
+
+ class Results {
+ static def jarBinaries = []
+ static def customBinaries = []
+ }
+
+ class BinaryNameCollectorRules extends RuleSource {
+ @Finalize
+ void printJarBinaries(ModelMap<JarBinarySpec> jarBinaries) {
+ for (JarBinarySpec jarBinary : jarBinaries) {
+ Results.jarBinaries.add jarBinary.name
+ }
+ }
+
+ @Finalize
+ void printCustomBinaries(ModelMap<CustomChildJarBinarySpec> customBinaries) {
+ for (CustomChildJarBinarySpec customBinary : customBinaries) {
+ Results.customBinaries.add customBinary.name
+ }
+ }
+ }
+
+ apply plugin: BinaryNameCollectorRules
+
+ model {
+ components {
+ sampleLib(JvmLibrarySpec) {
+ binaries {
+ customJar(CustomChildJarBinarySpec) { binary ->
+ binary.value = "12"
+ assert binary.value == "12"
+
+ binary.parentValue = "Lajos"
+ assert binary.parentValue == "Lajos"
+
+ binary.childValue = "Tibor"
+ assert binary.childValue == "Tibor"
+ }
+ }
+ }
+ }
+ tasks {
+ create("validate") {
+ dependsOn "assemble"
+ assert Results.jarBinaries == ["customJar", "sampleLibJar"]
+ assert Results.customBinaries == ["customJar"]
+ }
+ }
+ }
+ """
+
+ expect:
+ succeeds "assemble", "validate"
+ new JarTestFixture(file("build/jars/sampleLibJar/sampleLib.jar")).isManifestPresentAndFirstEntry()
+ new JarTestFixture(file("build/jars/customJar/sampleLib.jar")).isManifestPresentAndFirstEntry()
+ }
+
+
+ def "managed JarBinarySpec subtypes can have @Unmanaged properties"() {
+ given:
+ buildFile << """
+ @Managed
+ interface CustomChildJarBinarySpec extends JarBinarySpec {
+ @Unmanaged
+ InputStream getThing()
+ void setThing(InputStream thing)
+ }
+
+ ${registerBinaryType("CustomChildJarBinarySpec")}
+
+ model {
+ components {
+ sampleLib(JvmLibrarySpec) {
+ binaries {
+ customJar(CustomChildJarBinarySpec) { binary ->
+ def stream = new ByteArrayInputStream(new byte[0])
+ binary.thing = stream
+ assert binary.thing == stream
+ }
+ }
+ }
+ }
+ }
+ """
+
+ expect:
+ succeeds "customJar"
+ new JarTestFixture(file("build/jars/customJar/sampleLib.jar")).isManifestPresentAndFirstEntry()
+ }
+
+ def "managed JarBinarySpec subtype cannot be created via BinaryContainer"() {
+ given:
+ buildFile << """
+ ${registerCustomJarBinaryType()}
+
+ binaries {
+ customJar(CustomJarBinarySpec)
+ }
+ """
+
+ expect:
+ def ex = fails "customJar"
+ ex.assertHasCause "Cannot create a CustomJarBinarySpec because this type is not known to this container. Known types are: (None)"
+ }
+
+ def "illegal managed subtype yields error at rule execution time"() {
+ given:
+ buildFile << """
+ @Managed
+ interface IllegalJarBinarySpec extends JarBinarySpec {
+ void sayHello(String person)
+ }
+
+ ${registerBinaryType("IllegalJarBinarySpec")}
+
+ model {
+ components {
+ sampleLib(JvmLibrarySpec) {
+ binaries {
+ illegalJar(IllegalJarBinarySpec)
+ }
+ }
+ }
+ }
+ """
+
+ expect:
+ def ex = fails "components"
+ ex.assertHasCause "Invalid managed model type IllegalJarBinarySpec: only paired getter/setter methods are supported (invalid methods: void IllegalJarBinarySpec#sayHello(java.lang.String))."
+ }
+
+ def registerCustomJarBinaryType() {
+ return """
+ @Managed
+ interface CustomJarBinarySpec extends JarBinarySpec {
+ String getValue()
+ void setValue(String value)
+ }
+
+ ${registerBinaryType("CustomJarBinarySpec")}
+ """
+ }
+
+ def registerBinaryType(String binaryType) {
+ return """
+ import org.gradle.jvm.platform.internal.DefaultJavaPlatform
+
+ class ${binaryType}Rules extends RuleSource {
+ @BinaryType
+ void customJarBinary(BinaryTypeBuilder<${binaryType}> builder) {
+ }
+
+ @Finalize
+ void setPlatformForBinaries(ModelMap<BinarySpec> binaries) {
+ def platform = DefaultJavaPlatform.current()
+ binaries.withType(${binaryType}).beforeEach { binary ->
+ binary.targetPlatform = platform
+ }
+ }
+ }
+
+ apply plugin: ${binaryType}Rules
+ """
+ }
+}
diff --git a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/JarBinariesIntegrationTest.groovy b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/JarBinariesIntegrationTest.groovy
index a41c2c4..c01e486 100644
--- a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/JarBinariesIntegrationTest.groovy
+++ b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/JarBinariesIntegrationTest.groovy
@@ -16,7 +16,6 @@
package org.gradle.jvm
-import org.gradle.api.JavaVersion
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@@ -81,8 +80,9 @@ class JarBinariesIntegrationTest extends AbstractIntegrationSpec {
failureDescriptionContains("Execution failed for task ':assemble'.")
failure.assertThatCause(Matchers.<String>allOf(
Matchers.startsWith("No buildable binaries found:"),
- Matchers.containsString("No tool chains can satisfy the requirement: Could not target platform: 'Java SE 9' using tool chain: 'JDK ${JavaVersion.current().majorVersion} (${JavaVersion.current()})"),
- Matchers.containsString("Disabled by user")
+ Matchers.containsString("myJvmLib1Jar: Could not target platform: 'Java SE 9' using tool chain:"),
+ Matchers.containsString("myJvmLib2Jar: Could not target platform: 'Java SE 9' using tool chain:"),
+ Matchers.containsString("myJvmLib3Jar: Disabled by user")
))
}
}
diff --git a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/plugins/JvmComponentPluginIntegrationTest.groovy b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/plugins/JvmComponentPluginIntegrationTest.groovy
index f72c0de..7ac3502 100644
--- a/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/plugins/JvmComponentPluginIntegrationTest.groovy
+++ b/subprojects/platform-jvm/src/integTest/groovy/org/gradle/jvm/plugins/JvmComponentPluginIntegrationTest.groovy
@@ -18,7 +18,6 @@ package org.gradle.jvm.plugins
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.EnableModelDsl
import org.gradle.test.fixtures.archive.JarTestFixture
-import spock.lang.Ignore
class JvmComponentPluginIntegrationTest extends AbstractIntegrationSpec {
@@ -134,8 +133,8 @@ class JvmComponentPluginIntegrationTest extends AbstractIntegrationSpec {
components {
myJvmLib(JvmLibrarySpec)
}
- jvm {
- allBinaries { jar ->
+ binaries {
+ all { jar ->
jar.jarFile = new File($("buildDir"), "bin/${jar.name}.bin")
}
}
@@ -148,10 +147,9 @@ class JvmComponentPluginIntegrationTest extends AbstractIntegrationSpec {
file("build/bin/myJvmLibJar.bin").assertExists()
}
- @Ignore("Not yet implemented")
def "can configure jvm binary for component"() {
given:
- buildFile << """
+ buildFile << '''
plugins {
id 'jvm-component'
}
@@ -159,13 +157,15 @@ class JvmComponentPluginIntegrationTest extends AbstractIntegrationSpec {
model {
components {
myJvmLib(JvmLibrarySpec) {
- binaries.withType(JarBinarySpec) { jar ->
- jar.jarFile = file("\${project.buildDir}/bin/\${jar.name}.bin")
+ binaries {
+ all { jar ->
+ jar.jarFile = new File($("buildDir"), "bin/${jar.name}.bin")
+ }
}
}
}
}
-"""
+'''
when:
succeeds "myJvmLibJar"
@@ -175,7 +175,7 @@ class JvmComponentPluginIntegrationTest extends AbstractIntegrationSpec {
def "can specify additional builder tasks for binary"() {
given:
- buildFile << """
+ buildFile << '''
plugins {
id 'jvm-component'
}
@@ -184,21 +184,24 @@ class JvmComponentPluginIntegrationTest extends AbstractIntegrationSpec {
components {
myJvmLib(JvmLibrarySpec)
}
- }
- binaries.all { binary ->
- def logTask = project.tasks.create("log_\${binary.name}") {
- doLast {
- println "Constructing \${binary.displayName}"
+ tasks {
+ $("binaries").values().each { binary ->
+ def taskName = "log" + binary.name.capitalize()
+ create(taskName) { task ->
+ task.doLast {
+ println "Constructing " + binary.displayName
+ }
+ }
+ binary.buildTask.dependsOn(taskName)
}
}
- binary.builtBy(logTask)
}
-"""
+'''
when:
succeeds "myJvmLibJar"
then:
- executed ":createMyJvmLibJar", ":log_myJvmLibJar", ":myJvmLibJar"
+ executed ":createMyJvmLibJar", ":logMyJvmLibJar", ":myJvmLibJar"
and:
output.contains("Constructing Jar 'myJvmLibJar'")
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/JvmLibraryResolutionErrorMessageBuilder.java b/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/JvmLibraryResolutionErrorMessageBuilder.java
new file mode 100644
index 0000000..0b5761b
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/JvmLibraryResolutionErrorMessageBuilder.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.resolve;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
+import org.gradle.jvm.JarBinarySpec;
+import org.gradle.jvm.platform.JavaPlatform;
+import org.gradle.language.base.internal.model.DefaultVariantsMetaData;
+import org.gradle.language.base.internal.model.VariantsMetaData;
+import org.gradle.language.base.internal.model.VariantsMetaDataHelper;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.platform.base.BinarySpec;
+import org.gradle.platform.base.Platform;
+
+import java.util.*;
+
+public class JvmLibraryResolutionErrorMessageBuilder implements LibraryResolutionErrorMessageBuilder {
+ private static final String TARGET_PLATFORM = "targetPlatform";
+
+ private final VariantsMetaData variantsMetaData;
+ private final ModelSchemaStore schemaStore;
+ private final Platform platform;
+ private final Set<String> resolveDimensions;
+
+ public JvmLibraryResolutionErrorMessageBuilder(VariantsMetaData variantsMetaData, ModelSchemaStore schemaStore) {
+ this.variantsMetaData = variantsMetaData;
+ this.schemaStore = schemaStore;
+ this.platform = variantsMetaData.getValueAsType(Platform.class, TARGET_PLATFORM);
+ this.resolveDimensions = variantsMetaData.getNonNullDimensions();
+ }
+
+ @Override
+ public String multipleBinariesForSameVariantErrorMessage(String libraryName, Collection<? extends BinarySpec> binaries) {
+ List<String> binaryDescriptors = new ArrayList<String>(binaries.size());
+ StringBuilder binaryDescriptor = new StringBuilder();
+ for (BinarySpec variant : binaries) {
+ binaryDescriptor.setLength(0);
+ binaryDescriptor.append(" - ").append(variant.getDisplayName()).append(":\n");
+ VariantsMetaData metaData = DefaultVariantsMetaData.extractFrom(variant, schemaStore);
+ Set<String> dimensions = new TreeSet<String>(metaData.getNonNullDimensions());
+ if (dimensions.size() > 1) { // 1 because of targetPlatform
+ for (String dimension : dimensions) {
+ binaryDescriptor.append(" * ").append(dimension).append(" '").append(metaData.getValueAsString(dimension)).append("'\n");
+
+ }
+ binaryDescriptors.add(binaryDescriptor.toString());
+ }
+ }
+ if (binaryDescriptors.isEmpty()) {
+ return String.format("Multiple binaries available for library '%s' (%s) : %s", libraryName, platform, binaries);
+ } else {
+ // custom variants on binaries
+ StringBuilder sb = new StringBuilder(String.format("Multiple binaries available for library '%s' (%s) :\n", libraryName, platform));
+ for (String descriptor : binaryDescriptors) {
+ sb.append(descriptor);
+ }
+ return sb.toString();
+ }
+ }
+
+ @Override
+ public String noCompatibleBinaryErrorMessage(String libraryName, Collection<BinarySpec> allBinaries) {
+ if (resolveDimensions.size() == 1) { // 1 because of targetPlatform
+ List<String> availablePlatforms = Lists.transform(
+ Lists.newArrayList(allBinaries), new Function<BinarySpec, String>() {
+ @Override
+ public String apply(BinarySpec input) {
+ return input instanceof JarBinarySpec ? ((JarBinarySpec) input).getTargetPlatform().toString() : input.toString();
+ }
+ }
+ );
+ return String.format("Cannot find a compatible binary for library '%s' (%s). Available platforms: %s", libraryName, platform, availablePlatforms);
+ } else {
+ final boolean moreThanOneBinary = allBinaries.size() > 1;
+ Set<String> availablePlatforms = new TreeSet<String>(Lists.transform(
+ Lists.newArrayList(allBinaries), new Function<BinarySpec, String>() {
+ @Override
+ public String apply(BinarySpec input) {
+ if (input instanceof JarBinarySpec) {
+ JavaPlatform targetPlatform = ((JarBinarySpec) input).getTargetPlatform();
+ if (moreThanOneBinary) {
+ return String.format("'%s' on %s", targetPlatform.getName(), input.getDisplayName());
+ }
+ return String.format("'%s'", targetPlatform.getName());
+ }
+ return null;
+ }
+ }
+ ));
+ StringBuilder error = new StringBuilder(String.format("Cannot find a compatible binary for library '%s' (%s).\n", libraryName, platform));
+ Joiner joiner = Joiner.on(",").skipNulls();
+ error.append(" Required platform '").append(platform.getName()).append("', ");
+ error.append("available: ").append(joiner.join(availablePlatforms));
+ error.append("\n");
+ HashMultimap<String, String> variants = HashMultimap.create();
+ for (BinarySpec spec : allBinaries) {
+ VariantsMetaData md = DefaultVariantsMetaData.extractFrom(spec, schemaStore);
+ Set<String> incompatibleDimensionTypes = VariantsMetaDataHelper.incompatibleDimensionTypes(variantsMetaData, md, resolveDimensions);
+ for (String dimension : resolveDimensions) {
+ String value = md.getValueAsString(dimension);
+ if (value != null) {
+ String message;
+ if (moreThanOneBinary) {
+ message = String.format("'%s' on %s", value, spec.getDisplayName());
+ } else {
+ message = String.format("'%s'", value);
+ }
+ if (incompatibleDimensionTypes.contains(dimension)) {
+ message = String.format("%s but with an incompatible type (expected '%s' was '%s')", message, variantsMetaData.getDimensionType(dimension).getConcreteClass().getName(), md.getDimensionType(dimension).getConcreteClass().getName());
+ }
+ variants.put(dimension, message);
+ }
+ }
+ }
+
+ for (String dimension : resolveDimensions) {
+ if (!isPlatformDimension(dimension)) {
+ error.append(" Required ").append(dimension).append(" '").append(variantsMetaData.getValueAsString(dimension)).append("'");
+ Set<String> available = new TreeSet<String>(variants.get(dimension));
+ if (!available.isEmpty()) {
+ error.append(", available: ").append(joiner.join(available)).append("\n");
+ } else {
+ error.append(" but no compatible binary was found\n");
+ }
+ }
+ }
+ return error.toString();
+ }
+ }
+
+ private static boolean isPlatformDimension(String dimension) {
+ return TARGET_PLATFORM.equals(dimension);
+ }
+
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/JvmLocalLibraryDependencyResolver.java b/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/JvmLocalLibraryDependencyResolver.java
new file mode 100644
index 0000000..2bbd5a3
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/JvmLocalLibraryDependencyResolver.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.api.internal.resolve;
+
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier;
+import org.gradle.jvm.JarBinarySpec;
+import org.gradle.language.base.internal.model.DefaultLibraryLocalComponentMetaData;
+import org.gradle.language.base.internal.model.VariantDimensionSelectorFactory;
+import org.gradle.language.base.internal.model.VariantsMetaData;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.platform.base.BinarySpec;
+
+import java.util.Collections;
+import java.util.List;
+
+public class JvmLocalLibraryDependencyResolver extends AbstractLocalLibraryDependencyResolver<JarBinarySpec> {
+
+ public JvmLocalLibraryDependencyResolver(ProjectModelResolver projectModelResolver, VariantsMetaData variantsMetaData, List<VariantDimensionSelectorFactory> selectorFactories, ModelSchemaStore schemaStore) {
+ super(JarBinarySpec.class, projectModelResolver, selectorFactories, variantsMetaData, new JvmLibraryResolutionErrorMessageBuilder(variantsMetaData, schemaStore), schemaStore);
+ }
+
+ protected DefaultLibraryLocalComponentMetaData createLocalComponentMetaData(BinarySpec selectedBinary, TaskDependency buildDependencies) {
+ JarBinarySpec jarBinarySpec = (JarBinarySpec) selectedBinary;
+ DefaultLibraryLocalComponentMetaData metaData = DefaultLibraryLocalComponentMetaData.newMetaData(jarBinarySpec.getId(), buildDependencies);
+ LibraryPublishArtifact jarBinary = new LibraryPublishArtifact("jar", jarBinarySpec.getJarFile());
+ metaData.addArtifacts(DefaultLibraryBinaryIdentifier.CONFIGURATION_NAME, Collections.singleton(jarBinary));
+ return metaData;
+ }
+
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/LibraryPublishArtifact.java b/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/LibraryPublishArtifact.java
new file mode 100644
index 0000000..64d13d8
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/api/internal/resolve/LibraryPublishArtifact.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.resolve;
+
+import org.apache.commons.lang.StringUtils;
+import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact;
+
+import java.io.File;
+
+public class LibraryPublishArtifact extends DefaultPublishArtifact {
+
+ public LibraryPublishArtifact(String type, File file) {
+ super(determineName(file), determineExtension(file), type, null, null, file);
+ }
+
+ private static String determineExtension(File file) {
+ return StringUtils.substringAfterLast(file.getName(), ".");
+ }
+
+ private static String determineName(File file) {
+ return StringUtils.substringBeforeLast(file.getName(), ".");
+ }
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JarBinarySpec.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JarBinarySpec.java
index a851d2b..b4398cb 100644
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JarBinarySpec.java
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JarBinarySpec.java
@@ -17,6 +17,7 @@
package org.gradle.jvm;
import org.gradle.api.Incubating;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
import org.gradle.internal.HasInternalProtocol;
import java.io.File;
@@ -27,6 +28,11 @@ import java.io.File;
@Incubating @HasInternalProtocol
public interface JarBinarySpec extends JvmBinarySpec {
/**
+ * The unique identifier of this JarBinarySpec.
+ */
+ LibraryBinaryIdentifier getId();
+
+ /**
* The jar file output for this binary.
*/
File getJarFile();
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JvmBinarySpec.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JvmBinarySpec.java
index e09a09a..9a1787c 100644
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JvmBinarySpec.java
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JvmBinarySpec.java
@@ -20,7 +20,7 @@ import org.gradle.api.Incubating;
import org.gradle.jvm.platform.JavaPlatform;
import org.gradle.jvm.toolchain.JavaToolChain;
import org.gradle.platform.base.BinarySpec;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
+import org.gradle.platform.base.Variant;
import java.io.File;
@@ -38,6 +38,7 @@ public interface JvmBinarySpec extends BinarySpec {
/**
* The target platform for this binary.
*/
+ @Variant
JavaPlatform getTargetPlatform();
/**
@@ -56,13 +57,6 @@ public interface JvmBinarySpec extends BinarySpec {
void setToolChain(JavaToolChain toolChain);
/**
- * Returns the {@link org.gradle.jvm.toolchain.JavaToolChain} that will be used to build this binary.
- */
- ToolResolver getToolResolver();
-
- void setToolResolver(ToolResolver toolResolver);
-
- /**
* The classes directory for this binary.
*/
File getClassesDir();
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JvmComponentExtension.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JvmComponentExtension.java
deleted file mode 100644
index a118001..0000000
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/JvmComponentExtension.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.jvm;
-
-import org.gradle.api.Action;
-import org.gradle.api.Incubating;
-
-/**
- * The configuration for jvm components created by this build.
- */
-// TODO:DAZ Remove this. It's just a hack to allow Jar binaries to be configured in the DSL.
-// Can't use binaries.all since the action needs to execute _after_ the plugin-supplied actions
-// There's a story in the design doc to do this properly
- at Incubating
-public interface JvmComponentExtension {
- void allBinaries(Action<? super JvmBinarySpec> action);
-
- Action<JvmBinarySpec> getAllBinariesAction();
-}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/BuildDirHolder.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/BuildDirHolder.java
new file mode 100644
index 0000000..4759de0
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/BuildDirHolder.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.jvm.internal;
+
+import java.io.File;
+
+public class BuildDirHolder {
+ private final File buildDir;
+
+ public BuildDirHolder(File buildDir) {
+ this.buildDir = buildDir;
+ }
+
+ public File getBuildDir() {
+ return buildDir;
+ }
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DefaultJarBinarySpec.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DefaultJarBinarySpec.java
index a355988..7ec6238 100644
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DefaultJarBinarySpec.java
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DefaultJarBinarySpec.java
@@ -16,13 +16,16 @@
package org.gradle.jvm.internal;
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier;
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier;
import org.gradle.jvm.JvmBinaryTasks;
+import org.gradle.jvm.internal.toolchain.JavaToolChainInternal;
import org.gradle.jvm.platform.JavaPlatform;
import org.gradle.jvm.toolchain.JavaToolChain;
+import org.gradle.platform.base.ComponentSpec;
import org.gradle.platform.base.binary.BaseBinarySpec;
import org.gradle.platform.base.internal.BinaryBuildAbility;
import org.gradle.platform.base.internal.ToolSearchBuildAbility;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import java.io.File;
@@ -33,20 +36,21 @@ public class DefaultJarBinarySpec extends BaseBinarySpec implements JarBinarySpe
private File classesDir;
private File resourcesDir;
private File jarFile;
- private String baseName;
- private ToolResolver toolResolver;
+ private ComponentSpec component;
@Override
protected String getTypeName() {
return "Jar";
}
- public String getBaseName() {
- return baseName == null ? getName() : baseName;
+ @Override
+ public void setComponent(ComponentSpec componentSpec) {
+ this.component = componentSpec;
}
- public void setBaseName(String baseName) {
- this.baseName = baseName;
+ @Override
+ public LibraryBinaryIdentifier getId() {
+ return new DefaultLibraryBinaryIdentifier(component.getProjectPath(), component.getName(), getName());
}
public JvmBinaryTasks getTasks() {
@@ -61,14 +65,6 @@ public class DefaultJarBinarySpec extends BaseBinarySpec implements JarBinarySpe
this.toolChain = toolChain;
}
- public ToolResolver getToolResolver() {
- return toolResolver;
- }
-
- public void setToolResolver(ToolResolver toolResolver) {
- this.toolResolver = toolResolver;
- }
-
public JavaPlatform getTargetPlatform() {
return platform;
}
@@ -103,6 +99,6 @@ public class DefaultJarBinarySpec extends BaseBinarySpec implements JarBinarySpe
@Override
protected BinaryBuildAbility getBinaryBuildAbility() {
- return new ToolSearchBuildAbility(getToolResolver().checkToolAvailability(getTargetPlatform()));
+ return new ToolSearchBuildAbility(((JavaToolChainInternal) getToolChain()).select(getTargetPlatform()));
}
}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DefaultJavaPlatformVariantDimensionSelector.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DefaultJavaPlatformVariantDimensionSelector.java
new file mode 100644
index 0000000..eab950a
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DefaultJavaPlatformVariantDimensionSelector.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.jvm.internal;
+
+import org.gradle.jvm.platform.JavaPlatform;
+import org.gradle.language.base.internal.model.VariantDimensionSelector;
+
+public class DefaultJavaPlatformVariantDimensionSelector implements VariantDimensionSelector<JavaPlatform> {
+ @Override
+ public boolean isCompatibleWithRequirement(JavaPlatform requirement, JavaPlatform value) {
+ return requirement.getTargetCompatibility().compareTo(value.getTargetCompatibility()) >= 0;
+ }
+
+ @Override
+ public boolean betterFit(JavaPlatform requirement, JavaPlatform oldValue, JavaPlatform newValue) {
+ return oldValue.getTargetCompatibility().compareTo(newValue.getTargetCompatibility()) < 0;
+ }
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DependencyResolvingClasspath.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DependencyResolvingClasspath.java
new file mode 100644
index 0000000..cfc430e
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/DependencyResolvingClasspath.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.jvm.internal;
+
+import com.google.common.collect.Lists;
+import org.gradle.api.artifacts.ResolvedArtifact;
+import org.gradle.api.internal.artifacts.ArtifactDependencyResolver;
+import org.gradle.api.internal.artifacts.GlobalDependencyResolutionRules;
+import org.gradle.api.internal.artifacts.ResolvedConfigurationIdentifier;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ArtifactSet;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DefaultResolvedArtifactResults;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DependencyArtifactsVisitor;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphEdge;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphNode;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphVisitor;
+import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
+import org.gradle.api.internal.file.AbstractFileCollection;
+import org.gradle.api.internal.tasks.DefaultTaskDependency;
+import org.gradle.api.tasks.TaskDependency;
+import org.gradle.internal.component.local.model.LocalConfigurationMetaData;
+import org.gradle.internal.component.model.ConfigurationMetaData;
+import org.gradle.internal.resolve.ModuleVersionResolveException;
+import org.gradle.jvm.JarBinarySpec;
+import org.gradle.language.base.internal.DependentSourceSetInternal;
+import org.gradle.language.base.internal.model.DefaultVariantsMetaData;
+import org.gradle.language.base.internal.resolve.DependentSourceSetResolveContext;
+import org.gradle.language.base.internal.resolve.LibraryResolveException;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.util.CollectionUtils;
+
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+public class DependencyResolvingClasspath extends AbstractFileCollection {
+ private final GlobalDependencyResolutionRules globalRules = GlobalDependencyResolutionRules.NO_OP;
+ private final List<ResolutionAwareRepository> remoteRepositories = Lists.newArrayList();
+ private final JarBinarySpec binary;
+ private final DependentSourceSetInternal sourceSet;
+ private final ArtifactDependencyResolver dependencyResolver;
+ private final DependentSourceSetResolveContext resolveContext;
+
+ private ResolveResult resolveResult;
+
+ public DependencyResolvingClasspath(
+ JarBinarySpec binarySpec,
+ DependentSourceSetInternal sourceSet,
+ ArtifactDependencyResolver dependencyResolver,
+ ModelSchemaStore schemaStore) {
+ this.binary = binarySpec;
+ this.sourceSet = sourceSet;
+ this.dependencyResolver = dependencyResolver;
+ this.resolveContext = new DependentSourceSetResolveContext(binary.getId(), sourceSet, DefaultVariantsMetaData.extractFrom(binary, schemaStore));
+ }
+
+ @Override
+ public String getDisplayName() {
+ return "Classpath for " + sourceSet.getDisplayName();
+ }
+
+ @Override
+ public Set<File> getFiles() {
+ ensureResolved(true);
+ Set<ResolvedArtifact> artifacts = resolveResult.artifactResults.getArtifacts();
+ return CollectionUtils.collect(artifacts, new org.gradle.api.Transformer<File, ResolvedArtifact>() {
+ @Override
+ public File transform(ResolvedArtifact resolvedArtifact) {
+ return resolvedArtifact.getFile();
+ }
+ });
+ }
+
+ @Override
+ public TaskDependency getBuildDependencies() {
+ ensureResolved(false);
+ return resolveResult.taskDependency;
+ }
+
+ private void ensureResolved(boolean failFast) {
+ if (resolveResult == null) {
+ resolveResult = new ResolveResult();
+
+ dependencyResolver.resolve(resolveContext, remoteRepositories, globalRules, resolveResult, resolveResult);
+ }
+ if (failFast) {
+ failOnUnresolvedDependency(resolveResult.notFound);
+ }
+ }
+
+ private void failOnUnresolvedDependency(List<Throwable> notFound) {
+ if (!notFound.isEmpty()) {
+ throw new LibraryResolveException(String.format("Could not resolve all dependencies for '%s' source set '%s'", binary.getDisplayName(), sourceSet.getDisplayName()), notFound);
+ }
+ }
+
+ class ResolveResult implements DependencyGraphVisitor, DependencyArtifactsVisitor {
+ public final DefaultTaskDependency taskDependency = new DefaultTaskDependency();
+ public final List<Throwable> notFound = new LinkedList<Throwable>();
+ public final DefaultResolvedArtifactResults artifactResults = new DefaultResolvedArtifactResults();
+
+ @Override
+ public void start(DependencyGraphNode root) {
+
+ }
+
+ @Override
+ public void visitNode(DependencyGraphNode resolvedConfiguration) {
+ ConfigurationMetaData configurationMetaData = resolvedConfiguration.getMetaData();
+ if (configurationMetaData instanceof LocalConfigurationMetaData) {
+ TaskDependency directBuildDependencies = ((LocalConfigurationMetaData) configurationMetaData).getDirectBuildDependencies();
+ taskDependency.add(directBuildDependencies);
+ }
+
+ for (DependencyGraphEdge dependency : resolvedConfiguration.getOutgoingEdges()) {
+ ModuleVersionResolveException failure = dependency.getFailure();
+ if (failure != null) {
+ notFound.add(failure);
+ }
+ }
+ }
+
+ @Override
+ public void visitEdge(DependencyGraphNode resolvedConfiguration) {
+
+ }
+
+ @Override
+ public void finish(DependencyGraphNode root) {
+ }
+
+ @Override
+ public void visitArtifacts(ResolvedConfigurationIdentifier parent, ResolvedConfigurationIdentifier child, ArtifactSet artifacts) {
+ artifactResults.addArtifactSet(artifacts);
+ }
+
+ @Override
+ public void finishArtifacts() {
+ artifactResults.resolveNow();
+ }
+ }
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/JarBinaryRules.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/JarBinaryRules.java
new file mode 100644
index 0000000..35d456e
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/JarBinaryRules.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.jvm.internal;
+
+import org.gradle.api.Action;
+import org.gradle.jvm.JarBinarySpec;
+import org.gradle.jvm.toolchain.JavaToolChainRegistry;
+import org.gradle.model.Defaults;
+import org.gradle.model.RuleSource;
+import org.gradle.platform.base.ComponentSpec;
+
+import java.io.File;
+
+ at SuppressWarnings("UnusedDeclaration")
+public class JarBinaryRules extends RuleSource {
+ @Defaults
+ void configureJarBinaries(final ComponentSpec jvmLibrary, BuildDirHolder buildDirHolder, final JavaToolChainRegistry toolChains) {
+ final File binariesDir = new File(buildDirHolder.getBuildDir(), "jars");
+ final File classesDir = new File(buildDirHolder.getBuildDir(), "classes");
+ jvmLibrary.getBinaries().withType(JarBinarySpec.class).beforeEach(new Action<JarBinarySpec>() {
+ @Override
+ public void execute(JarBinarySpec jarBinary) {
+ File outputDir = new File(classesDir, jarBinary.getName());
+ jarBinary.setClassesDir(outputDir);
+ jarBinary.setResourcesDir(outputDir);
+ jarBinary.setJarFile(new File(binariesDir, String.format("%s/%s.jar", jarBinary.getName(), jarBinary.getId().getLibraryName())));
+ jarBinary.setToolChain(toolChains.getForPlatform(jarBinary.getTargetPlatform()));
+ }
+ });
+ }
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/JarBinarySpecInternal.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/JarBinarySpecInternal.java
index 83b18ea..9f5a16a 100644
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/JarBinarySpecInternal.java
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/JarBinarySpecInternal.java
@@ -16,11 +16,9 @@
package org.gradle.jvm.internal;
-import org.gradle.platform.base.internal.BinarySpecInternal;
import org.gradle.jvm.JarBinarySpec;
+import org.gradle.platform.base.internal.BinarySpecInternal;
+import org.gradle.platform.base.internal.ComponentSpecAware;
-public interface JarBinarySpecInternal extends JarBinarySpec, BinarySpecInternal {
- String getBaseName();
-
- void setBaseName(String baseName);
+public interface JarBinarySpecInternal extends JarBinarySpec, BinarySpecInternal, ComponentSpecAware {
}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/PlatformJvmServices.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/PlatformJvmServices.java
deleted file mode 100644
index a01cd89..0000000
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/PlatformJvmServices.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.jvm.internal;
-
-import org.gradle.internal.service.ServiceRegistration;
-import org.gradle.internal.service.scopes.PluginServiceRegistry;
-
-public class PlatformJvmServices implements PluginServiceRegistry {
- public void registerGlobalServices(ServiceRegistration registration) {
- registration.add(JarBinaryRenderer.class);
- }
-
- public void registerBuildServices(ServiceRegistration registration) {
- }
-
- public void registerGradleServices(ServiceRegistration registration) {
- }
-
- public void registerProjectServices(ServiceRegistration registration) {
- }
-}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/model/JarBinarySpecSpecializationModelInitializer.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/model/JarBinarySpecSpecializationModelInitializer.java
new file mode 100644
index 0000000..5c7d472
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/model/JarBinarySpecSpecializationModelInitializer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.jvm.internal.model;
+
+import org.gradle.jvm.JarBinarySpec;
+import org.gradle.jvm.internal.JarBinarySpecInternal;
+import org.gradle.model.internal.core.ModelProjection;
+import org.gradle.model.internal.core.ModelReference;
+import org.gradle.model.internal.core.ModelView;
+import org.gradle.model.internal.core.MutableModelNode;
+import org.gradle.model.internal.inspect.ManagedModelInitializer;
+import org.gradle.model.internal.manage.instance.ManagedProxyFactory;
+import org.gradle.model.internal.manage.projection.ManagedModelProjection;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.ModelManagedImplStructSchema;
+import org.gradle.platform.base.internal.BinarySpecFactory;
+
+import java.util.Collections;
+import java.util.List;
+
+public class JarBinarySpecSpecializationModelInitializer<T> extends ManagedModelInitializer<T> {
+
+ private static final ManagedProxyFactory PROXY_FACTORY = new ManagedProxyFactory();
+
+ public JarBinarySpecSpecializationModelInitializer(ModelManagedImplStructSchema<T> modelSchema, ModelSchemaStore schemaStore) {
+ super(modelSchema, schemaStore);
+ }
+
+ @Override
+ public List<? extends ModelReference<?>> getInputs() {
+ return Collections.singletonList(ModelReference.of(BinarySpecFactory.class));
+ }
+
+ @Override
+ public void execute(MutableModelNode modelNode, List<ModelView<?>> inputs) {
+ super.execute(modelNode, inputs);
+ BinarySpecFactory binarySpecFactory = (BinarySpecFactory) inputs.get(0).getInstance();
+ JarBinarySpecInternal jarBinarySpec = (JarBinarySpecInternal) binarySpecFactory.create(JarBinarySpec.class, modelNode, modelNode.getPath().getName());
+ modelNode.setPrivateData(JarBinarySpecInternal.class, jarBinarySpec);
+ }
+
+ @Override
+ public List<? extends ModelProjection> getProjections() {
+ return Collections.singletonList(new ManagedModelProjection<T>(modelSchema, schemaStore, PROXY_FACTORY));
+ }
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/model/JarBinarySpecSpecializationSchemaExtractionStrategy.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/model/JarBinarySpecSpecializationSchemaExtractionStrategy.java
new file mode 100644
index 0000000..1f1863b
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/model/JarBinarySpecSpecializationSchemaExtractionStrategy.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.jvm.internal.model;
+
+import org.gradle.jvm.JarBinarySpec;
+import org.gradle.jvm.internal.JarBinarySpecInternal;
+import org.gradle.model.internal.core.NodeInitializer;
+import org.gradle.model.internal.manage.schema.ModelManagedImplStructSchema;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+import org.gradle.model.internal.manage.schema.extract.ManagedImplStructSchemaExtractionStrategySupport;
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractor;
+
+import javax.inject.Inject;
+
+public class JarBinarySpecSpecializationSchemaExtractionStrategy extends ManagedImplStructSchemaExtractionStrategySupport {
+
+ @Inject
+ public JarBinarySpecSpecializationSchemaExtractionStrategy(ModelSchemaAspectExtractor aspectExtractor) {
+ super(aspectExtractor, JarBinarySpecInternal.class, JarBinarySpec.class);
+ }
+
+ @Override
+ protected <R> NodeInitializer createNodeInitializer(ModelManagedImplStructSchema<R> schema, ModelSchemaStore store) {
+ return new JarBinarySpecSpecializationModelInitializer<R>(schema, store);
+ }
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/plugins/DefaultJvmComponentExtension.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/plugins/DefaultJvmComponentExtension.java
deleted file mode 100644
index 26a9df1..0000000
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/plugins/DefaultJvmComponentExtension.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.jvm.internal.plugins;
-
-import org.gradle.api.Action;
-import org.gradle.jvm.JvmBinarySpec;
-import org.gradle.jvm.JvmComponentExtension;
-import org.gradle.listener.ActionBroadcast;
-
-public class DefaultJvmComponentExtension implements JvmComponentExtension {
- private final ActionBroadcast<JvmBinarySpec> binariesAction = new ActionBroadcast<JvmBinarySpec>();
-
- public void allBinaries(Action<? super JvmBinarySpec> action) {
- binariesAction.add(action);
- }
-
- public Action<JvmBinarySpec> getAllBinariesAction() {
- return binariesAction;
- }
-}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/services/PlatformJvmServices.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/services/PlatformJvmServices.java
new file mode 100644
index 0000000..ac30a95
--- /dev/null
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/internal/services/PlatformJvmServices.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.jvm.internal.services;
+
+import org.gradle.api.internal.artifacts.ResolveContext;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.DelegatingComponentResolvers;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ResolverProviderFactory;
+import org.gradle.api.internal.resolve.JvmLocalLibraryDependencyResolver;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
+import org.gradle.internal.service.ServiceRegistration;
+import org.gradle.internal.service.ServiceRegistry;
+import org.gradle.internal.service.scopes.PluginServiceRegistry;
+import org.gradle.jvm.internal.DefaultJavaPlatformVariantDimensionSelector;
+import org.gradle.jvm.internal.JarBinaryRenderer;
+import org.gradle.jvm.internal.model.JarBinarySpecSpecializationSchemaExtractionStrategy;
+import org.gradle.jvm.platform.JavaPlatform;
+import org.gradle.language.base.internal.model.DefaultVariantDimensionSelectorFactory;
+import org.gradle.language.base.internal.model.VariantDimensionSelectorFactory;
+import org.gradle.language.base.internal.resolve.DependentSourceSetResolveContext;
+import org.gradle.model.internal.manage.schema.ModelSchemaStore;
+
+public class PlatformJvmServices implements PluginServiceRegistry {
+ public void registerGlobalServices(ServiceRegistration registration) {
+ registration.add(JarBinaryRenderer.class);
+ registration.add(JarBinarySpecSpecializationSchemaExtractionStrategy.class);
+ registration.add(VariantDimensionSelectorFactory.class, DefaultVariantDimensionSelectorFactory.of(JavaPlatform.class, new DefaultJavaPlatformVariantDimensionSelector()));
+ }
+
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
+ public void registerBuildServices(ServiceRegistration registration) {
+ registration.addProvider(new BuildScopeServices());
+ }
+
+ public void registerGradleServices(ServiceRegistration registration) {
+ }
+
+ public void registerProjectServices(ServiceRegistration registration) {
+ }
+
+ private class BuildScopeServices {
+ LocalLibraryDependencyResolverFactory createResolverProviderFactory(ProjectModelResolver projectModelResolver, ServiceRegistry registry) {
+ return new LocalLibraryDependencyResolverFactory(projectModelResolver, registry);
+ }
+ }
+
+ public static class LocalLibraryDependencyResolverFactory implements ResolverProviderFactory {
+ private final ProjectModelResolver projectModelResolver;
+ private final ServiceRegistry registry;
+
+ public LocalLibraryDependencyResolverFactory(ProjectModelResolver projectModelResolver, ServiceRegistry registry) {
+ this.projectModelResolver = projectModelResolver;
+ this.registry = registry;
+ }
+
+ @Override
+ public boolean canCreate(ResolveContext context) {
+ return context instanceof DependentSourceSetResolveContext;
+ }
+
+ @Override
+ public ComponentResolvers create(ResolveContext context) {
+ JvmLocalLibraryDependencyResolver delegate = new JvmLocalLibraryDependencyResolver(projectModelResolver,
+ ((DependentSourceSetResolveContext) context).getVariants(),
+ registry.getAll(VariantDimensionSelectorFactory.class),
+ registry.get(ModelSchemaStore.class));
+ return DelegatingComponentResolvers.of(delegate);
+ }
+ }
+
+}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/platform/internal/DefaultJavaPlatform.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/platform/internal/DefaultJavaPlatform.java
index e55329d..26cd819 100644
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/platform/internal/DefaultJavaPlatform.java
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/platform/internal/DefaultJavaPlatform.java
@@ -28,16 +28,15 @@ public class DefaultJavaPlatform implements JavaPlatform {
private final String name;
private JavaVersion targetCompatibility;
- public DefaultJavaPlatform(String name) {
- this.name = name;
- this.targetCompatibility = JavaVersion.current();
- }
-
public DefaultJavaPlatform(JavaVersion javaVersion) {
this.name = generateName(javaVersion);
this.targetCompatibility = javaVersion;
}
+ public static JavaPlatform current() {
+ return new DefaultJavaPlatform(JavaVersion.current());
+ }
+
public JavaVersion getTargetCompatibility() {
return targetCompatibility;
}
diff --git a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/plugins/JvmComponentPlugin.java b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/plugins/JvmComponentPlugin.java
index 32eccb5..7e7f47b 100644
--- a/subprojects/platform-jvm/src/main/java/org/gradle/jvm/plugins/JvmComponentPlugin.java
+++ b/subprojects/platform-jvm/src/main/java/org/gradle/jvm/plugins/JvmComponentPlugin.java
@@ -17,13 +17,10 @@ package org.gradle.jvm.plugins;
import org.apache.commons.lang.StringUtils;
import org.gradle.api.*;
-import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.jvm.JarBinarySpec;
-import org.gradle.jvm.JvmComponentExtension;
import org.gradle.jvm.JvmLibrarySpec;
import org.gradle.jvm.internal.*;
-import org.gradle.jvm.internal.plugins.DefaultJvmComponentExtension;
import org.gradle.jvm.internal.toolchain.JavaToolChainInternal;
import org.gradle.jvm.platform.JavaPlatform;
import org.gradle.jvm.platform.internal.DefaultJavaPlatform;
@@ -31,11 +28,13 @@ import org.gradle.jvm.tasks.Jar;
import org.gradle.jvm.toolchain.JavaToolChainRegistry;
import org.gradle.jvm.toolchain.internal.DefaultJavaToolChainRegistry;
import org.gradle.model.*;
+import org.gradle.model.internal.registry.ModelRegistry;
+import org.gradle.model.internal.type.ModelType;
import org.gradle.platform.base.*;
import org.gradle.platform.base.internal.*;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import org.gradle.util.CollectionUtils;
+import javax.inject.Inject;
import java.io.File;
import java.util.Collections;
import java.util.List;
@@ -45,133 +44,105 @@ import java.util.List;
* the components container.
*/
@Incubating
- at SuppressWarnings("UnusedDeclaration")
-public class JvmComponentPlugin extends RuleSource {
- @ComponentType
- void register(ComponentTypeBuilder<JvmLibrarySpec> builder) {
- builder.defaultImplementation(DefaultJvmLibrarySpec.class);
- }
-
- @BinaryType
- void registerJar(BinaryTypeBuilder<JarBinarySpec> builder) {
- builder.defaultImplementation(DefaultJarBinarySpec.class);
- }
+public class JvmComponentPlugin implements Plugin<Project> {
+ private final ModelRegistry modelRegistry;
- @Model
- JvmComponentExtension jvm(ServiceRegistry serviceRegistry) {
- final Instantiator instantiator = serviceRegistry.get(Instantiator.class);
- return instantiator.newInstance(DefaultJvmComponentExtension.class);
+ @Inject
+ public JvmComponentPlugin(ModelRegistry modelRegistry) {
+ this.modelRegistry = modelRegistry;
}
- @Model
- BinaryNamingSchemeBuilder binaryNamingSchemeBuilder() {
- return new DefaultBinaryNamingSchemeBuilder();
+ @Override
+ public void apply(Project project) {
+ modelRegistry.getRoot().applyToAllLinksTransitive(ModelType.of(ComponentSpec.class), JarBinaryRules.class);
}
- @Model
- JavaToolChainRegistry javaToolChain(ServiceRegistry serviceRegistry) {
- JavaToolChainInternal toolChain = serviceRegistry.get(JavaToolChainInternal.class);
- return new DefaultJavaToolChainRegistry(toolChain);
- }
+ @SuppressWarnings("UnusedDeclaration")
+ static class Rules extends RuleSource {
+ @ComponentType
+ void register(ComponentTypeBuilder<JvmLibrarySpec> builder) {
+ builder.defaultImplementation(DefaultJvmLibrarySpec.class);
+ }
- @Mutate
- public void registerPlatformResolver(PlatformResolvers platformResolvers) {
- platformResolvers.register(new JavaPlatformResolver());
- }
+ @BinaryType
+ void registerJar(BinaryTypeBuilder<JarBinarySpec> builder) {
+ builder.defaultImplementation(DefaultJarBinarySpec.class);
+ }
- @ComponentBinaries
- public void createBinaries(ModelMap<JarBinarySpec> binaries, final JvmLibrarySpec jvmLibrary,
- PlatformResolvers platforms, BinaryNamingSchemeBuilder namingSchemeBuilder, final JvmComponentExtension jvmComponentExtension,
- @Path("buildDir") File buildDir, ServiceRegistry serviceRegistry, JavaToolChainRegistry toolChains) {
+ @Model
+ BinaryNamingSchemeBuilder binaryNamingSchemeBuilder() {
+ return new DefaultBinaryNamingSchemeBuilder();
+ }
- final File binariesDir = new File(buildDir, "jars");
- final File classesDir = new File(buildDir, "classes");
- ToolResolver toolResolver = serviceRegistry.get(ToolResolver.class);
+ @Model
+ JavaToolChainRegistry javaToolChain(ServiceRegistry serviceRegistry) {
+ JavaToolChainInternal toolChain = serviceRegistry.get(JavaToolChainInternal.class);
+ return new DefaultJavaToolChainRegistry(toolChain);
+ }
- List<JavaPlatform> selectedPlatforms = resolvePlatforms(jvmLibrary, platforms);
- for (final JavaPlatform platform : selectedPlatforms) {
- final JavaToolChainInternal toolChain = (JavaToolChainInternal) toolChains.getForPlatform(platform);
- final String binaryName = createBinaryName(jvmLibrary, namingSchemeBuilder, selectedPlatforms, platform);
- binaries.create(binaryName, new ConfigureJarBinary(jvmLibrary, toolChain, platform, classesDir, binariesDir, jvmComponentExtension, toolResolver));
+ @Model
+ BuildDirHolder buildDirHolder(@Path("buildDir") File buildDir) {
+ return new BuildDirHolder(buildDir);
}
- }
- private List<JavaPlatform> resolvePlatforms(JvmLibrarySpec jvmLibrary, final PlatformResolvers platforms) {
- List<PlatformRequirement> targetPlatforms = ((JvmLibrarySpecInternal) jvmLibrary).getTargetPlatforms();
- if (targetPlatforms.isEmpty()) {
- // TODO:DAZ Make it simpler to get the default java platform name, or use a spec here
- String defaultJavaPlatformName = new DefaultJavaPlatform(JavaVersion.current()).getName();
- targetPlatforms = Collections.singletonList(DefaultPlatformRequirement.create(defaultJavaPlatformName));
+ @Mutate
+ public void registerPlatformResolver(PlatformResolvers platformResolvers) {
+ platformResolvers.register(new JavaPlatformResolver());
}
- return CollectionUtils.collect(targetPlatforms, new Transformer<JavaPlatform, PlatformRequirement>() {
- @Override
- public JavaPlatform transform(PlatformRequirement platformRequirement) {
- return platforms.resolve(JavaPlatform.class, platformRequirement);
- }
- });
- }
- @BinaryTasks
- public void createTasks(ModelMap<Task> tasks, final JarBinarySpec binary) {
- String taskName = "create" + StringUtils.capitalize(binary.getName());
- tasks.create(taskName, Jar.class, new Action<Jar>() {
- @Override
- public void execute(Jar jar) {
- jar.setDescription(String.format("Creates the binary file for %s.", binary));
- jar.from(binary.getClassesDir());
- jar.from(binary.getResourcesDir());
-
- jar.setDestinationDir(binary.getJarFile().getParentFile());
- jar.setArchiveName(binary.getJarFile().getName());
+ @ComponentBinaries
+ public void createBinaries(ModelMap<JarBinarySpec> binaries, final JvmLibrarySpec jvmLibrary,
+ PlatformResolvers platforms, BinaryNamingSchemeBuilder namingSchemeBuilder,
+ @Path("buildDir") File buildDir) {
+ List<JavaPlatform> selectedPlatforms = resolvePlatforms(jvmLibrary, platforms);
+ for (final JavaPlatform platform : selectedPlatforms) {
+ final String binaryName = createBinaryName(jvmLibrary, namingSchemeBuilder, selectedPlatforms, platform);
+ binaries.create(binaryName, new Action<JarBinarySpec>() {
+ @Override
+ public void execute(JarBinarySpec jarBinary) {
+ jarBinary.setTargetPlatform(platform);
+ }
+ });
}
- });
-
- // bad, bad, bad
- binary.builtBy(tasks.get(taskName));
- }
-
- private String createBinaryName(JvmLibrarySpec jvmLibrary, BinaryNamingSchemeBuilder namingSchemeBuilder, List<JavaPlatform> selectedPlatforms, JavaPlatform platform) {
- BinaryNamingSchemeBuilder componentBuilder = namingSchemeBuilder
- .withComponentName(jvmLibrary.getName())
- .withTypeString("jar");
- if (selectedPlatforms.size() > 1) {
- componentBuilder = componentBuilder.withVariantDimension(platform.getName());
}
- return componentBuilder.build().getLifecycleTaskName();
- }
- private static class ConfigureJarBinary implements Action<JarBinarySpec> {
- private final JvmLibrarySpec jvmLibrary;
- private final JavaToolChainInternal toolChain;
- private final JavaPlatform platform;
- private final File classesDir;
- private final File binariesDir;
- private final JvmComponentExtension jvmComponentExtension;
- private final ToolResolver toolResolver;
-
- public ConfigureJarBinary(JvmLibrarySpec jvmLibrary, JavaToolChainInternal toolChain, JavaPlatform platform, File classesDir, File binariesDir, JvmComponentExtension jvmComponentExtension, ToolResolver toolResolver) {
- this.jvmLibrary = jvmLibrary;
- this.toolChain = toolChain;
- this.platform = platform;
- this.classesDir = classesDir;
- this.binariesDir = binariesDir;
- this.jvmComponentExtension = jvmComponentExtension;
- this.toolResolver = toolResolver;
+ private List<JavaPlatform> resolvePlatforms(JvmLibrarySpec jvmLibrary, final PlatformResolvers platforms) {
+ List<PlatformRequirement> targetPlatforms = ((JvmLibrarySpecInternal) jvmLibrary).getTargetPlatforms();
+ if (targetPlatforms.isEmpty()) {
+ targetPlatforms = Collections.singletonList(DefaultPlatformRequirement.create(DefaultJavaPlatform.current().getName()));
+ }
+ return CollectionUtils.collect(targetPlatforms, new Transformer<JavaPlatform, PlatformRequirement>() {
+ @Override
+ public JavaPlatform transform(PlatformRequirement platformRequirement) {
+ return platforms.resolve(JavaPlatform.class, platformRequirement);
+ }
+ });
}
- public void execute(JarBinarySpec jarBinary) {
- JarBinarySpecInternal jarBinaryInternal = (JarBinarySpecInternal) jarBinary;
- jarBinaryInternal.setBaseName(jvmLibrary.getName());
- jarBinary.setToolChain(toolChain);
- jarBinary.setTargetPlatform(platform);
- jarBinary.setToolResolver(toolResolver);
-
- File outputDir = new File(classesDir, jarBinary.getName());
- jarBinary.setClassesDir(outputDir);
- jarBinary.setResourcesDir(outputDir);
- jarBinary.setJarFile(new File(binariesDir, String.format("%s/%s.jar", jarBinary.getName(), jarBinaryInternal.getBaseName())));
+ @BinaryTasks
+ public void createTasks(ModelMap<Task> tasks, final JarBinarySpec binary) {
+ String taskName = "create" + StringUtils.capitalize(binary.getName());
+ tasks.create(taskName, Jar.class, new Action<Jar>() {
+ @Override
+ public void execute(Jar jar) {
+ jar.setDescription(String.format("Creates the binary file for %s.", binary));
+ jar.from(binary.getClassesDir());
+ jar.from(binary.getResourcesDir());
+
+ jar.setDestinationDir(binary.getJarFile().getParentFile());
+ jar.setArchiveName(binary.getJarFile().getName());
+ }
+ });
+ }
- jvmComponentExtension.getAllBinariesAction().execute(jarBinary);
+ private String createBinaryName(JvmLibrarySpec jvmLibrary, BinaryNamingSchemeBuilder namingSchemeBuilder, List<JavaPlatform> selectedPlatforms, JavaPlatform platform) {
+ BinaryNamingSchemeBuilder componentBuilder = namingSchemeBuilder
+ .withComponentName(jvmLibrary.getName())
+ .withTypeString("jar");
+ if (selectedPlatforms.size() > 1) {
+ componentBuilder = componentBuilder.withVariantDimension(platform.getName());
+ }
+ return componentBuilder.build().getLifecycleTaskName();
}
}
}
diff --git a/subprojects/platform-jvm/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry b/subprojects/platform-jvm/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry
index 72095b3..cb345a8 100644
--- a/subprojects/platform-jvm/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry
+++ b/subprojects/platform-jvm/src/main/resources/META-INF/services/org.gradle.internal.service.scopes.PluginServiceRegistry
@@ -1 +1 @@
-org.gradle.jvm.internal.PlatformJvmServices
\ No newline at end of file
+org.gradle.jvm.internal.services.PlatformJvmServices
diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/api/internal/resolve/JvmLocalLibraryDependencyResolverTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/api/internal/resolve/JvmLocalLibraryDependencyResolverTest.groovy
new file mode 100644
index 0000000..471a038
--- /dev/null
+++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/api/internal/resolve/JvmLocalLibraryDependencyResolverTest.groovy
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.internal.resolve
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.artifacts.ModuleVersionSelector
+import org.gradle.api.artifacts.component.LibraryBinaryIdentifier
+import org.gradle.api.artifacts.component.LibraryComponentSelector
+import org.gradle.api.artifacts.component.ModuleComponentIdentifier
+import org.gradle.api.internal.component.ArtifactType
+import org.gradle.api.internal.project.ProjectInternal
+import org.gradle.api.internal.project.ProjectRegistry
+import org.gradle.api.internal.tasks.TaskContainerInternal
+import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier
+import org.gradle.internal.component.model.*
+import org.gradle.internal.resolve.result.DefaultBuildableArtifactResolveResult
+import org.gradle.internal.resolve.result.DefaultBuildableArtifactSetResolveResult
+import org.gradle.internal.resolve.result.DefaultBuildableComponentIdResolveResult
+import org.gradle.jvm.JarBinarySpec
+import org.gradle.jvm.JvmLibrarySpec
+import org.gradle.jvm.internal.DefaultJavaPlatformVariantDimensionSelector
+import org.gradle.jvm.platform.JavaPlatform
+import org.gradle.jvm.platform.internal.DefaultJavaPlatform
+import org.gradle.language.base.internal.model.DefaultVariantDimensionSelectorFactory
+import org.gradle.language.base.internal.model.VariantsMetaData
+import org.gradle.model.ModelMap
+import org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaAspectExtractor
+import org.gradle.model.internal.manage.schema.extract.ModelSchemaExtractor
+import org.gradle.model.internal.registry.ModelRegistry
+import org.gradle.model.internal.type.ModelType
+import org.gradle.platform.base.ComponentSpecContainer
+import org.gradle.platform.base.LibrarySpec
+import org.gradle.platform.base.internal.VariantAspectExtractionStrategy
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class JvmLocalLibraryDependencyResolverTest extends Specification {
+
+ Map<String, Project> projects
+ ProjectRegistry<ProjectInternal> projectRegistry
+ ProjectModelResolver projectModelResolver
+ Project rootProject
+ JvmLocalLibraryDependencyResolver resolver
+ DependencyMetaData metadata
+ LibraryComponentSelector selector
+ ModuleVersionSelector requested
+ JavaPlatform platform
+
+ def setup() {
+ projects = [:]
+ projectRegistry = Mock(ProjectRegistry)
+ projectRegistry.getProject(_) >> {
+ String name = it[0]
+ projects[name]
+ }
+ projectModelResolver = new DefaultProjectModelResolver(projectRegistry)
+ rootProject = mockProject(':')
+ platform = DefaultJavaPlatform.current()
+ def variants = Mock(VariantsMetaData)
+ variants.getValueAsType(JavaPlatform, 'targetPlatform') >> platform
+ variants.nonNullDimensions >> ['targetPlatform']
+ variants.allDimensions >> ['targetPlatform']
+ variants.getDimensionType(_) >> ModelType.of(JavaPlatform)
+ def schemaStore = new DefaultModelSchemaStore(new ModelSchemaExtractor([], new ModelSchemaAspectExtractor([new VariantAspectExtractionStrategy()])))
+ resolver = new JvmLocalLibraryDependencyResolver(projectModelResolver, variants, [DefaultVariantDimensionSelectorFactory.of(JavaPlatform, new DefaultJavaPlatformVariantDimensionSelector())], schemaStore)
+ metadata = Mock(DependencyMetaData)
+ selector = Mock(LibraryComponentSelector)
+ requested = Mock(ModuleVersionSelector)
+ metadata.requested >> requested
+ metadata.selector >> selector
+
+ }
+
+ private ProjectInternal mockProject(String path) {
+ def mock = Mock(ProjectInternal)
+ mock.findProject(':') >> mock
+ mock.path >> path
+ mock.modelRegistry >> Mock(ModelRegistry)
+ mock.tasks >> Mock(TaskContainerInternal)
+ projects[path] = mock
+ mock
+ }
+
+ @Unroll("Resolution for library #lib on project #projectPath completes")
+ def "can resolve the library defined in a project"() {
+ given:
+ requested.group >> projectPath
+ requested.name >> lib
+ selector.projectPath >> projectPath
+ selector.libraryName >> lib
+ mockLibraries(rootProject, rootProjectComponents)
+
+ subprojects.each { name, libs ->
+ def pj = mockProject(":$name")
+ mockLibraries(pj, libs)
+ }
+
+
+ def result = new DefaultBuildableComponentIdResolveResult()
+
+ when:
+ resolver.resolve(metadata, result)
+
+ then:
+ result.hasResult()
+ if (failure) {
+ assert result.failure.cause.message =~ failure
+ } else {
+ assert result.failure == null
+ def md = result.metaData
+ assert md.id.group == selector.projectPath
+ if (selector.libraryName) {
+ assert md.id.name == selector.libraryName
+ } else {
+ assert md.id.name.length() > 0
+ }
+ }
+
+ where:
+ lib | projectPath | rootProjectComponents | subprojects | failure
+ 'lib' | ':' | ['lib'] | [:] | false
+ null | ':' | ['lib'] | [:] | false
+ 'lib' | ':' | ['lib', 'lib2'] | [:] | false
+ 'lib2' | ':' | ['lib', 'lib2'] | [:] | false
+ 'lib2' | ':' | ['lib'] | [:] | "Did you want to use 'lib'"
+ 'lib2' | ':' | ['lib', 'lib3'] | [:] | "Did you want to use one of 'lib', 'lib3'"
+ null | ':' | ['lib', 'lib2'] | [:] | "Project ':' contains more than one library. Please select one of 'lib', 'lib2'"
+ 'lib' | ':foo' | ['lib'] | [:] | "Project ':foo' not found."
+ 'lib' | ':' | null | [:] | "Project ':' doesn't define any library"
+ 'lib' | ':' | [] | [:] | "Project ':' doesn't define any library"
+ 'lib' | ':foo' | [] | [foo: ['lib']] | false
+ 'lib' | ':foo' | [] | [foo: ['lib', 'lib2']] | false
+ 'lib' | ':foo' | [] | [foo: ['lib2']] | "Did you want to use 'lib2'"
+ 'lib2' | ':foo' | [] | [foo: ['lib', 'lib3']] | "Did you want to use one of 'lib', 'lib3'"
+ null | ':foo' | [] | [foo: ['lib', 'lib2']] | "Project ':foo' contains more than one library. Please select one of 'lib', 'lib2'"
+ null | ':foo' | [] | [foo: null] | "Project ':foo' doesn't define any library"
+ null | ':foo' | [] | [foo: []] | "Project ':foo' doesn't define any library"
+
+ }
+
+ def "handles library artifacts"() {
+ given:
+ def artifact = Mock(ComponentArtifactMetaData)
+ def result = new DefaultBuildableArtifactResolveResult()
+ artifact.componentId >> Mock(LibraryBinaryIdentifier)
+
+ when:
+ resolver.resolveArtifact(artifact, Mock(ModuleSource), result)
+
+ then:
+ result.hasResult()
+ }
+
+ def "ignores non library artifacts"() {
+ given:
+ def artifact = Mock(ComponentArtifactMetaData)
+ def result = new DefaultBuildableArtifactResolveResult()
+ artifact.componentId >> Mock(ModuleComponentIdentifier)
+
+ when:
+ resolver.resolveArtifact(artifact, Mock(ModuleSource), result)
+
+ then:
+ !result.hasResult()
+ }
+
+ @Unroll
+ def "handles library module artifacts for #type"() {
+ given:
+ def component = Mock(ComponentResolveMetaData)
+ def result = new DefaultBuildableArtifactSetResolveResult()
+ component.componentId >> Mock(LibraryBinaryIdentifier)
+
+ when:
+ resolver.resolveModuleArtifacts(component, type, result)
+
+ then:
+ result.hasResult()
+
+ where:
+ type << [Mock(ComponentUsage), ArtifactType.SOURCES]
+ }
+
+ @Unroll
+ def "ignores non library module artifacts for #type"() {
+ given:
+ def component = Mock(ComponentResolveMetaData)
+ def result = new DefaultBuildableArtifactSetResolveResult()
+ component.componentId >> Mock(ModuleComponentIdentifier)
+
+ when:
+ resolver.resolveModuleArtifacts(component, type, result)
+
+ then:
+ !result.hasResult()
+
+ where:
+ type << [Mock(ComponentUsage), ArtifactType.SOURCES]
+ }
+
+ private ModelMap<? extends LibrarySpec> mockLibraries(Project project, List<String> libraries) {
+ if (libraries == null) {
+ project.modelRegistry.find(_, _) >> null
+ } else {
+ ComponentSpecContainer components = Mock()
+ project.modelRegistry.find(_, _) >> components
+ def map = Mock(ModelMap)
+ def librarySpecs = libraries.collect { library ->
+ def lib = Mock(JvmLibrarySpec)
+ lib.name >> library
+ def binaries = Mock(ModelMap)
+ def binary = Mock(JarBinarySpec)
+ binary.id >> new DefaultLibraryBinaryIdentifier(project.path, library, 'api')
+ binary.displayName >> "binary for $lib"
+ binary.name >> 'api'
+ binary.buildTask >> Mock(Task)
+ binary.targetPlatform >> platform
+ binary.jarFile >> new File("api.jar")
+ def values = [binary]
+ binaries.values() >> { values }
+ binaries.withType(JarBinarySpec) >> {
+ values as ModelMap
+ }
+ lib.binaries >> binaries
+ lib
+ }
+ map.values() >> librarySpecs
+ map.get(_) >> { args ->
+ librarySpecs.find { it.name == args[0] }
+ }
+ map
+ components.withType(_) >> map
+ }
+ }
+}
diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/DefaultJavaPlatformVariantDimensionSelectorTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/DefaultJavaPlatformVariantDimensionSelectorTest.groovy
new file mode 100644
index 0000000..ed17ef4
--- /dev/null
+++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/DefaultJavaPlatformVariantDimensionSelectorTest.groovy
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.jvm.internal
+
+import org.gradle.api.JavaVersion
+import org.gradle.jvm.platform.JavaPlatform
+import org.gradle.jvm.platform.internal.DefaultJavaPlatform
+import org.gradle.language.base.internal.model.VariantDimensionSelector
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class DefaultJavaPlatformVariantDimensionSelectorTest extends Specification {
+ @Unroll("Java #requirement is compatible with #value : #expected")
+ def "should check that Java platform is compatible"() {
+ given:
+ VariantDimensionSelector<JavaPlatform> selector = new DefaultJavaPlatformVariantDimensionSelector()
+
+ when:
+ def compatible = selector.isCompatibleWithRequirement(requirement, value)
+
+ then:
+ compatible == expected
+
+ where:
+ required | found | expected
+ '1.5' | '1.5' | true
+ '1.5' | '1.6' | false
+ '1.6' | '1.5' | true
+ '1.7' | '1.5' | true
+ '1.7' | '1.6' | true
+
+ and:
+ requirement = new DefaultJavaPlatform(JavaVersion.toVersion(required))
+ value = new DefaultJavaPlatform(JavaVersion.toVersion(found))
+ }
+
+ @Unroll("Java #newValue is a better fit than #oldValue : #expected")
+ def "should check that Java platform is a better fit than one other"() {
+ given:
+ VariantDimensionSelector<JavaPlatform> selector = new DefaultJavaPlatformVariantDimensionSelector()
+
+ when:
+ def compatible = selector.betterFit(new DefaultJavaPlatform(JavaVersion.VERSION_1_7), oldValue, newValue)
+
+ then:
+ compatible == expected
+
+ where:
+ required | found | expected
+ '1.5' | '1.5' | false
+ '1.5' | '1.6' | true
+ '1.6' | '1.5' | false
+ '1.7' | '1.5' | false
+ '1.7' | '1.6' | false
+
+ and:
+ oldValue = new DefaultJavaPlatform(JavaVersion.toVersion(required))
+ newValue = new DefaultJavaPlatform(JavaVersion.toVersion(found))
+ }
+}
diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/DefaultJvmLibrarySpecTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/DefaultJvmLibrarySpecTest.groovy
index 836d7ad..9b831a8 100644
--- a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/DefaultJvmLibrarySpecTest.groovy
+++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/DefaultJvmLibrarySpecTest.groovy
@@ -55,7 +55,7 @@ class DefaultJvmLibrarySpecTest extends Specification {
mainSourceSet.add(lss2)
then:
- library.getSource().values() as List == [lss1, lss2]
+ library.sources as List == [lss1, lss2]
}
private DefaultJvmLibrarySpec createJvmLibrarySpec() {
diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/plugins/CreateJvmBinariesTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/plugins/CreateJvmBinariesTest.groovy
index 329d8bc..638e55c 100644
--- a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/plugins/CreateJvmBinariesTest.groovy
+++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/internal/plugins/CreateJvmBinariesTest.groovy
@@ -15,13 +15,11 @@
*/
package org.gradle.jvm.internal.plugins
-
import org.gradle.api.Action
import org.gradle.internal.reflect.DirectInstantiator
import org.gradle.internal.reflect.Instantiator
import org.gradle.internal.service.ServiceRegistryBuilder
import org.gradle.jvm.JarBinarySpec
-import org.gradle.jvm.JvmComponentExtension
import org.gradle.jvm.internal.DefaultJvmLibrarySpec
import org.gradle.jvm.internal.toolchain.JavaToolChainInternal
import org.gradle.jvm.platform.JavaPlatform
@@ -32,55 +30,45 @@ import org.gradle.language.base.LanguageSourceSet
import org.gradle.language.base.ProjectSourceSet
import org.gradle.language.base.internal.DefaultFunctionalSourceSet
import org.gradle.model.ModelMap
-import org.gradle.model.internal.core.MutableModelNode
import org.gradle.model.internal.fixture.ModelRegistryHelper
import org.gradle.platform.base.ComponentSpecIdentifier
import org.gradle.platform.base.component.BaseComponentFixtures
import org.gradle.platform.base.internal.BinaryNamingScheme
import org.gradle.platform.base.internal.BinaryNamingSchemeBuilder
import org.gradle.platform.base.internal.PlatformResolvers
-import org.gradle.platform.base.internal.toolchain.ToolResolver
import spock.lang.Specification
class CreateJvmBinariesTest extends Specification {
def buildDir = new File("buildDir")
def namingSchemeBuilder = Mock(BinaryNamingSchemeBuilder)
def toolChain = Mock(JavaToolChainInternal)
- def rule = new JvmComponentPlugin()
+ def rule = new JvmComponentPlugin.Rules()
def platforms = Mock(PlatformResolvers)
ModelMap<JarBinarySpec> binaries = Mock(ModelMap)
def instantiator = Mock(Instantiator)
def mainSourceSet = new DefaultFunctionalSourceSet("ss", DirectInstantiator.INSTANCE, Stub(ProjectSourceSet))
def toolChainRegistry = Mock(JavaToolChainRegistry)
- def toolResolver = Mock(ToolResolver)
- def binariesNode = Mock(MutableModelNode) {
-
- }
def serviceRegistry = ServiceRegistryBuilder.builder().provider(new Object() {
Instantiator createInstantiator() {
instantiator
}
- ToolResolver createToolResolver() {
- toolResolver
- }
+
}).build()
def "adds a binary for each jvm library"() {
def library = BaseComponentFixtures.create(DefaultJvmLibrarySpec, new ModelRegistryHelper(), componentId("jvmLibOne", ":project-path"), mainSourceSet, DirectInstantiator.INSTANCE)
def namingScheme = Mock(BinaryNamingScheme)
- def jvmExtension = Mock(JvmComponentExtension)
- def platform = new DefaultJavaPlatform("test")
+ def platform = DefaultJavaPlatform.current()
def source1 = sourceSet("ss1")
def source2 = sourceSet("ss2")
when:
- library.sources.addAll([source1, source2])
- rule.createBinaries(binaries, library, platforms, namingSchemeBuilder, jvmExtension, buildDir, serviceRegistry, toolChainRegistry)
+ library.functionalSourceSet.addAll([source1, source2])
+ rule.createBinaries(binaries, library, platforms, namingSchemeBuilder, buildDir)
then:
1 * platforms.resolve(JavaPlatform, _) >> platform
- 1 * toolChainRegistry.getForPlatform(platform) >> toolChain
1 * namingSchemeBuilder.withComponentName("jvmLibOne") >> namingSchemeBuilder
1 * namingSchemeBuilder.withTypeString("jar") >> namingSchemeBuilder
1 * namingSchemeBuilder.build() >> namingScheme
diff --git a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/platform/internal/DefaultJavaPlatformTest.groovy b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/platform/internal/DefaultJavaPlatformTest.groovy
index 63816ca..b013bd6 100644
--- a/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/platform/internal/DefaultJavaPlatformTest.groovy
+++ b/subprojects/platform-jvm/src/test/groovy/org/gradle/jvm/platform/internal/DefaultJavaPlatformTest.groovy
@@ -23,7 +23,7 @@ class DefaultJavaPlatformTest extends Specification {
def "is for current java version if not set"() {
when:
- def platform = new DefaultJavaPlatform("test")
+ def platform = DefaultJavaPlatform.current()
then:
platform.targetCompatibility == JavaVersion.current()
@@ -41,7 +41,7 @@ class DefaultJavaPlatformTest extends Specification {
def "has reasonable string representation"() {
when:
- def platform = new DefaultJavaPlatform(JavaVersion.current())
+ def platform = DefaultJavaPlatform.current()
then:
platform.name == "java${JavaVersion.current().majorVersion}"
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryBuildTypesIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryBuildTypesIntegrationTest.groovy
index 30aab52..cfb6ab1 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryBuildTypesIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryBuildTypesIntegrationTest.groovy
@@ -22,10 +22,10 @@ import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
- at LeaksFileHandles
class BinaryBuildTypesIntegrationTest extends AbstractInstalledToolChainIntegrationSpec {
def helloWorldApp = new CppHelloWorldApp()
+ @LeaksFileHandles("can't delete build/binaries/mainExecutable/integration")
def "creates debug and release variants"() {
when:
helloWorldApp.writeSources(file("src/main"))
@@ -88,6 +88,7 @@ model {
}
}
+ @LeaksFileHandles
def "configure component for a single build type"() {
when:
helloWorldApp.writeSources(file("src/main"))
@@ -121,6 +122,7 @@ model {
}
@Requires(TestPrecondition.CAN_INSTALL_EXECUTABLE)
+ @LeaksFileHandles
def "executable with build type depends on library with matching build type"() {
when:
helloWorldApp.executable.writeSources(file("src/main"))
@@ -177,7 +179,7 @@ model {
fails "mainExecutable"
then:
- failure.assertHasCause("Exception thrown while executing model rule: org.gradle.nativeplatform.internal.configure.NativeComponentRules#createBinaries(")
+ failure.assertHasCause("Exception thrown while executing model rule: NativeComponentRules#createBinaries")
failure.assertHasCause("Invalid BuildType: 'unknown'")
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryConfigurationIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryConfigurationIntegrationTest.groovy
index 603bbf7..f35f00a 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryConfigurationIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryConfigurationIntegrationTest.groovy
@@ -14,6 +14,9 @@
* limitations under the License.
*/
package org.gradle.nativeplatform
+
+import groovy.transform.NotYetImplemented
+import org.gradle.integtests.fixtures.EnableModelDsl
import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
import org.gradle.nativeplatform.fixtures.AbstractInstalledToolChainIntegrationSpec
import org.gradle.nativeplatform.fixtures.app.CppHelloWorldApp
@@ -26,8 +29,12 @@ import spock.lang.IgnoreIf
import spock.lang.Issue
import spock.lang.Unroll
- at LeaksFileHandles
class BinaryConfigurationIntegrationTest extends AbstractInstalledToolChainIntegrationSpec {
+ def setup() {
+ EnableModelDsl.enable(executer)
+ }
+
+ @LeaksFileHandles
def "can configure the binaries of a C++ application"() {
given:
buildFile << """
@@ -64,6 +71,7 @@ model {
executable.exec().out == "Hello!"
}
+ @LeaksFileHandles("can't delete build/binaries/mainExecutable")
def "can build debug binaries for a C++ executable"() {
given:
buildFile << """
@@ -106,6 +114,7 @@ model {
}
@Requires(TestPrecondition.CAN_INSTALL_EXECUTABLE)
+ @LeaksFileHandles
def "can configure the binaries of a C++ library"() {
given:
buildFile << """
@@ -162,99 +171,41 @@ model {
installation("build/install/mainExecutable").exec().out == "Hello!"
}
- def "can configure a binary to use additional source sets"() {
- given:
- buildFile << """
-apply plugin: "cpp"
-
-model {
- components { comp ->
- util(NativeLibrarySpec) {
- sources {
- cpp {
- exportedHeaders.srcDir "src/shared/headers"
- }
- }
- }
- main(NativeExecutableSpec) {
- sources {
- cpp {
- exportedHeaders.srcDir "src/shared/headers"
- }
- }
- binaries.all {
- source comp.util.sources.cpp
- }
- }
- }
-}
-"""
- settingsFile << "rootProject.name = 'test'"
-
- and:
- file("src/shared/headers/greeting.h") << """
- void greeting();
-"""
-
- file("src/util/cpp/greeting.cpp") << """
- #include <iostream>
- #include "greeting.h"
-
- void greeting() {
- std::cout << "Hello!";
- }
- """
-
- file("src/main/cpp/helloworld.cpp") << """
- #include "greeting.h"
-
- int main() {
- greeting();
- return 0;
- }
- """
-
- when:
- run "mainExecutable"
-
- then:
- def executable = executable("build/binaries/mainExecutable/main")
- executable.exec().out == "Hello!"
- }
-
def "can customize binaries before and after linking"() {
def helloWorldApp = new CppHelloWorldApp()
given:
- buildFile << """
+ buildFile << '''
apply plugin: 'cpp'
model {
components {
main(NativeExecutableSpec)
}
-}
-
-binaries.withType(NativeExecutableBinary) { binary ->
- def preLink = task("\${binary.name}PreLink") {
- dependsOn binary.tasks.withType(CppCompile)
-
- doLast {
- println "Pre Link"
- }
- }
- binary.tasks.link.dependsOn preLink
-
- def postLink = task("\${binary.name}PostLink") {
- dependsOn binary.tasks.link
-
- doLast {
- println "Post Link"
+ tasks { t ->
+ $("components.main").binaries { binaries ->
+ binaries.values().each { binary ->
+ def preLinkTask = binary.name + "PreLink"
+ t.create(preLinkTask) {
+ dependsOn binary.tasks.withType(CppCompile)
+ doLast {
+ println "Pre Link"
+ }
+ }
+ binary.tasks.link.dependsOn preLinkTask
+
+ def postLinkTask = binary.name + "PostLink"
+ t.create(postLinkTask) {
+ dependsOn binary.tasks.link
+ doLast {
+ println "Post Link"
+ }
+ }
+ binary.tasks.build.dependsOn postLinkTask
+ }
}
}
-
- binary.builtBy postLink
}
-"""
+'''
and:
helloWorldApp.writeSources(file("src/main"))
@@ -307,6 +258,7 @@ subprojects {
apply plugin: 'cpp'
model {
components {
+ def modPath = { File original -> new File(original.parent + "/new_output/_" + original.name) }
main(NativeExecutableSpec) {
binaries.all {
executableFile = modPath(executableFile)
@@ -323,10 +275,6 @@ model {
}
}
}
-
-def modPath(File file) {
- new File("\${file.parentFile}/new_output/_\${file.name}")
-}
"""
when:
@@ -341,6 +289,7 @@ def modPath(File file) {
@Unroll
@Requires(TestPrecondition.CAN_INSTALL_EXECUTABLE)
+ @LeaksFileHandles
def "can link to #linkage library binary with custom output file"() {
given:
def app = new CppHelloWorldApp()
@@ -352,6 +301,7 @@ def modPath(File file) {
apply plugin: 'cpp'
model {
components {
+ def modPath = { File original -> new File(original.parent + "/new_output/_" + original.name) }
main(NativeExecutableSpec) {
sources {
cpp.lib library: "hello", linkage: "${linkage}"
@@ -368,10 +318,6 @@ model {
}
}
}
-
-def modPath(File file) {
- new File("\${file.parentFile}/new_output/_\${file.name}")
-}
"""
when:
@@ -383,4 +329,33 @@ def modPath(File file) {
where:
linkage << ["static", "shared"]
}
+
+ @Issue("GRADLE-3332")
+ @NotYetImplemented
+ def "can create helper task to install buildable executables"() {
+ def helloWorldApp = new CppHelloWorldApp()
+ given:
+ buildFile << '''
+apply plugin: 'cpp'
+
+model {
+ components {
+ main(NativeExecutableSpec)
+ }
+}
+task installDeveloperImage {
+ description = "Install all debug executables"
+ binaries.withType(NativeExecutableBinary) {
+ if (it.buildable && buildType == buildTypes.debug) {
+ dependsOn it.tasks.install
+ }
+ }
+}
+'''
+ and:
+ helloWorldApp.writeSources(file("src/main"))
+
+ expect:
+ succeeds "tasks"
+ }
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryFlavorsIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryFlavorsIntegrationTest.groovy
index 706b875..ea0b7c5 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryFlavorsIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/BinaryFlavorsIntegrationTest.groovy
@@ -24,7 +24,6 @@ import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@Requires(TestPrecondition.CAN_INSTALL_EXECUTABLE)
- at LeaksFileHandles
class BinaryFlavorsIntegrationTest extends AbstractInstalledToolChainIntegrationSpec {
static final DEFAULT = HelloWorldApp.HELLO_WORLD
static final FRENCH = HelloWorldApp.HELLO_WORLD_FRENCH
@@ -67,6 +66,7 @@ model {
helloWorldApp.writeSources(file("src/main"), file("src/hello"), file("src/greetings"))
}
+ @LeaksFileHandles
def "can configure components for a single flavor"() {
given:
buildFile << """
@@ -100,6 +100,7 @@ model {
installation("build/install/mainExecutable/german").assertInstalled()
}
+ @LeaksFileHandles("can't delete build/install/mainExecutable/french")
def "executable with flavors depends on library with matching flavors"() {
when:
buildFile << """
@@ -171,7 +172,7 @@ model {
fails "mainExecutable"
then:
- failure.assertHasCause("Exception thrown while executing model rule: org.gradle.nativeplatform.internal.configure.NativeComponentRules#createBinaries(")
+ failure.assertHasCause("Exception thrown while executing model rule: NativeComponentRules#createBinaries")
failure.assertHasCause("Invalid Flavor: 'unknown'")
}
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/ComponentReportIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/ComponentReportIntegrationTest.groovy
index 1ce71d3..f4f64db 100644
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/ComponentReportIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/ComponentReportIntegrationTest.groovy
@@ -35,7 +35,13 @@ model {
${toolChain.buildScriptConfig}
}
components {
- someLib(NativeLibrarySpec)
+ someLib(NativeLibrarySpec) {
+ binaries.withType(StaticLibraryBinarySpec) {
+ sources {
+ moreCpp(CppSourceSet)
+ }
+ }
+ }
}
}
"""
@@ -66,6 +72,9 @@ Binaries
flavor: default
tool chain: Tool chain 'clang' (Clang)
static library file: build/binaries/someLibStaticLibrary/libsomeLib.a
+ source sets:
+ C++ source 'someLib:moreCpp'
+ No source directories
"""
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/LibraryDependenciesIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/LibraryDependenciesIntegrationTest.groovy
index 4e1ad55..531dbfc 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/LibraryDependenciesIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/LibraryDependenciesIntegrationTest.groovy
@@ -83,7 +83,7 @@ project(":other") {
where:
label | dependencyNotation | description | cause
"does not exist" | "library: 'unknown'" | "Could not locate library 'unknown'." | "NativeLibrarySpec with name 'unknown' not found."
- "project that does not exist" | "project: ':unknown', library: 'hello'" | "Could not locate library 'hello' for project ':unknown'." | "Project with path ':unknown' could not be found in project ':exe'."
+ "project that does not exist" | "project: ':unknown', library: 'hello'" | "Could not locate library 'hello' for project ':unknown'." | "Project with path ':unknown' not found."
"does not exist in referenced project" | "project: ':other', library: 'unknown'" | "Could not locate library 'unknown' for project ':other'." | "NativeLibrarySpec with name 'unknown' not found."
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativeBinariesIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativeBinariesIntegrationTest.groovy
index c09b2b3..fc45dec 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativeBinariesIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativeBinariesIntegrationTest.groovy
@@ -229,7 +229,7 @@ model {
then:
fails "mainExecutable"
- failure.assertHasCause("Exception thrown while executing model rule: model.components > main.<init> > components.main.getSources() > create(java)");
+ failure.assertHasCause("Exception thrown while executing model rule: model.components > create(main) > components.main.getSources() > create(java)");
failure.assertHasCause("Cannot create a JavaSourceSet because this type is not known to this container. Known types are: CSourceSet, CppSourceSet")
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativePlatformSamplesIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativePlatformSamplesIntegrationTest.groovy
index a51dc64..64ec390 100644
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativePlatformSamplesIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/NativePlatformSamplesIntegrationTest.groovy
@@ -15,7 +15,9 @@
*/
package org.gradle.nativeplatform
+import org.gradle.integtests.fixtures.EnableModelDsl
import org.gradle.integtests.fixtures.Sample
+import org.gradle.internal.os.OperatingSystem
import org.gradle.nativeplatform.fixtures.AbstractInstalledToolChainIntegrationSpec
import org.gradle.nativeplatform.fixtures.RequiresInstalledToolChain
import org.gradle.test.fixtures.file.LeaksFileHandles
@@ -39,6 +41,7 @@ class NativePlatformSamplesIntegrationTest extends AbstractInstalledToolChainInt
@Rule public final Sample toolChains = sample(testDirProvider, 'tool-chains')
@Rule public final Sample prebuilt = sample(testDirProvider, 'prebuilt')
@Rule public final Sample targetPlatforms = sample(testDirProvider, 'target-platforms')
+ @Rule public final Sample sourcesetVariant = sample(testDirectoryProvider, "sourceset-variant")
private static Sample sample(TestDirectoryProvider testDirectoryProvider, String name) {
return new Sample(testDirectoryProvider, "native-binaries/${name}", name)
@@ -53,6 +56,7 @@ class NativePlatformSamplesIntegrationTest extends AbstractInstalledToolChainInt
sample cppExe
when:
+ EnableModelDsl.enable(executer)
run "installMain"
then:
@@ -239,4 +243,30 @@ Util build type: DEBUG
Util build type: RELEASE
"""
}
+
+ def sourcesetvariant() {
+ given:
+ sample sourcesetVariant
+
+ final String platformName
+ if (OperatingSystem.current().isMacOsX()) {
+ platformName = "MacOSX"
+ } else if (OperatingSystem.current().isLinux()) {
+ platformName = "Linux"
+ } else if (OperatingSystem.current().isWindows()) {
+ platformName = "Windows"
+ } else {
+ platformName = "Unknown"
+ }
+
+ when:
+ run "installMainExecutable", "tasks"
+
+ then:
+ executedAndNotSkipped(":compileMainExecutableMainPlatform$platformName", ":installMainExecutable")
+
+ and:
+ executable(sourcesetVariant.dir.file("build/binaries/mainExecutable/main")).assertExists()
+ installation(sourcesetVariant.dir.file("build/install/mainExecutable")).exec().out.contains("Attributes of '$platformName' platform")
+ }
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteDefinitionIntegrationSpec.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteDefinitionIntegrationSpec.groovy
index 1f61ae3..f6815b0 100644
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteDefinitionIntegrationSpec.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteDefinitionIntegrationSpec.groovy
@@ -16,8 +16,8 @@
package org.gradle.nativeplatform
+import org.gradle.api.reporting.model.ModelReportOutput
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.util.TextUtil
class TestSuiteDefinitionIntegrationSpec extends AbstractIntegrationSpec {
def setup() {
@@ -89,15 +89,22 @@ model {
run "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- testSuites
- unitTests
- binaries
- tests
- tasks = []
- sources
- tests = DefaultCustomTestSourceSet 'unitTests:tests'
-"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ testSuites {
+ unitTests {
+ binaries {
+ tests {
+ tasks()
+ }
+ }
+ sources {
+ tests()
+ }
+ }
+ }
+ }
+
+
when:
run "check"
@@ -123,11 +130,15 @@ model {
run "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- components
- unitTests
- binaries
- sources"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ components {
+ unitTests {
+ binaries()
+ sources()
+
+ }
+ }
+ }
when:
run "assemble"
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteModelIntegrationSpec.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteModelIntegrationSpec.groovy
index 8b439e1..a316ab6 100644
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteModelIntegrationSpec.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/TestSuiteModelIntegrationSpec.groovy
@@ -16,15 +16,14 @@
package org.gradle.nativeplatform
+import org.gradle.api.reporting.model.ModelReportOutput
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.EnableModelDsl
-import org.gradle.util.TextUtil
class TestSuiteModelIntegrationSpec extends AbstractIntegrationSpec {
def "setup"() {
EnableModelDsl.enable(executer)
-
buildScript """
apply type: NativeBinariesTestPlugin
@@ -105,11 +104,14 @@ class TestSuiteModelIntegrationSpec extends AbstractIntegrationSpec {
run "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- testSuites
- main
- binaries
- sources"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ testSuites {
+ main {
+ binaries()
+ sources()
+ }
+ }
+ }
}
def "can reference sources container for a test suite in a rule"() {
@@ -164,21 +166,31 @@ class TestSuiteModelIntegrationSpec extends AbstractIntegrationSpec {
run "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- testSuites
- foo
- binaries
- sources
- bar = DefaultCustomLanguageSourceSet 'foo:bar'
- main
- binaries
- sources
- main = DefaultCustomLanguageSourceSet 'main:main'
- test = DefaultCustomLanguageSourceSet 'main:test'
- secondary
- binaries
- sources
- test = DefaultCustomLanguageSourceSet 'secondary:test'"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ testSuites {
+ foo {
+ binaries()
+ sources {
+ bar(nodeValue: "DefaultCustomLanguageSourceSet 'foo:bar'")
+ }
+ }
+ main {
+ binaries()
+ sources {
+ main(nodeValue: "DefaultCustomLanguageSourceSet 'main:main'")
+ test(nodeValue: "DefaultCustomLanguageSourceSet 'main:test'")
+ }
+ }
+ secondary {
+ binaries()
+ sources {
+ test(nodeValue: "DefaultCustomLanguageSourceSet 'secondary:test'")
+
+ }
+ }
+ }
+ }
+
}
def "can reference sources container elements in a rule"() {
@@ -274,14 +286,24 @@ class TestSuiteModelIntegrationSpec extends AbstractIntegrationSpec {
run "model"
then:
- output.contains(TextUtil.toPlatformLineSeparators("""
- testSuites
- main
- binaries
- first
- tasks = []
- second
- tasks = []"""))
+ ModelReportOutput.from(output).hasNodeStructure {
+ testSuites {
+ main {
+ binaries {
+ first {
+ tasks(nodeValue: "[]")
+ }
+ second {
+ tasks(nodeValue: "[]")
+ }
+
+ }
+ sources {
+
+ }
+ }
+ }
+ }
}
def "can reference binaries container for a test suite in a rule"() {
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/platform/BinaryNativePlatformIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/platform/BinaryNativePlatformIntegrationTest.groovy
index 1d175dc..d27c7bb 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/platform/BinaryNativePlatformIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/platform/BinaryNativePlatformIntegrationTest.groovy
@@ -370,7 +370,7 @@ model {
fails "mainExecutable"
then:
- failure.assertHasCause("Exception thrown while executing model rule: org.gradle.nativeplatform.internal.configure.NativeComponentRules#createBinaries(")
+ failure.assertHasCause("Exception thrown while executing model rule: NativeComponentRules#createBinaries")
failure.assertHasCause("Invalid NativePlatform: unknown")
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/sourceset/GeneratedSourcesIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/sourceset/GeneratedSourcesIntegrationTest.groovy
index e163f37..b4996a5 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/sourceset/GeneratedSourcesIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/sourceset/GeneratedSourcesIntegrationTest.groovy
@@ -342,7 +342,7 @@ model {
fails "mainExecutable"
then:
- failure.assertHasCause "Exception thrown while executing model rule: org.gradle.nativeplatform.plugins.NativeComponentModelPlugin\$Rules#configureGeneratedSourceSets("
+ failure.assertHasCause "Exception thrown while executing model rule: NativeComponentModelPlugin.Rules#configureGeneratedSourceSets"
failure.assertHasCause "Could not find property 'sourceDir' on task ':generateSources'."
}
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainCustomisationIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainCustomisationIntegrationTest.groovy
index 31fc530..7fde7fa 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainCustomisationIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainCustomisationIntegrationTest.groovy
@@ -20,6 +20,7 @@ import org.gradle.internal.os.OperatingSystem
import org.gradle.nativeplatform.fixtures.AbstractInstalledToolChainIntegrationSpec
import org.gradle.nativeplatform.fixtures.RequiresInstalledToolChain
import org.gradle.nativeplatform.fixtures.app.CHelloWorldApp
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@@ -27,6 +28,7 @@ import org.gradle.util.TestPrecondition
import static org.gradle.nativeplatform.fixtures.ToolChainRequirement.GccCompatible
@RequiresInstalledToolChain(GccCompatible)
+ at LeaksFileHandles
class GccToolChainCustomisationIntegrationTest extends AbstractInstalledToolChainIntegrationSpec {
def helloWorldApp = new CHelloWorldApp()
diff --git a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainDiscoveryIntegrationTest.groovy b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainDiscoveryIntegrationTest.groovy
index 2ca464c..3df7cf4 100755
--- a/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainDiscoveryIntegrationTest.groovy
+++ b/subprojects/platform-native/src/integTest/groovy/org/gradle/nativeplatform/toolchain/GccToolChainDiscoveryIntegrationTest.groovy
@@ -21,6 +21,7 @@ import org.gradle.nativeplatform.fixtures.AbstractInstalledToolChainIntegrationS
import org.gradle.nativeplatform.fixtures.NativePlatformsTestFixture
import org.gradle.nativeplatform.fixtures.RequiresInstalledToolChain
import org.gradle.nativeplatform.fixtures.app.CHelloWorldApp
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.hamcrest.Matchers
import spock.lang.IgnoreIf
@@ -53,6 +54,7 @@ model {
helloWorldApp.library.writeSources(file("src/hello"))
}
+ @LeaksFileHandles
def "can build when language tools that are not required are not available"() {
when:
buildFile << """
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeBinarySpec.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeBinarySpec.java
index 9c4e561..d4ff755 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeBinarySpec.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeBinarySpec.java
@@ -113,7 +113,7 @@ public abstract class AbstractNativeBinarySpec extends BaseBinarySpec implements
}
public Collection<NativeDependencySet> getLibs() {
- return resolve(getSource().withType(DependentSourceSet.class)).getAllResults();
+ return resolve(getInputs().withType(DependentSourceSet.class)).getAllResults();
}
public Collection<NativeDependencySet> getLibs(DependentSourceSet sourceSet) {
@@ -125,14 +125,14 @@ public abstract class AbstractNativeBinarySpec extends BaseBinarySpec implements
}
public Collection<NativeLibraryBinary> getDependentBinaries() {
- return resolve(getSource().withType(DependentSourceSet.class)).getAllLibraryBinaries();
+ return resolve(getInputs().withType(DependentSourceSet.class)).getAllLibraryBinaries();
}
public Map<File, PreCompiledHeader> getPrefixFileToPCH() {
return prefixFileToPCH;
}
- private NativeBinaryResolveResult resolve(Collection<? extends DependentSourceSet> sourceSets) {
+ private NativeBinaryResolveResult resolve(Iterable<? extends DependentSourceSet> sourceSets) {
Set<? super Object> allLibs = new LinkedHashSet<Object>(libs);
for (DependentSourceSet dependentSourceSet : sourceSets) {
allLibs.addAll(dependentSourceSet.getLibs());
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeComponentSpec.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeComponentSpec.java
index f9ed0e5..73d5ef4 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeComponentSpec.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeComponentSpec.java
@@ -15,13 +15,13 @@
*/
package org.gradle.nativeplatform.internal;
-import com.google.common.collect.Sets;
import org.gradle.nativeplatform.NativeComponentSpec;
import org.gradle.nativeplatform.ObjectFile;
import org.gradle.platform.base.TransformationFileType;
import org.gradle.platform.base.component.BaseComponentSpec;
import org.gradle.util.GUtil;
+import java.util.Collections;
import java.util.Set;
public abstract class AbstractNativeComponentSpec extends BaseComponentSpec implements NativeComponentSpec {
@@ -35,9 +35,7 @@ public abstract class AbstractNativeComponentSpec extends BaseComponentSpec impl
this.baseName = baseName;
}
- public Set<Class<? extends TransformationFileType>> getInputTypes() {
- Set<Class<? extends TransformationFileType>> inputTypes = Sets.newHashSet();
- inputTypes.add(ObjectFile.class);
- return inputTypes;
+ public Set<? extends Class<? extends TransformationFileType>> getInputTypes() {
+ return Collections.singleton(ObjectFile.class);
}
}
\ No newline at end of file
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeLibraryBinarySpec.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeLibraryBinarySpec.java
index de353d2..bd3237e 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeLibraryBinarySpec.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/AbstractNativeLibraryBinarySpec.java
@@ -41,7 +41,7 @@ public abstract class AbstractNativeLibraryBinarySpec extends AbstractNativeBina
}
protected boolean hasSources() {
- for (LanguageSourceSet sourceSet : getSource()) {
+ for (LanguageSourceSet sourceSet : getInputs()) {
if (!sourceSet.getSource().isEmpty()) {
return true;
}
@@ -60,7 +60,7 @@ public abstract class AbstractNativeLibraryBinarySpec extends AbstractNativeBina
public Set<File> getFiles() {
Set<File> headerDirs = new LinkedHashSet<File>();
- for (HeaderExportingSourceSet sourceSet : getSource().withType(HeaderExportingSourceSet.class)) {
+ for (HeaderExportingSourceSet sourceSet : getInputs().withType(HeaderExportingSourceSet.class)) {
headerDirs.addAll(sourceSet.getExportedHeaders().getSrcDirs());
}
return headerDirs;
@@ -69,7 +69,7 @@ public abstract class AbstractNativeLibraryBinarySpec extends AbstractNativeBina
@Override
public TaskDependency getBuildDependencies() {
DefaultTaskDependency dependency = new DefaultTaskDependency();
- for (HeaderExportingSourceSet sourceSet : getSource().withType(HeaderExportingSourceSet.class)) {
+ for (HeaderExportingSourceSet sourceSet : getInputs().withType(HeaderExportingSourceSet.class)) {
dependency.add(sourceSet.getBuildDependencies());
}
return dependency;
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpec.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpec.java
index 6339f26..1ed627f 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpec.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpec.java
@@ -98,7 +98,7 @@ public class DefaultSharedLibraryBinarySpec extends AbstractNativeLibraryBinaryS
}
private boolean hasResources() {
- for (NativeResourceSet windowsResourceSet : getSource().withType(NativeResourceSet.class)) {
+ for (NativeResourceSet windowsResourceSet : getInputs().withType(NativeResourceSet.class)) {
if (!windowsResourceSet.getSource().isEmpty()) {
return true;
}
@@ -107,7 +107,7 @@ public class DefaultSharedLibraryBinarySpec extends AbstractNativeLibraryBinaryS
}
private boolean hasExportedSymbols() {
- for (LanguageSourceSet languageSourceSet : getSource()) {
+ for (LanguageSourceSet languageSourceSet : getInputs()) {
if (!(languageSourceSet instanceof NativeResourceSet)) {
if (!languageSourceSet.getSource().isEmpty()) {
return true;
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/configure/NativeComponentRules.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/configure/NativeComponentRules.java
index eb4a7a7..e047302 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/configure/NativeComponentRules.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/configure/NativeComponentRules.java
@@ -44,7 +44,7 @@ import java.util.Set;
public class NativeComponentRules extends RuleSource {
@Defaults
public void applyHeaderSourceSetConventions(final NativeComponentSpec component) {
- component.getSource().withType(HeaderExportingSourceSet.class).afterEach(new Action<HeaderExportingSourceSet>() {
+ component.getSources().withType(HeaderExportingSourceSet.class).afterEach(new Action<HeaderExportingSourceSet>() {
@Override
public void execute(HeaderExportingSourceSet headerSourceSet) {
// Only apply default locations when none explicitly configured
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/prebuilt/PrebuiltLibraryBinaryLocator.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/prebuilt/PrebuiltLibraryBinaryLocator.java
index 51ff73b..1ff07d0 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/prebuilt/PrebuiltLibraryBinaryLocator.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/prebuilt/PrebuiltLibraryBinaryLocator.java
@@ -18,26 +18,26 @@ package org.gradle.nativeplatform.internal.prebuilt;
import org.gradle.api.DomainObjectSet;
import org.gradle.api.NamedDomainObjectSet;
-import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
import org.gradle.model.internal.core.ModelPath;
+import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.model.internal.type.ModelType;
import org.gradle.nativeplatform.*;
import org.gradle.nativeplatform.internal.resolve.LibraryBinaryLocator;
-import org.gradle.nativeplatform.internal.resolve.ProjectLocator;
import java.util.ArrayList;
import java.util.List;
public class PrebuiltLibraryBinaryLocator implements LibraryBinaryLocator {
- private final ProjectLocator projectLocator;
+ private final ProjectModelResolver projectModelResolver;
- public PrebuiltLibraryBinaryLocator(ProjectLocator projectLocator) {
- this.projectLocator = projectLocator;
+ public PrebuiltLibraryBinaryLocator(ProjectModelResolver projectModelResolver) {
+ this.projectModelResolver = projectModelResolver;
}
public DomainObjectSet<NativeLibraryBinary> getBinaries(NativeLibraryRequirement requirement) {
- ProjectInternal project = projectLocator.locateProject(requirement.getProjectPath());
- NamedDomainObjectSet<PrebuiltLibraries> repositories = project.getModelRegistry().realize(ModelPath.path("repositories"), ModelType.of(Repositories.class)).withType(PrebuiltLibraries.class);
+ ModelRegistry projectModel = projectModelResolver.resolveProjectModel(requirement.getProjectPath());
+ NamedDomainObjectSet<PrebuiltLibraries> repositories = projectModel.realize(ModelPath.path("repositories"), ModelType.of(Repositories.class)).withType(PrebuiltLibraries.class);
if (repositories.isEmpty()) {
throw new PrebuiltLibraryResolveException("Project does not have any prebuilt library repositories.");
}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ChainedLibraryBinaryLocator.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ChainedLibraryBinaryLocator.java
index f215c2e..46746fa 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ChainedLibraryBinaryLocator.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ChainedLibraryBinaryLocator.java
@@ -17,6 +17,7 @@
package org.gradle.nativeplatform.internal.resolve;
import org.gradle.api.DomainObjectSet;
+import org.gradle.language.base.internal.resolve.LibraryResolveException;
import org.gradle.nativeplatform.NativeLibraryBinary;
import org.gradle.nativeplatform.NativeLibraryRequirement;
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/CurrentProjectModelResolver.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/CurrentProjectModelResolver.java
new file mode 100644
index 0000000..c670221
--- /dev/null
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/CurrentProjectModelResolver.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.nativeplatform.internal.resolve;
+
+import org.gradle.api.internal.resolve.ProjectModelResolver;
+import org.gradle.model.internal.registry.ModelRegistry;
+
+public class CurrentProjectModelResolver implements ProjectModelResolver {
+ private final String projectPath;
+ private final ProjectModelResolver delegate;
+
+ public CurrentProjectModelResolver(String projectPath, ProjectModelResolver delegate) {
+ this.projectPath = projectPath;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public ModelRegistry resolveProjectModel(String path) {
+ if (path == null || path.length() == 0) {
+ return delegate.resolveProjectModel(projectPath);
+ }
+
+ return delegate.resolveProjectModel(path);
+ }
+}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/DefaultLibraryResolver.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/DefaultLibraryResolver.java
index 3a6e629..5446a40 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/DefaultLibraryResolver.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/DefaultLibraryResolver.java
@@ -17,6 +17,7 @@ package org.gradle.nativeplatform.internal.resolve;
import org.gradle.api.DomainObjectSet;
import org.gradle.api.InvalidUserDataException;
+import org.gradle.language.base.internal.resolve.LibraryResolveException;
import org.gradle.nativeplatform.*;
import org.gradle.nativeplatform.platform.NativePlatform;
import org.gradle.util.GUtil;
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/DefaultProjectLocator.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/DefaultProjectLocator.java
deleted file mode 100644
index e39e7af..0000000
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/DefaultProjectLocator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.nativeplatform.internal.resolve;
-
-import org.gradle.api.internal.artifacts.dsl.dependencies.ProjectFinder;
-import org.gradle.api.internal.project.ProjectInternal;
-
-public class DefaultProjectLocator implements ProjectLocator {
- private final String projectPath;
- private final ProjectFinder delegate;
-
- public DefaultProjectLocator(String projectPath, ProjectFinder delegate) {
- this.projectPath = projectPath;
- this.delegate = delegate;
- }
-
- public ProjectInternal locateProject(String path) {
- if (path == null || path.length() == 0) {
- return delegate.getProject(projectPath);
- }
-
- ProjectInternal referencedProject = delegate.getProject(path);
- // TODO This is a brain-dead way to ensure that the reference project's model is ready to access
- referencedProject.evaluate();
- referencedProject.getTasks().discoverTasks();
- return referencedProject;
- }
-}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/LibraryResolveException.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/LibraryResolveException.java
deleted file mode 100644
index b92f26a..0000000
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/LibraryResolveException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.nativeplatform.internal.resolve;
-
-import org.gradle.internal.exceptions.DefaultMultiCauseException;
-import org.gradle.internal.exceptions.Contextual;
-
- at Contextual
-class LibraryResolveException extends DefaultMultiCauseException {
-
- public LibraryResolveException(String message) {
- super(message);
- }
-
- LibraryResolveException(String message, Iterable<? extends Throwable> causes) {
- super(message, causes);
- }
-}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java
index 1e7f5b1..c2e35b9 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java
@@ -16,7 +16,10 @@
package org.gradle.nativeplatform.internal.resolve;
import org.gradle.api.internal.artifacts.configurations.DependencyMetaDataProvider;
-import org.gradle.api.internal.artifacts.dsl.dependencies.ProjectFinder;
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.project.ProjectRegistry;
+import org.gradle.api.internal.resolve.DefaultProjectModelResolver;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
import org.gradle.nativeplatform.internal.prebuilt.PrebuiltLibraryBinaryLocator;
import java.util.ArrayList;
@@ -24,15 +27,15 @@ import java.util.List;
public class NativeDependencyResolverServices {
- public ProjectLocator createProjectLocator(ProjectFinder projectFinder, DependencyMetaDataProvider metaDataProvider) {
+ public ProjectModelResolver createProjectLocator(ProjectRegistry<ProjectInternal> projectRegistry, DependencyMetaDataProvider metaDataProvider) {
String currentProjectPath = metaDataProvider.getModule().getProjectPath();
- return new DefaultProjectLocator(currentProjectPath, projectFinder);
+ return new CurrentProjectModelResolver(currentProjectPath, new DefaultProjectModelResolver(projectRegistry));
}
- public LibraryBinaryLocator createLibraryBinaryLocator(ProjectLocator projectLocator) {
+ public LibraryBinaryLocator createLibraryBinaryLocator(ProjectModelResolver projectModelResolver) {
List<LibraryBinaryLocator> locators = new ArrayList<LibraryBinaryLocator>();
- locators.add(new ProjectLibraryBinaryLocator(projectLocator));
- locators.add(new PrebuiltLibraryBinaryLocator(projectLocator));
+ locators.add(new ProjectLibraryBinaryLocator(projectModelResolver));
+ locators.add(new PrebuiltLibraryBinaryLocator(projectModelResolver));
return new ChainedLibraryBinaryLocator(locators);
}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java
index ded54d3..e9838ab 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java
@@ -18,7 +18,8 @@ package org.gradle.nativeplatform.internal.resolve;
import org.gradle.api.DomainObjectSet;
import org.gradle.api.UnknownDomainObjectException;
import org.gradle.api.internal.DefaultDomainObjectSet;
-import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.resolve.ProjectModelResolver;
+import org.gradle.language.base.internal.resolve.LibraryResolveException;
import org.gradle.model.ModelMap;
import org.gradle.model.internal.core.ModelPath;
import org.gradle.model.internal.registry.ModelRegistry;
@@ -30,19 +31,18 @@ import org.gradle.nativeplatform.NativeLibrarySpec;
import org.gradle.platform.base.ComponentSpecContainer;
public class ProjectLibraryBinaryLocator implements LibraryBinaryLocator {
- private final ProjectLocator projectLocator;
+ private final ProjectModelResolver projectModelResolver;
- public ProjectLibraryBinaryLocator(ProjectLocator projectLocator) {
- this.projectLocator = projectLocator;
+ public ProjectLibraryBinaryLocator(ProjectModelResolver projectModelResolver) {
+ this.projectModelResolver = projectModelResolver;
}
// Converts the binaries of a project library into regular binary instances
public DomainObjectSet<NativeLibraryBinary> getBinaries(NativeLibraryRequirement requirement) {
- ProjectInternal project = findProject(requirement);
- ModelRegistry modelRegistry = project.getModelRegistry();
- ComponentSpecContainer components = modelRegistry.find(ModelPath.path("components"), ModelType.of(ComponentSpecContainer.class));
+ ModelRegistry projectModel = findProject(requirement);
+ ComponentSpecContainer components = projectModel.find(ModelPath.path("components"), ModelType.of(ComponentSpecContainer.class));
if (components == null) {
- throw new LibraryResolveException(String.format("Project does not have a libraries container: '%s'", project.getPath()));
+ throw new LibraryResolveException(String.format("Project does not have a libraries container: '%s'", requirement.getProjectPath()));
}
String libraryName = requirement.getLibraryName();
NativeLibrarySpec library = components.withType(NativeLibrarySpec.class).get(libraryName);
@@ -51,15 +51,14 @@ public class ProjectLibraryBinaryLocator implements LibraryBinaryLocator {
}
ModelMap<NativeBinarySpec> projectBinaries = library.getBinaries().withType(NativeBinarySpec.class);
DomainObjectSet<NativeLibraryBinary> binaries = new DefaultDomainObjectSet<NativeLibraryBinary>(NativeLibraryBinary.class);
- // TODO:DAZ Convert, don't cast
for (NativeBinarySpec nativeBinarySpec : projectBinaries.values()) {
binaries.add((NativeLibraryBinary) nativeBinarySpec);
}
return binaries;
}
- private ProjectInternal findProject(NativeLibraryRequirement requirement) {
- return projectLocator.locateProject(requirement.getProjectPath());
+ private ModelRegistry findProject(NativeLibraryRequirement requirement) {
+ return projectModelResolver.resolveProjectModel(requirement.getProjectPath());
}
}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLocator.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLocator.java
deleted file mode 100644
index 7d316af..0000000
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLocator.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.nativeplatform.internal.resolve;
-
-import org.gradle.api.internal.project.ProjectInternal;
-
-public interface ProjectLocator {
- ProjectInternal locateProject(String path);
-}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/services/NativeBinaryServices.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/services/NativeBinaryServices.java
index f8908b9..20a42df 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/services/NativeBinaryServices.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/internal/services/NativeBinaryServices.java
@@ -39,6 +39,9 @@ public class NativeBinaryServices implements PluginServiceRegistry {
registration.add(NativePlatformResolver.class);
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.add(DefaultVisualStudioLocator.class);
registration.add(DefaultWindowsSdkLocator.class);
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/Architecture.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/Architecture.java
index 7113204..299741b 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/Architecture.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/Architecture.java
@@ -21,6 +21,39 @@ import org.gradle.internal.HasInternalProtocol;
/**
* A cpu architecture.
+ *
+ * <table>
+ * <tr>
+ * <th>Instruction Set</th>
+ * <th>32-bit names</th>
+ * <th>64-bit names</th>
+ * </tr>
+ * <tr>
+ * <td>Intel x86</td>
+ * <td>"x86", "i386", "ia-32", "i686"</td>
+ * <td>"x86_64", "amd64", "x64", "x86-64"</td>
+ * </tr>
+ * <tr>
+ * <td>Intel Itanium</td>
+ * <td>N/A</td>
+ * <td>"ia-64", "ia64"</td>
+ * </tr>
+ * <tr>
+ * <td>Power PC</td>
+ * <td>"ppc"</td>
+ * <td>"ppc64"</td>
+ * </tr>
+ * <tr>
+ * <td>Sparc</td>
+ * <td>"sparc", "sparc32", "sparc-v8"</td>
+ * <td>"sparc64", "ultrasparc", "sparc-v9"</td>
+ * </tr>
+ * <tr>
+ * <td>ARM</td>
+ * <td>"arm", "arm-v7", "armv7", "arm32"</td>
+ * <td>"arm64", "arm-v8"</td>
+ * </tr>
+ * </table>
*/
@Incubating
@HasInternalProtocol
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/NativePlatform.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/NativePlatform.java
index 4349064..08bd51c 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/NativePlatform.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/NativePlatform.java
@@ -45,40 +45,10 @@ public interface NativePlatform extends Platform {
/**
* Sets the cpu architecture being targeted.
+ * <p>
* The architecture is provided as a string name, which is translated into one of the supported architecture types.
- *
- * <table>
- * <tr>
- * <th>Instruction Set</th>
- * <th>32-bit names</th>
- * <th>64-bit names</th>
- * </tr>
- * <tr>
- * <td>Intel x86</td>
- * <td>"x86", "i386", "ia-32"</td>
- * <td>"x86_64", "amd64", "x64", "x86-64"</td>
- * </tr>
- * <tr>
- * <td>Intel Itanium</td>
- * <td></td>
- * <td>"ia-64"</td>
- * </tr>
- * <tr>
- * <td>Power PC</td>
- * <td>"ppc"</td>
- * <td>"ppc64"</td>
- * </tr>
- * <tr>
- * <td>Sparc</td>
- * <td>"sparc", "sparc32", "sparc-v7", "sparc-v8"</td>
- * <td>"sparc64", "ultrasparc", "sparc-v9"</td>
- * </tr>
- * <tr>
- * <td>ARM</td>
- * <td>"arm"</td>
- * <td></td>
- * </tr>
- * </table>
+ * </p>
+ * @see Architecture Supported notations.
*/
void architecture(String name);
@@ -90,30 +60,10 @@ public interface NativePlatform extends Platform {
/**
* Sets the operating system being targeted.
+ * <p>
* The operating system is provided as a string name, which is translated into one of the supported operating system types.
- *
- * <table>
- * <tr>
- * <th>Operating System</th>
- * <th>Aliases</th>
- * </tr>
- * <tr>
- * <td>Windows</td>
- * <td>"windows"</td>
- * </tr>
- * <tr>
- * <td>GNU/Linux</td>
- * <td>"linux"</td>
- * </tr>
- * <tr>
- * <td>Mac OS X</td>
- * <td>"osx", "mac os x", "darwin"</td>
- * </tr>
- * <tr>
- * <td>Solaris</td>
- * <td>"solaris", "sunos"</td>
- * </tr>
- * </table>
+ * </p>
+ * @see OperatingSystem Supported notations.
*/
void operatingSystem(String name);
}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/OperatingSystem.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/OperatingSystem.java
index 2626743..9a0a7a7 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/OperatingSystem.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/platform/OperatingSystem.java
@@ -20,6 +20,29 @@ import org.gradle.api.Named;
/**
* A machine operating system.
+ *
+ * <table>
+ * <tr>
+ * <th>Operating System</th>
+ * <th>Aliases</th>
+ * </tr>
+ * <tr>
+ * <td>Windows</td>
+ * <td>"windows"</td>
+ * </tr>
+ * <tr>
+ * <td>GNU/Linux</td>
+ * <td>"linux"</td>
+ * </tr>
+ * <tr>
+ * <td>Mac OS X</td>
+ * <td>"osx", "mac os x", "darwin"</td>
+ * </tr>
+ * <tr>
+ * <td>Solaris</td>
+ * <td>"solaris", "sunos"</td>
+ * </tr>
+ * </table>
*/
@Incubating
public interface OperatingSystem extends Named {
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java
index 8884d95..5a23de7 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java
@@ -15,9 +15,11 @@
*/
package org.gradle.nativeplatform.plugins;
+import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.gradle.api.*;
import org.gradle.api.artifacts.repositories.ArtifactRepository;
+import org.gradle.api.file.FileCollection;
import org.gradle.api.file.SourceDirectorySet;
import org.gradle.api.internal.DefaultPolymorphicDomainObjectContainer;
import org.gradle.api.internal.file.FileResolver;
@@ -31,6 +33,7 @@ import org.gradle.language.base.internal.LanguageSourceSetInternal;
import org.gradle.language.base.internal.SourceTransformTaskConfig;
import org.gradle.language.base.internal.registry.LanguageTransformContainer;
import org.gradle.language.base.plugins.ComponentModelBasePlugin;
+import org.gradle.language.base.plugins.LifecycleBasePlugin;
import org.gradle.language.nativeplatform.DependentSourceSet;
import org.gradle.language.nativeplatform.HeaderExportingSourceSet;
import org.gradle.language.nativeplatform.internal.DependentSourceSetInternal;
@@ -46,7 +49,8 @@ import org.gradle.nativeplatform.internal.prebuilt.PrebuiltLibraryInitializer;
import org.gradle.nativeplatform.platform.NativePlatform;
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform;
import org.gradle.nativeplatform.platform.internal.NativePlatforms;
-import org.gradle.nativeplatform.tasks.PrefixHeaderFileGenerateTask;
+import org.gradle.nativeplatform.tasks.*;
+import org.gradle.nativeplatform.test.internal.NativeTestSuiteBinarySpecInternal;
import org.gradle.nativeplatform.toolchain.internal.DefaultNativeToolChainRegistry;
import org.gradle.nativeplatform.toolchain.internal.NativeToolChainRegistryInternal;
import org.gradle.nativeplatform.toolchain.internal.PreCompiledHeader;
@@ -55,6 +59,8 @@ import org.gradle.platform.base.internal.PlatformResolvers;
import javax.inject.Inject;
import java.io.File;
+import java.util.List;
+import java.util.concurrent.Callable;
/**
* A plugin that sets up the infrastructure for defining native binaries.
@@ -176,7 +182,7 @@ public class NativeComponentModelPlugin implements Plugin<ProjectInternal> {
componentSpecs.afterEach(new Action<NativeComponentSpec>() {
@Override
public void execute(NativeComponentSpec componentSpec) {
- componentSpec.getSource().withType(LanguageSourceSet.class).afterEach(new Action<LanguageSourceSet>() {
+ componentSpec.getSources().withType(LanguageSourceSet.class).afterEach(new Action<LanguageSourceSet>() {
@Override
public void execute(LanguageSourceSet languageSourceSet) {
LanguageSourceSetInternal internalSourceSet = (LanguageSourceSetInternal) languageSourceSet;
@@ -199,7 +205,7 @@ public class NativeComponentModelPlugin implements Plugin<ProjectInternal> {
componentSpecs.afterEach(new Action<NativeComponentSpec>() {
@Override
public void execute(final NativeComponentSpec componentSpec) {
- componentSpec.getSource().withType(DependentSourceSet.class).afterEach(new Action<DependentSourceSet>() {
+ componentSpec.getSources().withType(DependentSourceSet.class).afterEach(new Action<DependentSourceSet>() {
@Override
public void execute(DependentSourceSet dependentSourceSet) {
if (dependentSourceSet.getPreCompiledHeader() != null) {
@@ -218,7 +224,7 @@ public class NativeComponentModelPlugin implements Plugin<ProjectInternal> {
@Mutate
void configurePrefixHeaderGenerationTasks(final TaskContainer tasks, ModelMap<NativeComponentSpec> nativeComponents) {
for (final NativeComponentSpec nativeComponentSpec : nativeComponents.values()) {
- for (final DependentSourceSet dependentSourceSet : nativeComponentSpec.getSource().withType(DependentSourceSet.class).values()) {
+ for (final DependentSourceSet dependentSourceSet : nativeComponentSpec.getSources().withType(DependentSourceSet.class).values()) {
final DependentSourceSetInternal internalSourceSet = (DependentSourceSetInternal) dependentSourceSet;
if (internalSourceSet.getPrefixHeaderFile() != null) {
String taskName = String.format("generate%s%sPrefixHeaderFile", StringUtils.capitalize(nativeComponentSpec.getName()), StringUtils.capitalize(dependentSourceSet.getName()));
@@ -235,31 +241,29 @@ public class NativeComponentModelPlugin implements Plugin<ProjectInternal> {
}
@Mutate
- void configurePreCompiledHeaderCompileTasks(ModelMap<NativeBinarySpecInternal> binaries, final ServiceRegistry serviceRegistry, final LanguageTransformContainer languageTransforms, final @Path("buildDir") File buildDir) {
- binaries.all(new Action<NativeBinarySpecInternal>() {
- @Override
- public void execute(final NativeBinarySpecInternal nativeBinarySpec) {
- for (final PchEnabledLanguageTransform<?> transform : languageTransforms.withType(PchEnabledLanguageTransform.class)) {
- nativeBinarySpec.getSource().withType(transform.getSourceSetType(), new Action<LanguageSourceSet>() {
- @Override
- public void execute(final LanguageSourceSet languageSourceSet) {
- final DependentSourceSet dependentSourceSet = (DependentSourceSet) languageSourceSet;
- if (dependentSourceSet.getPreCompiledHeader() != null) {
- nativeBinarySpec.getPrefixFileToPCH().put(((DependentSourceSetInternal) dependentSourceSet).getPrefixHeaderFile(), new PreCompiledHeader());
- final SourceTransformTaskConfig pchTransformTaskConfig = transform.getPchTransformTask();
- String pchTaskName = String.format("%s%s%sPreCompiledHeader", pchTransformTaskConfig.getTaskPrefix(), StringUtils.capitalize(nativeBinarySpec.getName()), StringUtils.capitalize(dependentSourceSet.getName()));
- nativeBinarySpec.getTasks().create(pchTaskName, pchTransformTaskConfig.getTaskType(), new Action<DefaultTask>() {
- @Override
- public void execute(DefaultTask task) {
- pchTransformTaskConfig.configureTask(task, nativeBinarySpec, dependentSourceSet);
- }
- });
- }
+ void configurePreCompiledHeaderCompileTasks(final TaskContainer tasks, ModelMap<NativeBinarySpecInternal> binaries, final LanguageTransformContainer languageTransforms, final ServiceRegistry serviceRegistry) {
+ for (final NativeBinarySpecInternal nativeBinarySpec : binaries.values()) {
+ for (final PchEnabledLanguageTransform<?> transform : languageTransforms.withType(PchEnabledLanguageTransform.class)) {
+ nativeBinarySpec.getInputs().withType(transform.getSourceSetType(), new Action<LanguageSourceSet>() {
+ @Override
+ public void execute(final LanguageSourceSet languageSourceSet) {
+ final DependentSourceSet dependentSourceSet = (DependentSourceSet) languageSourceSet;
+ if (dependentSourceSet.getPreCompiledHeader() != null) {
+ nativeBinarySpec.getPrefixFileToPCH().put(((DependentSourceSetInternal) dependentSourceSet).getPrefixHeaderFile(), new PreCompiledHeader());
+ final SourceTransformTaskConfig pchTransformTaskConfig = transform.getPchTransformTask();
+ String pchTaskName = String.format("%s%s%sPreCompiledHeader", pchTransformTaskConfig.getTaskPrefix(), StringUtils.capitalize(nativeBinarySpec.getName()), StringUtils.capitalize(dependentSourceSet.getName()));
+ Task pchTask = tasks.create(pchTaskName, pchTransformTaskConfig.getTaskType(), new Action<DefaultTask>() {
+ @Override
+ public void execute(DefaultTask task) {
+ pchTransformTaskConfig.configureTask(task, nativeBinarySpec, dependentSourceSet, serviceRegistry);
+ }
+ });
+ nativeBinarySpec.getTasks().add(pchTask);
}
- });
- }
+ }
+ });
}
- });
+ }
}
private void maybeSetSourceDir(SourceDirectorySet sourceSet, Task task, String propertyName) {
@@ -269,6 +273,135 @@ public class NativeComponentModelPlugin implements Plugin<ProjectInternal> {
}
}
+ @BinaryTasks
+ public void createTasks(ModelMap<Task> tasks, final SharedLibraryBinarySpecInternal binary) {
+ String taskName = binary.getNamingScheme().getTaskName("link");
+ tasks.create(taskName, LinkSharedLibrary.class, new Action<LinkSharedLibrary>() {
+ @Override
+ public void execute(LinkSharedLibrary linkTask) {
+ linkTask.setDescription("Links " + binary.getName());
+ linkTask.setToolChain(binary.getToolChain());
+ linkTask.setTargetPlatform(binary.getTargetPlatform());
+ linkTask.setOutputFile(binary.getSharedLibraryFile());
+ linkTask.setInstallName(binary.getSharedLibraryFile().getName());
+ linkTask.setLinkerArgs(binary.getLinker().getArgs());
+
+ linkTask.lib(new BinaryLibs(binary) {
+ @Override
+ protected FileCollection getFiles(NativeDependencySet nativeDependencySet) {
+ return nativeDependencySet.getLinkFiles();
+ }
+ });
+ }
+ });
+ }
+
+ @BinaryTasks
+ public void createTasks(ModelMap<Task> tasks, final StaticLibraryBinarySpecInternal binary) {
+ String taskName = binary.getNamingScheme().getTaskName("create");
+ tasks.create(taskName, CreateStaticLibrary.class, new Action<CreateStaticLibrary>() {
+ @Override
+ public void execute(CreateStaticLibrary task) {
+ task.setDescription("Creates " + binary.getName());
+ task.setToolChain(binary.getToolChain());
+ task.setTargetPlatform(binary.getTargetPlatform());
+ task.setOutputFile(binary.getStaticLibraryFile());
+ task.setStaticLibArgs(binary.getStaticLibArchiver().getArgs());
+ }
+ });
+ }
+
+ @BinaryTasks
+ public void createTasks(ModelMap<Task> tasks, final NativeExecutableBinarySpecInternal executableBinary) {
+ createExecutableTask(tasks, executableBinary, executableBinary.getExecutableFile());
+ }
+
+ @BinaryTasks
+ public void createTasks(ModelMap<Task> tasks, final NativeTestSuiteBinarySpecInternal testSuiteBinary) {
+ createExecutableTask(tasks, testSuiteBinary, testSuiteBinary.getExecutableFile());
+ }
+
+ private void createExecutableTask(ModelMap<Task> tasks, final NativeBinarySpecInternal binary, final File executableFile) {
+ String taskName = binary.getNamingScheme().getTaskName("link");
+ tasks.create(taskName, LinkExecutable.class, new Action<LinkExecutable>() {
+ @Override
+ public void execute(LinkExecutable linkTask) {
+ linkTask.setDescription("Links " + binary.getName());
+ linkTask.setToolChain(binary.getToolChain());
+ linkTask.setTargetPlatform(binary.getTargetPlatform());
+ linkTask.setOutputFile(executableFile);
+ linkTask.setLinkerArgs(binary.getLinker().getArgs());
+
+ linkTask.lib(new BinaryLibs(binary) {
+ @Override
+ protected FileCollection getFiles(NativeDependencySet nativeDependencySet) {
+ return nativeDependencySet.getLinkFiles();
+ }
+ });
+ }
+ });
+ }
+
+ /**
+ * Can't use @BinaryTasks because the binary is not _built-by_ the install task, but it is associated with it.
+ * Rule is called multiple times, so need to check for task existence before creating.
+ */
+ @Defaults
+ void createInstallTasks(TaskContainer tasks, ModelMap<NativeBinarySpecInternal> binaries, @Path("buildDir") File buildDir) {
+ // There's no common API for NativeExecutableBinarySpec and NativeTestSuiteBinarySpec
+ for (NativeExecutableBinarySpecInternal binary : binaries.withType(NativeExecutableBinarySpecInternal.class).values()) {
+ Task installTask = createInstallTask(tasks, binary, binary.getExecutableFile(), buildDir);
+ binary.getTasks().add(installTask);
+ }
+ for (NativeTestSuiteBinarySpecInternal binary : binaries.withType(NativeTestSuiteBinarySpecInternal.class).values()) {
+ Task installTask = createInstallTask(tasks, binary, binary.getExecutableFile(), buildDir);
+ binary.getTasks().add(installTask);
+ }
+ }
+
+ private Task createInstallTask(TaskContainer tasks, final NativeBinarySpecInternal binary, final File executableFile, final File buildDirectory) {
+ return tasks.create(binary.getNamingScheme().getTaskName("install"), InstallExecutable.class, new Action<InstallExecutable>() {
+ @Override
+ public void execute(InstallExecutable installTask) {
+ installTask.setDescription("Installs a development image of " + binary.getName());
+ installTask.setGroup(LifecycleBasePlugin.BUILD_GROUP);
+ installTask.setToolChain(binary.getToolChain());
+
+ File defaultDestination = new File(buildDirectory, "install/" + binary.getNamingScheme().getOutputDirectoryBase());
+ installTask.setDestinationDir(defaultDestination);
+
+ installTask.setExecutable(executableFile);
+
+ installTask.lib(new BinaryLibs(binary) {
+ @Override
+ protected FileCollection getFiles(NativeDependencySet nativeDependencySet) {
+ return nativeDependencySet.getRuntimeFiles();
+ }
+ });
+
+ installTask.dependsOn(binary);
+ }
+ });
+ }
+ }
+
+ private abstract static class BinaryLibs implements Callable<List<FileCollection>> {
+ private final NativeBinarySpec binary;
+
+ public BinaryLibs(NativeBinarySpec binary) {
+ this.binary = binary;
+ }
+
+ @Override
+ public List<FileCollection> call() throws Exception {
+ List<FileCollection> runtimeFiles = Lists.newArrayList();
+ for (NativeDependencySet nativeDependencySet : binary.getLibs()) {
+ runtimeFiles.add(getFiles(nativeDependencySet));
+ }
+ return runtimeFiles;
+ }
+
+ protected abstract FileCollection getFiles(NativeDependencySet nativeDependencySet);
}
private static class DefaultRepositories extends DefaultPolymorphicDomainObjectContainer<ArtifactRepository> implements Repositories {
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentPlugin.groovy b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentPlugin.groovy
deleted file mode 100644
index 1d2d572..0000000
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentPlugin.groovy
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.nativeplatform.plugins
-
-import org.gradle.api.Incubating
-import org.gradle.api.Plugin
-import org.gradle.api.internal.project.ProjectInternal
-import org.gradle.api.tasks.TaskContainer
-import org.gradle.language.base.plugins.LifecycleBasePlugin
-import org.gradle.nativeplatform.NativeBinarySpec
-import org.gradle.nativeplatform.NativeExecutableBinarySpec
-import org.gradle.nativeplatform.SharedLibraryBinarySpec
-import org.gradle.nativeplatform.StaticLibraryBinarySpec
-import org.gradle.nativeplatform.internal.NativeBinarySpecInternal
-import org.gradle.nativeplatform.tasks.CreateStaticLibrary
-import org.gradle.nativeplatform.tasks.InstallExecutable
-import org.gradle.nativeplatform.tasks.LinkExecutable
-import org.gradle.nativeplatform.tasks.LinkSharedLibrary
-import org.gradle.nativeplatform.test.NativeTestSuiteBinarySpec
-import org.gradle.nativeplatform.toolchain.internal.plugins.StandardToolChainsPlugin
-import org.gradle.platform.base.BinaryContainer
-
-/**
- * A plugin that creates tasks used for constructing native binaries.
- */
- at Incubating
-public class NativeComponentPlugin implements Plugin<ProjectInternal> {
-
- public void apply(final ProjectInternal project) {
- project.pluginManager.apply(NativeComponentModelPlugin.class);
- project.pluginManager.apply(StandardToolChainsPlugin)
-
- createTasks(project.tasks, project.binaries)
- }
-
- // TODO:DAZ Convert to a model rule and use simple iteration - this breaks non-rule code that uses binary.tasks.link
- static void createTasks(TaskContainer tasks, BinaryContainer binaries) {
- binaries.withType(NativeBinarySpec) { NativeBinarySpecInternal binary ->
- createTasksForBinary(tasks, binary)
- }
- }
-
- private static void createTasksForBinary(TaskContainer tasks, NativeBinarySpecInternal binary) {
- def builderTask
- if (binary instanceof NativeExecutableBinarySpec || binary instanceof NativeTestSuiteBinarySpec) {
- builderTask = createLinkExecutableTask(tasks, binary)
- binary.tasks.add createInstallTask(tasks, binary);
- } else if (binary instanceof SharedLibraryBinarySpec) {
- builderTask = createLinkSharedLibraryTask(tasks, binary)
- } else if (binary instanceof StaticLibraryBinarySpec) {
- builderTask = createStaticLibraryTask(tasks, binary)
- } else {
- throw new RuntimeException("Not a valid binary type for building: " + binary)
- }
- binary.tasks.add builderTask
- binary.builtBy builderTask
- }
-
- private static LinkExecutable createLinkExecutableTask(TaskContainer tasks, def executable) {
- def binary = executable as NativeBinarySpecInternal
- LinkExecutable linkTask = tasks.create(binary.namingScheme.getTaskName("link"), LinkExecutable)
- linkTask.description = "Links ${executable}"
-
- linkTask.toolChain = binary.toolChain
- linkTask.targetPlatform = executable.targetPlatform
-
- linkTask.lib { binary.libs*.linkFiles }
-
- linkTask.conventionMapping.outputFile = { executable.executableFile }
- linkTask.linkerArgs = binary.linker.args
- return linkTask
- }
-
- private static LinkSharedLibrary createLinkSharedLibraryTask(TaskContainer tasks, SharedLibraryBinarySpec sharedLibrary) {
- def binary = sharedLibrary as NativeBinarySpecInternal
- LinkSharedLibrary linkTask = tasks.create(binary.namingScheme.getTaskName("link"), LinkSharedLibrary)
- linkTask.description = "Links ${sharedLibrary}"
-
- linkTask.toolChain = binary.toolChain
- linkTask.targetPlatform = binary.targetPlatform
-
- linkTask.lib { binary.libs*.linkFiles }
-
- linkTask.conventionMapping.outputFile = { sharedLibrary.sharedLibraryFile }
- linkTask.conventionMapping.installName = { sharedLibrary.sharedLibraryFile.name }
- linkTask.linkerArgs = binary.linker.args
- return linkTask
- }
-
- private static CreateStaticLibrary createStaticLibraryTask(TaskContainer tasks, StaticLibraryBinarySpec staticLibrary) {
- def binary = staticLibrary as NativeBinarySpecInternal
- CreateStaticLibrary task = tasks.create(binary.namingScheme.getTaskName("create"), CreateStaticLibrary)
- task.description = "Creates ${staticLibrary}"
-
- task.toolChain = binary.toolChain
- task.targetPlatform = staticLibrary.targetPlatform
- task.conventionMapping.outputFile = { staticLibrary.staticLibraryFile }
- task.staticLibArgs = binary.staticLibArchiver.args
- return task
- }
-
- private static createInstallTask(TaskContainer tasks, def executable) {
- def binary = executable as NativeBinarySpecInternal
- InstallExecutable installTask = tasks.create(binary.namingScheme.getTaskName("install"), InstallExecutable)
- installTask.description = "Installs a development image of $executable"
- installTask.group = LifecycleBasePlugin.BUILD_GROUP
-
- installTask.toolChain = binary.toolChain
-
- def project = installTask.project
- installTask.conventionMapping.destinationDir = { project.file("${project.buildDir}/install/${binary.namingScheme.outputDirectoryBase}") }
-
- installTask.conventionMapping.executable = { executable.executableFile }
- installTask.lib { binary.libs*.runtimeFiles }
-
- installTask.dependsOn(executable)
- return installTask
- }
-}
\ No newline at end of file
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentPlugin.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentPlugin.java
new file mode 100644
index 0000000..ee46d12
--- /dev/null
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/plugins/NativeComponentPlugin.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.nativeplatform.plugins;
+
+import org.gradle.api.Incubating;
+import org.gradle.api.Plugin;
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.nativeplatform.toolchain.internal.plugins.StandardToolChainsPlugin;
+
+/**
+ * A plugin that creates tasks used for constructing native binaries.
+ */
+ at Incubating
+public class NativeComponentPlugin implements Plugin<ProjectInternal> {
+ public void apply(final ProjectInternal project) {
+ project.getPluginManager().apply(NativeComponentModelPlugin.class);
+ project.getPluginManager().apply(StandardToolChainsPlugin.class);
+ }
+
+}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/internal/DefaultNativeTestSuiteBinarySpec.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/internal/DefaultNativeTestSuiteBinarySpec.java
index 650448f..2ad46dc 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/internal/DefaultNativeTestSuiteBinarySpec.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/internal/DefaultNativeTestSuiteBinarySpec.java
@@ -31,7 +31,7 @@ import java.io.File;
public abstract class DefaultNativeTestSuiteBinarySpec extends AbstractNativeBinarySpec implements NativeTestSuiteBinarySpecInternal {
private final DefaultTasksCollection tasks = new DefaultTasksCollection(super.getTasks());
- private NativeBinarySpec testedBinary;
+ private NativeBinarySpecInternal testedBinary;
private File executableFile;
@Override
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/plugins/NativeBinariesTestPlugin.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/plugins/NativeBinariesTestPlugin.java
index 8812d14..19c2673 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/plugins/NativeBinariesTestPlugin.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/test/plugins/NativeBinariesTestPlugin.java
@@ -34,11 +34,11 @@ import org.gradle.model.internal.manage.schema.ModelMapSchema;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.model.internal.type.ModelType;
-import org.gradle.nativeplatform.NativeBinarySpec;
import org.gradle.nativeplatform.internal.NativeBinarySpecInternal;
import org.gradle.nativeplatform.plugins.NativeComponentPlugin;
import org.gradle.nativeplatform.tasks.InstallExecutable;
import org.gradle.nativeplatform.test.NativeTestSuiteBinarySpec;
+import org.gradle.nativeplatform.test.internal.NativeTestSuiteBinarySpecInternal;
import org.gradle.nativeplatform.test.tasks.RunTestExecutable;
import org.gradle.platform.base.BinaryContainer;
import org.gradle.platform.base.internal.BinaryNamingScheme;
@@ -78,13 +78,12 @@ public class NativeBinariesTestPlugin implements Plugin<Project> {
@Finalize
// Must run after test binaries have been created (currently in CUnit plugin)
void attachTestedBinarySourcesToTestBinaries(BinaryContainer binaries) {
- for (NativeTestSuiteBinarySpec testSuiteBinary : binaries.withType(NativeTestSuiteBinarySpec.class)) {
- NativeBinarySpec testedBinary = testSuiteBinary.getTestedBinary();
- testSuiteBinary.source(testedBinary.getSource());
-
- for (DependentSourceSet testSource : testSuiteBinary.getSource().withType(DependentSourceSet.class)) {
- testSource.lib(testedBinary.getSource());
+ for (NativeTestSuiteBinarySpecInternal testSuiteBinary : binaries.withType(NativeTestSuiteBinarySpecInternal.class)) {
+ NativeBinarySpecInternal testedBinary = (NativeBinarySpecInternal) testSuiteBinary.getTestedBinary();
+ for (DependentSourceSet testSource : testSuiteBinary.getInputs().withType(DependentSourceSet.class)) {
+ testSource.lib(testedBinary.getInputs());
}
+ testSuiteBinary.getInputs().addAll(testedBinary.getInputs());
}
}
diff --git a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/toolchain/internal/gcc/AbstractGccCompatibleToolChain.java b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/toolchain/internal/gcc/AbstractGccCompatibleToolChain.java
index abf76fe..80a6a74 100644
--- a/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/toolchain/internal/gcc/AbstractGccCompatibleToolChain.java
+++ b/subprojects/platform-native/src/main/groovy/org/gradle/nativeplatform/toolchain/internal/gcc/AbstractGccCompatibleToolChain.java
@@ -15,12 +15,14 @@
*/
package org.gradle.nativeplatform.toolchain.internal.gcc;
+import com.google.common.collect.Maps;
import org.gradle.api.Action;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.internal.Actions;
import org.gradle.internal.operations.BuildOperationProcessor;
import org.gradle.internal.os.OperatingSystem;
import org.gradle.internal.reflect.Instantiator;
+import org.gradle.nativeplatform.platform.NativePlatform;
import org.gradle.nativeplatform.platform.internal.NativePlatformInternal;
import org.gradle.nativeplatform.toolchain.GccCompatibleToolChain;
import org.gradle.nativeplatform.toolchain.GccPlatformToolChain;
@@ -44,6 +46,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import static java.util.Arrays.asList;
@@ -55,6 +58,7 @@ public abstract class AbstractGccCompatibleToolChain extends ExtendableToolChain
private final ExecActionFactory execActionFactory;
private final ToolSearchPath toolSearchPath;
private final List<TargetPlatformConfiguration> platformConfigs = new ArrayList<TargetPlatformConfiguration>();
+ private final Map<NativePlatform, PlatformToolProvider> toolProviders = Maps.newHashMap();
private final CompilerMetaDataProvider metaDataProvider;
private final Instantiator instantiator;
private int configInsertLocation;
@@ -111,6 +115,15 @@ public abstract class AbstractGccCompatibleToolChain extends ExtendableToolChain
}
public PlatformToolProvider select(NativePlatformInternal targetPlatform) {
+ PlatformToolProvider toolProvider = toolProviders.get(targetPlatform);
+ if (toolProvider == null) {
+ toolProvider = createPlatformToolProvider(targetPlatform);
+ toolProviders.put(targetPlatform, toolProvider);
+ }
+ return toolProvider;
+ }
+
+ private PlatformToolProvider createPlatformToolProvider(NativePlatformInternal targetPlatform) {
TargetPlatformConfiguration targetPlatformConfigurationConfiguration = getPlatformConfiguration(targetPlatform);
ToolChainAvailability result = new ToolChainAvailability();
if (targetPlatformConfigurationConfiguration == null) {
diff --git a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpecTest.groovy b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpecTest.groovy
index 789d712..2d41bbf 100644
--- a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpecTest.groovy
+++ b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultSharedLibraryBinarySpecTest.groovy
@@ -15,7 +15,6 @@
*/
package org.gradle.nativeplatform.internal
-
import org.gradle.api.Task
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.internal.project.taskfactory.ITaskFactory
@@ -87,10 +86,10 @@ class DefaultSharedLibraryBinarySpecTest extends Specification {
getFiles() >> [tmpDir.createFile("input.src")]
}
def sourceSet = Stub(HeaderExportingSourceSet) {
- getSource() >> sourceDirSet
+ getSources() >> sourceDirSet
getExportedHeaders() >> headerDirSet
}
- binary.source sourceSet
+ binary.inputs.add sourceSet
expect:
binary.sharedLibraryFile == sharedLibraryFile
@@ -116,9 +115,9 @@ class DefaultSharedLibraryBinarySpecTest extends Specification {
getFiles() >> [tmpDir.createFile("input.rc")]
}
def resourceSet = Stub(NativeResourceSet) {
- getSource() >> sourceDirSet
+ getSources() >> sourceDirSet
}
- binary.source resourceSet
+ binary.inputs.add resourceSet
def binaryFile = tmpDir.createFile("binary.run")
def linkFile = tmpDir.createFile("binary.link")
diff --git a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultStaticLibraryBinarySpecTest.groovy b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultStaticLibraryBinarySpecTest.groovy
index a8e102a..ea123e8 100644
--- a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultStaticLibraryBinarySpecTest.groovy
+++ b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/DefaultStaticLibraryBinarySpecTest.groovy
@@ -145,10 +145,10 @@ class DefaultStaticLibraryBinarySpecTest extends Specification {
getFiles() >> [tmpDir.createFile("input.src")]
}
def sourceSet = Stub(HeaderExportingSourceSet) {
- getSource() >> sourceDirSet
+ getSources() >> sourceDirSet
getExportedHeaders() >> headerDirSet
}
- binary.source sourceSet
+ binary.inputs.add sourceSet
headerDir
}
}
diff --git a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/NativeBinarySpecTest.groovy b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/NativeBinarySpecTest.groovy
index d505520..ec19f9d 100644
--- a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/NativeBinarySpecTest.groovy
+++ b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/NativeBinarySpecTest.groovy
@@ -18,7 +18,6 @@ package org.gradle.nativeplatform.internal
import org.gradle.api.internal.project.taskfactory.ITaskFactory
import org.gradle.internal.reflect.DirectInstantiator
-import org.gradle.language.base.LanguageSourceSet
import org.gradle.language.base.ProjectSourceSet
import org.gradle.language.base.internal.DefaultFunctionalSourceSet
import org.gradle.language.nativeplatform.DependentSourceSet
@@ -55,41 +54,6 @@ class NativeBinarySpecTest extends Specification {
}
def resolver = Mock(NativeDependencyResolver)
- def "binary uses source from its owner component"() {
- given:
- def sourceSet = Stub(LanguageSourceSet)
-
- when:
- component.sources.add(sourceSet)
- def binary = testBinary(component)
-
- then:
- binary.source.contains(sourceSet)
- }
-
- def "binary uses all source sets from a functional source set"() {
- given:
- def binary = testBinary(component)
- def functionalSourceSet = new DefaultFunctionalSourceSet("func", instantiator, Stub(ProjectSourceSet))
- def sourceSet1 = Stub(LanguageSourceSet) {
- getName() >> "ss1"
- }
- def sourceSet2 = Stub(LanguageSourceSet) {
- getName() >> "ss2"
- }
-
- when:
- functionalSourceSet.add(sourceSet1)
- functionalSourceSet.add(sourceSet2)
-
- and:
- binary.source functionalSourceSet
-
- then:
- binary.source.contains(sourceSet1)
- binary.source.contains(sourceSet2)
- }
-
def "uses resolver to resolve lib to dependency"() {
def binary = testBinary(component, flavor1)
def lib = new Object()
@@ -118,7 +82,7 @@ class NativeBinarySpecTest extends Specification {
def sourceSet = Stub(DependentSourceSet) {
getLibs() >> [lib]
}
- binary.source sourceSet
+ binary.inputs.add sourceSet
1 * resolver.resolve({ NativeBinaryResolveResult result ->
result.allResolutions*.input == [lib]
@@ -169,7 +133,7 @@ class NativeBinarySpecTest extends Specification {
def sourceSet = Stub(DependentSourceSet) {
getLibs() >> [sourceLib]
}
- binary.source sourceSet
+ binary.inputs.add sourceSet
binary.lib(lib2)
and:
diff --git a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy
index 8069e88..e6047b3 100644
--- a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy
+++ b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy
@@ -14,11 +14,11 @@
* limitations under the License.
*/
package org.gradle.nativeplatform.internal.resolve
-
import org.gradle.api.UnknownDomainObjectException
import org.gradle.api.UnknownProjectException
import org.gradle.api.internal.DefaultDomainObjectSet
-import org.gradle.api.internal.project.ProjectInternal
+import org.gradle.api.internal.resolve.ProjectModelResolver
+import org.gradle.language.base.internal.resolve.LibraryResolveException
import org.gradle.model.ModelMap
import org.gradle.model.internal.core.ModelPath
import org.gradle.model.internal.registry.ModelRegistry
@@ -33,9 +33,8 @@ import org.gradle.platform.base.ComponentSpecContainer
import spock.lang.Specification
class ProjectLibraryBinaryLocatorTest extends Specification {
- def project = Mock(ProjectInternal)
- def modelRegistry = Mock(ModelRegistry)
- def projectLocator = Mock(ProjectLocator)
+ def projectModel = Mock(ModelRegistry)
+ def projectLocator = Mock(ProjectModelResolver)
def requirement = Mock(NativeLibraryRequirement)
def library = Mock(NativeLibrarySpec)
def binary = Mock(MockNativeLibraryBinary)
@@ -55,7 +54,7 @@ class ProjectLibraryBinaryLocatorTest extends Specification {
requirement = new ProjectNativeLibraryRequirement("libName", null)
and:
- projectLocator.locateProject(null) >> project
+ projectLocator.resolveProjectModel(null) >> projectModel
findLibraryInProject()
then:
@@ -67,7 +66,7 @@ class ProjectLibraryBinaryLocatorTest extends Specification {
requirement = new ProjectNativeLibraryRequirement("other", "libName", null)
and:
- projectLocator.locateProject("other") >> project
+ projectLocator.resolveProjectModel("other") >> projectModel
findLibraryInProject()
then:
@@ -79,7 +78,7 @@ class ProjectLibraryBinaryLocatorTest extends Specification {
requirement = new ProjectNativeLibraryRequirement("other", "libName", "static")
and:
- projectLocator.locateProject("other") >> project
+ projectLocator.resolveProjectModel("other") >> projectModel
findLibraryInProject()
then:
@@ -91,7 +90,7 @@ class ProjectLibraryBinaryLocatorTest extends Specification {
requirement = new ProjectNativeLibraryRequirement("unknown", "libName", "static")
and:
- projectLocator.locateProject("unknown") >> { throw new UnknownProjectException("unknown")}
+ projectLocator.resolveProjectModel("unknown") >> { throw new UnknownProjectException("unknown")}
and:
locator.getBinaries(requirement)
@@ -105,8 +104,8 @@ class ProjectLibraryBinaryLocatorTest extends Specification {
requirement = new ProjectNativeLibraryRequirement("other", "unknown", "static")
and:
- projectLocator.locateProject("other") >> project
- def libraries = findLibraryContainer(project)
+ projectLocator.resolveProjectModel("other") >> projectModel
+ def libraries = findLibraryContainer(projectModel)
libraries.get("unknown") >> { null }
and:
@@ -121,28 +120,25 @@ class ProjectLibraryBinaryLocatorTest extends Specification {
requirement = new ProjectNativeLibraryRequirement("other", "libName", "static")
and:
- projectLocator.locateProject("other") >> project
- project.modelRegistry >> modelRegistry
- modelRegistry.find(ModelPath.path("components"), ModelTypes.modelMap(NativeLibrarySpec)) >> null
- project.path >> "project-path"
+ projectLocator.resolveProjectModel("other") >> projectModel
+ projectModel.find(ModelPath.path("components"), ModelTypes.modelMap(NativeLibrarySpec)) >> null
and:
locator.getBinaries(requirement)
then:
def e = thrown(LibraryResolveException)
- e.message == "Project does not have a libraries container: 'project-path'"
+ e.message == "Project does not have a libraries container: 'other'"
}
private void findLibraryInProject() {
- def libraries = findLibraryContainer(project)
+ def libraries = findLibraryContainer(projectModel)
libraries.containsKey("libName") >> true
libraries.get("libName") >> library
}
- private findLibraryContainer(ProjectInternal project) {
+ private findLibraryContainer(ModelRegistry modelRegistry) {
def components = Mock(ComponentSpecContainer)
- project.modelRegistry >> modelRegistry
modelRegistry.find(ModelPath.path("components"), ModelType.of(ComponentSpecContainer)) >> components
components.withType(NativeLibrarySpec.class) >> components
return components
diff --git a/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/internal/configure/TestNativeBinariesFactory.java b/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/internal/configure/TestNativeBinariesFactory.java
index 702fb1c..045ed52 100644
--- a/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/internal/configure/TestNativeBinariesFactory.java
+++ b/subprojects/platform-native/src/testFixtures/groovy/org/gradle/nativeplatform/internal/configure/TestNativeBinariesFactory.java
@@ -36,7 +36,7 @@ public class TestNativeBinariesFactory {
T binary = BaseBinarySpec.create(type, name, instantiator, taskFactory);
NativeBinaries.initialize(binary, namingScheme, resolver, platform, buildType, flavor);
ComponentSpecInternal componentInternal = (ComponentSpecInternal) component;
- binary.setBinarySources(componentInternal.getSources().copy(name));
+ binary.getInputs().addAll(component.getSources().values());
return binary;
}
}
diff --git a/subprojects/platform-play/platform-play.gradle b/subprojects/platform-play/platform-play.gradle
index aecee73..1fb0522 100644
--- a/subprojects/platform-play/platform-play.gradle
+++ b/subprojects/platform-play/platform-play.gradle
@@ -7,12 +7,14 @@ dependencies {
compile project(":languageScala")
compile project(":javascript")
compile project(":diagnostics")
+
+ testFixturesCompile project(":internalIntegTesting")
}
useTestFixtures()
-useTestFixtures(project: ":platformBase", sourceSet: 'integTest')
useTestFixtures(project: ":languageScala", sourceSet: 'integTest')
useTestFixtures(project: ":languageJava", sourceSet: 'integTest')
+useTestFixtures(project: ":launcher", sourceSet: 'testFixtures')
useClassycle()
strictCompile()
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndJavaLangProjectIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndJavaLangProjectIntegrationTest.groovy
deleted file mode 100644
index ecf7a91..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndJavaLangProjectIntegrationTest.groovy
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest
-
-import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.integtests.fixtures.jvm.TestJvmComponent
-import org.gradle.language.fixtures.TestJavaComponent
-import org.gradle.play.integtest.fixtures.app.BasicPlayApp
-import org.gradle.play.integtest.fixtures.app.PlayApp
-import org.gradle.test.fixtures.archive.JarTestFixture
-
-class MixedPlayAndJavaLangProjectIntegrationTest extends AbstractIntegrationSpec {
- TestJvmComponent javaApp = new TestJavaComponent()
- PlayApp playApp = new BasicPlayApp()
-
- def setup() {
- playApp.writeSources(file("."))
- javaApp.writeSources(file("src/javaLib"))
- javaApp.writeResources(file("src/javaLib/resources"))
- settingsFile.text = "rootProject.name = 'mixedJavaAndPlay'"
- buildFile.text = """
- plugins {
- id 'jvm-component'
- id '${javaApp.languageName}-lang'
- id 'play'
- }
- repositories{
- mavenCentral()
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
- }
-
- model {
- components {
- javaLib(JvmLibrarySpec)
- }
- }
-"""
- }
-
- def "assemble builds jvm component and play component binaries"() {
- when:
- succeeds("assemble")
- then:
- executedAndNotSkipped(":compileJavaLibJarJavaLibJava", ":processJavaLibJarJavaLibResources", ":createJavaLibJar", ":javaLibJar", ":createPlayBinaryAssetsJar",
- ":routesCompileRoutesSourcesPlayBinary", ":twirlCompileTwirlTemplatesPlayBinary", ":scalaCompilePlayBinary", ":createPlayBinaryJar", ":playBinary", ":assemble")
- and:
- file("build/classes/javaLibJar").assertHasDescendants(javaApp.expectedOutputs*.fullPath as String[])
- new JarTestFixture(file("build/jars/javaLibJar/javaLib.jar")).hasDescendants(javaApp.expectedOutputs*.fullPath as String[])
- file("build/playBinary/lib/mixedJavaAndPlay.jar").exists()
- file("build/playBinary/lib/mixedJavaAndPlay-assets.jar").exists()
- }
-
-}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndJvmLibraryProjectIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndJvmLibraryProjectIntegrationTest.groovy
new file mode 100644
index 0000000..569d75b
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndJvmLibraryProjectIntegrationTest.groovy
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.jvm.TestJvmComponent
+import org.gradle.language.fixtures.TestJavaComponent
+import org.gradle.play.integtest.fixtures.app.BasicPlayApp
+import org.gradle.play.integtest.fixtures.app.PlayApp
+import org.gradle.test.fixtures.archive.JarTestFixture
+
+class MixedPlayAndJvmLibraryProjectIntegrationTest extends AbstractIntegrationSpec {
+ TestJvmComponent jvmApp = new TestJavaComponent()
+ PlayApp playApp = new BasicPlayApp()
+
+ def setup() {
+ playApp.writeSources(testDirectory)
+ jvmApp.writeSources(file("src/jvmLib"))
+ jvmApp.writeResources(file("src/jvmLib/resources"))
+ settingsFile.text = "rootProject.name = 'mixedJvmAndPlay'"
+ buildFile.text = """
+ plugins {
+ id 'jvm-component'
+ id '${jvmApp.languageName}-lang'
+ id 'play'
+ }
+ repositories {
+ mavenCentral()
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+ }
+
+ model {
+ components {
+ jvmLib(JvmLibrarySpec)
+ }
+ }
+"""
+ }
+
+ def "assemble builds jvm component and play component binaries"() {
+ when:
+ succeeds("assemble")
+ then:
+ executedAndNotSkipped(":compileJvmLibJarJvmLibJava", ":processJvmLibJarJvmLibResources", ":createJvmLibJar", ":jvmLibJar", ":createPlayBinaryAssetsJar",
+ ":compilePlayBinaryRoutes", ":compilePlayBinaryTwirlTemplates", ":compilePlayBinaryScala", ":createPlayBinaryJar", ":playBinary", ":assemble")
+ and:
+ file("build/classes/jvmLibJar").assertHasDescendants(jvmApp.expectedOutputs*.fullPath as String[])
+ new JarTestFixture(file("build/jars/jvmLibJar/jvmLib.jar")).hasDescendants(jvmApp.expectedOutputs*.fullPath as String[])
+ file("build/playBinary/lib/mixedJvmAndPlay.jar").exists()
+ file("build/playBinary/lib/mixedJvmAndPlay-assets.jar").exists()
+ }
+
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndScalaLangProjectIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndScalaLangProjectIntegrationTest.groovy
deleted file mode 100644
index a942e49..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/MixedPlayAndScalaLangProjectIntegrationTest.groovy
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest
-
-import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.integtests.fixtures.jvm.TestJvmComponent
-import org.gradle.language.scala.fixtures.TestScalaComponent
-import org.gradle.play.integtest.fixtures.app.BasicPlayApp
-import org.gradle.play.integtest.fixtures.app.PlayApp
-import org.gradle.test.fixtures.archive.JarTestFixture
-
-class MixedPlayAndScalaLangProjectIntegrationTest extends AbstractIntegrationSpec {
- TestJvmComponent scalaApp = new TestScalaComponent()
- PlayApp playApp = new BasicPlayApp()
-
- def setup() {
- playApp.writeSources(file("."))
- scalaApp.writeSources(file("src/scalaLib"))
- scalaApp.writeResources(file("src/scalaLib/resources"))
- settingsFile.text = "rootProject.name = 'mixedScalaAndPlay'"
- buildFile.text = """
- plugins {
- id 'jvm-component'
- id '${scalaApp.languageName}-lang'
- id 'play'
- }
- repositories{
- mavenCentral()
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
- }
-
- model {
- components {
- scalaLib(JvmLibrarySpec)
- }
- }
-"""
- }
-
- def "assemble builds jvm component and play component binaries"() {
- when:
- succeeds("assemble")
- then:
- executedAndNotSkipped(":createPlayBinaryAssetsJar", ":routesCompileRoutesSourcesPlayBinary", ":twirlCompileTwirlTemplatesPlayBinary", ":scalaCompilePlayBinary", ":createPlayBinaryJar", ":playBinary",
- ":compileScalaLibJarScalaLibScala", ":processScalaLibJarScalaLibResources", ":createScalaLibJar", ":scalaLibJar", ":assemble")
- and:
- file("build/classes/scalaLibJar").assertHasDescendants(scalaApp.expectedOutputs*.fullPath as String[])
- new JarTestFixture(file("build/jars/scalaLibJar/scalaLib.jar")).hasDescendants(scalaApp.expectedOutputs*.fullPath as String[])
- file("build/playBinary/lib/mixedScalaAndPlay.jar").exists()
- file("build/playBinary/lib/mixedScalaAndPlay-assets.jar").exists()
- }
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayAppWithFailingTestsIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayAppWithFailingTestsIntegrationTest.groovy
index 0aa429e..9ca2dce 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayAppWithFailingTestsIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayAppWithFailingTestsIntegrationTest.groovy
@@ -27,7 +27,7 @@ class PlayAppWithFailingTestsIntegrationTest extends PlayMultiVersionIntegration
PlayApp playApp = new WithFailingTestsApp();
def setup() {
- playApp.writeSources(file("."))
+ playApp.writeSources(testDirectory)
buildFile << """
model {
components {
@@ -45,13 +45,13 @@ model {
then:
output.contains(TextUtil.toPlatformLineSeparators("""
-FailingApplicationSpec > Application should::render the index page FAILED
- org.specs2.reporter.SpecFailureAssertionFailedError
+FailingApplicationSpec > failingTest FAILED
+ java.lang.AssertionError at FailingApplicationSpec.scala:23
"""))
output.contains(TextUtil.toPlatformLineSeparators("""
-FailingIntegrationSpec > Application should::work from within a browser FAILED
- org.specs2.reporter.SpecFailureAssertionFailedError
+FailingIntegrationSpec > failingTest FAILED
+ java.lang.AssertionError at FailingIntegrationSpec.scala:23
"""))
errorOutput.contains("6 tests completed, 2 failed")
errorOutput.contains("> There were failing tests.")
@@ -63,4 +63,4 @@ FailingIntegrationSpec > Application should::work from within a browser FAILED
result.testClass("FailingIntegrationSpec").assertTestCount(1, 1, 0)
result.testClass("FailingApplicationSpec").assertTestCount(2, 1, 0)
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayBinaryApplicationIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayBinaryApplicationIntegrationTest.groovy
index a1e9285..a87c706 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayBinaryApplicationIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayBinaryApplicationIntegrationTest.groovy
@@ -16,9 +16,7 @@
package org.gradle.play.integtest
-import org.gradle.integtests.fixtures.executer.GradleHandle
import org.gradle.play.integtest.fixtures.PlayMultiVersionRunApplicationIntegrationTest
-import org.gradle.util.TextUtil
abstract class PlayBinaryApplicationIntegrationTest extends PlayMultiVersionRunApplicationIntegrationTest {
@@ -28,9 +26,9 @@ abstract class PlayBinaryApplicationIntegrationTest extends PlayMultiVersionRunA
then:
executedAndNotSkipped(
- ":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
- ":scalaCompilePlayBinary",
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
+ ":compilePlayBinaryScala",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
":playBinary",
@@ -43,40 +41,34 @@ abstract class PlayBinaryApplicationIntegrationTest extends PlayMultiVersionRunA
succeeds("createPlayBinaryJar")
then:
- skipped(":createPlayBinaryJar", ":twirlCompileTwirlTemplatesPlayBinary")
+ skipped(":createPlayBinaryJar", ":compilePlayBinaryTwirlTemplates")
}
def "can run play app"() {
setup:
- httpPort = portFinder.nextAvailable
+ run "assemble"
buildFile << """
model {
tasks.runPlayBinary {
- httpPort = $httpPort
+ httpPort = 0
}
}
"""
- run "assemble"
when:
- def userInput = new PipedOutputStream();
- executer.withStdIn(new PipedInputStream(userInput))
- GradleHandle gradleHandle = executer.withTasks("runPlayBinary").start()
+ startBuild "runPlayBinary"
then:
- verifyStarted()
+ runningApp.verifyStarted()
and:
- verifyRunningApp()
+ runningApp.verifyContent()
when: "stopping gradle"
- userInput.write(4) // ctrl+d
- userInput.write(TextUtil.toPlatformLineSeparators("\n").bytes) // For some reason flush() doesn't get the keystroke to the DaemonExecuter
-
- gradleHandle.waitForFinish()
+ build.cancelWithEOT().waitForFinish()
then: "play server is stopped too"
- verifyStopped()
+ runningApp.verifyStopped()
}
void verifyJars() {
@@ -91,4 +83,4 @@ abstract class PlayBinaryApplicationIntegrationTest extends PlayMultiVersionRunA
"public/stylesheets/main.css",
"public/javascripts/hello.js")
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayDistributionApplicationIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayDistributionApplicationIntegrationTest.groovy
index 34c6667..132785f 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayDistributionApplicationIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayDistributionApplicationIntegrationTest.groovy
@@ -30,8 +30,8 @@ abstract class PlayDistributionApplicationIntegrationTest extends PlayMultiVersi
then:
executedAndNotSkipped(
- ":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
":createPlayBinaryJar",
":createPlayBinaryDistributionJar",
":createPlayBinaryAssetsJar",
@@ -48,8 +48,8 @@ abstract class PlayDistributionApplicationIntegrationTest extends PlayMultiVersi
then:
executedAndNotSkipped(":createPlayBinaryDist")
skipped(
- ":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
":createPlayBinaryJar",
":createPlayBinaryDistributionJar",
":createPlayBinaryAssetsJar",
@@ -67,23 +67,23 @@ abstract class PlayDistributionApplicationIntegrationTest extends PlayMultiVersi
String distDirPath = new File(testDirectory, "build/stage").path
setup:
- httpPort = portFinder.nextAvailable
run "stage"
when:
- builder = new DistributionTestExecHandleBuilder(httpPort.toString(), distDirPath)
+ builder = new DistributionTestExecHandleBuilder('0', distDirPath)
handle = builder.build()
handle.start()
+ runningApp.initialize(handle)
then:
- verifyStarted()
+ runningApp.verifyStarted()
and:
- verifyRunningApp()
+ runningApp.verifyContent()
cleanup:
- ((DistributionTestExecHandleBuilder.DistributionTestExecHandle) handle).shutdown()
- verifyStopped()
+ ((DistributionTestExecHandleBuilder.DistributionTestExecHandle) handle).shutdown(runningApp.httpPort)
+ runningApp.verifyStopped()
}
void verifyZips() {
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayMultiProjectApplicationIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayMultiProjectApplicationIntegrationTest.groovy
index bb3188b..4a436c8 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayMultiProjectApplicationIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayMultiProjectApplicationIntegrationTest.groovy
@@ -19,27 +19,23 @@ package org.gradle.play.integtest
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.executer.GradleHandle
import org.gradle.play.integtest.fixtures.DistributionTestExecHandleBuilder
+import org.gradle.play.integtest.fixtures.MultiProjectRunningPlayApp
+import org.gradle.play.integtest.fixtures.RunningPlayApp
import org.gradle.play.integtest.fixtures.app.PlayApp
import org.gradle.play.integtest.fixtures.app.PlayMultiProject
import org.gradle.process.internal.ExecHandle
import org.gradle.process.internal.ExecHandleBuilder
import org.gradle.test.fixtures.archive.JarTestFixture
import org.gradle.test.fixtures.archive.ZipTestFixture
-import org.gradle.util.AvailablePortFinder
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
-import org.gradle.util.TextUtil
-
-import static org.gradle.integtests.fixtures.UrlValidator.*
class PlayMultiProjectApplicationIntegrationTest extends AbstractIntegrationSpec {
PlayApp playApp = new PlayMultiProject()
-
- int httpPort
- def portFinder = AvailablePortFinder.createPrivate()
+ RunningPlayApp runningApp = new MultiProjectRunningPlayApp(testDirectory)
def setup() {
- playApp.writeSources(file("."))
+ playApp.writeSources(testDirectory)
}
def "can build play app binary"() {
@@ -48,35 +44,35 @@ class PlayMultiProjectApplicationIntegrationTest extends AbstractIntegrationSpec
then:
executedAndNotSkipped(
- ":javalibrary:jar",
- ":submodule:playBinary",
- ":primary:playBinary",
- ":primary:assemble")
+ ":javalibrary:jar",
+ ":submodule:playBinary",
+ ":primary:playBinary",
+ ":primary:assemble")
and:
jar("primary/build/playBinary/lib/primary.jar").containsDescendants(
- "Routes.class",
- "controllers/Application.class")
+ "Routes.class",
+ "controllers/Application.class")
jar("primary/build/playBinary/lib/primary-assets.jar").hasDescendants(
- "public/primary.txt")
+ "public/primary.txt")
jar("submodule/build/playBinary/lib/submodule.jar").containsDescendants(
- "controllers/submodule/Application.class")
+ "controllers/submodule/Application.class")
jar("submodule/build/playBinary/lib/submodule-assets.jar").hasDescendants(
- "public/submodule.txt")
+ "public/submodule.txt")
when:
succeeds(":primary:dist")
then:
zip("primary/build/distributions/playBinary.zip").containsDescendants(
- "playBinary/lib/primary.jar",
- "playBinary/lib/primary-assets.jar",
- "playBinary/lib/submodule.jar",
- "playBinary/lib/submodule-assets.jar",
- "playBinary/lib/javalibrary.jar",
- "playBinary/bin/playBinary",
- "playBinary/bin/playBinary.bat",
- "playBinary/conf/application.conf"
+ "playBinary/lib/primary.jar",
+ "playBinary/lib/primary-assets.jar",
+ "playBinary/lib/submodule.jar",
+ "playBinary/lib/submodule-assets.jar",
+ "playBinary/lib/javalibrary.jar",
+ "playBinary/bin/playBinary",
+ "playBinary/bin/playBinary.bat",
+ "playBinary/conf/application.conf"
)
when:
@@ -84,89 +80,70 @@ class PlayMultiProjectApplicationIntegrationTest extends AbstractIntegrationSpec
then:
file("primary/build/stage/playBinary").assertIsDir().assertContainsDescendants(
- "lib/primary.jar",
- "lib/primary-assets.jar",
- "lib/submodule.jar",
- "lib/submodule-assets.jar",
- "bin/playBinary",
- "bin/playBinary.bat",
- "conf/application.conf"
+ "lib/primary.jar",
+ "lib/primary-assets.jar",
+ "lib/submodule.jar",
+ "lib/submodule-assets.jar",
+ "bin/playBinary",
+ "bin/playBinary.bat",
+ "conf/application.conf"
)
}
-
- def "can run play app"(){
- setup:
- httpPort = portFinder.nextAvailable
+ def "can run play app"() {
+ setup:
file("primary/build.gradle") << """
model {
tasks.runPlayBinary {
- httpPort = $httpPort
+ httpPort = 0
}
}
"""
run ":primary:assemble"
when:
- def userInput = new PipedOutputStream();
- executer.withStdIn(new PipedInputStream(userInput))
- GradleHandle gradleHandle = executer.withTasks(":primary:runPlayBinary").start()
+ GradleHandle build = executer.withTasks(":primary:runPlayBinary").withForceInteractive(true).withStdinPipe().start()
+ runningApp.initialize(build)
then:
- def url = playUrl().toString()
- available(url, "Play app", 60000)
+ runningApp.verifyStarted()
and:
- validateRunningApp();
+ runningApp.verifyContent();
when: "stopping gradle"
- userInput.write(4) // ctrl+d
- userInput.write(TextUtil.toPlatformLineSeparators("\n").bytes) // For some reason flush() doesn't get the keystroke to the DaemonExecuter
-
- gradleHandle.waitForFinish()
+ build.cancelWithEOT().waitForFinish()
then: "play server is stopped too"
- notAvailable(url)
+ runningApp.verifyStopped()
}
@Requires(TestPrecondition.NOT_UNKNOWN_OS)
- def "can run play distribution" () {
+ def "can run play distribution"() {
println file(".")
ExecHandle handle
String distDirPath = file("primary/build/stage").path
setup:
- httpPort = portFinder.nextAvailable
run ":primary:stage"
when:
- ExecHandleBuilder builder = new DistributionTestExecHandleBuilder(httpPort.toString(), distDirPath)
+ ExecHandleBuilder builder = new DistributionTestExecHandleBuilder('0', distDirPath)
handle = builder.build()
handle.start()
+ runningApp.initialize(handle)
then:
- available(playUrl().toString(), "Play app", 60000)
+ runningApp.verifyStarted()
and:
- validateRunningApp()
+ runningApp.verifyContent()
cleanup:
- ((DistributionTestExecHandleBuilder.DistributionTestExecHandle) handle).shutdown()
- notAvailable(playUrl().toString())
- }
-
- def validateRunningApp() {
- assertUrlContent playUrl(), "Your new application is ready."
- assertUrlContent playUrl("assets/primary.txt"), "Primary asset"
- assertUrlContent playUrl("submodule"), "Submodule page"
- assertUrlContent playUrl("assets/submodule.txt"), "Submodule asset"
- true
- }
-
- URL playUrl(String path='') {
- return new URL("http://localhost:$httpPort/${path}")
+ ((DistributionTestExecHandleBuilder.DistributionTestExecHandle) handle).shutdown(runningApp.httpPort)
+ runningApp.verifyStopped()
}
JarTestFixture jar(String fileName) {
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayPlatformIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayPlatformIntegrationTest.groovy
index 4b83321..22a07c1 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayPlatformIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayPlatformIntegrationTest.groovy
@@ -18,15 +18,18 @@ package org.gradle.play.integtest
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.play.integtest.fixtures.app.BasicPlayApp
import org.gradle.play.integtest.fixtures.app.PlayApp
+import org.gradle.play.internal.DefaultPlayPlatform
import org.gradle.test.fixtures.archive.JarTestFixture
import org.gradle.test.fixtures.archive.ZipTestFixture
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
import spock.lang.Unroll
public class PlayPlatformIntegrationTest extends AbstractIntegrationSpec {
PlayApp playApp = new BasicPlayApp()
def setup() {
- playApp.writeSources(file("."))
+ playApp.writeSources(testDirectory)
}
def "can build play app binary for default platform"() {
@@ -35,7 +38,7 @@ public class PlayPlatformIntegrationTest extends AbstractIntegrationSpec {
then:
file("build/stage/playBinary/lib").assertContainsDescendants(
- "play_2.11-2.3.7.jar"
+ "play_2.11-${DefaultPlayPlatform.DEFAULT_PLAY_VERSION}.jar"
)
}
@@ -67,8 +70,42 @@ model {
"play: '2.3.6'" | '2.3.6' | '2.11'
"play: '2.3.6', scala: '2.10'" | '2.3.6' | '2.10'
"play: '2.3.6', scala: '2.11'" | '2.3.6' | '2.11'
+
+ "play: '2.3.8'" | '2.3.8' | '2.11'
+ "play: '2.3.8', scala: '2.10'" | '2.3.8' | '2.10'
+ "play: '2.3.8', scala: '2.11'" | '2.3.8' | '2.11'
+
}
+ @Requires(TestPrecondition.JDK8_OR_LATER)
+ @Unroll
+ def "can build play app binary for specified platform on JDK8 [#platform]"() {
+ when:
+ buildFile << """
+model {
+ components {
+ play {
+ platform ${platform}
+ }
+ }
+}
+"""
+
+ succeeds("stage")
+
+ then:
+ file("build/stage/playBinary/lib").assertContainsDescendants(
+ "play_${scalaPlatform}-${playVersion}.jar"
+ )
+
+ where:
+ platform | playVersion | scalaPlatform
+ "play: '2.4.0'" | '2.4.0' | '2.11'
+ "play: '2.4.0', scala: '2.10'" | '2.4.0' | '2.10'
+ "play: '2.4.0', scala: '2.11'" | '2.4.0' | '2.11'
+ }
+
+
def "fails when trying to build a Play 2.2.x application with Scala 2.11.x"() {
when:
buildFile << """
@@ -104,7 +141,7 @@ model {
fails "assemble"
and:
- failure.assertHasCause "Not a supported Play version: 2.1.0. This plugin is compatible with: [2.3.x, 2.2.x]."
+ failure.assertHasCause "Not a supported Play version: 2.1.0. This plugin is compatible with: [2.4.x, 2.3.x, 2.2.x]."
}
def "fails when trying to build for an invalid scala platform"() {
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayTestApplicationIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayTestApplicationIntegrationTest.groovy
index 4f16207..cb922a7 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayTestApplicationIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/PlayTestApplicationIntegrationTest.groovy
@@ -19,29 +19,16 @@ package org.gradle.play.integtest
import org.gradle.integtests.fixtures.JUnitXmlTestExecutionResult
import org.gradle.integtests.fixtures.TestExecutionResult
import org.gradle.play.integtest.fixtures.PlayMultiVersionApplicationIntegrationTest
-import org.gradle.util.AvailablePortFinder
abstract class PlayTestApplicationIntegrationTest extends PlayMultiVersionApplicationIntegrationTest {
- def portFinder = AvailablePortFinder.createPrivate()
-
def "can run play app tests"() {
- setup:
- int testPort = portFinder.nextAvailable
- buildFile << """
- model {
- tasks.testPlayBinary {
- systemProperty 'testserver.port', $testPort
- }
- }
- """
-
when:
succeeds("check")
then:
executed(
- ":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
- ":scalaCompilePlayBinary",
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
+ ":compilePlayBinaryScala",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
":playBinary",
@@ -55,9 +42,9 @@ abstract class PlayTestApplicationIntegrationTest extends PlayMultiVersionApplic
succeeds("check")
then:
skipped(
- ":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
- ":scalaCompilePlayBinary",
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
+ ":compilePlayBinaryScala",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
":playBinary",
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/AdvancedAppContentVerifier.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/AdvancedAppContentVerifier.groovy
deleted file mode 100644
index 76eb2c3..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/AdvancedAppContentVerifier.groovy
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest.advanced
-
-import org.gradle.play.integtest.fixtures.PlayMultiVersionRunApplicationIntegrationTest
-
-import static org.gradle.integtests.fixtures.UrlValidator.*
-
-class AdvancedAppContentVerifier {
- static void verifyRunningApp(PlayMultiVersionRunApplicationIntegrationTest test) {
- // Custom Routes
- assert test.playUrl().text.contains("<li>foo:1</li>")
- assert test.playUrl("root").text.contains("<li>bar:2</li>")
- assert test.playUrl("java/one").text.contains("Your new application is ready.")
- assert test.playUrl("scala/one").text.contains("<li>foo:1</li>")
-
- // Custom Assets
- assertUrlContent test.playUrl("assets/javascripts/test.js"), test.file("app/assets/javascripts/sample.js")
- assertUrlContent test.playUrl("assets/javascripts/sample.js"), test.file("app/assets/javascripts/sample.js")
- assertUrlContent test.playUrl("assets/javascripts/test.min.js"), minifiedSample
- assertUrlContent test.playUrl("assets/javascripts/sample.min.js"), minifiedSample
- }
-
- static String getMinifiedSample() {
- return "(function(){var c,e,f,b;b=function(a){return a*a};c=[1,2,3,4,5];e={root:Math.sqrt,square:b,cube:function(a){return a*b(a)}};\"undefined\"!==typeof elvis&&null!==elvis&&alert(\"I knew it!\");(function(){var a,b,d;d=[];a=0;for(b=c.length;a<b;a++)f=c[a],d.push(e.cube(f));return d})()}).call(this);"
- }
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayBinaryAdvancedAppIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayBinaryAdvancedAppIntegrationTest.groovy
index cd942d9..ace2965 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayBinaryAdvancedAppIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayBinaryAdvancedAppIntegrationTest.groovy
@@ -17,10 +17,15 @@
package org.gradle.play.integtest.advanced
import org.gradle.play.integtest.PlayBinaryApplicationIntegrationTest
+import org.gradle.play.integtest.fixtures.AdvancedRunningPlayApp
import org.gradle.play.integtest.fixtures.app.AdvancedPlayApp
import org.gradle.play.integtest.fixtures.app.PlayApp
class PlayBinaryAdvancedAppIntegrationTest extends PlayBinaryApplicationIntegrationTest {
+ def setup() {
+ runningApp = new AdvancedRunningPlayApp(testDirectory)
+ }
+
@Override
PlayApp getPlayApp() {
return new AdvancedPlayApp()
@@ -46,11 +51,4 @@ class PlayBinaryAdvancedAppIntegrationTest extends PlayBinaryApplicationIntegrat
"public/javascripts/test.min.js"
)
}
-
- @Override
- void verifyRunningApp() {
- super.verifyRunningApp()
-
- AdvancedAppContentVerifier.verifyRunningApp(this)
- }
}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayDistributionAdvancedAppIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayDistributionAdvancedAppIntegrationTest.groovy
index 1c82acb..1b1d6b6 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayDistributionAdvancedAppIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/advanced/PlayDistributionAdvancedAppIntegrationTest.groovy
@@ -17,12 +17,15 @@
package org.gradle.play.integtest.advanced
import org.gradle.play.integtest.PlayDistributionApplicationIntegrationTest
+import org.gradle.play.integtest.fixtures.AdvancedRunningPlayApp
import org.gradle.play.integtest.fixtures.app.AdvancedPlayApp
import org.gradle.play.integtest.fixtures.app.PlayApp
-import static org.gradle.integtests.fixtures.UrlValidator.*
-
class PlayDistributionAdvancedAppIntegrationTest extends PlayDistributionApplicationIntegrationTest {
+ def setup() {
+ runningApp = new AdvancedRunningPlayApp(testDirectory)
+ }
+
@Override
PlayApp getPlayApp() {
return new AdvancedPlayApp()
@@ -61,11 +64,4 @@ class PlayDistributionAdvancedAppIntegrationTest extends PlayDistributionApplica
"controllers/jva/PureJava.class"
)
}
-
- @Override
- void verifyRunningApp() {
- super.verifyRunningApp()
-
- AdvancedAppContentVerifier.verifyRunningApp(this)
- }
}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayContinuousBuildIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayContinuousBuildIntegrationTest.groovy
new file mode 100644
index 0000000..f90d1b6
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayContinuousBuildIntegrationTest.groovy
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.continuous
+
+import org.gradle.play.integtest.fixtures.AbstractMultiVersionPlayContinuousBuildIntegrationTest
+import org.gradle.play.integtest.fixtures.RunningPlayApp
+import org.gradle.play.integtest.fixtures.app.BasicPlayApp
+import org.gradle.play.integtest.fixtures.app.PlayApp
+
+class PlayContinuousBuildIntegrationTest extends AbstractMultiVersionPlayContinuousBuildIntegrationTest {
+ RunningPlayApp runningApp = new RunningPlayApp(testDirectory)
+ PlayApp playApp = new BasicPlayApp()
+
+ def "build does not block when running play app with continuous build" () {
+ when: "the build runs until it enters continuous build"
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+ }
+
+ def "can run play app multiple times with continuous build" () {
+ when:
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ file("conf/routes") << "\n# changed"
+
+ then:
+ succeeds()
+
+ when:
+ file("conf/routes") << "\n# changed again"
+
+ then:
+ succeeds()
+
+ when:
+ file("conf/routes") << "\n# changed yet again"
+
+ then:
+ succeeds()
+ }
+
+ def "build failure prior to launch does not prevent launch on subsequent build" () {
+ executer.withStackTraceChecksDisabled()
+ def original = file("app/controllers/Application.scala").text
+
+ when: "source file is broken"
+ file("app/controllers/Application.scala").text = "object Application extends Controller {"
+
+ then:
+ fails("runPlayBinary")
+
+ when: "source file is fixed"
+ file("app/controllers/Application.scala").text = original
+
+ then:
+ succeeds()
+
+ and:
+ appIsRunningAndDeployed()
+ }
+
+ def "play application is stopped when build is cancelled" () {
+ when:
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ gradle.cancel()
+
+ then:
+ cancelsAndExits()
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayMultiProjectContinuousBuildIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayMultiProjectContinuousBuildIntegrationTest.groovy
new file mode 100644
index 0000000..202e50c
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayMultiProjectContinuousBuildIntegrationTest.groovy
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.continuous
+
+import org.gradle.play.integtest.fixtures.AbstractMultiVersionPlayContinuousBuildIntegrationTest
+import org.gradle.play.integtest.fixtures.MultiProjectRunningPlayApp
+import org.gradle.play.integtest.fixtures.RunningPlayApp
+import org.gradle.play.integtest.fixtures.app.BasicPlayApp
+import org.gradle.play.integtest.fixtures.app.PlayApp
+import org.gradle.play.integtest.fixtures.app.PlayMultiProject
+import org.gradle.test.fixtures.file.TestFile
+
+
+class PlayMultiProjectContinuousBuildIntegrationTest extends AbstractMultiVersionPlayContinuousBuildIntegrationTest {
+ PlayApp playApp = new PlayMultiProject()
+ PlayApp childApp = new BasicPlayApp()
+ TestFile childDirectory = testDirectory.file('child')
+ RunningPlayApp runningApp = new MultiProjectRunningPlayApp(testDirectory)
+ RunningPlayApp runningChildApp = new RunningPlayApp(childDirectory)
+ TestFile playRunBuildFile = file("primary/build.gradle")
+
+ def "can run multiproject play app with continuous build" () {
+ when:
+ succeeds(":primary:runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ and:
+ doesntExit()
+
+ cleanup: "stopping gradle"
+ stopGradle()
+ appIsStopped()
+ }
+
+ def "can run play apps in multiple projects in multiproject continuous build" () {
+ childApp.writeSources(childDirectory)
+ childDirectory.file('build.gradle') << """
+ model {
+ tasks.runPlayBinary {
+ httpPort = 0
+ }
+ }
+
+ // ensure that child run task always runs second
+ tasks.withType(PlayRun) {
+ dependsOn project(':primary').tasks.withType(PlayRun)
+ }
+ """
+ file('settings.gradle') << """
+ include ':child'
+ """
+
+ when:
+ succeeds(":primary:runPlayBinary", ":child:runPlayBinary")
+
+ then:
+ executedAndNotSkipped(":primary:runPlayBinary", ":child:runPlayBinary")
+
+ and:
+ appIsRunningAndDeployed()
+ childAppIsRunningAndDeployed()
+
+ when:
+ file('primary/conf/routes') << "# some change"
+
+ then:
+ succeeds()
+
+ when:
+ childDirectory.file('conf/routes') << "# some change"
+
+ then:
+ succeeds()
+
+ when:
+ sendEOT()
+
+ then:
+ cancelsAndExits()
+
+ and:
+ appIsStopped()
+ childAppIsStopped()
+ }
+
+ def childAppIsRunningAndDeployed() {
+ runningChildApp.initialize(gradle)
+ runningChildApp.verifyStarted('', 1)
+ runningChildApp.verifyContent()
+ true
+ }
+
+ def childAppIsStopped() {
+ runningChildApp.requireHttpPort(1)
+ runningChildApp.verifyStopped()
+ true
+ }
+
+ def "show build failures in play apps in multiple projects in multiproject continuous build" () {
+ childApp.writeSources(childDirectory)
+ childDirectory.file('build.gradle') << """
+ model {
+ tasks.runPlayBinary {
+ httpPort = 0
+ }
+ }
+ """
+ file('settings.gradle') << """
+ include ':child'
+ """
+
+ when:
+ succeeds(":primary:runPlayBinary", ":child:runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+ childAppIsRunningAndDeployed()
+
+ when:
+ addBadJava("primary/app")
+
+ then:
+ fails()
+ notExecuted(":primary:runPlayBinary")
+ errorPageHasTaskFailure(":primary:compilePlayBinaryScala")
+ childErrorPageHasTaskFailure(":primary:compilePlayBinaryScala")
+
+ when:
+ fixBadJava("primary/app")
+ then:
+ succeeds()
+ appIsRunningAndDeployed()
+ childAppIsRunningAndDeployed()
+ }
+
+
+ def addBadJava(path) {
+ file("$path/models/NewType.java") << """
+package models;
+
+public class NewType {
+"""
+ }
+
+ def fixBadJava(path) {
+ file("$path/models/NewType.java") << """
+}
+"""
+ }
+
+ private errorPageHasTaskFailure(task) {
+ def error = runningApp.playUrlError()
+ assert error.httpCode == 500
+ assert error.text.contains("Gradle Build Failure")
+ assert error.text.contains("Execution failed for task '$task'.")
+ error
+ }
+ private childErrorPageHasTaskFailure(task) {
+ def error = runningChildApp.playUrlError()
+ assert error.httpCode == 500
+ assert error.text.contains("Gradle Build Failure")
+ assert error.text.contains("Execution failed for task '$task'.")
+ error
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayMultiProjectReloadIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayMultiProjectReloadIntegrationTest.groovy
new file mode 100644
index 0000000..7de4502
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayMultiProjectReloadIntegrationTest.groovy
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.continuous
+import org.gradle.play.integtest.fixtures.AbstractMultiVersionPlayReloadIntegrationTest
+import org.gradle.play.integtest.fixtures.MultiProjectRunningPlayApp
+import org.gradle.play.integtest.fixtures.RunningPlayApp
+import org.gradle.play.integtest.fixtures.app.PlayApp
+import org.gradle.play.integtest.fixtures.app.PlayMultiProject
+import org.gradle.test.fixtures.file.TestFile
+
+class PlayMultiProjectReloadIntegrationTest extends AbstractMultiVersionPlayReloadIntegrationTest {
+ RunningPlayApp runningApp = new MultiProjectRunningPlayApp(testDirectory)
+ PlayApp playApp = new PlayMultiProject()
+ TestFile playRunBuildFile = file("primary/build.gradle")
+
+ def cleanup() {
+ stopGradle()
+ appIsStopped()
+ }
+
+ def "can modify play app while app is running in continuous build"() {
+ when:
+ succeeds(":primary:runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ addHelloWorld()
+
+ then:
+ succeeds()
+ runningApp.playUrl('hello').text == 'Hello world'
+ }
+
+ private void addHelloWorld() {
+ file("primary/conf/routes") << "\nGET /hello controllers.Application.hello"
+ file("primary/app/controllers/Application.scala").with {
+ text = text.replaceFirst(/(?s)\}\s*$/, '''
+ def hello = Action {
+ Ok("Hello world")
+ }
+}
+''')
+ }
+ }
+
+ def "can modify sub module in multi-project play app while app is running in continuous build"() {
+ when:
+ succeeds(":primary:runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ addSubmoduleHelloWorld()
+
+ then:
+ succeeds()
+ runningApp.playUrl('subhello').text == 'Hello world'
+ }
+
+ private void addSubmoduleHelloWorld() {
+ file("primary/conf/routes") << "\nGET /subhello controllers.submodule.Application.hello"
+ file("submodule/app/controllers/submodule/Application.scala").with {
+ text = text.replaceFirst(/(?s)\}\s*$/, '''
+ def hello = Action {
+ Ok("Hello world")
+ }
+}
+''')
+ }
+ }
+
+ def "can modify java sub module in multi-project play app while app is running in continuous build"() {
+ when:
+ succeeds(":primary:runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ addSubmoduleHelloWorldFromJavaClass()
+
+ then:
+ succeeds()
+ runningApp.playUrl('subhello').text == 'Hello from Java!'
+ }
+
+ private void addSubmoduleHelloWorldFromJavaClass() {
+ file("primary/conf/routes") << "\nGET /subhello controllers.submodule.Application.hello"
+ file("submodule/app/controllers/submodule/Application.scala").with {
+ text = text.replaceFirst(~/(?m)^import\s/, '''
+import org.test.Util
+$0''')
+ text = text.replaceFirst(/(?s)\}\s*$/, '''
+ def hello = Action {
+ Ok(Util.hello())
+ }
+}
+''')
+ }
+ file("javalibrary/src/main/java/org/test/Util.java").with {
+ text = text.replaceFirst(/(?s)\}\s*$/, '''
+ public static String hello() {
+ return "Hello from Java!";
+ }
+}
+''')
+ }
+ file("submodule/build.gradle") << '''
+dependencies {
+ play project(":javalibrary")
+}
+'''
+ }
+
+ def "can add javascript file to primary project"() {
+ when:
+ succeeds(":primary:runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ file("primary/public/helloworld.js") << '''
+var message = "Hello JS";
+'''
+
+ then:
+ succeeds()
+ runningApp.playUrl('assets/helloworld.js').text.contains('Hello JS')
+ }
+
+ def "should reload with exception when modify java in submodule"() {
+ when:
+ succeeds(":primary:runPlayBinary")
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ addBadJava("submodule/app")
+
+ then:
+ fails()
+ !executedTasks.contains(':primary:runPlayBinary')
+ errorPageHasTaskFailure(":submodule:compilePlayBinaryScala")
+
+ when:
+ fixBadJava("submodule/app")
+ then:
+ succeeds()
+ appIsRunningAndDeployed()
+ }
+
+ def addBadJava(path) {
+ file("$path/models/NewType.java") << """
+package models;
+
+public class NewType {
+"""
+ }
+
+ def fixBadJava(path) {
+ file("$path/models/NewType.java") << """
+}
+"""
+ }
+
+ def "can add javascript file to sub module"() {
+ when:
+ succeeds(":primary:runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ file("submodule/public/helloworld.js") << '''
+var message = "Hello from submodule";
+'''
+
+ then:
+ succeeds()
+ runningApp.playUrl('assets/helloworld.js').text.contains('Hello from submodule')
+ }
+
+ private errorPageHasTaskFailure(task) {
+ def error = runningApp.playUrlError()
+ assert error.httpCode == 500
+ assert error.text.contains("Gradle Build Failure")
+ assert error.text.contains("Execution failed for task '$task'.")
+ error
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayReloadIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayReloadIntegrationTest.groovy
new file mode 100644
index 0000000..5fed6e9
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/continuous/PlayReloadIntegrationTest.groovy
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.continuous
+
+import org.gradle.play.integtest.fixtures.AbstractMultiVersionPlayReloadIntegrationTest
+import org.gradle.play.integtest.fixtures.RunningPlayApp
+import org.gradle.play.integtest.fixtures.app.AdvancedPlayApp
+import org.gradle.play.integtest.fixtures.app.PlayApp
+
+class PlayReloadIntegrationTest extends AbstractMultiVersionPlayReloadIntegrationTest {
+ RunningPlayApp runningApp = new RunningPlayApp(testDirectory)
+ PlayApp playApp = new AdvancedPlayApp()
+
+ def cleanup() {
+ stopGradle()
+ appIsStopped()
+ }
+
+ def "should reload modified scala controller and routes"() {
+ when:
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ addHelloWorld()
+
+ then:
+ succeeds()
+ runningApp.playUrl('hello').text == 'Hello world'
+ }
+
+ private void addHelloWorld() {
+ file("conf/routes") << "\nGET /hello controllers.Application.hello"
+ file("app/controllers/Application.scala").with {
+ text = text.replaceFirst(/(?s)\}\s*$/, '''
+ def hello = Action {
+ Ok("Hello world")
+ }
+}
+''')
+ }
+ }
+
+ def "should reload with exception when modify scala controller"() {
+ when:
+ succeeds("runPlayBinary")
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ addBadCode()
+ then:
+ fails()
+ !executedTasks.contains('runPlayBinary')
+ errorPageHasTaskFailure("compilePlayBinaryScala")
+
+ when:
+ fixBadCode()
+ then:
+ succeeds()
+ appIsRunningAndDeployed()
+
+ }
+
+ private errorPageHasTaskFailure(task) {
+ def error = runningApp.playUrlError()
+ assert error.httpCode == 500
+ assert error.text.contains("Gradle Build Failure")
+ assert error.text.contains("Execution failed for task ':$task'.")
+ error
+ }
+
+ private void addBadCode() {
+ file("app/controllers/Application.scala").with {
+ text = text.replaceFirst(/(?s)\}\s*$/, '''
+ def hello = Action {
+ Ok("Hello world")
+ }
+''') // missing closing brace
+ }
+ }
+
+ private void fixBadCode() {
+ file("app/controllers/Application.scala") << "}"
+ }
+
+ def "should reload modified coffeescript"() {
+ when:
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+ !runningApp.playUrl('assets/javascripts/test.js').text.contains('Hello coffeescript')
+ !runningApp.playUrl('assets/javascripts/test.min.js').text.contains('Hello coffeescript')
+
+ when:
+ file("app/assets/javascripts/test.coffee") << '''
+message = "Hello coffeescript"
+alert message
+'''
+
+ then:
+ succeeds()
+ runningApp.playUrl('assets/javascripts/test.js').text.contains('Hello coffeescript')
+ runningApp.playUrl('assets/javascripts/test.min.js').text.contains('Hello coffeescript')
+ }
+
+ def "should detect new javascript files"() {
+ when:
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ file("app/assets/javascripts/helloworld.js") << '''
+var message = "Hello JS";
+'''
+
+ then:
+ succeeds()
+ runningApp.playUrl('assets/javascripts/helloworld.js').text.contains('Hello JS')
+ runningApp.playUrl('assets/javascripts/helloworld.min.js').text.contains('Hello JS')
+ }
+
+ def "should reload modified java model"() {
+ when:
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+ assert runningApp.playUrl().text.contains("<li>foo:1</li>")
+
+ when:
+ file("app/models/DataType.java").with {
+ text = text.replaceFirst(~/"%s:%s"/, '"Hello %s:%s !"')
+ }
+
+ then:
+ succeeds()
+ assert runningApp.playUrl().text.contains("<li>Hello foo:1 !</li>")
+ }
+
+ def "should reload twirl template"() {
+ when:
+ succeeds("runPlayBinary")
+
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ file("app/views/index.scala.html").with {
+ text = text.replaceFirst(~/Welcome to Play/, 'Welcome to Play with Gradle')
+ }
+
+ then:
+ succeeds()
+ assert runningApp.playUrl().text.contains("Welcome to Play with Gradle")
+ }
+
+ def "should reload with exception when task that depends on runPlayBinary fails"() {
+ given:
+ buildFile << """
+task otherTask {
+ dependsOn 'runPlayBinary'
+ doLast {
+ // second time through this route exists
+ if (file("conf/routes").text.contains("/hello")) {
+ throw new GradleException("always fails")
+ }
+ }
+}
+"""
+ when:
+ succeeds("otherTask")
+ then:
+ appIsRunningAndDeployed()
+
+ when:
+ addHelloWorld()
+
+ then:
+ fails()
+ !executedTasks.contains('runPlayBinary')
+ errorPageHasTaskFailure("otherTask")
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/DistributionTestExecHandleBuilder.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/DistributionTestExecHandleBuilder.groovy
deleted file mode 100644
index 62b062c..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/DistributionTestExecHandleBuilder.groovy
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest.fixtures
-
-import com.google.common.collect.Lists
-import org.gradle.internal.os.OperatingSystem
-import org.gradle.process.internal.ExecHandle
-import org.gradle.process.internal.ExecHandleBuilder
-
-class DistributionTestExecHandleBuilder extends ExecHandleBuilder {
- final String port
-
- DistributionTestExecHandleBuilder(String port, String baseDirName) {
- super()
- this.port = port
-
- def extension = ""
- if (OperatingSystem.current().windows) {
- extension = ".bat"
- }
-
- this.setExecutable("${baseDirName}/playBinary/bin/playBinary${extension}")
- this.environment("PLAY_BINARY_OPTS": "-Dhttp.port=${port}")
- this.setWorkingDir(baseDirName)
- }
-
- @Override
- List<String> getAllArguments() {
- return Lists.newArrayList()
- }
-
- @Override
- ExecHandle build() {
- return new DistributionTestExecHandle(super.build(), port)
- }
-
- public static class DistributionTestExecHandle implements ExecHandle {
- @Delegate
- final ExecHandle delegate
- final String port
-
- public DistributionTestExecHandle(ExecHandle delegate, String port) {
- this.delegate = delegate
- this.port = port
- }
-
- void shutdown() {
- try {
- new URL("http://localhost:${port}/shutdown").bytes
- } catch (SocketException e) {
- // Expected
- }
-
- try {
- abort()
- } catch (IllegalStateException e) {
- // Ignore if process is already not running
- println "Did not abort play process since current state is: ${state.toString()}"
- }
- }
- }
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayCoverage.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayCoverage.groovy
deleted file mode 100644
index 8e82b34..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayCoverage.groovy
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest.fixtures
-
-class PlayCoverage {
- static final String[] DEFAULT = ["2.2.1", "2.2.6", "2.3.1", "2.3.7"]
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionApplicationIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionApplicationIntegrationTest.groovy
deleted file mode 100644
index de7420c..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionApplicationIntegrationTest.groovy
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest.fixtures
-
-import org.gradle.play.integtest.fixtures.app.PlayApp
-import org.gradle.test.fixtures.archive.JarTestFixture
-import org.gradle.test.fixtures.archive.ZipTestFixture
-
-abstract class PlayMultiVersionApplicationIntegrationTest extends PlayMultiVersionIntegrationTest {
- abstract PlayApp getPlayApp()
-
- def setup() {
- buildFile << """
- model {
- components {
- play {
- targetPlatform "play-${version}"
- }
- }
- }
- """
-
- playApp.writeSources(file("."))
- settingsFile << """
- rootProject.name = '${playApp.name}'
- """
- }
-
- JarTestFixture jar(String fileName) {
- new JarTestFixture(file(fileName))
- }
-
- ZipTestFixture zip(String fileName) {
- new ZipTestFixture(file(fileName))
- }
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionIntegrationTest.groovy
deleted file mode 100644
index 7de8af7..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionIntegrationTest.groovy
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest.fixtures
-import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
-import org.gradle.integtests.fixtures.TargetCoverage
-import org.gradle.util.Requires
-import org.gradle.util.TestPrecondition
-
- at TargetCoverage({PlayCoverage.DEFAULT})
- at Requires(TestPrecondition.JDK7_OR_LATER)
-abstract class PlayMultiVersionIntegrationTest extends MultiVersionIntegrationSpec {
-
-
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionRunApplicationIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionRunApplicationIntegrationTest.groovy
deleted file mode 100644
index ec8d06b..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionRunApplicationIntegrationTest.groovy
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.play.integtest.fixtures
-
-import org.gradle.util.AvailablePortFinder
-
-import static org.gradle.integtests.fixtures.UrlValidator.*
-
-abstract class PlayMultiVersionRunApplicationIntegrationTest extends PlayMultiVersionApplicationIntegrationTest {
- int httpPort
- def portFinder = AvailablePortFinder.createPrivate()
-
- URL playUrl(String path='') {
- return new URL("http://localhost:$httpPort/${path}")
- }
-
- void verifyStarted() {
- def url = playUrl().toString()
- available(url, "Play app", 60000)
- assert playUrl().text.contains("Your new application is ready.")
- }
-
- void verifyStopped() {
- notAvailable(playUrl().toString())
- }
-
- void verifyRunningApp() {
- // Check all static assets from the shared content
- assertUrlContent playUrl("assets/stylesheets/main.css"), file("public/stylesheets/main.css")
- assertUrlContent playUrl("assets/javascripts/hello.js"), file("public/javascripts/hello.js")
- assertBinaryUrlContent playUrl("assets/images/favicon.svg"), file("public/images/favicon.svg")
- }
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/AbstractPlaySampleIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/AbstractPlaySampleIntegrationTest.groovy
index 928667d..97c56f3 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/AbstractPlaySampleIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/AbstractPlaySampleIntegrationTest.groovy
@@ -18,18 +18,16 @@ package org.gradle.play.integtest.samples
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.Sample
import org.gradle.integtests.fixtures.executer.GradleHandle
-import org.gradle.util.AvailablePortFinder
+import org.gradle.play.integtest.fixtures.RunningPlayApp
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
-import org.gradle.util.TextUtil
import static org.gradle.integtests.fixtures.UrlValidator.*
@Requires(TestPrecondition.JDK7_OR_LATER)
abstract class AbstractPlaySampleIntegrationTest extends AbstractIntegrationSpec {
- def portFinder = AvailablePortFinder.createPrivate()
- def initScript
- int httpPort
+ File initScript
+ RunningPlayApp runningPlayApp = new RunningPlayApp(testDirectory)
abstract Sample getPlaySample();
@@ -41,11 +39,10 @@ abstract class AbstractPlaySampleIntegrationTest extends AbstractIntegrationSpec
}
def setup() {
- httpPort = portFinder.nextAvailable
initScript = file("initFile") << """
gradle.allprojects {
tasks.withType(PlayRun) {
- httpPort = $httpPort
+ httpPort = 0
}
}
"""
@@ -62,32 +59,25 @@ abstract class AbstractPlaySampleIntegrationTest extends AbstractIntegrationSpec
when:
sample playSample
- def userInput = new PipedOutputStream();
- executer.withStdIn(new PipedInputStream(userInput))
- executer.usingInitScript(initScript)
+ executer.usingInitScript(initScript).withStdinPipe()
GradleHandle gradleHandle = executer.withTasks(":runPlayBinary").start()
+ runningPlayApp.initialize(gradleHandle)
then:
- available("http://localhost:$httpPort", "Play app", 60000)
+ runningPlayApp.waitForStarted()
and:
checkContent()
when:
- stopWithCtrlD(userInput, gradleHandle)
+ gradleHandle.cancelWithEOT().waitForFinish()
then: "play server is stopped too"
- notAvailable("http://localhost:$httpPort")
- }
-
- static stopWithCtrlD(PipedOutputStream userInput, GradleHandle gradleHandle) {
- userInput.write(4) // ctrl+d
- userInput.write(TextUtil.toPlatformLineSeparators("\n").bytes) // For some reason flush() doesn't get the keystroke to the DaemonExecuter
- gradleHandle.waitForFinish()
+ runningPlayApp.verifyStopped()
}
URL playUrl(String path='') {
- return new URL("http://localhost:$httpPort/${path}")
+ runningPlayApp.playUrl(path)
}
File publicAsset(String asset) {
@@ -97,4 +87,4 @@ abstract class AbstractPlaySampleIntegrationTest extends AbstractIntegrationSpec
File appAsset(String asset) {
return new File(playSample.dir, "app/assets/${asset}")
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/MultiprojectPlaySampleIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/MultiprojectPlaySampleIntegrationTest.groovy
index 1c9e6d9..da7b471 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/MultiprojectPlaySampleIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/MultiprojectPlaySampleIntegrationTest.groovy
@@ -58,21 +58,20 @@ class MultiprojectPlaySampleIntegrationTest extends AbstractPlaySampleIntegratio
when:
sample playSample
- def userInput = new PipedOutputStream();
- executer.withStdIn(new PipedInputStream(userInput))
- executer.usingInitScript(initScript)
+ executer.usingInitScript(initScript).withStdinPipe()
GradleHandle gradleHandle = executer.withTasks(":admin:runPlayBinary").start()
+ runningPlayApp.initialize(gradleHandle)
then:
- available("http://localhost:$httpPort/admin", "Play app", 60000)
+ runningPlayApp.waitForStarted()
and:
checkAdminModuleContent()
when:
- stopWithCtrlD(userInput, gradleHandle)
+ gradleHandle.cancelWithEOT().waitForFinish()
then: "play server is stopped too"
- notAvailable("http://localhost:$httpPort/admin")
+ runningPlayApp.verifyStopped('admin')
}
}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/UserGuidePlaySamplesIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/UserGuidePlaySamplesIntegrationTest.groovy
new file mode 100644
index 0000000..566157c
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/samples/UserGuidePlaySamplesIntegrationTest.groovy
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.samples
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.Sample
+import org.gradle.test.fixtures.archive.JarTestFixture
+import org.gradle.test.fixtures.archive.ZipTestFixture
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import org.junit.Rule
+
+ at Requires(TestPrecondition.JDK7_OR_LATER)
+class UserGuidePlaySamplesIntegrationTest extends AbstractIntegrationSpec {
+ @Rule Sample sourceSetsPlaySample = new Sample(temporaryFolder, "play/sourcesets")
+ @Rule Sample compilerPlaySample = new Sample(temporaryFolder, "play/configure-compiler")
+ @Rule Sample distributionPlaySample = new Sample(temporaryFolder, "play/custom-distribution")
+ @Rule Sample customAssetsPlaySample = new Sample(temporaryFolder, "play/custom-assets")
+ @Rule Sample play24Sample = new Sample(temporaryFolder, "play/play-2.4")
+
+ def "sourcesets sample is buildable" () {
+ when:
+ sample sourceSetsPlaySample
+
+ then:
+ succeeds "build"
+
+ and:
+ applicationJar(sourceSetsPlaySample).containsDescendants(
+ "controllers/hello/HelloController.class",
+ "controllers/date/DateController.class",
+ "controllers/hello/routes.class",
+ "controllers/date/routes.class",
+ "html/main.class"
+ )
+ assetsJar(sourceSetsPlaySample).with {
+ containsDescendants(
+ "public/sample.js"
+ )
+ doesNotContainDescendants(
+ "public/old_sample.js"
+ )
+ }
+ }
+
+ def "compiler sample is buildable" () {
+ when:
+ sample compilerPlaySample
+
+ then:
+ succeeds "build"
+
+ and:
+ applicationJar(compilerPlaySample).containsDescendants(
+ "controllers/Application.class"
+ )
+ }
+
+ def "distribution sample is buildable" () {
+ when:
+ sample distributionPlaySample
+
+ then:
+ succeeds "dist"
+
+ and:
+ distributionZip(distributionPlaySample).containsDescendants(
+ "playBinary/README.md",
+ "playBinary/bin/runPlayBinaryAsUser.sh"
+ )
+ }
+
+ def "custom assets sample is buildable" () {
+ when:
+ sample customAssetsPlaySample
+
+ then:
+ succeeds "build"
+
+ and:
+ customAssetsPlaySample.dir.file("build/playBinary/addCopyRights/sample.js").text.contains("* Copyright 2015")
+ assetsJar(customAssetsPlaySample).containsDescendants(
+ "public/sample.js"
+ )
+ }
+
+ @Requires(TestPrecondition.JDK8_OR_LATER)
+ def "injected routes sample is buildable" () {
+ when:
+ sample play24Sample
+
+ then:
+ succeeds "build"
+
+ and:
+ play24Sample.dir.file("build/playBinary/src/compilePlayBinaryRoutes").assertHasDescendants(
+ "controllers/routes.java",
+ "controllers/ReverseRoutes.scala",
+ "router/Routes.scala",
+ "controllers/javascript/JavaScriptReverseRoutes.scala",
+ "router/RoutesPrefix.scala")
+ }
+
+ JarTestFixture applicationJar(Sample sample) {
+ def projectName = sample.dir.name
+ new JarTestFixture(sample.dir.file("build/playBinary/lib/${projectName}.jar"))
+ }
+
+ JarTestFixture assetsJar(Sample sample) {
+ def projectName = sample.dir.name
+ new JarTestFixture(sample.dir.file("build/playBinary/lib/${projectName}-assets.jar"))
+ }
+
+ ZipTestFixture distributionZip(Sample sample) {
+ new ZipTestFixture(sample.dir.file("build/distributions/playBinary.zip"))
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayApplicationPluginIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayApplicationPluginIntegrationTest.groovy
index 423168b..fd8aa3d 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayApplicationPluginIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayApplicationPluginIntegrationTest.groovy
@@ -16,14 +16,13 @@
package org.gradle.play.plugins
-import com.sun.xml.internal.ws.util.StringUtils
import org.gradle.api.JavaVersion
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.TestResources
+import org.gradle.play.internal.DefaultPlayPlatform
import org.gradle.test.fixtures.archive.JarTestFixture
import org.gradle.util.TextUtil
import org.junit.Rule
-import spock.lang.Unroll
class PlayApplicationPluginIntegrationTest extends AbstractIntegrationSpec {
@@ -37,11 +36,16 @@ class PlayApplicationPluginIntegrationTest extends AbstractIntegrationSpec {
id 'play-application'
}
- repositories{
+ repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
}
"""
@@ -62,7 +66,7 @@ Source sets
includes: **/*.java
JVM resources 'play:resources'
srcDir: conf
- Routes source 'play:routesSources'
+ Routes source 'play:routes'
srcDir: conf
includes: routes, *.routes
Scala source 'play:scala'
@@ -75,7 +79,7 @@ Source sets
Binaries
Play Application Jar 'playBinary'
build using task: :playBinary
- platform: Play Platform (Play 2.3.7, Scala: 2.11, Java: Java SE ${JavaVersion.current().majorVersion})"""))
+ platform: Play Platform (Play ${DefaultPlayPlatform.DEFAULT_PLAY_VERSION}, Scala: 2.11, Java: Java SE ${JavaVersion.current().majorVersion})"""))
}
def "cannot register multiple PlayApplicationSpec components"() {
@@ -105,25 +109,27 @@ Binaries
":createPlayBinaryAssetsJar",
":playBinary",
":assemble")
- skipped(":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
- ":scalaCompilePlayBinary")
+ skipped(":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
+ ":compilePlayBinaryScala")
and:
jar("build/playBinary/lib/play-app.jar").hasDescendants()
jar("build/playBinary/lib/play-app-assets.jar").hasDescendants()
}
- @Unroll
- def "can declare additional #languageName sourceSets"() {
+ def "can declare additional scala and java sourceSets"() {
given:
buildFile << """
model {
components {
play {
sources {
- extra($sourceSetType) {
- source.srcDir "src/extra"
+ extraJava(JavaSourceSet) {
+ source.srcDir "src/extraJava"
+ }
+ extraScala(ScalaLanguageSourceSet) {
+ source.srcDir "src/extraScala"
}
}
}
@@ -131,10 +137,13 @@ Binaries
}
"""
and:
- file("src/extra/org/acme/model/Person.${languageName}") << """
+ file("src/extraJava/org/acme/model/JavaPerson.java") << """
package org.acme.model;
- class Person {
- }
+ class JavaPerson {}
+"""
+ file("src/extraScala/org/acme/model/ScalaPerson.scala") << """
+ package org.acme.model;
+ class ScalaPerson {}
"""
when:
@@ -142,8 +151,12 @@ Binaries
then:
output.contains(TextUtil.toPlatformLineSeparators("""
- ${StringUtils.capitalize(languageName)} source 'play:extra'
- srcDir: src${File.separator}extra
+ Java source 'play:extraJava'
+ srcDir: src${File.separator}extraJava
+"""))
+ output.contains(TextUtil.toPlatformLineSeparators("""
+ Scala source 'play:extraScala'
+ srcDir: src${File.separator}extraScala
"""))
when:
@@ -151,26 +164,20 @@ Binaries
then:
executedAndNotSkipped(
+ ":compilePlayBinaryScala",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
- ":scalaCompilePlayBinary",
":playBinary",
":assemble")
- skipped(":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary")
+ skipped(":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates")
and:
- jar("build/playBinary/lib/play-app.jar").hasDescendants("org/acme/model/Person.class")
+ jar("build/playBinary/lib/play-app.jar").hasDescendants("org/acme/model/JavaPerson.class", "org/acme/model/ScalaPerson.class")
jar("build/playBinary/lib/play-app-assets.jar").hasDescendants()
-
- where:
-
- languageName | sourceSetType
- "scala" | "ScalaLanguageSourceSet"
- "java" | "JavaSourceSet"
}
JarTestFixture jar(String fileName) {
new JarTestFixture(file(fileName))
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginIntegrationTest.groovy
index 831e50b..aa18b57 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginIntegrationTest.groovy
@@ -27,7 +27,7 @@ class PlayCoffeeScriptPluginIntegrationTest extends AbstractIntegrationSpec {
def setup() {
buildFile << """
plugins {
- id 'play-application'
+ id 'play'
id 'play-coffeescript'
}
@@ -49,10 +49,9 @@ class PlayCoffeeScriptPluginIntegrationTest extends AbstractIntegrationSpec {
then:
normalizedOutput.contains("""
- CoffeeScript source 'play:coffeeScriptAssets'
+ CoffeeScript source 'play:coffeeScript'
srcDir: app/assets
- includes: **/*.coffee""")
- normalizedOutput.contains("""
+ includes: **/*.coffee
CoffeeScript source 'play:otherCoffeeScript'
srcDir: src/play/otherCoffeeScript
""")
@@ -63,7 +62,7 @@ class PlayCoffeeScriptPluginIntegrationTest extends AbstractIntegrationSpec {
task checkTasks {
doLast {
assert tasks.withType(CoffeeScriptCompile).size() == 2
- tasks.withType(CoffeeScriptCompile)*.name as Set == ["compilePlayBinaryCoffeeScriptAssets", "compilePlayBinaryOtherCoffeeScript"] as Set
+ tasks.withType(CoffeeScriptCompile)*.name as Set == ["compileCoffeeScriptPlayBinary", "compileOtherCoffeeScriptPlayBinary"] as Set
}
}
"""
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayDistributionPluginIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayDistributionPluginIntegrationTest.groovy
index c43cda5..c304bb4 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayDistributionPluginIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayDistributionPluginIntegrationTest.groovy
@@ -35,9 +35,14 @@ class PlayDistributionPluginIntegrationTest extends AbstractIntegrationSpec {
repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
}
"""
@@ -71,9 +76,9 @@ class PlayDistributionPluginIntegrationTest extends AbstractIntegrationSpec {
":createPlayBinaryStartScripts",
":stagePlayBinaryDist")
skipped(
- ":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
- ":scalaCompilePlayBinary")
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
+ ":compilePlayBinaryScala")
and:
file("build/stage/playBinary").assertContainsDescendants(
@@ -92,9 +97,9 @@ class PlayDistributionPluginIntegrationTest extends AbstractIntegrationSpec {
then:
executedAndNotSkipped(":createPlayBinaryDist")
skipped(
- ":routesCompileRoutesSourcesPlayBinary",
- ":twirlCompileTwirlTemplatesPlayBinary",
- ":scalaCompilePlayBinary",
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryTwirlTemplates",
+ ":compilePlayBinaryScala",
":createPlayBinaryJar",
":createPlayBinaryDistributionJar",
":createPlayBinaryAssetsJar",
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayJavaScriptPluginIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayJavaScriptPluginIntegrationTest.groovy
index 321531d..d2bd16a 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayJavaScriptPluginIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/plugins/PlayJavaScriptPluginIntegrationTest.groovy
@@ -45,7 +45,7 @@ class PlayJavaScriptPluginIntegrationTest extends AbstractIntegrationSpec {
then:
normalizedOutput.contains("""
- JavaScript source 'play:javaScriptAssets'
+ JavaScript source 'play:javaScript'
srcDir: app/assets
includes: **/*.js
JavaScript source 'play:otherJavaScript'
@@ -57,7 +57,7 @@ class PlayJavaScriptPluginIntegrationTest extends AbstractIntegrationSpec {
buildFile << """
task checkTasks {
doLast {
- tasks.withType(JavaScriptMinify)*.name as Set == ["minifyPlayBinaryJavaScriptAssets", "minifyPlayBinaryOtherJavaScript"] as Set
+ tasks.withType(JavaScriptMinify)*.name as Set == ["minifyPlayBinaryJavaScript", "minifyPlayBinaryOtherJavaScript"] as Set
}
}
"""
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/AbstractRoutesCompileIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/AbstractRoutesCompileIntegrationTest.groovy
new file mode 100644
index 0000000..692c8b0
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/AbstractRoutesCompileIntegrationTest.groovy
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.gradle.play.tasks
+
+import org.apache.commons.lang.StringUtils
+import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
+import org.gradle.test.fixtures.archive.JarTestFixture
+import org.gradle.test.fixtures.file.TestFile
+import org.gradle.util.TextUtil
+
+abstract class AbstractRoutesCompileIntegrationTest extends MultiVersionIntegrationSpec {
+ def destinationDirPath = "build/playBinary/src/compilePlayBinaryRoutes"
+ def destinationDir = file(destinationDirPath)
+
+ abstract getRoutesJavaFileNameTemplate(String packageName, String namespace);
+ abstract getRoutesReverseFileNameTemplate(String packageName, String namespace);
+ abstract getRoutesScalaFileNameTemplate(String packageName, String namespace);
+ abstract getOtherRoutesFilesTemplates();
+
+ def setup() {
+ settingsFile << """ rootProject.name = 'routes-play-app' """
+ buildFile <<"""
+plugins {
+ id 'play-application'
+}
+
+model {
+ components {
+ play {
+ targetPlatform "play-${version}"
+ }
+ }
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
+"""
+ }
+
+ def "can run RoutesCompile"() {
+ given:
+ withRoutesTemplate()
+ expect:
+ succeeds("compilePlayBinaryRoutes")
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList() as String[])
+ }
+
+ def "recompiles on changed routes file input"() {
+ given:
+ TestFile templateFile = withRoutesTemplate()
+ succeeds("compilePlayBinaryRoutes")
+
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList() as String[])
+ def routesFirstCompileSnapshot = file(destinationDirPath, getRoutesJavaFileNameTemplate('','')).snapshot();
+ def revRoutingFirstCompileSnapshot = file(destinationDirPath, getRoutesReverseFileNameTemplate('','')).snapshot();
+ def routingFirstCompileSnapshot = file(destinationDirPath, getRoutesScalaFileNameTemplate('','')).snapshot();
+
+ when:
+ templateFile << """
+GET /newroute controllers.Application.index()
+"""
+
+ and:
+ succeeds "compilePlayBinaryRoutes"
+
+ then:
+ executedAndNotSkipped ":compilePlayBinaryRoutes"
+
+ and:
+ file(destinationDirPath, getRoutesJavaFileNameTemplate('','')).assertHasChangedSince(routesFirstCompileSnapshot)
+ file(destinationDirPath, getRoutesReverseFileNameTemplate('','')).assertHasChangedSince(revRoutingFirstCompileSnapshot);
+ file(destinationDirPath, getRoutesScalaFileNameTemplate('','')).assertHasChangedSince(routingFirstCompileSnapshot);
+
+ when:
+ succeeds "compilePlayBinaryRoutes"
+
+ then:
+ skipped ":compilePlayBinaryRoutes"
+ }
+
+ def "compiles additional routes file and cleans up output on removal"(){
+ when:
+ withRoutesTemplate()
+ then:
+ succeeds("compilePlayBinaryRoutes")
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList() as String[])
+
+ when:
+ withRoutesTemplate("foo")
+ and:
+ succeeds("compilePlayBinaryRoutes")
+ then:
+ destinationDir.assertHasDescendants((createRouteFileList() + createRouteFileList('foo')) as String[])
+
+ when:
+ file("conf/foo.routes").delete()
+ then:
+ succeeds("compilePlayBinaryRoutes")
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList() as String[])
+ createRouteFileList('foo').each { destinationDir.file(it).assertDoesNotExist() }
+ }
+
+ def "compiles multiple Routes source sets as part of play application build" () {
+ withExtraSourceSets()
+ withRoutesTemplate()
+ withRoutesSource(file("extraRoutes", "some", "pkg", "some.pkg.routes"), ".some.pkg")
+ withRoutesSource(file("otherRoutes", "other", "other.routes"), ".other")
+
+ when:
+ succeeds "assemble"
+
+ then:
+ executedAndNotSkipped(
+ ":compilePlayBinaryRoutes",
+ ":compilePlayBinaryExtraRoutes",
+ ":compilePlayBinaryOtherRoutes"
+ )
+
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList() as String[])
+ destinationDir("extraRoutes").assertHasDescendants(createRouteFileList('some/pkg') as String[])
+ destinationDir("otherRoutes").assertHasDescendants(createRouteFileList('other') as String[])
+
+ and:
+ jar("build/playBinary/lib/routes-play-app.jar").containsDescendants("controllers/routes.class")
+ jar("build/playBinary/lib/routes-play-app.jar").containsDescendants("controllers/some/pkg/routes.class")
+ jar("build/playBinary/lib/routes-play-app.jar").containsDescendants("controllers/other/routes.class")
+ }
+
+ def "extra route sources appear in the components report" () {
+ withExtraSourceSets()
+
+ when:
+ succeeds "components"
+
+ then:
+ output.contains(TextUtil.toPlatformLineSeparators("""
+Play Application 'play'
+-----------------------
+
+Source sets
+ Java source 'play:java'
+ srcDir: app
+ includes: **/*.java
+ JVM resources 'play:resources'
+ srcDir: conf
+ Routes source 'play:extraRoutes'
+ srcDir: extraRoutes
+ Routes source 'play:otherRoutes'
+ srcDir: otherRoutes
+ Routes source 'play:routes'
+ srcDir: conf
+ includes: routes, *.routes
+ Scala source 'play:scala'
+ srcDir: app
+ includes: **/*.scala
+ Twirl template source 'play:twirlTemplates'
+ srcDir: app
+ includes: **/*.html
+
+Binaries
+"""))
+ }
+
+ def "can run RoutesCompile with namespaceReverseRouter set"() {
+ given:
+ withRoutesTemplate("org.gradle.test")
+ buildFile << """
+ model {
+ components {
+ play {
+ tasks.withType(RoutesCompile) {
+ namespaceReverseRouter = true
+ }
+ }
+ }
+ }
+ """
+ expect:
+ succeeds("compilePlayBinaryRoutes")
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList("org/gradle/test", "org/gradle/test") as String[])
+ }
+
+ def destinationDir(String sourceSetName) {
+ return file("build/playBinary/src/compilePlayBinary${StringUtils.capitalize(sourceSetName)}")
+ }
+
+ def withRoutesSource(TestFile routesFile, String packageId) {
+ routesFile.createFile()
+ routesFile << """
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET / controllers${packageId}.Application.index()
+"""
+ withControllerSource(file("app/controllers/${packageId}/Application.scala"), packageId)
+ return routesFile
+ }
+
+ def withControllerSource(TestFile file, String packageId) {
+ file.createFile()
+ file << """
+package controllers${packageId}
+
+
+import play.api._
+import play.api.mvc._
+import models._
+
+object Application extends Controller {
+ def index = Action {
+ Ok("Your new application is ready.")
+ }
+}
+"""
+ }
+
+ def withRoutesTemplate(String packageName = "") {
+ def routesFile = packageName.isEmpty() ? file("conf", "routes") : file("conf", packageName + ".routes")
+ def packageId = packageName.isEmpty() ? "" : ".$packageName"
+ withRoutesSource(routesFile, packageId)
+ }
+
+ def createRouteFileList(String packageName = '', String namespace='') {
+ [getRoutesJavaFileNameTemplate(packageName, namespace), getRoutesReverseFileNameTemplate(packageName, namespace), getRoutesScalaFileNameTemplate(packageName, namespace)] + otherRoutesFilesTemplates.collect { it(packageName, namespace) }
+ }
+
+ def withExtraSourceSets() {
+ buildFile << """
+ model {
+ components {
+ play {
+ sources {
+ extraRoutes(RoutesSourceSet) {
+ source.srcDir "extraRoutes"
+ }
+ otherRoutes(RoutesSourceSet) {
+ source.srcDir "otherRoutes"
+ }
+ }
+ }
+ }
+ }
+ """
+ }
+
+ JarTestFixture jar(String fileName) {
+ new JarTestFixture(file(fileName))
+ }
+
+ def "can add additional imports"() {
+ given:
+ withRoutesTemplate()
+ and:
+ buildFile << """
+model {
+ components {
+ play {
+ tasks.withType(RoutesCompile) {
+ additionalImports << "extra.package"
+ }
+ }
+ }
+}
+"""
+ expect:
+ succeeds("compilePlayBinaryRoutes")
+ and:
+ destinationDir.file(getRoutesReverseFileNameTemplate('', '')).text.contains("extra.package")
+ destinationDir.file(getRoutesScalaFileNameTemplate('', '')).text.contains("extra.package")
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CoffeeScriptCompileIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CoffeeScriptCompileIntegrationTest.groovy
index 14be7d1..994927b 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CoffeeScriptCompileIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CoffeeScriptCompileIntegrationTest.groovy
@@ -19,7 +19,7 @@ package org.gradle.play.tasks
class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileIntegrationTest {
@Override
String getDefaultSourceSet() {
- return "CoffeeScriptAssets"
+ return "CoffeeScript"
}
def setup() {
@@ -29,16 +29,21 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
id 'play-coffeescript'
}
- repositories{
+ repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
maven {
name = "gradle-js"
url = "https://repo.gradle.org/gradle/javascript-public"
- }
+ }
}
"""
}
@@ -50,8 +55,8 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
then:
executedAndNotSkipped(
- ":compilePlayBinaryCoffeeScriptAssets",
- ":minifyPlayBinaryCoffeeScriptAssetsJavaScript",
+ ":compilePlayBinaryCoffeeScript",
+ ":minifyPlayBinaryCoffeeScriptJavaScript",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
":playBinary")
@@ -67,10 +72,10 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
def "minify task depends on compile task" () {
when:
withCoffeeScriptSource(assets("test.coffee"))
- succeeds "minifyPlayBinaryCoffeeScriptAssetsJavaScript"
+ succeeds "minifyPlayBinaryCoffeeScriptJavaScript"
then:
- executedAndNotSkipped ":compilePlayBinaryCoffeeScriptAssets"
+ executedAndNotSkipped ":compilePlayBinaryCoffeeScript"
}
def "compiles multiple coffeescript source sets as part of play application build" () {
@@ -101,13 +106,13 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
then:
executedAndNotSkipped(
- ":compilePlayBinaryCoffeeScriptAssets",
- ":minifyPlayBinaryCoffeeScriptAssetsJavaScript",
+ ":compilePlayBinaryCoffeeScript",
+ ":minifyPlayBinaryCoffeeScriptJavaScript",
":compilePlayBinaryExtraCoffeeScript",
":minifyPlayBinaryExtraCoffeeScriptJavaScript",
":compilePlayBinaryAnotherCoffeeScript",
":minifyPlayBinaryAnotherCoffeeScriptJavaScript",
- ":minifyPlayBinaryJavaScriptAssets",
+ ":minifyPlayBinaryJavaScript",
":minifyPlayBinaryExtraJavaScript",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
@@ -144,8 +149,8 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
succeeds "assemble"
then:
- skipped(":compilePlayBinaryCoffeeScriptAssets",
- ":minifyPlayBinaryCoffeeScriptAssetsJavaScript",
+ skipped(":compilePlayBinaryCoffeeScript",
+ ":minifyPlayBinaryCoffeeScriptJavaScript",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
":playBinary")
@@ -162,8 +167,8 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
then:
executedAndNotSkipped(
- ":compilePlayBinaryCoffeeScriptAssets",
- ":minifyPlayBinaryCoffeeScriptAssetsJavaScript",
+ ":compilePlayBinaryCoffeeScript",
+ ":minifyPlayBinaryCoffeeScriptJavaScript",
":createPlayBinaryAssetsJar",
":playBinary")
}
@@ -182,8 +187,8 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
then:
executedAndNotSkipped(
- ":compilePlayBinaryCoffeeScriptAssets",
- ":minifyPlayBinaryCoffeeScriptAssetsJavaScript",
+ ":compilePlayBinaryCoffeeScript",
+ ":minifyPlayBinaryCoffeeScriptJavaScript",
":createPlayBinaryAssetsJar",
":playBinary")
compiled("test.js").exists()
@@ -227,7 +232,7 @@ class CoffeeScriptCompileIntegrationTest extends AbstractCoffeeScriptCompileInte
fails "assemble"
then:
- failure.assertHasDescription "Execution failed for task ':compilePlayBinaryCoffeeScriptAssets'."
+ failure.assertHasDescription "Execution failed for task ':compilePlayBinaryCoffeeScript'."
failure.assertHasCause "Failed to compile coffeescript file: test1.coffee"
failure.assertHasCause "SyntaxError: unexpected if (coffee-script-js-1.8.0.js#10)"
}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CustomCoffeeScriptImplementationIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CustomCoffeeScriptImplementationIntegrationTest.groovy
index d138aed..ea3ffe2 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CustomCoffeeScriptImplementationIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/CustomCoffeeScriptImplementationIntegrationTest.groovy
@@ -21,7 +21,7 @@ class CustomCoffeeScriptImplementationIntegrationTest extends AbstractCoffeeScri
@Override
String getDefaultSourceSet() {
- return "CoffeeScriptAssets"
+ return "CoffeeScript"
}
def setup() {
@@ -29,7 +29,7 @@ class CustomCoffeeScriptImplementationIntegrationTest extends AbstractCoffeeScri
file(customCoffeeScriptImplFileName) << getClass().getResource("/coffee-script.min.js").text
withCoffeeScriptSource('app/assets/test.coffee')
- withCoffeeScriptSource('src/play/extraCoffeeScriptAssets/test2.coffee')
+ withCoffeeScriptSource('src/play/extraCoffeeScript/test2.coffee')
buildFile << """
plugins {
id 'play'
@@ -52,7 +52,7 @@ class CustomCoffeeScriptImplementationIntegrationTest extends AbstractCoffeeScri
components {
play {
sources {
- extraCoffeeScriptAssets(CoffeeScriptSourceSet)
+ extraCoffeeScript(CoffeeScriptSourceSet)
}
binaries.all {
tasks.withType(PlayCoffeeScriptCompile) {
@@ -65,11 +65,11 @@ class CustomCoffeeScriptImplementationIntegrationTest extends AbstractCoffeeScri
"""
when:
- succeeds "compilePlayBinaryCoffeeScriptAssets", "compilePlayBinaryExtraCoffeeScriptAssets"
+ succeeds "compilePlayBinaryCoffeeScript", "compilePlayBinaryExtraCoffeeScript"
then:
matchesExpectedRaw('test.js')
- matchesExpectedRaw('ExtraCoffeeScriptAssets', 'test2.js')
+ matchesExpectedRaw('ExtraCoffeeScript', 'test2.js')
}
def "can compile coffeescript with a custom implementation from configuration"() {
@@ -86,7 +86,7 @@ class CustomCoffeeScriptImplementationIntegrationTest extends AbstractCoffeeScri
components {
play {
sources {
- extraCoffeeScriptAssets(CoffeeScriptSourceSet)
+ extraCoffeeScript(CoffeeScriptSourceSet)
}
binaries.all {
tasks.withType(PlayCoffeeScriptCompile) {
@@ -99,10 +99,10 @@ class CustomCoffeeScriptImplementationIntegrationTest extends AbstractCoffeeScri
"""
when:
- succeeds "compilePlayBinaryCoffeeScriptAssets", "compilePlayBinaryExtraCoffeeScriptAssets"
+ succeeds "compilePlayBinaryCoffeeScript", "compilePlayBinaryExtraCoffeeScript"
then:
matchesExpectedRaw('test.js')
- matchesExpectedRaw('ExtraCoffeeScriptAssets', 'test2.js')
+ matchesExpectedRaw('ExtraCoffeeScript', 'test2.js')
}
}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/DistributionZipIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/DistributionZipIntegrationTest.groovy
index 813547e..dce0ab9 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/DistributionZipIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/DistributionZipIntegrationTest.groovy
@@ -29,9 +29,14 @@ class DistributionZipIntegrationTest extends AbstractIntegrationSpec {
repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
}
"""
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/JavaScriptMinifyIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/JavaScriptMinifyIntegrationTest.groovy
index ff0d382..7a9529e 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/JavaScriptMinifyIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/JavaScriptMinifyIntegrationTest.groovy
@@ -21,7 +21,7 @@ import org.hamcrest.Matchers
class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegrationTest {
@Override
String getDefaultSourceSet() {
- return "JavaScriptAssets"
+ return "JavaScript"
}
def setup() {
@@ -31,11 +31,16 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
id 'play-javascript'
}
- repositories{
+ repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
}
"""
@@ -50,7 +55,7 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
then:
executedAndNotSkipped(
- ":minifyPlayBinaryJavaScriptAssets",
+ ":minifyPlayBinaryJavaScript",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
":playBinary")
@@ -74,7 +79,7 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
succeeds "assemble"
then:
- skipped(":minifyPlayBinaryJavaScriptAssets",
+ skipped(":minifyPlayBinaryJavaScript",
":createPlayBinaryJar",
":createPlayBinaryAssetsJar",
":playBinary")
@@ -93,7 +98,7 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
then:
executedAndNotSkipped(
- ":minifyPlayBinaryJavaScriptAssets",
+ ":minifyPlayBinaryJavaScript",
":createPlayBinaryAssetsJar",
":playBinary")
minified("test.min.js").exists()
@@ -111,7 +116,7 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
then:
executedAndNotSkipped(
- ":minifyPlayBinaryJavaScriptAssets",
+ ":minifyPlayBinaryJavaScript",
":createPlayBinaryAssetsJar",
":playBinary")
}
@@ -173,7 +178,7 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
then:
executedAndNotSkipped(
- ":minifyPlayBinaryJavaScriptAssets",
+ ":minifyPlayBinaryJavaScript",
":minifyPlayBinaryExtraJavaScript",
":minifyPlayBinaryAnotherJavaScript",
":createPlayBinaryJar",
@@ -198,7 +203,7 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
succeeds "assemble"
then:
- skipped(":minifyPlayBinaryJavaScriptAssets",
+ skipped(":minifyPlayBinaryJavaScript",
":minifyPlayBinaryExtraJavaScript",
":minifyPlayBinaryAnotherJavaScript",
":createPlayBinaryJar",
@@ -218,7 +223,7 @@ class JavaScriptMinifyIntegrationTest extends AbstractJavaScriptMinifyIntegratio
then:
minified("javascripts/hello.min.js").exists()
copied("javascripts/hello.js").exists()
- failure.assertHasDescription("Execution failed for task ':minifyPlayBinaryJavaScriptAssets'.")
+ failure.assertHasDescription("Execution failed for task ':minifyPlayBinaryJavaScript'.")
String slash = File.separator
failure.assertThatCause(Matchers.allOf([
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/Play23RoutesCompileIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/Play23RoutesCompileIntegrationTest.groovy
new file mode 100644
index 0000000..b239cb0
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/Play23RoutesCompileIntegrationTest.groovy
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.tasks
+
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.play.integtest.fixtures.PlayCoverage
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+
+ at TargetCoverage({ PlayCoverage.PLAY23_OR_EARLIER })
+ at Requires(TestPrecondition.JDK7_OR_LATER)
+class Play23RoutesCompileIntegrationTest extends AbstractRoutesCompileIntegrationTest {
+ @Override
+ def getRoutesJavaFileNameTemplate(String packageName, String namespace) {
+ return "${namespace ? namespace + '/' :''}controllers/${packageName ? packageName + '/' :''}routes.java"
+ }
+
+ @Override
+ def getRoutesReverseFileNameTemplate(String packageName, String namespace) {
+ return "${packageName ? packageName + '/' :''}routes_reverseRouting.scala"
+ }
+
+ @Override
+ def getRoutesScalaFileNameTemplate(String packageName, String namespace) {
+ return "${packageName ? packageName + '/' :''}routes_routing.scala"
+ }
+
+ @Override
+ def getOtherRoutesFilesTemplates() {
+ return []
+ }
+
+ def "trying to use injected router with older versions of Play produces reasonable error"() {
+ given:
+ withRoutesTemplate()
+
+ buildFile << """
+model {
+ components {
+ play {
+ injectedRoutesGenerator = true
+ }
+ }
+}
+"""
+ expect:
+ fails("assemble")
+ and:
+ errorOutput.contains("Injected routers are only supported in Play 2.4 or newer.")
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/Play24RoutesCompileIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/Play24RoutesCompileIntegrationTest.groovy
new file mode 100644
index 0000000..3ec8b25
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/Play24RoutesCompileIntegrationTest.groovy
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.tasks
+
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.play.integtest.fixtures.PlayCoverage
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+
+ at TargetCoverage({ PlayCoverage.PLAY24_OR_LATER })
+ at Requires(TestPrecondition.JDK8_OR_LATER)
+class Play24RoutesCompileIntegrationTest extends AbstractRoutesCompileIntegrationTest {
+ @Override
+ def getRoutesJavaFileNameTemplate(String packageName, String namespace) {
+ return "${namespace ? namespace + '/' :''}controllers/${packageName ? packageName + '/' :''}routes.java"
+ }
+
+ @Override
+ def getRoutesReverseFileNameTemplate(String packageName, String namespace) {
+ return "${namespace ? namespace + '/' :''}controllers/${packageName ? packageName + '/' :''}ReverseRoutes.scala"
+ }
+
+ @Override
+ def getRoutesScalaFileNameTemplate(String packageName, String namespace) {
+ return "${packageName?:'router'}/Routes.scala"
+ }
+
+ @Override
+ def getOtherRoutesFilesTemplates() {
+ return [
+ {packageName, namespace -> "${namespace ? namespace + '/' :''}controllers/${packageName ? packageName + '/' :''}javascript/JavaScriptReverseRoutes.scala" },
+ {packageName, namespace -> "${packageName?:'router'}/RoutesPrefix.scala" }
+ ]
+ }
+
+ def "can specify route compiler type as injected"() {
+ given:
+ withRoutesTemplate()
+ withInjectedRoutesController()
+ buildFile << """
+model {
+ components {
+ play {
+ injectedRoutesGenerator = true
+ }
+ }
+}
+"""
+ expect:
+ succeeds("compilePlayBinaryScala")
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList() as String[])
+ }
+
+ def "recompiles when route compiler type is changed"() {
+ when:
+ withRoutesTemplate()
+ then:
+ succeeds("compilePlayBinaryScala")
+
+ when:
+ withInjectedRoutesController()
+ buildFile << """
+model {
+ components {
+ play {
+ injectedRoutesGenerator = true
+ }
+ }
+}
+"""
+ then:
+ succeeds("compilePlayBinaryScala")
+ executedTasks.contains(":compilePlayBinaryRoutes")
+ and:
+ destinationDir.assertHasDescendants(createRouteFileList() as String[])
+ }
+
+ private withInjectedRoutesController() {
+ file("app/controllers/Application.scala").with {
+ // change Scala companion object into a regular class
+ text = text.replaceFirst(/object/, "class")
+ }
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/PlayRunIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/PlayRunIntegrationTest.groovy
new file mode 100644
index 0000000..445dfab
--- /dev/null
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/PlayRunIntegrationTest.groovy
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.tasks
+
+import org.gradle.play.integtest.fixtures.PlayMultiVersionRunApplicationIntegrationTest
+import org.gradle.play.integtest.fixtures.app.BasicPlayApp
+import org.gradle.play.integtest.fixtures.app.PlayApp
+
+class PlayRunIntegrationTest extends PlayMultiVersionRunApplicationIntegrationTest {
+ PlayApp playApp = new BasicPlayApp()
+
+ def setup() {
+ buildFile << """
+ model {
+ tasks.runPlayBinary {
+ httpPort = 0
+ }
+ }
+ """
+ }
+
+ def "play run container classloader is isolated from the worker process classloader"() {
+ withLoadProjectClassController()
+
+ setup:
+ // build once to speed up the playRun build and avoid spurious timeouts
+ succeeds "assemble"
+
+ when:
+ startBuild "runPlayBinary"
+
+ then:
+ runningApp.verifyStarted()
+ runningApp.playUrl("loadProjectClass").text.contains("SUCCESS: class not found")
+
+ cleanup:
+ build.cancelWithEOT().waitForFinish()
+ runningApp.verifyStopped()
+ }
+
+ void withLoadProjectClassController() {
+ file("app/controllers/jva").mkdirs()
+ file("app/controllers/jva/LoadProjectClass.java").text = loadProjectClassController
+ file("conf/routes") << """
+GET /loadProjectClass controllers.jva.LoadProjectClass.index
+"""
+ }
+
+ String getLoadProjectClassController() {
+ return """
+package controllers.jva;
+
+import play.*;
+import play.mvc.*;
+
+public class LoadProjectClass extends Controller {
+
+ public static Result index() {
+ try {
+ LoadProjectClass.class.getClassLoader().loadClass("org.gradle.api.Project");
+ } catch (ClassNotFoundException e) {
+ return ok("SUCCESS: class not found");
+ }
+ return ok("FAILED: class was found");
+ }
+
+}
+"""
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/RoutesCompileIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/RoutesCompileIntegrationTest.groovy
deleted file mode 100644
index 8733e06..0000000
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/RoutesCompileIntegrationTest.groovy
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-package org.gradle.play.tasks
-
-import org.apache.commons.lang.StringUtils
-import org.gradle.play.integtest.fixtures.PlayMultiVersionIntegrationTest
-import org.gradle.test.fixtures.archive.JarTestFixture
-import org.gradle.test.fixtures.file.TestFile
-import org.gradle.util.TextUtil
-
-class RoutesCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
- def destinationDirPath = "build/playBinary/src/routesCompileRoutesSourcesPlayBinary"
- def destinationDir = file(destinationDirPath)
-
- def setup() {
- settingsFile << """ rootProject.name = 'routes-play-app' """
- buildFile <<"""
-plugins {
- id 'play-application'
-}
-
-model {
- components {
- play {
- targetPlatform "play-${version}"
- }
- }
-}
-
-repositories{
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
-}
-"""
- }
-
- def "can run RoutesCompile"() {
- given:
- withRoutesTemplate()
- expect:
- succeeds("routesCompileRoutesSourcesPlayBinary")
- and:
- destinationDir.assertHasDescendants("controllers/routes.java", "routes_reverseRouting.scala", "routes_routing.scala")
- }
-
- def "recompiles on changed routes file input"() {
- given:
- TestFile templateFile = withRoutesTemplate()
- succeeds("routesCompileRoutesSourcesPlayBinary")
-
- and:
- destinationDir.assertHasDescendants("controllers/routes.java", "routes_reverseRouting.scala", "routes_routing.scala")
- def routesFirstCompileSnapshot = file(destinationDirPath, "controllers/routes.java").snapshot();
- def revRoutingFirstCompileSnapshot = file(destinationDirPath, "routes_reverseRouting.scala").snapshot();
- def routingFirstCompileSnapshot = file(destinationDirPath, "routes_routing.scala").snapshot();
-
- when:
- templateFile << "\n\n"
- and:
- succeeds "routesCompileRoutesSourcesPlayBinary"
-
- then:
- executedAndNotSkipped ":routesCompileRoutesSourcesPlayBinary"
-
- and:
- file(destinationDirPath, "controllers/routes.java").assertHasChangedSince(routesFirstCompileSnapshot)
- file(destinationDirPath, "routes_reverseRouting.scala").assertHasChangedSince(revRoutingFirstCompileSnapshot);
- file(destinationDirPath, "routes_routing.scala").assertHasChangedSince(routingFirstCompileSnapshot);
-
- when:
- succeeds "routesCompileRoutesSourcesPlayBinary"
-
- then:
- skipped ":routesCompileRoutesSourcesPlayBinary"
- }
-
- def "compiles additional routes file and cleans up output on removal"(){
- when:
- withRoutesTemplate()
- then:
- succeeds("routesCompileRoutesSourcesPlayBinary")
- and:
- destinationDir.assertHasDescendants("controllers/routes.java", "routes_reverseRouting.scala", "routes_routing.scala")
-
- when:
- withRoutesTemplate("foo")
- and:
- succeeds("routesCompileRoutesSourcesPlayBinary")
- then:
- destinationDir.assertHasDescendants("controllers/routes.java", "routes_reverseRouting.scala", "routes_routing.scala",
- "controllers/foo/routes.java", "foo/routes_reverseRouting.scala", "foo/routes_routing.scala")
-
- when:
- file("conf/foo.routes").delete()
- then:
- succeeds("routesCompileRoutesSourcesPlayBinary")
- and:
- destinationDir.assertHasDescendants("controllers/routes.java", "routes_reverseRouting.scala", "routes_routing.scala")
- }
-
- def "compiles multiple Routes source sets as part of play application build" () {
- withExtraSourceSets()
- withRoutesTemplate()
- withRoutesSource(file("extraRoutes", "some", "pkg", "some.pkg.routes"), ".some.pkg")
- withRoutesSource(file("otherRoutes", "other", "other.routes"), ".other")
-
- when:
- succeeds "assemble"
-
- then:
- executedAndNotSkipped(
- ":routesCompileRoutesSourcesPlayBinary",
- ":routesCompileExtraRoutesPlayBinary",
- ":routesCompileOtherRoutesPlayBinary"
- )
-
- and:
- destinationDir.assertHasDescendants("controllers/routes.java", "routes_reverseRouting.scala", "routes_routing.scala")
- destinationDir("extraRoutes").assertHasDescendants("controllers/some/pkg/routes.java", "some/pkg/routes_reverseRouting.scala", "some/pkg/routes_routing.scala")
- destinationDir("otherRoutes").assertHasDescendants("controllers/other/routes.java", "other/routes_reverseRouting.scala", "other/routes_routing.scala")
-
- and:
- jar("build/playBinary/lib/routes-play-app.jar").containsDescendants("controllers/routes.class")
- jar("build/playBinary/lib/routes-play-app.jar").containsDescendants("controllers/some/pkg/routes.class")
- jar("build/playBinary/lib/routes-play-app.jar").containsDescendants("controllers/other/routes.class")
- }
-
- def "extra route sources appear in the components report" () {
- withExtraSourceSets()
-
- when:
- succeeds "components"
-
- then:
- output.contains(TextUtil.toPlatformLineSeparators("""
-Play Application 'play'
------------------------
-
-Source sets
- Java source 'play:java'
- srcDir: app
- includes: **/*.java
- JVM resources 'play:resources'
- srcDir: conf
- Routes source 'play:extraRoutes'
- srcDir: extraRoutes
- Routes source 'play:otherRoutes'
- srcDir: otherRoutes
- Routes source 'play:routesSources'
- srcDir: conf
- includes: routes, *.routes
- Scala source 'play:scala'
- srcDir: app
- includes: **/*.scala
- Twirl template source 'play:twirlTemplates'
- srcDir: app
- includes: **/*.html
-
-Binaries
-"""))
- }
-
- def destinationDir(String sourceSetName) {
- return file("build/playBinary/src/routesCompile${StringUtils.capitalize(sourceSetName)}PlayBinary")
- }
-
- def withRoutesSource(TestFile routesFile, String packageId) {
- routesFile.createFile()
- routesFile << """
-# Routes
-# This file defines all application routes (Higher priority routes first)
-# ~~~~
-
-# Home page
-GET / controllers${packageId}.Application.index()
-"""
- withControllerSource(file("app/controllers/${packageId}/Application.scala"), packageId)
- return routesFile
- }
-
- def withControllerSource(TestFile file, String packageId) {
- file.createFile()
- file << """
-package controllers${packageId}
-
-
-import play.api._
-import play.api.mvc._
-import models._
-
-object Application extends Controller {
- def index = Action {
- Ok("Your new application is ready.")
- }
-}
-"""
- }
-
- def withRoutesTemplate(String packageName = "") {
- def routesFile = packageName.isEmpty() ? file("conf", "routes") : file("conf", packageName + ".routes")
- def packageId = packageName.isEmpty() ? "" : ".$packageName"
- withRoutesSource(routesFile, packageId)
- }
-
- def withExtraSourceSets() {
- buildFile << """
- model {
- components {
- play {
- sources {
- extraRoutes(RoutesSourceSet) {
- source.srcDir "extraRoutes"
- }
- otherRoutes(RoutesSourceSet) {
- source.srcDir "otherRoutes"
- }
- }
- }
- }
- }
- """
- }
-
- JarTestFixture jar(String fileName) {
- new JarTestFixture(file(fileName))
- }
-}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlCompileIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlCompileIntegrationTest.groovy
index 746ba38..e73c132 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlCompileIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlCompileIntegrationTest.groovy
@@ -21,7 +21,7 @@ import org.gradle.test.fixtures.archive.JarTestFixture
import org.gradle.util.TextUtil
class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
- def destinationDirPath = "build/playBinary/src/twirlCompileTwirlTemplatesPlayBinary/views/html"
+ def destinationDirPath = "build/playBinary/src/compilePlayBinaryTwirlTemplates/views/html"
def destinationDir = file(destinationDirPath)
def setup() {
@@ -31,11 +31,16 @@ class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
id 'play-application'
}
- repositories{
+ repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
}
@@ -53,21 +58,21 @@ class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
given:
withTwirlTemplate()
when:
- succeeds("twirlCompileTwirlTemplatesPlayBinary")
+ succeeds("compilePlayBinaryTwirlTemplates")
then:
destinationDir.assertHasDescendants("index.template.scala")
when:
- succeeds("twirlCompileTwirlTemplatesPlayBinary")
+ succeeds("compilePlayBinaryTwirlTemplates")
then:
- skipped(":twirlCompileTwirlTemplatesPlayBinary");
+ skipped(":compilePlayBinaryTwirlTemplates");
}
def "runs compiler incrementally"() {
when:
withTwirlTemplate("input1.scala.html")
then:
- succeeds("twirlCompileTwirlTemplatesPlayBinary")
+ succeeds("compilePlayBinaryTwirlTemplates")
and:
destinationDir.assertHasDescendants("input1.template.scala")
def input1FirstCompileSnapshot = file("${destinationDirPath}/input1.template.scala").snapshot();
@@ -75,7 +80,7 @@ class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
when:
withTwirlTemplate("input2.scala.html")
and:
- succeeds("twirlCompileTwirlTemplatesPlayBinary")
+ succeeds("compilePlayBinaryTwirlTemplates")
then:
destinationDir.assertHasDescendants("input1.template.scala", "input2.template.scala")
and:
@@ -84,7 +89,7 @@ class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
when:
file("app/views/input2.scala.html").delete()
then:
- succeeds("twirlCompileTwirlTemplatesPlayBinary")
+ succeeds("compilePlayBinaryTwirlTemplates")
and:
destinationDir.assertHasDescendants("input1.template.scala")
}
@@ -93,7 +98,7 @@ class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
given:
withTwirlTemplate("input1.scala.html")
withTwirlTemplate("input2.scala.html")
- succeeds("twirlCompileTwirlTemplatesPlayBinary")
+ succeeds("compilePlayBinaryTwirlTemplates")
and:
destinationDir.assertHasDescendants("input1.template.scala", "input2.template.scala")
@@ -103,7 +108,7 @@ class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
file("app/views/input2.scala.html").delete()
then:
- succeeds("twirlCompileTwirlTemplatesPlayBinary")
+ succeeds("compilePlayBinaryTwirlTemplates")
and:
destinationDir.assertHasDescendants("input1.template.scala")
file("${destinationDirPath}/input1.template.scala").assertHasNotChangedSince(input1FirstCompileSnapshot);
@@ -121,20 +126,19 @@ class TwirlCompileIntegrationTest extends PlayMultiVersionIntegrationTest {
then:
executedAndNotSkipped(
- ":twirlCompileTwirlTemplatesPlayBinary",
- ":twirlCompileExtraTwirlPlayBinary",
- ":twirlCompileOtherTwirlPlayBinary"
+ ":compilePlayBinaryTwirlTemplates",
+ ":compilePlayBinaryExtraTwirl",
+ ":compilePlayBinaryOtherTwirl"
)
and:
destinationDir.assertHasDescendants("index.template.scala")
- file("build/playBinary/src/twirlCompileOtherTwirlPlayBinary/templates/html").assertHasDescendants("other.template.scala")
- file("build/playBinary/src/twirlCompileExtraTwirlPlayBinary/html").assertHasDescendants("extra.template.scala")
+ file("build/playBinary/src/compilePlayBinaryOtherTwirl/templates/html").assertHasDescendants("other.template.scala")
+ file("build/playBinary/src/compilePlayBinaryExtraTwirl/html").assertHasDescendants("extra.template.scala")
and:
- jar("build/playBinary/lib/twirl-play-app.jar").assertContainsFile("views/html/index.class")
- jar("build/playBinary/lib/twirl-play-app.jar").assertContainsFile("templates/html/other.class")
- jar("build/playBinary/lib/twirl-play-app.jar").assertContainsFile("html/extra.class")
+ jar("build/playBinary/lib/twirl-play-app.jar")
+ .containsDescendants("views/html/index.class", "templates/html/other.class", "html/extra.class")
}
def "extra sources appear in the component report"() {
@@ -154,7 +158,7 @@ Source sets
includes: **/*.java
JVM resources 'play:resources'
srcDir: conf
- Routes source 'play:routesSources'
+ Routes source 'play:routes'
srcDir: conf
includes: routes, *.routes
Scala source 'play:scala'
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlVersionIntegrationTest.groovy b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlVersionIntegrationTest.groovy
index a11cf26..b2cc27c 100644
--- a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlVersionIntegrationTest.groovy
+++ b/subprojects/platform-play/src/integTest/groovy/org/gradle/play/tasks/TwirlVersionIntegrationTest.groovy
@@ -17,6 +17,7 @@
package org.gradle.play.tasks
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.play.internal.DefaultPlayPlatform
class TwirlVersionIntegrationTest extends AbstractIntegrationSpec {
def baseBuildFile = """
@@ -24,11 +25,16 @@ class TwirlVersionIntegrationTest extends AbstractIntegrationSpec {
id 'play-application'
}
- repositories{
+ repositories {
jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
}
}
"""
@@ -45,20 +51,20 @@ class TwirlVersionIntegrationTest extends AbstractIntegrationSpec {
succeeds "playBinary"
then:
- executedAndNotSkipped(":twirlCompileTwirlTemplatesPlayBinary", ":scalaCompilePlayBinary")
+ executedAndNotSkipped(":compilePlayBinaryTwirlTemplates", ":compilePlayBinaryScala")
and:
- file("build/playBinary/src/twirlCompileTwirlTemplatesPlayBinary/views/html/index.template.scala").exists()
+ file("build/playBinary/src/compilePlayBinaryTwirlTemplates/views/html/index.template.scala").exists()
when:
- withPlayVersion("2.3.7")
+ withPlayVersion(DefaultPlayPlatform.DEFAULT_PLAY_VERSION)
succeeds "playBinary"
then:
- executedAndNotSkipped(":twirlCompileTwirlTemplatesPlayBinary", ":scalaCompilePlayBinary")
+ executedAndNotSkipped(":compilePlayBinaryTwirlTemplates", ":compilePlayBinaryScala")
and:
- file("build/playBinary/src/twirlCompileTwirlTemplatesPlayBinary/views/html/index.template.scala").exists()
+ file("build/playBinary/src/compilePlayBinaryTwirlTemplates/views/html/index.template.scala").exists()
}
def "changing between twirl-compatible versions of play does NOT cause Twirl to recompile" () {
@@ -69,18 +75,18 @@ class TwirlVersionIntegrationTest extends AbstractIntegrationSpec {
succeeds "playBinary"
then:
- executedAndNotSkipped(":twirlCompileTwirlTemplatesPlayBinary", ":scalaCompilePlayBinary")
+ executedAndNotSkipped(":compilePlayBinaryTwirlTemplates", ":compilePlayBinaryScala")
and:
- file("build/playBinary/src/twirlCompileTwirlTemplatesPlayBinary/views/html/index.template.scala").exists()
+ file("build/playBinary/src/compilePlayBinaryTwirlTemplates/views/html/index.template.scala").exists()
when:
- withPlayVersion("2.3.7")
+ withPlayVersion(DefaultPlayPlatform.DEFAULT_PLAY_VERSION)
succeeds "playBinary"
then:
- skipped(":twirlCompileTwirlTemplatesPlayBinary")
- executedAndNotSkipped(":scalaCompilePlayBinary")
+ skipped(":compilePlayBinaryTwirlTemplates")
+ executedAndNotSkipped(":compilePlayBinaryScala")
}
def withPlayVersion(String playVersion) {
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/build.gradle b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/build.gradle
deleted file mode 100644
index 1b1f91e..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-plugins {
- id 'play'
- id 'play-coffeescript'
-}
-
-repositories {
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
- maven {
- name = "gradle-js"
- url = "https://repo.gradle.org/gradle/javascript-public"
- }
-}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/build.gradle b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/build.gradle
deleted file mode 100644
index b373f49..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/build.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
-plugins {
- id 'play'
-}
-
-repositories {
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
-}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/ApplicationSpec.scala b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/ApplicationSpec.scala
deleted file mode 100644
index 12e93c1..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/ApplicationSpec.scala
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.specs2.mutable._
-import org.specs2.runner._
-import org.junit.runner._
-import play.api.test._
-import play.api.test.Helpers._
- at RunWith(classOf[JUnitRunner])
-class ApplicationSpec extends Specification {
- "Application" should {
- "send 404 on a bad request" in new WithApplication {
- route(FakeRequest(GET, "/boum")) must beNone
- }
- "render the index page" in new WithApplication {
- val home = route(FakeRequest(GET, "/")).get
- status(home) must equalTo(OK)
- contentType(home) must beSome.which(_ == "text/html")
- contentAsString(home) must contain("Your new application is ready.")
- }
- }
-}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/IntegrationSpec.scala b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/IntegrationSpec.scala
deleted file mode 100644
index ea6c8d9..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/IntegrationSpec.scala
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.specs2.mutable._
-import org.specs2.runner._
-import org.junit.runner._
-import play.api.test._
-import play.api.test.Helpers._
-/**
- * add your integration spec here.
- * An integration test will fire up a whole play appl
- */
- at RunWith(classOf[JUnitRunner])
-class IntegrationSpec extends Specification {
- "Application" should {
- "work from within a browser" in new WithBrowser {
- browser.goTo("http://localhost:" + port)
- browser.pageSource must contain("Your new application is ready.")
- }
- }
-}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/build.gradle b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/build.gradle
deleted file mode 100644
index b36eff1..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-plugins {
- id 'play'
-}
-
-dependencies {
- play "com.google.guava:guava:17.0"
- playTest "commons-lang:commons-lang:2.6"
-}
-
-repositories {
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
-}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/ApplicationSpec.scala b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/ApplicationSpec.scala
deleted file mode 100644
index fb589fc..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/ApplicationSpec.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.specs2.mutable._
-import org.specs2.runner._
-import org.junit.runner._
-import play.api.test._
-import play.api.test.Helpers._
-
- at RunWith(classOf[JUnitRunner])
-class ApplicationSpec extends Specification {
- "Application" should {
- "send 404 on a bad request" in new WithApplication {
- route(FakeRequest(GET, "/boum")) must beNone
- }
- "render the index page" in new WithApplication {
- val home = route(FakeRequest(GET, "/")).get
- status(home) must equalTo(OK)
- contentType(home) must beSome.which(_ == "text/html")
- contentAsString(home) must contain("Your new application is ready.")
- }
- }
-}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/IntegrationSpec.scala b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/IntegrationSpec.scala
deleted file mode 100644
index ff9620b..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/IntegrationSpec.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.specs2.mutable._
-import org.specs2.runner._
-import org.junit.runner._
-import play.api.test._
-import play.api.test.Helpers._
-
-import com.google.common.base.Strings
-import org.apache.commons.lang.StringUtils
-
-/**
- * add your integration spec here.
- * An integration test will fire up a whole play appl
- */
- at RunWith(classOf[JUnitRunner])
-class IntegrationSpec extends Specification {
- "Application" should {
- "work from within a browser" in new WithBrowser {
- browser.goTo("http://localhost:" + port)
- browser.pageSource must contain(StringUtils.strip(Strings.nullToEmpty(" Your new application is ready. ")))
- }
- }
-}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/build.gradle b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/build.gradle
deleted file mode 100644
index d54c456..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/build.gradle
+++ /dev/null
@@ -1,9 +0,0 @@
-allprojects {
- repositories{
- jcenter()
- maven{
- name = "typesafe-maven-release"
- url = "https://repo.typesafe.com/typesafe/maven-releases"
- }
- }
-}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingApplicationSpec.scala b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingApplicationSpec.scala
deleted file mode 100644
index 2ec43ec..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingApplicationSpec.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.junit.Ignore
-import org.specs2.mutable._
-import org.specs2.runner._
-import org.junit.runner._
-import play.api.test._
-import play.api.test.Helpers._
- at RunWith(classOf[JUnitRunner])
-class FailingApplicationSpec extends Specification {
- "Application" should {
- "send 404 on a bad request" in new WithApplication{
- route(FakeRequest(GET, "/boum")) must beNone
- }
- "render the index page" in new WithApplication{
- val home = route(FakeRequest(GET, "/")).get
- status(home) must equalTo(OK)
- contentType(home) must beSome.which(_ == "text/html")
- contentAsString(home) must contain ("This application content is wrong")
- }
- }
-}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingIntegrationSpec.scala b/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingIntegrationSpec.scala
deleted file mode 100644
index ee5c864..0000000
--- a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingIntegrationSpec.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.specs2.mutable._
-import org.specs2.runner._
-import org.junit.runner._
-
-import play.api.test._
-import play.api.test.Helpers._
-
- at RunWith(classOf[JUnitRunner])
-class FailingIntegrationSpec extends Specification {
-
- "Application" should {
-
- "work from within a browser" in new WithBrowser {
-
- browser.goTo("http://localhost:" + port)
-
- browser.pageSource must contain("This application content is wrong.")
- }
- }
-}
\ No newline at end of file
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/JvmClasses.java b/subprojects/platform-play/src/main/java/org/gradle/play/JvmClasses.java
index 014d840..8f58326 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/JvmClasses.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/JvmClasses.java
@@ -26,7 +26,6 @@ import java.util.Set;
* A set of classes and resources that operate together.
*/
@Incubating
-// TODO:DAZ Move this to platform-jvm
public interface JvmClasses extends BuildableModelElement {
/**
* The classes directory for this binary.
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationBinarySpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationBinarySpec.java
index 904f82b..0f47aa0 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationBinarySpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationBinarySpec.java
@@ -23,26 +23,49 @@ import org.gradle.language.javascript.JavaScriptSourceSet;
import org.gradle.language.scala.ScalaLanguageSourceSet;
import org.gradle.platform.base.BinarySpec;
import org.gradle.play.platform.PlayPlatform;
+import org.gradle.play.toolchain.PlayToolChain;
import java.io.File;
import java.util.Map;
/**
- * Represents a binary artifact that is the result of building a play component.
+ * Represents a binary artifact that is the result of building a Play application software component.
*/
@Incubating
@HasInternalProtocol
public interface PlayApplicationBinarySpec extends BinarySpec {
PlayApplicationSpec getApplication();
+ /**
+ * The PlayPlatform this binary is built for.
+ * @return platform for this binary
+ */
PlayPlatform getTargetPlatform();
+ PlayToolChain getToolChain();
+
+ /**
+ * The application jar file produced for this binary.
+ * @return the application jar file
+ */
File getJarFile();
+ /**
+ * The assets jar file produced for this binary.
+ * @return the assets jar file
+ */
File getAssetsJarFile();
+ /**
+ * A buildable object representing the class files and resources that will be included in the application jar file.
+ * @return the JvmClasses for this binary
+ */
JvmClasses getClasses();
+ /**
+ * A buildable object representing the public assets that will be included in the assets jar file.
+ * @return the PublicAssets for this binary
+ */
PublicAssets getAssets();
Map<LanguageSourceSet, ScalaLanguageSourceSet> getGeneratedScala();
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationSpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationSpec.java
index a7a101e..a48453a 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationSpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/PlayApplicationSpec.java
@@ -21,10 +21,54 @@ import org.gradle.internal.HasInternalProtocol;
import org.gradle.platform.base.PlatformAwareComponentSpec;
/**
- * Definition of a play framework software component that is built by Gradle.
+ * Definition of a Play Framework software component that is built by Gradle.
*/
@Incubating @HasInternalProtocol
public interface PlayApplicationSpec extends PlatformAwareComponentSpec {
+ /**
+ * Specifies a {@link org.gradle.play.platform.PlayPlatform} with a given set of requirements that this
+ * component should be built be for. Can accept a map of play, scala and/or java requirements or a string
+ * representation of the desired play platform.
+ * <pre>
+ * model {
+ * components {
+ * play {
+ * platform 'play-2.3.9'
+ * platform play: '2.3.2'
+ * platform play: '2.3.6', scala: '2.10'
+ * platform play: '2.3.7', scala: '2.11', java: '1.8'
+ * }
+ * }
+ * }
+ * </pre>
+ * @param platformRequirements Map of Play requirements or the name of an Play platform.
+ */
void platform(Object platformRequirements);
+
+ /**
+ * Configures the style of router to use with this application.
+ *
+ * <p>
+ * By default, a static routes generator is used to generate a singleton router. This requires that all the actions
+ * that the router invokes on the application's controllers are either Scala singleton objects, or Java static methods.
+ * </p>
+ *
+ * <p>
+ * In Play 2.4+, a injected routes generator is recommended. This requires that the router declares its
+ * dependencies to the application's controllers in its constructor. The controllers methods need to be instance methods.
+ * </p>
+ *
+ * @param injectedRoutesGenerator false if a static router should be generated (default).
+ * true if an injected router should be generated.
+ */
+ void setInjectedRoutesGenerator(boolean injectedRoutesGenerator);
+
+ /**
+ * Will an injected router be generated for this application?
+ *
+ * @return false if a static router will be generated for the application,
+ * true if an injected router will be generated.
+ */
+ boolean getInjectedRoutesGenerator();
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/distribution/PlayDistribution.java b/subprojects/platform-play/src/main/java/org/gradle/play/distribution/PlayDistribution.java
index 13383d3..ad23983 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/distribution/PlayDistribution.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/distribution/PlayDistribution.java
@@ -25,5 +25,9 @@ import org.gradle.play.PlayApplicationBinarySpec;
*/
@Incubating
public interface PlayDistribution extends Distribution {
+ /**
+ * The binary this distribution is associated with
+ * @return the binary
+ */
PlayApplicationBinarySpec getBinary();
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationBinarySpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationBinarySpec.java
index 48c4f69..56e493c 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationBinarySpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationBinarySpec.java
@@ -26,10 +26,10 @@ import org.gradle.language.scala.ScalaLanguageSourceSet;
import org.gradle.platform.base.binary.BaseBinarySpec;
import org.gradle.platform.base.internal.BinaryBuildAbility;
import org.gradle.platform.base.internal.ToolSearchBuildAbility;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import org.gradle.play.JvmClasses;
import org.gradle.play.PlayApplicationSpec;
import org.gradle.play.PublicAssets;
+import org.gradle.play.internal.toolchain.PlayToolChainInternal;
import org.gradle.play.platform.PlayPlatform;
import java.io.File;
@@ -42,10 +42,10 @@ public class DefaultPlayApplicationBinarySpec extends BaseBinarySpec implements
private Map<LanguageSourceSet, ScalaLanguageSourceSet> generatedScala = Maps.newHashMap();
private Map<LanguageSourceSet, JavaScriptSourceSet> generatedJavaScript = Maps.newHashMap();
private PlayPlatform platform;
+ private PlayToolChainInternal toolChain;
private File jarFile;
private File assetsJarFile;
private FileCollection classpath;
- private ToolResolver toolResolver;
private PlayApplicationSpec application;
@Override
@@ -67,6 +67,10 @@ public class DefaultPlayApplicationBinarySpec extends BaseBinarySpec implements
return platform;
}
+ public PlayToolChainInternal getToolChain() {
+ return toolChain;
+ }
+
public File getJarFile() {
return jarFile;
}
@@ -75,6 +79,10 @@ public class DefaultPlayApplicationBinarySpec extends BaseBinarySpec implements
this.platform = platform;
}
+ public void setToolChain(PlayToolChainInternal toolChain) {
+ this.toolChain = toolChain;
+ }
+
public void setJarFile(File file) {
this.jarFile = file;
}
@@ -117,17 +125,7 @@ public class DefaultPlayApplicationBinarySpec extends BaseBinarySpec implements
@Override
public BinaryBuildAbility getBinaryBuildAbility() {
- return new ToolSearchBuildAbility(toolResolver.checkToolAvailability(getTargetPlatform()));
- }
-
- @Override
- public void setToolResolver(ToolResolver toolResolver) {
- this.toolResolver = toolResolver;
- }
-
- @Override
- public ToolResolver getToolResolver() {
- return toolResolver;
+ return new ToolSearchBuildAbility(getToolChain().select(getTargetPlatform()));
}
private static class DefaultJvmClasses extends AbstractBuildableModelElement implements JvmClasses {
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationSpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationSpec.java
index 7dc5f37..f72ee9e 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationSpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayApplicationSpec.java
@@ -26,6 +26,7 @@ import java.util.List;
public class DefaultPlayApplicationSpec extends BaseComponentSpec implements PlayApplicationSpecInternal {
private final List<PlatformRequirement> targetPlatforms = Lists.newArrayList();
+ private boolean injectedRoutesGenerator;
protected String getTypeName() {
return "Play Application";
@@ -44,4 +45,14 @@ public class DefaultPlayApplicationSpec extends BaseComponentSpec implements Pla
PlatformRequirement requirement = PlayPlatformNotationParser.parser().parseNotation(platformRequirements);
this.targetPlatforms.add(requirement);
}
+
+ @Override
+ public void setInjectedRoutesGenerator(boolean injectedRoutesGenerator) {
+ this.injectedRoutesGenerator = injectedRoutesGenerator;
+ }
+
+ @Override
+ public boolean getInjectedRoutesGenerator() {
+ return injectedRoutesGenerator;
+ }
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayPlatform.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayPlatform.java
index aef5080..8ede624 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayPlatform.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/DefaultPlayPlatform.java
@@ -20,6 +20,7 @@ import org.gradle.language.scala.ScalaPlatform;
import org.gradle.play.internal.platform.PlayPlatformInternal;
public class DefaultPlayPlatform implements PlayPlatformInternal {
+ public final static String DEFAULT_PLAY_VERSION = "2.3.9";
private final String playVersion;
private final ScalaPlatform scalaPlatform;
private final JavaPlatform javaPlatform;
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayApplicationBinarySpecInternal.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayApplicationBinarySpecInternal.java
index 6e81d19..d343bf3 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayApplicationBinarySpecInternal.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayApplicationBinarySpecInternal.java
@@ -18,9 +18,9 @@ package org.gradle.play.internal;
import org.gradle.api.file.FileCollection;
import org.gradle.platform.base.internal.BinarySpecInternal;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import org.gradle.play.PlayApplicationBinarySpec;
import org.gradle.play.PlayApplicationSpec;
+import org.gradle.play.internal.toolchain.PlayToolChainInternal;
import org.gradle.play.platform.PlayPlatform;
import java.io.File;
@@ -30,16 +30,14 @@ public interface PlayApplicationBinarySpecInternal extends PlayApplicationBinary
void setTargetPlatform(PlayPlatform platform);
- void setToolResolver(ToolResolver toolResolver);
+ void setToolChain(PlayToolChainInternal toolChain);
- ToolResolver getToolResolver();
+ PlayToolChainInternal getToolChain();
void setJarFile(File file);
void setAssetsJarFile(File file);
- // TODO:DAZ Should be taken from the LanguageSourceSet instances?
- // TODO:DAZ Should be a Classpath instance
FileCollection getClasspath();
void setClasspath(FileCollection applicationClasspath);
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformNotationParser.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformNotationParser.java
index e3e1b8a..2167e69 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformNotationParser.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformNotationParser.java
@@ -22,7 +22,6 @@ import org.gradle.internal.typeconversion.*;
import org.gradle.platform.base.internal.DefaultPlatformRequirement;
import org.gradle.platform.base.internal.PlatformRequirement;
-// TODO:DAZ Unit test
public class PlayPlatformNotationParser {
private static final NotationParserBuilder<PlatformRequirement> BUILDER = NotationParserBuilder
@@ -42,7 +41,7 @@ public class PlayPlatformNotationParser {
static class MapConverter extends MapNotationConverter<PlatformRequirement> {
@Override
public void describe(DiagnosticsVisitor visitor) {
- visitor.candidate("Map defining the platform versions").example("[play: '2.3.7', scala:'2.11.4', java: '1.6']");
+ visitor.candidate("Map defining the platform versions").example("[play: '" + DefaultPlayPlatform.DEFAULT_PLAY_VERSION + "', scala:'2.11.4', java: '1.6']");
}
protected PlatformRequirement parseMap(@MapKey("play") String playVersion,
@@ -55,11 +54,11 @@ public class PlayPlatformNotationParser {
static class StringConverter implements NotationConverter<String, PlatformRequirement> {
@Override
public void describe(DiagnosticsVisitor visitor) {
- visitor.candidate("The name of a Play platform").example("'play-2.3.7'.");
+ visitor.candidate("The name of a Play platform").example("'play-" + DefaultPlayPlatform.DEFAULT_PLAY_VERSION + "'.");
}
public void convert(String notation, NotationConvertResult<? super PlatformRequirement> result) throws TypeConversionException {
result.converted(new DefaultPlatformRequirement(notation));
}
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformResolver.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformResolver.java
index c4bc719..4a1aeaa 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformResolver.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlayPlatformResolver.java
@@ -27,7 +27,7 @@ import org.gradle.play.internal.platform.PlayMajorVersion;
import org.gradle.play.platform.PlayPlatform;
import org.gradle.util.GUtil;
-// TODO:DAZ Resolve the JavaPlatform and ScalaPlatform, rather than instantiating directly
+// TODO Resolve the JavaPlatform and ScalaPlatform from their PlatformResolvers, rather than instantiating directly
public class PlayPlatformResolver implements PlatformResolver<PlayPlatform> {
@Override
public Class<PlayPlatform> getType() {
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlaySourceSetRules.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlaySourceSetRules.java
new file mode 100644
index 0000000..a142e3a
--- /dev/null
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/PlaySourceSetRules.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.internal;
+
+import org.gradle.api.Action;
+import org.gradle.language.java.JavaSourceSet;
+import org.gradle.language.jvm.JvmResourceSet;
+import org.gradle.language.routes.RoutesSourceSet;
+import org.gradle.language.scala.ScalaLanguageSourceSet;
+import org.gradle.language.twirl.TwirlSourceSet;
+import org.gradle.model.Defaults;
+import org.gradle.model.RuleSource;
+import org.gradle.play.PlayApplicationSpec;
+
+public class PlaySourceSetRules extends RuleSource {
+
+ @Defaults
+ void createJvmSourceSets(PlayApplicationSpec playComponent) {
+ playComponent.getSources().create("scala", ScalaLanguageSourceSet.class, new Action<ScalaLanguageSourceSet>() {
+ @Override
+ public void execute(ScalaLanguageSourceSet scalaSources) {
+ scalaSources.getSource().srcDir("app");
+ scalaSources.getSource().include("**/*.scala");
+ }
+ });
+
+ playComponent.getSources().create("java", JavaSourceSet.class, new Action<JavaSourceSet>() {
+ @Override
+ public void execute(JavaSourceSet javaSources) {
+ javaSources.getSource().srcDir("app");
+ javaSources.getSource().include("**/*.java");
+ }
+ });
+
+ playComponent.getSources().create("resources", JvmResourceSet.class, new Action<JvmResourceSet>() {
+ @Override
+ public void execute(JvmResourceSet appResources) {
+ appResources.getSource().srcDirs("conf");
+ }
+ });
+ }
+
+ @Defaults
+ void createTwirlSourceSets(PlayApplicationSpec playComponent) {
+ playComponent.getSources().create("twirlTemplates", TwirlSourceSet.class, new Action<TwirlSourceSet>() {
+ @Override
+ public void execute(TwirlSourceSet twirlSourceSet) {
+ twirlSourceSet.getSource().srcDir("app");
+ twirlSourceSet.getSource().include("**/*.html");
+ }
+ });
+ }
+
+ @Defaults
+ void createRoutesSourceSets(PlayApplicationSpec playComponent) {
+ playComponent.getSources().create("routes", RoutesSourceSet.class, new Action<RoutesSourceSet>() {
+ @Override
+ public void execute(RoutesSourceSet routesSourceSet) {
+ routesSourceSet.getSource().srcDir("conf");
+ routesSourceSet.getSource().include("routes");
+ routesSourceSet.getSource().include("*.routes");
+ }
+ });
+ }
+}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/platform/PlayMajorVersion.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/platform/PlayMajorVersion.java
index 72d2450..359a081 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/platform/PlayMajorVersion.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/platform/PlayMajorVersion.java
@@ -26,7 +26,8 @@ import java.util.List;
public enum PlayMajorVersion {
PLAY_2_2_X("2.2.x", "2.10"),
- PLAY_2_3_X("2.3.x", "2.11", "2.10");
+ PLAY_2_3_X("2.3.x", "2.11", "2.10"),
+ PLAY_2_4_X("2.4.x", "2.11", "2.10");
private final String name;
private final List<String> compatibleScalaVersions;
@@ -61,7 +62,10 @@ public enum PlayMajorVersion {
if (versionNumber.getMajor() == 2 && versionNumber.getMinor() == 3) {
return PlayMajorVersion.PLAY_2_3_X;
}
- throw new InvalidUserDataException(String.format("Not a supported Play version: %s. This plugin is compatible with: [2.3.x, 2.2.x].", playVersion));
+ if (versionNumber.getMajor() == 2 && versionNumber.getMinor() == 4) {
+ return PlayMajorVersion.PLAY_2_4_X;
+ }
+ throw new InvalidUserDataException(String.format("Not a supported Play version: %s. This plugin is compatible with: [2.4.x, 2.3.x, 2.2.x].", playVersion));
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultRoutesCompileSpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultRoutesCompileSpec.java
index 6739237..72f79f9 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultRoutesCompileSpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultRoutesCompileSpec.java
@@ -19,18 +19,27 @@ package org.gradle.play.internal.routes;
import org.gradle.api.tasks.compile.BaseForkOptions;
import java.io.File;
+import java.util.Collection;
public class DefaultRoutesCompileSpec implements RoutesCompileSpec {
private final Iterable<File> sourceFiles;
private final File outputDirectory;
private final BaseForkOptions forkOptions;
private final boolean javaProject;
+ private final boolean namespaceReverseRouter;
+ private final boolean generateReverseRoutes;
+ private final boolean injectedRoutesGenerator;
+ private final Collection<String> additionalImports;
- public DefaultRoutesCompileSpec(Iterable<File> sourceFiles, File outputDirectory, BaseForkOptions forkOptions, boolean javaProject) {
+ public DefaultRoutesCompileSpec(Iterable<File> sourceFiles, File outputDirectory, BaseForkOptions forkOptions, boolean javaProject, boolean namespaceReverseRouter, boolean generateReverseRoutes, boolean injectedRoutesGenerator, Collection<String> additionalImports) {
this.sourceFiles = sourceFiles;
this.outputDirectory = outputDirectory;
this.forkOptions = forkOptions;
this.javaProject = javaProject;
+ this.namespaceReverseRouter = namespaceReverseRouter;
+ this.generateReverseRoutes = generateReverseRoutes;
+ this.injectedRoutesGenerator = injectedRoutesGenerator;
+ this.additionalImports = additionalImports;
}
public Iterable<File> getSources() {
@@ -48,4 +57,22 @@ public class DefaultRoutesCompileSpec implements RoutesCompileSpec {
public boolean isJavaProject() {
return javaProject;
}
+
+ public boolean isNamespaceReverseRouter() {
+ return namespaceReverseRouter;
+ }
+
+ public boolean isGenerateReverseRoutes() {
+ return generateReverseRoutes;
+ }
+
+ @Override
+ public boolean isInjectedRoutesGenerator() {
+ return injectedRoutesGenerator;
+ }
+
+ @Override
+ public Collection<String> getAdditionalImports() {
+ return additionalImports;
+ }
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultVersionedRoutesCompilerAdapter.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultVersionedRoutesCompilerAdapter.java
index 9ed498e..4a67569 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultVersionedRoutesCompilerAdapter.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/DefaultVersionedRoutesCompilerAdapter.java
@@ -28,23 +28,15 @@ abstract class DefaultVersionedRoutesCompilerAdapter implements VersionedRoutesC
this.scalaVersion = scalaVersion;
}
- protected boolean isGenerateReverseRoute() {
- return true;
- }
-
- protected boolean isNamespaceReverseRouter() {
- return false;
- }
-
protected boolean isGenerateRefReverseRouter() {
return false;
}
- public Object getDependencyNotation() {
+ public String getDependencyNotation() {
return String.format("com.typesafe.play:routes-compiler_%s:%s", scalaVersion, playVersion);
}
public List<String> getClassLoaderPackages() {
- return Arrays.asList("play.router", "scala.collection", "scala.collection.mutable", "scala.util.matching");
+ return Arrays.asList("play.router", "scala.collection", "scala.collection.mutable", "scala.util.matching", "play.routes.compiler");
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompileSpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompileSpec.java
index bbef556..875032b 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompileSpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompileSpec.java
@@ -20,9 +20,18 @@ import org.gradle.play.internal.spec.PlayCompileSpec;
import java.io.File;
import java.io.Serializable;
+import java.util.Collection;
public interface RoutesCompileSpec extends PlayCompileSpec, Serializable {
Iterable<File> getSources();
boolean isJavaProject();
+
+ boolean isNamespaceReverseRouter();
+
+ boolean isGenerateReverseRoutes();
+
+ boolean isInjectedRoutesGenerator();
+
+ Collection<String> getAdditionalImports();
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompiler.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompiler.java
index c44d676..ad1cba4 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompiler.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompiler.java
@@ -67,7 +67,7 @@ public class RoutesCompiler implements Compiler<RoutesCompileSpec>, Serializable
try {
ClassLoader cl = getClass().getClassLoader();
ScalaMethod compile = adapter.getCompileMethod(cl);
- Object ret = compile.invoke(adapter.createCompileParameters(cl, sourceFile, spec.getDestinationDir(), spec.isJavaProject()));
+ Object ret = compile.invoke(adapter.createCompileParameters(cl, sourceFile, spec.getDestinationDir(), spec.isJavaProject(), spec.isNamespaceReverseRouter(), spec.isGenerateReverseRoutes(), spec.isInjectedRoutesGenerator(), spec.getAdditionalImports()));
if (ret != null && ret instanceof Boolean) {
return (Boolean) ret;
} else {
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV22X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV22X.java
index 56eea89..d1abe55 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV22X.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV22X.java
@@ -23,6 +23,7 @@ import org.gradle.scala.internal.reflect.ScalaReflectionUtil;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
import java.util.List;
class RoutesCompilerAdapterV22X extends DefaultVersionedRoutesCompilerAdapter {
@@ -47,13 +48,15 @@ class RoutesCompilerAdapterV22X extends DefaultVersionedRoutesCompilerAdapter {
);
}
- public Object[] createCompileParameters(ClassLoader cl, File file, File destinationDir, boolean javaProject) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ public Object[] createCompileParameters(ClassLoader cl, File file, File destinationDir, boolean javaProject, boolean namespaceReverseRouter, boolean generateReverseRoutes, boolean injectedRoutesGenerator, Collection<String> additionalImports) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ List<String> defaultImports = javaProject ? defaultJavaImports : defaultScalaImports;
+ defaultImports.addAll(additionalImports);
return new Object[] {
file,
destinationDir,
- ScalaListBuffer.fromList(cl, javaProject ? defaultJavaImports : defaultScalaImports),
- isGenerateReverseRoute(),
- isNamespaceReverseRouter()
+ ScalaListBuffer.fromList(cl, defaultImports),
+ generateReverseRoutes,
+ namespaceReverseRouter
};
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV23X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV23X.java
index 2ceef47..68d7f49 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV23X.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV23X.java
@@ -23,6 +23,7 @@ import org.gradle.scala.internal.reflect.ScalaReflectionUtil;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
import java.util.List;
class RoutesCompilerAdapterV23X extends DefaultVersionedRoutesCompilerAdapter {
@@ -49,14 +50,16 @@ class RoutesCompilerAdapterV23X extends DefaultVersionedRoutesCompilerAdapter {
}
@Override
- public Object[] createCompileParameters(ClassLoader cl, File file, File destinationDir, boolean javaProject) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ public Object[] createCompileParameters(ClassLoader cl, File file, File destinationDir, boolean javaProject, boolean namespaceReverseRouter, boolean generateReverseRoutes, boolean injectedRoutesGenerator, Collection<String> additionalImports) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ List<String> defaultImports = javaProject ? defaultJavaImports : defaultScalaImports;
+ defaultImports.addAll(additionalImports);
return new Object[] {
file,
destinationDir,
- ScalaListBuffer.fromList(cl, javaProject ? defaultJavaImports : defaultScalaImports),
- isGenerateReverseRoute(),
+ ScalaListBuffer.fromList(cl, defaultImports),
+ generateReverseRoutes,
isGenerateRefReverseRouter(),
- isNamespaceReverseRouter()
+ namespaceReverseRouter
};
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV24X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV24X.java
new file mode 100644
index 0000000..36ae5cb
--- /dev/null
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerAdapterV24X.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.internal.routes;
+
+import com.google.common.collect.Lists;
+import org.gradle.internal.reflect.DirectInstantiator;
+import org.gradle.scala.internal.reflect.ScalaListBuffer;
+import org.gradle.scala.internal.reflect.ScalaMethod;
+import org.gradle.scala.internal.reflect.ScalaObject;
+import org.gradle.scala.internal.reflect.ScalaReflectionUtil;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.List;
+
+public class RoutesCompilerAdapterV24X extends DefaultVersionedRoutesCompilerAdapter {
+ private static final String PLAY_ROUTES_COMPILER_STATIC_ROUTES_GENERATOR = "play.routes.compiler.StaticRoutesGenerator";
+ private static final String PLAY_ROUTES_COMPILER_INJECTED_ROUTES_GENERATOR = "play.routes.compiler.InjectedRoutesGenerator";
+
+ private final List<String> defaultScalaImports = Lists.newArrayList("controllers.Assets.Asset");
+ private final List<String> defaultJavaImports = Lists.newArrayList("controllers.Assets.Asset", "play.libs.F");
+
+ public RoutesCompilerAdapterV24X(String playVersion) {
+ // No 2.11 version of routes compiler published
+ super(playVersion, "2.10");
+ }
+
+ public ScalaMethod getCompileMethod(ClassLoader cl) throws ClassNotFoundException {
+ return ScalaReflectionUtil.scalaMethod(
+ cl,
+ "play.routes.compiler.RoutesCompiler",
+ "compile",
+ cl.loadClass("play.routes.compiler.RoutesCompiler$RoutesCompilerTask"),
+ cl.loadClass("play.routes.compiler.RoutesGenerator"),
+ File.class
+ );
+ }
+
+ @Override
+ public Object[] createCompileParameters(ClassLoader cl, File file, File destinationDir, boolean javaProject, boolean namespaceReverseRouter, boolean generateReverseRoutes, boolean injectedRoutesGenerator, Collection<String> additionalImports) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+ List<String> defaultImports = javaProject ? defaultJavaImports : defaultScalaImports;
+ defaultImports.addAll(additionalImports);
+
+ Object routesCompilerTask = DirectInstantiator.instantiate(cl.loadClass("play.routes.compiler.RoutesCompiler$RoutesCompilerTask"),
+ file,
+ ScalaListBuffer.fromList(cl, defaultImports),
+ isGenerateForwardsRouter(),
+ generateReverseRoutes,
+ namespaceReverseRouter
+ );
+
+ String routeGenerator;
+ if (injectedRoutesGenerator) {
+ routeGenerator = PLAY_ROUTES_COMPILER_INJECTED_ROUTES_GENERATOR;
+ } else {
+ routeGenerator = PLAY_ROUTES_COMPILER_STATIC_ROUTES_GENERATOR;
+ }
+ return new Object[]{
+ routesCompilerTask,
+ new ScalaObject(cl, routeGenerator).getInstance(),
+ destinationDir
+ };
+ }
+
+ protected boolean isGenerateForwardsRouter() {
+ return true;
+ }
+}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerFactory.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerFactory.java
index f9aff39..85caaea 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerFactory.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/RoutesCompilerFactory.java
@@ -31,6 +31,8 @@ public class RoutesCompilerFactory {
return new RoutesCompilerAdapterV22X(playVersion);
case PLAY_2_3_X:
return new RoutesCompilerAdapterV23X(playVersion);
+ case PLAY_2_4_X:
+ return new RoutesCompilerAdapterV24X(playVersion);
default:
throw new RuntimeException("Could not create routes compile spec for Play version: " + playVersion);
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/VersionedRoutesCompilerAdapter.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/VersionedRoutesCompilerAdapter.java
index b3b1d1e..5f813ab 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/VersionedRoutesCompilerAdapter.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/routes/VersionedRoutesCompilerAdapter.java
@@ -21,14 +21,15 @@ import org.gradle.scala.internal.reflect.ScalaMethod;
import java.io.File;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
import java.util.List;
public interface VersionedRoutesCompilerAdapter extends Serializable {
- Object getDependencyNotation();
+ String getDependencyNotation();
ScalaMethod getCompileMethod(ClassLoader cl) throws ClassNotFoundException;
- Object[] createCompileParameters(ClassLoader cl, File file, File destinationDir, boolean javaProject) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException;
+ Object[] createCompileParameters(ClassLoader cl, File file, File destinationDir, boolean javaProject, boolean namespaceReverseRouter, boolean generateReverseRoutes, boolean injectedRoutesGenerator, Collection<String> additionalImports) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException;
List<String> getClassLoaderPackages();
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultPlayRunSpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultPlayRunSpec.java
index 414c0e3..c474af0 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultPlayRunSpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultPlayRunSpec.java
@@ -17,20 +17,28 @@
package org.gradle.play.internal.run;
import com.google.common.collect.Sets;
-import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.compile.BaseForkOptions;
import java.io.File;
import java.io.Serializable;
+import java.util.Collections;
public class DefaultPlayRunSpec implements PlayRunSpec, Serializable {
private final Iterable<File> classpath;
+ private final Iterable<File> changingClasspath;
+ private final File applicationJar;
+ private final File assetsJar;
+ private final Iterable<File> assetsDirs;
private final File projectPath;
private BaseForkOptions forkOptions;
private int httpPort;
- public DefaultPlayRunSpec(FileCollection classpath, File projectPath, BaseForkOptions forkOptions, int httpPort) {
+ public DefaultPlayRunSpec(Iterable<File> classpath, Iterable<File> changingClasspath, File applicationJar, File assetsJar, Iterable<File> assetsDirs, File projectPath, BaseForkOptions forkOptions, int httpPort) {
this.classpath = Sets.newHashSet(classpath);
+ this.changingClasspath = changingClasspath != null ? Sets.newHashSet(changingClasspath) : Collections.<File>emptySet();
+ this.applicationJar = applicationJar;
+ this.assetsJar = assetsJar;
+ this.assetsDirs = assetsDirs;
this.projectPath = projectPath;
this.forkOptions = forkOptions;
this.httpPort = httpPort;
@@ -44,6 +52,10 @@ public class DefaultPlayRunSpec implements PlayRunSpec, Serializable {
return classpath;
}
+ public Iterable<File> getChangingClasspath() {
+ return changingClasspath;
+ }
+
public File getProjectPath() {
return projectPath;
}
@@ -51,4 +63,16 @@ public class DefaultPlayRunSpec implements PlayRunSpec, Serializable {
public int getHttpPort() {
return httpPort;
}
+
+ public File getApplicationJar() {
+ return applicationJar;
+ }
+
+ public File getAssetsJar() {
+ return assetsJar;
+ }
+
+ public Iterable<File> getAssetsDirs() {
+ return assetsDirs;
+ }
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultVersionedPlayRunAdapter.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultVersionedPlayRunAdapter.java
index ddf25fd..bd385c7 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultVersionedPlayRunAdapter.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/DefaultVersionedPlayRunAdapter.java
@@ -16,45 +16,84 @@
package org.gradle.play.internal.run;
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.logging.Logger;
+import org.gradle.api.logging.Logging;
+import org.gradle.internal.Cast;
import org.gradle.internal.UncheckedException;
+import org.gradle.internal.classpath.ClassPath;
import org.gradle.internal.classpath.DefaultClassPath;
+import org.gradle.internal.reflect.DirectInstantiator;
import org.gradle.scala.internal.reflect.ScalaMethod;
import org.gradle.scala.internal.reflect.ScalaReflectionUtil;
+import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
+import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.jar.JarFile;
public abstract class DefaultVersionedPlayRunAdapter implements VersionedPlayRunAdapter, Serializable {
+ public static final String PLAY_EXCEPTION_CLASSNAME = "play.api.PlayException";
+ private static final Logger LOGGER = Logging.getLogger(DefaultVersionedPlayRunAdapter.class);
+
+ private final AtomicBoolean reload = new AtomicBoolean();
+ private final AtomicReference<ClassLoader> currentClassloader = new AtomicReference<ClassLoader>();
+ private final Queue<SoftReference<Closeable>> loadersToClose = new ConcurrentLinkedQueue<SoftReference<Closeable>>();
+ private volatile Throwable buildFailure;
+
protected abstract Class<?> getBuildLinkClass(ClassLoader classLoader) throws ClassNotFoundException;
protected abstract Class<?> getDocHandlerFactoryClass(ClassLoader classLoader) throws ClassNotFoundException;
protected abstract Class<?> getBuildDocHandlerClass(ClassLoader docsClassLoader) throws ClassNotFoundException;
- public Object getBuildLink(ClassLoader classLoader, final File projectPath, final Iterable<File> classpath) throws ClassNotFoundException {
+ public Object getBuildLink(final ClassLoader classLoader, final File projectPath, final File applicationJar, final Iterable<File> changingClasspath, final File assetsJar, final Iterable<File> assetsDirs) throws ClassNotFoundException {
+ final ClassLoader assetsClassLoader = createAssetsClassLoader(assetsJar, assetsDirs, classLoader);
+ final Class<? extends Throwable> playExceptionClass = Cast.uncheckedCast(classLoader.loadClass(PLAY_EXCEPTION_CLASSNAME));
+ reload();
return Proxy.newProxyInstance(classLoader, new Class<?>[]{getBuildLinkClass(classLoader)}, new InvocationHandler() {
- private volatile boolean shouldReloadNextTime = true;
-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("projectPath")) {
return projectPath;
} else if (method.getName().equals("reload")) {
- if (shouldReloadNextTime) {
- shouldReloadNextTime = false; //reload only once for now
- DefaultClassPath projectClasspath = new DefaultClassPath(classpath);
- return new URLClassLoader(projectClasspath.getAsURLs().toArray(new URL[]{}), Thread.currentThread().getContextClassLoader());
+
+ // We can't close replaced loaders immediately, because their classes may be used during shutdown,
+ // after the return of the reload() call that caused the loader to be swapped out.
+ // We have no way of knowing when the loader is actually done with, so we use the request after the request
+ // that triggered the reload as the trigger point to close the replaced loader.
+ closeOldLoaders();
+ if (reload.getAndSet(false)) {
+ ClassPath classpath = new DefaultClassPath(applicationJar).plus(new DefaultClassPath(changingClasspath));
+ URLClassLoader currentClassLoader = new URLClassLoader(classpath.getAsURLArray(), assetsClassLoader);
+ storeClassLoader(currentClassLoader);
+ return currentClassLoader;
} else {
- return null;
+ Throwable failure = buildFailure;
+ if (failure == null) {
+ return null;
+ } else {
+ try {
+ return DirectInstantiator.instantiate(playExceptionClass, "Gradle Build Failure", failure.getMessage(), failure);
+ } catch (Exception e) {
+ LOGGER.warn("Could not translate " + failure + " to " + PLAY_EXCEPTION_CLASSNAME, e);
+ return failure;
+ }
+ }
}
} else if (method.getName().equals("settings")) {
return new HashMap<String, String>();
@@ -65,6 +104,51 @@ public abstract class DefaultVersionedPlayRunAdapter implements VersionedPlayRun
});
}
+ protected ClassLoader createAssetsClassLoader(File assetsJar, Iterable<File> assetsDirs, ClassLoader classLoader) {
+ try {
+ return new URLClassLoader(new URL[]{assetsJar.toURI().toURL()}, classLoader);
+ } catch (MalformedURLException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+
+ private ClassLoader storeClassLoader(ClassLoader classLoader) {
+ final ClassLoader previous = currentClassloader.getAndSet(classLoader);
+ if (previous != null && previous instanceof Closeable) {
+ loadersToClose.add(new SoftReference<Closeable>(Cast.cast(Closeable.class, previous)));
+ }
+ return classLoader;
+ }
+
+ private void closeOldLoaders() throws IOException {
+ SoftReference<Closeable> ref = loadersToClose.poll();
+ while (ref != null) {
+ Closeable closeable = ref.get();
+ if (closeable != null) {
+ closeable.close();
+ }
+ ref.clear();
+ ref = loadersToClose.poll();
+ }
+ }
+
+
+ @Override
+ public void reload() {
+ reload.set(true);
+ buildFailure = null;
+ }
+
+ @Override
+ public void buildError(Throwable throwable) {
+ buildFailure = throwable;
+ }
+
+ @Override
+ public Iterable<Dependency> getRunsupportClasspathDependencies(String playVersion, String scalaCompatibilityVersion) {
+ return null;
+ }
+
public Object getBuildDocHandler(ClassLoader docsClassLoader, Iterable<File> classpath) throws NoSuchMethodException, ClassNotFoundException, IOException, IllegalAccessException {
Class<?> docHandlerFactoryClass = getDocHandlerFactoryClass(docsClassLoader);
Method docHandlerFactoryMethod = docHandlerFactoryClass.getMethod("fromJar", JarFile.class, String.class);
@@ -77,7 +161,6 @@ public abstract class DefaultVersionedPlayRunAdapter implements VersionedPlayRun
}
private JarFile findDocumentationJar(Iterable<File> classpath) throws IOException {
- // TODO:DAZ Use the location of the DocHandlerFactoryClass instead.
File docJarFile = null;
for (File file : classpath) {
if (file.getName().startsWith("play-docs")) {
@@ -88,9 +171,9 @@ public abstract class DefaultVersionedPlayRunAdapter implements VersionedPlayRun
return new JarFile(docJarFile);
}
-
- public ScalaMethod getNettyServerDevHttpMethod(ClassLoader classLoader, ClassLoader docsClassLoader) throws ClassNotFoundException {
- return ScalaReflectionUtil.scalaMethod(classLoader, "play.core.server.NettyServer", "mainDevHttpMode", getBuildLinkClass(classLoader), getBuildDocHandlerClass(docsClassLoader), int.class);
+ public void runDevHttpServer(ClassLoader classLoader, ClassLoader docsClassLoader, Object buildLink, Object buildDocHandler, int httpPort) throws ClassNotFoundException {
+ ScalaMethod runMethod = ScalaReflectionUtil.scalaMethod(classLoader, "play.core.server.NettyServer", "mainDevHttpMode", getBuildLinkClass(classLoader), getBuildDocHandlerClass(docsClassLoader), int.class);
+ runMethod.invoke(buildLink, buildDocHandler, httpPort);
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationDeploymentHandle.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationDeploymentHandle.java
new file mode 100644
index 0000000..7747262
--- /dev/null
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationDeploymentHandle.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.internal.run;
+
+import org.gradle.BuildAdapter;
+import org.gradle.BuildResult;
+import org.gradle.api.invocation.Gradle;
+import org.gradle.api.logging.Logger;
+import org.gradle.api.logging.Logging;
+import org.gradle.deployment.internal.DeploymentHandle;
+
+public class PlayApplicationDeploymentHandle implements DeploymentHandle {
+
+ private static final Logger LOGGER = Logging.getLogger(PlayApplicationDeploymentHandle.class);
+
+ private PlayApplicationRunnerToken runnerToken;
+ private final String id;
+
+ public PlayApplicationDeploymentHandle(String id) {
+ this.id = id;
+ }
+
+ public void start(PlayApplicationRunnerToken runnerToken) {
+ this.runnerToken = runnerToken;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return runnerToken != null && runnerToken.isRunning();
+ }
+
+ @Override
+ public void onNewBuild(Gradle gradle) {
+ gradle.addBuildListener(new BuildAdapter() {
+ @Override
+ public void buildFinished(BuildResult result) {
+ reloadFromResult(result);
+ }
+ });
+ }
+
+ void reloadFromResult(BuildResult result) {
+ if (isRunning()) {
+ Throwable failure = result.getFailure();
+ if (failure != null) {
+ runnerToken.rebuildFailure(failure);
+ } else {
+ runnerToken.rebuildSuccess();
+ }
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (isRunning()) {
+ LOGGER.info("Stopping Play deployment handle for " + id);
+ runnerToken.stop();
+ }
+ }
+}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunner.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunner.java
index 84588ba..bdc3f10 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunner.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunner.java
@@ -25,18 +25,16 @@ import org.gradle.process.internal.WorkerProcessBuilder;
import java.io.File;
public class PlayApplicationRunner {
- private final File workingDir;
private final Factory<WorkerProcessBuilder> workerFactory;
private final VersionedPlayRunAdapter adapter;
- public PlayApplicationRunner(File workingDir, Factory<WorkerProcessBuilder> workerFactory, VersionedPlayRunAdapter adapter) {
- this.workingDir = workingDir;
+ public PlayApplicationRunner(Factory<WorkerProcessBuilder> workerFactory, VersionedPlayRunAdapter adapter) {
this.workerFactory = workerFactory;
this.adapter = adapter;
}
public PlayApplicationRunnerToken start(PlayRunSpec spec) {
- WorkerProcess process = createWorkerProcess(workingDir, workerFactory, spec, adapter);
+ WorkerProcess process = createWorkerProcess(spec.getProjectPath(), workerFactory, spec, adapter);
process.start();
PlayWorkerClient clientCallBack = new PlayWorkerClient();
@@ -45,7 +43,7 @@ public class PlayApplicationRunner {
process.getConnection().connect();
PlayAppLifecycleUpdate result = clientCallBack.waitForRunning();
if (result.isRunning()) {
- return new PlayApplicationRunnerToken(workerServer, clientCallBack);
+ return new PlayApplicationRunnerToken(workerServer, clientCallBack, process);
} else {
throw new GradleException("Unable to start Play application.", result.getException());
}
@@ -54,12 +52,12 @@ public class PlayApplicationRunner {
private static WorkerProcess createWorkerProcess(File workingDir, Factory<WorkerProcessBuilder> workerFactory, PlayRunSpec spec, VersionedPlayRunAdapter adapter) {
WorkerProcessBuilder builder = workerFactory.create();
builder.setBaseName("Gradle Play Worker");
- builder.applicationClasspath(spec.getClasspath());
- builder.sharedPackages("org.gradle.play.internal.run", "play.core", "play.core.server", "play.docs", "scala");
+ builder.sharedPackages("org.gradle.play.internal.run");
JavaExecHandleBuilder javaCommand = builder.getJavaCommand();
javaCommand.setWorkingDir(workingDir);
javaCommand.setMinHeapSize(spec.getForkOptions().getMemoryInitialSize());
javaCommand.setMaxHeapSize(spec.getForkOptions().getMemoryMaximumSize());
+ javaCommand.setJvmArgs(spec.getForkOptions().getJvmArgs());
return builder.worker(new PlayWorkerServer(spec, adapter)).build();
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunnerFactory.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunnerFactory.java
new file mode 100644
index 0000000..9f517db
--- /dev/null
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunnerFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.internal.run;
+
+import org.gradle.internal.Factory;
+import org.gradle.play.internal.platform.PlayMajorVersion;
+import org.gradle.play.platform.PlayPlatform;
+import org.gradle.process.internal.WorkerProcessBuilder;
+
+public class PlayApplicationRunnerFactory {
+ public static PlayApplicationRunner create(PlayPlatform playPlatform, Factory<WorkerProcessBuilder> workerFactory) {
+ return new PlayApplicationRunner(workerFactory, createPlayRunAdapter(playPlatform));
+ }
+
+ public static VersionedPlayRunAdapter createPlayRunAdapter(PlayPlatform playPlatform) {
+ switch (PlayMajorVersion.forPlatform(playPlatform)) {
+ case PLAY_2_2_X:
+ return new PlayRunAdapterV22X();
+ case PLAY_2_4_X:
+ return new PlayRunAdapterV24X();
+ case PLAY_2_3_X:
+ default:
+ return new PlayRunAdapterV23X();
+ }
+ }
+}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunnerToken.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunnerToken.java
index af78bef..a363d11 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunnerToken.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayApplicationRunnerToken.java
@@ -16,18 +16,41 @@
package org.gradle.play.internal.run;
+import org.gradle.process.internal.WorkerProcess;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
public class PlayApplicationRunnerToken {
private final PlayWorkerClient clientCallBack;
private final PlayRunWorkerServerProtocol workerServer;
+ private final WorkerProcess process;
+ private final AtomicBoolean stopped;
- public PlayApplicationRunnerToken(PlayRunWorkerServerProtocol workerServer, PlayWorkerClient clientCallBack) {
+ public PlayApplicationRunnerToken(PlayRunWorkerServerProtocol workerServer, PlayWorkerClient clientCallBack, WorkerProcess process) {
this.workerServer = workerServer;
this.clientCallBack = clientCallBack;
+ this.process = process;
+ this.stopped = new AtomicBoolean(false);
}
public PlayAppLifecycleUpdate stop() {
workerServer.stop();
- return clientCallBack.waitForStop();
+ PlayAppLifecycleUpdate update = clientCallBack.waitForStop();
+ process.waitForStop();
+ stopped.set(true);
+ return update;
+ }
+
+ public void rebuildSuccess() {
+ workerServer.reload();
+ }
+
+ public void rebuildFailure(Throwable failure) {
+ workerServer.buildError(failure);
+ }
+
+ public boolean isRunning() {
+ return !stopped.get();
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV22X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV22X.java
index afce834..782ed3c 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV22X.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV22X.java
@@ -16,6 +16,10 @@
package org.gradle.play.internal.run;
+import org.gradle.api.artifacts.Dependency;
+
+import java.util.Collections;
+
public class PlayRunAdapterV22X extends DefaultVersionedPlayRunAdapter {
@Override
protected Class<?> getBuildLinkClass(ClassLoader classLoader) throws ClassNotFoundException {
@@ -31,4 +35,9 @@ public class PlayRunAdapterV22X extends DefaultVersionedPlayRunAdapter {
protected Class<?> getDocHandlerFactoryClass(ClassLoader docsClassLoader) throws ClassNotFoundException {
return docsClassLoader.loadClass("play.docs.SBTDocHandlerFactory");
}
+
+ @Override
+ public Iterable<Dependency> getRunsupportClasspathDependencies(String playVersion, String scalaCompatibilityVersion) {
+ return Collections.emptySet();
+ }
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV23X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV23X.java
index 811e535..8dd1d23 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV23X.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV23X.java
@@ -16,7 +16,25 @@
package org.gradle.play.internal.run;
+import com.google.common.collect.ImmutableList;
+import org.gradle.api.Transformer;
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency;
+import org.gradle.internal.Cast;
+import org.gradle.internal.UncheckedException;
+import org.gradle.internal.reflect.DirectInstantiator;
+import org.gradle.scala.internal.reflect.ScalaMethod;
+import org.gradle.scala.internal.reflect.ScalaReflectionUtil;
+import org.gradle.util.CollectionUtils;
+import org.gradle.util.VersionNumber;
+
+import java.io.File;
+import java.util.List;
+
public class PlayRunAdapterV23X extends DefaultVersionedPlayRunAdapter {
+ protected static final String RUN_SUPPORT_PLAY_MODULE = "run-support";
+ private static final VersionNumber MINIMUM_PLAY_VERSION_WITH_RUN_SUPPORT = VersionNumber.parse("2.3.7");
+
@Override
protected Class<?> getBuildLinkClass(ClassLoader classLoader) throws ClassNotFoundException {
return classLoader.loadClass("play.core.BuildLink");
@@ -32,4 +50,59 @@ public class PlayRunAdapterV23X extends DefaultVersionedPlayRunAdapter {
return docsClassLoader.loadClass("play.docs.BuildDocHandlerFactory");
}
+ @Override
+ protected ClassLoader createAssetsClassLoader(File assetsJar, Iterable<File> assetsDirs, ClassLoader classLoader) {
+ Class<?> assetsClassLoaderClass;
+
+ assetsClassLoaderClass = loadClass(classLoader, "play.runsupport.AssetsClassLoader");
+
+ final Class<?> tuple2Class = loadClass(classLoader, "scala.Tuple2");
+
+ List<?> tuples = CollectionUtils.collect(assetsDirs, new Transformer<Object, File>() {
+ @Override
+ public Object transform(File file) {
+ return DirectInstantiator.instantiate(tuple2Class, "public", file);
+ }
+ });
+
+ ScalaMethod listToScalaSeqMethod = ScalaReflectionUtil.scalaMethod(classLoader, "scala.collection.convert.WrapAsScala", "asScalaBuffer", List.class);
+ Object scalaTuples = listToScalaSeqMethod.invoke(tuples);
+
+ return Cast.uncheckedCast(DirectInstantiator.instantiate(assetsClassLoaderClass, classLoader, scalaTuples));
+ }
+
+ private Class<?> loadClass(ClassLoader classLoader, String className) {
+ try {
+ return classLoader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+
+ @Override
+ public Iterable<Dependency> getRunsupportClasspathDependencies(String playVersion, String scalaCompatibilityVersion) {
+ ImmutableList.Builder<Dependency> listBuilder = ImmutableList.builder();
+
+ String runsupportPlayVersion = playVersion;
+ boolean transitive = true;
+ // use run-support from 2.3.7 for versions before Play 2.3.7
+ if (VersionNumber.parse(playVersion).compareTo(MINIMUM_PLAY_VERSION_WITH_RUN_SUPPORT) < 0) {
+ runsupportPlayVersion = "2.3.7";
+ transitive = false;
+ }
+ DefaultExternalModuleDependency runSupportDependency = new DefaultExternalModuleDependency("com.typesafe.play", String.format("%s_%s", RUN_SUPPORT_PLAY_MODULE, scalaCompatibilityVersion), runsupportPlayVersion);
+ runSupportDependency.setTransitive(transitive);
+ listBuilder.add(runSupportDependency);
+
+ String name = scalaCompatibilityVersion.equals("2.10") ? "io" : String.format("%s_%s", "io", scalaCompatibilityVersion);
+ DefaultExternalModuleDependency dependency = new DefaultExternalModuleDependency("org.scala-sbt", name, getIOSupportDependencyVersion(), "runtime");
+ dependency.setTransitive(false);
+ listBuilder.add(dependency);
+
+ return listBuilder.build();
+ }
+
+ protected String getIOSupportDependencyVersion() {
+ return "0.13.6";
+ }
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV24X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV24X.java
new file mode 100644
index 0000000..e74746b
--- /dev/null
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunAdapterV24X.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.internal.run;
+
+import org.gradle.scala.internal.reflect.ScalaMethod;
+import org.gradle.scala.internal.reflect.ScalaReflectionUtil;
+
+public class PlayRunAdapterV24X extends PlayRunAdapterV23X {
+ @Override
+ public void runDevHttpServer(ClassLoader classLoader, ClassLoader docsClassLoader, Object buildLink, Object buildDocHandler, int httpPort) throws ClassNotFoundException {
+ ScalaMethod runMethod = ScalaReflectionUtil.scalaMethod(classLoader, "play.core.server.DevServerStart", "mainDevHttpMode", getBuildLinkClass(classLoader), getBuildDocHandlerClass(docsClassLoader), int.class, String.class);
+ runMethod.invoke(buildLink, buildDocHandler, httpPort, "0.0.0.0");
+ }
+
+ @Override
+ protected String getIOSupportDependencyVersion() {
+ return "0.13.8";
+ }
+}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunSpec.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunSpec.java
index d14566c..b36b478 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunSpec.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunSpec.java
@@ -26,6 +26,14 @@ public interface PlayRunSpec {
Iterable<File> getClasspath();
+ Iterable<File> getChangingClasspath();
+
+ File getApplicationJar();
+
+ File getAssetsJar();
+
+ Iterable<File> getAssetsDirs();
+
File getProjectPath();
int getHttpPort();
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunWorkerServerProtocol.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunWorkerServerProtocol.java
index 0497448..e8fcce7 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunWorkerServerProtocol.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayRunWorkerServerProtocol.java
@@ -19,4 +19,6 @@ package org.gradle.play.internal.run;
import org.gradle.internal.concurrent.Stoppable;
public interface PlayRunWorkerServerProtocol extends Stoppable {
+ void reload();
+ void buildError(Throwable throwable);
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayWorkerServer.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayWorkerServer.java
index 1522c06..df9ba9e 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayWorkerServer.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/PlayWorkerServer.java
@@ -19,22 +19,27 @@ package org.gradle.play.internal.run;
import org.gradle.api.Action;
import org.gradle.api.logging.Logging;
import org.gradle.internal.UncheckedException;
+import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.process.internal.WorkerProcessContext;
-import org.gradle.scala.internal.reflect.ScalaMethod;
+import java.io.IOException;
import java.io.Serializable;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLConnection;
import java.util.concurrent.CountDownLatch;
public class PlayWorkerServer implements Action<WorkerProcessContext>, PlayRunWorkerServerProtocol, Serializable {
private PlayRunSpec runSpec;
- private VersionedPlayRunAdapter spec;
+ private VersionedPlayRunAdapter runAdapter;
private volatile CountDownLatch stop;
- public PlayWorkerServer(PlayRunSpec runSpec, VersionedPlayRunAdapter spec) {
+ public PlayWorkerServer(PlayRunSpec runSpec, VersionedPlayRunAdapter runAdapter) {
this.runSpec = runSpec;
- this.spec = spec;
+ this.runAdapter = runAdapter;
}
public void execute(WorkerProcessContext context) {
@@ -64,20 +69,50 @@ public class PlayWorkerServer implements Action<WorkerProcessContext>, PlayRunWo
}
private void run() {
+ disableUrlConnectionCaching();
+ final Thread thread = Thread.currentThread();
+ final ClassLoader previousContextClassLoader = thread.getContextClassLoader();
+ final ClassLoader classLoader = new URLClassLoader(new DefaultClassPath(runSpec.getClasspath()).getAsURLArray(), null);
+ thread.setContextClassLoader(classLoader);
try {
- ClassLoader classLoader = getClass().getClassLoader();
- ClassLoader docsClassLoader = getClass().getClassLoader();
-
- Object buildDocHandler = spec.getBuildDocHandler(docsClassLoader, runSpec.getClasspath());
- ScalaMethod runMethod = spec.getNettyServerDevHttpMethod(classLoader, docsClassLoader);
- Object buildLink = spec.getBuildLink(classLoader, runSpec.getProjectPath(), runSpec.getClasspath());
- runMethod.invoke(buildLink, buildDocHandler, runSpec.getHttpPort());
+ Object buildDocHandler = runAdapter.getBuildDocHandler(classLoader, runSpec.getClasspath());
+ Object buildLink = runAdapter.getBuildLink(classLoader, runSpec.getProjectPath(), runSpec.getApplicationJar(), runSpec.getChangingClasspath(), runSpec.getAssetsJar(), runSpec.getAssetsDirs());
+ runAdapter.runDevHttpServer(classLoader, classLoader, buildLink, buildDocHandler, runSpec.getHttpPort());
} catch (Exception e) {
throw UncheckedException.throwAsUncheckedException(e);
+ } finally {
+ thread.setContextClassLoader(previousContextClassLoader);
+ }
+ }
+
+ private void disableUrlConnectionCaching() {
+ // fix problems in updating jar files by disabling default caching of URL connections.
+ // URLConnection default caching should be disabled since it causes jar file locking issues and JVM crashes in updating jar files.
+ // Changes to jar files won't be noticed in all cases when caching is enabled.
+ // sun.net.www.protocol.jar.JarURLConnection leaves the JarFile instance open if URLConnection caching is enabled.
+ try {
+ URL url = new URL("jar:file://valid_jar_url_syntax.jar!/");
+ URLConnection urlConnection = url.openConnection();
+ urlConnection.setDefaultUseCaches(false);
+ } catch (MalformedURLException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ } catch (IOException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
}
}
public void stop() {
stop.countDown();
}
+
+ @Override
+ public void reload() {
+ runAdapter.reload();
+ }
+
+ @Override
+ public void buildError(Throwable throwable) {
+ runAdapter.buildError(throwable);
+ }
+
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/VersionedPlayRunAdapter.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/VersionedPlayRunAdapter.java
index c2ceb54..62dac97 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/VersionedPlayRunAdapter.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/run/VersionedPlayRunAdapter.java
@@ -16,15 +16,21 @@
package org.gradle.play.internal.run;
-import org.gradle.scala.internal.reflect.ScalaMethod;
+import org.gradle.api.artifacts.Dependency;
import java.io.File;
import java.io.IOException;
public interface VersionedPlayRunAdapter {
- Object getBuildLink(ClassLoader classLoader, final File projectPath, Iterable<File> classpath) throws ClassNotFoundException;
+ void reload();
+
+ void buildError(Throwable throwable);
+
+ Object getBuildLink(ClassLoader classLoader, File projectPath, File applicationJar, Iterable<File> changingClasspath, File assetsJar, Iterable<File> assetsDirs) throws ClassNotFoundException;
Object getBuildDocHandler(ClassLoader docsClassLoader, Iterable<File> classpath) throws NoSuchMethodException, ClassNotFoundException, IOException, IllegalAccessException;
- ScalaMethod getNettyServerDevHttpMethod(ClassLoader classLoader, ClassLoader docsClassLoader) throws ClassNotFoundException;
+ void runDevHttpServer(ClassLoader classLoader, ClassLoader docsClassLoader, Object buildLink, Object buildDocHandler, int httpPort) throws ClassNotFoundException;
+
+ Iterable<Dependency> getRunsupportClasspathDependencies(String playVersion, String scalaCompatibilityVersion);
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/spec/PlayApplicationBinaryRenderer.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/spec/PlayApplicationBinaryRenderer.java
index d13ff65..a6375ed 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/spec/PlayApplicationBinaryRenderer.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/spec/PlayApplicationBinaryRenderer.java
@@ -29,6 +29,5 @@ public class PlayApplicationBinaryRenderer extends AbstractBinaryRenderer<PlayAp
@Override
protected void renderDetails(PlayApplicationBinarySpec binary, TextReportBuilder builder) {
builder.item("platform", binary.getTargetPlatform().getDisplayName());
- //builder.item("tool chain", binary.getToolChain().getDisplayName());
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolChain.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolChain.java
index d1317df..6035b5d 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolChain.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolChain.java
@@ -68,7 +68,7 @@ public class DefaultPlayToolChain implements PlayToolChainInternal {
Set<File> twirlClasspath = resolveToolClasspath(TwirlCompilerFactory.createAdapter(targetPlatform).getDependencyNotation()).resolve();
Set<File> routesClasspath = resolveToolClasspath(RoutesCompilerFactory.createAdapter(targetPlatform).getDependencyNotation()).resolve();
Set<File> javascriptClasspath = resolveToolClasspath(GoogleClosureCompiler.getDependencyNotation()).resolve();
- return new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, configurationContainer, dependencyHandler, workerProcessBuilderFactory, targetPlatform, twirlClasspath, routesClasspath, javascriptClasspath);
+ return new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, workerProcessBuilderFactory, targetPlatform, twirlClasspath, routesClasspath, javascriptClasspath);
} catch (ResolveException e) {
return new UnavailablePlayToolProvider(e);
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolProvider.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolProvider.java
index 10f7424..d5b273d 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolProvider.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/DefaultPlayToolProvider.java
@@ -16,23 +16,18 @@
package org.gradle.play.internal.toolchain;
-import org.gradle.api.artifacts.ConfigurationContainer;
-import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.api.internal.tasks.compile.daemon.CompilerDaemonManager;
import org.gradle.internal.Factory;
import org.gradle.language.base.internal.compile.CompileSpec;
import org.gradle.language.base.internal.compile.Compiler;
-import org.gradle.play.internal.javascript.JavaScriptCompileSpec;
import org.gradle.play.internal.javascript.GoogleClosureCompiler;
+import org.gradle.play.internal.javascript.JavaScriptCompileSpec;
import org.gradle.play.internal.platform.PlayMajorVersion;
import org.gradle.play.internal.routes.RoutesCompileSpec;
import org.gradle.play.internal.routes.RoutesCompiler;
import org.gradle.play.internal.routes.RoutesCompilerFactory;
-import org.gradle.play.internal.run.PlayApplicationRunner;
-import org.gradle.play.internal.run.PlayRunAdapterV22X;
-import org.gradle.play.internal.run.PlayRunAdapterV23X;
-import org.gradle.play.internal.run.VersionedPlayRunAdapter;
+import org.gradle.play.internal.run.*;
import org.gradle.play.internal.spec.PlayCompileSpec;
import org.gradle.play.internal.twirl.TwirlCompileSpec;
import org.gradle.play.internal.twirl.TwirlCompiler;
@@ -48,31 +43,26 @@ class DefaultPlayToolProvider implements PlayToolProvider {
private final FileResolver fileResolver;
private final CompilerDaemonManager compilerDaemonManager;
- private final ConfigurationContainer configurationContainer;
- private final DependencyHandler dependencyHandler;
private final PlayPlatform targetPlatform;
- private final PlayMajorVersion playMajorVersion;
private Factory<WorkerProcessBuilder> workerProcessBuilderFactory;
private final Set<File> twirlClasspath;
private final Set<File> routesClasspath;
private final Set<File> javaScriptClasspath;
- public DefaultPlayToolProvider(FileResolver fileResolver, CompilerDaemonManager compilerDaemonManager, ConfigurationContainer configurationContainer,
- DependencyHandler dependencyHandler, Factory<WorkerProcessBuilder> workerProcessBuilderFactory, PlayPlatform targetPlatform,
+ public DefaultPlayToolProvider(FileResolver fileResolver, CompilerDaemonManager compilerDaemonManager,
+ Factory<WorkerProcessBuilder> workerProcessBuilderFactory, PlayPlatform targetPlatform,
Set<File> twirlClasspath, Set<File> routesClasspath, Set<File> javaScriptClasspath) {
this.fileResolver = fileResolver;
this.compilerDaemonManager = compilerDaemonManager;
- this.configurationContainer = configurationContainer;
- this.dependencyHandler = dependencyHandler;
this.workerProcessBuilderFactory = workerProcessBuilderFactory;
this.targetPlatform = targetPlatform;
- this.playMajorVersion = PlayMajorVersion.forPlatform(targetPlatform);
this.twirlClasspath = twirlClasspath;
this.routesClasspath = routesClasspath;
this.javaScriptClasspath = javaScriptClasspath;
+ // validate that the targetPlatform is valid
+ PlayMajorVersion.forPlatform(targetPlatform);
}
- // TODO:DAZ Detangle Routes adapter from compile specs
public <T extends CompileSpec> Compiler<T> newCompiler(Class<T> spec) {
if (TwirlCompileSpec.class.isAssignableFrom(spec)) {
TwirlCompiler twirlCompiler = TwirlCompilerFactory.create(targetPlatform);
@@ -90,7 +80,7 @@ class DefaultPlayToolProvider implements PlayToolProvider {
@Override
public <T> T get(Class<T> toolType) {
if (PlayApplicationRunner.class.isAssignableFrom(toolType)) {
- return toolType.cast(newApplicationRunner());
+ return toolType.cast(PlayApplicationRunnerFactory.create(targetPlatform, workerProcessBuilderFactory));
}
throw new IllegalArgumentException(String.format("Don't know how to provide tool of type %s.", toolType.getSimpleName()));
}
@@ -101,21 +91,6 @@ class DefaultPlayToolProvider implements PlayToolProvider {
return converted;
}
- public PlayApplicationRunner newApplicationRunner() {
- VersionedPlayRunAdapter playRunAdapter = createPlayRunAdapter();
- return new PlayApplicationRunner(fileResolver.resolve("."), workerProcessBuilderFactory, playRunAdapter);
- }
-
- private VersionedPlayRunAdapter createPlayRunAdapter() {
- switch (playMajorVersion) {
- case PLAY_2_2_X:
- return new PlayRunAdapterV22X();
- case PLAY_2_3_X:
- default:
- return new PlayRunAdapterV23X();
- }
- }
-
public boolean isAvailable() {
return true;
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/PlayToolChainServiceRegistry.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/PlayToolChainServiceRegistry.java
index 173f6c2..bc5c0b0 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/PlayToolChainServiceRegistry.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/toolchain/PlayToolChainServiceRegistry.java
@@ -32,6 +32,9 @@ public class PlayToolChainServiceRegistry implements PluginServiceRegistry {
registration.add(PlayApplicationBinaryRenderer.class);
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
@@ -42,6 +45,7 @@ public class PlayToolChainServiceRegistry implements PluginServiceRegistry {
registration.addProvider(new ProjectScopeCompileServices());
}
+
private static class ProjectScopeCompileServices {
PlayToolChainInternal createPlayToolChain(FileResolver fileResolver, CompilerDaemonManager compilerDaemonManager, ConfigurationContainer configurationContainer, DependencyHandler dependencyHandler, Factory<WorkerProcessBuilder> workerProcessBuilderFactory) {
return new DefaultPlayToolChain(fileResolver, compilerDaemonManager, configurationContainer, dependencyHandler, workerProcessBuilderFactory);
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV10X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV10X.java
index a570b98..285a6f6 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV10X.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV10X.java
@@ -99,7 +99,7 @@ class TwirlCompilerAdapterV10X implements VersionedTwirlCompilerAdapter {
return Arrays.asList("play.twirl.compiler", "scala.io"); //scala.io is for Codec which is a parameter to twirl
}
- public Object getDependencyNotation() {
+ public String getDependencyNotation() {
return String.format("com.typesafe.play:twirl-compiler_%s:%s", scalaVersion, twirlVersion);
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV22X.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV22X.java
index 5bbb67d..c349b98 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV22X.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerAdapterV22X.java
@@ -26,7 +26,6 @@ import java.util.List;
class TwirlCompilerAdapterV22X implements VersionedTwirlCompilerAdapter {
- // TODO:DAZ Validate these
private static final String DEFAULT_JAVA_IMPORTS =
"import play.api.templates._;"
+ "import play.api.templates.PlayMagic._;"
@@ -85,7 +84,7 @@ class TwirlCompilerAdapterV22X implements VersionedTwirlCompilerAdapter {
return Arrays.asList("play.templates");
}
- public Object getDependencyNotation() {
+ public String getDependencyNotation() {
return String.format("com.typesafe.play:templates-compiler_%s:%s", scalaVersion, twirlVersion);
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerFactory.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerFactory.java
index 5d7b176..abf77d2 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerFactory.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/TwirlCompilerFactory.java
@@ -29,9 +29,11 @@ public class TwirlCompilerFactory {
String scalaCompatibilityVersion = playPlatform.getScalaPlatform().getScalaCompatibilityVersion();
switch (PlayMajorVersion.forPlatform(playPlatform)) {
case PLAY_2_2_X:
- return new TwirlCompilerAdapterV22X("2.2.3", scalaCompatibilityVersion);
+ return new TwirlCompilerAdapterV22X("2.2.6", scalaCompatibilityVersion);
case PLAY_2_3_X:
- return new TwirlCompilerAdapterV10X("1.0.2", scalaCompatibilityVersion);
+ return new TwirlCompilerAdapterV10X("1.0.4", scalaCompatibilityVersion);
+ case PLAY_2_4_X:
+ return new TwirlCompilerAdapterV10X("1.1.1", scalaCompatibilityVersion);
default:
throw new RuntimeException("Could not create Twirl compile spec for Play version: " + playVersion);
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/VersionedTwirlCompilerAdapter.java b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/VersionedTwirlCompilerAdapter.java
index 55098c8..e36464a 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/VersionedTwirlCompilerAdapter.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/internal/twirl/VersionedTwirlCompilerAdapter.java
@@ -24,7 +24,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.List;
public interface VersionedTwirlCompilerAdapter extends Serializable {
- public Object getDependencyNotation();
+ String getDependencyNotation();
ScalaMethod getCompileMethod(ClassLoader cl) throws ClassNotFoundException;
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/platform/PlayPlatform.java b/subprojects/platform-play/src/main/java/org/gradle/play/platform/PlayPlatform.java
index ff7635d..c49f9e0 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/platform/PlayPlatform.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/platform/PlayPlatform.java
@@ -27,9 +27,21 @@ import org.gradle.platform.base.Platform;
@Incubating
public interface PlayPlatform extends Platform {
+ /**
+ * Version of Play Framework to use
+ * @return version of the Play Framework
+ */
public String getPlayVersion();
+ /**
+ * Version of Scala Runtime to use.
+ * @return version of the Scala runtime
+ */
public ScalaPlatform getScalaPlatform();
+ /**
+ * Version of Java Runtime to use.
+ * @return version of the Java runtime
+ */
public JavaPlatform getJavaPlatform();
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayApplicationPlugin.java b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayApplicationPlugin.java
index 2372f80..fb80c19 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayApplicationPlugin.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayApplicationPlugin.java
@@ -17,6 +17,7 @@ package org.gradle.play.plugins;
import org.apache.commons.lang.StringUtils;
import org.gradle.api.*;
+import org.gradle.api.artifacts.Dependency;
import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.api.internal.file.copy.CopySpecInternal;
@@ -26,15 +27,11 @@ import org.gradle.api.tasks.scala.IncrementalCompileOptions;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.jvm.tasks.Jar;
-import org.gradle.language.base.FunctionalSourceSet;
import org.gradle.language.base.LanguageSourceSet;
-import org.gradle.language.base.internal.compile.Compiler;
import org.gradle.language.base.sources.BaseLanguageSourceSet;
import org.gradle.language.java.JavaSourceSet;
-import org.gradle.language.java.internal.DefaultJavaLanguageSourceSet;
import org.gradle.language.java.plugins.JavaLanguagePlugin;
import org.gradle.language.jvm.JvmResourceSet;
-import org.gradle.language.jvm.internal.DefaultJvmResourceLanguageSourceSet;
import org.gradle.language.routes.RoutesSourceSet;
import org.gradle.language.routes.internal.DefaultRoutesSourceSet;
import org.gradle.language.scala.ScalaLanguageSourceSet;
@@ -44,28 +41,27 @@ import org.gradle.language.scala.tasks.PlatformScalaCompile;
import org.gradle.language.twirl.TwirlSourceSet;
import org.gradle.language.twirl.internal.DefaultTwirlSourceSet;
import org.gradle.model.*;
+import org.gradle.model.internal.registry.ModelRegistry;
+import org.gradle.model.internal.type.ModelType;
import org.gradle.platform.base.*;
-import org.gradle.platform.base.internal.ComponentSpecInternal;
import org.gradle.platform.base.internal.DefaultPlatformRequirement;
import org.gradle.platform.base.internal.PlatformRequirement;
import org.gradle.platform.base.internal.PlatformResolvers;
-import org.gradle.platform.base.internal.toolchain.ResolvedTool;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import org.gradle.play.JvmClasses;
import org.gradle.play.PlayApplicationBinarySpec;
import org.gradle.play.PlayApplicationSpec;
import org.gradle.play.PublicAssets;
import org.gradle.play.internal.*;
import org.gradle.play.internal.platform.PlayPlatformInternal;
-import org.gradle.play.internal.routes.RoutesCompileSpec;
-import org.gradle.play.internal.run.PlayApplicationRunner;
-import org.gradle.play.internal.twirl.TwirlCompileSpec;
-import org.gradle.play.internal.twirl.TwirlCompilerFactory;
+import org.gradle.play.internal.run.PlayApplicationRunnerFactory;
+import org.gradle.play.internal.toolchain.PlayToolChainInternal;
import org.gradle.play.platform.PlayPlatform;
import org.gradle.play.tasks.PlayRun;
import org.gradle.play.tasks.RoutesCompile;
import org.gradle.play.tasks.TwirlCompile;
+import org.gradle.util.VersionNumber;
+import javax.inject.Inject;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
@@ -73,17 +69,24 @@ import java.util.Date;
/**
* Plugin for Play Framework component support. Registers the {@link org.gradle.play.PlayApplicationSpec} component type for the components container.
*/
-
@Incubating
public class PlayApplicationPlugin implements Plugin<Project> {
- private final static String DEFAULT_PLAY_VERSION = "2.3.7";
public static final int DEFAULT_HTTP_PORT = 9000;
+ public static final String RUN_GROUP = "Run";
+ private final ModelRegistry modelRegistry;
+
+ @Inject
+ public PlayApplicationPlugin(ModelRegistry modelRegistry) {
+ this.modelRegistry = modelRegistry;
+ }
@Override
public void apply(Project project) {
project.getPluginManager().apply(JavaLanguagePlugin.class);
project.getPluginManager().apply(ScalaLanguagePlugin.class);
project.getExtensions().create("playConfigurations", PlayPluginConfigurations.class, project.getConfigurations(), project.getDependencies());
+
+ modelRegistry.getRoot().applyToAllLinksTransitive(ModelType.of(PlayApplicationSpec.class), PlaySourceSetRules.class);
}
@SuppressWarnings("UnusedDeclaration")
@@ -94,6 +97,11 @@ public class PlayApplicationPlugin implements Plugin<Project> {
}
@Model
+ PlayToolChainInternal playToolChain(ServiceRegistry serviceRegistry) {
+ return serviceRegistry.get(PlayToolChainInternal.class);
+ }
+
+ @Model
FileResolver fileResolver(ServiceRegistry serviceRegistry) {
return serviceRegistry.get(FileResolver.class);
}
@@ -130,34 +138,6 @@ public class PlayApplicationPlugin implements Plugin<Project> {
builder.defaultImplementation(DefaultRoutesSourceSet.class);
}
- @Mutate
- void configureDefaultPlaySources(ModelMap<PlayApplicationSpec> playApplicationComponents, ServiceRegistry serviceRegistry) {
- final FileResolver fileResolver = serviceRegistry.get(FileResolver.class);
- final Instantiator instantiator = serviceRegistry.get(Instantiator.class);
- playApplicationComponents.all(new Action<PlayApplicationSpec>() {
- public void execute(PlayApplicationSpec playComponent) {
- // TODO:DAZ Scala source set type should be registered via scala-lang plugin
- ScalaLanguageSourceSet scalaSources = BaseLanguageSourceSet.create(DefaultScalaLanguageSourceSet.class, "scala", playComponent.getName(), fileResolver, instantiator);
-
- // Compile scala/java sources under /app\
- // TODO:DAZ Should be selecting 'controllers/**' and 'model/**' I think, allowing user to add more includes
- scalaSources.getSource().srcDir("app");
- scalaSources.getSource().include("**/*.scala");
- FunctionalSourceSet sources = ((ComponentSpecInternal) playComponent).getSources();
- sources.add(scalaSources);
-
- JavaSourceSet javaSources = BaseLanguageSourceSet.create(DefaultJavaLanguageSourceSet.class, "java", playComponent.getName(), fileResolver, instantiator);
- javaSources.getSource().srcDir("app");
- javaSources.getSource().include("**/*.java");
- sources.add(javaSources);
-
- JvmResourceSet appResources = BaseLanguageSourceSet.create(DefaultJvmResourceLanguageSourceSet.class, "resources", playComponent.getName(), fileResolver, instantiator);
- appResources.getSource().srcDirs("conf");
- sources.add(appResources);
- }
- });
- }
-
@Validate
void failOnMultiplePlayComponents(ModelMap<PlayApplicationSpec> container) {
if (container.size() >= 2) {
@@ -177,14 +157,30 @@ public class PlayApplicationPlugin implements Plugin<Project> {
});
}
+ @Validate
+ void failIfInjectedRouterIsUsedWithOldVersion(ModelMap<PlayApplicationBinarySpec> playApplicationBinaries) {
+ playApplicationBinaries.afterEach(new Action<PlayApplicationBinarySpec>() {
+ @Override
+ public void execute(PlayApplicationBinarySpec playApplicationBinary) {
+ if (playApplicationBinary.getApplication().getInjectedRoutesGenerator()) {
+ final PlayPlatform playPlatform = playApplicationBinary.getTargetPlatform();
+ VersionNumber minSupportedVersion = VersionNumber.parse("2.4.0");
+ VersionNumber playVersion = VersionNumber.parse(playPlatform.getPlayVersion());
+ if (playVersion.compareTo(minSupportedVersion) < 0) {
+ throw new GradleException("Injected routers are only supported in Play 2.4 or newer.");
+ }
+ }
+ }
+ });
+ }
+
@ComponentBinaries
void createBinaries(ModelMap<PlayApplicationBinarySpec> binaries, final PlayApplicationSpec componentSpec,
- final PlatformResolvers platforms, final PlayPluginConfigurations configurations, final ServiceRegistry serviceRegistry,
+ final PlatformResolvers platforms, final PlayToolChainInternal playToolChainInternal, final PlayPluginConfigurations configurations, final ServiceRegistry serviceRegistry,
@Path("buildDir") final File buildDir, final ProjectIdentifier projectIdentifier) {
final FileResolver fileResolver = serviceRegistry.get(FileResolver.class);
final Instantiator instantiator = serviceRegistry.get(Instantiator.class);
- final ToolResolver toolResolver = serviceRegistry.get(ToolResolver.class);
final String binaryName = String.format("%sBinary", componentSpec.getName());
binaries.create(binaryName, new Action<PlayApplicationBinarySpec>() {
@@ -193,11 +189,11 @@ public class PlayApplicationPlugin implements Plugin<Project> {
playBinaryInternal.setApplication(componentSpec);
final File binaryBuildDir = new File(buildDir, binaryName);
- final PlayPlatform chosenPlatform = resolveTargetPlatform(componentSpec, platforms, configurations);
+ final PlayPlatform chosenPlatform = resolveTargetPlatform(componentSpec, platforms);
initialiseConfigurations(configurations, chosenPlatform);
playBinaryInternal.setTargetPlatform(chosenPlatform);
- playBinaryInternal.setToolResolver(toolResolver);
+ playBinaryInternal.setToolChain(playToolChainInternal);
File mainJar = new File(binaryBuildDir, String.format("lib/%s.jar", projectIdentifier.getName()));
File assetsJar = new File(binaryBuildDir, String.format("lib/%s-assets.jar", projectIdentifier.getName()));
@@ -210,30 +206,29 @@ public class PlayApplicationPlugin implements Plugin<Project> {
JvmClasses classes = playBinary.getClasses();
classes.setClassesDir(new File(binaryBuildDir, "classes"));
- ModelMap<JvmResourceSet> jvmResourceSets = componentSpec.getSource().withType(JvmResourceSet.class);
+ ModelMap<JvmResourceSet> jvmResourceSets = componentSpec.getSources().withType(JvmResourceSet.class);
for (JvmResourceSet jvmResourceSet : jvmResourceSets.values()) {
for (File resourceDir : jvmResourceSet.getSource()) {
classes.addResourceDir(resourceDir);
}
}
- // TODO:DAZ These should be configured on the component
PublicAssets assets = playBinary.getAssets();
assets.addAssetDir(new File(projectIdentifier.getProjectDir(), "public"));
- playBinaryInternal.setClasspath(configurations.getPlay().getFileCollection());
+ playBinaryInternal.setClasspath(configurations.getPlay().getAllArtifacts());
}
});
}
- private PlayPlatform resolveTargetPlatform(PlayApplicationSpec componentSpec, final PlatformResolvers platforms, PlayPluginConfigurations configurations) {
+ private PlayPlatform resolveTargetPlatform(PlayApplicationSpec componentSpec, final PlatformResolvers platforms) {
PlatformRequirement targetPlatform = getTargetPlatform((PlayApplicationSpecInternal) componentSpec);
return platforms.resolve(PlayPlatform.class, targetPlatform);
}
private PlatformRequirement getTargetPlatform(PlayApplicationSpecInternal playApplicationSpec) {
if (playApplicationSpec.getTargetPlatforms().isEmpty()) {
- String defaultPlayPlatform = String.format("play-%s", DEFAULT_PLAY_VERSION);
+ String defaultPlayPlatform = String.format("play-%s", DefaultPlayPlatform.DEFAULT_PLAY_VERSION);
return DefaultPlatformRequirement.create(defaultPlayPlatform);
}
return playApplicationSpec.getTargetPlatforms().get(0);
@@ -243,31 +238,17 @@ public class PlayApplicationPlugin implements Plugin<Project> {
configurations.getPlayPlatform().addDependency(((PlayPlatformInternal) playPlatform).getDependencyNotation("play"));
configurations.getPlayTest().addDependency(((PlayPlatformInternal) playPlatform).getDependencyNotation("play-test"));
configurations.getPlayRun().addDependency(((PlayPlatformInternal) playPlatform).getDependencyNotation("play-docs"));
- }
- @Mutate
- void createTwirlSourceSets(ModelMap<PlayApplicationSpec> components) {
- components.beforeEach(new Action<PlayApplicationSpec>() {
- @Override
- public void execute(PlayApplicationSpec playComponent) {
- TwirlSourceSet twirlSourceSet = ((ComponentSpecInternal) playComponent).getSources().create("twirlTemplates", TwirlSourceSet.class);
- twirlSourceSet.getSource().srcDir("app");
- twirlSourceSet.getSource().include("**/*.html");
- }
- });
+ addRunSupportDependencies(configurations, playPlatform);
}
- @Mutate
- void createRoutesSourceSets(ModelMap<PlayApplicationSpec> components) {
- components.beforeEach(new Action<PlayApplicationSpec>() {
- @Override
- public void execute(PlayApplicationSpec playComponent) {
- RoutesSourceSet routesSourceSet = ((ComponentSpecInternal) playComponent).getSources().create("routesSources", RoutesSourceSet.class);
- routesSourceSet.getSource().srcDir("conf");
- routesSourceSet.getSource().include("routes");
- routesSourceSet.getSource().include("*.routes");
- }
- });
+ private void addRunSupportDependencies(PlayPluginConfigurations configurations, PlayPlatform playPlatform) {
+ String playVersion = playPlatform.getPlayVersion();
+ String scalaCompatibilityVersion = playPlatform.getScalaPlatform().getScalaCompatibilityVersion();
+ Iterable<Dependency> runSupportDependencies = PlayApplicationRunnerFactory.createPlayRunAdapter(playPlatform).getRunsupportClasspathDependencies(playVersion, scalaCompatibilityVersion);
+ for (Dependency dependencyNotation : runSupportDependencies) {
+ configurations.getPlayRun().addDependency(dependencyNotation);
+ }
}
@Mutate
@@ -282,8 +263,9 @@ public class PlayApplicationPlugin implements Plugin<Project> {
binaries.all(new Action<PlayApplicationBinarySpec>() {
@Override
public void execute(PlayApplicationBinarySpec playApplicationBinarySpec) {
- for (LanguageSourceSet languageSourceSet : playApplicationBinarySpec.getSource().withType(languageSourceSetType)) {
- ScalaLanguageSourceSet twirlScalaSources = BaseLanguageSourceSet.create(DefaultScalaLanguageSourceSet.class, String.format("%sScalaSources", languageSourceSet.getName()), playApplicationBinarySpec.getName(), fileResolver, instantiator);
+ for (LanguageSourceSet languageSourceSet : playApplicationBinarySpec.getInputs().withType(languageSourceSetType)) {
+ String name = String.format("%sScalaSources", languageSourceSet.getName());
+ ScalaLanguageSourceSet twirlScalaSources = BaseLanguageSourceSet.create(DefaultScalaLanguageSourceSet.class, name, playApplicationBinarySpec.getName(), fileResolver, instantiator);
playApplicationBinarySpec.getGeneratedScala().put(languageSourceSet, twirlScalaSources);
}
}
@@ -292,18 +274,16 @@ public class PlayApplicationPlugin implements Plugin<Project> {
@BinaryTasks
void createTwirlCompileTasks(ModelMap<Task> tasks, final PlayApplicationBinarySpec binary, ServiceRegistry serviceRegistry, @Path("buildDir") final File buildDir) {
- final ToolResolver toolResolver = serviceRegistry.get(ToolResolver.class);
- final ResolvedTool<Compiler<TwirlCompileSpec>> compilerTool = toolResolver.resolveCompiler(TwirlCompileSpec.class, binary.getTargetPlatform());
- for (final TwirlSourceSet twirlSourceSet : binary.getSource().withType(TwirlSourceSet.class)) {
- final String twirlCompileTaskName = String.format("twirlCompile%s%s", StringUtils.capitalize(twirlSourceSet.getName()), StringUtils.capitalize(binary.getName()));
+ for (final TwirlSourceSet twirlSourceSet : binary.getInputs().withType(TwirlSourceSet.class)) {
+ final String twirlCompileTaskName = String.format("compile%s%s", StringUtils.capitalize(binary.getName()), StringUtils.capitalize(twirlSourceSet.getName()));
final File twirlCompileOutputDirectory = srcOutputDirectory(buildDir, binary, twirlCompileTaskName);
tasks.create(twirlCompileTaskName, TwirlCompile.class, new Action<TwirlCompile>() {
public void execute(TwirlCompile twirlCompile) {
- twirlCompile.setDependencyNotation(TwirlCompilerFactory.createAdapter(binary.getTargetPlatform()).getDependencyNotation());
+ twirlCompile.setDescription("Compiles twirl templates for the '" + twirlSourceSet.getName() + "' source set.");
+ twirlCompile.setPlatform(binary.getTargetPlatform());
twirlCompile.setSource(twirlSourceSet.getSource());
twirlCompile.setOutputDirectory(twirlCompileOutputDirectory);
- twirlCompile.setCompilerTool(compilerTool);
ScalaLanguageSourceSet twirlScalaSources = binary.getGeneratedScala().get(twirlSourceSet);
twirlScalaSources.getSource().srcDir(twirlCompileOutputDirectory);
@@ -315,18 +295,18 @@ public class PlayApplicationPlugin implements Plugin<Project> {
@BinaryTasks
void createRoutesCompileTasks(ModelMap<Task> tasks, final PlayApplicationBinarySpec binary, ServiceRegistry serviceRegistry, @Path("buildDir") final File buildDir) {
- final ToolResolver toolResolver = serviceRegistry.get(ToolResolver.class);
- final ResolvedTool<Compiler<RoutesCompileSpec>> compilerTool = toolResolver.resolveCompiler(RoutesCompileSpec.class, binary.getTargetPlatform());
- for (final RoutesSourceSet routesSourceSet : binary.getSource().withType(RoutesSourceSet.class)) {
- final String routesCompileTaskName = String.format("routesCompile%s%s", StringUtils.capitalize(routesSourceSet.getName()), StringUtils.capitalize(binary.getName()));
+ for (final RoutesSourceSet routesSourceSet : binary.getInputs().withType(RoutesSourceSet.class)) {
+ final String routesCompileTaskName = String.format("compile%s%s", StringUtils.capitalize(binary.getName()), StringUtils.capitalize(routesSourceSet.getName()));
final File routesCompilerOutputDirectory = srcOutputDirectory(buildDir, binary, routesCompileTaskName);
tasks.create(routesCompileTaskName, RoutesCompile.class, new Action<RoutesCompile>() {
public void execute(RoutesCompile routesCompile) {
- routesCompile.setCompilerTool(compilerTool);
+ routesCompile.setDescription("Generates routes for the '" + routesSourceSet.getName() + "' source set.");
+ routesCompile.setPlatform(binary.getTargetPlatform());
routesCompile.setAdditionalImports(new ArrayList<String>());
routesCompile.setSource(routesSourceSet.getSource());
routesCompile.setOutputDirectory(routesCompilerOutputDirectory);
+ routesCompile.setInjectedRoutesGenerator(binary.getApplication().getInjectedRoutesGenerator());
ScalaLanguageSourceSet routesScalaSources = binary.getGeneratedScala().get(routesSourceSet);
routesScalaSources.getSource().srcDir(routesCompilerOutputDirectory);
@@ -338,9 +318,10 @@ public class PlayApplicationPlugin implements Plugin<Project> {
@BinaryTasks
void createScalaCompileTask(ModelMap<Task> tasks, final PlayApplicationBinarySpec binary, @Path("buildDir") final File buildDir) {
- final String scalaCompileTaskName = String.format("scalaCompile%s", StringUtils.capitalize(binary.getName()));
+ final String scalaCompileTaskName = String.format("compile%s%s", StringUtils.capitalize(binary.getName()), "Scala");
tasks.create(scalaCompileTaskName, PlatformScalaCompile.class, new Action<PlatformScalaCompile>() {
public void execute(PlatformScalaCompile scalaCompile) {
+ scalaCompile.setDescription("Compiles all scala and java source sets for the '" + binary.getName() + "' binary.");
scalaCompile.setDestinationDir(binary.getClasses().getClassesDir());
scalaCompile.setPlatform(binary.getTargetPlatform().getScalaPlatform());
@@ -352,19 +333,19 @@ public class PlayApplicationPlugin implements Plugin<Project> {
IncrementalCompileOptions incrementalOptions = scalaCompile.getScalaCompileOptions().getIncrementalOptions();
incrementalOptions.setAnalysisFile(new File(buildDir, String.format("tmp/scala/compilerAnalysis/%s.analysis", scalaCompileTaskName)));
- for (LanguageSourceSet appSources : binary.getSource().withType(ScalaLanguageSourceSet.class)) {
+ for (LanguageSourceSet appSources : binary.getInputs().withType(ScalaLanguageSourceSet.class)) {
scalaCompile.source(appSources.getSource());
scalaCompile.dependsOn(appSources);
}
- for (LanguageSourceSet appSources : binary.getSource().withType(JavaSourceSet.class)) {
+ for (LanguageSourceSet appSources : binary.getInputs().withType(JavaSourceSet.class)) {
scalaCompile.source(appSources.getSource());
scalaCompile.dependsOn(appSources);
}
for (LanguageSourceSet generatedSourceSet : binary.getGeneratedScala().values()) {
scalaCompile.source(generatedSourceSet.getSource());
- scalaCompile.dependsOn(generatedSourceSet.getBuildDependencies());
+ scalaCompile.dependsOn(generatedSourceSet);
}
scalaCompile.setClasspath(((PlayApplicationBinarySpecInternal) binary).getClasspath());
@@ -379,6 +360,7 @@ public class PlayApplicationPlugin implements Plugin<Project> {
String jarTaskName = String.format("create%sJar", StringUtils.capitalize(binary.getName()));
tasks.create(jarTaskName, Jar.class, new Action<Jar>() {
public void execute(Jar jar) {
+ jar.setDescription("Assembles the application jar for the '" + binary.getName() + "' binary.");
jar.setDestinationDir(binary.getJarFile().getParentFile());
jar.setArchiveName(binary.getJarFile().getName());
jar.from(binary.getClasses().getClassesDir());
@@ -390,6 +372,7 @@ public class PlayApplicationPlugin implements Plugin<Project> {
String assetsJarTaskName = String.format("create%sAssetsJar", StringUtils.capitalize(binary.getName()));
tasks.create(assetsJarTaskName, Jar.class, new Action<Jar>() {
public void execute(Jar jar) {
+ jar.setDescription("Assembles the assets jar for the '" + binary.getName() + "' binary.");
jar.setDestinationDir(binary.getAssetsJarFile().getParentFile());
jar.setArchiveName(binary.getAssetsJarFile().getName());
jar.setClassifier("assets");
@@ -401,20 +384,23 @@ public class PlayApplicationPlugin implements Plugin<Project> {
});
}
- // TODO:DAZ Need a nice way to create tasks that are associated with a binary but not part of _building_ it.
@Mutate
- void createPlayRunTask(ModelMap<Task> tasks, BinaryContainer binaryContainer, ServiceRegistry serviceRegistry, final PlayPluginConfigurations configurations) {
- ToolResolver toolResolver = serviceRegistry.get(ToolResolver.class);
+ void createPlayRunTask(ModelMap<Task> tasks, BinaryContainer binaryContainer, final ServiceRegistry serviceRegistry, final PlayPluginConfigurations configurations, ProjectIdentifier projectIdentifier, final PlayToolChainInternal playToolChain) {
+
for (final PlayApplicationBinarySpecInternal binary : binaryContainer.withType(PlayApplicationBinarySpecInternal.class)) {
- final ResolvedTool<PlayApplicationRunner> playApplicationRunnerTool = toolResolver.resolve(PlayApplicationRunner.class, binary.getTargetPlatform());
String runTaskName = String.format("run%s", StringUtils.capitalize(binary.getName()));
+
tasks.create(runTaskName, PlayRun.class, new Action<PlayRun>() {
public void execute(PlayRun playRun) {
+ playRun.setDescription("Runs the Play application for local development.");
+ playRun.setGroup(RUN_GROUP);
playRun.setHttpPort(DEFAULT_HTTP_PORT);
- playRun.setPlayApplicationRunnerTool(playApplicationRunnerTool);
+ playRun.setPlayToolProvider(playToolChain.select(binary.getTargetPlatform()));
playRun.setApplicationJar(binary.getJarFile());
playRun.setAssetsJar(binary.getAssetsJarFile());
- playRun.setRuntimeClasspath(configurations.getPlayRun().getFileCollection());
+ playRun.setAssetsDirs(binary.getAssets().getAssetDirs());
+ playRun.setRuntimeClasspath(configurations.getPlayRun().getNonChangingArtifacts());
+ playRun.setChangingClasspath(configurations.getPlayRun().getChangingArtifacts());
playRun.dependsOn(binary.getBuildTask());
}
});
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayCoffeeScriptPlugin.java b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayCoffeeScriptPlugin.java
index 8481c7b..21214ed 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayCoffeeScriptPlugin.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayCoffeeScriptPlugin.java
@@ -35,7 +35,6 @@ import org.gradle.model.RuleSource;
import org.gradle.platform.base.BinaryTasks;
import org.gradle.platform.base.LanguageType;
import org.gradle.platform.base.LanguageTypeBuilder;
-import org.gradle.platform.base.internal.ComponentSpecInternal;
import org.gradle.play.PlayApplicationBinarySpec;
import org.gradle.play.PlayApplicationSpec;
import org.gradle.play.tasks.PlayCoffeeScriptCompile;
@@ -47,7 +46,7 @@ import static org.apache.commons.lang.StringUtils.capitalize;
/**
* Plugin for adding coffeescript compilation to a Play application. Adds support for
* defining {@link org.gradle.language.coffeescript.CoffeeScriptSourceSet} source sets. A
- * "coffeeScriptAssets" source set is created by default.
+ * "coffeeScript" source set is created by default.
*/
@SuppressWarnings("UnusedDeclaration")
@Incubating
@@ -74,10 +73,13 @@ public class PlayCoffeeScriptPlugin extends RuleSource {
components.beforeEach(new Action<PlayApplicationSpec>() {
@Override
public void execute(PlayApplicationSpec playComponent) {
- // TODO - should have some way to lookup using internal type
- CoffeeScriptSourceSet coffeeScriptSourceSet = ((ComponentSpecInternal) playComponent).getSources().create("coffeeScriptAssets", CoffeeScriptSourceSet.class);
- coffeeScriptSourceSet.getSource().srcDir("app/assets");
- coffeeScriptSourceSet.getSource().include("**/*.coffee");
+ playComponent.getSources().create("coffeeScript", CoffeeScriptSourceSet.class, new Action<CoffeeScriptSourceSet>() {
+ @Override
+ public void execute(CoffeeScriptSourceSet coffeeScriptSourceSet) {
+ coffeeScriptSourceSet.getSource().srcDir("app/assets");
+ coffeeScriptSourceSet.getSource().include("**/*.coffee");
+ }
+ });
}
});
}
@@ -89,7 +91,7 @@ public class PlayCoffeeScriptPlugin extends RuleSource {
binaries.all(new Action<PlayApplicationBinarySpec>() {
@Override
public void execute(PlayApplicationBinarySpec playApplicationBinarySpec) {
- for (CoffeeScriptSourceSet coffeeScriptSourceSet : playApplicationBinarySpec.getSource().withType(CoffeeScriptSourceSet.class)) {
+ for (CoffeeScriptSourceSet coffeeScriptSourceSet : playApplicationBinarySpec.getInputs().withType(CoffeeScriptSourceSet.class)) {
JavaScriptSourceSet javaScriptSourceSet = BaseLanguageSourceSet.create(DefaultJavaScriptSourceSet.class, String.format("%sJavaScript", coffeeScriptSourceSet.getName()), playApplicationBinarySpec.getName(), fileResolver, instantiator);
playApplicationBinarySpec.getGeneratedJavaScript().put(coffeeScriptSourceSet, javaScriptSourceSet);
}
@@ -107,12 +109,14 @@ public class PlayCoffeeScriptPlugin extends RuleSource {
}
});
- for (final CoffeeScriptSourceSet coffeeScriptSourceSet : binary.getSource().withType(CoffeeScriptSourceSet.class)) {
+ for (final CoffeeScriptSourceSet coffeeScriptSourceSet : binary.getInputs().withType(CoffeeScriptSourceSet.class)) {
if (((LanguageSourceSetInternal) coffeeScriptSourceSet).getMayHaveSources()) {
final String compileTaskName = "compile" + capitalize(binary.getName()) + capitalize(coffeeScriptSourceSet.getName());
tasks.create(compileTaskName, PlayCoffeeScriptCompile.class, new Action<PlayCoffeeScriptCompile>() {
@Override
public void execute(PlayCoffeeScriptCompile coffeeScriptCompile) {
+ coffeeScriptCompile.setDescription("Compiles coffeescript for the '" + coffeeScriptSourceSet.getName() + "' source set.");
+
File outputDirectory = outputDirectory(buildDir, binary, compileTaskName);
coffeeScriptCompile.setDestinationDir(outputDirectory);
coffeeScriptCompile.setSource(coffeeScriptSourceSet.getSource());
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayDistributionPlugin.java b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayDistributionPlugin.java
index 3dbdf62..5032e89 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayDistributionPlugin.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayDistributionPlugin.java
@@ -16,9 +16,15 @@
package org.gradle.play.plugins;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
-import org.gradle.api.*;
+import org.gradle.api.Action;
+import org.gradle.api.Incubating;
+import org.gradle.api.InvalidUserCodeException;
+import org.gradle.api.Task;
import org.gradle.api.file.CopySpec;
import org.gradle.api.internal.file.FileOperations;
import org.gradle.api.internal.file.copy.CopySpecInternal;
@@ -35,11 +41,10 @@ import org.gradle.play.distribution.PlayDistribution;
import org.gradle.play.distribution.PlayDistributionContainer;
import org.gradle.play.internal.distribution.DefaultPlayDistribution;
import org.gradle.play.internal.distribution.DefaultPlayDistributionContainer;
-import org.gradle.util.CollectionUtils;
import java.io.File;
+import java.util.Collections;
import java.util.Map;
-import java.util.Set;
/**
* A plugin that adds a distribution zip to a Play application build.
@@ -60,7 +65,7 @@ public class PlayDistributionPlugin extends RuleSource {
tasks.create("dist", new Action<Task>() {
@Override
public void execute(Task task) {
- task.setDescription("Assembles all play distributions.");
+ task.setDescription("Assembles all Play distributions.");
task.setGroup(DISTRIBUTION_GROUP);
}
});
@@ -68,7 +73,7 @@ public class PlayDistributionPlugin extends RuleSource {
tasks.create("stage", new Action<Task>() {
@Override
public void execute(Task task) {
- task.setDescription("Stages all play distributions.");
+ task.setDescription("Stages all Play distributions.");
task.setGroup(DISTRIBUTION_GROUP);
}
});
@@ -100,6 +105,7 @@ public class PlayDistributionPlugin extends RuleSource {
tasks.create(jarTaskName, Jar.class, new Action<Jar>() {
@Override
public void execute(Jar jar) {
+ jar.setDescription("Assembles an application jar suitable for deployment for the '" + binary.getName() + "' binary.");
jar.dependsOn(binary.getTasks().withType(Jar.class));
jar.from(jar.getProject().zipTree(binary.getJarFile()));
jar.setDestinationDir(distJarDir);
@@ -117,7 +123,7 @@ public class PlayDistributionPlugin extends RuleSource {
tasks.create(createStartScriptsTaskName, CreateStartScripts.class, new Action<CreateStartScripts>() {
@Override
public void execute(CreateStartScripts createStartScripts) {
- createStartScripts.setDescription("Creates OS specific scripts to run the play application.");
+ createStartScripts.setDescription("Creates OS specific scripts to run the '" + binary.getName() + "' application.");
createStartScripts.setClasspath(distributionJar.getOutputs().getFiles());
createStartScripts.setMainClassName("play.core.server.NettyServer");
createStartScripts.setApplicationName(binary.getName());
@@ -130,7 +136,7 @@ public class PlayDistributionPlugin extends RuleSource {
CopySpec libSpec = distSpec.addChild().into("lib");
libSpec.from(distributionJar);
libSpec.from(binary.getAssetsJarFile());
- libSpec.from(configurations.getPlayRun().getFileCollection());
+ libSpec.from(configurations.getPlayRun().getAllArtifacts());
CopySpec binSpec = distSpec.addChild().into("bin");
binSpec.from(createStartScripts);
@@ -151,8 +157,7 @@ public class PlayDistributionPlugin extends RuleSource {
tasks.create(stageTaskName, Copy.class, new Action<Copy>() {
@Override
public void execute(Copy copy) {
- copy.setDescription("Copies the binary distribution to a staging directory.");
- copy.setGroup(DISTRIBUTION_GROUP);
+ copy.setDescription("Copies the '" + distribution.getName() + "' distribution to a staging directory.");
copy.setDestinationDir(stageDir);
CopySpecInternal baseSpec = copy.getRootSpec().addChild();
@@ -172,8 +177,7 @@ public class PlayDistributionPlugin extends RuleSource {
tasks.create(distributionTaskName, Zip.class, new Action<Zip>() {
@Override
public void execute(final Zip zip) {
- zip.setDescription("Bundles the play binary as a distribution.");
- zip.setGroup(DISTRIBUTION_GROUP);
+ zip.setDescription("Packages the '" + distribution.getName() + "' distribution as a zip file.");
zip.setArchiveName(String.format("%s.zip", baseName));
zip.setDestinationDir(new File(buildDir, "distributions"));
zip.from(stageTask);
@@ -203,16 +207,20 @@ public class PlayDistributionPlugin extends RuleSource {
@Override
public String toString() {
- Set<File> classpathFiles = playConfiguration.getFileCollection().getFiles();
- classpathFiles.add(assetsJarFile);
- Set<String> classpathFileNames = CollectionUtils.collect(classpathFiles, new Transformer<String, File>() {
- @Override
- public String transform(File file) {
- return file.getName();
- }
- });
-
- return StringUtils.join(classpathFileNames, " ");
+ return Joiner.on(" ").join(
+ Iterables.transform(
+ Iterables.concat(
+ playConfiguration.getAllArtifacts(),
+ Collections.singleton(assetsJarFile)
+ ),
+ new Function<File, String>() {
+ @Override
+ public String apply(File input) {
+ return input.getName();
+ }
+ }
+ )
+ );
}
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayJavaScriptPlugin.java b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayJavaScriptPlugin.java
index bf16cc4..87d687c 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayJavaScriptPlugin.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayJavaScriptPlugin.java
@@ -21,7 +21,6 @@ import org.gradle.api.Incubating;
import org.gradle.api.Task;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.language.base.internal.LanguageSourceSetInternal;
-import org.gradle.language.base.internal.compile.Compiler;
import org.gradle.language.javascript.JavaScriptSourceSet;
import org.gradle.language.javascript.internal.DefaultJavaScriptSourceSet;
import org.gradle.model.ModelMap;
@@ -31,12 +30,8 @@ import org.gradle.model.RuleSource;
import org.gradle.platform.base.BinaryTasks;
import org.gradle.platform.base.LanguageType;
import org.gradle.platform.base.LanguageTypeBuilder;
-import org.gradle.platform.base.internal.ComponentSpecInternal;
-import org.gradle.platform.base.internal.toolchain.ResolvedTool;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import org.gradle.play.PlayApplicationBinarySpec;
import org.gradle.play.PlayApplicationSpec;
-import org.gradle.play.internal.javascript.JavaScriptCompileSpec;
import org.gradle.play.tasks.JavaScriptMinify;
import java.io.File;
@@ -60,39 +55,40 @@ public class PlayJavaScriptPlugin extends RuleSource {
components.beforeEach(new Action<PlayApplicationSpec>() {
@Override
public void execute(PlayApplicationSpec playComponent) {
- // TODO - should have some way to lookup using internal type
- JavaScriptSourceSet javaScriptSourceSet = ((ComponentSpecInternal) playComponent).getSources().create("javaScriptAssets", JavaScriptSourceSet.class);
- javaScriptSourceSet.getSource().srcDir("app/assets");
- javaScriptSourceSet.getSource().include("**/*.js");
+ playComponent.getSources().create("javaScript", JavaScriptSourceSet.class, new Action<JavaScriptSourceSet>() {
+ @Override
+ public void execute(JavaScriptSourceSet javaScriptSourceSet) {
+ javaScriptSourceSet.getSource().srcDir("app/assets");
+ javaScriptSourceSet.getSource().include("**/*.js");
+ }
+ });
}
});
}
@BinaryTasks
void createJavaScriptTasks(ModelMap<Task> tasks, final PlayApplicationBinarySpec binary, ServiceRegistry serviceRegistry, @Path("buildDir") final File buildDir) {
- ToolResolver toolResolver = serviceRegistry.get(ToolResolver.class);
- ResolvedTool<Compiler<JavaScriptCompileSpec>> compilerTool = toolResolver.resolveCompiler(JavaScriptCompileSpec.class, binary.getTargetPlatform());
- for (JavaScriptSourceSet javaScriptSourceSet : binary.getSource().withType(JavaScriptSourceSet.class)) {
+ for (JavaScriptSourceSet javaScriptSourceSet : binary.getInputs().withType(JavaScriptSourceSet.class)) {
if (((LanguageSourceSetInternal) javaScriptSourceSet).getMayHaveSources()) {
- createJavaScriptMinifyTask(tasks, javaScriptSourceSet, binary, compilerTool, buildDir);
+ createJavaScriptMinifyTask(tasks, javaScriptSourceSet, binary, buildDir);
}
}
for (JavaScriptSourceSet javaScriptSourceSet : binary.getGeneratedJavaScript().values()) {
- createJavaScriptMinifyTask(tasks, javaScriptSourceSet, binary, compilerTool, buildDir);
+ createJavaScriptMinifyTask(tasks, javaScriptSourceSet, binary, buildDir);
}
}
- void createJavaScriptMinifyTask(ModelMap
- <Task> tasks, final JavaScriptSourceSet javaScriptSourceSet, final PlayApplicationBinarySpec binary, final ResolvedTool<Compiler<JavaScriptCompileSpec>> compilerTool, @Path("buildDir") final File buildDir) {
+ void createJavaScriptMinifyTask(ModelMap<Task> tasks, final JavaScriptSourceSet javaScriptSourceSet, final PlayApplicationBinarySpec binary, @Path("buildDir") final File buildDir) {
final String minifyTaskName = "minify" + capitalize(binary.getName()) + capitalize(javaScriptSourceSet.getName());
final File minifyOutputDirectory = new File(buildDir, String.format("%s/src/%s", binary.getName(), minifyTaskName));
tasks.create(minifyTaskName, JavaScriptMinify.class, new Action<JavaScriptMinify>() {
@Override
public void execute(JavaScriptMinify javaScriptMinify) {
+ javaScriptMinify.setDescription("Minifies javascript for the '" + javaScriptSourceSet.getName() +"' source set.");
javaScriptMinify.setSource(javaScriptSourceSet.getSource());
javaScriptMinify.setDestinationDir(minifyOutputDirectory);
- javaScriptMinify.setCompilerTool(compilerTool);
+ javaScriptMinify.setPlayPlatform(binary.getTargetPlatform());
binary.getAssets().builtBy(javaScriptMinify);
binary.getAssets().addAssetDir(minifyOutputDirectory);
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayPluginConfigurations.java b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayPluginConfigurations.java
index a72fa04..054d11e 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayPluginConfigurations.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayPluginConfigurations.java
@@ -16,12 +16,16 @@
package org.gradle.play.plugins;
-import org.gradle.api.artifacts.Configuration;
-import org.gradle.api.artifacts.ConfigurationContainer;
-import org.gradle.api.artifacts.Dependency;
-import org.gradle.api.artifacts.PublishArtifact;
+import com.google.common.collect.ImmutableSet;
+import org.gradle.api.artifacts.*;
+import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.file.FileCollection;
+import org.gradle.api.internal.file.FileCollectionInternal;
+import org.gradle.api.internal.file.collections.LazilyInitializedFileCollection;
+import org.gradle.api.internal.file.collections.SimpleFileCollection;
+
+import java.io.File;
/**
* Conventional locations and names for play plugins.
@@ -78,11 +82,23 @@ public class PlayPluginConfigurations {
this.name = name;
}
- FileCollection getFileCollection() {
+ private Configuration getConfiguration() {
return configurations.getByName(name);
}
-
- void addDependency(String notation) {
+
+ FileCollection getAllArtifacts() {
+ return getConfiguration();
+ }
+
+ FileCollection getChangingArtifacts() {
+ return new FilterByProjectComponentTypeFileCollection(getConfiguration(), true);
+ }
+
+ FileCollection getNonChangingArtifacts() {
+ return new FilterByProjectComponentTypeFileCollection(getConfiguration(), false);
+ }
+
+ void addDependency(Object notation) {
dependencyHandler.add(name, notation);
}
@@ -90,4 +106,25 @@ public class PlayPluginConfigurations {
configurations.getByName(name).getArtifacts().add(artifact);
}
}
+
+ private static class FilterByProjectComponentTypeFileCollection extends LazilyInitializedFileCollection {
+ private final Configuration configuration;
+ private final boolean matchProjectComponents;
+
+ private FilterByProjectComponentTypeFileCollection(Configuration configuration, boolean matchProjectComponents) {
+ this.configuration = configuration;
+ this.matchProjectComponents = matchProjectComponents;
+ }
+
+ @Override
+ public FileCollectionInternal createDelegate() {
+ ImmutableSet.Builder<File> files = ImmutableSet.builder();
+ for (ResolvedArtifact artifact : configuration.getResolvedConfiguration().getResolvedArtifacts()) {
+ if ((artifact.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier) == matchProjectComponents) {
+ files.add(artifact.getFile());
+ }
+ }
+ return new SimpleFileCollection(files.build());
+ }
+ }
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayTestPlugin.java b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayTestPlugin.java
index fbca0a6..5f0cc5b 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayTestPlugin.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/plugins/PlayTestPlugin.java
@@ -36,6 +36,7 @@ import org.gradle.model.RuleSource;
import org.gradle.platform.base.BinaryContainer;
import org.gradle.play.PlayApplicationBinarySpec;
import org.gradle.play.internal.PlayApplicationBinarySpecInternal;
+import org.gradle.play.internal.toolchain.PlayToolProvider;
import java.io.File;
import java.util.Arrays;
@@ -50,15 +51,17 @@ public class PlayTestPlugin extends RuleSource {
void createTestTasks(ModelMap<Task> tasks, BinaryContainer binaryContainer, final PlayPluginConfigurations configurations,
final FileResolver fileResolver, final ProjectIdentifier projectIdentifier, @Path("buildDir") final File buildDir) {
for (final PlayApplicationBinarySpecInternal binary : binaryContainer.withType(PlayApplicationBinarySpecInternal.class)) {
- final FileCollection testCompileClasspath = getTestCompileClasspath(binary, configurations);
+ final PlayToolProvider playToolProvider = binary.getToolChain().select(binary.getTargetPlatform());
+ final FileCollection testCompileClasspath = getTestCompileClasspath(binary, playToolProvider, configurations);
final String testCompileTaskName = String.format("compile%sTests", StringUtils.capitalize(binary.getName()));
- // TODO:DAZ Model a test suite
final File testSourceDir = fileResolver.resolve("test");
final FileCollection testSources = new SimpleFileCollection(testSourceDir).getAsFileTree().matching(new PatternSet().include("**/*.scala", "**/*.java"));
final File testClassesDir = new File(buildDir, String.format("%s/testClasses", binary.getName()));
tasks.create(testCompileTaskName, PlatformScalaCompile.class, new Action<PlatformScalaCompile>() {
public void execute(PlatformScalaCompile scalaCompile) {
+ scalaCompile.setDescription("Compiles the scala and java test sources for the '" + binary.getName() + "' binary.");
+
scalaCompile.setClasspath(testCompileClasspath);
scalaCompile.dependsOn(binary.getBuildTask());
@@ -80,6 +83,8 @@ public class PlayTestPlugin extends RuleSource {
final File binaryBuildDir = new File(buildDir, binary.getName());
tasks.create(testTaskName, Test.class, new Action<Test>() {
public void execute(Test test) {
+ test.setDescription("Runs tests for the '" + binary.getName() + "' binary.");
+
test.setClasspath(getRuntimeClasspath(testClassesDir, testCompileClasspath));
test.setTestClassesDir(testClassesDir);
@@ -95,8 +100,8 @@ public class PlayTestPlugin extends RuleSource {
}
}
- private FileCollection getTestCompileClasspath(PlayApplicationBinarySpec binary, PlayPluginConfigurations configurations) {
- return new SimpleFileCollection(binary.getJarFile()).plus(configurations.getPlayTest().getFileCollection());
+ private FileCollection getTestCompileClasspath(PlayApplicationBinarySpec binary, PlayToolProvider playToolProvider, PlayPluginConfigurations configurations) {
+ return new SimpleFileCollection(binary.getJarFile()).plus(configurations.getPlayTest().getAllArtifacts());
}
private FileCollection getRuntimeClasspath(File testClassesDir, FileCollection testCompileClasspath) {
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/JavaScriptMinify.java b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/JavaScriptMinify.java
index 658bb5f..2bf074b 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/JavaScriptMinify.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/JavaScriptMinify.java
@@ -32,9 +32,11 @@ import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.compile.BaseForkOptions;
import org.gradle.language.base.internal.tasks.SimpleStaleClassCleaner;
import org.gradle.language.base.internal.tasks.StaleClassCleaner;
-import org.gradle.platform.base.internal.toolchain.ResolvedTool;
+import org.gradle.platform.base.internal.toolchain.ToolProvider;
import org.gradle.play.internal.javascript.DefaultJavaScriptCompileSpec;
import org.gradle.play.internal.javascript.JavaScriptCompileSpec;
+import org.gradle.play.internal.toolchain.PlayToolChainInternal;
+import org.gradle.play.platform.PlayPlatform;
import org.gradle.play.toolchain.PlayToolChain;
import org.gradle.language.base.internal.compile.Compiler;
@@ -48,7 +50,7 @@ import java.util.List;
@Incubating
public class JavaScriptMinify extends SourceTask {
private File destinationDir;
- private ResolvedTool<Compiler<JavaScriptCompileSpec>> compilerTool;
+ private PlayPlatform playPlatform;
private BaseForkOptions forkOptions;
public JavaScriptMinify() {
@@ -61,7 +63,7 @@ public class JavaScriptMinify extends SourceTask {
}
/**
- * Returns the tool chain that will be used to compile the javascript source.
+ * Returns the tool chain that will be used to compile the JavaScript source.
*
* @return The tool chain.
*/
@@ -72,7 +74,7 @@ public class JavaScriptMinify extends SourceTask {
}
/**
- * Returns the output directory that processed javascript is written to.
+ * Returns the output directory that processed JavaScript is written to.
*
* @return The output directory.
*/
@@ -82,7 +84,7 @@ public class JavaScriptMinify extends SourceTask {
}
/**
- * Sets the output directory where processed javascript should be written.
+ * Sets the output directory where processed JavaScript should be written.
*
* @param destinationDir The output directory.
*/
@@ -90,14 +92,24 @@ public class JavaScriptMinify extends SourceTask {
this.destinationDir = destinationDir;
}
- public void setCompilerTool(ResolvedTool<Compiler<JavaScriptCompileSpec>> compilerTool) {
- this.compilerTool = compilerTool;
+ /**
+ * Sets the target Play platform.
+ *
+ * @param playPlatform The target Play platform.
+ */
+ public void setPlayPlatform(PlayPlatform playPlatform) {
+ this.playPlatform = playPlatform;
+ }
+
+ private Compiler<JavaScriptCompileSpec> getCompiler() {
+ ToolProvider select = ((PlayToolChainInternal) getToolChain()).select(playPlatform);
+ return select.newCompiler(JavaScriptCompileSpec.class);
}
/**
- * The fork options to be applied to the javascript compiler.
+ * The fork options to be applied to the JavaScript compiler.
*
- * @return The fork options for the javascript compiler.
+ * @return The fork options for the JavaScript compiler.
*/
public BaseForkOptions getForkOptions() {
if (forkOptions == null) {
@@ -116,7 +128,7 @@ public class JavaScriptMinify extends SourceTask {
getSource().visit(visitor);
JavaScriptCompileSpec spec = new DefaultJavaScriptCompileSpec(visitor.relativeFiles, getDestinationDir(), getForkOptions());
- compilerTool.get().execute(spec);
+ getCompiler().execute(spec);
}
/**
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayCoffeeScriptCompile.java b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayCoffeeScriptCompile.java
index 3c4ab82..fb39e1f 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayCoffeeScriptCompile.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayCoffeeScriptCompile.java
@@ -24,7 +24,7 @@ import org.gradle.language.base.internal.tasks.StaleClassCleaner;
import org.gradle.plugins.javascript.coffeescript.CoffeeScriptCompile;
/**
- * Task for compiling CoffeeScript sources
+ * Task for compiling CoffeeScript sources into JavaScript.
*/
@Incubating
public class PlayCoffeeScriptCompile extends CoffeeScriptCompile {
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayRun.java b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayRun.java
index b21d327..d55c31f 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayRun.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/PlayRun.java
@@ -20,26 +20,25 @@ import org.gradle.api.Incubating;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.file.FileCollection;
import org.gradle.api.internal.ConventionTask;
-import org.gradle.api.internal.file.collections.SimpleFileCollection;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.compile.BaseForkOptions;
+import org.gradle.deployment.internal.DeploymentRegistry;
import org.gradle.logging.ProgressLogger;
import org.gradle.logging.ProgressLoggerFactory;
-import org.gradle.platform.base.internal.toolchain.ResolvedTool;
-import org.gradle.play.internal.run.DefaultPlayRunSpec;
-import org.gradle.play.internal.run.PlayApplicationRunner;
-import org.gradle.play.internal.run.PlayApplicationRunnerToken;
-import org.gradle.play.internal.run.PlayRunSpec;
+import org.gradle.play.internal.run.*;
+import org.gradle.play.internal.toolchain.PlayToolProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
+import java.util.Set;
/**
- * A Task to run a play application.
+ * Task to run a Play application.
*/
@Incubating
public class PlayRun extends ConventionTask {
@@ -54,14 +53,20 @@ public class PlayRun extends ConventionTask {
private File assetsJar;
@InputFiles
+ private Set<File> assetsDirs;
+
+ @InputFiles
private FileCollection runtimeClasspath;
+ @InputFiles
+ private FileCollection changingClasspath;
+
private BaseForkOptions forkOptions;
- private ResolvedTool<PlayApplicationRunner> playApplicationRunnerTool;
+ private PlayToolProvider playToolProvider;
/**
- * fork options for the running a play application.
+ * fork options for the running a Play application.
*/
public BaseForkOptions getForkOptions() {
if (forkOptions == null) {
@@ -73,24 +78,33 @@ public class PlayRun extends ConventionTask {
@TaskAction
public void run() {
ProgressLoggerFactory progressLoggerFactory = getServices().get(ProgressLoggerFactory.class);
- ProgressLogger progressLogger = progressLoggerFactory.newOperation(PlayRun.class)
+ PlayApplicationDeploymentHandle deploymentHandle = registerOrFindDeploymentHandle(getPath());
+
+ if (!deploymentHandle.isRunning()) {
+ ProgressLogger progressLogger = progressLoggerFactory.newOperation(PlayRun.class)
.start("Start Play server", "Starting Play");
- int httpPort = getHttpPort();
- FileCollection applicationJars = new SimpleFileCollection(applicationJar, assetsJar);
- applicationJars = applicationJars.plus(runtimeClasspath);
- PlayRunSpec spec = new DefaultPlayRunSpec(applicationJars, getProject().getProjectDir(), getForkOptions(), httpPort);
-
- try {
- PlayApplicationRunnerToken runnerToken = playApplicationRunnerTool.get().start(spec);
- progressLogger.completed();
- progressLogger = progressLoggerFactory.newOperation(PlayRun.class)
- .start(String.format("Run Play App at http://localhost:%d/", httpPort),
- String.format("Running at http://localhost:%d/ (stop with ctrl+d)", httpPort));
- waitForCtrlD();
- runnerToken.stop();
- } finally {
- progressLogger.completed();
+ try {
+ int httpPort = getHttpPort();
+ PlayRunSpec spec = new DefaultPlayRunSpec(runtimeClasspath, changingClasspath, applicationJar, assetsJar, assetsDirs, getProject().getProjectDir(), getForkOptions(), httpPort);
+ PlayApplicationRunnerToken runnerToken = playToolProvider.get(PlayApplicationRunner.class).start(spec);
+ deploymentHandle.start(runnerToken);
+ } finally {
+ progressLogger.completed();
+ }
+ }
+
+ if (!getProject().getGradle().getStartParameter().isContinuous()) {
+ ProgressLogger progressLogger = progressLoggerFactory.newOperation(PlayRun.class)
+ .start(String.format("Run Play App at http://localhost:%d/", httpPort),
+ String.format("Running at http://localhost:%d/", httpPort));
+ try {
+ waitForCtrlD();
+ } finally {
+ progressLogger.completed();
+ }
+ } else {
+ logger.warn(String.format("Running Play App (%s) at http://localhost:%d/", getPath(), httpPort));
}
}
@@ -109,6 +123,13 @@ public class PlayRun extends ConventionTask {
}
}
+ /**
+ * The HTTP port listened to by the Play application.
+ *
+ * This port should be available. The Play application will fail to start if the port is already in use.
+ *
+ * @return HTTP port
+ */
public int getHttpPort() {
return httpPort;
}
@@ -117,19 +138,63 @@ public class PlayRun extends ConventionTask {
this.httpPort = httpPort;
}
+ /**
+ * The Play application jar to run.
+ */
+ public File getApplicationJar() {
+ return applicationJar;
+ }
+
public void setApplicationJar(File applicationJar) {
this.applicationJar = applicationJar;
}
+ /**
+ * The assets jar to run with the Play application.
+ */
+ public File getAssetsJar() {
+ return assetsJar;
+ }
+
public void setAssetsJar(File assetsJar) {
this.assetsJar = assetsJar;
}
+ /**
+ * The directories of the assets for the Play application (for live reload functionality).
+ */
+ public Set<File> getAssetsDirs() {
+ return assetsDirs;
+ }
+
+ public void setAssetsDirs(Set<File> assetsDirs) {
+ this.assetsDirs = assetsDirs;
+ }
+
public void setRuntimeClasspath(FileCollection runtimeClasspath) {
this.runtimeClasspath = runtimeClasspath;
}
- public void setPlayApplicationRunnerTool(ResolvedTool<PlayApplicationRunner> playApplicationRunnerTool) {
- this.playApplicationRunnerTool = playApplicationRunnerTool;
+ public void setChangingClasspath(FileCollection changingClasspath) {
+ this.changingClasspath = changingClasspath;
+ }
+
+ public void setPlayToolProvider(PlayToolProvider playToolProvider) {
+ this.playToolProvider = playToolProvider;
+ }
+
+ @Inject
+ public DeploymentRegistry getDeploymentRegistry() {
+ throw new UnsupportedOperationException();
+ }
+
+ private PlayApplicationDeploymentHandle registerOrFindDeploymentHandle(String deploymentId) {
+ DeploymentRegistry deploymentRegistry = getDeploymentRegistry();
+ PlayApplicationDeploymentHandle deploymentHandle = deploymentRegistry.get(PlayApplicationDeploymentHandle.class, deploymentId);
+ if (deploymentHandle == null) {
+ deploymentHandle = new PlayApplicationDeploymentHandle(deploymentId);
+ deploymentRegistry.register(deploymentId, deploymentHandle);
+ }
+ return deploymentHandle;
}
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/RoutesCompile.java b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/RoutesCompile.java
index ba24632..31c16be 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/RoutesCompile.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/RoutesCompile.java
@@ -17,15 +17,18 @@
package org.gradle.play.tasks;
import org.gradle.api.Incubating;
+import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.SourceTask;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.compile.BaseForkOptions;
import org.gradle.language.base.internal.compile.Compiler;
-import org.gradle.platform.base.internal.toolchain.ResolvedTool;
+import org.gradle.platform.base.internal.toolchain.ToolProvider;
import org.gradle.play.internal.CleaningPlayToolCompiler;
import org.gradle.play.internal.routes.DefaultRoutesCompileSpec;
import org.gradle.play.internal.routes.RoutesCompileSpec;
+import org.gradle.play.internal.toolchain.PlayToolChainInternal;
+import org.gradle.play.platform.PlayPlatform;
import org.gradle.play.toolchain.PlayToolChain;
import javax.inject.Inject;
@@ -34,7 +37,12 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Task for compiling routes templates
+ * Task for compiling routes templates into Scala code.
+ * <p>
+ * This task is usually created as one of the build tasks when building a Play application with the {@link org.gradle.play.plugins.PlayPlugin} plugin.
+ *
+ * Explicit configuration of this task is not expected and should be performed on the equivalent settings at the {@link org.gradle.play.PlayApplicationSpec} level.
+ * </p>
*/
@Incubating
public class RoutesCompile extends SourceTask {
@@ -49,10 +57,11 @@ public class RoutesCompile extends SourceTask {
*/
private List<String> additionalImports = new ArrayList<String>();
- private boolean javaProject;
private boolean namespaceReverseRouter;
+ private boolean generateReverseRoutes = true;
+ private PlayPlatform platform;
private BaseForkOptions forkOptions;
- private ResolvedTool<Compiler<RoutesCompileSpec>> compilerTool;
+ private boolean injectedRoutesGenerator;
/**
* Returns the directory to generate the parser source files into.
@@ -74,34 +83,39 @@ public class RoutesCompile extends SourceTask {
}
/**
- * Specifies the additional imports of the Play Routes compiler.
+ * Returns the additional imports of the Play Routes compiler.
+ *
+ * @return The additional imports.
*/
+ @Input
public List<String> getAdditionalImports() {
return additionalImports;
}
/**
- * Returns the additional imports of the Play Routes compiler.
- *
- * @return The additional imports.
+ * Specifies the additional imports of the Play Routes compiler.
*/
public void setAdditionalImports(List<String> additionalImports) {
this.additionalImports.addAll(additionalImports);
}
-
@TaskAction
void compile() {
- RoutesCompileSpec spec = new DefaultRoutesCompileSpec(getSource().getFiles(), getOutputDirectory(), getForkOptions(), isJavaProject());
- new CleaningPlayToolCompiler<RoutesCompileSpec>(compilerTool.get(), getOutputs()).execute(spec);
+ RoutesCompileSpec spec = new DefaultRoutesCompileSpec(getSource().getFiles(), getOutputDirectory(), getForkOptions(), isJavaProject(), isNamespaceReverseRouter(), isGenerateReverseRoutes(), getInjectedRoutesGenerator(), getAdditionalImports());
+ new CleaningPlayToolCompiler<RoutesCompileSpec>(getCompiler(), getOutputs()).execute(spec);
}
- public void setCompilerTool(ResolvedTool<Compiler<RoutesCompileSpec>> compilerTool) {
- this.compilerTool = compilerTool;
+ private Compiler<RoutesCompileSpec> getCompiler() {
+ ToolProvider select = ((PlayToolChainInternal) getToolChain()).select(platform);
+ return select.newCompiler(RoutesCompileSpec.class);
}
public boolean isJavaProject() {
- return javaProject;
+ return false;
+ }
+
+ public void setPlatform(PlayPlatform platform) {
+ this.platform = platform;
}
/**
@@ -115,10 +129,67 @@ public class RoutesCompile extends SourceTask {
throw new UnsupportedOperationException();
}
+ /**
+ * The fork options to be applied to the Routes compiler.
+ *
+ * @return The fork options for the Routes compiler.
+ */
public BaseForkOptions getForkOptions() {
if (forkOptions == null) {
forkOptions = new BaseForkOptions();
}
return forkOptions;
}
+
+ /**
+ * Whether the reverse router should be namespaced.
+ */
+ @Input
+ public boolean isNamespaceReverseRouter() {
+ return namespaceReverseRouter;
+ }
+
+ /**
+ * Sets whether or not the reverse router should be namespaced.
+ */
+ public void setNamespaceReverseRouter(boolean namespaceReverseRouter) {
+ this.namespaceReverseRouter = namespaceReverseRouter;
+ }
+
+ /**
+ * Whether a reverse router should be generated. Default is true.
+ */
+ @Input
+ public boolean isGenerateReverseRoutes() {
+ return generateReverseRoutes;
+ }
+
+ /**
+ * Sets whether or not a reverse router should be generated.
+ */
+ public void setGenerateReverseRoutes(boolean generateReverseRoutes) {
+ this.generateReverseRoutes = generateReverseRoutes;
+ }
+
+ /**
+ * Is the injected routes generator (<code>play.routes.compiler.InjectedRoutesGenerator</code>) used for
+ * generating routes? Default is false.
+ *
+ * @return false if StaticRoutesGenerator will be used to generate routes,
+ * true if InjectedRoutesGenerator will be used to generate routes.
+ */
+ @Input
+ public boolean getInjectedRoutesGenerator() {
+ return injectedRoutesGenerator;
+ }
+
+ /**
+ * Configure if the injected routes generator should be used to generate routes.
+ *
+ * @param injectedRoutesGenerator false - use StaticRoutesGenerator
+ * true - use InjectedRoutesGenerator
+ */
+ public void setInjectedRoutesGenerator(boolean injectedRoutesGenerator) {
+ this.injectedRoutesGenerator = injectedRoutesGenerator;
+ }
}
diff --git a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/TwirlCompile.java b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/TwirlCompile.java
index 2250cf1..2718e1d 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/play/tasks/TwirlCompile.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/play/tasks/TwirlCompile.java
@@ -30,18 +30,23 @@ import org.gradle.api.tasks.compile.BaseForkOptions;
import org.gradle.api.tasks.incremental.IncrementalTaskInputs;
import org.gradle.api.tasks.incremental.InputFileDetails;
import org.gradle.language.base.internal.compile.Compiler;
-import org.gradle.platform.base.internal.toolchain.ResolvedTool;
+import org.gradle.platform.base.internal.toolchain.ToolProvider;
import org.gradle.play.internal.CleaningPlayToolCompiler;
+import org.gradle.play.internal.toolchain.PlayToolChainInternal;
import org.gradle.play.internal.twirl.DefaultTwirlCompileSpec;
import org.gradle.play.internal.twirl.TwirlCompileSpec;
+import org.gradle.play.internal.twirl.TwirlCompilerFactory;
+import org.gradle.play.platform.PlayPlatform;
+import org.gradle.play.toolchain.PlayToolChain;
+import javax.inject.Inject;
import java.io.File;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
- * Task for compiling twirl templates
+ * Task for compiling Twirl templates into Scala code.
*/
@Incubating
public class TwirlCompile extends SourceTask {
@@ -50,10 +55,10 @@ public class TwirlCompile extends SourceTask {
* Target directory for the compiled template files.
*/
private File outputDirectory;
+
private BaseForkOptions forkOptions;
- private ResolvedTool<Compiler<TwirlCompileSpec>> compilerTool;
private TwirlStaleOutputCleaner cleaner;
- private Object dependencyNotation;
+ private PlayPlatform platform;
/**
* fork options for the twirl compiler.
@@ -65,10 +70,6 @@ public class TwirlCompile extends SourceTask {
return forkOptions;
}
- public void setCompilerTool(ResolvedTool<Compiler<TwirlCompileSpec>> compilerTool) {
- this.compilerTool = compilerTool;
- }
-
/**
* Returns the directory to generate the parser source files into.
*
@@ -81,11 +82,7 @@ public class TwirlCompile extends SourceTask {
@Input
public Object getDependencyNotation() {
- return dependencyNotation;
- }
-
- public void setDependencyNotation(Object dependencyNotation) {
- this.dependencyNotation = dependencyNotation;
+ return TwirlCompilerFactory.createAdapter(platform).getDependencyNotation();
}
/**
@@ -103,7 +100,7 @@ public class TwirlCompile extends SourceTask {
getSource().visit(relativeFileCollector);
TwirlCompileSpec spec = new DefaultTwirlCompileSpec(relativeFileCollector.relativeFiles, getOutputDirectory(), getForkOptions(), useJavaDefaults());
if (!inputs.isIncremental()) {
- new CleaningPlayToolCompiler<TwirlCompileSpec>(compilerTool.get(), getOutputs()).execute(spec);
+ new CleaningPlayToolCompiler<TwirlCompileSpec>(getCompiler(), getOutputs()).execute(spec);
} else {
final Set<File> sourcesToCompile = new HashSet<File>();
inputs.outOfDate(new Action<InputFileDetails>() {
@@ -122,10 +119,15 @@ public class TwirlCompile extends SourceTask {
cleaner = new TwirlStaleOutputCleaner(getOutputDirectory());
}
cleaner.execute(staleOutputFiles);
- compilerTool.get().execute(spec);
+ getCompiler().execute(spec);
}
}
+ private Compiler<TwirlCompileSpec> getCompiler() {
+ ToolProvider toolProvider = ((PlayToolChainInternal) getToolChain()).select(platform);
+ return toolProvider.newCompiler(TwirlCompileSpec.class);
+ }
+
private boolean useJavaDefaults() {
return false; //TODO: add this as a configurable parameter
}
@@ -134,6 +136,33 @@ public class TwirlCompile extends SourceTask {
this.cleaner = cleaner;
}
+ public void setPlatform(PlayPlatform platform) {
+ this.platform = platform;
+ }
+
+ /**
+ * Returns the tool chain that will be used to compile the twirl source.
+ *
+ * @return The tool chain.
+ */
+ @Incubating
+ @Inject
+ public PlayToolChain getToolChain() {
+ // Implementation is generated
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets the tool chain that will be used to compile the twirl source.
+ *
+ * @param toolChain The tool chain.
+ */
+ @Incubating
+ public void setToolChain(PlayToolChain toolChain) {
+ // Implementation is generated
+ throw new UnsupportedOperationException();
+ }
+
private static class TwirlStaleOutputCleaner {
private final File destinationDir;
diff --git a/subprojects/platform-play/src/main/java/org/gradle/scala/internal/reflect/ScalaMethod.java b/subprojects/platform-play/src/main/java/org/gradle/scala/internal/reflect/ScalaMethod.java
index 46d8b2d..63e810e 100644
--- a/subprojects/platform-play/src/main/java/org/gradle/scala/internal/reflect/ScalaMethod.java
+++ b/subprojects/platform-play/src/main/java/org/gradle/scala/internal/reflect/ScalaMethod.java
@@ -18,7 +18,6 @@ package org.gradle.scala.internal.reflect;
import org.gradle.api.GradleException;
import org.gradle.internal.UncheckedException;
-import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -27,14 +26,16 @@ public class ScalaMethod {
private final Method method;
private final Object instance;
- public ScalaMethod(ClassLoader classLoader, String className, String methodName, Class<?>... typeParameters) {
- description = String.format("%s.%s()", className, methodName);
- Class<?> baseClass = getClass(classLoader, className);
- final Field scalaObject = getModule(baseClass);
- instance = getInstance(scalaObject);
+ public ScalaMethod(ScalaObject scalaObject, String methodName, Class<?>... typeParameters) {
+ description = String.format("%s.%s()", scalaObject.getClassName(), methodName);
+ instance = scalaObject.getInstance();
method = getMethod(scalaObject.getType(), methodName, typeParameters);
}
+ public ScalaMethod(ClassLoader classLoader, String className, String methodName, Class<?>... typeParameters) {
+ this(new ScalaObject(classLoader, className), methodName, typeParameters);
+ }
+
private Method getMethod(Class<?> type, String methodName, Class<?>[] typeParameters) {
try {
return type.getMethod(methodName, typeParameters);
@@ -43,30 +44,6 @@ public class ScalaMethod {
}
}
- private Object getInstance(Field scalaObject) {
- try {
- return scalaObject.get(null);
- } catch (IllegalAccessException e) {
- throw UncheckedException.throwAsUncheckedException(e);
- }
- }
-
- private Class<?> getClass(ClassLoader classLoader, String typeName) {
- try {
- return classLoader.loadClass(typeName + "$");
- } catch (ClassNotFoundException e) {
- throw UncheckedException.throwAsUncheckedException(e);
- }
- }
-
- private Field getModule(Class<?> baseClass) {
- try {
- return baseClass.getField("MODULE$");
- } catch (NoSuchFieldException e) {
- throw UncheckedException.throwAsUncheckedException(e);
- }
- }
-
public Object invoke(Object... args) {
try {
return method.invoke(instance, args);
diff --git a/subprojects/platform-play/src/main/java/org/gradle/scala/internal/reflect/ScalaObject.java b/subprojects/platform-play/src/main/java/org/gradle/scala/internal/reflect/ScalaObject.java
new file mode 100644
index 0000000..fc04da9
--- /dev/null
+++ b/subprojects/platform-play/src/main/java/org/gradle/scala/internal/reflect/ScalaObject.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.scala.internal.reflect;
+
+import org.gradle.internal.UncheckedException;
+
+import java.lang.reflect.Field;
+
+public class ScalaObject {
+ private final Object instance;
+ private final Class<?> type;
+ private final String className;
+
+ public ScalaObject(ClassLoader classLoader, String className) {
+ this.className = className;
+ Class<?> baseClass = getClass(classLoader, className);
+ final Field scalaObject = getModule(baseClass);
+ instance = getInstance(scalaObject);
+ type = scalaObject.getType();
+ }
+
+ private Object getInstance(Field scalaObject) {
+ try {
+ return scalaObject.get(null);
+ } catch (IllegalAccessException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+
+ private Class<?> getClass(ClassLoader classLoader, String typeName) {
+ try {
+ return classLoader.loadClass(typeName + "$");
+ } catch (ClassNotFoundException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+
+ private Field getModule(Class<?> baseClass) {
+ try {
+ return baseClass.getField("MODULE$");
+ } catch (NoSuchFieldException e) {
+ throw UncheckedException.throwAsUncheckedException(e);
+ }
+ }
+
+ public Object getInstance() {
+ return instance;
+ }
+
+ public Class<?> getType() {
+ return type;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+}
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayApplicationBinarySpecTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayApplicationBinarySpecTest.groovy
index 037f4c9..8a4e3f4 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayApplicationBinarySpecTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayApplicationBinarySpecTest.groovy
@@ -15,13 +15,13 @@
*/
package org.gradle.play.internal
-
import org.gradle.api.internal.project.taskfactory.ITaskFactory
import org.gradle.internal.reflect.DirectInstantiator
import org.gradle.platform.base.binary.BaseBinarySpec
import org.gradle.platform.base.internal.BinaryBuildAbility
-import org.gradle.platform.base.internal.toolchain.ToolResolver
-import org.gradle.platform.base.internal.toolchain.ToolSearchResult
+import org.gradle.play.internal.toolchain.PlayToolChainInternal
+import org.gradle.play.internal.toolchain.PlayToolProvider
+import org.gradle.play.platform.PlayPlatform
import org.gradle.util.TreeVisitor
import spock.lang.Specification
@@ -29,15 +29,16 @@ class DefaultPlayApplicationBinarySpecTest extends Specification {
PlayApplicationBinarySpecInternal playBinary = BaseBinarySpec.create(DefaultPlayApplicationBinarySpec.class, "test", DirectInstantiator.INSTANCE, Stub(ITaskFactory))
def "sets binary build ability for unavailable toolchain" () {
- ToolSearchResult result = Mock(ToolSearchResult) {
+ PlayToolProvider result = Mock(PlayToolProvider) {
isAvailable() >> false
}
- ToolResolver toolResolver = Mock(ToolResolver) {
- checkToolAvailability(_) >> result
- }
- playBinary.setToolResolver(toolResolver)
+ def toolChain = Mock(PlayToolChainInternal)
+ def platform = Mock(PlayPlatform)
+ toolChain.select(platform) >> result
when:
+ playBinary.setToolChain(toolChain)
+ playBinary.setTargetPlatform(platform)
BinaryBuildAbility buildAbility = playBinary.getBuildAbility()
then:
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayToolChainTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayToolChainTest.groovy
index 8f6df93..f6f83ed 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayToolChainTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/DefaultPlayToolChainTest.groovy
@@ -43,7 +43,7 @@ class DefaultPlayToolChainTest extends Specification {
def toolChain = new DefaultPlayToolChain(fileResolver, compilerDaemonManager, configurationContainer, dependencyHandler, workerProcessBuilderFactory)
def setup() {
- playPlatform.playVersion >> "2.3.7"
+ playPlatform.playVersion >> DefaultPlayPlatform.DEFAULT_PLAY_VERSION
playPlatform.scalaPlatform >> Stub(ScalaPlatform) {
getScalaCompatibilityVersion() >> "2.10"
}
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/PlayPlatformResolverTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/PlayPlatformResolverTest.groovy
index a2f5b38..a2d45f7 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/PlayPlatformResolverTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/PlayPlatformResolverTest.groovy
@@ -44,7 +44,7 @@ class PlayPlatformResolverTest extends Specification {
then:
def e = thrown(InvalidUserDataException)
- e.message == "Not a supported Play version: 2.1.0. This plugin is compatible with: [2.3.x, 2.2.x]."
+ e.message == "Not a supported Play version: 2.1.0. This plugin is compatible with: [2.4.x, 2.3.x, 2.2.x]."
where:
requirement << ["play-2.1.0", [play: '2.1.0']]
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/run/PlayApplicationDeploymentHandleTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/run/PlayApplicationDeploymentHandleTest.groovy
new file mode 100644
index 0000000..8741537
--- /dev/null
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/run/PlayApplicationDeploymentHandleTest.groovy
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.internal.run
+
+import org.gradle.BuildListener
+import org.gradle.BuildResult
+import org.gradle.api.invocation.Gradle
+import spock.lang.Specification
+
+
+class PlayApplicationDeploymentHandleTest extends Specification {
+ def PlayApplicationRunnerToken runnerToken = Mock(PlayApplicationRunnerToken)
+ def PlayApplicationDeploymentHandle deploymentHandle = new PlayApplicationDeploymentHandle("test")
+ def Gradle gradle = Mock(Gradle)
+ def failure = new Throwable()
+ def BuildResult goodBuild = new BuildResult(gradle, null)
+ def BuildResult badBuild = new BuildResult(gradle, failure)
+
+ def "reloading deployment handle reloads runner" () {
+ when:
+ deploymentHandle.start(runnerToken)
+ deploymentHandle.reloadFromResult(goodBuild)
+
+ then:
+ 1 * runnerToken.isRunning() >> true
+ 1 * runnerToken.rebuildSuccess()
+
+ when:
+ deploymentHandle.reloadFromResult(badBuild)
+
+ then:
+ 1 * runnerToken.isRunning() >> true
+ 1 * runnerToken.rebuildFailure(failure)
+
+ }
+
+ def "stopping deployment handle stops runner" () {
+ when:
+ deploymentHandle.start(runnerToken)
+ deploymentHandle.stop()
+
+ then:
+ 1 * runnerToken.isRunning() >> true
+ 1 * runnerToken.stop()
+ }
+
+ def "cannot reload a stopped deployment handle" () {
+ given:
+ runnerToken.isRunning() >> false
+ deploymentHandle.start(runnerToken)
+
+ when:
+ deploymentHandle.reloadFromResult(goodBuild)
+
+ then:
+ 0 * runnerToken.rebuildSuccess()
+
+ when:
+ deploymentHandle.reloadFromResult(badBuild)
+
+ then:
+ 0 * runnerToken.rebuildFailure(_)
+ }
+
+ def "cannot reload a deployment handle that was never started" () {
+ when:
+ deploymentHandle.reloadFromResult(goodBuild)
+ then:
+ 0 * runnerToken.rebuildFailure(_)
+
+ when:
+ deploymentHandle.reloadFromResult(badBuild)
+ then:
+ 0 * runnerToken.rebuildSuccess()
+ }
+
+ def "registers for build finished events" () {
+ when:
+ deploymentHandle.onNewBuild(gradle)
+ then:
+ 1 * gradle.addBuildListener({ it instanceof BuildListener })
+ }
+
+}
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/run/PlayApplicationRunnerTokenTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/run/PlayApplicationRunnerTokenTest.groovy
new file mode 100644
index 0000000..f2e8903
--- /dev/null
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/run/PlayApplicationRunnerTokenTest.groovy
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.internal.run
+
+import org.gradle.process.internal.WorkerProcess
+import spock.lang.Specification
+
+class PlayApplicationRunnerTokenTest extends Specification {
+
+ def process = Mock(WorkerProcess)
+ def client = Mock(PlayWorkerClient)
+ def server = Mock(PlayRunWorkerServerProtocol)
+ def runnerToken = new PlayApplicationRunnerToken(server, client, process)
+
+ def "stops all participants when stopped"() {
+ when:
+ runnerToken.stop()
+
+ then:
+ 1 * server.stop()
+ 1 * client.waitForStop()
+ 1 * process.waitForStop()
+ }
+
+ def "rebuildSuccess sends successful build result to server"() {
+ when:
+ runnerToken.rebuildSuccess()
+
+ then:
+ 1 * server.reload()
+ }
+
+ def "rebuildFailure sends failure build result to server"() {
+ given:
+ def failure = new Throwable()
+ when:
+ runnerToken.rebuildFailure(failure)
+
+ then:
+ 1 * server.buildError(failure)
+ }
+}
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/toolchain/DefaultPlayToolProviderTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/toolchain/DefaultPlayToolProviderTest.groovy
index b49a582..485c4e7 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/toolchain/DefaultPlayToolProviderTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/internal/toolchain/DefaultPlayToolProviderTest.groovy
@@ -15,6 +15,7 @@
*/
package org.gradle.play.internal.toolchain
+
import org.gradle.api.InvalidUserDataException
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.dsl.DependencyHandler
@@ -22,10 +23,8 @@ import org.gradle.api.internal.file.FileResolver
import org.gradle.api.internal.tasks.compile.daemon.CompilerDaemonManager
import org.gradle.language.base.internal.compile.CompileSpec
import org.gradle.language.scala.ScalaPlatform
-import org.gradle.play.internal.run.PlayApplicationRunner
-import org.gradle.play.internal.run.PlayRunAdapterV22X
-import org.gradle.play.internal.run.PlayRunAdapterV23X
-import org.gradle.play.internal.run.PlayRunSpec
+import org.gradle.play.internal.DefaultPlayPlatform
+import org.gradle.play.internal.run.*
import org.gradle.play.platform.PlayPlatform
import org.gradle.process.internal.WorkerProcessBuilder
import spock.lang.Specification
@@ -52,43 +51,41 @@ class DefaultPlayToolProviderTest extends Specification {
_ * playPlatform.getPlayVersion() >> playVersion
when:
- playToolProvider = new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, configurationContainer, dependencyHandler, workerProcessBuilderFactory, playPlatform, twirlClasspath, routesClasspath, javascriptClasspath)
+ playToolProvider = new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, workerProcessBuilderFactory, playPlatform, twirlClasspath, routesClasspath, javascriptClasspath)
def runner = playToolProvider.get(PlayApplicationRunner.class)
then:
runner != null
runner.adapter.class == adapter
- and:
- 1 * fileResolver.resolve('.') >> new File(".")
-
where:
playVersion | adapter
"2.2.x" | PlayRunAdapterV22X
"2.3.x" | PlayRunAdapterV23X
+ "2.4.x" | PlayRunAdapterV24X
}
def "cannot create tool provider for unsupported play versions"() {
when:
_ * playPlatform.getPlayVersion() >> playVersion
- playToolProvider = new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, configurationContainer, dependencyHandler, workerProcessBuilderFactory, playPlatform, twirlClasspath, routesClasspath, javascriptClasspath)
+ playToolProvider = new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, workerProcessBuilderFactory, playPlatform, twirlClasspath, routesClasspath, javascriptClasspath)
then: "fails with meaningful error message"
def exception = thrown(InvalidUserDataException)
- exception.message == "Not a supported Play version: ${playVersion}. This plugin is compatible with: [2.3.x, 2.2.x]."
+ exception.message == "Not a supported Play version: ${playVersion}. This plugin is compatible with: [2.4.x, 2.3.x, 2.2.x]."
and: "no dependencies resolved"
0 * dependencyHandler.create(_)
0 * configurationContainer.detachedConfiguration(_)
where:
- playVersion << ["2.1.x", "2.4.x", "3.0.0"]
+ playVersion << ["2.1.x", "2.5.x", "3.0.0"]
}
def "newCompiler provides decent error for unsupported CompileSpec"() {
setup:
- _ * playPlatform.getPlayVersion() >> "2.3.7"
- playToolProvider = new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, configurationContainer, dependencyHandler, workerProcessBuilderFactory, playPlatform, twirlClasspath, routesClasspath, javascriptClasspath)
+ _ * playPlatform.getPlayVersion() >> DefaultPlayPlatform.DEFAULT_PLAY_VERSION
+ playToolProvider = new DefaultPlayToolProvider(fileResolver, compilerDaemonManager, workerProcessBuilderFactory, playPlatform, twirlClasspath, routesClasspath, javascriptClasspath)
when:
playToolProvider.newCompiler(UnknownCompileSpec.class)
@@ -98,6 +95,7 @@ class DefaultPlayToolProviderTest extends Specification {
ex.message == "Cannot create Compiler for unsupported CompileSpec type 'UnknownCompileSpec'"
}
+ class UnknownCompileSpec implements CompileSpec {}
}
-class UnknownCompileSpec implements CompileSpec {}
+
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginTest.groovy
index cc39c09..ba5135d 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayCoffeeScriptPluginTest.groovy
@@ -15,10 +15,8 @@
*/
package org.gradle.play.plugins
-
import org.gradle.api.Action
import org.gradle.api.file.SourceDirectorySet
-import org.gradle.language.base.FunctionalSourceSet
import org.gradle.language.coffeescript.CoffeeScriptSourceSet
import org.gradle.model.ModelMap
import org.gradle.platform.base.internal.ComponentSpecInternal
@@ -29,25 +27,28 @@ class PlayCoffeeScriptPluginTest extends Specification {
def "adds coffeescript source sets to play components" () {
def plugin = new PlayCoffeeScriptPlugin()
def components = Mock(ModelMap)
- def sources = Mock(FunctionalSourceSet)
+ def sources = Mock(ModelMap)
def sourceSet = Mock(CoffeeScriptSourceSet)
def sourceDirSet = Mock(SourceDirectorySet)
when:
- def playApp = Stub(PlayAppInternal) {
+ def playApp = Stub(PlayApplicationSpec) {
getName() >> "play"
getSources() >> sources
}
_ * components.beforeEach(_) >> { Action a -> a.execute(playApp) }
+ _ * sourceSet.getSource() >> sourceDirSet
and:
plugin.createCoffeeScriptSourceSets(components)
then:
- 1 * sources.create("coffeeScriptAssets", CoffeeScriptSourceSet) >> sourceSet
- 2 * sourceSet.getSource() >> sourceDirSet
+ 1 * sources.create("coffeeScript", CoffeeScriptSourceSet, _ as Action) >> {
+ String name, Class type, Action a -> a.execute(sourceSet)
+ }
1 * sourceDirSet.srcDir("app/assets")
1 * sourceDirSet.include("**/*.coffee")
+ 0 * _._
}
interface PlayAppInternal extends PlayApplicationSpec, ComponentSpecInternal {}
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayDistributionPluginTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayDistributionPluginTest.groovy
index b0d6477..361da33 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayDistributionPluginTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayDistributionPluginTest.groovy
@@ -180,7 +180,6 @@ class PlayDistributionPluginTest extends Specification {
1 * tasks.create("createPlayBinaryDist", Zip, _) >> { String name, Class type, Action action ->
action.execute(Mock(Zip) {
1 * setDescription(_)
- 1 * setGroup(_)
1 * setDestinationDir(_)
1 * setArchiveName("playBinary.zip")
1 * from(_ as Copy)
@@ -189,7 +188,6 @@ class PlayDistributionPluginTest extends Specification {
1 * tasks.create("stagePlayBinaryDist", Copy, _) >> { String name, Class type, Action action ->
action.execute(Mock(Copy) {
1 * setDescription(_)
- 1 * setGroup(_)
1 * setDestinationDir(_)
1 * getRootSpec() >> Mock(DestinationRootCopySpec) {
1 * addChild() >> Mock(CopySpecInternal) {
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayJavaScriptPluginTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayJavaScriptPluginTest.groovy
index 63c905b..b292c79 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayJavaScriptPluginTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayJavaScriptPluginTest.groovy
@@ -15,10 +15,8 @@
*/
package org.gradle.play.plugins
-
import org.gradle.api.Action
import org.gradle.api.file.SourceDirectorySet
-import org.gradle.language.base.FunctionalSourceSet
import org.gradle.language.javascript.JavaScriptSourceSet
import org.gradle.model.ModelMap
import org.gradle.platform.base.internal.ComponentSpecInternal
@@ -29,7 +27,7 @@ class PlayJavaScriptPluginTest extends Specification {
def "adds javaScript source sets to play components" () {
def plugin = new PlayJavaScriptPlugin()
def components = Mock(ModelMap)
- def sources = Mock(FunctionalSourceSet)
+ def sources = Mock(ModelMap)
def sourceSet = Mock(JavaScriptSourceSet)
def sourceDirSet = Mock(SourceDirectorySet)
@@ -39,15 +37,18 @@ class PlayJavaScriptPluginTest extends Specification {
getSources() >> sources
}
_ * components.beforeEach(_) >> { Action a -> a.execute(playApp) }
+ _ * sourceSet.getSource() >> sourceDirSet
and:
plugin.createJavascriptSourceSets(components)
then:
- 1 * sources.create("javaScriptAssets", JavaScriptSourceSet) >> sourceSet
- 2 * sourceSet.getSource() >> sourceDirSet
+ 1 * sources.create("javaScript", JavaScriptSourceSet, _ as Action) >> {
+ String name, Class type, Action a -> a.execute(sourceSet)
+ }
1 * sourceDirSet.srcDir("app/assets")
1 * sourceDirSet.include("**/*.js")
+ 0 * _._
}
interface PlayAppInternal extends PlayApplicationSpec, ComponentSpecInternal {}
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayTestPluginTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayTestPluginTest.groovy
index b924bf6..aae0c5a 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayTestPluginTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/plugins/PlayTestPluginTest.groovy
@@ -66,6 +66,10 @@ class PlayTestPluginTest extends Specification {
def fileResolver = Mock(FileResolver)
1 * fileResolver.resolve('test') >> new File('test')
+ 1 * binary.getTargetPlatform() >> playPlatform
+ 1 * binary.getToolChain() >> playToolChain
+ 1 * playToolChain.select(playPlatform) >> playToolProvider
+
when:
plugin.createTestTasks(taskModelMap, binaryContainer, new PlayPluginConfigurations(configurations, dependencyHandler), fileResolver, projectIdentifier, buildDir)
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/PlayRunTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/PlayRunTest.groovy
index 7205036..b56c010 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/PlayRunTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/PlayRunTest.groovy
@@ -15,12 +15,11 @@
*/
package org.gradle.play.tasks
-
import org.gradle.api.internal.file.collections.SimpleFileCollection
-import org.gradle.platform.base.internal.toolchain.ResolvedTool
import org.gradle.play.internal.run.PlayApplicationRunner
import org.gradle.play.internal.run.PlayApplicationRunnerToken
import org.gradle.play.internal.run.PlayRunSpec
+import org.gradle.play.internal.toolchain.PlayToolProvider
import org.gradle.util.RedirectStdIn
import org.gradle.util.TestUtil
import org.junit.ClassRule
@@ -28,12 +27,9 @@ import spock.lang.Shared
import spock.lang.Specification
class PlayRunTest extends Specification {
-
PlayApplicationRunnerToken runnerToken = Mock(PlayApplicationRunnerToken)
+ PlayToolProvider playToolProvider = Mock(PlayToolProvider)
PlayApplicationRunner playApplicationRunner = Mock(PlayApplicationRunner)
- ResolvedTool<PlayApplicationRunner> playApplicationRunnerTool = Mock(ResolvedTool) {
- get() >> playApplicationRunner
- }
InputStream systemInputStream = Mock()
@Shared @ClassRule
@@ -45,7 +41,7 @@ class PlayRunTest extends Specification {
playRun = TestUtil.createTask(PlayRun)
playRun.applicationJar = new File("application.jar")
playRun.runtimeClasspath = new SimpleFileCollection()
- playRun.playApplicationRunnerTool = playApplicationRunnerTool
+ playRun.playToolProvider = playToolProvider
System.in = systemInputStream
}
@@ -55,8 +51,9 @@ class PlayRunTest extends Specification {
playRun.forkOptions.memoryInitialSize = "1G"
playRun.forkOptions.memoryMaximumSize = "5G"
when:
- playRun.execute();
+ playRun.run();
then:
+ 1 * playToolProvider.get(PlayApplicationRunner) >> playApplicationRunner
1 * playApplicationRunner.start(_) >> { PlayRunSpec spec ->
assert spec.getForkOptions().memoryInitialSize == "1G"
assert spec.getForkOptions().memoryMaximumSize == "5G"
@@ -67,22 +64,12 @@ class PlayRunTest extends Specification {
def "passes forkOptions never null"() {
1 * systemInputStream.read() >> 4
when:
- playRun.execute();
+ playRun.run();
then:
+ 1 * playToolProvider.get(PlayApplicationRunner) >> playApplicationRunner
1 * playApplicationRunner.start(_) >> { PlayRunSpec spec ->
assert spec.getForkOptions() != null
runnerToken
}
}
-
- def "stops application after receiving ctrl+d"() {
- 1 * systemInputStream.read() >> {
- 1 * runnerToken.stop()
- return 4
- }
- when:
- playRun.execute();
- then:
- 1 * playApplicationRunner.start(_) >> runnerToken
- }
}
diff --git a/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/TwirlCompileTest.groovy b/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/TwirlCompileTest.groovy
index 977bea1..f1f0013 100644
--- a/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/TwirlCompileTest.groovy
+++ b/subprojects/platform-play/src/test/groovy/org/gradle/play/tasks/TwirlCompileTest.groovy
@@ -20,25 +20,34 @@ import org.gradle.api.internal.TaskExecutionHistory
import org.gradle.api.internal.project.DefaultProject
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.api.tasks.incremental.InputFileDetails
-import org.gradle.platform.base.internal.toolchain.ResolvedTool
+import org.gradle.language.base.internal.compile.Compiler
+import org.gradle.play.internal.toolchain.PlayToolChainInternal
+import org.gradle.play.internal.toolchain.PlayToolProvider
import org.gradle.play.internal.twirl.TwirlCompileSpec
+import org.gradle.play.platform.PlayPlatform
import org.gradle.util.TestUtil
import spock.lang.Specification
-import org.gradle.language.base.internal.compile.Compiler
class TwirlCompileTest extends Specification {
DefaultProject project = TestUtil.createRootProject()
- TwirlCompile compile = project.tasks.create("twirlCompile", TwirlCompile)
+ TwirlCompile compile = project.tasks.create("compile", TwirlCompile)
Compiler<TwirlCompileSpec> twirlCompiler = Mock(Compiler)
- ResolvedTool<Compiler<TwirlCompileSpec>> twirlCompilerTool = Mock(ResolvedTool) {
- get() >> twirlCompiler
- }
IncrementalTaskInputs taskInputs = Mock(IncrementalTaskInputs)
+ def setup() {
+ def toolChain = Mock(PlayToolChainInternal)
+ def platform = Mock(PlayPlatform)
+ def toolProvider = Mock(PlayToolProvider)
+ toolChain.select(platform) >> toolProvider
+ toolProvider.newCompiler(TwirlCompileSpec) >> twirlCompiler
+
+ compile.toolChain = toolChain
+ compile.platform = platform
+ }
+
def "invokes twirl compiler"(){
given:
def outputDir = Mock(File);
- compile.compilerTool = twirlCompilerTool
compile.outputDirectory = outputDir
compile.outputs.history = Stub(TaskExecutionHistory)
when:
@@ -55,7 +64,6 @@ class TwirlCompileTest extends Specification {
def "deletes stale output files"(){
given:
def outputDir = new File("outputDir");
- compile.compilerTool = twirlCompilerTool
compile.outputDirectory = outputDir
def outputCleaner = Spy(TwirlCompile.TwirlStaleOutputCleaner, constructorArgs: [outputDir])
compile.setCleaner(outputCleaner)
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractMultiVersionPlayContinuousBuildIntegrationTest.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractMultiVersionPlayContinuousBuildIntegrationTest.groovy
new file mode 100644
index 0000000..f426403
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractMultiVersionPlayContinuousBuildIntegrationTest.groovy
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.api.JavaVersion
+import org.gradle.integtests.fixtures.MultiVersionSpecRunner
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.util.VersionNumber
+import org.junit.runner.RunWith
+
+ at RunWith(MultiVersionSpecRunner)
+ at TargetCoverage({ JavaVersion.current().isJava8Compatible() ? PlayCoverage.ALL : PlayCoverage.PLAY23_OR_EARLIER })
+abstract class AbstractMultiVersionPlayContinuousBuildIntegrationTest extends AbstractPlayContinuousBuildIntegrationTest {
+ static def version
+
+ static VersionNumber getVersionNumber() {
+ VersionNumber.parse(version.toString())
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractMultiVersionPlayReloadIntegrationTest.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractMultiVersionPlayReloadIntegrationTest.groovy
new file mode 100644
index 0000000..2accfa3
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractMultiVersionPlayReloadIntegrationTest.groovy
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.api.JavaVersion
+import org.gradle.integtests.fixtures.TargetCoverage
+
+ at TargetCoverage({ JavaVersion.current().isJava8Compatible() ? PlayCoverage.PLAY23_OR_LATER : PlayCoverage.PLAY23 })
+abstract class AbstractMultiVersionPlayReloadIntegrationTest extends AbstractMultiVersionPlayContinuousBuildIntegrationTest {
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractPlayContinuousBuildIntegrationTest.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractPlayContinuousBuildIntegrationTest.groovy
new file mode 100644
index 0000000..1c0a452
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AbstractPlayContinuousBuildIntegrationTest.groovy
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.integtests.fixtures.executer.ExecutionResult
+import org.gradle.launcher.continuous.Java7RequiringContinuousIntegrationTest
+import org.gradle.play.integtest.fixtures.app.PlayApp
+import org.gradle.test.fixtures.file.TestFile
+
+abstract class AbstractPlayContinuousBuildIntegrationTest extends Java7RequiringContinuousIntegrationTest {
+ abstract PlayApp getPlayApp()
+ abstract RunningPlayApp getRunningApp()
+
+ def setup() {
+ writeSources()
+ buildTimeout = 90
+ }
+
+ TestFile getPlayRunBuildFile() {
+ buildFile
+ }
+
+ def writeSources() {
+ playApp.writeSources(testDirectory)
+
+ playRunBuildFile << """
+ model {
+ tasks.runPlayBinary {
+ httpPort = 0
+ }
+ }
+ """
+
+ settingsFile << """
+ rootProject.name = '${playApp.name}'
+ """
+ }
+
+ void appIsRunningAndDeployed() {
+ runningApp.initialize(gradle)
+ runningApp.verifyStarted()
+ runningApp.verifyContent()
+ }
+
+ void appIsStopped() {
+ runningApp.verifyStopped()
+ }
+
+ @Override
+ protected ExecutionResult succeeds(String... tasks) {
+ executer.withArguments("--info")
+ return super.succeeds(tasks)
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AdvancedRunningPlayApp.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AdvancedRunningPlayApp.groovy
new file mode 100644
index 0000000..5edcf9b
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/AdvancedRunningPlayApp.groovy
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.test.fixtures.file.TestFile
+
+import static org.gradle.integtests.fixtures.UrlValidator.*
+
+class AdvancedRunningPlayApp extends RunningPlayApp {
+ AdvancedRunningPlayApp(TestFile testDirectory) {
+ super(testDirectory)
+ }
+
+ @Override
+ void verifyContent() {
+ super.verifyContent()
+
+ // Custom Routes
+ assert playUrl().text.contains("<li>foo:1</li>")
+ assert playUrl("root").text.contains("<li>bar:2</li>")
+ assert playUrl("java/one").text.contains("Your new application is ready.")
+ assert playUrl("scala/one").text.contains("<li>foo:1</li>")
+
+ // Custom Assets
+ assertUrlContent playUrl("assets/javascripts/test.js"), testDirectory.file("app/assets/javascripts/sample.js")
+ assertUrlContent playUrl("assets/javascripts/sample.js"), testDirectory.file("app/assets/javascripts/sample.js")
+ assertUrlContent playUrl("assets/javascripts/test.min.js"), minifiedSample
+ assertUrlContent playUrl("assets/javascripts/sample.min.js"), minifiedSample
+ }
+
+ static String getMinifiedSample() {
+ return "(function(){var c,e,f,b;b=function(a){return a*a};c=[1,2,3,4,5];e={root:Math.sqrt,square:b,cube:function(a){return a*b(a)}};\"undefined\"!==typeof elvis&&null!==elvis&&alert(\"I knew it!\");(function(){var a,b,d;d=[];a=0;for(b=c.length;a<b;a++)f=c[a],d.push(e.cube(f));return d})()}).call(this);"
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/DistributionTestExecHandleBuilder.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/DistributionTestExecHandleBuilder.groovy
new file mode 100644
index 0000000..ca8610e
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/DistributionTestExecHandleBuilder.groovy
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+import com.google.common.collect.Lists
+import org.apache.commons.io.output.CloseShieldOutputStream
+import org.apache.commons.io.output.TeeOutputStream
+import org.gradle.internal.os.OperatingSystem
+import org.gradle.process.internal.ExecHandle
+import org.gradle.process.internal.ExecHandleBuilder
+import org.gradle.test.fixtures.ConcurrentTestUtil
+
+class DistributionTestExecHandleBuilder extends ExecHandleBuilder {
+ final String port
+
+ DistributionTestExecHandleBuilder(String port, String baseDirName) {
+ super()
+ this.port = port
+
+ def extension = ""
+ if (OperatingSystem.current().windows) {
+ extension = ".bat"
+ }
+
+ this.setExecutable("${baseDirName}/playBinary/bin/playBinary${extension}")
+ this.environment("PLAY_BINARY_OPTS": "-Dhttp.port=${port}")
+ this.setWorkingDir(baseDirName)
+ }
+
+ @Override
+ List<String> getAllArguments() {
+ return Lists.newArrayList()
+ }
+
+ @Override
+ ExecHandle build() {
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream()
+ ByteArrayOutputStream errorOutput = new ByteArrayOutputStream()
+ this.setStandardOutput(new CloseShieldOutputStream(new TeeOutputStream(System.out, stdout)));
+ this.setErrorOutput(new CloseShieldOutputStream(new TeeOutputStream(System.err, errorOutput)));
+ return new DistributionTestExecHandle(super.build(), stdout, errorOutput)
+ }
+
+ public static class DistributionTestExecHandle implements ExecHandle {
+ final private ByteArrayOutputStream standardOutput
+ final private ByteArrayOutputStream errorOutput
+
+ @Delegate
+ final ExecHandle delegate
+
+ public DistributionTestExecHandle(ExecHandle delegate, ByteArrayOutputStream standardOutput, ByteArrayOutputStream errorOutput) {
+ this.delegate = delegate
+ this.standardOutput = standardOutput
+ this.errorOutput = errorOutput
+ }
+
+ void shutdown(int port) {
+ try {
+ stop(port)
+ } finally {
+ try {
+ abort()
+ } catch (IllegalStateException e) {
+ // Ignore if process is already not running
+ println "Did not abort play process since current state is: ${state.toString()}"
+ }
+ }
+ }
+
+ private stop(int port) {
+ try {
+ new URL("http://localhost:${port}/shutdown").bytes
+ } catch (SocketException e) {
+ // Expected
+ }
+
+ ConcurrentTestUtil.poll(30) {
+ try {
+ def connection = new URL("http://localhost:${port}/").openConnection()
+ connection.connect()
+ // we can still connect to the application
+ assert false: "Waiting for application to finally die"
+ } catch (IOException e) {
+ // Application is dead
+ }
+ }
+ }
+
+ ByteArrayOutputStream getStandardOutput() {
+ return standardOutput
+ }
+
+ ByteArrayOutputStream getErrorOutput() {
+ return errorOutput
+ }
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/MultiProjectRunningPlayApp.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/MultiProjectRunningPlayApp.groovy
new file mode 100644
index 0000000..ff7c262
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/MultiProjectRunningPlayApp.groovy
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.test.fixtures.file.TestFile
+
+import static org.gradle.integtests.fixtures.UrlValidator.assertUrlContent
+
+
+class MultiProjectRunningPlayApp extends RunningPlayApp {
+ MultiProjectRunningPlayApp(TestFile testDirectory) {
+ super(testDirectory)
+ }
+
+ @Override
+ void verifyContent() {
+ assertUrlContent playUrl(), "Your new application is ready."
+ assertUrlContent playUrl("assets/primary.txt"), "Primary asset"
+ assertUrlContent playUrl("submodule"), "Submodule page"
+ assertUrlContent playUrl("assets/submodule.txt"), "Submodule asset"
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayCoverage.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayCoverage.groovy
new file mode 100644
index 0000000..12352e2
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayCoverage.groovy
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.play.internal.DefaultPlayPlatform
+import org.gradle.util.VersionNumber
+
+class PlayCoverage {
+ static final List<VersionNumber> ALL_VERSIONS = ["2.2.1", "2.2.6", "2.3.1", "2.4.0", DefaultPlayPlatform.DEFAULT_PLAY_VERSION].collect { VersionNumber.parse(it) }
+ static final List<String> PLAY23_OR_EARLIER = ALL_VERSIONS.findAll { it.major <= 2 && it.minor <= 3 }.asImmutable()
+ static final List<String> PLAY23_OR_LATER = ALL_VERSIONS.findAll { it.major >= 2 && it.minor >= 3 }.asImmutable()
+ static final List<String> PLAY24_OR_LATER = ALL_VERSIONS.findAll { it.major >= 2 && it.minor >= 4 }.asImmutable()
+ static final List<String> PLAY23 = ALL_VERSIONS.findAll { it.major == 2 && it.minor == 3 }.asImmutable()
+ static final List<String> ALL = ALL_VERSIONS.asImmutable()
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionApplicationIntegrationTest.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionApplicationIntegrationTest.groovy
new file mode 100644
index 0000000..b0091e6
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionApplicationIntegrationTest.groovy
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
+import org.gradle.play.integtest.fixtures.app.PlayApp
+import org.gradle.test.fixtures.archive.JarTestFixture
+import org.gradle.test.fixtures.archive.ZipTestFixture
+
+abstract class PlayMultiVersionApplicationIntegrationTest extends PlayMultiVersionIntegrationTest {
+ abstract PlayApp getPlayApp()
+
+ def setup() {
+ buildFile << """
+ model {
+ components {
+ play {
+ targetPlatform "play-${MultiVersionIntegrationSpec.version}"
+ }
+ }
+ }
+ """
+
+ playApp.writeSources(testDirectory)
+ settingsFile << """
+ rootProject.name = '${playApp.name}'
+ """
+ }
+
+ JarTestFixture jar(String fileName) {
+ new JarTestFixture(file(fileName))
+ }
+
+ ZipTestFixture zip(String fileName) {
+ new ZipTestFixture(file(fileName))
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionIntegrationTest.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionIntegrationTest.groovy
new file mode 100644
index 0000000..cff5fb4
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionIntegrationTest.groovy
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.api.JavaVersion
+import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+
+ at TargetCoverage({ JavaVersion.current().isJava8Compatible() ? PlayCoverage.ALL : PlayCoverage.PLAY23_OR_EARLIER })
+ at Requires(TestPrecondition.JDK7_OR_LATER)
+abstract class PlayMultiVersionIntegrationTest extends MultiVersionIntegrationSpec {
+
+
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionRunApplicationIntegrationTest.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionRunApplicationIntegrationTest.groovy
new file mode 100644
index 0000000..8577c61
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/PlayMultiVersionRunApplicationIntegrationTest.groovy
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+
+import org.gradle.integtests.fixtures.executer.GradleHandle
+
+abstract class PlayMultiVersionRunApplicationIntegrationTest extends PlayMultiVersionApplicationIntegrationTest {
+ RunningPlayApp runningApp
+ GradleHandle build
+
+ def setup() {
+ runningApp = new RunningPlayApp(testDirectory)
+ }
+
+ def startBuild(tasks) {
+ build = executer.withTasks(tasks).withForceInteractive(true).withStdinPipe().start()
+ runningApp.initialize(build)
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/RunningPlayApp.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/RunningPlayApp.groovy
new file mode 100644
index 0000000..112ba2c
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/RunningPlayApp.groovy
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.play.integtest.fixtures
+import org.apache.http.HttpStatus
+import org.gradle.integtests.fixtures.executer.GradleHandle
+import org.gradle.play.integtest.fixtures.DistributionTestExecHandleBuilder.DistributionTestExecHandle
+import org.gradle.test.fixtures.ConcurrentTestUtil
+import org.gradle.test.fixtures.file.TestFile
+
+import static org.gradle.integtests.fixtures.UrlValidator.*
+
+class RunningPlayApp {
+ private static final int UNASSIGNED = -1
+ int httpPort = UNASSIGNED
+ final TestFile testDirectory
+ Closure output
+
+ RunningPlayApp(TestFile testDirectory) {
+ this.testDirectory = testDirectory
+ }
+
+ URL playUrl(String path='') {
+ requireHttpPort()
+ return new URL("http://localhost:$httpPort/${path}")
+ }
+
+ def playUrlError(String path='', int timeout=30) {
+ requireHttpPort()
+ HttpURLConnection connection
+ ConcurrentTestUtil.poll(timeout) {
+ connection = playUrl(path).openConnection()
+ assert connection.responseCode >= HttpStatus.SC_BAD_REQUEST
+ }
+
+ return [ 'httpCode': connection.responseCode,
+ 'message': connection.responseMessage,
+ 'text': connection.errorStream.text ]
+ }
+
+ protected int parseHttpPort(int occurrence) {
+ if (output == null) {
+ throw new IllegalStateException("Attempted to parse the http port from the build output, but initialize() was not called first!")
+ }
+
+ def matcher = output.call() =~ 'play - Listening for HTTP on .*:([0-9]+)'
+ if (matcher.count >= occurrence + 1) {
+ httpPort = matcher[occurrence][1] as int
+ return httpPort
+ } else {
+ return UNASSIGNED
+ }
+ }
+
+ void requireHttpPort(int occurence) {
+ if (httpPort == UNASSIGNED) {
+ if (parseHttpPort(occurence) == UNASSIGNED) {
+ throw new IllegalStateException("Could not parse Play http port from gradle output!")
+ }
+ }
+ }
+
+ void requireHttpPort() {
+ requireHttpPort(0)
+ }
+
+ void initialize(GradleHandle gradle) {
+ output = { gradle.standardOutput }
+ }
+
+ void initialize(DistributionTestExecHandle distHandle) {
+ output = { distHandle.standardOutput }
+ }
+
+ void waitForStarted(int occurrence = 0) {
+ int timeout = 60
+ ConcurrentTestUtil.poll(timeout) {
+ assert parseHttpPort(occurrence) != UNASSIGNED : "Could not parse Play http port from spec output after ${timeout} seconds"
+ }
+ }
+
+ void verifyStarted(String path = '', int occurrence = 0) {
+ waitForStarted(occurrence)
+ assert playUrl(path).text.contains("Your new application is ready.")
+ }
+
+ void verifyStopped(String path = '') {
+ notAvailable(playUrl(path).toString())
+ }
+
+ void verifyContent() {
+ // Check all static assets from the shared content
+ assertUrlContent playUrl("assets/stylesheets/main.css"), testDirectory.file("public/stylesheets/main.css")
+ assertUrlContent playUrl("assets/javascripts/hello.js"), testDirectory.file("public/javascripts/hello.js")
+ assertBinaryUrlContent playUrl("assets/images/favicon.svg"), testDirectory.file("public/images/favicon.svg")
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/AdvancedPlayApp.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/AdvancedPlayApp.groovy
similarity index 100%
rename from subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/AdvancedPlayApp.groovy
rename to subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/AdvancedPlayApp.groovy
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/BasicPlayApp.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/BasicPlayApp.groovy
similarity index 100%
rename from subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/BasicPlayApp.groovy
rename to subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/BasicPlayApp.groovy
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/PlayApp.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/PlayApp.groovy
similarity index 100%
rename from subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/PlayApp.groovy
rename to subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/PlayApp.groovy
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/PlayAppWithDependencies.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/PlayAppWithDependencies.groovy
similarity index 100%
rename from subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/PlayAppWithDependencies.groovy
rename to subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/PlayAppWithDependencies.groovy
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/PlayMultiProject.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/PlayMultiProject.groovy
similarity index 100%
rename from subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/PlayMultiProject.groovy
rename to subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/PlayMultiProject.groovy
diff --git a/subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/WithFailingTestsApp.groovy b/subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/WithFailingTestsApp.groovy
similarity index 100%
rename from subprojects/platform-play/src/integTest/groovy/org/gradle/play/integtest/fixtures/app/WithFailingTestsApp.groovy
rename to subprojects/platform-play/src/testFixtures/groovy/org/gradle/play/integtest/fixtures/app/WithFailingTestsApp.groovy
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/sample.js b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/sample.js
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/sample.js
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/sample.js
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/test.coffee b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/test.coffee
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/test.coffee
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/assets/javascripts/test.coffee
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/Application.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/Application.scala
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/Application.scala
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/Application.scala
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/jva/PureJava.java b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/jva/PureJava.java
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/jva/PureJava.java
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/jva/PureJava.java
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/scala/MixedJava.java b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/scala/MixedJava.java
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/scala/MixedJava.java
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/controllers/scala/MixedJava.java
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/DataType.java b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/DataType.java
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/DataType.java
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/DataType.java
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/ScalaClass.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/ScalaClass.scala
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/ScalaClass.scala
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/models/ScalaClass.scala
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/special/strangename/Application.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/special/strangename/Application.scala
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/special/strangename/Application.scala
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/special/strangename/Application.scala
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/awesome/index.scala.html b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/awesome/index.scala.html
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/awesome/index.scala.html
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/awesome/index.scala.html
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/index.scala.html b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/index.scala.html
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/index.scala.html
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/index.scala.html
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/main.scala.html b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/main.scala.html
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/main.scala.html
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/app/views/main.scala.html
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/build.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/build.gradle
new file mode 100644
index 0000000..8ef8c5f
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/build.gradle
@@ -0,0 +1,21 @@
+plugins {
+ id 'play'
+ id 'play-coffeescript'
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+ maven {
+ name "gradle-js"
+ url "https://repo.gradle.org/gradle/javascript-public"
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/jva.routes b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/jva.routes
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/jva.routes
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/jva.routes
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/routes b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/routes
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/routes
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/routes
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/scala.routes b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/scala.routes
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/scala.routes
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/advancedplayapp/conf/scala.routes
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/controllers/Application.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/controllers/Application.scala
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/controllers/Application.scala
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/controllers/Application.scala
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/index.scala.html b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/index.scala.html
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/index.scala.html
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/index.scala.html
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/main.scala.html b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/main.scala.html
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/main.scala.html
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/app/views/main.scala.html
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/build.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/build.gradle
new file mode 100644
index 0000000..2eaad69
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/build.gradle
@@ -0,0 +1,16 @@
+plugins {
+ id 'play'
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/conf/routes b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/conf/routes
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/conf/routes
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/conf/routes
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/ApplicationSpec.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/ApplicationSpec.scala
new file mode 100644
index 0000000..1d5b0fc
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/ApplicationSpec.scala
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.junit._
+
+class ApplicationSpec {
+ @Test
+ def passingTest() {
+ }
+ @Test
+ def passingTest2() {
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/IntegrationSpec.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/IntegrationSpec.scala
new file mode 100644
index 0000000..a1fdc66
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/IntegrationSpec.scala
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.junit._
+
+class IntegrationSpec {
+ @Test
+ def passingTest() {
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/notATest.yaml b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/notATest.yaml
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/notATest.yaml
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/basicplayapp/test/notATest.yaml
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/controllers/Application.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/controllers/Application.scala
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/controllers/Application.scala
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/controllers/Application.scala
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/index.scala.html b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/index.scala.html
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/index.scala.html
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/index.scala.html
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/main.scala.html b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/main.scala.html
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/main.scala.html
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/app/views/main.scala.html
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/build.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/build.gradle
new file mode 100644
index 0000000..1e1c704
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/build.gradle
@@ -0,0 +1,21 @@
+plugins {
+ id 'play'
+}
+
+dependencies {
+ play "com.google.guava:guava:17.0"
+ playTest "commons-lang:commons-lang:2.6"
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/conf/routes b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/conf/routes
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/conf/routes
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/conf/routes
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/ApplicationSpec.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/ApplicationSpec.scala
new file mode 100644
index 0000000..1d5b0fc
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/ApplicationSpec.scala
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.junit._
+
+class ApplicationSpec {
+ @Test
+ def passingTest() {
+ }
+ @Test
+ def passingTest2() {
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/IntegrationSpec.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/IntegrationSpec.scala
new file mode 100644
index 0000000..a1fdc66
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/IntegrationSpec.scala
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.junit._
+
+class IntegrationSpec {
+ @Test
+ def passingTest() {
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/notATest.yaml b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/notATest.yaml
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/notATest.yaml
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playappwithdependencies/test/notATest.yaml
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/build.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/build.gradle
new file mode 100644
index 0000000..63e4907
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/build.gradle
@@ -0,0 +1,14 @@
+allprojects {
+ repositories {
+ jcenter()
+ maven {
+ name "typesafe-maven-release"
+ url "https://repo.typesafe.com/typesafe/maven-releases"
+ }
+ ivy {
+ name "typesafe-ivy-release"
+ url "https://repo.typesafe.com/typesafe/ivy-releases"
+ layout "ivy"
+ }
+ }
+}
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/build.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/build.gradle
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/build.gradle
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/build.gradle
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/src/main/java/org/test/Util.java b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/src/main/java/org/test/Util.java
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/src/main/java/org/test/Util.java
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/javalibrary/src/main/java/org/test/Util.java
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/app/controllers/Application.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/app/controllers/Application.scala
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/app/controllers/Application.scala
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/app/controllers/Application.scala
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/build.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/build.gradle
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/build.gradle
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/build.gradle
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/application.conf b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/application.conf
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/application.conf
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/application.conf
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/routes b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/routes
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/routes
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/conf/routes
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/public/primary.txt b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/public/primary.txt
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/public/primary.txt
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/primary/public/primary.txt
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/settings.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/settings.gradle
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/settings.gradle
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/settings.gradle
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/app/controllers/submodule/Application.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/app/controllers/submodule/Application.scala
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/app/controllers/submodule/Application.scala
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/app/controllers/submodule/Application.scala
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/build.gradle b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/build.gradle
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/build.gradle
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/build.gradle
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/public/submodule.txt b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/public/submodule.txt
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/public/submodule.txt
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/playmultiproject/submodule/public/submodule.txt
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/README b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/README
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/README
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/README
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/conf/application.conf b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/conf/application.conf
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/conf/application.conf
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/conf/application.conf
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/conf/logback.xml b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/conf/logback.xml
new file mode 100644
index 0000000..6045363
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/conf/logback.xml
@@ -0,0 +1,22 @@
+<configuration>
+
+ <conversionRule conversionWord="coloredLevel" converterClass="play.api.Logger$ColoredLevel" />
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%coloredLevel - %logger - %message%n%xException</pattern>
+ </encoder>
+ </appender>
+
+ <!--
+ The logger name is typically the Java/Scala package name.
+ This configures the log level to log at for a package and its children packages.
+ -->
+ <logger name="play" level="INFO" />
+ <logger name="application" level="DEBUG" />
+
+ <root level="ERROR">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/images/favicon.svg b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/public/images/favicon.svg
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/images/favicon.svg
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/public/images/favicon.svg
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/javascripts/hello.js b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/public/javascripts/hello.js
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/javascripts/hello.js
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/public/javascripts/hello.js
diff --git a/subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
similarity index 100%
rename from subprojects/platform-play/src/integTest/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
rename to subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/shared/public/stylesheets/main.css
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingApplicationSpec.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingApplicationSpec.scala
new file mode 100644
index 0000000..5885516
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingApplicationSpec.scala
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.junit._
+import org.junit.Assert._
+
+class FailingApplicationSpec {
+ @Test
+ def failingTest() {
+ fail()
+ }
+ @Test
+ def passingTest() {
+ }
+}
diff --git a/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingIntegrationSpec.scala b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingIntegrationSpec.scala
new file mode 100644
index 0000000..9673162
--- /dev/null
+++ b/subprojects/platform-play/src/testFixtures/resources/org/gradle/play/integtest/fixtures/app/withfailingtestsapp/test/FailingIntegrationSpec.scala
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.junit._
+import org.junit.Assert._
+
+class FailingIntegrationSpec {
+ @Test
+ def failingTest() {
+ fail()
+ }
+}
diff --git a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseClassLoadingIntegrationSpec.groovy b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseClassLoadingIntegrationSpec.groovy
index 8cc6806..e295823 100644
--- a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseClassLoadingIntegrationSpec.groovy
+++ b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseClassLoadingIntegrationSpec.groovy
@@ -20,9 +20,11 @@ import org.gradle.api.Project
import org.gradle.api.specs.AndSpec
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.plugin.use.resolve.service.PluginResolutionServiceTestServer
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.plugin.PluginBuilder
import org.junit.Rule
+ at LeaksFileHandles
class PluginUseClassLoadingIntegrationSpec extends AbstractIntegrationSpec {
public static final String PLUGIN_ID = "org.myplugin"
diff --git a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseDslIntegrationSpec.groovy b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseDslIntegrationSpec.groovy
index 7ec36e5..e4337c3 100644
--- a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseDslIntegrationSpec.groovy
+++ b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/PluginUseDslIntegrationSpec.groovy
@@ -68,7 +68,7 @@ class PluginUseDslIntegrationSpec extends AbstractIntegrationSpec {
}
void includesLinkToUserguide() {
- assert failure.assertThatCause(containsString("http://gradle.org/docs/${GradleVersion.current().getVersion()}/userguide/plugins.html#sec:plugins_block"))
+ assert failure.assertThatCause(containsString("https://docs.gradle.org/${GradleVersion.current().getVersion()}/userguide/plugins.html#sec:plugins_block"))
}
def "build logic cannot precede plugins block"() {
diff --git a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionDeprecatedClientIntegrationTest.groovy b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionDeprecatedClientIntegrationTest.groovy
index a494da9..83c86eb 100644
--- a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionDeprecatedClientIntegrationTest.groovy
+++ b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionDeprecatedClientIntegrationTest.groovy
@@ -276,7 +276,7 @@ class PluginResolutionDeprecatedClientIntegrationTest extends AbstractIntegratio
void failPluginNotFound() {
fails "tasks"
- failure.assertThatDescription(containsText("Plugin \\[id: '.+', version: '1.0'\\] was not found"))
+ failure.assertThatDescription(containsText("Plugin [id: '${PLUGIN_ID_1}', version: '1.0'] was not found"))
}
void fail() {
diff --git a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionServiceCommsIntegrationTest.groovy b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionServiceCommsIntegrationTest.groovy
index 680d544..803ea1c 100644
--- a/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionServiceCommsIntegrationTest.groovy
+++ b/subprojects/plugin-use/src/integTest/groovy/org/gradle/plugin/use/resolve/service/PluginResolutionServiceCommsIntegrationTest.groovy
@@ -15,20 +15,18 @@
*/
package org.gradle.plugin.use.resolve.service
-
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.executer.ExecutionFailure
import org.gradle.plugin.use.resolve.service.internal.ErrorResponse
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.plugin.PluginBuilder
import org.gradle.test.fixtures.server.http.HttpServer
import org.gradle.util.GradleVersion
-import org.gradle.test.fixtures.file.LeaksFileHandles
import org.hamcrest.Matchers
import org.junit.Rule
import spock.lang.Unroll
-import static org.gradle.util.Matchers.containsText
-
+import static org.gradle.util.Matchers.matchesRegexp
/**
* Tests the communication aspects of working with the plugin resolution service.
*/
@@ -321,8 +319,9 @@ public class PluginResolutionServiceCommsIntegrationTest extends AbstractIntegra
expect:
fails("verify")
errorResolvingPlugin()
- failure.assertThatCause(containsText("Could not GET 'http://localhost:\\d+/.+?/plugin/use/org.my.myplugin/1\\.0'"))
- failure.assertThatCause(containsText("Connection to http://localhost:\\d+ refused"))
+
+ failure.assertThatCause(matchesRegexp(".*?Could not GET 'http://localhost:\\d+/.+?/plugin/use/org.my.myplugin/1.0'.*?"))
+ failure.assertThatCause(matchesRegexp(".*?Connection( to http://localhost:\\d+)? refused"))
}
def "non contactable dependency repository produces error"() {
@@ -343,7 +342,7 @@ public class PluginResolutionServiceCommsIntegrationTest extends AbstractIntegra
fails("verify")
errorResolvingPlugin()
failure.assertHasCause("Failed to resolve all plugin dependencies from $address")
- failure.assertThatCause(containsText("Connection to $address refused"))
+ failure.assertThatCause(matchesRegexp(".*?Connection( to $address)? refused"))
}
private void publishPlugin(String pluginId, String group, String artifact, String version) {
diff --git a/subprojects/plugin-use/src/main/java/org/gradle/plugin/use/internal/PluginUsePluginServiceRegistry.java b/subprojects/plugin-use/src/main/java/org/gradle/plugin/use/internal/PluginUsePluginServiceRegistry.java
index 59886da..adc08a2 100644
--- a/subprojects/plugin-use/src/main/java/org/gradle/plugin/use/internal/PluginUsePluginServiceRegistry.java
+++ b/subprojects/plugin-use/src/main/java/org/gradle/plugin/use/internal/PluginUsePluginServiceRegistry.java
@@ -18,6 +18,7 @@ package org.gradle.plugin.use.internal;
import org.gradle.StartParameter;
import org.gradle.api.UnknownProjectException;
+import org.gradle.authentication.Authentication;
import org.gradle.api.internal.DocumentationRegistry;
import org.gradle.api.internal.artifacts.DependencyManagementServices;
import org.gradle.api.internal.artifacts.DependencyResolutionServices;
@@ -34,7 +35,6 @@ import org.gradle.cache.PersistentCache;
import org.gradle.cache.internal.FileLockManager;
import org.gradle.initialization.ClassLoaderScopeRegistry;
import org.gradle.internal.Factory;
-import org.gradle.internal.resource.PasswordCredentials;
import org.gradle.internal.resource.transport.http.DefaultHttpSettings;
import org.gradle.internal.resource.transport.http.HttpClientHelper;
import org.gradle.internal.resource.transport.http.HttpResourceAccessor;
@@ -42,6 +42,8 @@ import org.gradle.internal.service.ServiceRegistration;
import org.gradle.internal.service.scopes.PluginServiceRegistry;
import org.gradle.plugin.use.resolve.service.internal.*;
+import java.util.Collections;
+
import static org.gradle.cache.internal.filelock.LockOptionsBuilder.mode;
public class PluginUsePluginServiceRegistry implements PluginServiceRegistry {
@@ -51,6 +53,9 @@ public class PluginUsePluginServiceRegistry implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.addProvider(new BuildScopeServices());
}
@@ -63,7 +68,7 @@ public class PluginUsePluginServiceRegistry implements PluginServiceRegistry {
private static class BuildScopeServices {
PluginResolutionServiceClient createPluginResolutionServiceClient(CacheRepository cacheRepository, StartParameter startParameter) {
- HttpClientHelper http = new HttpClientHelper(new DefaultHttpSettings(new PasswordCredentials()));
+ HttpClientHelper http = new HttpClientHelper(new DefaultHttpSettings(Collections.<Authentication>emptySet()));
HttpResourceAccessor accessor = new HttpResourceAccessor(http);
PluginResolutionServiceClient httpClient = startParameter.isOffline()
? new OfflinePluginResolutionServiceClient()
diff --git a/subprojects/plugins/plugins.gradle b/subprojects/plugins/plugins.gradle
index 5be1bb9..2433f48 100644
--- a/subprojects/plugins/plugins.gradle
+++ b/subprojects/plugins/plugins.gradle
@@ -64,3 +64,4 @@ useTestFixtures()
useTestFixtures(sourceSet: "testFixtures")
useTestFixtures(project: ":dependencyManagement")
useTestFixtures(project: ':diagnostics')
+useTestFixtures(project: ':messaging')
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/api/plugins/BasePluginIntegrationTest.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/api/plugins/BasePluginIntegrationTest.groovy
index f587e4e..c85f1e1 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/api/plugins/BasePluginIntegrationTest.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/api/plugins/BasePluginIntegrationTest.groovy
@@ -14,15 +14,14 @@
* limitations under the License.
*/
package org.gradle.api.plugins
+
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
class BasePluginIntegrationTest extends AbstractIntegrationSpec {
@Requires(TestPrecondition.MANDATORY_FILE_LOCKING)
- @LeaksFileHandles
def "clean failure message indicates file"() {
given:
executer.requireGradleHome()
@@ -31,7 +30,8 @@ class BasePluginIntegrationTest extends AbstractIntegrationSpec {
"""
and:
- def lock = new RandomAccessFile(file("build/newFile").createFile(), "rw").channel.lock()
+ def channel = new RandomAccessFile(file("build/newFile").createFile(), "rw").channel
+ def lock = channel.lock()
when:
fails "clean"
@@ -41,6 +41,7 @@ class BasePluginIntegrationTest extends AbstractIntegrationSpec {
cleanup:
lock?.release()
+ channel?.close()
}
def "can define 'build' and 'check' tasks when applying plugin"() {
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/BasicGroovyCompilerIntegrationSpec.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/BasicGroovyCompilerIntegrationSpec.groovy
index bf47af0..6b1c5b0 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/BasicGroovyCompilerIntegrationSpec.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/BasicGroovyCompilerIntegrationSpec.groovy
@@ -57,6 +57,10 @@ abstract class BasicGroovyCompilerIntegrationSpec extends MultiVersionIntegratio
}
def "compileWithAnnotationProcessor"() {
+ if (versionLowerThan("1.7")) {
+ return
+ }
+
when:
writeAnnotationProcessingBuild(
"", // no Java
@@ -74,6 +78,10 @@ abstract class BasicGroovyCompilerIntegrationSpec extends MultiVersionIntegratio
}
def "compileBadCodeWithAnnotationProcessor"() {
+ if (versionLowerThan("1.7")) {
+ return
+ }
+
when:
writeAnnotationProcessingBuild(
"", // no Java
@@ -163,6 +171,10 @@ abstract class BasicGroovyCompilerIntegrationSpec extends MultiVersionIntegratio
}
def "jointCompileWithAnnotationProcessor"() {
+ if (versionLowerThan("1.7")) {
+ return
+ }
+
when:
writeAnnotationProcessingBuild(
"$annotationText public class Java {}",
@@ -202,6 +214,10 @@ abstract class BasicGroovyCompilerIntegrationSpec extends MultiVersionIntegratio
}
def "jointCompileBadCodeWithAnnotationProcessor"() {
+ if (versionLowerThan("1.7")) {
+ return
+ }
+
when:
writeAnnotationProcessingBuild(
"$annotationText public class Java {}",
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/InvokeDynamicGroovyCompilerSpec.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/InvokeDynamicGroovyCompilerSpec.groovy
index 04402f3..c6c1888 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/InvokeDynamicGroovyCompilerSpec.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/groovy/compile/InvokeDynamicGroovyCompilerSpec.groovy
@@ -16,12 +16,14 @@
package org.gradle.groovy.compile
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
import org.gradle.integtests.fixtures.TargetVersions
@Requires(TestPrecondition.JDK7_OR_LATER)
@TargetVersions(['2.0.5:indy'])
+ at LeaksFileHandles
class InvokeDynamicGroovyCompilerSpec extends ApiGroovyCompilerIntegrationSpec {
def canEnableAndDisableInvokeDynamicOptimization() {
when:
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/java/compile/BasicJavaCompilerIntegrationSpec.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/java/compile/BasicJavaCompilerIntegrationSpec.groovy
index 521f8b7..0c39725 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/java/compile/BasicJavaCompilerIntegrationSpec.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/java/compile/BasicJavaCompilerIntegrationSpec.groovy
@@ -87,7 +87,6 @@ abstract class BasicJavaCompilerIntegrationSpec extends AbstractIntegrationSpec
file('encoded.out').getText("utf-8") == "\u03b1\u03b2\u03b3"
}
- @LeaksFileHandles
def compilesWithSpecifiedDebugSettings() {
given:
goodCode()
@@ -234,7 +233,7 @@ class Main {
return new ClassFile(file(path))
}
- @LeaksFileHandles
+ @LeaksFileHandles("holds processor.jar open for in process compiler")
def "can use annotation processor"() {
when:
buildFile << """
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/JUnitCoverage.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/JUnitCoverage.groovy
index 584d0c8..91c358c 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/JUnitCoverage.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/JUnitCoverage.groovy
@@ -19,9 +19,9 @@ package org.gradle.testing.fixture;
class JUnitCoverage {
final static String NEWEST = '4.12'
final static String[] LARGE_COVERAGE = ['4.0', '4.4', '4.8.2', NEWEST]
- final static String[] STANDARD_COVERAGE = ['4.4', NEWEST]
- final static String[] LOGGING = [NEWEST]
+ final static String[] IGNORE_ON_CLASS = ['4.4', '4.8.2', NEWEST]
final static String[] ASSUMPTIONS = ['4.5', NEWEST]
final static String[] CATEGORIES = ['4.8', NEWEST]
- final static String[] FILTERING = ['4.6', NEWEST]
+ final static String[] FILTER_JUNIT3_TESTS = ['3.8.1', '4.6', NEWEST]
+ final static String[] LOGGING = [NEWEST]
}
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/TestNGCoverage.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/TestNGCoverage.groovy
index 675ab21..16a192c 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/TestNGCoverage.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/fixture/TestNGCoverage.groovy
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-package org.gradle.testing.fixture;
+package org.gradle.testing.fixture
+
+import org.gradle.internal.jvm.Jvm;
class TestNGCoverage {
- final static String NEWEST = '6.8.7'
- final static String[] STANDARD_COVERAGE = ['5.14.10', '6.2', NEWEST]
+ final static String NEWEST = Jvm.current().javaVersion.java7Compatible ? '6.9.4' : '6.8.7'
+ final static String[] STANDARD_COVERAGE = ['5.14.10', '6.2', '6.8.7', NEWEST]
/**
* Adds java plugin and configures TestNG support in given build script file.
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitClassLevelFilteringIntegrationTest.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitClassLevelFilteringIntegrationTest.groovy
new file mode 100644
index 0000000..8c9035d
--- /dev/null
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitClassLevelFilteringIntegrationTest.groovy
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.gradle.testing.junit
+
+import org.gradle.integtests.fixtures.DefaultTestExecutionResult
+import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.testing.fixture.JUnitCoverage
+
+ at TargetCoverage({JUnitCoverage.LARGE_COVERAGE})
+public class JUnitClassLevelFilteringIntegrationTest extends MultiVersionIntegrationSpec {
+ def "runs all tests for class instead of method when runner is not filterable"() {
+ buildFile << """
+ apply plugin: 'java'
+ repositories { mavenCentral() }
+ dependencies { testCompile 'junit:junit:${version}' }
+ test { useJUnit() }
+ """
+ file("src/test/java/FooTest.java") << """
+ import org.junit.*;
+ import org.junit.runner.*;
+ @RunWith(SomeRunner.class)
+ public class FooTest {
+ }
+ """
+ file("src/test/java/SomeRunner.java") << """
+ import org.junit.*;
+ import org.junit.runner.*;
+ import org.junit.runner.notification.*;
+ public class SomeRunner extends Runner {
+ Class<?> c;
+
+ public SomeRunner(Class<?> c) {
+ this.c = c;
+ }
+
+ public Description getDescription() {
+ Description suite = Description.createSuiteDescription(c.getName());
+ suite.addChild(Description.createTestDescription(c, "pass"));
+ suite.addChild(Description.createTestDescription(c, "other"));
+ return suite;
+ }
+
+ public void run(RunNotifier notifier) {
+ for(Description d: getDescription().getChildren()) {
+ notifier.fireTestStarted(d);
+ notifier.fireTestFinished(d);
+ }
+ }
+ }
+ """
+
+ when:
+ run("test", "--tests", "FooTest.pass")
+
+ then:
+ def result = new DefaultTestExecutionResult(testDirectory)
+ result.assertTestClassesExecuted("FooTest")
+ result.testClass("FooTest").assertTestsExecuted("other", "pass")
+
+ when:
+ fails("test", "--tests", "FooTest.ignored")
+
+ then:
+ failure.assertHasCause("No tests found for given includes: [FooTest.ignored]")
+
+ when:
+ fails("test", "--tests", "NotFooTest.pass")
+
+ then:
+ failure.assertHasCause("No tests found for given includes: [NotFooTest.pass]")
+ }
+}
\ No newline at end of file
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringIntegrationTest.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringIntegrationTest.groovy
index 17850c0..4e17623 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringIntegrationTest.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringIntegrationTest.groovy
@@ -16,12 +16,13 @@
package org.gradle.testing.junit
-
+import org.gradle.integtests.fixtures.DefaultTestExecutionResult
import org.gradle.integtests.fixtures.TargetCoverage
import org.gradle.testing.fixture.AbstractTestFilteringIntegrationTest
import org.gradle.testing.fixture.JUnitCoverage
+import spock.lang.Ignore
- at TargetCoverage({JUnitCoverage.FILTERING})
+ at TargetCoverage({ JUnitCoverage.LARGE_COVERAGE })
public class JUnitFilteringIntegrationTest extends AbstractTestFilteringIntegrationTest {
void configureFramework() {
@@ -29,4 +30,50 @@ public class JUnitFilteringIntegrationTest extends AbstractTestFilteringIntegrat
dependency = "junit:junit"
imports = "org.junit.*"
}
-}
\ No newline at end of file
+
+ @Ignore
+ def "can filter parameterized junit tests"() {
+ buildFile << """
+ test {
+ filter {
+ includeTestsMatching "ParameterizedFoo.pass"
+ }
+ }
+ """
+ file("src/test/java/ParameterizedFoo.java") << """import $imports;
+ import org.junit.runners.Parameterized;
+ import org.junit.runners.Parameterized.Parameters;
+ import org.junit.runner.RunWith;
+ import java.util.Arrays;
+ import java.util.Collection;
+
+ @RunWith(Parameterized.class)
+ public class ParameterizedFoo {
+ int index;
+ public ParameterizedFoo(int index){
+ this.index = index;
+ }
+
+ @Parameters
+ public static Collection data() {
+ return Arrays.asList(new Object[][] {
+ { 2 },
+ { 6 },
+ { 19 },
+ { 22 },
+ { 23 }
+ });
+ }
+ @Test public void pass() {}
+ @Test public void fail() {}
+ }
+ """
+ when:
+ run("test")
+
+ then:
+ def result = new DefaultTestExecutionResult(testDirectory)
+ result.assertTestClassesExecuted("ParameterizedFoo")
+ result.testClass("ParameterizedFoo").assertTestsExecuted("pass")
+ }
+}
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringSupportIntegrationTest.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringSupportIntegrationTest.groovy
index 4ece704..68e8e97 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringSupportIntegrationTest.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitFilteringSupportIntegrationTest.groovy
@@ -17,46 +17,41 @@
package org.gradle.testing.junit
-import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-
-public class JUnitFilteringSupportIntegrationTest extends AbstractIntegrationSpec {
-
- void "informs that we dont support filtering for lower versions of JUnit 4.x"() {
- buildFile << """
- apply plugin: 'java'
- repositories { mavenCentral() }
- dependencies { testCompile 'junit:junit:4.5' }
- test.filter.includeTestsMatching "FooTest.pass"
- """
-
- file("src/test/java/FooTest.java") << """import org.junit.*;
- public class FooTest {
- @Test public void pass() {}
- }
- """
-
- when: fails("test")
-
- then:
- failure.assertHasCause("Test filtering is not supported for given version of JUnit. Please upgrade JUnit version to at least 4.6.")
- }
-
- void "informs that we dont support filtering for JUnit 3.x"() {
+import org.gradle.integtests.fixtures.DefaultTestExecutionResult
+import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.testing.fixture.JUnitCoverage
+
+ at TargetCoverage({JUnitCoverage.FILTER_JUNIT3_TESTS})
+public class JUnitFilteringSupportIntegrationTest extends MultiVersionIntegrationSpec {
+ void "filters tests implemented using 3.x test cases"() {
buildFile << """
apply plugin: 'java'
repositories { mavenCentral() }
- dependencies { testCompile 'junit:junit:3.8.1' }
- test.filter.includeTestsMatching "FooTest.pass"
+ dependencies { testCompile 'junit:junit:${version}' }
"""
file("src/test/java/FooTest.java") << """
- public class FooTest {
+ import junit.framework.*;
+
+ public class FooTest extends TestCase {
public void testPass() {}
+ public void testOk() {}
}
"""
- when: fails("test")
+ when:
+ succeeds("test", "--tests", "FooTest.testPass")
- then: failure.assertHasCause("Test filtering is not supported for given version of JUnit. Please upgrade JUnit version to at least 4.6.")
+ then:
+ def result = new DefaultTestExecutionResult(testDirectory)
+ result.assertTestClassesExecuted("FooTest")
+ result.testClass("FooTest").assertTestsExecuted("testPass")
+
+ when:
+ fails("test", "--tests", "FooTest.unknown")
+
+ then:
+ failure.assertHasCause("No tests found for given includes: [FooTest.unknown]")
}
}
\ No newline at end of file
diff --git a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitIgnoreClassMultiVersionIntegrationSpec.groovy b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitIgnoreClassMultiVersionIntegrationSpec.groovy
index 13e67c7..4143bcf 100644
--- a/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitIgnoreClassMultiVersionIntegrationSpec.groovy
+++ b/subprojects/plugins/src/integTest/groovy/org/gradle/testing/junit/JUnitIgnoreClassMultiVersionIntegrationSpec.groovy
@@ -23,7 +23,7 @@ import org.gradle.integtests.fixtures.TestResources
import org.gradle.testing.fixture.JUnitCoverage
import org.junit.Rule
- at TargetCoverage({JUnitCoverage.STANDARD_COVERAGE})
+ at TargetCoverage({JUnitCoverage.IGNORE_ON_CLASS})
class JUnitIgnoreClassMultiVersionIntegrationSpec extends MultiVersionIntegrationSpec {
@Rule TestResources resources = new TestResources(temporaryFolder)
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/java/AbstractLanguageSourceSet.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/java/AbstractLanguageSourceSet.java
index bb48acc..027d723 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/java/AbstractLanguageSourceSet.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/java/AbstractLanguageSourceSet.java
@@ -27,6 +27,7 @@ public abstract class AbstractLanguageSourceSet extends AbstractBuildableModelEl
private final String name;
private final String fullName;
private final String displayName;
+ private final String parentName;
private final SourceDirectorySet source;
private boolean generated;
private Task generatorTask;
@@ -36,6 +37,7 @@ public abstract class AbstractLanguageSourceSet extends AbstractBuildableModelEl
this.fullName = parentName + StringUtils.capitalize(name);
this.displayName = String.format("%s '%s:%s'", typeName, parentName, name);
this.source = source;
+ this.parentName = parentName;
super.builtBy(source.getBuildDependencies());
}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java
index 971f46d..9fa8d70 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java
@@ -17,23 +17,24 @@ package org.gradle.api.internal.jvm;
import org.gradle.api.Action;
import org.gradle.api.DomainObjectSet;
-import org.gradle.api.PolymorphicDomainObjectContainer;
import org.gradle.api.internal.AbstractBuildableModelElement;
import org.gradle.api.internal.DefaultDomainObjectSet;
import org.gradle.api.internal.project.taskfactory.ITaskFactory;
+import org.gradle.api.internal.rules.NamedDomainObjectFactoryRegistry;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.jvm.JvmBinaryTasks;
import org.gradle.jvm.internal.DefaultJvmBinaryTasks;
+import org.gradle.jvm.internal.toolchain.JavaToolChainInternal;
import org.gradle.jvm.platform.JavaPlatform;
import org.gradle.jvm.toolchain.JavaToolChain;
-import org.gradle.language.base.FunctionalSourceSet;
import org.gradle.language.base.LanguageSourceSet;
+import org.gradle.model.ModelMap;
import org.gradle.platform.base.BinaryTasksCollection;
import org.gradle.platform.base.internal.*;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import java.io.File;
+ at SuppressWarnings("deprecation")
public class DefaultClassDirectoryBinarySpec extends AbstractBuildableModelElement implements ClassDirectoryBinarySpecInternal {
private final DefaultDomainObjectSet<LanguageSourceSet> sourceSets = new DefaultDomainObjectSet<LanguageSourceSet>(LanguageSourceSet.class);
private final BinaryNamingScheme namingScheme;
@@ -41,18 +42,16 @@ public class DefaultClassDirectoryBinarySpec extends AbstractBuildableModelEleme
private final JavaToolChain toolChain;
private final JavaPlatform platform;
private final DefaultJvmBinaryTasks tasks;
- private final ToolResolver toolResolver;
private File classesDir;
private File resourcesDir;
private boolean buildable = true;
- public DefaultClassDirectoryBinarySpec(String name, JavaToolChain toolChain, JavaPlatform platform, Instantiator instantiator, ITaskFactory taskFactory, ToolResolver toolResolver) {
+ public DefaultClassDirectoryBinarySpec(String name, JavaToolChain toolChain, JavaPlatform platform, Instantiator instantiator, ITaskFactory taskFactory) {
this.name = name;
this.toolChain = toolChain;
this.platform = platform;
this.namingScheme = new ClassDirectoryBinaryNamingScheme(removeClassesSuffix(name));
this.tasks = instantiator.newInstance(DefaultJvmBinaryTasks.class, new DefaultBinaryTasksCollection(this, taskFactory));
- this.toolResolver = toolResolver;
}
private String removeClassesSuffix(String name) {
@@ -87,16 +86,6 @@ public class DefaultClassDirectoryBinarySpec extends AbstractBuildableModelEleme
throw new UnsupportedOperationException();
}
- @Override
- public ToolResolver getToolResolver() {
- return toolResolver;
- }
-
- @Override
- public void setToolResolver(ToolResolver toolResolver) {
- throw new UnsupportedOperationException();
- }
-
public boolean isBuildable() {
return getBuildAbility().isBuildable();
}
@@ -133,33 +122,36 @@ public class DefaultClassDirectoryBinarySpec extends AbstractBuildableModelEleme
this.resourcesDir = resourcesDir;
}
- public FunctionalSourceSet getBinarySources() {
+ @Override
+ public void sources(Action<? super ModelMap<LanguageSourceSet>> action) {
throw new UnsupportedOperationException();
}
- public void setBinarySources(FunctionalSourceSet sources) {
- throw new UnsupportedOperationException();
+ @Override
+ public DomainObjectSet<LanguageSourceSet> getSource() {
+ return getInputs();
}
@Override
- public void sources(Action<? super PolymorphicDomainObjectContainer<LanguageSourceSet>> action) {
+ public ModelMap<LanguageSourceSet> getSources() {
throw new UnsupportedOperationException();
}
@Override
- public DomainObjectSet<LanguageSourceSet> getSource() {
+ public DomainObjectSet<LanguageSourceSet> getInputs() {
return sourceSets;
}
- public void source(Object source) {
- throw new UnsupportedOperationException();
- }
-
@Override
public void addSourceSet(LanguageSourceSet sourceSet) {
sourceSets.add(sourceSet);
}
+ @Override
+ public NamedDomainObjectFactoryRegistry<LanguageSourceSet> getEntityInstantiator() {
+ throw new UnsupportedOperationException();
+ }
+
public String getDisplayName() {
return namingScheme.getDescription();
}
@@ -173,6 +165,6 @@ public class DefaultClassDirectoryBinarySpec extends AbstractBuildableModelEleme
if (!buildable) {
return new FixedBuildAbility(false);
}
- return new ToolSearchBuildAbility(toolResolver.checkToolAvailability(getTargetPlatform()));
+ return new ToolSearchBuildAbility(((JavaToolChainInternal) getToolChain()).select(getTargetPlatform()));
}
}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/CompileServices.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/CompileServices.java
index 86e0100..42ff2af 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/CompileServices.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/CompileServices.java
@@ -36,6 +36,9 @@ public class CompileServices implements PluginServiceRegistry {
registration.add(ClassDirectoryBinaryRenderer.class);
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/NoMatchingTestsReporter.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/NoMatchingTestsReporter.java
index ffd578b..b0b1856 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/NoMatchingTestsReporter.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/NoMatchingTestsReporter.java
@@ -16,7 +16,7 @@
package org.gradle.api.internal.tasks.testing;
-import org.gradle.api.GradleException;
+import org.gradle.api.tasks.testing.TestExecutionException;
import org.gradle.api.tasks.testing.TestDescriptor;
import org.gradle.api.tasks.testing.TestListener;
import org.gradle.api.tasks.testing.TestResult;
@@ -32,11 +32,11 @@ public class NoMatchingTestsReporter implements TestListener {
public void afterSuite(TestDescriptor suite, TestResult result) {
if (suite.getParent() == null && result.getTestCount() == 0) {
- throw new GradleException(message);
+ throw new TestExecutionException(message);
}
}
public void beforeTest(TestDescriptor testDescriptor) {}
public void afterTest(TestDescriptor testDescriptor, TestResult result) {}
-}
\ No newline at end of file
+}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilter.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilter.java
index 18a2c8b..b204ee2 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilter.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilter.java
@@ -26,6 +26,7 @@ import java.util.Set;
public class DefaultTestFilter implements TestFilter {
private Set<String> testNames = new HashSet<String>();
+ private boolean failOnNoMatching = true;
private void validateName(String name) {
if (name == null || name.length() == 0) {
@@ -39,6 +40,26 @@ public class DefaultTestFilter implements TestFilter {
return this;
}
+ public TestFilter includeTest(String className, String methodName) {
+ validateName(className);
+ if(methodName == null || methodName.trim().isEmpty()){
+ testNames.add(new StringBuilder(className).append(".*").toString());
+ }else{
+ testNames.add(new StringBuilder(className).append(".").append(methodName).toString());
+ }
+ return this;
+ }
+
+ @Override
+ public void setFailOnNoMatchingTests(boolean failOnNoMatchingTests) {
+ this.failOnNoMatching = failOnNoMatchingTests;
+ }
+
+ @Override
+ public boolean isFailOnNoMatchingTests() {
+ return failOnNoMatching;
+ }
+
@Input
public Set<String> getIncludePatterns() {
return testNames;
@@ -51,4 +72,4 @@ public class DefaultTestFilter implements TestFilter {
this.testNames = Sets.newHashSet(testNamePatterns);
return this;
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java
index 0676458..f83050d 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java
@@ -24,9 +24,16 @@ import org.gradle.util.CollectionUtils;
import org.junit.runner.Description;
import org.junit.runner.Request;
import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
public class JUnitTestClassExecuter {
private final ClassLoader applicationClassLoader;
private final RunListener listener;
@@ -56,7 +63,7 @@ public class JUnitTestClassExecuter {
private void runTestClass(String testClassName) throws ClassNotFoundException {
final Class<?> testClass = Class.forName(testClassName, false, applicationClassLoader);
- Request request = Request.aClass(testClass);
+ List<Filter> filters = new ArrayList<Filter>();
if (options.hasCategoryConfiguration()) {
Transformer<Class<?>, String> transformer = new Transformer<Class<?>, String>() {
public Class<?> transform(final String original) {
@@ -67,24 +74,55 @@ public class JUnitTestClassExecuter {
}
}
};
- request = request.filterWith(new CategoryFilter(
+ filters.add(new CategoryFilter(
CollectionUtils.collect(options.getIncludeCategories(), transformer),
CollectionUtils.collect(options.getExcludeCategories(), transformer)
));
}
if (!options.getIncludedTests().isEmpty()) {
- request = request.filterWith(new MethodNameFilter(options.getIncludedTests()));
+ filters.add(new MethodNameFilter(options.getIncludedTests()));
}
+ Request request = Request.aClass(testClass);
Runner runner = request.getRunner();
- //In case of no matching methods junit will return a ErrorReportingRunner for org.junit.runner.manipulation.Filter.class.
- //Will be fixed with adding class filters
- if (!org.junit.runner.manipulation.Filter.class.getName().equals(runner.getDescription().getDisplayName())) {
- RunNotifier notifier = new RunNotifier();
- notifier.addListener(listener);
- runner.run(notifier);
+ if (runner instanceof Filterable) {
+ Filterable filterable = (Filterable) runner;
+ for (Filter filter : filters) {
+ try {
+ filterable.filter(filter);
+ } catch (NoTestsRemainException e) {
+ // Ignore
+ return;
+ }
+ }
+ } else if (allTestsFiltered(runner, filters)) {
+ return;
+ }
+
+ RunNotifier notifier = new RunNotifier();
+ notifier.addListener(listener);
+ runner.run(notifier);
+ }
+
+ private boolean allTestsFiltered(Runner runner, List<Filter> filters) {
+ LinkedList<Description> queue = new LinkedList<Description>();
+ queue.add(runner.getDescription());
+ while (!queue.isEmpty()) {
+ Description description = queue.removeFirst();
+ queue.addAll(description.getChildren());
+ boolean run = true;
+ for (Filter filter : filters) {
+ if (!filter.shouldRun(description)) {
+ run = false;
+ break;
+ }
+ }
+ if (run) {
+ return false;
+ }
}
+ return true;
}
private static class MethodNameFilter extends org.junit.runner.manipulation.Filter {
@@ -97,7 +135,7 @@ public class JUnitTestClassExecuter {
@Override
public boolean shouldRun(Description description) {
- return matcher.matchesTest(description.getClassName(), description.getMethodName());
+ return matcher.matchesTest(JUnitTestEventAdapter.className(description), JUnitTestEventAdapter.methodName(description));
}
public String describe() {
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestEventAdapter.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestEventAdapter.java
index 5ebb10b..5a2bc9c 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestEventAdapter.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestEventAdapter.java
@@ -32,6 +32,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JUnitTestEventAdapter extends RunListener {
+ private static final Pattern DESCRIPTOR_PATTERN = Pattern.compile("(.*)\\((.*)\\)", Pattern.DOTALL);
private final TestResultProcessor resultProcessor;
private final TimeProvider timeProvider;
private final IdGenerator<?> idGenerator;
@@ -132,15 +133,16 @@ public class JUnitTestEventAdapter extends RunListener {
}
private TestDescriptorInternal nullSafeDescriptor(Object id, Description description) {
- if (methodName(description) != null) {
- return new DefaultTestDescriptor(id, className(description), methodName(description));
+ String methodName = methodName(description);
+ if (methodName != null) {
+ return new DefaultTestDescriptor(id, className(description), methodName);
} else {
return new DefaultTestDescriptor(id, className(description), "classMethod");
}
}
// Use this instead of Description.getMethodName(), it is not available in JUnit <= 4.5
- private String methodName(Description description) {
+ public static String methodName(Description description) {
Matcher matcher = methodStringMatcher(description);
if (matcher.matches()) {
return matcher.group(1);
@@ -149,13 +151,13 @@ public class JUnitTestEventAdapter extends RunListener {
}
// Use this instead of Description.getClassName(), it is not available in JUnit <= 4.5
- private String className(Description description) {
+ public static String className(Description description) {
Matcher matcher = methodStringMatcher(description);
return matcher.matches() ? matcher.group(2) : description.toString();
}
- private Matcher methodStringMatcher(Description description) {
- return Pattern.compile("(.*)\\((.*)\\)", Pattern.DOTALL).matcher(description.toString());
+ private static Matcher methodStringMatcher(Description description) {
+ return DESCRIPTOR_PATTERN.matcher(description.toString());
}
}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestFramework.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestFramework.java
index 86d5d77..3ef9ebc 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestFramework.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestFramework.java
@@ -50,7 +50,6 @@ public class JUnitTestFramework implements TestFramework {
public WorkerTestClassProcessorFactory getProcessorFactory() {
verifyJUnitCategorySupport();
- verifyJUnitFilteringSupport();
return new TestClassProcessorFactoryImpl(new JUnitSpec(options.getIncludeCategories(), options.getExcludeCategories(), filter.getIncludePatterns()));
}
@@ -64,29 +63,10 @@ public class JUnitTestFramework implements TestFramework {
}
}
- private void verifyJUnitFilteringSupport() {
- if (!filter.getIncludePatterns().isEmpty()) {
- try {
- Class<?> descriptionClass = getTestClassLoader().loadClass("org.junit.runner.Description");
- descriptionClass.getMethod("getClassName");
- } catch (ClassNotFoundException e) { //JUnit 3.8.1
- filteringNotSupported();
- } catch (NoSuchMethodException e) { //JUnit 4.5-
- filteringNotSupported();
- } catch (Exception e) {
- throw new RuntimeException("Problem encountered when detecting support for JUnit filtering.", e);
- }
- }
- }
-
private ClassLoader getTestClassLoader() {
return classLoaderFactory.create();
}
- private void filteringNotSupported() {
- throw new GradleException("Test filtering is not supported for given version of JUnit. Please upgrade JUnit version to at least 4.6.");
- }
-
public Action<WorkerProcessBuilder> getWorkerConfigurationAction() {
return new Action<WorkerProcessBuilder>() {
public void execute(WorkerProcessBuilder workerProcessBuilder) {
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/ForkingTestClassProcessor.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/ForkingTestClassProcessor.java
index ca3477f..25cac36 100755
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/ForkingTestClassProcessor.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/ForkingTestClassProcessor.java
@@ -72,7 +72,7 @@ public class ForkingTestClassProcessor implements TestClassProcessor {
workerProcess.start();
ObjectConnection connection = workerProcess.getConnection();
- connection.useParameterSerializer(new TestEventSerializer());
+ connection.useParameterSerializer(TestEventSerializer.create());
connection.addIncoming(TestResultProcessor.class, resultProcessor);
RemoteTestClassProcessor remoteProcessor = connection.addOutgoing(RemoteTestClassProcessor.class);
connection.connect();
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializer.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializer.java
index 662127e..1896b5f 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializer.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializer.java
@@ -21,13 +21,10 @@ import org.gradle.api.tasks.testing.TestOutputEvent;
import org.gradle.api.tasks.testing.TestResult;
import org.gradle.internal.id.CompositeIdGenerator;
import org.gradle.internal.serialize.*;
-import org.gradle.messaging.remote.internal.Message;
-import org.gradle.internal.serialize.kryo.StatefulSerializer;
-public class TestEventSerializer implements StatefulSerializer<Object[]> {
- private final Serializer<Object> paramSerializer;
-
- public TestEventSerializer() {
+public class TestEventSerializer {
+ public static Serializer<Object[]> create() {
+ BaseSerializerFactory factory = new BaseSerializerFactory();
DefaultSerializerRegistry<Object> registry = new DefaultSerializerRegistry<Object>();
registry.register(DefaultTestClassRunInfo.class, new DefaultTestClassRunInfoSerializer());
registry.register(CompositeIdGenerator.CompositeId.class, new IdSerializer());
@@ -39,32 +36,8 @@ public class TestEventSerializer implements StatefulSerializer<Object[]> {
registry.register(TestStartEvent.class, new TestStartEventSerializer());
registry.register(TestCompleteEvent.class, new TestCompleteEventSerializer());
registry.register(DefaultTestOutputEvent.class, new DefaultTestOutputEventSerializer());
- registry.register(Throwable.class, new ThrowableSerializer());
- paramSerializer = registry.build();
- }
-
- public ObjectReader<Object[]> newReader(final Decoder decoder) {
- return new ObjectReader<Object[]>() {
- public Object[] read() throws Exception {
- int count = decoder.readSmallInt();
- Object[] params = new Object[count];
- for (int i = 0; i < params.length; i++) {
- params[i] = paramSerializer.read(decoder);
- }
- return params;
- }
- };
- }
-
- public ObjectWriter<Object[]> newWriter(final Encoder encoder) {
- return new ObjectWriter<Object[]>() {
- public void write(Object[] value) throws Exception {
- encoder.writeSmallInt(value.length);
- for (int i = 0; i < value.length; i++) {
- paramSerializer.write(encoder, value[i]);
- }
- }
- };
+ registry.register(Throwable.class, factory.getSerializerFor(Throwable.class));
+ return new ObjectArraySerializer(registry.build());
}
private static class NullableSerializer<T> implements Serializer<T> {
@@ -89,16 +62,6 @@ public class TestEventSerializer implements StatefulSerializer<Object[]> {
}
}
- private static class ThrowableSerializer implements Serializer<Throwable> {
- public Throwable read(Decoder decoder) throws Exception {
- return (Throwable) Message.receive(decoder.getInputStream(), getClass().getClassLoader());
- }
-
- public void write(Encoder encoder, Throwable value) throws Exception {
- Message.send(value, encoder.getOutputStream());
- }
- }
-
private static class IdSerializer implements Serializer<CompositeIdGenerator.CompositeId> {
public CompositeIdGenerator.CompositeId read(Decoder decoder) throws Exception {
return new CompositeIdGenerator.CompositeId(decoder.readLong(), decoder.readLong());
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorker.java b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorker.java
index b420760..3b79cc0 100755
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorker.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorker.java
@@ -31,9 +31,9 @@ import org.gradle.internal.id.IdGenerator;
import org.gradle.internal.id.LongIdGenerator;
import org.gradle.internal.service.DefaultServiceRegistry;
import org.gradle.internal.service.ServiceRegistry;
-import org.gradle.messaging.dispatch.ContextClassLoaderProxy;
import org.gradle.messaging.actor.ActorFactory;
import org.gradle.messaging.actor.internal.DefaultActorFactory;
+import org.gradle.messaging.dispatch.ContextClassLoaderProxy;
import org.gradle.messaging.remote.ObjectConnection;
import org.gradle.process.internal.WorkerProcessContext;
import org.slf4j.Logger;
@@ -89,7 +89,7 @@ public class TestWorker implements Action<WorkerProcessContext>, RemoteTestClass
processor = proxy.getSource();
ObjectConnection serverConnection = workerProcessContext.getServerConnection();
- serverConnection.useParameterSerializer(new TestEventSerializer());
+ serverConnection.useParameterSerializer(TestEventSerializer.create());
this.resultProcessor = serverConnection.addOutgoing(TestResultProcessor.class);
serverConnection.addIncoming(RemoteTestClassProcessor.class, this);
serverConnection.connect();
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/plugins/LegacyJavaComponentPlugin.java b/subprojects/plugins/src/main/groovy/org/gradle/api/plugins/LegacyJavaComponentPlugin.java
index 796d05d..f73bcda 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/plugins/LegacyJavaComponentPlugin.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/plugins/LegacyJavaComponentPlugin.java
@@ -35,7 +35,6 @@ import org.gradle.language.jvm.JvmResourceSet;
import org.gradle.language.jvm.tasks.ProcessResources;
import org.gradle.platform.base.BinaryContainer;
import org.gradle.platform.base.internal.BinaryNamingScheme;
-import org.gradle.platform.base.internal.toolchain.ToolResolver;
import javax.inject.Inject;
import java.io.File;
@@ -55,14 +54,12 @@ public class LegacyJavaComponentPlugin implements Plugin<Project> {
private final Instantiator instantiator;
private final JavaToolChain toolChain;
private final ITaskFactory taskFactory;
- private final ToolResolver toolResolver;
@Inject
- public LegacyJavaComponentPlugin(Instantiator instantiator, JavaToolChain toolChain, ITaskFactory taskFactory, ToolResolver toolResolver) {
+ public LegacyJavaComponentPlugin(Instantiator instantiator, JavaToolChain toolChain, ITaskFactory taskFactory) {
this.instantiator = instantiator;
this.toolChain = toolChain;
this.taskFactory = taskFactory;
- this.toolResolver = toolResolver;
}
public void apply(final Project target) {
@@ -71,7 +68,7 @@ public class LegacyJavaComponentPlugin implements Plugin<Project> {
BinaryContainer binaryContainer = target.getExtensions().getByType(BinaryContainer.class);
binaryContainer.registerFactory(ClassDirectoryBinarySpec.class, new NamedDomainObjectFactory<ClassDirectoryBinarySpec>() {
public ClassDirectoryBinarySpec create(String name) {
- return instantiator.newInstance(DefaultClassDirectoryBinarySpec.class, name, toolChain, new DefaultJavaPlatform(JavaVersion.current()), instantiator, taskFactory, toolResolver);
+ return instantiator.newInstance(DefaultClassDirectoryBinarySpec.class, name, toolChain, DefaultJavaPlatform.current(), instantiator, taskFactory);
}
});
@@ -97,7 +94,7 @@ public class LegacyJavaComponentPlugin implements Plugin<Project> {
private void createCompileJavaTaskForBinary(final ClassDirectoryBinarySpecInternal binary, final Project target) {
final BinaryNamingScheme namingScheme = binary.getNamingScheme();
- binary.getSource().withType(JavaSourceSet.class).all(new Action<JavaSourceSet>() {
+ binary.getInputs().withType(JavaSourceSet.class).all(new Action<JavaSourceSet>() {
public void execute(JavaSourceSet javaSourceSet) {
JavaCompile compileTask = target.getTasks().create(namingScheme.getTaskName("compile", "java"), JavaCompile.class);
configureCompileTask(compileTask, javaSourceSet, binary);
@@ -109,7 +106,7 @@ public class LegacyJavaComponentPlugin implements Plugin<Project> {
private void createProcessResourcesTaskForBinary(final ClassDirectoryBinarySpecInternal binary, final Project target) {
final BinaryNamingScheme namingScheme = binary.getNamingScheme();
- binary.getSource().withType(JvmResourceSet.class).all(new Action<JvmResourceSet>() {
+ binary.getInputs().withType(JvmResourceSet.class).all(new Action<JvmResourceSet>() {
public void execute(JvmResourceSet resourceSet) {
Copy resourcesTask = target.getTasks().create(namingScheme.getTaskName("process", "resources"), ProcessResources.class);
resourcesTask.setDescription(String.format("Processes %s.", resourceSet));
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java b/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
index d9bb026..bccff3f 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
@@ -495,7 +495,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
TestEventLogger eventLogger = new TestEventLogger(getTextOutputFactory(), currentLevel, levelLogging, exceptionFormatter);
addTestListener(eventLogger);
addTestOutputListener(eventLogger);
- if (!getFilter().getIncludePatterns().isEmpty()) {
+ if (getFilter().isFailOnNoMatchingTests() && !getFilter().getIncludePatterns().isEmpty()) {
addTestListener(new NoMatchingTestsReporter("No tests found for given includes: " + getFilter().getIncludePatterns()));
}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/TestExecutionException.java b/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/TestExecutionException.java
new file mode 100644
index 0000000..9845cb9
--- /dev/null
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/TestExecutionException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.api.tasks.testing;
+
+import org.gradle.api.GradleException;
+import org.gradle.api.Incubating;
+
+/**
+ * <p>A <code>TestExecutionException</code> is thrown when no tests can be found that match the specified test filters.
+ *
+ * @since 2.6
+ */
+ at Incubating
+public class TestExecutionException extends GradleException {
+ public TestExecutionException(String message) {
+ super(message);
+ }
+
+ public TestExecutionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/TestFilter.java b/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/TestFilter.java
index 5babf8e..1336205 100644
--- a/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/TestFilter.java
+++ b/subprojects/plugins/src/main/groovy/org/gradle/api/tasks/testing/TestFilter.java
@@ -47,6 +47,9 @@ import java.util.Set;
*
* //only ui tests from integration tests, by some naming convention
* includeTestsMatching "*IntegTest*ui"
+ *
+ * //specific test class and test method
+ * includeTest "org.gradle.SomeTest", "someTestMethod"
* }
* }
*
@@ -58,10 +61,8 @@ import java.util.Set;
public interface TestFilter {
/**
- * Appends a test name pattern to the filter. Wildcard '*' is supported,
- * either test method name or class name is supported.
- * Examples of test names: "com.foo.FooTest.someMethod", "com.foo.FooTest", "*FooTest*", "com.foo*".
- * See examples in the docs for {@link TestFilter}.
+ * Appends a test name pattern to the filter. Wildcard '*' is supported, either test method name or class name is supported. Examples of test names: "com.foo.FooTest.someMethod",
+ * "com.foo.FooTest", "*FooTest*", "com.foo*". See examples in the docs for {@link TestFilter}.
*
* @param testNamePattern test name pattern to include, can be class or method name, can contain wildcard '*'
* @return this filter object
@@ -69,19 +70,40 @@ public interface TestFilter {
TestFilter includeTestsMatching(String testNamePattern);
/**
- * Returns the included test name patterns. They can be class or method names and may contain wildcard '*'.
- * Test name patterns can be appended via {@link #includeTestsMatching(String)} or set via {@link #setIncludePatterns(String...)}.
+ * Returns the included test name patterns. They can be class or method names and may contain wildcard '*'. Test name patterns can be appended via {@link #includeTestsMatching(String)} or set via
+ * {@link #setIncludePatterns(String...)}.
*
* @return included test name patterns
*/
Set<String> getIncludePatterns();
/**
- * Sets the test name patterns to be included in the filter. Wildcard '*' is supported.
- * Replaces any existing test name patterns.
+ * Sets the test name patterns to be included in the filter. Wildcard '*' is supported. Replaces any existing test name patterns.
*
* @param testNamePatterns class or method name patterns to set, may contain wildcard '*'
* @return this filter object
*/
TestFilter setIncludePatterns(String... testNamePatterns);
+
+ /**
+ * Add a test method specified by test class name and method name.
+ *
+ * @param className the class name of the test to execute
+ * @param methodName the method name of the test to execute. Can be null.
+ * @return this filter object
+ */
+ TestFilter includeTest(String className, String methodName);
+
+ /**
+ * Let the test task fail if a filter configuration was provided but no test matched the given configuration.
+ * @param failOnNoMatchingTests whether a test task should fail if no test is matching the filter configuration.
+ * */
+ void setFailOnNoMatchingTests(boolean failOnNoMatchingTests);
+
+ /**
+ * Returns whether the task should fail if no matching tests where found.
+ * The default is true.
+ */
+ boolean isFailOnNoMatchingTests();
}
+
diff --git a/subprojects/plugins/src/main/groovy/org/gradle/jvm/package-info.java b/subprojects/plugins/src/main/groovy/org/gradle/jvm/package-info.java
deleted file mode 100644
index d2ccf28..0000000
--- a/subprojects/plugins/src/main/groovy/org/gradle/jvm/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Classes for adapting the legacy plugins to the new component model.
- */
-package org.gradle.jvm;
diff --git a/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt b/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
index bec72be..e8a187a 100755
--- a/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+++ b/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
@@ -42,11 +42,6 @@ case "`uname`" in
;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if \$cygwin ; then
- [ -n "\$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "\$JAVA_HOME"`
-fi
-
# Attempt to set APP_HOME
# Resolve links: \$0 may be a link
PRG="\$0"
@@ -114,6 +109,7 @@ fi
if \$cygwin ; then
APP_HOME=`cygpath --path --mixed "\$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "\$CLASSPATH"`
+ JAVACMD=`cygpath --unix "\$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy
index 5c3493c..1081e6c 100644
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy
@@ -20,7 +20,6 @@ import org.gradle.api.internal.project.taskfactory.ITaskFactory
import org.gradle.internal.reflect.DirectInstantiator
import org.gradle.jvm.platform.JavaPlatform
import org.gradle.jvm.toolchain.JavaToolChain
-import org.gradle.platform.base.internal.toolchain.ToolResolver
import spock.lang.Specification
public class DefaultClassDirectoryBinarySpecTest extends Specification {
@@ -86,6 +85,6 @@ public class DefaultClassDirectoryBinarySpecTest extends Specification {
}
private DefaultClassDirectoryBinarySpec binary(String name) {
- new DefaultClassDirectoryBinarySpec(name, toolChain, platform, DirectInstantiator.INSTANCE, Mock(ITaskFactory), Mock(ToolResolver))
+ new DefaultClassDirectoryBinarySpec(name, toolChain, platform, DirectInstantiator.INSTANCE, Mock(ITaskFactory))
}
}
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/plugins/UnixStartScriptGeneratorTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/plugins/UnixStartScriptGeneratorTest.groovy
index 61a2310..eae96bd 100644
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/plugins/UnixStartScriptGeneratorTest.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/plugins/UnixStartScriptGeneratorTest.groovy
@@ -46,7 +46,7 @@ class UnixStartScriptGeneratorTest extends Specification {
generator.generateScript(details, destination)
then:
- destination.toString().split(TextUtil.unixLineSeparator).length == 164
+ destination.toString().split(TextUtil.unixLineSeparator).length == 160
}
def "defaultJvmOpts is expanded properly in unix script"() {
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilterTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilterTest.groovy
index 58e2398..2ae1b37 100644
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilterTest.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/filter/DefaultTestFilterTest.groovy
@@ -39,6 +39,16 @@ class DefaultTestFilterTest extends Specification {
then: spec.includePatterns == ["x"] as Set
}
+ def "allows configuring by test class and methodname"() {
+ expect: spec.includePatterns.isEmpty()
+
+ when:
+ spec.includeTest("acme.FooTest", "bar")
+ spec.includeTest("acme.BarTest", null)
+
+ then: spec.includePatterns == ["acme.FooTest.bar", "acme.BarTest.*"] as Set
+ }
+
def "prevents empty names"() {
when: spec.includeTestsMatching(null)
then: thrown(InvalidUserDataException)
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorData.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorData.groovy
index 8ffa3af..44334da 100644
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorData.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorData.groovy
@@ -192,8 +192,8 @@ public class CustomRunner extends Runner {
@Override
public Description getDescription() {
Description description = Description.createSuiteDescription(type)
- description.addChild(Description.createTestDescription(type, 'ok1'))
- description.addChild(Description.createTestDescription(type, 'ok2'))
+ description.addChild(Description.createTestDescription(type, 'broken'))
+ description.addChild(Description.createTestDescription(type, 'ok'))
return description
}
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy
index bd44adf..f2470c2 100644
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy
@@ -260,6 +260,31 @@ class JUnitTestClassProcessorTest extends Specification {
0 * processor.started(_, _)
}
+ def "executes all tests for class with test runner that is not filterable when any test description matches"() {
+ classProcessor = withSpec(new JUnitSpec([] as Set, [] as Set, [ATestClassWithRunner.name + ".ok"] as Set))
+
+ when: process(ATestClassWithRunner)
+
+ then: 1 * processor.started({ it.id == 1 }, { it.parentId == null })
+ then: 1 * processor.started({ it.id == 2 && it.name == "broken" && it.className == ATestClassWithRunner.name }, { it.parentId == 1 })
+ then: 1 * processor.started({ it.id == 3 && it.name == "ok" && it.className == ATestClassWithRunner.name }, { it.parentId == 1 })
+ then: 1 * processor.failure(2, CustomRunner.failure)
+ then: 1 * processor.completed(3, { it.resultType == null })
+ then: 1 * processor.completed(2, { it.resultType == null })
+ then: 1 * processor.completed(1, { it.resultType == null })
+ 0 * processor._
+ }
+
+ def "does not execute class with test runner that is not filterable when no test description matches"() {
+ classProcessor = withSpec(new JUnitSpec([] as Set, [] as Set, [ATestClassWithRunner.name + ".ignoreme"] as Set))
+
+ when: process(ATestClassWithRunner)
+
+ then: 1 * processor.started({ it.id == 1 }, { it.parentId == null })
+ then: 1 * processor.completed(1, { it.resultType == null })
+ 0 * processor._
+ }
+
def "executes no methods when method name does not match"() {
classProcessor = withSpec(new JUnitSpec([] as Set, [] as Set, ["does not exist"] as Set))
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializerTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializerTest.groovy
index 344d282..ab4bf36 100644
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializerTest.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestEventSerializerTest.groovy
@@ -17,23 +17,14 @@
package org.gradle.api.internal.tasks.testing.worker
import org.gradle.api.GradleException
-import org.gradle.api.internal.tasks.testing.DefaultTestClassDescriptor
-import org.gradle.api.internal.tasks.testing.DefaultTestClassRunInfo
-import org.gradle.api.internal.tasks.testing.DefaultTestDescriptor
-import org.gradle.api.internal.tasks.testing.DefaultTestMethodDescriptor
-import org.gradle.api.internal.tasks.testing.DefaultTestOutputEvent
-import org.gradle.api.internal.tasks.testing.DefaultTestSuiteDescriptor
-import org.gradle.api.internal.tasks.testing.TestCompleteEvent
-import org.gradle.api.internal.tasks.testing.TestStartEvent
+import org.gradle.api.internal.tasks.testing.*
import org.gradle.api.tasks.testing.TestOutputEvent
import org.gradle.api.tasks.testing.TestResult
import org.gradle.internal.id.CompositeIdGenerator
-import org.gradle.internal.serialize.InputStreamBackedDecoder
-import org.gradle.internal.serialize.OutputStreamBackedEncoder
-import spock.lang.Specification
+import org.gradle.internal.serialize.SerializerSpec
-class TestEventSerializerTest extends Specification {
- def serializer = new TestEventSerializer()
+class TestEventSerializerTest extends SerializerSpec {
+ def serializer = TestEventSerializer.create()
def "serializes DefaultTestClassRunInfo"() {
def info = new DefaultTestClassRunInfo("some-test")
@@ -194,9 +185,6 @@ class TestEventSerializerTest extends Specification {
}
def Object[] serialize(Object... source) {
- def outstr = new ByteArrayOutputStream()
- serializer.newWriter(new OutputStreamBackedEncoder(outstr)).write(source)
-
- return serializer.newReader(new InputStreamBackedDecoder(new ByteArrayInputStream(outstr.toByteArray()))).read()
+ return super.serialize(source, serializer)
}
}
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorkerTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorkerTest.groovy
index 267ae6c..08df5a0 100755
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorkerTest.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/worker/TestWorkerTest.groovy
@@ -17,85 +17,58 @@
package org.gradle.api.internal.tasks.testing.worker
-import org.gradle.api.internal.tasks.testing.TestResultProcessor
import org.gradle.api.internal.tasks.testing.TestClassProcessor
import org.gradle.api.internal.tasks.testing.TestClassRunInfo
+import org.gradle.api.internal.tasks.testing.TestResultProcessor
+import org.gradle.api.internal.tasks.testing.WorkerTestClassProcessorFactory
import org.gradle.messaging.remote.ObjectConnection
import org.gradle.process.internal.WorkerProcessContext
-import org.gradle.util.JUnit4GroovyMockery
-import org.gradle.util.MultithreadedTestCase
-import org.jmock.integration.junit4.JMock
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import static org.junit.Assert.*
-import static org.hamcrest.Matchers.*
-import org.gradle.api.internal.tasks.testing.WorkerTestClassProcessorFactory
-import org.junit.Rule
+import org.gradle.test.fixtures.concurrent.ConcurrentSpec
import org.gradle.util.SetSystemProperties
+import org.junit.Rule
- at RunWith(JMock.class)
-public class TestWorkerTest extends MultithreadedTestCase {
- @Rule public final SetSystemProperties properties = new SetSystemProperties()
- private final JUnit4GroovyMockery context = new JUnit4GroovyMockery()
- private final WorkerProcessContext workerContext = context.mock(WorkerProcessContext.class)
- private final ObjectConnection connection = context.mock(ObjectConnection.class)
- private final WorkerTestClassProcessorFactory factory = context.mock(WorkerTestClassProcessorFactory.class)
- private final TestClassProcessor processor = context.mock(TestClassProcessor.class)
- private final TestClassRunInfo test = context.mock(TestClassRunInfo.class)
- private final TestResultProcessor resultProcessor = context.mock(TestResultProcessor.class)
- private final TestWorker worker = new TestWorker(factory)
-
- @Before
- public void setup() {
- context.checking {
- allowing(workerContext).getWorkerId()
- will(returnValue('<worker-id>'))
-
- ignoring(workerContext).getDisplayName()
-
- allowing(workerContext).getServerConnection()
- will(returnValue(connection))
+public class TestWorkerTest extends ConcurrentSpec {
+ @Rule SetSystemProperties properties = new SetSystemProperties()
+ def workerContext = Mock(WorkerProcessContext)
+ def connection = Mock(ObjectConnection)
+ def factory = Mock(WorkerTestClassProcessorFactory)
+ def processor = Mock(TestClassProcessor)
+ def test = Mock(TestClassRunInfo)
+ def resultProcessor = Mock(TestResultProcessor)
+ def worker = new TestWorker(factory)
- ignoring(workerContext).getApplicationClassLoader()
- }
+ def setup() {
+ workerContext.workerId >> "<worker-id>"
+ workerContext.serverConnection >> connection
}
- @Test
- public void createsTestProcessorAndBlocksUntilEndOfProcessingReceived() {
- context.checking {
- one(factory).create(withParam(notNullValue()))
- will(returnValue(processor))
-
- one(connection).addOutgoing(TestResultProcessor.class)
- will(returnValue(resultProcessor))
-
- one(connection).addIncoming(RemoteTestClassProcessor.class, worker)
- will {
- start {
- worker.startProcessing()
- worker.processTestClass(test)
- syncAt(1)
- worker.stop()
- }
- }
-
- one(connection).useParameterSerializer(withParam(instanceOf(TestEventSerializer)))
- one(connection).connect()
-
- ignoring(resultProcessor)
-
- one(processor).startProcessing(withParam(notNullValue()))
- one(processor).processTestClass(test)
- one(processor).stop()
+ def createsTestProcessorAndBlocksUntilEndOfProcessingReceived() {
+ when:
+ async {
+ worker.execute(workerContext)
+ instant.completed
}
- run {
- expectBlocksUntil(1) {
- worker.execute(workerContext)
+ then:
+ instant.completed > instant.stopped
+ System.properties['org.gradle.test.worker'] == '<worker-id>'
+
+ and:
+ 1 * factory.create(_) >> processor
+ 1 * connection.addOutgoing(TestResultProcessor) >> resultProcessor
+ 1 * connection.addIncoming(RemoteTestClassProcessor, worker)
+ 1 * connection.useParameterSerializer(_)
+ 1 * connection.connect() >> {
+ start {
+ worker.startProcessing()
+ worker.processTestClass(test)
+ thread.block()
+ instant.stopped
+ worker.stop()
}
}
-
- assertThat(System.properties['org.gradle.test.worker'], equalTo('<worker-id>'))
+ 1 * processor.startProcessing(_)
+ 1 * processor.processTestClass(test)
+ 1 * processor.stop()
}
}
diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/plugins/JavaBasePluginTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/plugins/JavaBasePluginTest.groovy
index 741fa49..a23d218 100644
--- a/subprojects/plugins/src/test/groovy/org/gradle/api/plugins/JavaBasePluginTest.groovy
+++ b/subprojects/plugins/src/test/groovy/org/gradle/api/plugins/JavaBasePluginTest.groovy
@@ -265,6 +265,6 @@ class JavaBasePluginTest extends Specification {
binary instanceof ClassDirectoryBinarySpec
binary.classesDir == project.file("classes")
binary.resourcesDir == project.file("resources")
- binary.source as Set == project.sources as Set
+ binary.inputs as Set == project.sources as Set
}
}
diff --git a/subprojects/publish/src/main/groovy/org/gradle/api/publish/internal/PublishServices.java b/subprojects/publish/src/main/groovy/org/gradle/api/publish/internal/PublishServices.java
index 6660c16..1ad52e7 100644
--- a/subprojects/publish/src/main/groovy/org/gradle/api/publish/internal/PublishServices.java
+++ b/subprojects/publish/src/main/groovy/org/gradle/api/publish/internal/PublishServices.java
@@ -23,6 +23,9 @@ public class PublishServices implements PluginServiceRegistry {
public void registerGlobalServices(ServiceRegistration registration) {
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
registration.add(ProjectDependencyPublicationResolver.class);
}
diff --git a/subprojects/resources-http/resources-http.gradle b/subprojects/resources-http/resources-http.gradle
index b34a596..79ffb62 100644
--- a/subprojects/resources-http/resources-http.gradle
+++ b/subprojects/resources-http/resources-http.gradle
@@ -17,7 +17,7 @@
dependencies {
compile project(':resources')
compile project(':baseServices')
- compile project(':core') // TODO:DAZ Only required to bring in PluginServiceRegistry: should be in baseServices?
+ compile project(':core')
compile libraries.commons_httpclient
compile libraries.commons_lang
compile libraries.nekohtml
diff --git a/subprojects/resources-http/src/main/java/org/gradle/authentication/http/BasicAuthentication.java b/subprojects/resources-http/src/main/java/org/gradle/authentication/http/BasicAuthentication.java
new file mode 100644
index 0000000..6f14706
--- /dev/null
+++ b/subprojects/resources-http/src/main/java/org/gradle/authentication/http/BasicAuthentication.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.authentication.http;
+
+import org.gradle.api.Incubating;
+import org.gradle.authentication.Authentication;
+
+/**
+ * Authentication scheme for basic access authentication over HTTP. When using this scheme, credentials are sent preemptively.
+ */
+ at Incubating
+public interface BasicAuthentication extends Authentication {
+}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/authentication/http/DigestAuthentication.java b/subprojects/resources-http/src/main/java/org/gradle/authentication/http/DigestAuthentication.java
new file mode 100644
index 0000000..5b3c7b9
--- /dev/null
+++ b/subprojects/resources-http/src/main/java/org/gradle/authentication/http/DigestAuthentication.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.authentication.http;
+
+import org.gradle.api.Incubating;
+import org.gradle.authentication.Authentication;
+
+/**
+ * Authentication scheme for digest access authentication over HTTP.
+ */
+ at Incubating
+public interface DigestAuthentication extends Authentication {
+}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/authentication/http/package-info.java b/subprojects/resources-http/src/main/java/org/gradle/authentication/http/package-info.java
new file mode 100644
index 0000000..fd57df6
--- /dev/null
+++ b/subprojects/resources-http/src/main/java/org/gradle/authentication/http/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Classes related to transport authentication protocols for HTTP.
+ *
+ * @since 2.7
+ */
+ at Incubating
+package org.gradle.authentication.http;
+
+import org.gradle.api.Incubating;
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/authentication/DefaultBasicAuthentication.java b/subprojects/resources-http/src/main/java/org/gradle/internal/authentication/DefaultBasicAuthentication.java
new file mode 100644
index 0000000..8375361
--- /dev/null
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/authentication/DefaultBasicAuthentication.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
+import org.gradle.authentication.http.BasicAuthentication;
+
+public class DefaultBasicAuthentication extends AbstractAuthentication implements BasicAuthentication {
+ public DefaultBasicAuthentication(String name) {
+ super(name, BasicAuthentication.class, PasswordCredentials.class);
+ }
+}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/authentication/DefaultDigestAuthentication.java b/subprojects/resources-http/src/main/java/org/gradle/internal/authentication/DefaultDigestAuthentication.java
new file mode 100644
index 0000000..32d05c3
--- /dev/null
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/authentication/DefaultDigestAuthentication.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
+import org.gradle.authentication.http.DigestAuthentication;
+
+public class DefaultDigestAuthentication extends AbstractAuthentication implements DigestAuthentication {
+ public DefaultDigestAuthentication(String name) {
+ super(name, DigestAuthentication.class, PasswordCredentials.class);
+ }
+}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/AlwaysRedirectRedirectStrategy.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/AlwaysRedirectRedirectStrategy.java
index 9e8b616..8217ca4 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/AlwaysRedirectRedirectStrategy.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/AlwaysRedirectRedirectStrategy.java
@@ -26,6 +26,11 @@ import org.apache.http.protocol.HttpContext;
import java.net.URI;
+/**
+ * A class which makes httpclient follow redirects for all http methods.
+ * This has been introduced to overcome a regression caused by switching to apache httpclient as the transport mechanism for publishing (https://issues.gradle.org/browse/GRADLE-3312)
+ * The rational for httpclient not following redirects, by default, can be found here: https://issues.apache.org/jira/browse/HTTPCLIENT-860
+ */
public class AlwaysRedirectRedirectStrategy extends DefaultRedirectStrategy {
public AlwaysRedirectRedirectStrategy() {
@@ -39,19 +44,19 @@ public class AlwaysRedirectRedirectStrategy extends DefaultRedirectStrategy {
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
URI uri = this.getLocationURI(request, response, context);
String method = request.getRequestLine().getMethod();
- if (method.equalsIgnoreCase("HEAD")) {
+ if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {
return new HttpHead(uri);
- } else if (method.equalsIgnoreCase("POST")) {
+ } else if (method.equalsIgnoreCase(HttpPost.METHOD_NAME)) {
return this.copyEntity(new HttpPost(uri), request);
- } else if (method.equalsIgnoreCase("PUT")) {
+ } else if (method.equalsIgnoreCase(HttpPut.METHOD_NAME)) {
return this.copyEntity(new HttpPut(uri), request);
- } else if (method.equalsIgnoreCase("DELETE")) {
+ } else if (method.equalsIgnoreCase(HttpDelete.METHOD_NAME)) {
return new HttpDelete(uri);
- } else if (method.equalsIgnoreCase("TRACE")) {
+ } else if (method.equalsIgnoreCase(HttpTrace.METHOD_NAME)) {
return new HttpTrace(uri);
- } else if (method.equalsIgnoreCase("OPTIONS")) {
+ } else if (method.equalsIgnoreCase(HttpOptions.METHOD_NAME)) {
return new HttpOptions(uri);
- } else if (method.equalsIgnoreCase("PATCH")) {
+ } else if (method.equalsIgnoreCase(HttpPatch.METHOD_NAME)) {
return this.copyEntity(new HttpPatch(uri), request);
} else {
return new HttpGet(uri);
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/DefaultHttpSettings.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/DefaultHttpSettings.java
index 1fd13a9..eba9593 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/DefaultHttpSettings.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/DefaultHttpSettings.java
@@ -16,21 +16,29 @@
package org.gradle.internal.resource.transport.http;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.authentication.Authentication;
+
+import java.util.Collection;
public class DefaultHttpSettings implements HttpSettings {
- private final PasswordCredentials passwordCredentials;
private final HttpProxySettings proxySettings = new JavaSystemPropertiesHttpProxySettings();
+ private final Collection<Authentication> authenticationSettings;
- public DefaultHttpSettings(PasswordCredentials passwordCredentials) {
- this.passwordCredentials = passwordCredentials;
- }
+ public DefaultHttpSettings(Collection<Authentication> authenticationSettings) {
+ if (authenticationSettings == null) {
+ throw new IllegalArgumentException("Authentication settings cannot be null.");
+ }
- public PasswordCredentials getCredentials() {
- return passwordCredentials;
+ this.authenticationSettings = authenticationSettings;
}
+ @Override
public HttpProxySettings getProxySettings() {
return proxySettings;
}
+
+ @Override
+ public Collection<Authentication> getAuthenticationSettings() {
+ return authenticationSettings;
+ }
}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpClientConfigurer.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpClientConfigurer.java
index 9fcd652..1c3360c 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpClientConfigurer.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpClientConfigurer.java
@@ -31,14 +31,24 @@ import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
+import org.gradle.authentication.Authentication;
+import org.gradle.authentication.http.BasicAuthentication;
+import org.gradle.authentication.http.DigestAuthentication;
+import org.gradle.internal.authentication.AllSchemesAuthentication;
+import org.gradle.internal.authentication.AuthenticationInternal;
+import org.gradle.api.specs.Spec;
+import org.gradle.internal.Cast;
+import org.gradle.internal.resource.UriResource;
import org.gradle.internal.resource.transport.http.ntlm.NTLMCredentials;
import org.gradle.internal.resource.transport.http.ntlm.NTLMSchemeFactory;
-import org.gradle.internal.resource.UriResource;
+import org.gradle.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
public class HttpClientConfigurer {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientConfigurer.class);
@@ -51,40 +61,69 @@ public class HttpClientConfigurer {
public void configure(DefaultHttpClient httpClient) {
NTLMSchemeFactory.register(httpClient);
- configureCredentials(httpClient, httpSettings.getCredentials());
+ configureCredentials(httpClient, httpSettings.getAuthenticationSettings());
configureProxyCredentials(httpClient, httpSettings.getProxySettings());
configureRetryHandler(httpClient);
configureUserAgent(httpClient);
}
- private void configureCredentials(DefaultHttpClient httpClient, PasswordCredentials credentials) {
- if(credentials != null) {
- String username = credentials.getUsername();
- if (username != null && username.length() > 0) {
- useCredentials(httpClient, credentials, AuthScope.ANY_HOST, AuthScope.ANY_PORT);
+ private void configureCredentials(DefaultHttpClient httpClient, Collection<Authentication> authentications) {
+ if(authentications.size() > 0) {
+ useCredentials(httpClient, AuthScope.ANY_HOST, AuthScope.ANY_PORT, authentications);
- // Use preemptive authorisation if no other authorisation has been established
- httpClient.addRequestInterceptor(new PreemptiveAuth(new BasicScheme()), 0);
- }
+ // Use preemptive authorisation if no other authorisation has been established
+ httpClient.addRequestInterceptor(new PreemptiveAuth(new BasicScheme(), isPreemptiveEnabled(authentications)), 0);
}
}
private void configureProxyCredentials(DefaultHttpClient httpClient, HttpProxySettings proxySettings) {
HttpProxySettings.HttpProxy proxy = proxySettings.getProxy();
if (proxy != null && proxy.credentials != null) {
- useCredentials(httpClient, proxy.credentials, proxy.host, proxy.port);
+ useCredentials(httpClient, proxy.host, proxy.port, Collections.singleton(new AllSchemesAuthentication(proxy.credentials)));
+ }
+ }
+
+ private void useCredentials(DefaultHttpClient httpClient, String host, int port, Collection<? extends Authentication> authentications) {
+ Credentials httpCredentials;
+
+ for (Authentication authentication : authentications) {
+ String scheme = getAuthScheme(authentication);
+ PasswordCredentials credentials = getPasswordCredentials(authentication);
+
+ if (authentication instanceof AllSchemesAuthentication) {
+ NTLMCredentials ntlmCredentials = new NTLMCredentials(credentials);
+ httpCredentials = new NTCredentials(ntlmCredentials.getUsername(), ntlmCredentials.getPassword(), ntlmCredentials.getWorkstation(), ntlmCredentials.getDomain());
+ httpClient.getCredentialsProvider().setCredentials(new AuthScope(host, port, AuthScope.ANY_REALM, AuthPolicy.NTLM), httpCredentials);
+
+ LOGGER.debug("Using {} and {} for authenticating against '{}:{}' using {}", new Object[]{credentials, ntlmCredentials, host, port, AuthPolicy.NTLM});
+ }
+
+ httpCredentials = new UsernamePasswordCredentials(credentials.getUsername(), credentials.getPassword());
+ httpClient.getCredentialsProvider().setCredentials(new AuthScope(host, port, AuthScope.ANY_REALM, scheme), httpCredentials);
+ LOGGER.debug("Using {} for authenticating against '{}:{}' using {}", new Object[]{credentials, host, port, scheme});
}
}
- private void useCredentials(DefaultHttpClient httpClient, PasswordCredentials credentials, String host, int port) {
- Credentials basicCredentials = new UsernamePasswordCredentials(credentials.getUsername(), credentials.getPassword());
- httpClient.getCredentialsProvider().setCredentials(new AuthScope(host, port), basicCredentials);
+ private boolean isPreemptiveEnabled(Collection<Authentication> authentications) {
+ return CollectionUtils.any(authentications, new Spec<Authentication>() {
+ @Override
+ public boolean isSatisfiedBy(Authentication element) {
+ return element instanceof BasicAuthentication;
+ }
+ });
+ }
- NTLMCredentials ntlmCredentials = new NTLMCredentials(credentials);
- Credentials ntCredentials = new NTCredentials(ntlmCredentials.getUsername(), ntlmCredentials.getPassword(), ntlmCredentials.getWorkstation(), ntlmCredentials.getDomain());
- httpClient.getCredentialsProvider().setCredentials(new AuthScope(host, port, AuthScope.ANY_REALM, AuthPolicy.NTLM), ntCredentials);
+ public void configureUserAgent(DefaultHttpClient httpClient) {
+ HttpProtocolParams.setUserAgent(httpClient.getParams(), UriResource.getUserAgentString());
+ }
- LOGGER.debug("Using {} and {} for authenticating against '{}:{}'", new Object[]{credentials, ntlmCredentials, host, port});
+ private PasswordCredentials getPasswordCredentials(Authentication authentication) {
+ org.gradle.api.credentials.Credentials credentials = ((AuthenticationInternal) authentication).getCredentials();
+ if (!(credentials instanceof PasswordCredentials)) {
+ throw new IllegalArgumentException(String.format("Credentials must be an instance of: %s", PasswordCredentials.class.getCanonicalName()));
+ }
+
+ return Cast.uncheckedCast(credentials);
}
private void configureRetryHandler(DefaultHttpClient httpClient) {
@@ -95,15 +134,25 @@ public class HttpClientConfigurer {
});
}
- public void configureUserAgent(DefaultHttpClient httpClient) {
- HttpProtocolParams.setUserAgent(httpClient.getParams(), UriResource.getUserAgentString());
+ private String getAuthScheme(Authentication authentication) {
+ if (authentication instanceof BasicAuthentication) {
+ return AuthPolicy.BASIC;
+ } else if (authentication instanceof DigestAuthentication) {
+ return AuthPolicy.DIGEST;
+ } else if (authentication instanceof AllSchemesAuthentication) {
+ return AuthScope.ANY_SCHEME;
+ } else {
+ throw new IllegalArgumentException(String.format("Authentication scheme of '%s' is not supported.", authentication.getClass().getSimpleName()));
+ }
}
static class PreemptiveAuth implements HttpRequestInterceptor {
private final AuthScheme authScheme;
+ private final boolean alwaysSendAuth;
- PreemptiveAuth(AuthScheme authScheme) {
+ PreemptiveAuth(AuthScheme authScheme, boolean alwaysSendAuth) {
this.authScheme = authScheme;
+ this.alwaysSendAuth = alwaysSendAuth;
}
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
@@ -116,7 +165,7 @@ public class HttpClientConfigurer {
// If no authState has been established and this is a PUT or POST request, add preemptive authorisation
String requestMethod = request.getRequestLine().getMethod();
- if (requestMethod.equals(HttpPut.METHOD_NAME) || requestMethod.equals(HttpPost.METHOD_NAME)) {
+ if (alwaysSendAuth || requestMethod.equals(HttpPut.METHOD_NAME) || requestMethod.equals(HttpPost.METHOD_NAME)) {
CredentialsProvider credentialsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
Credentials credentials = credentialsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpConnectorFactory.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpConnectorFactory.java
index 88a714b..fa0a931 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpConnectorFactory.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpConnectorFactory.java
@@ -17,12 +17,16 @@
package org.gradle.internal.resource.transport.http;
import com.google.common.collect.Sets;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.authentication.Authentication;
+import org.gradle.authentication.http.BasicAuthentication;
+import org.gradle.authentication.http.DigestAuthentication;
+import org.gradle.internal.authentication.AllSchemesAuthentication;
import org.gradle.internal.resource.connector.ResourceConnectorFactory;
import org.gradle.internal.resource.connector.ResourceConnectorSpecification;
import org.gradle.internal.resource.transfer.DefaultExternalResourceConnector;
import org.gradle.internal.resource.transfer.ExternalResourceConnector;
+import java.util.HashSet;
import java.util.Set;
public class HttpConnectorFactory implements ResourceConnectorFactory {
@@ -32,8 +36,17 @@ public class HttpConnectorFactory implements ResourceConnectorFactory {
}
@Override
+ public Set<Class<? extends Authentication>> getSupportedAuthentication() {
+ Set<Class<? extends Authentication>> supported = new HashSet<Class<? extends Authentication>>();
+ supported.add(BasicAuthentication.class);
+ supported.add(DigestAuthentication.class);
+ supported.add(AllSchemesAuthentication.class);
+ return supported;
+ }
+
+ @Override
public ExternalResourceConnector createResourceConnector(ResourceConnectorSpecification connectionDetails) {
- HttpClientHelper http = new HttpClientHelper(new DefaultHttpSettings(connectionDetails.getCredentials(PasswordCredentials.class)));
+ HttpClientHelper http = new HttpClientHelper(new DefaultHttpSettings(connectionDetails.getAuthentications()));
HttpResourceAccessor accessor = new HttpResourceAccessor(http);
HttpResourceLister lister = new HttpResourceLister(accessor);
HttpResourceUploader uploader = new HttpResourceUploader(http);
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpProxySettings.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpProxySettings.java
index fbb8b91..ea9cd80 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpProxySettings.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpProxySettings.java
@@ -16,7 +16,8 @@
package org.gradle.internal.resource.transport.http;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
+import org.gradle.api.internal.artifacts.repositories.DefaultPasswordCredentials;
public interface HttpProxySettings {
@@ -35,7 +36,7 @@ public interface HttpProxySettings {
if (username == null || username.length() == 0) {
credentials = null;
} else {
- credentials = new PasswordCredentials(username, password);
+ credentials = new DefaultPasswordCredentials(username, password);
}
}
}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpResourcesPluginServiceRegistry.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpResourcesPluginServiceRegistry.java
index 41d9fd1..074835c 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpResourcesPluginServiceRegistry.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpResourcesPluginServiceRegistry.java
@@ -16,6 +16,11 @@
package org.gradle.internal.resource.transport.http;
+import org.gradle.authentication.http.BasicAuthentication;
+import org.gradle.authentication.http.DigestAuthentication;
+import org.gradle.internal.authentication.DefaultBasicAuthentication;
+import org.gradle.internal.authentication.DefaultDigestAuthentication;
+import org.gradle.internal.authentication.AuthenticationSchemeRegistry;
import org.gradle.internal.resource.connector.ResourceConnectorFactory;
import org.gradle.internal.service.ServiceRegistration;
import org.gradle.internal.service.scopes.PluginServiceRegistry;
@@ -25,7 +30,11 @@ public class HttpResourcesPluginServiceRegistry implements PluginServiceRegistry
registration.addProvider(new GlobalScopeServices());
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
+ registration.addProvider(new AuthenticationSchemeAction());
}
public void registerGradleServices(ServiceRegistration registration) {
@@ -39,4 +48,11 @@ public class HttpResourcesPluginServiceRegistry implements PluginServiceRegistry
return new HttpConnectorFactory();
}
}
+
+ private static class AuthenticationSchemeAction {
+ public void configure(ServiceRegistration registration, AuthenticationSchemeRegistry authenticationSchemeRegistry) {
+ authenticationSchemeRegistry.registerScheme(BasicAuthentication.class, DefaultBasicAuthentication.class);
+ authenticationSchemeRegistry.registerScheme(DigestAuthentication.class, DefaultDigestAuthentication.class);
+ }
+ }
}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpSettings.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpSettings.java
index e206386..2696fa4 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpSettings.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpSettings.java
@@ -16,10 +16,12 @@
package org.gradle.internal.resource.transport.http;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.authentication.Authentication;
-public interface HttpSettings {
- PasswordCredentials getCredentials();
+import java.util.Collection;
+public interface HttpSettings {
HttpProxySettings getProxySettings();
+
+ Collection<Authentication> getAuthenticationSettings();
}
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/RepeatableInputStreamEntity.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/RepeatableInputStreamEntity.java
index 8bce19f..2af5790 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/RepeatableInputStreamEntity.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/RepeatableInputStreamEntity.java
@@ -49,7 +49,12 @@ public class RepeatableInputStreamEntity extends AbstractHttpEntity {
}
public void writeTo(OutputStream outstream) throws IOException {
- IOUtils.copyLarge(getContent(), outstream);
+ InputStream content = getContent();
+ try {
+ IOUtils.copyLarge(content, outstream);
+ } finally {
+ content.close();
+ }
}
public boolean isStreaming() {
diff --git a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentials.java b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentials.java
index ec41db6..2211533 100644
--- a/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentials.java
+++ b/subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentials.java
@@ -16,7 +16,7 @@
package org.gradle.internal.resource.transport.http.ntlm;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import java.net.InetAddress;
import java.net.UnknownHostException;
diff --git a/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientConfigurerTest.groovy b/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientConfigurerTest.groovy
index 346b392..fd14c61 100644
--- a/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientConfigurerTest.groovy
+++ b/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientConfigurerTest.groovy
@@ -18,19 +18,23 @@ package org.gradle.internal.resource.transport.http
import org.apache.http.auth.AuthScope
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.params.HttpProtocolParams
-import org.gradle.internal.resource.PasswordCredentials
+import org.gradle.api.artifacts.repositories.PasswordCredentials
+import org.gradle.internal.authentication.AllSchemesAuthentication
import org.gradle.internal.resource.UriResource
import spock.lang.Specification
public class HttpClientConfigurerTest extends Specification {
DefaultHttpClient httpClient = new DefaultHttpClient()
PasswordCredentials credentials = Mock()
+ AllSchemesAuthentication authentication = Mock() {
+ getCredentials() >> credentials
+ }
HttpSettings httpSettings = Mock()
HttpProxySettings proxySettings = Mock()
HttpClientConfigurer configurer = new HttpClientConfigurer(httpSettings)
def "configures http client with no credentials or proxy"() {
- httpSettings.credentials >> credentials
+ httpSettings.authenticationSettings >> []
httpSettings.proxySettings >> proxySettings
when:
@@ -41,7 +45,7 @@ public class HttpClientConfigurerTest extends Specification {
}
def "configures http client with proxy credentials"() {
- httpSettings.credentials >> credentials
+ httpSettings.authenticationSettings >> []
httpSettings.proxySettings >> proxySettings
proxySettings.proxy >> new HttpProxySettings.HttpProxy("host", 1111, "domain/proxyUser", "proxyPass")
@@ -63,7 +67,7 @@ public class HttpClientConfigurerTest extends Specification {
}
def "configures http client with credentials"() {
- httpSettings.credentials >> credentials
+ httpSettings.authenticationSettings >> [authentication]
credentials.username >> "domain/user"
credentials.password >> "pass"
httpSettings.proxySettings >> proxySettings
@@ -89,7 +93,7 @@ public class HttpClientConfigurerTest extends Specification {
}
def "configures http client with user agent"() {
- httpSettings.credentials >> credentials
+ httpSettings.authenticationSettings >> []
httpSettings.proxySettings >> proxySettings
when:
diff --git a/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientHelperTest.groovy b/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientHelperTest.groovy
index 3902dae..6361302 100644
--- a/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientHelperTest.groovy
+++ b/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/HttpClientHelperTest.groovy
@@ -18,7 +18,7 @@ package org.gradle.internal.resource.transport.http
import org.apache.http.HttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpRequestBase
-import org.gradle.internal.resource.PasswordCredentials
+import org.gradle.api.artifacts.repositories.PasswordCredentials
import org.gradle.util.SetSystemProperties
import org.junit.Rule
import spock.lang.Specification
diff --git a/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentialsTest.groovy b/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentialsTest.groovy
index 3dcc1d3..8491a57 100644
--- a/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentialsTest.groovy
+++ b/subprojects/resources-http/src/test/groovy/org/gradle/internal/resource/transport/http/ntlm/NTLMCredentialsTest.groovy
@@ -15,7 +15,7 @@
*/
package org.gradle.internal.resource.transport.http.ntlm
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials
import org.gradle.util.SetSystemProperties
import org.junit.Rule
import spock.lang.Specification
diff --git a/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/ivy/IvyS3RepoResolveIntegrationTest.groovy b/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/ivy/IvyS3RepoResolveIntegrationTest.groovy
index 5b206a1..cc81430 100644
--- a/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/ivy/IvyS3RepoResolveIntegrationTest.groovy
+++ b/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/ivy/IvyS3RepoResolveIntegrationTest.groovy
@@ -36,4 +36,34 @@ class IvyS3RepoResolveIntegrationTest extends AbstractIvyRemoteRepoResolveIntegr
executer.withArgument("-Dorg.gradle.s3.maxErrorRetry=0")
result = executer.withTasks(*tasks).run()
}
+
+ def "cannot add invalid authentication types for s3 repo"() {
+ given:
+ def remoteIvyRepo = server.getRemoteIvyRepo()
+ def module = remoteIvyRepo.module('org.group.name', 'projectA', '1.2')
+ module.publish()
+
+ and:
+ buildFile << """
+ repositories {
+ ivy {
+ url "${remoteIvyRepo.uri}"
+ authentication {
+ auth(BasicAuthentication)
+ }
+ }
+ }
+ configurations { compile }
+ dependencies { compile 'org.group.name:projectA:1.2' }
+ task retrieve(type: Sync) {
+ from configurations.compile
+ into 'libs'
+ }
+ """
+
+ expect:
+ fails 'retrieve'
+ and:
+ errorOutput.contains("> Authentication scheme 'auth'(BasicAuthentication) is not supported by protocol 's3'")
+ }
}
diff --git a/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/maven/MavenS3RepoErrorsIntegrationTest.groovy b/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/maven/MavenS3RepoErrorsIntegrationTest.groovy
index d804ff2..7962429 100644
--- a/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/maven/MavenS3RepoErrorsIntegrationTest.groovy
+++ b/subprojects/resources-s3/src/integTest/groovy/org/gradle/integtests/resource/s3/maven/MavenS3RepoErrorsIntegrationTest.groovy
@@ -120,4 +120,26 @@ Searched in the following locations:
Required by:
"""))
}
+
+ def "cannot add invalid authentication types for s3 repo"() {
+ given:
+ module.publish()
+
+ and:
+ buildFile << """
+ repositories {
+ maven {
+ url "${mavenS3Repo.uri}"
+ authentication {
+ auth(BasicAuthentication)
+ }
+ }
+ }
+ """
+
+ expect:
+ fails 'retrieve'
+ and:
+ errorOutput.contains("> Authentication scheme 'auth'(BasicAuthentication) is not supported by protocol 's3'")
+ }
}
diff --git a/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3Client.java b/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3Client.java
index 0f41a4f..1ca015b 100644
--- a/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3Client.java
+++ b/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3Client.java
@@ -25,8 +25,8 @@ import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.S3ClientOptions;
import com.amazonaws.services.s3.model.*;
import com.google.common.base.Optional;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import org.gradle.api.credentials.AwsCredentials;
-import org.gradle.internal.resource.PasswordCredentials;
import org.gradle.internal.resource.ResourceException;
import org.gradle.internal.resource.transport.http.HttpProxySettings;
import org.slf4j.Logger;
diff --git a/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ConnectorFactory.java b/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ConnectorFactory.java
index f065a55..7417c0a 100644
--- a/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ConnectorFactory.java
+++ b/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ConnectorFactory.java
@@ -16,12 +16,15 @@
package org.gradle.internal.resource.transport.aws.s3;
+import org.gradle.authentication.Authentication;
import org.gradle.api.credentials.AwsCredentials;
+import org.gradle.internal.authentication.AllSchemesAuthentication;
import org.gradle.internal.resource.connector.ResourceConnectorFactory;
import org.gradle.internal.resource.connector.ResourceConnectorSpecification;
import org.gradle.internal.resource.transfer.ExternalResourceConnector;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Set;
public class S3ConnectorFactory implements ResourceConnectorFactory {
@@ -31,11 +34,18 @@ public class S3ConnectorFactory implements ResourceConnectorFactory {
}
@Override
+ public Set<Class<? extends Authentication>> getSupportedAuthentication() {
+ Set<Class<? extends Authentication>> supported = new HashSet<Class<? extends Authentication>>();
+ supported.add(AllSchemesAuthentication.class);
+ return supported;
+ }
+
+ @Override
public ExternalResourceConnector createResourceConnector(ResourceConnectorSpecification connectionDetails) {
- AwsCredentials credentials = connectionDetails.getCredentials(AwsCredentials.class);
- if(credentials == null) {
+ AwsCredentials awsCredentials = connectionDetails.getCredentials(AwsCredentials.class);
+ if(awsCredentials == null) {
throw new IllegalArgumentException("AwsCredentials must be set for S3 backed repository.");
}
- return new S3ResourceConnector(new S3Client(credentials, new S3ConnectionProperties()));
+ return new S3ResourceConnector(new S3Client(awsCredentials, new S3ConnectionProperties()));
}
}
diff --git a/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ResourcesPluginServiceRegistry.java b/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ResourcesPluginServiceRegistry.java
index 7291107..1de61b7 100644
--- a/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ResourcesPluginServiceRegistry.java
+++ b/subprojects/resources-s3/src/main/java/org/gradle/internal/resource/transport/aws/s3/S3ResourcesPluginServiceRegistry.java
@@ -25,6 +25,9 @@ public class S3ResourcesPluginServiceRegistry implements PluginServiceRegistry {
registration.addProvider(new GlobalScopeServices());
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
diff --git a/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/ivy/IvySftpRepoErrorsIntegrationTest.groovy b/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/ivy/IvySftpRepoErrorsIntegrationTest.groovy
index 096713b..dbcb89f 100644
--- a/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/ivy/IvySftpRepoErrorsIntegrationTest.groovy
+++ b/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/ivy/IvySftpRepoErrorsIntegrationTest.groovy
@@ -214,4 +214,34 @@ Required by:
.assertHasCause('Could not resolve org.group.name:projectA:1.2')
.assertHasCause("Could not get resource '${projectA.ivy.uri}'")
}
+
+ def "cannot add invalid authentication types for sftp repo"() {
+ given:
+ def remoteIvyRepo = getIvySftpRepo()
+ def module = remoteIvyRepo.module('org.group.name', 'projectA', '1.2')
+ module.publish()
+ and:
+ buildFile << """
+repositories {
+ ivy {
+ url "${getIvySftpRepo().uri}"
+ authentication {
+ auth(BasicAuthentication)
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task retrieve(type: Sync) {
+ from configurations.compile
+ into 'libs'
+}
+"""
+ expect:
+ fails 'retrieve'
+ and:
+ errorOutput.contains("> Authentication scheme 'auth'(BasicAuthentication) is not supported by protocol 'sftp'")
+ }
}
diff --git a/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/maven/MavenSftpRepoResolveIntegrationTest.groovy b/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/maven/MavenSftpRepoResolveIntegrationTest.groovy
index 43340a2..829e581 100644
--- a/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/maven/MavenSftpRepoResolveIntegrationTest.groovy
+++ b/subprojects/resources-sftp/src/integTest/groovy/org/gradle/integtests/resolve/resource/sftp/maven/MavenSftpRepoResolveIntegrationTest.groovy
@@ -56,4 +56,35 @@ class MavenSftpRepoResolveIntegrationTest extends AbstractSftpDependencyResoluti
succeeds 'retrieve'
file('libs').assertHasDescendants 'projectA-1.2.jar'
}
+
+
+ def "cannot add invalid authentication types for sftp repo"() {
+ given:
+ def mavenSftpRepo = getMavenSftpRepo()
+ def module = mavenSftpRepo.module('org.group.name', 'projectA', '1.2')
+ module.publish()
+ and:
+ buildFile << """
+repositories {
+ maven {
+ url "${mavenSftpRepo.uri}"
+ authentication {
+ auth(BasicAuthentication)
+ }
+ }
+}
+configurations { compile }
+dependencies {
+ compile 'group:projectA:1.2'
+}
+task retrieve(type: Sync) {
+ from configurations.compile
+ into 'libs'
+}
+"""
+ expect:
+ fails 'retrieve'
+ and:
+ errorOutput.contains("> Authentication scheme 'auth'(BasicAuthentication) is not supported by protocol 'sftp'")
+ }
}
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpClientFactory.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpClientFactory.java
index 2407ec7..02d1e4b 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpClientFactory.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpClientFactory.java
@@ -20,9 +20,9 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.jcraft.jsch.*;
import net.jcip.annotations.ThreadSafe;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import org.gradle.internal.concurrent.CompositeStoppable;
import org.gradle.internal.concurrent.Stoppable;
-import org.gradle.internal.resource.PasswordCredentials;
import org.gradle.internal.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpConnectorFactory.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpConnectorFactory.java
index a34acbe..02745b3 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpConnectorFactory.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpConnectorFactory.java
@@ -16,13 +16,16 @@
package org.gradle.internal.resource.transport.sftp;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
+import org.gradle.authentication.Authentication;
+import org.gradle.internal.authentication.AllSchemesAuthentication;
import org.gradle.internal.resource.connector.ResourceConnectorFactory;
import org.gradle.internal.resource.connector.ResourceConnectorSpecification;
import org.gradle.internal.resource.transfer.DefaultExternalResourceConnector;
import org.gradle.internal.resource.transfer.ExternalResourceConnector;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Set;
public class SftpConnectorFactory implements ResourceConnectorFactory {
@@ -38,6 +41,13 @@ public class SftpConnectorFactory implements ResourceConnectorFactory {
}
@Override
+ public Set<Class<? extends Authentication>> getSupportedAuthentication() {
+ Set<Class<? extends Authentication>> supported = new HashSet<Class<? extends Authentication>>();
+ supported.add(AllSchemesAuthentication.class);
+ return supported;
+ }
+
+ @Override
public ExternalResourceConnector createResourceConnector(ResourceConnectorSpecification connectionDetails) {
PasswordCredentials passwordCredentials = connectionDetails.getCredentials(PasswordCredentials.class);
SftpResourceAccessor accessor = new SftpResourceAccessor(sftpClientFactory, passwordCredentials);
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpHost.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpHost.java
index c9152b8..cc67fb0 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpHost.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpHost.java
@@ -16,7 +16,7 @@
package org.gradle.internal.resource.transport.sftp;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import java.net.URI;
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResource.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResource.java
index 5c6cd9e..6085f3e 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResource.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResource.java
@@ -16,7 +16,7 @@
package org.gradle.internal.resource.transport.sftp;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import org.gradle.internal.resource.ResourceException;
import org.gradle.internal.resource.metadata.ExternalResourceMetaData;
import org.gradle.internal.resource.transfer.ExternalResourceReadResponse;
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceAccessor.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceAccessor.java
index 826cfbc..9bc5378 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceAccessor.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceAccessor.java
@@ -18,7 +18,7 @@ package org.gradle.internal.resource.transport.sftp;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import org.gradle.internal.resource.ResourceException;
import org.gradle.internal.resource.metadata.DefaultExternalResourceMetaData;
import org.gradle.internal.resource.metadata.ExternalResourceMetaData;
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceLister.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceLister.java
index 12be299..01319bd 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceLister.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceLister.java
@@ -17,7 +17,7 @@
package org.gradle.internal.resource.transport.sftp;
import com.jcraft.jsch.ChannelSftp;
-import org.gradle.internal.resource.PasswordCredentials;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import org.gradle.internal.resource.ResourceException;
import org.gradle.internal.resource.transfer.ExternalResourceLister;
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceUploader.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceUploader.java
index 6bb84a4..bc68c21 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceUploader.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourceUploader.java
@@ -18,8 +18,8 @@ package org.gradle.internal.resource.transport.sftp;
import com.jcraft.jsch.ChannelSftp;
import org.apache.commons.io.FilenameUtils;
+import org.gradle.api.artifacts.repositories.PasswordCredentials;
import org.gradle.internal.resource.local.LocalResource;
-import org.gradle.internal.resource.PasswordCredentials;
import org.gradle.internal.resource.ResourceException;
import org.gradle.internal.resource.transfer.ExternalResourceUploader;
diff --git a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourcesPluginServiceRegistry.java b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourcesPluginServiceRegistry.java
index 4b10d95..e5e316b 100644
--- a/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourcesPluginServiceRegistry.java
+++ b/subprojects/resources-sftp/src/main/java/org/gradle/internal/resource/transport/sftp/SftpResourcesPluginServiceRegistry.java
@@ -26,6 +26,9 @@ public class SftpResourcesPluginServiceRegistry implements PluginServiceRegistry
registration.addProvider(new GlobalScopeServices());
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
public void registerBuildServices(ServiceRegistration registration) {
}
diff --git a/subprojects/resources-sftp/src/test/groovy/org/gradle/internal/resource/transport/sftp/SftpClientFactoryTest.groovy b/subprojects/resources-sftp/src/test/groovy/org/gradle/internal/resource/transport/sftp/SftpClientFactoryTest.groovy
index 2d9fabc..7a5d4c7 100644
--- a/subprojects/resources-sftp/src/test/groovy/org/gradle/internal/resource/transport/sftp/SftpClientFactoryTest.groovy
+++ b/subprojects/resources-sftp/src/test/groovy/org/gradle/internal/resource/transport/sftp/SftpClientFactoryTest.groovy
@@ -15,7 +15,9 @@
*/
package org.gradle.internal.resource.transport.sftp
-import org.gradle.internal.resource.PasswordCredentials
+
+import org.gradle.api.artifacts.repositories.PasswordCredentials
+import org.gradle.api.internal.artifacts.repositories.DefaultPasswordCredentials
import org.gradle.test.fixtures.concurrent.ConcurrentSpec
import static org.gradle.internal.resource.transport.sftp.SftpClientFactory.SftpClientCreator
@@ -33,7 +35,7 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri = new URI('http://localhost:22/repo')
- PasswordCredentials credentials = new PasswordCredentials('sftp', 'sftp')
+ PasswordCredentials credentials = new DefaultPasswordCredentials('sftp', 'sftp')
when:
LockableSftpClient actualClient = sftpClientFactory.createSftpClient(uri, credentials)
@@ -59,7 +61,7 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri = new URI('http://localhost:22/repo')
- PasswordCredentials credentials = new PasswordCredentials('sftp', 'sftp')
+ PasswordCredentials credentials = new DefaultPasswordCredentials('sftp', 'sftp')
when:
LockableSftpClient initialClient = sftpClientFactory.createSftpClient(uri, credentials)
@@ -82,7 +84,7 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri = new URI('http://localhost:22/repo')
- PasswordCredentials credentials = new PasswordCredentials('sftp', 'sftp')
+ PasswordCredentials credentials = new DefaultPasswordCredentials('sftp', 'sftp')
when:
LockableSftpClient initialClient = sftpClientFactory.createSftpClient(uri, credentials)
@@ -115,8 +117,8 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri1 = new URI('http://localhost:22/repo1')
URI uri2 = new URI('http://localhost:22/repo2')
- PasswordCredentials credentials1 = new PasswordCredentials('sftp1', 'sftp1')
- PasswordCredentials credentials2 = new PasswordCredentials('sftp2', 'sftp2')
+ PasswordCredentials credentials1 = new DefaultPasswordCredentials('sftp1', 'sftp1')
+ PasswordCredentials credentials2 = new DefaultPasswordCredentials('sftp2', 'sftp2')
when:
LockableSftpClient client1 = sftpClientFactory.createSftpClient(uri1, credentials1)
@@ -148,7 +150,7 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri = new URI('http://localhost:22/repo')
- PasswordCredentials credentials = new PasswordCredentials('sftp', 'sftp')
+ PasswordCredentials credentials = new DefaultPasswordCredentials('sftp', 'sftp')
when:
LockableSftpClient actualClient = sftpClientFactory.createSftpClient(uri, credentials)
@@ -171,8 +173,8 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri1 = new URI('http://localhost:22/repo1')
URI uri2 = new URI('http://localhost:22/repo2')
- PasswordCredentials credentials1 = new PasswordCredentials('sftp1', 'sftp1')
- PasswordCredentials credentials2 = new PasswordCredentials('sftp2', 'sftp2')
+ PasswordCredentials credentials1 = new DefaultPasswordCredentials('sftp1', 'sftp1')
+ PasswordCredentials credentials2 = new DefaultPasswordCredentials('sftp2', 'sftp2')
when:
LockableSftpClient client1 = sftpClientFactory.createSftpClient(uri1, credentials1)
@@ -198,7 +200,7 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri = new URI('http://localhost:22/repo')
- PasswordCredentials credentials = new PasswordCredentials('sftp', 'sftp')
+ PasswordCredentials credentials = new DefaultPasswordCredentials('sftp', 'sftp')
when:
async {
@@ -223,7 +225,7 @@ class SftpClientFactoryTest extends ConcurrentSpec {
given:
URI uri = new URI('http://localhost:22/repo')
- PasswordCredentials credentials = new PasswordCredentials('sftp', 'sftp')
+ PasswordCredentials credentials = new DefaultPasswordCredentials('sftp', 'sftp')
LockableSftpClient actualClient1
LockableSftpClient actualClient2
diff --git a/subprojects/resources/src/main/java/org/gradle/authentication/Authentication.java b/subprojects/resources/src/main/java/org/gradle/authentication/Authentication.java
new file mode 100644
index 0000000..0c1423a
--- /dev/null
+++ b/subprojects/resources/src/main/java/org/gradle/authentication/Authentication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.authentication;
+
+import org.gradle.api.Incubating;
+import org.gradle.api.Named;
+import org.gradle.internal.HasInternalProtocol;
+
+/**
+ * Base interface for transport authentication schemes.
+ */
+ at Incubating
+ at HasInternalProtocol
+public interface Authentication extends Named {
+}
diff --git a/subprojects/resources/src/main/java/org/gradle/authentication/package-info.java b/subprojects/resources/src/main/java/org/gradle/authentication/package-info.java
new file mode 100644
index 0000000..12d2672
--- /dev/null
+++ b/subprojects/resources/src/main/java/org/gradle/authentication/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Classes related to transport authentication protocols.
+ *
+ * @since 2.7
+ */
+ at Incubating
+package org.gradle.authentication;
+
+import org.gradle.api.Incubating;
diff --git a/subprojects/resources/src/main/java/org/gradle/internal/authentication/AuthenticationSchemeRegistry.java b/subprojects/resources/src/main/java/org/gradle/internal/authentication/AuthenticationSchemeRegistry.java
new file mode 100644
index 0000000..941396d
--- /dev/null
+++ b/subprojects/resources/src/main/java/org/gradle/internal/authentication/AuthenticationSchemeRegistry.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import org.gradle.authentication.Authentication;
+
+import java.util.Map;
+
+public interface AuthenticationSchemeRegistry {
+ <T extends Authentication> void registerScheme(Class<T> type, final Class<? extends T> implementationType);
+ <T extends Authentication> Map<Class<T>, Class<? extends T>> getRegisteredSchemes();
+}
diff --git a/subprojects/resources/src/main/java/org/gradle/internal/authentication/DefaultAuthenticationSchemeRegistry.java b/subprojects/resources/src/main/java/org/gradle/internal/authentication/DefaultAuthenticationSchemeRegistry.java
new file mode 100644
index 0000000..be74b9f
--- /dev/null
+++ b/subprojects/resources/src/main/java/org/gradle/internal/authentication/DefaultAuthenticationSchemeRegistry.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.internal.authentication;
+
+import com.google.common.collect.Maps;
+import org.gradle.authentication.Authentication;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class DefaultAuthenticationSchemeRegistry implements AuthenticationSchemeRegistry {
+ Map<Class<? extends Authentication>, Class<? extends Authentication>> registeredSchemes = Maps.newHashMap();
+
+ @Override
+ public <T extends Authentication> void registerScheme(Class<T> type, final Class<? extends T> implementationType) {
+ registeredSchemes.put(type, implementationType);
+ }
+
+ @Override
+ public Map<Class<? extends Authentication>, Class<? extends Authentication>> getRegisteredSchemes() {
+ return Collections.unmodifiableMap(registeredSchemes);
+ }
+}
diff --git a/subprojects/resources/src/main/java/org/gradle/internal/resource/PasswordCredentials.java b/subprojects/resources/src/main/java/org/gradle/internal/resource/PasswordCredentials.java
deleted file mode 100644
index e36190a..0000000
--- a/subprojects/resources/src/main/java/org/gradle/internal/resource/PasswordCredentials.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.internal.resource;
-
-public class PasswordCredentials {
-
- private final String username;
- private final String password;
-
- public PasswordCredentials() {
- this(null, null);
- }
-
- public PasswordCredentials(String username, String password) {
- this.username = username;
- this.password = password;
- }
-
- public String getUsername() {
- return username;
- }
-
- public String getPassword() {
- return password;
- }
-
-}
diff --git a/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorFactory.java b/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorFactory.java
index 81a9aaf..7d589eb 100644
--- a/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorFactory.java
+++ b/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorFactory.java
@@ -16,6 +16,7 @@
package org.gradle.internal.resource.connector;
+import org.gradle.authentication.Authentication;
import org.gradle.internal.resource.transfer.ExternalResourceConnector;
import java.util.Set;
@@ -23,5 +24,7 @@ import java.util.Set;
public interface ResourceConnectorFactory {
Set<String> getSupportedProtocols();
+ Set<Class<? extends Authentication>> getSupportedAuthentication();
+
ExternalResourceConnector createResourceConnector(ResourceConnectorSpecification connectionDetails);
}
diff --git a/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorSpecification.java b/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorSpecification.java
index 5852d3b..d190b0f 100644
--- a/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorSpecification.java
+++ b/subprojects/resources/src/main/java/org/gradle/internal/resource/connector/ResourceConnectorSpecification.java
@@ -16,7 +16,12 @@
package org.gradle.internal.resource.connector;
+import org.gradle.authentication.Authentication;
+
+import java.util.Collection;
+
public interface ResourceConnectorSpecification {
- // TODO:DAZ <T extends Credentials>
<T> T getCredentials(Class<T> type);
+
+ Collection<Authentication> getAuthentications();
}
diff --git a/subprojects/scala/scala.gradle b/subprojects/scala/scala.gradle
index ac227b0..6e849a1 100644
--- a/subprojects/scala/scala.gradle
+++ b/subprojects/scala/scala.gradle
@@ -30,6 +30,6 @@ dependencies {
useTestFixtures(project: ":plugins") // includes core test fixtures
-configure([integTest, daemonIntegTest]) {
+integTest {
jvmArgs "-XX:MaxPermSize=1500m" // AntInProcessScalaCompilerIntegrationTest needs lots of permgen
}
diff --git a/subprojects/scala/src/integTest/groovy/org/gradle/integtests/fixtures/ZincCoverage.groovy b/subprojects/scala/src/integTest/groovy/org/gradle/integtests/fixtures/ZincCoverage.groovy
new file mode 100644
index 0000000..10e5a22
--- /dev/null
+++ b/subprojects/scala/src/integTest/groovy/org/gradle/integtests/fixtures/ZincCoverage.groovy
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.fixtures
+
+import org.gradle.language.scala.internal.toolchain.DefaultScalaToolProvider
+
+
+class ZincCoverage {
+ public static final List<String> ALL_VERSIONS = [ "0.3.0", "0.3.5.3", DefaultScalaToolProvider.DEFAULT_ZINC_VERSION ]
+}
diff --git a/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy b/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy
index 0d6b774..05b5813 100644
--- a/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy
+++ b/subprojects/scala/src/integTest/groovy/org/gradle/scala/ScalaPluginIntegrationTest.groovy
@@ -16,14 +16,11 @@
package org.gradle.scala
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
-import org.gradle.util.Requires
-import org.gradle.util.TestPrecondition
import spock.lang.Issue
class ScalaPluginIntegrationTest extends AbstractIntegrationSpec {
- @Requires(TestPrecondition.JDK8_OR_LATER)
@Issue("https://issues.gradle.org/browse/GRADLE-3094")
- def "can apply scala plugin when running under java 8"() {
+ def "can apply scala plugin"() {
file("build.gradle") << """
apply plugin: "scala"
diff --git a/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AbstractAntInProcessScalaCompilerIntegrationTest.groovy b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AbstractAntInProcessScalaCompilerIntegrationTest.groovy
index f8a796d..3c57441 100644
--- a/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AbstractAntInProcessScalaCompilerIntegrationTest.groovy
+++ b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AbstractAntInProcessScalaCompilerIntegrationTest.groovy
@@ -16,13 +16,16 @@
package org.gradle.scala.compile
-import org.gradle.integtests.fixtures.ScalaCoverage
-import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
- at TargetCoverage({ScalaCoverage.DEFAULT})
abstract class AbstractAntInProcessScalaCompilerIntegrationTest extends BasicScalaCompilerIntegrationTest {
def setup() {
executer.requireIsolatedDaemons()
+ if (GradleContextualExecuter.daemon) {
+ executer.beforeExecute {
+ executer.withBuildJvmOpts("-XX:MaxPermSize=320m")
+ }
+ }
}
String compilerConfiguration() {
diff --git a/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AntInProcessOlderScalaCompilerIntegrationTest.groovy b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AntInProcessOlderScalaCompilerIntegrationTest.groovy
index cb4ba96..51cf58b 100644
--- a/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AntInProcessOlderScalaCompilerIntegrationTest.groovy
+++ b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/AntInProcessOlderScalaCompilerIntegrationTest.groovy
@@ -22,7 +22,7 @@ import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
- at TargetCoverage({ScalaCoverage.DEFAULT})
+ at TargetCoverage({ScalaCoverage.OLDER})
@Requires(TestPrecondition.JDK7_OR_EARLIER)
@LeaksFileHandles
class AntInProcessOlderScalaCompilerIntegrationTest extends AbstractAntInProcessScalaCompilerIntegrationTest {}
diff --git a/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/ZincScalaCompilerMultiVersionIntegrationTest.groovy b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/ZincScalaCompilerMultiVersionIntegrationTest.groovy
new file mode 100644
index 0000000..d02889e
--- /dev/null
+++ b/subprojects/scala/src/integTest/groovy/org/gradle/scala/compile/ZincScalaCompilerMultiVersionIntegrationTest.groovy
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.scala.compile
+
+import org.gradle.integtests.fixtures.MultiVersionIntegrationSpec
+import org.gradle.integtests.fixtures.TargetCoverage
+import org.gradle.integtests.fixtures.ZincCoverage
+
+ at TargetCoverage({ZincCoverage.ALL_VERSIONS})
+class ZincScalaCompilerMultiVersionIntegrationTest extends MultiVersionIntegrationSpec {
+ def setup() {
+ buildFile << """
+ apply plugin: "scala"
+
+ repositories {
+ jcenter()
+ }
+
+ dependencies {
+ compile "org.scala-lang:scala-library:2.10.4"
+ zinc "com.typesafe.zinc:zinc:${version}"
+ }
+
+ tasks.withType(ScalaCompile) {
+ scalaCompileOptions.useAnt = false
+ }
+ """
+ args("--info")
+ }
+
+ def "can build with configured zinc compiler version" () {
+ given:
+ withScalaSources()
+
+ expect:
+ succeeds("compileScala")
+ output.contains("Compiling with Zinc Scala compiler")
+ file("build/classes/main/compile/test").assertContainsDescendants(
+ "Person.class",
+ "Person2.class"
+ )
+ }
+
+ def withScalaSources() {
+ file("src/main/scala/compile/test/Person.scala") <<
+ """
+package compile.test
+
+import scala.collection.JavaConversions._
+
+class Person(val name: String, val age: Int) {
+ def hello() {
+ val x: java.util.List[Int] = List(3, 1, 2)
+ java.util.Collections.reverse(x)
+ }
+}
+"""
+ file("src/main/scala/compile/test/Person2.scala") <<
+ """
+package compile.test
+
+class Person2(name: String, age: Int) extends Person(name, age) {
+}
+"""
+ }
+}
diff --git a/subprojects/scala/src/main/groovy/org/gradle/api/tasks/ScalaRuntime.java b/subprojects/scala/src/main/groovy/org/gradle/api/tasks/ScalaRuntime.java
index 380beb7..5e66c56 100644
--- a/subprojects/scala/src/main/groovy/org/gradle/api/tasks/ScalaRuntime.java
+++ b/subprojects/scala/src/main/groovy/org/gradle/api/tasks/ScalaRuntime.java
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
/**
* Provides information related to the Scala runtime(s) used in a project. Added by the
- * {@link org.gradle.api.plugins.scala.ScalaBasePlugin} as a project extension named {@code scalaRuntime}.
+ * {@code org.gradle.api.plugins.scala.ScalaBasePlugin} as a project extension named {@code scalaRuntime}.
*
* <p>Example usage:
*
diff --git a/subprojects/scala/src/main/groovy/org/gradle/api/tasks/scala/package-info.java b/subprojects/scala/src/main/groovy/org/gradle/api/tasks/scala/package-info.java
deleted file mode 100644
index 0b6744f..0000000
--- a/subprojects/scala/src/main/groovy/org/gradle/api/tasks/scala/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Scala {@link org.gradle.api.Task} implementations.
- */
-package org.gradle.api.tasks.scala;
diff --git a/subprojects/sonar/src/integTest/groovy/org/gradle/api/plugins/sonar/SonarSmokeIntegrationTest.groovy b/subprojects/sonar/src/integTest/groovy/org/gradle/api/plugins/sonar/SonarSmokeIntegrationTest.groovy
index 1dec253..e9ffb0a 100644
--- a/subprojects/sonar/src/integTest/groovy/org/gradle/api/plugins/sonar/SonarSmokeIntegrationTest.groovy
+++ b/subprojects/sonar/src/integTest/groovy/org/gradle/api/plugins/sonar/SonarSmokeIntegrationTest.groovy
@@ -19,12 +19,13 @@ package org.gradle.api.plugins.sonar
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.TestResources
import org.gradle.internal.classloader.ClasspathUtil
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.test.fixtures.server.http.ServletContainer
-import org.gradle.util.AvailablePortFinder
-import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
+import org.gradle.util.ports.FixedAvailablePortAllocator
+import org.gradle.util.ports.PortAllocator
import org.junit.Rule
import spock.lang.AutoCleanup
import spock.lang.Shared
@@ -32,7 +33,7 @@ import spock.lang.Shared
@Requires(TestPrecondition.JDK7_OR_EARLIER)
class SonarSmokeIntegrationTest extends AbstractIntegrationSpec {
@Shared
- AvailablePortFinder portFinder = AvailablePortFinder.createPrivate()
+ PortAllocator portFinder = FixedAvailablePortAllocator.getInstance()
@AutoCleanup("stop")
ServletContainer container
@@ -56,7 +57,7 @@ class SonarSmokeIntegrationTest extends AbstractIntegrationSpec {
System.setProperty("SONAR_HOME", sonarHome.path)
new AntBuilder().unzip(src: zipFile, dest: sonarHome, overwrite: true)
- databasePort = portFinder.nextAvailable
+ databasePort = portFinder.assignPort()
sonarHome.file("conf/sonar.properties") << """
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar
@@ -68,6 +69,10 @@ sonar.embeddedDatabase.port=$databasePort
container.start()
}
+ def cleanup() {
+ portFinder.releasePort(databasePort)
+ }
+
@LeaksFileHandles
def "can run Sonar analysis"() {
executer.requireIsolatedDaemons()
diff --git a/subprojects/sonar/src/integTest/groovy/org/gradle/sonar/runner/SonarTestServer.groovy b/subprojects/sonar/src/integTest/groovy/org/gradle/sonar/runner/SonarTestServer.groovy
index 8055ea0..de7260e 100644
--- a/subprojects/sonar/src/integTest/groovy/org/gradle/sonar/runner/SonarTestServer.groovy
+++ b/subprojects/sonar/src/integTest/groovy/org/gradle/sonar/runner/SonarTestServer.groovy
@@ -26,13 +26,14 @@ import org.gradle.internal.classloader.ClasspathUtil
import org.gradle.internal.jvm.Jvm
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
-import org.gradle.util.AvailablePortFinder
+import org.gradle.util.ports.FixedAvailablePortAllocator
+import org.gradle.util.ports.PortAllocator
import org.junit.rules.ExternalResource
class SonarTestServer extends ExternalResource {
private TestNameTestDirectoryProvider provider
- private AvailablePortFinder portFinder
+ private PortAllocator portFinder
private int databasePort
private int httpPort
@@ -41,7 +42,7 @@ class SonarTestServer extends ExternalResource {
SonarTestServer(TestNameTestDirectoryProvider provider, GradleExecuter gradleExecuter) {
this.provider = provider
- this.portFinder = AvailablePortFinder.createPrivate()
+ this.portFinder = FixedAvailablePortAllocator.getInstance()
gradleExecuter.beforeExecute {
withArgument("-Dsonar.host.url=http://localhost:${httpPort}")
@@ -60,6 +61,8 @@ class SonarTestServer extends ExternalResource {
@Override
protected void after() {
stopServer()
+ portFinder.releasePort(httpPort)
+ portFinder.releasePort(databasePort)
}
void startServer() {
@@ -82,8 +85,8 @@ class SonarTestServer extends ExternalResource {
}
private TestFile prepareSonarHomeFolder() {
- databasePort = portFinder.nextAvailable
- httpPort = portFinder.nextAvailable
+ databasePort = portFinder.assignPort()
+ httpPort = portFinder.assignPort()
def classpath = ClasspathUtil.getClasspath(getClass().classLoader).collect() {
new File(it.toURI())
}
@@ -135,4 +138,4 @@ class SonarTestServer extends ExternalResource {
void assertProjectPresent(String name) {
assert getResources()*.key.contains(name)
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/TestKitEndUserIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/TestKitEndUserIntegrationTest.groovy
new file mode 100644
index 0000000..98a2368
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/TestKitEndUserIntegrationTest.groovy
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.daemon.DaemonLogsAnalyzer
+import org.gradle.integtests.fixtures.executer.ExecutionResult
+import org.gradle.test.fixtures.file.LeaksFileHandles
+import org.gradle.test.fixtures.file.TestFile
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.internal.TempTestKitDirProvider
+import org.gradle.util.GFileUtils
+
+class TestKitEndUserIntegrationTest extends AbstractIntegrationSpec {
+ def setup() {
+ executer.requireGradleHome().withStackTraceChecksDisabled()
+ buildFile << buildFileForGroovyProject()
+ }
+
+ def "use of GradleRunner API in test class without declaring test-kit dependency causes compilation error"() {
+ given:
+ writeTest(buildLogicFunctionalTestCreatingGradleRunner())
+
+ when:
+ fails('build')
+
+ then:
+ executedAndNotSkipped(':compileTestGroovy')
+ failureHasCause('Compilation failed; see the compiler error output for details.')
+ failure.error.contains("unable to resolve class $GradleRunner.name")
+ }
+
+ private TestFile writeTest(String content, String className = 'BuildLogicFunctionalTest') {
+ testDirectoryProvider.file("src/test/groovy/org/gradle/test/${className}.groovy") << content
+ }
+
+ def "use of GradleRunner API in test class by depending on external test-kit dependency causes compilation error"() {
+ File gradleDistPluginsDir = new File(distribution.gradleHomeDir, 'lib/plugins')
+ File[] gradleTestKitLibs = gradleDistPluginsDir.listFiles(new GradleTestKitJarFilenameFilter())
+ assert gradleTestKitLibs.length == 1
+ File gradleTestKitLib = gradleTestKitLibs[0]
+ TestFile libDir = testDirectoryProvider.createDir('lib')
+ GFileUtils.copyFile(gradleTestKitLib, new File(libDir, gradleTestKitLib.name))
+
+ buildFile << libDirDependency()
+ writeTest(buildLogicFunctionalTestCreatingGradleRunner())
+
+ when:
+ fails('build')
+
+ then:
+ executedAndNotSkipped(':compileTestGroovy')
+ failure.error.contains("Unable to load class $GradleRunner.name due to missing dependency")
+ }
+
+ def "creating GradleRunner instance by depending on Gradle libraries outside of Gradle distribution throws exception"() {
+ File gradleDistLibDir = new File(distribution.gradleHomeDir, 'lib')
+ File gradleDistPluginsDir = new File(gradleDistLibDir, 'plugins')
+ File[] gradleCoreLibs = gradleDistLibDir.listFiles(new GradleCoreJarFilenameFilter())
+ File[] gradleTestKitLibs = gradleDistPluginsDir.listFiles(new GradleTestKitJarFilenameFilter())
+ assert gradleCoreLibs.length == 3
+ assert gradleTestKitLibs.length == 1
+ File[] allGradleLibs = gradleCoreLibs + gradleTestKitLibs
+ TestFile libDir = testDirectoryProvider.createDir('lib')
+
+ allGradleLibs.each {
+ GFileUtils.copyFile(it, new File(libDir, it.name))
+ }
+
+ buildFile << libDirDependency()
+ writeTest(buildLogicFunctionalTestCreatingGradleRunner())
+
+ when:
+ fails('build')
+
+ then:
+ executedAndNotSkipped(':test')
+ failure.output.contains('java.lang.IllegalStateException: Could not create a GradleRunner, as the GradleRunner class was not loaded from a Gradle distribution')
+ }
+
+ def "successfully execute functional test and verify expected result"() {
+ buildFile << gradleTestKitDependency()
+ writeTest successfulSpockTest('BuildLogicFunctionalTest')
+
+ when:
+ succeeds('build')
+
+ then:
+ executedAndNotSkipped(":test", ":build")
+ assertDaemonsAreStopping()
+ }
+
+ def "successfully execute functional tests with parallel forks"() {
+ buildFile << gradleTestKitDependency()
+ buildFile << """
+ test {
+ maxParallelForks = 3
+
+ testLogging {
+ events 'started'
+ }
+ }
+ """
+
+ def testClassNames = (1..10).collect { "BuildLogicFunctionalTest$it" }
+
+ testClassNames.each { testClassName ->
+ writeTest successfulSpockTest(testClassName), testClassName
+ }
+
+ when:
+ ExecutionResult result = succeeds('build')
+
+ then:
+ executedAndNotSkipped(":test", ":build")
+
+ testClassNames.each { testClassName ->
+ assert result.assertOutputContains("org.gradle.test.${testClassName} > execute helloWorld task STARTED")
+ }
+
+ assertDaemonsAreStopping()
+ }
+
+ def "successfully execute functional test with custom Gradle user home directory"() {
+ buildFile << gradleTestKitDependency()
+ writeTest """
+ package org.gradle.test
+
+ import org.gradle.testkit.runner.GradleRunner
+ import static org.gradle.testkit.runner.TaskOutcome.*
+ import org.junit.Rule
+ import org.junit.rules.TemporaryFolder
+ import spock.lang.Specification
+
+ class BuildLogicFunctionalTest extends Specification {
+ @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
+ @Rule final TemporaryFolder testGradleUserHomeDir = new TemporaryFolder()
+
+ File buildFile
+
+ def setup() {
+ buildFile = testProjectDir.newFile('build.gradle')
+ }
+
+ def "execute helloWorld task"() {
+ given:
+ buildFile << '''
+ task helloWorld {
+ doLast {
+ println 'Hello world!'
+ }
+ }
+ '''
+
+ when:
+ def result = GradleRunner.create()
+ .withProjectDir(testProjectDir.root)
+ .withArguments('helloWorld')
+ .withTestKitDir(testGradleUserHomeDir.root)
+ .build()
+
+ then:
+ result.standardOutput.contains('Hello world!')
+ result.standardError == ''
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+ }
+ """
+
+ when:
+ succeeds('build')
+
+ then:
+ executedAndNotSkipped(":test", ":build")
+ assertDaemonsAreStopping()
+ }
+
+ def "functional test fails due to invalid JVM parameter for test execution"() {
+ buildFile << gradleTestKitDependency()
+ writeTest """
+ package org.gradle.test
+
+ import org.gradle.testkit.runner.GradleRunner
+ import static org.gradle.testkit.runner.TaskOutcome.*
+ import org.junit.Rule
+ import org.junit.rules.TemporaryFolder
+ import spock.lang.Specification
+
+ class BuildLogicFunctionalTest extends Specification {
+ @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
+ File buildFile
+
+ def setup() {
+ buildFile = testProjectDir.newFile('build.gradle')
+ new File(testProjectDir.root, 'gradle.properties') << 'org.gradle.jvmargs=-unknown'
+ }
+
+ def "execute helloWorld task"() {
+ given:
+ buildFile << '''
+ task helloWorld {
+ doLast {
+ println 'Hello world!'
+ }
+ }
+ '''
+
+ expect:
+ GradleRunner.create()
+ .withProjectDir(testProjectDir.root)
+ .withArguments('helloWorld')
+ .build()
+ }
+ }
+ """
+
+ when:
+ fails('build')
+
+ then:
+ failureDescriptionContains("Execution failed for task ':test'.")
+ // IBM JVM produces a slightly different error message
+ failure.output.contains('Unrecognized option: -unknown') || failure.output.contains('Command-line option unrecognised: -unknown')
+ assertDaemonsAreStopping()
+ }
+
+ @LeaksFileHandles
+ def "can test plugin and custom task as external files by adding them to the build script's classpath"() {
+ file("settings.gradle") << "include 'sub'"
+ file("sub/build.gradle") << "apply plugin: 'groovy'; dependencies { compile localGroovy() }"
+ file("sub/src/main/groovy/org/gradle/test/lib/Support.groovy") << "package org.gradle.test.lib; class Support { static String MSG = 'Hello world!' }"
+
+ buildFile <<
+ gradleApiDependency() <<
+ gradleTestKitDependency() <<
+ """
+ dependencies {
+ compile project(":sub")
+ }
+
+ task createClasspathManifest {
+ def outputDir = file("\$buildDir/\$name")
+
+ inputs.files sourceSets.main.runtimeClasspath
+ outputs.dir outputDir
+
+ doLast {
+ outputDir.mkdirs()
+ file("\$outputDir/plugin-classpath.txt").text = sourceSets.main.runtimeClasspath.join("\\n")
+ }
+ }
+
+ dependencies {
+ testCompile files(createClasspathManifest)
+ }
+ """
+
+ file("src/main/groovy/org/gradle/test/HelloWorldPlugin.groovy") << """
+ package org.gradle.test
+
+ import org.gradle.api.Plugin
+ import org.gradle.api.Project
+
+ class HelloWorldPlugin implements Plugin<Project> {
+ void apply(Project project) {
+ project.task('helloWorld', type: HelloWorld)
+ }
+ }
+ """
+
+ file("src/main/groovy/org/gradle/test/HelloWorld.groovy") << """
+ package org.gradle.test
+
+ import org.gradle.api.DefaultTask
+ import org.gradle.api.tasks.TaskAction
+ import org.gradle.test.lib.Support
+
+ class HelloWorld extends DefaultTask {
+ @TaskAction
+ void doSomething() {
+ println Support.MSG
+ }
+ }
+ """
+
+ writeTest """
+ package org.gradle.test
+
+ import org.gradle.testkit.runner.GradleRunner
+ import static org.gradle.testkit.runner.TaskOutcome.*
+ import org.junit.Rule
+ import org.junit.rules.TemporaryFolder
+ import spock.lang.Specification
+
+ class BuildLogicFunctionalTest extends Specification {
+ @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
+ File buildFile
+
+ def setup() {
+ buildFile = testProjectDir.newFile('build.gradle')
+ def pluginClasspath = getClass().classLoader.findResource("plugin-classpath.txt")
+ .readLines()
+ .collect { it.replace('\\\\', '\\\\\\\\') } // escape backslashes in Windows paths
+ .collect { "'\$it'" }
+ .join(", ")
+
+ buildFile << \"\"\"
+ buildscript {
+ dependencies {
+ classpath files(\$pluginClasspath)
+ }
+ }
+ \"\"\"
+ }
+
+ def "execute helloWorld task"() {
+ given:
+ buildFile << 'apply plugin: org.gradle.test.HelloWorldPlugin'
+
+ when:
+ def result = GradleRunner.create()
+ .withProjectDir(testProjectDir.root)
+ .withArguments('helloWorld')
+ .build()
+
+ then:
+ result.standardOutput.contains('Hello world!')
+ result.standardError == ''
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+ }
+ """
+
+ when:
+ succeeds('build')
+
+ then:
+ executedAndNotSkipped(':test')
+ assertDaemonsAreStopping()
+ }
+
+ private DaemonLogsAnalyzer createDaemonLogAnalyzer() {
+ File daemonBaseDir = new File(new TempTestKitDirProvider().getDir(), 'daemon')
+ DaemonLogsAnalyzer.newAnalyzer(daemonBaseDir, executer.distribution.version.version)
+ }
+
+ private void assertDaemonsAreStopping() {
+ createDaemonLogAnalyzer().visible*.stops()
+ }
+
+ private static String buildFileForGroovyProject() {
+ """
+ apply plugin: 'groovy'
+
+ dependencies {
+ compile localGroovy()
+ testCompile 'org.spockframework:spock-core:1.0-groovy-2.3'
+ }
+
+ repositories {
+ mavenCentral()
+ }
+
+ test.testLogging.exceptionFormat = 'full'
+ """
+ }
+
+ private static String gradleTestKitDependency() {
+ """
+ dependencies {
+ testCompile gradleTestKit()
+ }
+ """
+ }
+
+ private static String gradleApiDependency() {
+ """
+ dependencies {
+ compile gradleApi()
+ }
+ """
+ }
+
+ private static String libDirDependency() {
+ """
+ dependencies {
+ testCompile fileTree(dir: 'lib', include: '*.jar')
+ }
+ """
+ }
+
+ private static String buildLogicFunctionalTestCreatingGradleRunner() {
+ """
+ package org.gradle.test
+
+ import org.gradle.testkit.runner.GradleRunner
+ import spock.lang.Specification
+
+ class BuildLogicFunctionalTest extends Specification {
+ def "create GradleRunner"() {
+ expect:
+ GradleRunner.create()
+ }
+ }
+ """
+ }
+
+ private static String successfulSpockTest(String className) {
+ """
+ package org.gradle.test
+
+ import org.gradle.testkit.runner.GradleRunner
+ import static org.gradle.testkit.runner.TaskOutcome.*
+ import org.junit.Rule
+ import org.junit.rules.TemporaryFolder
+ import spock.lang.Specification
+
+ class $className extends Specification {
+ @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
+ File buildFile
+
+ def setup() {
+ buildFile = testProjectDir.newFile('build.gradle')
+ }
+
+ def "execute helloWorld task"() {
+ given:
+ buildFile << '''
+ task helloWorld {
+ doLast {
+ println 'Hello world!'
+ }
+ }
+ '''
+
+ when:
+ def result = GradleRunner.create()
+ .withProjectDir(testProjectDir.root)
+ .withArguments('helloWorld')
+ .build()
+
+ then:
+ result.standardOutput.contains('Hello world!')
+ result.standardError == ''
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+ }
+ """
+ }
+
+ private class GradleTestKitJarFilenameFilter implements FilenameFilter {
+ boolean accept(File dir, String name) {
+ name.startsWith('gradle-test-kit')
+ }
+ }
+
+ private class GradleCoreJarFilenameFilter implements FilenameFilter {
+ boolean accept(File dir, String name) {
+ name.startsWith('gradle-core') || name.startsWith('gradle-base-services')
+ }
+ }
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/TestKitSamplesIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/TestKitSamplesIntegrationTest.groovy
new file mode 100644
index 0000000..791174f
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/TestKitSamplesIntegrationTest.groovy
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.testkit
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.integtests.fixtures.Sample
+import org.gradle.integtests.fixtures.UsesSample
+import org.gradle.test.fixtures.file.LeaksFileHandles
+import org.junit.Rule
+
+ at LeaksFileHandles
+class TestKitSamplesIntegrationTest extends AbstractIntegrationSpec {
+
+ @Rule Sample sample = new Sample(testDirectoryProvider)
+
+ def setup() {
+ executer.requireGradleHome()
+ }
+
+ @UsesSample("testKit/testKitJunit")
+ def junit() {
+ expect:
+ executer.inDirectory(sample.dir)
+ succeeds "check"
+ }
+
+ @UsesSample("testKit/testKitSpock")
+ def spock() {
+ expect:
+ executer.inDirectory(sample.dir)
+ succeeds "check"
+ }
+
+ @UsesSample("testKit/testKitSpockClasspath")
+ def buildscriptClasspath() {
+ expect:
+ executer.inDirectory(sample.dir)
+ succeeds "check"
+ }
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/AbstractGradleRunnerIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/AbstractGradleRunnerIntegrationTest.groovy
new file mode 100644
index 0000000..5951288
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/AbstractGradleRunnerIntegrationTest.groovy
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner
+
+import org.gradle.integtests.fixtures.daemon.DaemonLogsAnalyzer
+import org.gradle.integtests.fixtures.daemon.DaemonsFixture
+import org.gradle.integtests.fixtures.executer.IntegrationTestBuildContext
+import org.gradle.internal.nativeintegration.services.NativeServices
+import org.gradle.internal.os.OperatingSystem
+import org.gradle.test.fixtures.file.TestFile
+import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.gradle.testkit.runner.internal.DefaultGradleRunner
+import org.gradle.testkit.runner.internal.TestKitGradleExecutor
+import org.gradle.util.SetSystemProperties
+import org.junit.Rule
+import spock.lang.Shared
+import spock.lang.Specification
+
+abstract class AbstractGradleRunnerIntegrationTest extends Specification {
+
+ @Shared
+ IntegrationTestBuildContext buildContext = new IntegrationTestBuildContext()
+
+ @Rule
+ TestNameTestDirectoryProvider testProjectDir = new TestNameTestDirectoryProvider()
+
+ @Rule
+ SetSystemProperties setSystemProperties = new SetSystemProperties((NativeServices.NATIVE_DIR_OVERRIDE): buildContext.gradleUserHomeDir.file("native").absolutePath)
+
+ TestFile getTestKitWorkspace() {
+ testProjectDir.file("test-kit-workspace")
+ }
+
+ TestFile getBuildFile() {
+ file('build.gradle')
+ }
+
+ TestFile file(String path) {
+ testProjectDir.file(path)
+ }
+
+ protected DefaultGradleRunner runner(List<String> arguments) {
+ return runner(arguments as String[])
+ }
+
+ DefaultGradleRunner runner(String... arguments) {
+ new DefaultGradleRunner(buildContext.gradleHomeDir)
+ .withTestKitDir(testKitWorkspace)
+ .withProjectDir(testProjectDir.testDirectory)
+ .withArguments(arguments)
+ }
+
+ static String helloWorldTask() {
+ """
+ task helloWorld {
+ doLast {
+ println 'Hello world!'
+ }
+ }
+ """
+ }
+
+ DaemonsFixture daemons(File gradleUserHomeDir, String daemonDir = 'daemon') {
+ DaemonLogsAnalyzer.newAnalyzer(new File(gradleUserHomeDir, daemonDir), buildContext.version.version)
+ }
+
+ DaemonsFixture daemons() {
+ daemons(testKitWorkspace, TestKitGradleExecutor.TEST_KIT_DAEMON_DIR_NAME)
+ }
+
+ def cleanup() {
+ daemons().killAll()
+ if (OperatingSystem.current().isWindows()) {
+ sleep 1000 // wait for process to release files
+ }
+ }
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerArgumentsIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerArgumentsIntegrationTest.groovy
new file mode 100644
index 0000000..92366a0
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerArgumentsIntegrationTest.groovy
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner
+
+import spock.lang.Unroll
+
+import static org.gradle.testkit.runner.TaskOutcome.*
+
+class GradleRunnerArgumentsIntegrationTest extends AbstractGradleRunnerIntegrationTest {
+
+ def "can execute build without specifying any arguments"() {
+ when:
+ GradleRunner gradleRunner = runner()
+ BuildResult result = gradleRunner.build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':help')
+ !result.standardError
+ result.tasks.collect { it.path } == [':help']
+ result.taskPaths(SUCCESS) == [':help']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ def "execute build for multiple tasks"() {
+ given:
+ buildFile << helloWorldTask()
+ buildFile << """
+ task byeWorld {
+ doLast {
+ println 'Bye world!'
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld', 'byeWorld')
+ BuildResult result = gradleRunner.build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':helloWorld')
+ result.standardOutput.contains('Hello world!')
+ result.standardOutput.contains(':byeWorld')
+ result.standardOutput.contains('Bye world!')
+ !result.standardError
+ result.tasks.collect { it.path } == [':helloWorld', ':byeWorld']
+ result.taskPaths(SUCCESS) == [':helloWorld', ':byeWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ @Unroll
+ def "can provide arguments #arguments for build execution"() {
+ given:
+ final String debugMessage = 'Some debug message'
+ final String infoMessage = 'My property: ${project.hasProperty("myProp") ? project.getProperty("myProp") : null}'
+ final String quietMessage = 'Log in any case'
+
+ buildFile << """
+ task helloWorld {
+ doLast {
+ logger.debug '$debugMessage'
+ logger.info '$infoMessage'
+ logger.quiet '$quietMessage'
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner(['helloWorld'] + arguments)
+ BuildResult result = gradleRunner.build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':helloWorld')
+ result.standardOutput.contains(debugMessage) == hasDebugMessage
+ result.standardOutput.contains(infoMessage) == hasInfoMessage
+ result.standardOutput.contains(quietMessage) == hasQuietMessage
+ result.tasks.collect { it.path } == [':helloWorld']
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+
+ where:
+ arguments | hasDebugMessage | hasInfoMessage | hasQuietMessage
+ [] | false | false | true
+ ['-PmyProp=hello'] | false | false | true
+ ['-d', '-PmyProp=hello'] | true | true | true
+ ['-i', '-PmyProp=hello'] | false | true | true
+ }
+
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerBuildFailureIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerBuildFailureIntegrationTest.groovy
new file mode 100644
index 0000000..fec76da
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerBuildFailureIntegrationTest.groovy
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner
+
+import org.gradle.util.TextUtil
+
+import static TaskOutcome.*
+
+class GradleRunnerBuildFailureIntegrationTest extends AbstractGradleRunnerIntegrationTest {
+
+ def "execute build for expected failure"() {
+ given:
+ buildFile << """
+ task helloWorld {
+ doLast {
+ throw new GradleException('Expected exception')
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ BuildResult result = gradleRunner.buildAndFail()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':helloWorld FAILED')
+ result.standardError.contains("Execution failed for task ':helloWorld'")
+ result.standardError.contains('Expected exception')
+ result.tasks.collect { it.path } == [':helloWorld']
+ result.taskPaths(SUCCESS).empty
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED) == [':helloWorld']
+ }
+
+ def "execute build for expected failure but succeeds"() {
+ given:
+ buildFile << helloWorldTask()
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ gradleRunner.buildAndFail()
+
+ then:
+ Throwable t = thrown(UnexpectedBuildSuccess)
+ String expectedMessage = """Unexpected build execution success in ${TextUtil.escapeString(gradleRunner.projectDir.canonicalPath)} with arguments \\u005BhelloWorld\\u005D
+
+Output:
+:helloWorld
+Hello world!
+
+BUILD SUCCESSFUL
+
+Total time: .+ secs
+
+-----
+Error:
+
+-----"""
+ TextUtil.normaliseLineSeparators(t.message) ==~ expectedMessage
+ }
+
+ def "execute build for expected success but fails"() {
+ given:
+ buildFile << """
+ task helloWorld {
+ doLast {
+ throw new GradleException('Unexpected exception')
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ gradleRunner.build()
+
+ then:
+ Throwable t = thrown(UnexpectedBuildFailure)
+ String expectedMessage = """Unexpected build execution failure in ${TextUtil.escapeString(gradleRunner.projectDir.canonicalPath)} with arguments \\u005BhelloWorld\\u005D
+
+Output:
+:helloWorld FAILED
+
+BUILD FAILED
+
+Total time: .+ secs
+
+-----
+Error:
+
+FAILURE: Build failed with an exception.
+
+\\u002A Where:
+Build file '${TextUtil.escapeString(new File(gradleRunner.projectDir, "build.gradle").canonicalPath)}' line: 4
+
+\\u002A What went wrong:
+Execution failed for task ':helloWorld'.
+> Unexpected exception
+
+\\u002A Try:
+Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
+
+-----
+Reason:
+Unexpected exception
+-----"""
+ TextUtil.normaliseLineSeparators(t.message) ==~ expectedMessage
+ }
+
+ def "execute build without assigning a project directory"() {
+ String expectedErrorMessage = 'Please specify a project directory before executing the build'
+
+ given:
+ GradleRunner gradleRunner = runner('helloWorld')
+ gradleRunner.withProjectDir(null)
+
+ when:
+ gradleRunner.build()
+
+ then:
+ Throwable t = thrown(InvalidRunnerConfigurationException)
+ t.message == expectedErrorMessage
+
+ when:
+ gradleRunner.buildAndFail()
+
+ then:
+ t = thrown(InvalidRunnerConfigurationException)
+ t.message == expectedErrorMessage
+ }
+
+ def "build execution for non-existent task"() {
+ given:
+ buildFile << helloWorldTask()
+
+ when:
+ GradleRunner gradleRunner = runner('doesNotExist')
+ BuildResult result = gradleRunner.buildAndFail()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains('BUILD FAILED')
+ result.standardError.contains("Task 'doesNotExist' not found in root project")
+ result.tasks.empty
+ result.taskPaths(SUCCESS).empty
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerIsolatedDaemonIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerIsolatedDaemonIntegrationTest.groovy
new file mode 100644
index 0000000..7c5aa3f
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerIsolatedDaemonIntegrationTest.groovy
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner
+
+import org.gradle.integtests.fixtures.daemon.DaemonFixture
+import org.gradle.integtests.fixtures.daemon.DaemonsFixture
+import org.gradle.integtests.fixtures.executer.DaemonGradleExecuter
+import org.gradle.integtests.fixtures.executer.UnderDevelopmentGradleDistribution
+import org.gradle.test.fixtures.ConcurrentTestUtil
+import org.gradle.test.fixtures.file.LeaksFileHandles
+import org.gradle.test.fixtures.file.TestFile
+import org.gradle.testkit.runner.internal.DefaultGradleRunner
+import org.junit.Rule
+
+import static org.gradle.testkit.runner.TaskOutcome.*
+
+class GradleRunnerIsolatedDaemonIntegrationTest extends AbstractGradleRunnerIntegrationTest {
+
+ @Rule
+ final ConcurrentTestUtil concurrent = new ConcurrentTestUtil(15000)
+
+ def "configuration in default Gradle user home directory is ignored for test execution with daemon"() {
+ given:
+ def userHome = file("user-home")
+ def gradleUserHome = userHome.file(".gradle")
+
+ and:
+ writeGradlePropertiesFile(gradleUserHome, 'myProp1=propertiesFile')
+ writeInitScriptFile(gradleUserHome, "allprojects { ext.myProp2 = 'initScript' }")
+
+ and:
+ buildFile << """
+ task check {
+ doLast {
+ assert !project.ext.has('myProp1')
+ assert !project.ext.has('myProp2')
+ }
+ }
+ """
+
+ when:
+ DefaultGradleRunner gradleRunner = runner('check')
+ gradleRunner.withJvmArguments("-Duser.home=$userHome")
+ BuildResult result = gradleRunner.build()
+
+ then:
+ result.tasks.collect { it.path } == [':check']
+ result.taskPaths(SUCCESS) == [':check']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ def "configuration in custom Gradle user home directory is used for test execution with daemon"() {
+ setup:
+ writeGradlePropertiesFile(testKitWorkspace, 'myProp1=propertiesFile')
+ writeInitScriptFile(testKitWorkspace, "allprojects { ext.myProp2 = 'initScript' }")
+
+ and:
+ buildFile << """
+ task check {
+ doLast {
+ assert project.ext.has('myProp1')
+ assert project.ext.has('myProp2')
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('check')
+ BuildResult result = gradleRunner.build()
+
+ then:
+ result.tasks.collect { it.path } == [':check']
+ result.taskPaths(SUCCESS) == [':check']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ @LeaksFileHandles
+ def "daemon process dedicated to test execution uses short idle timeout"() {
+ when:
+ runner().build()
+
+ then:
+ onlyDaemon().context.idleTimeout == 120000
+ }
+
+ @LeaksFileHandles
+ def "daemon process dedicated to test execution is reused if one already exists"() {
+ when:
+ runner().build()
+
+ then:
+ def pid = onlyDaemon().with {
+ assertIdle()
+ context.pid
+ }
+
+ when:
+ runner().build()
+
+ then:
+ onlyDaemon().context.pid == pid
+ }
+
+ @LeaksFileHandles
+ def "user daemon process does not reuse existing daemon process intended for test execution even when using same gradle user home"() {
+ given:
+ def nonTestKitDaemons = daemons(testKitWorkspace)
+
+ when:
+ runner().build()
+
+ then:
+ def testKitDaemon = onlyDaemon()
+ testKitDaemon.assertIdle()
+ nonTestKitDaemons.visible.empty
+
+ when:
+ new DaemonGradleExecuter(new UnderDevelopmentGradleDistribution(), testProjectDir)
+ .usingProjectDirectory(testProjectDir.testDirectory)
+ .withGradleUserHomeDir(testKitWorkspace)
+ .withDaemonBaseDir(testKitWorkspace.file("daemon")) // simulate default, our fixtures deviate from the default
+ .run()
+
+ then:
+ def userDaemon = onlyDaemon(nonTestKitDaemons)
+ userDaemon.assertIdle()
+ userDaemon.context.pid != testKitDaemon.context.pid
+
+ cleanup:
+ userDaemon?.kill()
+ }
+
+ def "executing a build with a -g option does not affect daemon mechanics"() {
+ when:
+ runner("-g", file("custom-gradle-user-home").absolutePath).build()
+
+ then:
+ onlyDaemon().assertIdle()
+ }
+
+ def "runners executed concurrently can share the same Gradle user home directory"() {
+ when:
+ 3.times {
+ concurrent.start {
+ runner().build()
+ }
+ }
+
+ then:
+ concurrent.finished()
+ }
+
+ protected DaemonFixture onlyDaemon(DaemonsFixture daemons = this.daemons()) {
+ List<DaemonFixture> userDaemons = daemons.visible
+ assert userDaemons.size() == 1
+ userDaemons[0]
+ }
+
+ static TestFile writeGradlePropertiesFile(File gradleUserHomeDir, String content) {
+ new TestFile(gradleUserHomeDir, 'gradle.properties') << content
+ }
+
+ static TestFile writeInitScriptFile(File gradleUserHomeDir, String content) {
+ new TestFile(gradleUserHomeDir, 'init.gradle') << content
+ }
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerMechanicalFailureIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerMechanicalFailureIntegrationTest.groovy
new file mode 100644
index 0000000..7dab963
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerMechanicalFailureIntegrationTest.groovy
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner
+
+import org.gradle.tooling.GradleConnectionException
+import org.gradle.util.GFileUtils
+import org.gradle.util.TextUtil
+
+import static org.gradle.testkit.runner.TaskOutcome.*
+
+class GradleRunnerMechanicalFailureIntegrationTest extends AbstractGradleRunnerIntegrationTest {
+ def "build execution for script with invalid Groovy syntax"() {
+ given:
+ buildFile << """
+ task helloWorld {
+ doLast {
+ 'Hello world!"
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ BuildResult result = gradleRunner.buildAndFail()
+
+ then:
+ noExceptionThrown()
+ !result.standardOutput.contains(':helloWorld')
+ result.standardError.contains('Could not compile build file')
+ result.tasks.empty
+ result.taskPaths(SUCCESS).empty
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ def "build execution for script with unknown Gradle API method class"() {
+ given:
+ buildFile << """
+ task helloWorld {
+ doSomething {
+ println 'Hello world!'
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ BuildResult result = gradleRunner.buildAndFail()
+
+ then:
+ noExceptionThrown()
+ !result.standardOutput.contains(':helloWorld')
+ result.standardError.contains('Could not find method doSomething()')
+ result.tasks.empty
+ result.taskPaths(SUCCESS).empty
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ def "build execution with badly formed argument"() {
+ given:
+ buildFile << helloWorldTask()
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld', '--unknown')
+ gradleRunner.build()
+
+ then:
+ Throwable t = thrown(UnexpectedBuildFailure)
+ String message = TextUtil.normaliseLineSeparators(t.message)
+ message.contains("""Reason:
+Unknown command-line option '--unknown'.""")
+ message.contains('Problem configuring task :helloWorld from command line.')
+ }
+
+ def "build execution with non-existent working directory"() {
+ given:
+ File nonExistentWorkingDir = new File('some/path/that/does/not/exist')
+ buildFile << helloWorldTask()
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ gradleRunner.withProjectDir(nonExistentWorkingDir)
+ gradleRunner.build()
+
+ then:
+ Throwable t = thrown(UnexpectedBuildFailure)
+ String message = TextUtil.normaliseLineSeparators(t.message)
+ message.contains("""Reason:
+Project directory '$nonExistentWorkingDir.absolutePath' does not exist.""")
+ !message.contains(':helloWorld')
+ }
+
+ def "build execution with invalid JVM arguments"() {
+ given:
+ GFileUtils.writeFile('org.gradle.jvmargs=-unknown', testProjectDir.file('gradle.properties'))
+ buildFile << helloWorldTask()
+
+ when:
+ runner().build()
+
+ then:
+ thrown GradleConnectionException
+ }
+
+ def "daemon dies during build execution"() {
+ given:
+ buildFile << """
+ task helloWorld {
+ doLast {
+ println 'Hello world!'
+ Runtime.runtime.halt(0)
+ println 'Bye world!'
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ gradleRunner.build()
+
+ then:
+ thrown GradleConnectionException
+ }
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerResultIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerResultIntegrationTest.groovy
new file mode 100644
index 0000000..b2b330c
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerResultIntegrationTest.groovy
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner
+
+import java.util.concurrent.CountDownLatch
+
+import static org.gradle.testkit.runner.TaskOutcome.*
+
+/**
+ * Tests more intricate aspects of the BuildResult object
+ */
+class GradleRunnerResultIntegrationTest extends AbstractGradleRunnerIntegrationTest {
+
+ def "execute task actions marked as up-to-date or skipped"() {
+ given:
+ buildFile << """
+ task helloWorld
+
+ task byeWorld {
+ onlyIf {
+ false
+ }
+ }
+ """
+
+ when:
+ BuildResult result = runner('helloWorld', 'byeWorld').build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':helloWorld UP-TO-DATE')
+ result.standardOutput.contains(':byeWorld SKIPPED')
+ result.tasks.collect { it.path } == [':helloWorld', ':byeWorld']
+ result.taskPaths(SUCCESS) == []
+ result.taskPaths(SKIPPED) == [':byeWorld']
+ result.taskPaths(UP_TO_DATE) == [':helloWorld']
+ result.taskPaths(FAILED).empty
+ }
+
+ def "executed buildSrc tasks are never listed in result"() {
+ given:
+ testProjectDir.createDir('buildSrc')
+ buildFile << helloWorldTask()
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ BuildResult result = gradleRunner.build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':buildSrc:compileJava UP-TO-DATE')
+ result.standardOutput.contains(':buildSrc:build')
+ result.standardOutput.contains('Hello world!')
+ !result.standardError
+ result.tasks.collect { it.path } == [':helloWorld']
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ result.task(":helloWorld") == result.tasks.find { it.path == ":helloWorld" }
+ result.task(":nonsense") == null
+ }
+
+ def "task order represents execution order"() {
+ when:
+ file("settings.gradle") << "include 'a', 'b', 'c', 'd'"
+ buildFile << """
+ def latch = new $CountDownLatch.name(1)
+
+ project(":a") {
+ task t << {
+ latch.await()
+ }
+ }
+
+ project(":b") {
+ task t
+ }
+
+ project(":c") { // c is guaranteed to start after a, but finish before it does
+ task t {
+ dependsOn ":b:t"
+ }
+ }
+
+ project(":d") {
+ task t {
+ dependsOn ":c:t"
+ doLast {
+ latch.countDown()
+ }
+ }
+ }
+ """
+
+ then:
+ def result = runner("t", "--parallel", "--max-workers=2").build()
+ result.tasks.findIndexOf { it.path == ":c:t" } > result.tasks.findIndexOf { it.path == ":a:t" }
+ }
+}
diff --git a/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerSmokeIntegrationTest.groovy b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerSmokeIntegrationTest.groovy
new file mode 100644
index 0000000..ed4a1df
--- /dev/null
+++ b/subprojects/test-kit/src/integTest/groovy/org/gradle/testkit/runner/GradleRunnerSmokeIntegrationTest.groovy
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner
+
+import org.gradle.util.GFileUtils
+
+import static TaskOutcome.*
+
+class GradleRunnerSmokeIntegrationTest extends AbstractGradleRunnerIntegrationTest {
+
+ def "execute build for expected success"() {
+ given:
+ buildFile << helloWorldTask()
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ BuildResult result = gradleRunner.build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':helloWorld')
+ result.standardOutput.contains('Hello world!')
+ !result.standardError
+ result.tasks.collect { it.path } == [':helloWorld']
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ def "execute plugin and custom task logic as part of the build script"() {
+ given:
+ buildFile << """
+ apply plugin: HelloWorldPlugin
+
+ class HelloWorldPlugin implements Plugin<Project> {
+ void apply(Project project) {
+ project.task('helloWorld', type: HelloWorld)
+ }
+ }
+
+ class HelloWorld extends DefaultTask {
+ @TaskAction
+ void doSomething() {
+ println 'Hello world!'
+ }
+ }
+ """
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ BuildResult result = gradleRunner.build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':helloWorld')
+ result.standardOutput.contains('Hello world!')
+ !result.standardError
+ result.tasks.collect { it.path } == [':helloWorld']
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+ def "execute build with buildSrc project"() {
+ given:
+ File buildSrcJavaSrcDir = testProjectDir.createDir('buildSrc', 'src', 'main', 'java', 'org', 'gradle', 'test')
+ GFileUtils.writeFile("""package org.gradle.test;
+
+public class MyApp {
+ public static void main(String args[]) {
+ System.out.println("Hello world!");
+ }
+}
+""", new File(buildSrcJavaSrcDir, 'MyApp.java'))
+
+
+ buildFile << helloWorldTask()
+
+ when:
+ GradleRunner gradleRunner = runner('helloWorld')
+ BuildResult result = gradleRunner.build()
+
+ then:
+ noExceptionThrown()
+ result.standardOutput.contains(':buildSrc:compileJava')
+ result.standardOutput.contains(':buildSrc:build')
+ result.standardOutput.contains(':helloWorld')
+ result.standardOutput.contains('Hello world!')
+ !result.standardError
+ result.tasks.collect { it.path } == [':helloWorld']
+ result.taskPaths(SUCCESS) == [':helloWorld']
+ result.taskPaths(SKIPPED).empty
+ result.taskPaths(UP_TO_DATE).empty
+ result.taskPaths(FAILED).empty
+ }
+
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/BuildResult.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/BuildResult.java
new file mode 100644
index 0000000..d34b1b4
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/BuildResult.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner;
+
+import org.gradle.api.Incubating;
+import org.gradle.api.Nullable;
+
+import java.util.List;
+
+/**
+ * The result of executing a build, via the {@link GradleRunner}.
+ *
+ * @since 2.6
+ * @see GradleRunner#build()
+ * @see GradleRunner#buildAndFail()
+ */
+ at Incubating
+public interface BuildResult {
+
+ /**
+ * The textual output produced during the build.
+ * <p>
+ * This is equivalent to the console output produced when running a build from the command line,
+ * except for any error output (which is available via {@link #getStandardError()}).
+ *
+ * @return the build output text, or empty string if there was no build output (e.g. ran with {@code -q})
+ */
+ String getStandardOutput();
+
+ /**
+ * The textual error output produced during the build (i.e. text written to {@link System#err}).
+ * <p>
+ * During a build, Gradle itself does not write its output to the error output stream.
+ * However, tools used by the build, as well as processes forked by the build
+ * (who's output is forwarded) may write to the error output stream.
+ * <p>
+ * If the build fails to start, due to an invalid argument for example, the message will be written to the error output
+ * and hence available here.
+ *
+ * @return the build error output text, or empty string if there was no error output
+ */
+ String getStandardError();
+
+ /**
+ * The tasks that were part of the build.
+ * <p>
+ * The order of the tasks corresponds to the order in which the tasks were started.
+ * If executing a parallel enabled build, the order is not guaranteed to be deterministic.
+ * <p>
+ * The returned list is an unmodifiable view of items.
+ * The returned list will be empty if no tasks were executed.
+ * This can occur if the build fails early, due to a build script failing to compile for example.
+ *
+ * @return the build tasks
+ */
+ List<BuildTask> getTasks();
+
+ /**
+ * The subset of {@link #getTasks()} that had the given outcome.
+ * <p>
+ * The returned list is an unmodifiable view of items.
+ * The returned list will be empty if no tasks were executed with the given outcome.
+ *
+ * @param outcome the desired outcome
+ * @return the build tasks with the given outcome
+ */
+ List<BuildTask> tasks(TaskOutcome outcome);
+
+ /**
+ * The paths of the subset of {@link #getTasks()} that had the given outcome.
+ * <p>
+ * The returned list is an unmodifiable view of items.
+ * The returned list will be empty if no tasks were executed with the given outcome.
+ *
+ * @param outcome the desired outcome
+ * @return the paths of the build tasks with the given outcome
+ */
+ List<String> taskPaths(TaskOutcome outcome);
+
+ /**
+ * Returns the result object for a particular task, or {@code null} if the given task was not part of the build.
+ *
+ * @param taskPath the path of the target task
+ * @return information about the executed task, or {@code null} if the task was not executed
+ */
+ @Nullable
+ BuildTask task(String taskPath);
+
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/BuildTask.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/BuildTask.java
new file mode 100644
index 0000000..9d58376
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/BuildTask.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner;
+
+/**
+ * A task that was executed when running a specific build.
+ *
+ * @since 2.6
+ * @see BuildResult
+ */
+public interface BuildTask {
+
+ /**
+ * The unique path of the task.
+ * <p>
+ * The task path is a combination of its enclosing project's path and its name.
+ * For example, in multi project build the {@code bar} task of the {@code foo} project has a path of {@code :foo:bar}.
+ * In a single project build, the {@code bar} task of the lone project has a path of {@code :bar}.
+ * <p>
+ * This value corresponds to the value output by Gradle for the task during its normal progress logging.
+ *
+ * @return the task path
+ */
+ String getPath();
+
+ /**
+ * The outcome of attempting to execute this task.
+ *
+ * @return the task outcome
+ */
+ TaskOutcome getOutcome();
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/GradleRunner.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/GradleRunner.java
new file mode 100644
index 0000000..7ca0f01
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/GradleRunner.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner;
+
+import org.gradle.api.Incubating;
+import org.gradle.api.internal.GradleDistributionLocator;
+import org.gradle.api.internal.classpath.DefaultGradleDistributionLocator;
+import org.gradle.internal.classloader.ClasspathUtil;
+import org.gradle.testkit.runner.internal.DefaultGradleRunner;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Executes a Gradle build, allowing inspection of the outcome.
+ * <p>
+ * A Gradle runner can be used to functionally test build logic, by executing a contrived build.
+ * Assertions can then be made on the outcome of the build, such as the state of files created by the build,
+ * or what tasks were actually executed during the build.
+ * <p>
+ * A runner can be created via the {@link #create()} method.
+ * <p>
+ * Typically, the test code using the runner will programmatically create a build (e.g. by writing Gradle build files to a temporary space) to execute.
+ * The build to execute is effectively specified by the {@link #withProjectDir(File)}} method.
+ * It is a requirement that a project directory be set.
+ * <p>
+ * The {@link #withArguments(String...)} method allows the build arguments to be specified,
+ * just as they would be on the command line.
+ * <p>
+ * The {@link #build()} method can be used to invoke the build when it is expected to succeed,
+ * while the {@link #buildAndFail()} method can be used when the build is expected to fail.
+ * <p>
+ * GradleRunner instances are not thread safe and cannot be used concurrently.
+ * However, multiple instances are able to be used concurrently.
+ * <p>
+ * Please see <a href="https://docs.gradle.org/current/userguide/test_kit.html">the Gradle TestKit User Guide chapter</a> for more information.
+ *
+ * @since 2.6
+ */
+ at Incubating
+public abstract class GradleRunner {
+
+ /**
+ * Creates a new Gradle runner.
+ * <p>
+ * The runner requires a Gradle distribution (and therefore a specific version of Gradle) in order to execute builds.
+ * This method will find a Gradle distribution, based on the filesystem location of this class.
+ * That is, it is expected that this class is loaded from a Gradle distribution.
+ * <p>
+ * When using the runner as part of tests <i>being executed by Gradle</i> (i.e. a build using the {@code gradleTestKit()} dependency),
+ * this means that the same distribution of Gradle that is executing the tests will be used by runner returned by this method.
+ * <p>
+ * When using the runner as part of tests <i>being executed by an IDE</i>,
+ * this means that the same distribution of Gradle that was used when importing the project will be used.
+ *
+ * @return a new Gradle runner
+ */
+ public static GradleRunner create() {
+ GradleDistributionLocator gradleDistributionLocator = new DefaultGradleDistributionLocator(GradleRunner.class);
+ final File gradleHome = gradleDistributionLocator.getGradleHome();
+ if (gradleHome == null) {
+ try {
+ File classpathForClass = ClasspathUtil.getClasspathForClass(GradleRunner.class);
+ throw new IllegalStateException("Could not create a GradleRunner, as the GradleRunner class was loaded from " + classpathForClass + " which is not a Gradle distribution");
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not create a GradleRunner, as the GradleRunner class was not loaded from a Gradle distribution");
+ }
+ }
+ return new DefaultGradleRunner(gradleHome);
+ }
+
+ /**
+ * Sets the directory to use for Test Kit's working storage needs.
+ * <p>
+ * This directory is used internally to store various files required by the runner.
+ * If no explicit Gradle user home is specified via the build arguments (i.e. the {@code -g «dir»} option}),
+ * this directory will also be used for the Gradle user home for the test build.
+ * <p>
+ * If no value has been specified when the build is initiated, a directory unique to the current operating system
+ * user will be created and used within the JVM's temporary directory as advertised by the {@code java.io.tmpdir} system property.
+ * This directory is not deleted by the runner after the test build.
+ * <p>
+ * You may wish to specify a location that is within your project and regularly cleaned, such as the project's build directory.
+ * <p>
+ * The actual contents of this directory are an internal implementation detail and may change at any time.
+ *
+ * @param testKitDir the test kit directory
+ * @return {@code this}
+ */
+ public abstract GradleRunner withTestKitDir(File testKitDir);
+
+ /**
+ * The directory that the build will be executed in.
+ * <p>
+ * This is analogous to the current directory when executing Gradle from the command line.
+ *
+ * @return the directory to execute the build in
+ */
+ public abstract File getProjectDir();
+
+ /**
+ * Sets the directory that the Gradle will be executed in.
+ * <p>
+ * This is typically set to the root project of the build under test.
+ * <p>
+ * A project directory must be set.
+ * This method must be called before {@link #build()} or {@link #buildAndFail()}.
+ * <p>
+ * All builds executed with the runner effectively implicitly add the {@code --no-search-upwards} argument.
+ * This suppresses Gradle's default behaviour of searching upwards through the file system in order to find the root of the current project tree.
+ * This default behaviour is often utilised when focusing on a particular build within a multi-project build.
+ * This behaviour is suppressed due to test builds being executed potentially being created within a “real build”
+ * (e.g. under the {@code /build} directory of the plugin's project directory).
+ *
+ * @param projectDir the project directory
+ * @return {@code this}
+ * @see #getProjectDir()
+ */
+ public abstract GradleRunner withProjectDir(File projectDir);
+
+ /**
+ * The build arguments.
+ * <p>
+ * Effectively, the command line arguments to Gradle.
+ * This includes all tasks, flags, properties etc.
+ *
+ * The returned list is an unmodifiable view of items.
+ *
+ * @return the build arguments
+ */
+ public abstract List<String> getArguments();
+
+ /**
+ * Sets the build arguments.
+ *
+ * @param arguments the build arguments
+ * @return this
+ * @see #getArguments()
+ */
+ public abstract GradleRunner withArguments(List<String> arguments);
+
+ /**
+ * Sets the build arguments.
+ *
+ * @param arguments the build arguments
+ * @return this
+ * @see #getArguments()
+ */
+ public abstract GradleRunner withArguments(String... arguments);
+
+ /**
+ * Executes a build, expecting it to complete without failure.
+ *
+ * @throws InvalidRunnerConfigurationException if the configuration of this runner is invalid (e.g. project directory not set)
+ * @throws UnexpectedBuildFailure if the build does not succeed
+ * @return the build result
+ */
+ public abstract BuildResult build() throws InvalidRunnerConfigurationException, UnexpectedBuildFailure;
+
+ /**
+ * Executes a build, expecting it to complete with failure.
+ *
+ * @throws InvalidRunnerConfigurationException if the configuration of this runner is invalid (e.g. project directory not set)
+ * @throws UnexpectedBuildSuccess if the build succeeds
+ * @return the build result
+ */
+ public abstract BuildResult buildAndFail() throws InvalidRunnerConfigurationException, UnexpectedBuildSuccess;
+
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/InvalidRunnerConfigurationException.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/InvalidRunnerConfigurationException.java
new file mode 100644
index 0000000..2aa7365
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/InvalidRunnerConfigurationException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner;
+
+import org.gradle.api.Incubating;
+
+/**
+ * Thrown when a build cannot be executed due to the runner being in an invalid state.
+ *
+ * @since 2.6
+ * @see GradleRunner#build()
+ * @see GradleRunner#buildAndFail()
+ */
+ at Incubating
+public class InvalidRunnerConfigurationException extends IllegalStateException {
+ public InvalidRunnerConfigurationException(String s) {
+ super(s);
+ }
+
+ public InvalidRunnerConfigurationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/TaskOutcome.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/TaskOutcome.java
new file mode 100644
index 0000000..83a8d0c
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/TaskOutcome.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner;
+
+/**
+ * The outcome of executing a task during a build.
+ *
+ * @since 2.6
+ * @see BuildTask#getOutcome()
+ */
+public enum TaskOutcome {
+
+ /**
+ * That task executed and performed its actions without failure.
+ */
+ SUCCESS,
+
+ /**
+ * The task attempted to execute, but did not complete successfully.
+ */
+ FAILED,
+
+ /**
+ * The task was not executed, as its output was up to date.
+ */
+ UP_TO_DATE,
+
+ /**
+ * The task was not executed due to some reason.
+ *
+ * A task may be skipped if it had no work to do (e.g. no source to compile).
+ */
+ SKIPPED
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/UnexpectedBuildFailure.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/UnexpectedBuildFailure.java
new file mode 100644
index 0000000..b048466
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/UnexpectedBuildFailure.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner;
+
+import org.gradle.api.Incubating;
+
+/**
+ * Thrown when executing a build that was expected to succeed, but failed.
+ *
+ * @since 2.6
+ * @see GradleRunner#build()
+ */
+ at Incubating
+public class UnexpectedBuildFailure extends RuntimeException {
+ public UnexpectedBuildFailure(String message) {
+ super(message);
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/UnexpectedBuildSuccess.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/UnexpectedBuildSuccess.java
new file mode 100644
index 0000000..48f5469
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/UnexpectedBuildSuccess.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner;
+
+import org.gradle.api.Incubating;
+
+/**
+ * Thrown when executing a build that was expected to fail, but succeeded.
+ *
+ * @since 2.6
+ * @see GradleRunner#buildAndFail()
+ */
+ at Incubating
+public class UnexpectedBuildSuccess extends RuntimeException {
+ public UnexpectedBuildSuccess(String message) {
+ super(message);
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/ConstantTestKitDirProvider.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/ConstantTestKitDirProvider.java
new file mode 100644
index 0000000..526af89
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/ConstantTestKitDirProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import java.io.File;
+
+class ConstantTestKitDirProvider implements TestKitDirProvider {
+ private final File testKitDir;
+
+ public ConstantTestKitDirProvider(File testKitDir) {
+ this.testKitDir = testKitDir;
+ }
+
+ @Override
+ public File getDir() {
+ return testKitDir;
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultBuildResult.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultBuildResult.java
new file mode 100644
index 0000000..8fd25f4
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultBuildResult.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import org.gradle.api.Nullable;
+import org.gradle.api.Transformer;
+import org.gradle.api.specs.Spec;
+import org.gradle.testkit.runner.BuildResult;
+import org.gradle.testkit.runner.BuildTask;
+import org.gradle.testkit.runner.TaskOutcome;
+import org.gradle.util.CollectionUtils;
+
+import java.util.Collections;
+import java.util.List;
+
+public class DefaultBuildResult implements BuildResult {
+ private final String standardOutput;
+ private final String standardError;
+ private final List<BuildTask> tasks;
+
+ public DefaultBuildResult(String standardOutput, String standardError, List<BuildTask> tasks) {
+ this.standardOutput = standardOutput;
+ this.standardError = standardError;
+ this.tasks = tasks;
+ }
+
+ public String getStandardOutput() {
+ return standardOutput;
+ }
+
+ public String getStandardError() {
+ return standardError;
+ }
+
+ public List<BuildTask> getTasks() {
+ return Collections.unmodifiableList(tasks);
+ }
+
+ public List<BuildTask> tasks(final TaskOutcome outcome) {
+ return Collections.unmodifiableList(CollectionUtils.filter(tasks, new Spec<BuildTask>() {
+ public boolean isSatisfiedBy(BuildTask element) {
+ return element.getOutcome() == outcome;
+ }
+ }));
+ }
+
+ public List<String> taskPaths(TaskOutcome outcome) {
+ return Collections.unmodifiableList(CollectionUtils.collect(tasks(outcome), new Transformer<String, BuildTask>() {
+ public String transform(BuildTask buildTask) {
+ return buildTask.getPath();
+ }
+ }));
+ }
+
+ @Nullable
+ @Override
+ public BuildTask task(String taskPath) {
+ for (BuildTask task : tasks) {
+ if (task.getPath().equals(taskPath)) {
+ return task;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultBuildTask.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultBuildTask.java
new file mode 100644
index 0000000..3647cb1
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultBuildTask.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import org.gradle.testkit.runner.BuildTask;
+import org.gradle.testkit.runner.TaskOutcome;
+
+public class DefaultBuildTask implements BuildTask {
+ private final String path;
+ private final TaskOutcome outcome;
+
+ public DefaultBuildTask(String path, TaskOutcome outcome) {
+ this.path = path;
+ this.outcome = outcome;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public TaskOutcome getOutcome() {
+ return outcome;
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultGradleRunner.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultGradleRunner.java
new file mode 100644
index 0000000..0e4981e
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/DefaultGradleRunner.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.gradle.api.Action;
+import org.gradle.internal.SystemProperties;
+import org.gradle.testkit.runner.*;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class DefaultGradleRunner extends GradleRunner {
+
+ public static final String DIAGNOSTICS_MESSAGE_SEPARATOR = "-----";
+ private final File gradleHome;
+ private final GradleExecutor gradleExecutor;
+
+ private TestKitDirProvider testKitDirProvider;
+
+ private File projectDirectory;
+ private List<String> arguments = new ArrayList<String>();
+ private List<String> jvmArguments = new ArrayList<String>();
+
+ public DefaultGradleRunner(File gradleHome) {
+ this(gradleHome, new TestKitGradleExecutor(), new TempTestKitDirProvider());
+ }
+
+ DefaultGradleRunner(File gradleHome, GradleExecutor gradleExecutor, TestKitDirProvider testKitDirProvider) {
+ this.gradleHome = gradleHome;
+ this.gradleExecutor = gradleExecutor;
+ this.testKitDirProvider = testKitDirProvider;
+ }
+
+ public TestKitDirProvider getTestKitDirProvider() {
+ return testKitDirProvider;
+ }
+
+ @Override
+ public DefaultGradleRunner withTestKitDir(final File testKitDir) {
+ if (testKitDir == null) {
+ throw new IllegalArgumentException("testKitDir argument cannot be null");
+ }
+ this.testKitDirProvider = new ConstantTestKitDirProvider(testKitDir);
+ return this;
+ }
+
+ public DefaultGradleRunner withJvmArguments(List<String> jvmArguments) {
+ this.jvmArguments = new ArrayList<String>(jvmArguments);
+ return this;
+ }
+
+ public DefaultGradleRunner withJvmArguments(String... jvmArguments) {
+ return withJvmArguments(Arrays.asList(jvmArguments));
+ }
+
+ @Override
+ public File getProjectDir() {
+ return projectDirectory;
+ }
+
+ @Override
+ public DefaultGradleRunner withProjectDir(File projectDir) {
+ this.projectDirectory = projectDir;
+ return this;
+ }
+
+ @Override
+ public List<String> getArguments() {
+ return Collections.unmodifiableList(arguments);
+ }
+
+ @Override
+ public DefaultGradleRunner withArguments(List<String> arguments) {
+ this.arguments = new ArrayList<String>(arguments);
+ return this;
+ }
+
+ @Override
+ public DefaultGradleRunner withArguments(String... arguments) {
+ return withArguments(Arrays.asList(arguments));
+ }
+
+ @Override
+ public BuildResult build() {
+ return run(new Action<GradleExecutionResult>() {
+ public void execute(GradleExecutionResult gradleExecutionResult) {
+ if (!gradleExecutionResult.isSuccessful()) {
+ throw new UnexpectedBuildFailure(createDiagnosticsMessage("Unexpected build execution failure", gradleExecutionResult));
+ }
+ }
+ });
+ }
+
+ @Override
+ public BuildResult buildAndFail() {
+ return run(new Action<GradleExecutionResult>() {
+ public void execute(GradleExecutionResult gradleExecutionResult) {
+ if (gradleExecutionResult.isSuccessful()) {
+ throw new UnexpectedBuildSuccess(createDiagnosticsMessage("Unexpected build execution success", gradleExecutionResult));
+ }
+ }
+ });
+ }
+
+ private String createDiagnosticsMessage(String trailingMessage, GradleExecutionResult gradleExecutionResult) {
+ String lineBreak = SystemProperties.getInstance().getLineSeparator();
+ StringBuilder message = new StringBuilder();
+ message.append(trailingMessage);
+ message.append(" in ");
+ message.append(getProjectDir().getAbsolutePath());
+ message.append(" with arguments ");
+ message.append(getArguments());
+ message.append(lineBreak).append(lineBreak);
+ message.append("Output:");
+ message.append(lineBreak);
+ message.append(gradleExecutionResult.getStandardOutput());
+ message.append(lineBreak);
+ message.append(DIAGNOSTICS_MESSAGE_SEPARATOR);
+ message.append(lineBreak);
+ message.append("Error:");
+ message.append(lineBreak);
+ message.append(gradleExecutionResult.getStandardError());
+ message.append(lineBreak);
+ message.append(DIAGNOSTICS_MESSAGE_SEPARATOR);
+
+ if (gradleExecutionResult.getThrowable() != null) {
+ message.append(lineBreak);
+ message.append("Reason:");
+ message.append(lineBreak);
+ message.append(determineExceptionMessage(gradleExecutionResult.getThrowable()));
+ message.append(lineBreak);
+ message.append(DIAGNOSTICS_MESSAGE_SEPARATOR);
+ }
+
+ return message.toString();
+ }
+
+ private String determineExceptionMessage(Throwable throwable) {
+ return throwable.getCause() == null ? throwable.getMessage() : ExceptionUtils.getRootCause(throwable).getMessage();
+ }
+
+ private BuildResult run(Action<GradleExecutionResult> resultVerification) {
+ if (projectDirectory == null) {
+ throw new InvalidRunnerConfigurationException("Please specify a project directory before executing the build");
+ }
+
+ File testKitDir = createTestKitDir(testKitDirProvider);
+
+ GradleExecutionResult execResult = gradleExecutor.run(
+ gradleHome,
+ testKitDir,
+ projectDirectory,
+ arguments,
+ jvmArguments
+ );
+
+ resultVerification.execute(execResult);
+
+ return new DefaultBuildResult(
+ execResult.getStandardOutput(),
+ execResult.getStandardError(),
+ execResult.getTasks()
+ );
+ }
+
+ private File createTestKitDir(TestKitDirProvider testKitDirProvider) {
+ File dir = testKitDirProvider.getDir();
+ if (dir.isDirectory()) {
+ if (!dir.canWrite()) {
+ throw new InvalidRunnerConfigurationException("Unable to write to test kit directory: " + dir.getAbsolutePath());
+ }
+ return dir;
+ } else if (dir.exists()) {
+ throw new InvalidRunnerConfigurationException("Unable to use non-directory as test kit directory: " + dir.getAbsolutePath());
+ } else if (dir.mkdirs() || dir.isDirectory()) {
+ return dir;
+ } else {
+ throw new InvalidRunnerConfigurationException("Unable to create test kit directory: " + dir.getAbsolutePath());
+ }
+ }
+
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/GradleExecutionResult.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/GradleExecutionResult.java
new file mode 100644
index 0000000..069d11b
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/GradleExecutionResult.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import org.gradle.testkit.runner.BuildTask;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+public class GradleExecutionResult {
+ private final ByteArrayOutputStream standardOutput;
+ private final ByteArrayOutputStream standardError;
+ private final List<BuildTask> tasks;
+ private final Throwable throwable;
+
+ public GradleExecutionResult(ByteArrayOutputStream standardOutput, ByteArrayOutputStream standardError, List<BuildTask> tasks) {
+ this(standardOutput, standardError, tasks, null);
+ }
+
+ public GradleExecutionResult(ByteArrayOutputStream standardOutput, ByteArrayOutputStream standardError, List<BuildTask> tasks, Throwable throwable) {
+ this.standardOutput = standardOutput;
+ this.standardError = standardError;
+ this.tasks = tasks;
+ this.throwable = throwable;
+ }
+
+ public String getStandardOutput() {
+ return standardOutput.toString();
+ }
+
+ public String getStandardError() {
+ return standardError.toString();
+ }
+
+ public List<BuildTask> getTasks() {
+ return tasks;
+ }
+
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ public boolean isSuccessful() {
+ return throwable == null;
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/GradleExecutor.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/GradleExecutor.java
new file mode 100644
index 0000000..3e5e039
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/GradleExecutor.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import java.io.File;
+import java.util.List;
+
+public interface GradleExecutor {
+ GradleExecutionResult run(File gradleHome, File gradleUserHome, File projectDir, List<String> buildArgs, List<String> jvmArgs);
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TempTestKitDirProvider.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TempTestKitDirProvider.java
new file mode 100644
index 0000000..dbf40d4
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TempTestKitDirProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import org.gradle.internal.SystemProperties;
+
+import java.io.File;
+
+public class TempTestKitDirProvider extends ConstantTestKitDirProvider {
+
+ public TempTestKitDirProvider() {
+ this(new File(SystemProperties.getInstance().getJavaIoTmpDir()));
+ }
+
+ TempTestKitDirProvider(File rootDir) {
+ super(new File(rootDir, String.format(".gradle-test-kit-%s", SystemProperties.getInstance().getUserName())));
+ }
+
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TestKitDirProvider.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TestKitDirProvider.java
new file mode 100644
index 0000000..96013d2
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TestKitDirProvider.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import java.io.File;
+
+public interface TestKitDirProvider {
+ File getDir();
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TestKitGradleExecutor.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TestKitGradleExecutor.java
new file mode 100644
index 0000000..41f0375
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/internal/TestKitGradleExecutor.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal;
+
+import org.gradle.testkit.runner.BuildTask;
+import org.gradle.testkit.runner.TaskOutcome;
+import org.gradle.tooling.BuildException;
+import org.gradle.tooling.BuildLauncher;
+import org.gradle.tooling.GradleConnector;
+import org.gradle.tooling.ProjectConnection;
+import org.gradle.tooling.events.ProgressEvent;
+import org.gradle.tooling.events.ProgressListener;
+import org.gradle.tooling.events.task.*;
+import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static org.gradle.testkit.runner.TaskOutcome.*;
+
+public class TestKitGradleExecutor implements GradleExecutor {
+
+ public static final String TEST_KIT_DAEMON_DIR_NAME = "test-kit-daemon";
+
+ public TestKitGradleExecutor() {
+ registerShutdownHook();
+ }
+
+ private void registerShutdownHook() {
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ public void run() {
+ DefaultGradleConnector.close();
+ }
+ }));
+ }
+
+ public GradleExecutionResult run(File gradleHome, File gradleUserHome, File projectDir, List<String> buildArgs, List<String> jvmArgs) {
+ final ByteArrayOutputStream standardOutput = new ByteArrayOutputStream();
+ final ByteArrayOutputStream standardError = new ByteArrayOutputStream();
+ final List<BuildTask> tasks = new ArrayList<BuildTask>();
+
+ GradleConnector gradleConnector = buildConnector(gradleHome, gradleUserHome, projectDir);
+ ProjectConnection connection = null;
+
+ try {
+ connection = gradleConnector.connect();
+ BuildLauncher launcher = connection.newBuild();
+ launcher.setStandardOutput(standardOutput);
+ launcher.setStandardError(standardError);
+ launcher.addProgressListener(new TaskExecutionProgressListener(tasks));
+
+ launcher.withArguments(buildArgs.toArray(new String[buildArgs.size()]));
+ launcher.setJvmArguments(jvmArgs.toArray(new String[jvmArgs.size()]));
+
+ launcher.run();
+ } catch (BuildException t) {
+ return new GradleExecutionResult(standardOutput, standardError, tasks, t);
+ } finally {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+
+ return new GradleExecutionResult(standardOutput, standardError, tasks);
+ }
+
+ private GradleConnector buildConnector(File gradleHome, File gradleUserHome, File projectDir) {
+ DefaultGradleConnector gradleConnector = (DefaultGradleConnector) GradleConnector.newConnector();
+ gradleConnector.useGradleUserHomeDir(gradleUserHome);
+ gradleConnector.daemonBaseDir(new File(gradleUserHome, TEST_KIT_DAEMON_DIR_NAME));
+ gradleConnector.forProjectDirectory(projectDir);
+ gradleConnector.searchUpwards(false);
+ gradleConnector.daemonMaxIdleTime(120, TimeUnit.SECONDS);
+ gradleConnector.useInstallation(gradleHome);
+ return gradleConnector;
+ }
+
+ private class TaskExecutionProgressListener implements ProgressListener {
+ private final List<BuildTask> tasks;
+ private final Map<String, Integer> order = new HashMap<String, Integer>();
+
+ public TaskExecutionProgressListener(List<BuildTask> tasks) {
+ this.tasks = tasks;
+ }
+
+ public void statusChanged(ProgressEvent event) {
+ if (event instanceof TaskStartEvent) {
+ TaskStartEvent taskStartEvent = (TaskStartEvent) event;
+ order.put(taskStartEvent.getDescriptor().getTaskPath(), tasks.size());
+ tasks.add(null);
+ }
+ if (event instanceof TaskFinishEvent) {
+ TaskFinishEvent taskFinishEvent = (TaskFinishEvent) event;
+ String taskPath = taskFinishEvent.getDescriptor().getTaskPath();
+ TaskOperationResult result = taskFinishEvent.getResult();
+ final Integer index = order.get(taskPath);
+ if (index == null) {
+ throw new IllegalStateException("Received task finish event for task " + taskPath + " without first receiving task start event");
+ }
+ tasks.set(index, determineBuildTask(result, taskPath));
+ }
+ }
+
+ private BuildTask determineBuildTask(TaskOperationResult result, String taskPath) {
+ if (isFailed(result)) {
+ return createBuildTask(taskPath, FAILED);
+ } else if (isSkipped(result)) {
+ return createBuildTask(taskPath, SKIPPED);
+ } else if (isUpToDate(result)) {
+ return createBuildTask(taskPath, UP_TO_DATE);
+ }
+
+ return createBuildTask(taskPath, SUCCESS);
+ }
+
+ private BuildTask createBuildTask(String taskPath, TaskOutcome outcome) {
+ return new DefaultBuildTask(taskPath, outcome);
+ }
+
+ private boolean isFailed(TaskOperationResult result) {
+ return result instanceof TaskFailureResult;
+ }
+
+ private boolean isSkipped(TaskOperationResult result) {
+ return result instanceof TaskSkippedResult;
+ }
+
+ private boolean isUpToDate(TaskOperationResult result) {
+ return result instanceof TaskSuccessResult && ((TaskSuccessResult) result).isUpToDate();
+ }
+ }
+}
diff --git a/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/package-info.java b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/package-info.java
new file mode 100644
index 0000000..d7b0a34
--- /dev/null
+++ b/subprojects/test-kit/src/main/java/org/gradle/testkit/runner/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Support for executing contrived Gradle builds for the purpose of testing build logic.
+ *
+ * @see org.gradle.testkit.runner.GradleRunner
+ */
+package org.gradle.testkit.runner;
diff --git a/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/DefaultBuildResultTest.groovy b/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/DefaultBuildResultTest.groovy
new file mode 100644
index 0000000..6aa27bb
--- /dev/null
+++ b/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/DefaultBuildResultTest.groovy
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal
+
+import org.gradle.testkit.runner.BuildTask
+import spock.lang.Specification
+
+import static org.gradle.testkit.runner.TaskOutcome.*
+
+class DefaultBuildResultTest extends Specification {
+ BuildTask successBuildResult = new DefaultBuildTask(':a', SUCCESS)
+ BuildTask failedBuildResult = new DefaultBuildTask(':b', FAILED)
+ BuildTask skippedBuildResult = new DefaultBuildTask(':c', SKIPPED)
+ def buildTasks = [successBuildResult, failedBuildResult]
+ DefaultBuildResult defaultBuildResult = new DefaultBuildResult('output', 'error', buildTasks)
+
+ def "provides expected field values"() {
+ expect:
+ defaultBuildResult.standardOutput == 'output'
+ defaultBuildResult.standardError == 'error'
+ defaultBuildResult.tasks == buildTasks
+ defaultBuildResult.tasks(SUCCESS) == [successBuildResult]
+ defaultBuildResult.tasks(FAILED) == [failedBuildResult]
+ defaultBuildResult.taskPaths(SUCCESS) == [successBuildResult.path]
+ defaultBuildResult.taskPaths(FAILED) == [failedBuildResult.path]
+ }
+
+ def "returned tasks are unmodifiable"() {
+ when:
+ defaultBuildResult.tasks << skippedBuildResult
+
+ then:
+ thrown(UnsupportedOperationException)
+
+ when:
+ defaultBuildResult.tasks(SUCCESS) << skippedBuildResult
+
+ then:
+ thrown(UnsupportedOperationException)
+
+ when:
+ defaultBuildResult.taskPaths(SUCCESS) << skippedBuildResult
+
+ then:
+ thrown(UnsupportedOperationException)
+ }
+}
diff --git a/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/DefaultGradleRunnerTest.groovy b/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/DefaultGradleRunnerTest.groovy
new file mode 100644
index 0000000..3095984
--- /dev/null
+++ b/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/DefaultGradleRunnerTest.groovy
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal
+
+import org.gradle.api.GradleException
+import org.gradle.testkit.runner.BuildResult
+import org.gradle.testkit.runner.InvalidRunnerConfigurationException
+import org.gradle.util.TextUtil
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class DefaultGradleRunnerTest extends Specification {
+ File gradleHome = Mock(File)
+ GradleExecutor gradleExecutor = Mock(GradleExecutor)
+ TestKitDirProvider testKitDirProvider = Mock(TestKitDirProvider)
+ File workingDir = new File('my/tests')
+ List<String> arguments = ['compile', 'test', '--parallel', '-Pfoo=bar']
+
+ def "provides expected field values"() {
+ when:
+ DefaultGradleRunner defaultGradleRunner = createRunner()
+ defaultGradleRunner.withProjectDir(workingDir).withArguments(arguments)
+
+ then:
+ defaultGradleRunner.projectDir == workingDir
+ defaultGradleRunner.arguments == arguments
+ 0 * testKitDirProvider.getDir()
+ }
+
+ def "can set custom test kit directory"() {
+ given:
+ File testKitDir = new File('some/dir')
+
+ when:
+ DefaultGradleRunner runner = createRunner()
+ .withProjectDir(workingDir)
+ .withTestKitDir(testKitDir)
+
+ then:
+ runner.projectDir == workingDir
+ 0 * testKitDirProvider.getDir()
+ runner.testKitDirProvider.dir.is testKitDir
+ }
+
+ def "throws exception if test kit dir is not writable"() {
+ when:
+ createRunner().withProjectDir(workingDir).build()
+
+ then:
+ 1 * testKitDirProvider.getDir() >> {
+ Mock(File) {
+ isDirectory() >> true
+ canWrite() >> false
+ getAbsolutePath() >> "path"
+ }
+ }
+ Throwable t = thrown(InvalidRunnerConfigurationException)
+ t.message == 'Unable to write to test kit directory: path'
+ }
+
+ def "throws exception if test kit exists and is not dir"() {
+ when:
+ createRunner().withProjectDir(workingDir).build()
+
+ then:
+ 1 * testKitDirProvider.getDir() >> {
+ Mock(File) {
+ isDirectory() >> false
+ exists() >> true
+ getAbsolutePath() >> "path"
+ }
+ }
+ Throwable t = thrown(InvalidRunnerConfigurationException)
+ t.message == 'Unable to use non-directory as test kit directory: path'
+ }
+
+ def "throws exception if test kit dir cannot be created"() {
+ when:
+ createRunner().withProjectDir(workingDir).build()
+
+ then:
+ 1 * testKitDirProvider.getDir() >> {
+ Mock(File) {
+ isDirectory() >> false
+ exists() >> false
+ mkdirs() >> false
+ getAbsolutePath() >> "path"
+ }
+ }
+ Throwable t = thrown(InvalidRunnerConfigurationException)
+ t.message == 'Unable to create test kit directory: path'
+ }
+
+ def "returned arguments are unmodifiable"() {
+ when:
+ createRunner().arguments << '-i'
+
+ then:
+ thrown(UnsupportedOperationException)
+ }
+
+ def "creates defensive copy of passed in argument lists"() {
+ given:
+ def originalArguments = ['arg1', 'arg2']
+ def originalJvmArguments = ['arg3', 'arg4']
+ DefaultGradleRunner defaultGradleRunner = createRunner()
+
+ when:
+ defaultGradleRunner.withArguments(originalArguments)
+ defaultGradleRunner.withJvmArguments(originalJvmArguments)
+
+ then:
+ defaultGradleRunner.arguments == ['arg1', 'arg2']
+ defaultGradleRunner.jvmArguments == ['arg3', 'arg4']
+
+ when:
+ originalArguments << 'arg5'
+ originalJvmArguments << 'arg6'
+
+ then:
+ defaultGradleRunner.arguments == ['arg1', 'arg2']
+ defaultGradleRunner.jvmArguments == ['arg3', 'arg4']
+ }
+
+ def "throws exception if working directory is not provided when build is requested"() {
+ when:
+ DefaultGradleRunner defaultGradleRunner = createRunner()
+ defaultGradleRunner.build()
+
+ then:
+ Throwable t = thrown(InvalidRunnerConfigurationException)
+ t.message == 'Please specify a project directory before executing the build'
+ }
+
+ def "throws exception if working directory is not provided when build and fail is requested"() {
+ when:
+ DefaultGradleRunner defaultGradleRunner = createRunner()
+ defaultGradleRunner.buildAndFail()
+
+ then:
+ Throwable t = thrown(InvalidRunnerConfigurationException)
+ t.message == 'Please specify a project directory before executing the build'
+ }
+
+ def "creates diagnostic message for execution result without thrown exception"() {
+ given:
+ DefaultGradleRunner defaultGradleRunner = createRunnerWithWorkingDirAndArgument()
+ GradleExecutionResult gradleExecutionResult = createGradleExecutionResult()
+
+ when:
+ String message = defaultGradleRunner.createDiagnosticsMessage('Gradle build executed', gradleExecutionResult)
+
+ then:
+ TextUtil.normaliseLineSeparators(message) == basicDiagnosticsMessage
+ }
+
+ @Unroll
+ def "creates diagnostic message for execution result for thrown #description"() {
+ given:
+ DefaultGradleRunner defaultGradleRunner = createRunnerWithWorkingDirAndArgument()
+ GradleExecutionResult gradleExecutionResult = createGradleExecutionResult(exception)
+
+ when:
+ String message = defaultGradleRunner.createDiagnosticsMessage('Gradle build executed', gradleExecutionResult)
+
+ then:
+ TextUtil.normaliseLineSeparators(message) == """$basicDiagnosticsMessage
+Reason:
+$expectedReason
+-----"""
+
+ where:
+ exception | expectedReason | description
+ new RuntimeException('Something went wrong') | 'Something went wrong' | 'exception having no parent cause'
+ new RuntimeException('Something went wrong', new GradleException('Unknown command line option')) | 'Unknown command line option' | 'exception having single parent cause'
+ new RuntimeException('Something went wrong', new GradleException('Unknown command line option', new Exception('Total fail'))) | 'Total fail' | 'exception having multiple parent causes'
+ }
+
+ def "temporary working space directory is not created if Gradle user home directory is not provided by user when build is requested"() {
+ given:
+ File gradleUserHomeDir = new File('some/dir')
+
+ when:
+ DefaultGradleRunner defaultGradleRunner = createRunnerWithWorkingDirAndArgument()
+ defaultGradleRunner.build()
+
+ then:
+ 1 * testKitDirProvider.getDir() >> gradleUserHomeDir
+ 1 * gradleExecutor.run(gradleHome, gradleUserHomeDir, workingDir, arguments, []) >> new GradleExecutionResult(new ByteArrayOutputStream(), new ByteArrayOutputStream(), null)
+ }
+
+ def "temporary working space directory is not created if Gradle user home directory is not provided by user when build and fail is requested"() {
+ given:
+ File gradleUserHomeDir = new File('some/dir')
+
+ when:
+ DefaultGradleRunner defaultGradleRunner = createRunnerWithWorkingDirAndArgument()
+ defaultGradleRunner.build()
+
+ then:
+ 1 * testKitDirProvider.getDir() >> gradleUserHomeDir
+ 1 * gradleExecutor.run(gradleHome, gradleUserHomeDir, workingDir, arguments, []) >> new GradleExecutionResult(new ByteArrayOutputStream(), new ByteArrayOutputStream(), null)
+ }
+
+ private DefaultGradleRunner createRunner() {
+ new DefaultGradleRunner(gradleHome, gradleExecutor, testKitDirProvider)
+ }
+
+ private DefaultGradleRunner createRunnerWithWorkingDirAndArgument() {
+ createRunner().withProjectDir(workingDir).withArguments(arguments)
+ }
+
+ private GradleExecutionResult createGradleExecutionResult(Throwable throwable = null) {
+ ByteArrayOutputStream standardOutput = new ByteArrayOutputStream()
+ standardOutput.write('This is some output'.bytes)
+ ByteArrayOutputStream standardError = new ByteArrayOutputStream()
+ standardError.write('This is some error'.bytes)
+ List<BuildResult> tasks = new ArrayList<BuildResult>();
+ new GradleExecutionResult(standardOutput, standardError, tasks, throwable)
+ }
+
+ private String getBasicDiagnosticsMessage() {
+ """Gradle build executed in $workingDir.absolutePath with arguments $arguments
+
+Output:
+This is some output
+$DefaultGradleRunner.DIAGNOSTICS_MESSAGE_SEPARATOR
+Error:
+This is some error
+$DefaultGradleRunner.DIAGNOSTICS_MESSAGE_SEPARATOR"""
+ }
+}
diff --git a/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/TempTestKitDirProviderTest.groovy b/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/TempTestKitDirProviderTest.groovy
new file mode 100644
index 0000000..e002c6b
--- /dev/null
+++ b/subprojects/test-kit/src/test/groovy/org/gradle/testkit/runner/internal/TempTestKitDirProviderTest.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.testkit.runner.internal
+
+import org.gradle.internal.SystemProperties
+import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.junit.Rule
+import spock.lang.Specification
+
+class TempTestKitDirProviderTest extends Specification {
+
+ @Rule
+ TestNameTestDirectoryProvider testDirectoryProvider = new TestNameTestDirectoryProvider()
+
+ File expectedTmpDir
+ TestKitDirProvider testKitDirProvider
+
+ def setup() {
+ testKitDirProvider = new TempTestKitDirProvider(testDirectoryProvider.testDirectory)
+ expectedTmpDir = new File(testDirectoryProvider.testDirectory, ".gradle-test-kit-${SystemProperties.instance.userName}")
+ }
+
+ def "can create temporary directory"() {
+ when:
+ File tmpDir = testKitDirProvider.getDir()
+
+ then:
+ !tmpDir.exists()
+ tmpDir == expectedTmpDir
+ }
+
+}
diff --git a/subprojects/test-kit/test-kit.gradle b/subprojects/test-kit/test-kit.gradle
new file mode 100644
index 0000000..01182f2
--- /dev/null
+++ b/subprojects/test-kit/test-kit.gradle
@@ -0,0 +1,7 @@
+dependencies {
+ compile project(':toolingApi')
+ testCompile libraries.groovy
+}
+
+strictCompile()
+useTestFixtures()
diff --git a/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/cunit/CUnitIntegrationTest.groovy b/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/cunit/CUnitIntegrationTest.groovy
index d857b12..17e408b 100755
--- a/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/cunit/CUnitIntegrationTest.groovy
+++ b/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/cunit/CUnitIntegrationTest.groovy
@@ -15,7 +15,7 @@
*/
package org.gradle.nativeplatform.test.cunit
-import org.gradle.api.reporting.model.ConsoleReportOutput
+import org.gradle.api.reporting.model.ModelReportOutput
import org.gradle.ide.visualstudio.fixtures.ProjectFile
import org.gradle.ide.visualstudio.fixtures.SolutionFile
import org.gradle.integtests.fixtures.executer.IntegrationTestBuildContext
@@ -195,22 +195,35 @@ model {
run "model"
then:
- ConsoleReportOutput consoleReportOutput = new ConsoleReportOutput(output)
- consoleReportOutput.hasNodeStructure(""" testSuites
- nativeComponentOneTest
- binaries
- nativeComponentOneTestCUnitExe
- tasks
- sources
- c
- cunitLauncher
- nativeComponentTwoTest
- binaries
- nativeComponentTwoTestCUnitExe
- tasks
- sources
- c
- cunitLauncher""")
+ ModelReportOutput.from(output).hasNodeStructure({
+ testSuites {
+ nativeComponentOneTest {
+ binaries {
+ nativeComponentOneTestCUnitExe {
+ tasks()
+ }
+
+ }
+ sources {
+ c()
+ cunitLauncher()
+ }
+ }
+
+ nativeComponentTwoTest {
+ binaries {
+ nativeComponentTwoTestCUnitExe {
+ tasks()
+ }
+ }
+ sources {
+ c()
+ cunitLauncher()
+ }
+ }
+ }
+ }
+ )
}
def "can supply cCompiler macro to cunit sources"() {
@@ -300,6 +313,7 @@ model {
sources {
variant(CSourceSet) {
source.srcDir "src/variant/c"
+ lib hello.sources.c
}
}
}
@@ -331,8 +345,8 @@ model {
sources {
variant(CSourceSet) {
source.srcDir "src/variantTest/c"
- lib sources.c
- lib sources.cunitLauncher
+ lib helloTest.sources.c
+ lib helloTest.sources.cunitLauncher
}
}
}
diff --git a/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestIntegrationTest.groovy b/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestIntegrationTest.groovy
index c9f4b18..cc6d952 100755
--- a/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestIntegrationTest.groovy
+++ b/subprojects/testing-native/src/integTest/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestIntegrationTest.groovy
@@ -280,6 +280,7 @@ model {
sources {
variant(CppSourceSet) {
source.srcDir "src/variant/cpp"
+ lib hello.sources.cpp
}
}
}
@@ -308,7 +309,7 @@ model {
sources {
variant(CppSourceSet) {
source.srcDir "src/variantTest/cpp"
- lib sources.cpp
+ lib helloTest.sources.cpp
}
}
}
diff --git a/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/cunit/plugins/CUnitPlugin.java b/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/cunit/plugins/CUnitPlugin.java
index 9088044..c358e05 100644
--- a/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/cunit/plugins/CUnitPlugin.java
+++ b/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/cunit/plugins/CUnitPlugin.java
@@ -92,7 +92,7 @@ public class CUnitPlugin implements Plugin<Project> {
public void configureCUnitTestSuiteSources(TestSuiteContainer testSuites, @Path("buildDir") File buildDir) {
for (final CUnitTestSuiteSpec suite : testSuites.withType(CUnitTestSuiteSpec.class).values()) {
- FunctionalSourceSet suiteSourceSet = ((ComponentSpecInternal) suite).getSources();
+ FunctionalSourceSet suiteSourceSet = ((ComponentSpecInternal) suite).getFunctionalSourceSet();
CSourceSet launcherSources = suiteSourceSet.maybeCreate(CUNIT_LAUNCHER_SOURCE_SET, CSourceSet.class);
File baseDir = new File(buildDir, String.format("src/%s/cunitLauncher", suite.getName()));
launcherSources.getSource().srcDir(new File(baseDir, "c"));
@@ -118,7 +118,7 @@ public class CUnitPlugin implements Plugin<Project> {
}
private CSourceSet findLauncherSources(CUnitTestSuiteSpec suite) {
- return suite.getSource().withType(CSourceSet.class).get(CUNIT_LAUNCHER_SOURCE_SET);
+ return suite.getSources().withType(CSourceSet.class).get(CUNIT_LAUNCHER_SOURCE_SET);
}
@BinaryType
diff --git a/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/internal/DefaultGoogleTestTestSuiteSpec.java b/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/internal/DefaultGoogleTestTestSuiteSpec.java
index 84145cc..d181815 100644
--- a/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/internal/DefaultGoogleTestTestSuiteSpec.java
+++ b/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/internal/DefaultGoogleTestTestSuiteSpec.java
@@ -22,7 +22,6 @@ import org.gradle.nativeplatform.test.googletest.GoogleTestTestSuiteSpec;
public class DefaultGoogleTestTestSuiteSpec extends AbstractNativeComponentSpec implements GoogleTestTestSuiteSpec {
private NativeComponentSpec testedComponent;
-
public String getDisplayName() {
return String.format("googleTest test suite '%s'", getName());
}
diff --git a/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/plugins/GoogleTestPlugin.java b/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/plugins/GoogleTestPlugin.java
index 290e312..a1b8231 100644
--- a/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/plugins/GoogleTestPlugin.java
+++ b/subprojects/testing-native/src/main/java/org/gradle/nativeplatform/test/googletest/plugins/GoogleTestPlugin.java
@@ -22,7 +22,6 @@ import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.internal.project.taskfactory.ITaskFactory;
import org.gradle.internal.service.ServiceRegistry;
-import org.gradle.language.base.FunctionalSourceSet;
import org.gradle.language.base.internal.registry.LanguageTransformContainer;
import org.gradle.language.cpp.CppSourceSet;
import org.gradle.language.cpp.plugins.CppLangPlugin;
@@ -44,7 +43,6 @@ import org.gradle.platform.base.BinaryTypeBuilder;
import org.gradle.platform.base.ComponentType;
import org.gradle.platform.base.ComponentTypeBuilder;
import org.gradle.platform.base.internal.BinaryNamingScheme;
-import org.gradle.platform.base.internal.ComponentSpecInternal;
import org.gradle.platform.base.internal.DefaultBinaryNamingSchemeBuilder;
import org.gradle.platform.base.test.TestSuiteContainer;
@@ -84,10 +82,10 @@ public class GoogleTestPlugin implements Plugin<Project> {
@Finalize
public void configureGoogleTestTestSuiteSources(TestSuiteContainer testSuites, @Path("buildDir") File buildDir) {
-
for (final GoogleTestTestSuiteSpec suite : testSuites.withType(GoogleTestTestSuiteSpec.class).values()) {
- FunctionalSourceSet suiteSourceSet = ((ComponentSpecInternal) suite).getSources();
- suiteSourceSet.maybeCreate("cpp", CppSourceSet.class);
+ if (!suite.getSources().containsKey("cpp")) {
+ suite.getSources().create("cpp", CppSourceSet.class);
+ }
}
}
diff --git a/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/cunit/CUnitTest.groovy b/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/cunit/CUnitTest.groovy
index 791a679..0c62056 100644
--- a/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/cunit/CUnitTest.groovy
+++ b/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/cunit/CUnitTest.groovy
@@ -39,7 +39,7 @@ class CUnitTest extends Specification {
when:
CUnitTestSuiteSpec testSuite = project.modelRegistry.realize(ModelPath.path("testSuites"), ModelTypes.modelMap(TestSuiteSpec)).mainTest
- def sources = testSuite.source.values()
+ def sources = testSuite.sources.values()
def binaries = testSuite.binaries.values()
then:
diff --git a/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestTest.groovy b/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestTest.groovy
index de4da32..7d2c4d4 100644
--- a/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestTest.groovy
+++ b/subprojects/testing-native/src/test/groovy/org/gradle/nativeplatform/test/googletest/GoogleTestTest.groovy
@@ -41,7 +41,7 @@ class GoogleTestTest extends Specification {
when:
GoogleTestTestSuiteSpec testSuite = project.modelRegistry.realize(ModelPath.path("testSuites"), ModelTypes.modelMap(TestSuiteSpec)).mainTest
- def sources = testSuite.source.values()
+ def sources = testSuite.sources.values()
def binaries = testSuite.binaries.values()
then:
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/BuildClientSubscriptionsSetup.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/BuildClientSubscriptionsSetup.java
deleted file mode 100644
index 5d6e764..0000000
--- a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/BuildClientSubscriptionsSetup.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.tooling.internal.provider.runner;
-
-import org.gradle.api.internal.GradleInternal;
-import org.gradle.initialization.BuildEventConsumer;
-import org.gradle.tooling.internal.provider.BuildClientSubscriptions;
-
-class BuildClientSubscriptionsSetup {
- /**
- * Registers listeners with {@code Gradle} to receive those events for which the client has subscribed. Dispatch the events received from the Gradle listeners via {@code BuildEventConsumer}.
- */
- static void registerListenersForClientSubscriptions(BuildClientSubscriptions clientSubscriptions, GradleInternal gradle) {
- BuildEventConsumer eventConsumer = gradle.getServices().get(BuildEventConsumer.class);
- if (clientSubscriptions.isSendTestProgressEvents()) {
- gradle.addListener(new ClientForwardingTestListener(eventConsumer, clientSubscriptions));
- }
- if (clientSubscriptions.isSendTaskProgressEvents()) {
- gradle.addListener(new ClientForwardingTaskListener(eventConsumer, clientSubscriptions));
- }
- if (clientSubscriptions.isSendBuildProgressEvents()) {
- gradle.addListener(new ClientForwardingBuildListener(eventConsumer));
- }
- }
-}
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/BuildModelActionRunner.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/BuildModelActionRunner.java
index 3231363..eef21bb 100644
--- a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/BuildModelActionRunner.java
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/BuildModelActionRunner.java
@@ -42,10 +42,6 @@ public class BuildModelActionRunner implements BuildActionRunner {
BuildModelAction buildModelAction = (BuildModelAction) action;
GradleInternal gradle = buildController.getGradle();
- // register listeners that dispatch all progress via the registered BuildEventConsumer instance,
- // this allows to send progress events back to the DaemonClient (via short-cut)
- BuildClientSubscriptionsSetup.registerListenersForClientSubscriptions(buildModelAction.getClientSubscriptions(), gradle);
-
if (buildModelAction.isRunTasks()) {
buildController.run();
} else {
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingBuildListener.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingBuildListener.java
index d1e518d..edd9d97 100644
--- a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingBuildListener.java
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingBuildListener.java
@@ -50,8 +50,8 @@ class ClientForwardingBuildListener implements InternalBuildListener {
private DefaultOperationDescriptor toBuildOperationDescriptor(BuildOperationInternal buildOperation) {
Object id = buildOperation.getId();
- String name = buildOperation.getOperationType().getName();
- String displayName = buildOperation.getOperationType().getDisplayName();
+ String name = buildOperation.getDisplayName();
+ String displayName = buildOperation.getDisplayName();
Object parentId = buildOperation.getParentId();
return new DefaultOperationDescriptor(id, name, displayName, parentId);
}
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingTestListener.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingTestListener.java
index c65187c..914d341 100644
--- a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingTestListener.java
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientForwardingTestListener.java
@@ -15,27 +15,35 @@
*/
package org.gradle.tooling.internal.provider.runner;
+import com.google.common.collect.Maps;
+import org.gradle.api.execution.internal.InternalTaskExecutionListener;
+import org.gradle.api.execution.internal.TaskOperationInternal;
import org.gradle.api.internal.tasks.testing.TestCompleteEvent;
import org.gradle.api.internal.tasks.testing.TestDescriptorInternal;
import org.gradle.api.internal.tasks.testing.TestStartEvent;
import org.gradle.api.internal.tasks.testing.results.TestListenerInternal;
+import org.gradle.api.tasks.testing.Test;
import org.gradle.api.tasks.testing.TestOutputEvent;
import org.gradle.api.tasks.testing.TestResult;
import org.gradle.initialization.BuildEventConsumer;
+import org.gradle.internal.progress.OperationResult;
+import org.gradle.internal.progress.OperationStartEvent;
import org.gradle.tooling.internal.protocol.events.InternalJvmTestDescriptor;
import org.gradle.tooling.internal.provider.BuildClientSubscriptions;
import org.gradle.tooling.internal.provider.events.*;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Test listener that forwards all receiving events to the client via the provided {@code BuildEventConsumer} instance.
*/
-class ClientForwardingTestListener implements TestListenerInternal {
+class ClientForwardingTestListener implements TestListenerInternal, InternalTaskExecutionListener {
private final BuildEventConsumer eventConsumer;
private final BuildClientSubscriptions clientSubscriptions;
+ private Map<Object, String> runningTasks = Maps.newHashMap();
ClientForwardingTestListener(BuildEventConsumer eventConsumer, BuildClientSubscriptions clientSubscriptions) {
this.eventConsumer = eventConsumer;
@@ -70,7 +78,8 @@ class ClientForwardingTestListener implements TestListenerInternal {
String className = suite.getClassName();
String methodName = null;
Object parentId = getParentId(suite);
- return new DefaultTestDescriptor(id, name, displayName, testKind, suiteName, className, methodName, parentId);
+ final String testTaskPath = getTaskPath(suite);
+ return new DefaultTestDescriptor(id, name, displayName, testKind, suiteName, className, methodName, parentId, testTaskPath);
}
private DefaultTestDescriptor toTestDescriptorForTest(TestDescriptorInternal test) {
@@ -82,7 +91,16 @@ class ClientForwardingTestListener implements TestListenerInternal {
String className = test.getClassName();
String methodName = test.getName();
Object parentId = getParentId(test);
- return new DefaultTestDescriptor(id, name, displayName, testKind, suiteName, className, methodName, parentId);
+ final String taskPath = getTaskPath(test);
+ return new DefaultTestDescriptor(id, name, displayName, testKind, suiteName, className, methodName, parentId, taskPath);
+ }
+
+ private String getTaskPath(TestDescriptorInternal givenDescriptor) {
+ TestDescriptorInternal descriptor = givenDescriptor;
+ while(descriptor.getOwnerBuildOperationId() == null && descriptor.getParent()!=null){
+ descriptor = descriptor.getParent();
+ }
+ return runningTasks.get(descriptor.getOwnerBuildOperationId());
}
private Object getParentId(TestDescriptorInternal descriptor) {
@@ -119,4 +137,15 @@ class ClientForwardingTestListener implements TestListenerInternal {
return failures;
}
+ @Override
+ public void beforeExecute(TaskOperationInternal taskOperation, OperationStartEvent startEvent) {
+ if(taskOperation.getTask() instanceof Test){
+ runningTasks.put(taskOperation.getId(), taskOperation.getTask().getPath());
+ }
+ }
+
+ @Override
+ public void afterExecute(TaskOperationInternal taskOperation, OperationResult result) {
+ runningTasks.remove(taskOperation.getId());
+ }
}
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientProvidedBuildActionRunner.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientProvidedBuildActionRunner.java
index 64d5353..572e0c2 100644
--- a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientProvidedBuildActionRunner.java
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ClientProvidedBuildActionRunner.java
@@ -42,10 +42,6 @@ public class ClientProvidedBuildActionRunner implements BuildActionRunner {
PayloadSerializer payloadSerializer = gradle.getServices().get(PayloadSerializer.class);
InternalBuildAction<?> clientAction = (InternalBuildAction<?>) payloadSerializer.deserialize(clientProvidedBuildAction.getAction());
- // register listeners that dispatch all progress via the registered BuildEventConsumer instance,
- // this allows to send progress events back to the DaemonClient (via short-cut)
- BuildClientSubscriptionsSetup.registerListenersForClientSubscriptions(clientProvidedBuildAction.getClientSubscriptions(), gradle);
-
buildController.configure();
// Currently need to force everything to be configured
gradle.getServices().get(ProjectConfigurer.class).configureHierarchy(gradle.getRootProject());
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/SubscribableBuildActionRunner.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/SubscribableBuildActionRunner.java
new file mode 100644
index 0000000..1fcefee
--- /dev/null
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/SubscribableBuildActionRunner.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.runner;
+
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.initialization.BuildEventConsumer;
+import org.gradle.internal.invocation.BuildAction;
+import org.gradle.internal.invocation.BuildActionRunner;
+import org.gradle.internal.invocation.BuildController;
+import org.gradle.tooling.internal.provider.BuildClientSubscriptions;
+import org.gradle.tooling.internal.provider.SubscribableBuildAction;
+
+public class SubscribableBuildActionRunner implements BuildActionRunner {
+ private BuildActionRunner delegate;
+
+ public SubscribableBuildActionRunner(BuildActionRunner delegate) {
+ this.delegate = delegate;
+ }
+
+ private void registerListenersForClientSubscriptions(BuildClientSubscriptions clientSubscriptions, GradleInternal gradle) {
+ BuildEventConsumer eventConsumer = gradle.getServices().get(BuildEventConsumer.class);
+ if (clientSubscriptions.isSendTestProgressEvents()) {
+ gradle.addListener(new ClientForwardingTestListener(eventConsumer, clientSubscriptions));
+ }
+ if (clientSubscriptions.isSendTaskProgressEvents()) {
+ gradle.addListener(new ClientForwardingTaskListener(eventConsumer, clientSubscriptions));
+ }
+ if (clientSubscriptions.isSendBuildProgressEvents()) {
+ gradle.addListener(new ClientForwardingBuildListener(eventConsumer));
+ }
+ }
+
+ @Override
+ public void run(BuildAction action, BuildController buildController) {
+ if (!(action instanceof SubscribableBuildAction)) {
+ return;
+ }
+ GradleInternal gradle = buildController.getGradle();
+ SubscribableBuildAction subscribableBuildAction = (SubscribableBuildAction) action;
+
+ // register listeners that dispatch all progress via the registered BuildEventConsumer instance,
+ // this allows to send progress events back to the DaemonClient (via short-cut)
+ registerListenersForClientSubscriptions(subscribableBuildAction.getClientSubscriptions(), gradle);
+ delegate.run(action, buildController);
+ }
+}
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionBuildConfigurationAction.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionBuildConfigurationAction.java
new file mode 100644
index 0000000..95647eb
--- /dev/null
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionBuildConfigurationAction.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.runner;
+
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.Transformer;
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.api.specs.Specs;
+import org.gradle.api.tasks.testing.Test;
+import org.gradle.api.tasks.testing.TestExecutionException;
+import org.gradle.api.tasks.testing.TestFilter;
+import org.gradle.execution.BuildConfigurationAction;
+import org.gradle.execution.BuildExecutionContext;
+import org.gradle.tooling.internal.protocol.events.InternalTestDescriptor;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+import org.gradle.tooling.internal.provider.TestExecutionRequestAction;
+import org.gradle.tooling.internal.provider.events.DefaultTestDescriptor;
+
+import java.util.*;
+
+class TestExecutionBuildConfigurationAction implements BuildConfigurationAction {
+ private final GradleInternal gradle;
+ private final TestExecutionRequestAction testExecutionRequest;
+
+ public TestExecutionBuildConfigurationAction(TestExecutionRequestAction testExecutionRequest, GradleInternal gradle) {
+ this.testExecutionRequest = testExecutionRequest;
+ this.gradle = gradle;
+ }
+
+ @Override
+ public void configure(BuildExecutionContext context) {
+ final Set<Test> allTestTasksToRun = new LinkedHashSet<Test>();
+ final GradleInternal gradleInternal = context.getGradle();
+ allTestTasksToRun.addAll(configureBuildForTestDescriptors(gradleInternal, testExecutionRequest));
+ allTestTasksToRun.addAll(configureBuildForInternalJvmTestRequest(gradleInternal, testExecutionRequest));
+ configureTestTasks(allTestTasksToRun);
+ gradle.getTaskGraph().addTasks(allTestTasksToRun);
+ }
+
+ private void configureTestTasks(Set<Test> allTestTasksToRun) {
+ for (Test task : allTestTasksToRun) {
+ task.setIgnoreFailures(true);
+ task.getFilter().setFailOnNoMatchingTests(false);
+ task.getOutputs().upToDateWhen(Specs.SATISFIES_NONE);
+ }
+ }
+
+ private List<Test> configureBuildForTestDescriptors(GradleInternal gradle, TestExecutionRequestAction testExecutionRequest) {
+ final Collection<InternalTestDescriptor> testDescriptors = testExecutionRequest.getTestExecutionDescriptors();
+
+ final List<String> testTaskPaths = org.gradle.util.CollectionUtils.collect(testDescriptors, new Transformer<String, InternalTestDescriptor>() {
+ @Override
+ public String transform(InternalTestDescriptor testDescriptor) {
+ return ((DefaultTestDescriptor) testDescriptor).getTaskPath();
+ }
+ });
+
+ List<Test> testTasksToRun = new ArrayList<Test>();
+ for (final String testTaskPath : testTaskPaths) {
+ final Task task = gradle.getRootProject().getTasks().findByPath(testTaskPath);
+ if (task == null) {
+ throw new TestExecutionException(String.format("Requested test task with path '%s' cannot be found.", testTaskPath));
+ } else if (!(task instanceof Test)) {
+ throw new TestExecutionException(String.format("Task '%s' of type '%s' not supported for executing tests via TestLauncher API.", testTaskPath, task.getClass().getName()));
+ } else {
+ Test testTask = (Test) task;
+ for (InternalTestDescriptor testDescriptor : testDescriptors) {
+ DefaultTestDescriptor defaultTestDescriptor = (DefaultTestDescriptor) testDescriptor;
+ if (defaultTestDescriptor.getTaskPath().equals(testTaskPath)) {
+ String className = defaultTestDescriptor.getClassName();
+ String methodName = defaultTestDescriptor.getMethodName();
+ if (className == null && methodName == null) {
+ testTask.getFilter().includeTestsMatching("*");
+ } else {
+ testTask.getFilter().includeTest(className, methodName);
+ }
+ }
+ }
+ testTasksToRun.add(testTask);
+ }
+ }
+ return testTasksToRun;
+ }
+
+ private List<Test> configureBuildForInternalJvmTestRequest(GradleInternal gradle, TestExecutionRequestAction testExecutionRequest) {
+ final Collection<InternalJvmTestRequest> internalJvmTestRequests = testExecutionRequest.getInternalJvmTestRequests();
+ if(internalJvmTestRequests.isEmpty()){
+ return Collections.emptyList();
+ }
+
+ List<Test> tasksToExecute = new ArrayList<Test>();
+
+ final Set<Project> allprojects = gradle.getRootProject().getAllprojects();
+ for (Project project : allprojects) {
+ final Collection<Test> testTasks = project.getTasks().withType(Test.class);
+ for (Test testTask : testTasks) {
+ for (InternalJvmTestRequest jvmTestRequest : internalJvmTestRequests) {
+ final TestFilter filter = testTask.getFilter();
+ filter.includeTest(jvmTestRequest.getClassName(), jvmTestRequest.getMethodName());
+ }
+ }
+ tasksToExecute.addAll(testTasks);
+ }
+ return tasksToExecute;
+ }
+}
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionRequestActionRunner.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionRequestActionRunner.java
new file mode 100644
index 0000000..b539d1f
--- /dev/null
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionRequestActionRunner.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.runner;
+
+import org.gradle.api.internal.GradleInternal;
+import org.gradle.api.tasks.testing.TestExecutionException;
+import org.gradle.execution.BuildConfigurationActionExecuter;
+import org.gradle.internal.invocation.BuildAction;
+import org.gradle.internal.invocation.BuildActionRunner;
+import org.gradle.internal.invocation.BuildController;
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionException;
+import org.gradle.tooling.internal.provider.BuildActionResult;
+import org.gradle.tooling.internal.provider.PayloadSerializer;
+import org.gradle.tooling.internal.provider.TestExecutionRequestAction;
+
+import java.util.Collections;
+
+public class TestExecutionRequestActionRunner implements BuildActionRunner {
+ @Override
+ public void run(BuildAction action, BuildController buildController) {
+ if (!(action instanceof TestExecutionRequestAction)) {
+ return;
+ }
+ GradleInternal gradle = buildController.getGradle();
+
+ try {
+ TestExecutionRequestAction testExecutionRequestAction = (TestExecutionRequestAction) action;
+ TestExecutionResultEvaluator testExecutionResultEvaluator = new TestExecutionResultEvaluator(testExecutionRequestAction);
+ gradle.addListener(testExecutionResultEvaluator);
+ doRun(testExecutionRequestAction, buildController);
+ testExecutionResultEvaluator.evaluate();
+ } catch (RuntimeException rex) {
+ Throwable throwable = findRootCause(rex);
+ if (throwable instanceof TestExecutionException) {
+ throw new InternalTestExecutionException("Error while running test(s)", throwable);
+ } else {
+ throw rex;
+ }
+ }
+ PayloadSerializer payloadSerializer = gradle.getServices().get(PayloadSerializer.class);
+ buildController.setResult(new BuildActionResult(payloadSerializer.serialize(null), null));
+ }
+
+ private void doRun(TestExecutionRequestAction action, BuildController buildController) {
+ TestExecutionBuildConfigurationAction testTasksConfigurationAction = new TestExecutionBuildConfigurationAction(action, buildController.getGradle());
+ buildController.getGradle().getServices().get(BuildConfigurationActionExecuter.class).setTaskSelectors(Collections.singletonList(testTasksConfigurationAction));
+ buildController.run();
+ }
+
+ private Throwable findRootCause(Exception tex) {
+ Throwable t = tex;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+ return t;
+ }
+}
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionResultEvaluator.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionResultEvaluator.java
new file mode 100644
index 0000000..a9b72b8
--- /dev/null
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/TestExecutionResultEvaluator.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.runner;
+
+import com.beust.jcommander.internal.Lists;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import org.gradle.api.execution.internal.InternalTaskExecutionListener;
+import org.gradle.api.execution.internal.TaskOperationInternal;
+import org.gradle.api.internal.tasks.testing.TestCompleteEvent;
+import org.gradle.api.internal.tasks.testing.TestDescriptorInternal;
+import org.gradle.api.internal.tasks.testing.TestStartEvent;
+import org.gradle.api.internal.tasks.testing.results.TestListenerInternal;
+import org.gradle.api.tasks.testing.TestExecutionException;
+import org.gradle.api.tasks.testing.TestOutputEvent;
+import org.gradle.api.tasks.testing.TestResult;
+import org.gradle.internal.progress.OperationResult;
+import org.gradle.internal.progress.OperationStartEvent;
+import org.gradle.tooling.internal.protocol.events.InternalTestDescriptor;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+import org.gradle.tooling.internal.provider.TestExecutionRequestAction;
+import org.gradle.tooling.internal.provider.events.DefaultTestDescriptor;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+class TestExecutionResultEvaluator implements TestListenerInternal, InternalTaskExecutionListener {
+ private static final String INDENT = " ";
+
+ private long resultCount;
+ private Map<Object, String> runningTasks = Maps.newHashMap();
+
+ private TestExecutionRequestAction internalTestExecutionRequest;
+ private List<FailedTest> failedTests = Lists.newArrayList();
+
+ public TestExecutionResultEvaluator(TestExecutionRequestAction internalTestExecutionRequest) {
+ this.internalTestExecutionRequest = internalTestExecutionRequest;
+ }
+
+ public boolean hasUnmatchedTests() {
+ return resultCount == 0;
+ }
+
+ public boolean hasFailedTests() {
+ return !failedTests.isEmpty();
+ }
+
+ public void evaluate() {
+ if (hasUnmatchedTests()) {
+ String formattedTestRequest = formatInternalTestExecutionRequest();
+ throw new TestExecutionException("No matching tests found in any candidate test task.\n" + formattedTestRequest);
+ }
+ if (hasFailedTests()) {
+ StringBuilder failedTestsMessage = new StringBuilder("Test failed.\n")
+ .append(INDENT).append("Failed tests:");
+ for (FailedTest failedTest : failedTests) {
+ failedTestsMessage.append("\n").append(Strings.repeat(INDENT, 2)).append(failedTest.getDescription());
+ }
+ throw new TestExecutionException(failedTestsMessage.toString());
+ }
+ }
+
+ private String formatInternalTestExecutionRequest() {
+ StringBuilder requestDetails = new StringBuilder(INDENT).append("Requested tests:");
+ for (InternalTestDescriptor internalTestDescriptor : internalTestExecutionRequest.getTestExecutionDescriptors()) {
+ requestDetails.append("\n").append(Strings.repeat(INDENT, 2)).append(internalTestDescriptor.getDisplayName());
+ requestDetails.append(" (Task: '").append(((DefaultTestDescriptor) internalTestDescriptor).getTaskPath()).append("')");
+ }
+ final Collection<InternalJvmTestRequest> internalJvmTestRequests = internalTestExecutionRequest.getInternalJvmTestRequests();
+
+ for (InternalJvmTestRequest internalJvmTestRequest : internalJvmTestRequests) {
+ final String className = internalJvmTestRequest.getClassName();
+ final String methodName = internalJvmTestRequest.getMethodName();
+ if(methodName == null){
+ requestDetails.append("\n").append(Strings.repeat(INDENT, 2)).append("Test class ").append(className);
+ }else{
+ requestDetails.append("\n").append(Strings.repeat(INDENT, 2)).append("Test method ").append(className).append(".").append(methodName).append("()");
+ }
+ }
+ return requestDetails.toString();
+ }
+
+ @Override
+ public void started(TestDescriptorInternal testDescriptor, TestStartEvent startEvent) {
+
+ }
+
+ @Override
+ public void completed(TestDescriptorInternal testDescriptor, TestResult testResult, TestCompleteEvent completeEvent) {
+ if (testDescriptor.getParent() == null) {
+ resultCount = resultCount + testResult.getTestCount();
+ }
+ if (!testDescriptor.isComposite() && testResult.getFailedTestCount() != 0) {
+ failedTests.add(new FailedTest(testDescriptor.getName(), testDescriptor.getClassName(), getTaskPath(testDescriptor)));
+ }
+ }
+
+ private String getTaskPath(TestDescriptorInternal givenDescriptor) {
+ TestDescriptorInternal descriptor = givenDescriptor;
+ while (descriptor.getOwnerBuildOperationId() == null && descriptor.getParent() != null) {
+ descriptor = descriptor.getParent();
+ }
+ return runningTasks.get(descriptor.getOwnerBuildOperationId());
+ }
+
+ @Override
+ public void output(TestDescriptorInternal testDescriptor, TestOutputEvent event) {
+ }
+
+ @Override
+ public void beforeExecute(TaskOperationInternal taskOperation, OperationStartEvent startEvent) {
+ runningTasks.put(taskOperation.getId(), taskOperation.getTask().getPath());
+ }
+
+ @Override
+ public void afterExecute(TaskOperationInternal taskOperation, OperationResult result) {
+ runningTasks.remove(taskOperation.getId());
+ }
+
+ private static class FailedTest {
+ final String name;
+ final String className;
+ final String taskPath;
+
+ public FailedTest(String name, String className, String taskPath) {
+ this.name = name;
+ this.className = className;
+ this.taskPath = taskPath;
+ }
+
+ public String getDescription() {
+ StringBuilder stringBuilder = new StringBuilder("Test ")
+ .append(className).append("#").append(name)
+ .append(" (Task: ").append(taskPath).append(")");
+ return stringBuilder.toString();
+
+ }
+ }
+}
diff --git a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ToolingBuilderServices.java b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ToolingBuilderServices.java
index 6800aa8..85b20c7 100644
--- a/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ToolingBuilderServices.java
+++ b/subprojects/tooling-api-builders/src/main/java/org/gradle/tooling/internal/provider/runner/ToolingBuilderServices.java
@@ -16,23 +16,30 @@
package org.gradle.tooling.internal.provider.runner;
+import org.gradle.internal.invocation.BuildActionRunner;
import org.gradle.internal.service.ServiceRegistration;
import org.gradle.internal.service.scopes.PluginServiceRegistry;
+import org.gradle.launcher.exec.ChainingBuildActionRunner;
+
+import java.util.Arrays;
public class ToolingBuilderServices implements PluginServiceRegistry {
@Override
public void registerGlobalServices(ServiceRegistration registration) {
- registration.addProvider(new Object() {
- BuildModelActionRunner createBuildModelActionRunner() {
- return new BuildModelActionRunner();
- }
- ClientProvidedBuildActionRunner createClientProvidedBuildActionRunner() {
- return new ClientProvidedBuildActionRunner();
+ registration.addProvider(new Object() {
+ BuildActionRunner createBuildActionRunner() {
+ return new SubscribableBuildActionRunner(new ChainingBuildActionRunner(Arrays.asList(
+ new BuildModelActionRunner(),
+ new TestExecutionRequestActionRunner(),
+ new ClientProvidedBuildActionRunner())));
}
});
}
+ public void registerBuildSessionServices(ServiceRegistration registration) {
+ }
+
@Override
public void registerBuildServices(ServiceRegistration registration) {
}
diff --git a/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionBuildConfigurationActionTest.groovy b/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionBuildConfigurationActionTest.groovy
new file mode 100644
index 0000000..020e3c9
--- /dev/null
+++ b/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionBuildConfigurationActionTest.groovy
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.runner
+
+import org.gradle.api.internal.GradleInternal
+import org.gradle.api.internal.TaskOutputsInternal
+import org.gradle.api.internal.project.ProjectInternal
+import org.gradle.api.internal.tasks.TaskContainerInternal
+import org.gradle.api.specs.Specs
+import org.gradle.api.tasks.TaskCollection
+import org.gradle.api.tasks.testing.Test
+import org.gradle.api.tasks.testing.TestFilter
+import org.gradle.execution.BuildExecutionContext
+import org.gradle.execution.TaskGraphExecuter
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest
+import org.gradle.tooling.internal.provider.TestExecutionRequestAction
+import org.gradle.tooling.internal.provider.events.DefaultTestDescriptor
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class TestExecutionBuildConfigurationActionTest extends Specification {
+
+ public static final String TEST_CLASS_NAME = "TestClass"
+ public static final String TEST_METHOD_NAME = "testMethod"
+ public static final String TEST_TASK_NAME = ":test"
+
+ ProjectInternal projectInternal
+ Test testTask
+ TaskContainerInternal tasksContainerInternal
+ TestFilter testFilter
+ TaskOutputsInternal outputsInternal
+ GradleInternal gradleInternal
+ BuildExecutionContext buildContext
+ TaskGraphExecuter taskGraphExecuter
+ TestExecutionRequestAction testExecutionRequest
+
+ def setup() {
+ outputsInternal = Mock()
+ projectInternal = Mock()
+ gradleInternal = Mock()
+ buildContext = Mock()
+ tasksContainerInternal = Mock()
+ taskGraphExecuter = Mock()
+ testExecutionRequest = Mock()
+ testTask = Mock()
+ testFilter = Mock()
+
+ setupProject()
+ setupTestTask()
+ }
+
+ private void setupProject() {
+ 1 * gradleInternal.getTaskGraph() >> taskGraphExecuter
+ 1 * buildContext.getGradle() >> gradleInternal
+ _ * gradleInternal.getRootProject() >> projectInternal
+ }
+
+ def "empty test execution request configures no tasks"() {
+ 1 * testExecutionRequest.getTestExecutionDescriptors() >> []
+ 1 * testExecutionRequest.getInternalJvmTestRequests() >> []
+
+ setup:
+ def buildConfigurationAction = new TestExecutionBuildConfigurationAction(testExecutionRequest, gradleInternal);
+ when:
+ buildConfigurationAction.configure(buildContext)
+ then:
+ 0 * projectInternal.getAllprojects() >> [projectInternal]
+ _ * taskGraphExecuter.addTasks({ args -> assert args.size() == 0 })
+ }
+
+ @Unroll
+ def "sets test filter with information from #requestType"() {
+ setup:
+ _ * projectInternal.getAllprojects() >> [projectInternal]
+
+ 1 * testExecutionRequest.getTestExecutionDescriptors() >> descriptors
+ 1 * testExecutionRequest.getInternalJvmTestRequests() >> internalJvmRequests
+
+ def buildConfigurationAction = new TestExecutionBuildConfigurationAction(testExecutionRequest, gradleInternal);
+ when:
+ buildConfigurationAction.configure(buildContext)
+ then:
+ 1 * testFilter.includeTest(expectedClassFilter, expectedMethodFilter)
+
+ 1 * testTask.setIgnoreFailures(true)
+ 1 * testFilter.setFailOnNoMatchingTests(false)
+ 1 * outputsInternal.upToDateWhen(Specs.SATISFIES_NONE)
+ where:
+ requestType | descriptors | internalJvmRequests | expectedClassFilter | expectedMethodFilter
+ "test descriptors" | [testDescriptor()] | [] | TEST_CLASS_NAME | TEST_METHOD_NAME
+ "test classes" | [] | [jvmTestRequest(TEST_CLASS_NAME, null)] | TEST_CLASS_NAME | null
+ "test methods" | [] | [jvmTestRequest(TEST_CLASS_NAME, TEST_METHOD_NAME)] | TEST_CLASS_NAME | TEST_METHOD_NAME
+ }
+
+ InternalJvmTestRequest jvmTestRequest(String className, String methodName) {
+ InternalJvmTestRequest jvmTestRequest = Mock()
+ _ * jvmTestRequest.getClassName() >> className
+ _ * jvmTestRequest.getMethodName() >> methodName
+ jvmTestRequest
+ }
+
+ private void setupTestTask() {
+ _ * projectInternal.getTasks() >> tasksContainerInternal
+ _ * testTask.getFilter() >> testFilter
+ _ * tasksContainerInternal.findByPath(TEST_TASK_NAME) >> testTask
+ TaskCollection<Test> testTaskCollection = Mock()
+ _ * testTaskCollection.iterator() >> [testTask].iterator()
+ _ * testTaskCollection.toArray() >> [testTask].toArray()
+ _ * tasksContainerInternal.withType(Test) >> testTaskCollection
+ _ * testTask.getOutputs() >> outputsInternal
+ }
+
+ private DefaultTestDescriptor testDescriptor() {
+ new DefaultTestDescriptor(1, "test1", "test 1", "ATOMIC", "test suite", TEST_CLASS_NAME, TEST_METHOD_NAME, 0, TEST_TASK_NAME)
+ }
+
+}
diff --git a/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionRequestActionRunnerTest.groovy b/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionRequestActionRunnerTest.groovy
new file mode 100644
index 0000000..1a0b130
--- /dev/null
+++ b/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionRequestActionRunnerTest.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.runner
+import org.gradle.internal.invocation.BuildAction
+import org.gradle.internal.invocation.BuildController
+import spock.lang.Specification
+
+class TestExecutionRequestActionRunnerTest extends Specification {
+
+ def "does not handle non TestExecutionRequestAction"(){
+ given:
+ def runner = new TestExecutionRequestActionRunner()
+ BuildAction buildAction = Mock(BuildAction)
+ BuildController buildController= Mock(BuildController)
+ when:
+ runner.run(buildAction, buildController)
+ then:
+ 0 * buildController._
+ 0 * buildAction._
+ }
+}
diff --git a/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionResultEvaluatorTest.groovy b/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionResultEvaluatorTest.groovy
new file mode 100644
index 0000000..1ad75ff
--- /dev/null
+++ b/subprojects/tooling-api-builders/src/test/groovy/org/gradle/tooling/internal/provider/runner/TestExecutionResultEvaluatorTest.groovy
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.provider.runner
+
+import org.gradle.api.execution.internal.TaskOperationInternal
+import org.gradle.api.internal.TaskInternal
+import org.gradle.api.internal.tasks.testing.TestCompleteEvent
+import org.gradle.api.internal.tasks.testing.TestDescriptorInternal
+import org.gradle.api.tasks.testing.TestExecutionException
+import org.gradle.api.tasks.testing.TestResult
+import org.gradle.internal.progress.OperationStartEvent
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest
+import org.gradle.tooling.internal.provider.TestExecutionRequestAction
+import org.gradle.tooling.internal.provider.events.DefaultTestDescriptor
+import spock.lang.Specification
+
+import static org.gradle.util.TextUtil.normaliseLineSeparators
+
+class TestExecutionResultEvaluatorTest extends Specification {
+ def "evaluate throws exception if no results tracked"() {
+ given:
+ def testExecutionRequest = Mock(TestExecutionRequestAction)
+ TestExecutionResultEvaluator evaluator = new TestExecutionResultEvaluator(testExecutionRequest)
+
+ def testDescriptorInternal = Mock(TestDescriptorInternal)
+ def defaultTestDescriptor = Mock(DefaultTestDescriptor)
+ 1 * defaultTestDescriptor.getDisplayName() >> "Some Test Descriptor"
+ 1 * defaultTestDescriptor.getTaskPath() >> ":someTestTask"
+
+ def testResult = Mock(TestResult)
+ def testClassRequest = Mock(InternalJvmTestRequest)
+ 1 * testClassRequest.getClassName() >> "org.acme.SomeFooTest"
+ 1 * testClassRequest.getMethodName() >> null
+
+ def testMethodRequest = Mock(InternalJvmTestRequest)
+ 1 * testMethodRequest.getClassName() >> "org.acme.SomeFooTest"
+ 1 * testMethodRequest.getMethodName() >> "fooMethod"
+
+ def testMethodRequest2 = Mock(InternalJvmTestRequest)
+ 1 * testMethodRequest2.getClassName() >> "org.acme.SomeBazTest"
+ 1 * testMethodRequest2.getMethodName() >> "bazMethod"
+
+
+ when:
+ evaluator.completed(testDescriptorInternal, testResult, Mock(TestCompleteEvent))
+ evaluator.evaluate();
+ then:
+ def e = thrown(TestExecutionException)
+ normaliseLineSeparators(e.message) == """No matching tests found in any candidate test task.
+ Requested tests:
+ Some Test Descriptor (Task: ':someTestTask')
+ Test class org.acme.SomeFooTest
+ Test method org.acme.SomeFooTest.fooMethod()
+ Test method org.acme.SomeBazTest.bazMethod()"""
+
+ and:
+ 1 * testExecutionRequest.getTestExecutionDescriptors()>> [defaultTestDescriptor]
+ 1 * testExecutionRequest.getInternalJvmTestRequests() >> [testClassRequest, testMethodRequest, testMethodRequest2]
+ }
+
+ def "evaluate throws exception if test failed"() {
+ given:
+ def testExecutionRequest = Mock(TestExecutionRequestAction)
+ TestExecutionResultEvaluator evaluator = new TestExecutionResultEvaluator(testExecutionRequest)
+
+ def testDescriptorInternal = Mock(TestDescriptorInternal)
+
+ testDescriptorInternal.getName() >> "someTest"
+ testDescriptorInternal.getClassName() >> "acme.SomeTestClass"
+ testDescriptorInternal.getOwnerBuildOperationId() >> 1
+
+ def testResult = Mock(TestResult)
+ 1 * testResult.getTestCount() >> 1
+ 1 * testResult.getFailedTestCount() >> 1
+
+ def testTask = Mock(TaskInternal)
+ 1 * testTask.getPath() >> ":someproject:someTestTask"
+ TaskOperationInternal taskOperationInternal = new TaskOperationInternal(1, 2, testTask)
+
+ when:
+ evaluator.beforeExecute(taskOperationInternal, Mock(OperationStartEvent))
+ evaluator.completed(testDescriptorInternal, testResult, Mock(TestCompleteEvent))
+ evaluator.evaluate()
+
+ then:
+ def e = thrown(TestExecutionException)
+ normaliseLineSeparators(e.message) == """Test failed.
+ Failed tests:
+ Test acme.SomeTestClass#someTest (Task: :someproject:someTestTask)"""
+ }
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/TestLauncherSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/TestLauncherSpec.groovy
new file mode 100644
index 0000000..0d70cc8
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/TestLauncherSpec.groovy
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling
+import org.apache.commons.io.output.TeeOutputStream
+import org.gradle.integtests.tooling.fixture.GradleBuildCancellation
+import org.gradle.integtests.tooling.fixture.ProgressEvents
+import org.gradle.integtests.tooling.fixture.TestOutputStream
+import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
+import org.gradle.test.fixtures.ConcurrentTestUtil
+import org.gradle.tooling.*
+import org.gradle.tooling.events.task.TaskFinishEvent
+import org.gradle.tooling.events.task.TaskOperationDescriptor
+import org.gradle.tooling.events.test.TestOperationDescriptor
+import org.junit.Rule
+
+abstract class TestLauncherSpec extends ToolingApiSpecification {
+ TestOutputStream stderr = new TestOutputStream()
+ TestOutputStream stdout = new TestOutputStream()
+
+ ProgressEvents events = new ProgressEvents()
+
+ @Rule
+ GradleBuildCancellation cancellationTokenSource
+
+ def setup() {
+ testCode()
+ }
+
+ void launchTests(Collection<TestOperationDescriptor> testsToLaunch) {
+ launchTests { TestLauncher testLauncher ->
+ testLauncher.withTests(testsToLaunch)
+ }
+ }
+
+ void launchTests(Closure configurationClosure) {
+ withConnection { ProjectConnection connection ->
+ launchTests(connection, null, cancellationTokenSource.token(), configurationClosure)
+ }
+ }
+
+ void launchTests(ProjectConnection connection, ResultHandler<Void> resultHandler, CancellationToken cancellationToken, Closure configurationClosure) {
+ TestLauncher testLauncher = connection.newTestLauncher()
+ .withCancellationToken(cancellationToken)
+ .addProgressListener(events)
+
+ if (toolingApi.isEmbedded()) {
+ testLauncher
+ .setStandardOutput(stdout)
+ .setStandardError(stderr)
+ } else {
+ testLauncher
+ .setStandardOutput(new TeeOutputStream(stdout, System.out))
+ .setStandardError(new TeeOutputStream(stderr, System.err))
+ }
+
+ configurationClosure.call(testLauncher)
+
+ events.clear()
+ if (resultHandler == null) {
+ testLauncher.run()
+ } else {
+ testLauncher.run(resultHandler)
+ }
+ }
+
+ def assertBuildCancelled() {
+ stdout.toString().contains("Build cancelled.")
+ true
+ }
+
+ void waitingForBuild() {
+ ConcurrentTestUtil.poll {
+ assert stdout.toString().contains("Waiting for changes to input files of tasks...");
+ }
+ stdout.reset()
+ stderr.reset()
+ }
+
+ boolean assertTaskExecuted(String taskPath) {
+ assert events.all.findAll { it instanceof TaskFinishEvent }.any { it.descriptor.taskPath == taskPath }
+ true
+ }
+
+ def assertTaskNotExecuted(String taskPath) {
+ assert !events.all.findAll { it instanceof TaskFinishEvent }.any { it.descriptor.taskPath == taskPath }
+ true
+ }
+
+ def assertTaskNotUpToDate(String taskPath) {
+ assert events.all.findAll { it instanceof TaskFinishEvent }.any { it.descriptor.taskPath == taskPath && !it.result.upToDate }
+ true
+ }
+
+ def assertTestNotExecuted(Map testInfo) {
+ assert !hasTestDescriptor(testInfo)
+ true
+ }
+
+ def assertTestExecuted(Map testInfo) {
+ assert hasTestDescriptor(testInfo)
+ true
+ }
+
+ Collection<TestOperationDescriptor> testDescriptors(List<TestOperationDescriptor> descriptors = events.tests.collect { it.descriptor }, String className, String methodName, String taskpath) {
+
+ def descriptorByClassAndMethod = descriptors.findAll { it.className == className && it.methodName == methodName }
+ if (taskpath == null) {
+ return descriptorByClassAndMethod
+ }
+
+ return descriptorByClassAndMethod.findAll {
+ def parent = it.parent
+ while (parent.parent != null) {
+ parent = parent.parent
+ if (parent instanceof TaskOperationDescriptor) {
+ return parent.taskPath == taskpath
+ }
+ }
+ false
+ }
+ }
+
+ Collection<TestOperationDescriptor> testDescriptors(List<TestOperationDescriptor> descriptors = events.tests.collect { it.descriptor }, String className, String methodName) {
+ testDescriptors(descriptors, className, methodName, null)
+ }
+
+ Collection<TestOperationDescriptor> testDescriptors(List<TestOperationDescriptor> descriptors = events.tests.collect { it.descriptor }, String className) {
+ testDescriptors(descriptors, className, null)
+ }
+
+ boolean hasTestDescriptor(testInfo) {
+ def collect = events.tests.collect { it.descriptor }
+ !testDescriptors(collect, testInfo.className, testInfo.methodName, testInfo.task).isEmpty()
+ }
+
+
+ void collectDescriptorsFromBuild() {
+ try {
+ withConnection {
+ ProjectConnection connection ->
+ connection.newBuild().forTasks('build').withArguments("--continue").addProgressListener(events).run()
+ }
+ } catch (BuildException e) {
+ }
+ }
+
+ def testCode() {
+ settingsFile << "rootProject.name = 'testproject'\n"
+ buildFile.text = simpleJavaProject()
+
+ buildFile << """
+ sourceSets {
+ moreTests {
+ java.srcDir "src/test"
+ compileClasspath = compileClasspath + sourceSets.test.compileClasspath
+ runtimeClasspath = runtimeClasspath + sourceSets.test.runtimeClasspath
+ }
+ }
+
+ task secondTest(type:Test) {
+ classpath = sourceSets.moreTests.runtimeClasspath
+ testClassesDir = sourceSets.moreTests.output.classesDir
+ }
+
+ build.dependsOn secondTest
+ """
+
+ file("src/test/java/example/MyTest.java") << """
+ package example;
+ public class MyTest {
+ @org.junit.Test public void foo() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo2() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ }
+ """
+
+ file("src/test/java/example2/MyOtherTest.java") << """
+ package example2;
+ public class MyOtherTest {
+ @org.junit.Test public void bar() throws Exception {
+ org.junit.Assert.assertEquals(2, 2);
+ }
+ }
+ """
+ file("src/test/java/example2/MyOtherTest2.java") << """
+ package example2;
+ public class MyOtherTest2 {
+ @org.junit.Test public void baz() throws Exception {
+ org.junit.Assert.assertEquals(2, 2);
+ }
+ }
+ """
+ }
+
+
+ def changeTestSource() {
+ // adding two more test methods
+ file("src/test/java/example/MyTest.java").text = """
+ package example;
+ public class MyTest {
+ @org.junit.Test public void foo() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo2() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo3() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo4() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ }
+ """
+ }
+
+ def withFailingTest() {
+ file("src/test/java/example/MyFailingTest.java").text = """
+ package example;
+ public class MyFailingTest {
+ @org.junit.Test public void fail() throws Exception {
+ org.junit.Assert.assertEquals(1, 2);
+ }
+
+ @org.junit.Test public void fail2() throws Exception {
+ org.junit.Assert.assertEquals(1, 2);
+ }
+ }"""
+
+ }
+
+ def simpleJavaProject() {
+ """
+ allprojects{
+ apply plugin: 'java'
+ repositories { mavenCentral() }
+ dependencies { testCompile 'junit:junit:4.12' }
+ }
+ """
+ }
+
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/ToolingApiUnsupportedVersionIntegrationTest.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/ToolingApiUnsupportedVersionIntegrationTest.groovy
index 9b52144..14214a7 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/ToolingApiUnsupportedVersionIntegrationTest.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/ToolingApiUnsupportedVersionIntegrationTest.groovy
@@ -20,6 +20,7 @@ import org.gradle.integtests.fixtures.executer.GradleDistribution
import org.gradle.integtests.fixtures.versions.ReleasedVersionDistributions
import org.gradle.integtests.tooling.fixture.ToolingApi
import org.gradle.integtests.tooling.r18.NullAction
+import org.gradle.tooling.ProjectConnection
import org.gradle.tooling.UnsupportedVersionException
import org.gradle.tooling.model.GradleProject
import org.gradle.util.GradleVersion
@@ -35,28 +36,37 @@ class ToolingApiUnsupportedVersionIntegrationTest extends AbstractIntegrationSpe
def "tooling api reports an error when requesting a model using a gradle version that does not implement the tooling api"() {
when:
- toolingApi.withConnection { connection -> connection.getModel(GradleProject.class) }
+ toolingApi.withConnection { ProjectConnection connection -> connection.getModel(GradleProject.class) }
then:
UnsupportedVersionException e = thrown()
- e.message == "The specified Gradle distribution '${distroZip}' does not implement the tooling API. Support for the tooling API was added in Gradle 1.0-milestone-3 and is available in all later versions."
+ e.message == "The version of Gradle you are using (Gradle distribution '${distroZip}') does not support the ModelBuilder API. Support for this is available in Gradle 1.0-milestone-8 and all later versions."
}
def "tooling api reports an error when running a build using a gradle version does not implement the tooling api"() {
when:
- toolingApi.withConnection { connection -> connection.newBuild().run() }
+ toolingApi.withConnection { ProjectConnection connection -> connection.newBuild().run() }
then:
UnsupportedVersionException e = thrown()
- e.message == "The specified Gradle distribution '${distroZip}' does not implement the tooling API. Support for the tooling API was added in Gradle 1.0-milestone-3 and is available in all later versions."
+ e.message == "The version of Gradle you are using (Gradle distribution '${distroZip}') does not support the BuildLauncher API. Support for this is available in Gradle 1.0-milestone-8 and all later versions."
}
def "tooling api reports an error when running a build action using a gradle version does not implement the tooling api"() {
when:
- toolingApi.withConnection { connection -> connection.action(new NullAction()).run() }
+ toolingApi.withConnection { ProjectConnection connection -> connection.action(new NullAction()).run() }
then:
UnsupportedVersionException e = thrown()
- e.message == "The specified Gradle distribution '${distroZip}' does not implement the tooling API. Support for the tooling API was added in Gradle 1.0-milestone-3 and is available in all later versions."
+ e.message == "The version of Gradle you are using (Gradle distribution '${distroZip}') does not support the BuildActionExecuter API. Support for this is available in Gradle 1.8 and all later versions."
+ }
+
+ def "tooling api reports an error when running tests using a gradle version does not implement the tooling api"() {
+ when:
+ toolingApi.withConnection { ProjectConnection connection -> connection.newTestLauncher().withJvmTestClasses("class").run() }
+
+ then:
+ UnsupportedVersionException e = thrown()
+ e.message == "The version of Gradle you are using (Gradle distribution '${distroZip}') does not support the TestLauncher API. Support for this is available in Gradle 2.6 and all later versions."
}
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ContinuousBuildToolingApiSpecification.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ContinuousBuildToolingApiSpecification.groovy
index d4eb7a4..579b8a6 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ContinuousBuildToolingApiSpecification.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ContinuousBuildToolingApiSpecification.groovy
@@ -20,14 +20,15 @@ import groovy.transform.stc.ClosureParams
import groovy.transform.stc.SimpleType
import org.apache.commons.io.output.TeeOutputStream
import org.gradle.integtests.fixtures.executer.*
+import org.gradle.test.fixtures.ConcurrentTestUtil
import org.gradle.test.fixtures.file.TestFile
import org.gradle.tooling.BuildLauncher
-import org.gradle.tooling.GradleConnector
+import org.gradle.tooling.CancellationToken
import org.gradle.tooling.ProjectConnection
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
+import org.junit.Rule
import spock.lang.Timeout
-import spock.util.concurrent.PollingConditions
@Timeout(180)
@Requires(TestPrecondition.JDK7_OR_LATER)
@@ -44,8 +45,9 @@ abstract class ContinuousBuildToolingApiSpecification extends ToolingApiSpecific
ExecutionFailure failure
int buildTimeout = 10
- def cancellationTokenSource = GradleConnector.newCancellationTokenSource()
+ @Rule
+ GradleBuildCancellation cancellationTokenSource
TestResultHandler buildResult
TestFile sourceDir
@@ -70,9 +72,9 @@ abstract class ContinuousBuildToolingApiSpecification extends ToolingApiSpecific
public <T> T runBuild(List<String> tasks = ["build"], Closure<T> underBuild) {
if (projectConnection) {
- cancellationTokenSource = GradleConnector.newCancellationTokenSource()
buildResult = new TestResultHandler()
- try {
+
+ cancellationTokenSource.withCancellation { CancellationToken token ->
// this is here to ensure that the lastModified() timestamps actually change in between builds.
// if the build is very fast, the timestamp of the file will not change and the JDK file watch service won't see the change.
def initScript = file("init.gradle")
@@ -89,7 +91,7 @@ abstract class ContinuousBuildToolingApiSpecification extends ToolingApiSpecific
BuildLauncher launcher = projectConnection.newBuild()
.withArguments("--continuous", "-I", initScript.absolutePath)
.forTasks(tasks as String[])
- .withCancellationToken(cancellationTokenSource.token())
+ .withCancellationToken(token)
if (toolingApi.isEmbedded()) {
launcher
@@ -108,8 +110,6 @@ abstract class ContinuousBuildToolingApiSpecification extends ToolingApiSpecific
cancellationTokenSource.cancel()
buildResult.finished(buildTimeout)
t
- } finally {
- cancellationTokenSource.cancel()
}
} else {
withConnection { runBuild(tasks, underBuild) }
@@ -139,8 +139,9 @@ abstract class ContinuousBuildToolingApiSpecification extends ToolingApiSpecific
}
private void waitForBuild() {
- new PollingConditions(initialDelay: 0.5).within(buildTimeout) {
- assert stdout.toString().contains(WAITING_MESSAGE)
+ ConcurrentTestUtil.poll(buildTimeout, 0.5) {
+ def out = stdout.toString()
+ assert out.contains(WAITING_MESSAGE)
}
def out = stdout.toString()
@@ -180,4 +181,5 @@ abstract class ContinuousBuildToolingApiSpecification extends ToolingApiSpecific
cancellationTokenSource.cancel()
true
}
+
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/GradleBuildCancellation.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/GradleBuildCancellation.groovy
new file mode 100644
index 0000000..671c8f4
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/GradleBuildCancellation.groovy
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.fixture
+
+import groovy.transform.stc.ClosureParams
+import groovy.transform.stc.SimpleType
+import org.gradle.tooling.CancellationToken
+import org.gradle.tooling.CancellationTokenSource
+import org.gradle.tooling.GradleConnector
+import org.gradle.tooling.ProjectConnection
+import org.junit.rules.ExternalResource
+
+class GradleBuildCancellation extends ExternalResource implements CancellationTokenSource {
+ CancellationTokenSource cancellationTokenSource
+
+ protected void before() throws Throwable {
+ cancellationTokenSource = GradleConnector.newCancellationTokenSource()
+ }
+
+ protected void after() {
+ cancel()
+ }
+
+ @Override
+ void cancel() {
+ cancellationTokenSource.cancel()
+ }
+
+ @Override
+ CancellationToken token() {
+ return cancellationTokenSource.token()
+ }
+
+ public <T> T withCancellation(@DelegatesTo(ProjectConnection) @ClosureParams(value = SimpleType, options = ["org.gradle.tooling.CancellationToken"]) Closure<T> cl) {
+ try {
+ cancellationTokenSource = GradleConnector.newCancellationTokenSource()
+ return cl.call(token())
+ } finally {
+ cancel();
+ }
+ }
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ProgressEvents.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ProgressEvents.groovy
new file mode 100644
index 0000000..54ea052
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ProgressEvents.groovy
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.fixture
+
+import org.gradle.tooling.Failure
+import org.gradle.tooling.events.*
+import org.gradle.tooling.events.task.TaskOperationDescriptor
+import org.gradle.tooling.events.test.TestOperationDescriptor
+
+class ProgressEvents implements ProgressListener {
+ private final List<ProgressEvent> events = []
+ private boolean dirty
+ private final Map<String, Operation> byDisplayName = new LinkedHashMap<>()
+ private final List<Operation> operations= new ArrayList<Operation>()
+
+
+ void clear() {
+ events.clear()
+ byDisplayName.clear()
+ operations.clear()
+ }
+
+ /**
+ * Asserts that the events form zero or more well-formed trees of operations.
+ */
+ void assertHasZeroOrMoreTrees() {
+ if (dirty) {
+ Set<OperationDescriptor> seen = []
+ Map<OperationDescriptor, StartEvent> running = [:]
+ for (ProgressEvent event : events) {
+ assert event.displayName == event.toString()
+
+ if (event instanceof StartEvent) {
+ def descriptor = event.descriptor
+ assert seen.add(descriptor)
+ assert !running.containsKey(descriptor)
+ running[descriptor] = event
+
+ // Display name should be mostly unique
+ // ignore this check for TestOperationDescriptors as they can be
+ // currently not unique when coming from different test tasks
+ if(!(descriptor instanceof TestOperationDescriptor)){
+ assert !byDisplayName.containsKey(descriptor.displayName)
+ }
+
+ Operation operation = new Operation(descriptor)
+ operations.add(operation)
+ byDisplayName[descriptor.displayName] = operation
+
+ // parent should also be running
+ assert descriptor.parent == null || running.containsKey(descriptor.parent)
+
+ assert descriptor.displayName == descriptor.toString()
+ assert event.displayName == "${descriptor.displayName} started" as String
+ } else if (event instanceof FinishEvent) {
+ def descriptor = event.descriptor
+ def startEvent = running.remove(descriptor)
+ assert startEvent != null
+
+ // parent should still be running
+ assert descriptor.parent == null || running.containsKey(descriptor.parent)
+
+ def storedOperation = operations.find { it.descriptor == descriptor }
+ storedOperation.result = event.result
+
+ assert event.displayName.matches("\\Q${descriptor.displayName}\\E \\w+")
+ assert startEvent.eventTime <= event.eventTime
+
+ assert event.result.startTime == startEvent.eventTime
+ assert event.result.endTime == event.eventTime
+ } else {
+ throw new AssertionError("Unexpected type of progress event received: ${event.getClass()}")
+ }
+ }
+ assert running.size() == 0: "Not all operations completed: ${running.values()}, events: ${events}"
+
+ dirty = false
+ }
+ }
+
+ /**
+ * Asserts that the events form exactly one well-formed trees of operations.
+ */
+ void assertHasSingleTree() {
+ assertHasZeroOrMoreTrees()
+ assert !operations.empty
+ assert operations[0].descriptor.parent == null
+
+ operations.tail().each { assert it.descriptor.parent != null }
+ }
+
+ /**
+ * Asserts that the events form a typical tree of operations for a build.
+ */
+ void assertIsABuild() {
+ assertHasSingleTree()
+
+ def root = operations[0]
+ assert root.buildOperation
+ assert root.descriptor.displayName == 'Run build'
+ }
+
+ boolean isEmpty() {
+ assertHasZeroOrMoreTrees()
+ return events.empty
+ }
+
+ /**
+ * Returns all events, in the order received.
+ */
+ List<ProgressEvent> getAll() {
+ assertHasZeroOrMoreTrees()
+ return events
+ }
+
+ /**
+ * Returns all operations, in the order started.
+ */
+ List<Operation> getOperations() {
+ assertHasZeroOrMoreTrees()
+ return operations
+ }
+
+ /**
+ * Returns all generic build operations, in the order started.
+ */
+ List<Operation> getBuildOperations() {
+ assertHasZeroOrMoreTrees()
+ return operations.findAll { it.buildOperation } as List
+ }
+
+ /**
+ * Returns all tests, in the order started.
+ */
+ List<Operation> getTests() {
+ assertHasZeroOrMoreTrees()
+ return operations.findAll { it.test } as List
+ }
+
+ /**
+ * Returns all tasks, in the order started.
+ */
+ List<Operation> getTasks() {
+ assertHasZeroOrMoreTrees()
+ return operations.findAll { it.task } as List
+ }
+
+ /**
+ * Returns all successful operations, in the order started.
+ */
+ List<Operation> getSuccessful() {
+ assertHasZeroOrMoreTrees()
+ return operations.findAll { it.successful } as List
+ }
+
+ /**
+ * Returns all failed operations, in the order started.
+ */
+ List<Operation> getFailed() {
+ assertHasZeroOrMoreTrees()
+ return operations.findAll { it.failed } as List
+ }
+
+ /**
+ * Returns the operation with the given display name. Fails whe not exactly one such operation.
+ */
+ Operation operation(String displayName) {
+ assertHasZeroOrMoreTrees()
+ assert byDisplayName.containsKey(displayName)
+ return byDisplayName[displayName]
+ }
+
+ @Override
+ void statusChanged(ProgressEvent event) {
+ dirty = true
+ byDisplayName.clear()
+ operations.clear()
+ events << event
+ }
+
+ static class Operation {
+ final OperationDescriptor descriptor
+ OperationResult result
+
+ private Operation(OperationDescriptor descriptor) {
+ this.descriptor = descriptor
+ }
+
+ @Override
+ String toString() {
+ return descriptor.displayName
+ }
+
+ boolean isTest() {
+ return descriptor instanceof TestOperationDescriptor
+ }
+
+ boolean isTask() {
+ return descriptor instanceof TaskOperationDescriptor
+ }
+
+ boolean isBuildOperation() {
+ return !test && !task
+ }
+
+ boolean isSuccessful() {
+ return result instanceof SuccessResult
+ }
+
+ boolean isFailed() {
+ return result instanceof FailureResult
+ }
+
+ List<Failure> getFailures() {
+ assert result instanceof FailureResult
+ return result.failures
+ }
+ }
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/TextUtil.java b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/TextUtil.java
index 8ec51b7..cf8d51c 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/TextUtil.java
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/TextUtil.java
@@ -16,12 +16,35 @@
package org.gradle.integtests.tooling.fixture;
+import java.io.File;
+import java.util.regex.Pattern;
+
public class TextUtil {
/**
* TODO - hack to avoid classloading issues. We should use org.gradle.util.TextUtil
+ *
+ * Currently we can't use it reliably because it causes CNF issues with cross version integration tests running against tooling api < 1.3.
*/
public static String escapeString(Object obj) {
return obj.toString().replaceAll("\\\\", "\\\\\\\\");
}
+
+ public static String normaliseFileSeparators(String path) {
+ return path.replaceAll(Pattern.quote(File.separator), "/");
+ }
+
+ /**
+ * Converts all line separators in the specified string to a single new line character.
+ */
+ public static String normaliseLineSeparators(String str) {
+ return str == null ? null : convertLineSeparators(str, "\n");
+ }
+
+ /**
+ * Converts all line separators in the specified string to the specified line separator.
+ */
+ public static String convertLineSeparators(String str, String sep) {
+ return str == null ? null : str.replaceAll("\r\n|\r|\n", sep);
+ }
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApi.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApi.groovy
index 6b56ddc..cb80432 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApi.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApi.groovy
@@ -42,7 +42,6 @@ class ToolingApi implements TestRule {
private TestFile gradleUserHomeDir
private TestFile daemonBaseDir
private boolean useSeparateDaemonBaseDir
- private boolean inProcess
private boolean requiresDaemon
private boolean requireIsolatedDaemons
@@ -56,7 +55,6 @@ class ToolingApi implements TestRule {
this.gradleUserHomeDir = context.gradleUserHomeDir
this.daemonBaseDir = context.daemonBaseDir
this.requiresDaemon = !GradleContextualExecuter.embedded
- this.inProcess = GradleContextualExecuter.embedded
this.testWorkDirProvider = testWorkDirProvider
}
@@ -64,7 +62,11 @@ class ToolingApi implements TestRule {
* Specifies that the test use its own Gradle user home dir and daemon registry.
*/
void requireIsolatedUserHome() {
- gradleUserHomeDir = testWorkDirProvider.testDirectory.file("user-home-dir")
+ withUserHome(testWorkDirProvider.testDirectory.file("user-home-dir"))
+ }
+
+ void withUserHome(TestFile userHomeDir) {
+ gradleUserHomeDir = userHomeDir
useSeparateDaemonBaseDir = false
}
@@ -152,23 +154,26 @@ class ToolingApi implements TestRule {
if (connector.metaClass.hasProperty(connector, 'verboseLogging')) {
connector.verboseLogging = verboseLogging
}
- if (isEmbedded()) {
- println("Using embedded tooling API provider from ${GradleVersion.current().version} to classpath (${dist.version.version})")
+ if (useClasspathImplementation) {
connector.useClasspathDistribution()
- connector.embedded(true)
} else {
- println("Using daemon tooling API provider from ${GradleVersion.current().version} to ${dist.version.version}")
connector.useInstallation(dist.gradleHomeDir.absoluteFile)
- connector.embedded(false)
}
+ connector.embedded(embedded)
connectorConfigurers.each {
connector.with(it)
}
return connector
}
+ boolean isUseClasspathImplementation() {
+ // Use classpath implementation only when running tests in embedded mode and for the current Gradle version
+ return GradleContextualExecuter.embedded && GradleVersion.current() == dist.version
+ }
+
boolean isEmbedded() {
- !requiresDaemon && GradleVersion.current() == dist.version
+ // Use in-process build when running tests in embedded mode and daemon is not required
+ return GradleContextualExecuter.embedded && !requiresDaemon
}
@Override
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApiCompatibilitySuiteRunner.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApiCompatibilitySuiteRunner.groovy
index 5d40492..8e84ce5 100755
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApiCompatibilitySuiteRunner.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/fixture/ToolingApiCompatibilitySuiteRunner.groovy
@@ -142,6 +142,7 @@ class ToolingApiCompatibilitySuiteRunner extends AbstractCompatibilityTestRunner
sharedClassLoader.allowClass(SetSystemProperties)
sharedClassLoader.allowClass(RedirectStdOutAndErr)
sharedClassLoader.allowPackage('org.gradle.integtests.fixtures')
+ sharedClassLoader.allowPackage('org.gradle.play.integtest.fixtures')
sharedClassLoader.allowPackage('org.gradle.test.fixtures')
sharedClassLoader.allowPackage('org.gradle.launcher.daemon.testing')
sharedClassLoader.allowClass(OperatingSystem)
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiEclipseModelCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiEclipseModelCrossVersionSpec.groovy
index 4305d05..cff846c 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiEclipseModelCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiEclipseModelCrossVersionSpec.groovy
@@ -23,7 +23,7 @@ import org.gradle.tooling.model.eclipse.HierarchicalEclipseProject
class ToolingApiEclipseModelCrossVersionSpec extends ToolingApiSpecification {
def "can build the eclipse model for a java project"() {
-
+
projectDir.file('build.gradle').text = '''
apply plugin: 'java'
description = 'this is a project'
@@ -91,7 +91,7 @@ gradle.taskGraph.beforeTask { throw new RuntimeException() }
}
def "can build the eclipse source directories for a java project"() {
-
+
projectDir.file('build.gradle').text = "apply plugin: 'java'"
projectDir.create {
@@ -141,7 +141,7 @@ gradle.taskGraph.beforeTask { throw new RuntimeException() }
}
def "can build the eclipse external dependencies for a java project"() {
-
+
projectDir.file('settings.gradle').text = '''
include "a"
rootProject.name = 'root'
@@ -170,7 +170,7 @@ dependencies {
}
def "can build the minimal Eclipse model for a java project with the idea plugin applied"() {
-
+
projectDir.file('build.gradle').text = '''
apply plugin: 'java'
apply plugin: 'idea'
@@ -188,7 +188,7 @@ dependencies {
}
def "can build the eclipse project dependencies for a java project"() {
-
+
projectDir.file('settings.gradle').text = '''
include "a", "a:b"
rootProject.name = 'root'
@@ -229,7 +229,7 @@ project(':a') {
}
def "can build project dependencies with targetProject references for complex scenarios"() {
-
+
projectDir.file('settings.gradle').text = '''
include "c", "a", "a:b"
rootProject.name = 'root'
@@ -268,7 +268,7 @@ project(':c') {
}
def "can build the eclipse project hierarchy for a multi-project build"() {
-
+
projectDir.file('settings.gradle').text = '''
include "child1", "child2", "child1:grandChild1"
rootProject.name = 'root'
@@ -314,4 +314,27 @@ project(':c') {
child.parent.name == 'root'
child.children.size() == 1
}
+
+ def "respects customized eclipse project name"() {
+ settingsFile.text = "include ':foo', ':bar'"
+ buildFile.text = """
+allprojects {
+ apply plugin:'java'
+ apply plugin:'eclipse'
+}
+
+configure(project(':bar')) {
+ eclipse {
+ project {
+ name = "customized-bar"
+ }
+ }
+}
+"""
+ when:
+ HierarchicalEclipseProject rootProject = withConnection { connection -> connection.getModel(HierarchicalEclipseProject.class) }
+ then:
+ rootProject.children.any { it.name == 'foo'}
+ rootProject.children.any { it.name == 'customized-bar'}
+ }
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiLoggingCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiLoggingCrossVersionSpec.groovy
index 1081ede..a187411 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiLoggingCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m3/ToolingApiLoggingCrossVersionSpec.groovy
@@ -50,7 +50,6 @@ task log << {
def build = connection.newBuild()
build.standardOutput = output
build.forTasks("log")
- build.withArguments("-d", "-s")
build.run(resultHandler)
server.waitFor()
ConcurrentTestUtil.poll {
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/JavaConfigurabilityCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/JavaConfigurabilityCrossVersionSpec.groovy
index f8e98a6..20b0944 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/JavaConfigurabilityCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/JavaConfigurabilityCrossVersionSpec.groovy
@@ -40,6 +40,7 @@ class JavaConfigurabilityCrossVersionSpec extends ToolingApiSpecification {
}
then:
+ env.java.javaHome
env.java.jvmArguments.contains "-Xms13m"
env.java.jvmArguments.contains "-Xmx333m"
}
@@ -55,7 +56,8 @@ class JavaConfigurabilityCrossVersionSpec extends ToolingApiSpecification {
then:
env.java.javaHome
- !env.java.jvmArguments.empty
+ env.java.jvmArguments.contains("-Xmx1024m")
+ env.java.jvmArguments.contains("-XX:+HeapDumpOnOutOfMemoryError")
}
def "tooling api provided jvm args take precedence over gradle.properties"() {
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/ToolingApiLoggingCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/ToolingApiLoggingCrossVersionSpec.groovy
index efcddcf..dca7ab9 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/ToolingApiLoggingCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m8/ToolingApiLoggingCrossVersionSpec.groovy
@@ -113,7 +113,6 @@ project.logger.debug("debug logging");
private ExecutionResult runUsingCommandLine() {
targetDist.executer(temporaryFolder)
.withArgument("--no-daemon") //suppress daemon usage suggestions
- .withGradleOpts("-Dorg.gradle.daemon.disable-starting-message=true")
.run()
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/GradlePropertiesToolingApiCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/GradlePropertiesToolingApiCrossVersionSpec.groovy
index d47d69c..8e23e1c 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/GradlePropertiesToolingApiCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/GradlePropertiesToolingApiCrossVersionSpec.groovy
@@ -21,7 +21,7 @@ import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.TextUtil
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.tooling.model.build.BuildEnvironment
-import spock.lang.IgnoreIf
+import org.junit.Assume
@TargetGradleVersion('>=1.0-milestone-9')
class GradlePropertiesToolingApiCrossVersionSpec extends ToolingApiSpecification {
@@ -49,10 +49,10 @@ assert System.getProperty('some-prop') == 'some-value'
env.java.jvmArguments.contains('-Xmx16m')
}
- @IgnoreIf({ AvailableJavaHomes.differentJdk == null })
def "tooling api honours java home specified in gradle.properties"() {
- File javaHome = AvailableJavaHomes.differentJdk.javaHome
- String javaHomePath = TextUtil.escapeString(javaHome.canonicalPath)
+ def jdk = AvailableJavaHomes.getAvailableJdk { targetDist.isToolingApiTargetJvmSupported(it.javaVersion) }
+ Assume.assumeNotNull(jdk)
+ String javaHomePath = TextUtil.escapeString(jdk.javaHome.canonicalPath)
file('build.gradle') << "assert new File(System.getProperty('java.home')).canonicalPath.startsWith('$javaHomePath')"
@@ -65,6 +65,6 @@ assert System.getProperty('some-prop') == 'some-value'
}
then:
- env.java.javaHome == javaHome
+ env.java.javaHome == jdk.javaHome
}
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy
index 933a769..d77800a 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/m9/M9JavaConfigurabilityCrossVersionSpec.groovy
@@ -17,17 +17,12 @@
package org.gradle.integtests.tooling.m9
import org.gradle.integtests.fixtures.AvailableJavaHomes
-import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.TextUtil
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
-import org.gradle.tooling.GradleConnectionException
import org.gradle.tooling.model.GradleProject
import org.gradle.tooling.model.build.BuildEnvironment
-import spock.lang.IgnoreIf
-import spock.lang.Issue
-import spock.lang.Timeout
+import org.junit.Assume
- at TargetGradleVersion('>=1.0-milestone-9')
class M9JavaConfigurabilityCrossVersionSpec extends ToolingApiSpecification {
def setup() {
@@ -36,34 +31,6 @@ class M9JavaConfigurabilityCrossVersionSpec extends ToolingApiSpecification {
toolingApi.requireDaemons()
}
- def "uses sensible java defaults if nulls configured"() {
- when:
- BuildEnvironment env = withConnection {
- def model = it.model(BuildEnvironment.class)
- model
- .setJvmArguments(null)
- .get()
- }
-
- then:
- env.java.javaHome
- }
-
- @Issue("GRADLE-1799")
- @Timeout(25)
- def "promptly discovers when java is not a valid installation"() {
- def dummyJdk = file("wrong jdk location").createDir()
-
- when:
- withConnection {
- it.newBuild().setJavaHome(dummyJdk).run()
- }
-
- then:
- GradleConnectionException ex = thrown()
- ex.cause.message.contains "wrong jdk location"
- }
-
def "uses defaults when a variant of empty jvm args requested"() {
when:
def env = withConnection {
@@ -84,27 +51,30 @@ class M9JavaConfigurabilityCrossVersionSpec extends ToolingApiSpecification {
env.java.jvmArguments == env3.java.jvmArguments
}
- @IgnoreIf({ AvailableJavaHomes.differentJdk == null })
def "customized java home is reflected in the java.home and the build model"() {
+ def jdk = AvailableJavaHomes.getAvailableJdk { targetDist.isToolingApiTargetJvmSupported(it.javaVersion) }
+ Assume.assumeNotNull(jdk)
+
given:
file('build.gradle') << "project.description = new File(System.getProperty('java.home')).canonicalPath"
when:
- File javaHome = AvailableJavaHomes.differentJdk.javaHome
+
BuildEnvironment env
GradleProject project
withConnection {
- env = it.model(BuildEnvironment.class).setJavaHome(javaHome).get()
- project = it.model(GradleProject.class).setJavaHome(javaHome).get()
+ env = it.model(BuildEnvironment.class).setJavaHome(jdk.javaHome).get()
+ project = it.model(GradleProject.class).setJavaHome(jdk.javaHome).get()
}
then:
project.description.startsWith(env.java.javaHome.canonicalPath)
}
- @IgnoreIf({ AvailableJavaHomes.differentJdk == null })
def "tooling api provided java home takes precedence over gradle.properties"() {
- File javaHome = AvailableJavaHomes.differentJdk.javaHome
+ def jdk = AvailableJavaHomes.getAvailableJdk { targetDist.isToolingApiTargetJvmSupported(it.javaVersion) }
+ Assume.assumeNotNull(jdk)
+ File javaHome = jdk.javaHome
String javaHomePath = TextUtil.escapeString(javaHome.canonicalPath)
File otherJava = new File(System.getProperty("java.home"))
String otherJavaPath = TextUtil.escapeString(otherJava.canonicalPath)
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r10rc1/PassingCommandLineArgumentsCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r10rc1/PassingCommandLineArgumentsCrossVersionSpec.groovy
index cf428e7..dc7c02a 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r10rc1/PassingCommandLineArgumentsCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r10rc1/PassingCommandLineArgumentsCrossVersionSpec.groovy
@@ -22,6 +22,7 @@ import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.tooling.ProjectConnection
import org.gradle.tooling.exceptions.UnsupportedBuildArgumentException
+import org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException
import org.gradle.tooling.model.GradleProject
@TargetGradleVersion(">=1.0")
@@ -114,13 +115,34 @@ class PassingCommandLineArgumentsCrossVersionSpec extends ToolingApiSpecificatio
ex.message.contains('--foreground')
}
+ @TargetGradleVersion(">=1.0-milestone-8 <1.0")
+ def "gives decent feedback when build arguments not supported"() {
+ when:
+ withConnection { ProjectConnection it ->
+ it.newBuild().withArguments('--foreground').run()
+ }
+
+ then:
+ UnsupportedOperationConfigurationException ex = thrown()
+ ex.message.contains("The version of Gradle you are using (${targetDist.version.version}) does not support the BuildLauncher API withArguments() configuration option. Support for this is available in Gradle 1.0 and all later versions.")
+
+ when:
+ withConnection { ProjectConnection it ->
+ it.model(GradleProject).withArguments('--foreground').get()
+ }
+
+ then:
+ UnsupportedOperationConfigurationException ex2 = thrown()
+ ex2.message.contains("The version of Gradle you are using (${targetDist.version.version}) does not support the ModelBuilder API withArguments() configuration option. Support for this is available in Gradle 1.0 and all later versions.")
+ }
+
def "can overwrite project dir via build arguments"() {
given:
file('otherDir').createDir()
file('build.gradle') << "assert projectDir.name.endsWith('otherDir')"
when:
- withConnection {
+ withConnection {
it.newBuild().withArguments('-p', 'otherDir').run()
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/ToolingApiDeprecationsCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/ToolingApiDeprecationsCrossVersionSpec.groovy
deleted file mode 100644
index 94dd8cf..0000000
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/ToolingApiDeprecationsCrossVersionSpec.groovy
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.integtests.tooling.r112
-
-import org.gradle.integtests.tooling.fixture.TargetGradleVersion
-import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
-import org.gradle.integtests.tooling.fixture.ToolingApiVersion
-import org.gradle.tooling.GradleConnectionException
-import org.gradle.tooling.ProjectConnection
-import org.gradle.tooling.UnsupportedVersionException
-import org.gradle.tooling.model.eclipse.EclipseProject
-
-class ToolingApiDeprecationsCrossVersionSpec extends ToolingApiSpecification {
- def setup() {
- file("build.gradle") << """
-task noop << {
- println "noop"
-}
-"""
- }
-
- @ToolingApiVersion(">=1.12")
- @TargetGradleVersion("<1.0-milestone-8")
- def "build rejected for pre 1.0m8 providers"() {
- when:
- def output = new ByteArrayOutputStream()
- withConnection { ProjectConnection connection ->
- def build = connection.newBuild()
- build.standardOutput = output
- build.forTasks("noop")
- build.run()
- }
-
- then:
- UnsupportedVersionException e = thrown()
- e.message == "Support for Gradle version ${targetDist.version.version} was removed in tooling API version 2.0. You should upgrade your Gradle build to use Gradle 1.0-milestone-8 or later."
- }
-
- @ToolingApiVersion(">=1.12")
- @TargetGradleVersion("<1.0-milestone-8")
- def "model retrieving fails for pre 1.0m8 providers"() {
- when:
- def output = new ByteArrayOutputStream()
- withConnection { ProjectConnection connection ->
- def modelBuilder = connection.model(EclipseProject)
- modelBuilder.standardOutput = output
- modelBuilder.get()
- }
-
- then:
- UnsupportedVersionException e = thrown()
- e.message == "Support for Gradle version ${targetDist.version.version} was removed in tooling API version 2.0. You should upgrade your Gradle build to use Gradle 1.0-milestone-8 or later."
- }
-
- @ToolingApiVersion("<1.2")
- @TargetGradleVersion(">=1.12")
- def "provider rejects build request from a tooling API older than 1.2"() {
- when:
- def output = new ByteArrayOutputStream()
- withConnection { ProjectConnection connection ->
- def build = connection.newBuild()
- build.standardOutput = output
- build.forTasks("noop")
- build.run()
- }
-
- then:
- GradleConnectionException e = thrown()
- e.cause.message.contains('Support for clients using a tooling API version older than 1.2 was removed in Gradle 2.0. You should upgrade your tooling API client to version 1.2 or later.')
- }
-
- @ToolingApiVersion("<1.2")
- @TargetGradleVersion(">=1.12")
- def "provider rejects model request from a tooling API older than 1.2"() {
- when:
- def output = new ByteArrayOutputStream()
- withConnection { ProjectConnection connection ->
- def modelBuilder = connection.model(EclipseProject)
- modelBuilder.standardOutput = output
- modelBuilder.get()
- }
-
- then:
- GradleConnectionException e = thrown()
- e.cause.message.contains('Support for clients using a tooling API version older than 1.2 was removed in Gradle 2.0. You should upgrade your tooling API client to version 1.2 or later.')
- }
-}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/ToolingApiUnsupportedVersionCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/ToolingApiUnsupportedVersionCrossVersionSpec.groovy
new file mode 100644
index 0000000..2424ea5
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/ToolingApiUnsupportedVersionCrossVersionSpec.groovy
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.r112
+
+import org.gradle.integtests.tooling.fixture.TargetGradleVersion
+import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
+import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.integtests.tooling.r18.NullAction
+import org.gradle.tooling.GradleConnectionException
+import org.gradle.tooling.ProjectConnection
+import org.gradle.tooling.UnsupportedVersionException
+import org.gradle.tooling.model.eclipse.EclipseProject
+
+class ToolingApiUnsupportedVersionCrossVersionSpec extends ToolingApiSpecification {
+ def setup() {
+ file("build.gradle") << """
+task noop << {
+ println "noop"
+}
+"""
+ }
+
+ @ToolingApiVersion("current")
+ @TargetGradleVersion("<1.0-milestone-8")
+ def "build fails for pre 1.0m8 providers"() {
+ when:
+ withConnection { ProjectConnection connection ->
+ connection.newBuild().run()
+ }
+
+ then:
+ UnsupportedVersionException e = thrown()
+ e.message == "Support for Gradle version ${targetDist.version.version} was removed in tooling API version 2.0. You should upgrade your Gradle build to use Gradle 1.0-milestone-8 or later."
+ }
+
+ @ToolingApiVersion("current")
+ @TargetGradleVersion("<1.0-milestone-8")
+ def "model retrieving fails for pre 1.0m8 providers"() {
+ when:
+ withConnection { ProjectConnection connection ->
+ connection.model(EclipseProject).get()
+ }
+
+ then:
+ UnsupportedVersionException e = thrown()
+ e.message == "Support for Gradle version ${targetDist.version.version} was removed in tooling API version 2.0. You should upgrade your Gradle build to use Gradle 1.0-milestone-8 or later."
+ }
+
+ @ToolingApiVersion("current")
+ @TargetGradleVersion("<1.0-milestone-8")
+ def "build action fails for pre 1.0m8 providers"() {
+ when:
+ withConnection { ProjectConnection connection ->
+ connection.action(new NullAction()).run()
+ }
+
+ then:
+ UnsupportedVersionException e = thrown()
+ e.message == "The version of Gradle you are using (${targetDist.version.version}) does not support the BuildActionExecuter API. Support for this is available in Gradle 1.8 and all later versions."
+ }
+
+ @ToolingApiVersion("current")
+ @TargetGradleVersion("<1.0-milestone-8")
+ def "test execution fails for pre 1.0m8 providers"() {
+ when:
+ withConnection { ProjectConnection connection ->
+ connection.newTestLauncher().withJvmTestClasses("class").run()
+ }
+
+ then:
+ UnsupportedVersionException e = thrown()
+ e.message == "The version of Gradle you are using (${targetDist.version.version}) does not support the TestLauncher API. Support for this is available in Gradle 2.6 and all later versions."
+ }
+
+ @ToolingApiVersion("<1.2")
+ @TargetGradleVersion(">=1.12")
+ def "provider rejects build request from a tooling API older than 1.2"() {
+ when:
+ def output = new ByteArrayOutputStream()
+ withConnection { ProjectConnection connection ->
+ def build = connection.newBuild()
+ build.standardOutput = output
+ build.forTasks("noop")
+ build.run()
+ }
+
+ then:
+ GradleConnectionException e = thrown()
+ e.cause.message.contains('Support for clients using a tooling API version older than 1.2 was removed in Gradle 2.0. You should upgrade your tooling API client to version 1.2 or later.')
+ }
+
+ @ToolingApiVersion("<1.2")
+ @TargetGradleVersion(">=1.12")
+ def "provider rejects model request from a tooling API older than 1.2"() {
+ when:
+ def output = new ByteArrayOutputStream()
+ withConnection { ProjectConnection connection ->
+ def modelBuilder = connection.model(EclipseProject)
+ modelBuilder.standardOutput = output
+ modelBuilder.get()
+ }
+
+ then:
+ GradleConnectionException e = thrown()
+ e.cause.message.contains('Support for clients using a tooling API version older than 1.2 was removed in Gradle 2.0. You should upgrade your tooling API client to version 1.2 or later.')
+ }
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/UserHomeDirCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/UserHomeDirCrossVersionSpec.groovy
index 32d9504..95ff75a 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/UserHomeDirCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r112/UserHomeDirCrossVersionSpec.groovy
@@ -16,10 +16,13 @@
package org.gradle.integtests.tooling.r112
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.tooling.BuildLauncher
+ at LeaksFileHandles
class UserHomeDirCrossVersionSpec extends ToolingApiSpecification {
def "build is executed using specified user home directory"() {
+ toolingApi.requireIsolatedDaemons()
File userHomeDir = temporaryFolder.createDir('userhomedir')
projectDir.file('settings.gradle') << 'rootProject.name="test"'
projectDir.file('build.gradle') << """task gradleBuild << {
@@ -29,6 +32,7 @@ class UserHomeDirCrossVersionSpec extends ToolingApiSpecification {
ByteArrayOutputStream baos = new ByteArrayOutputStream()
when:
+ toolingApi.withUserHome(userHomeDir)
toolingApi.withConnector { connector ->
connector.useGradleUserHomeDir(userHomeDir)
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/ProjectOutcomesModuleCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/ProjectOutcomesModuleCrossVersionSpec.groovy
index e954a60..bc780e3 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/ProjectOutcomesModuleCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/ProjectOutcomesModuleCrossVersionSpec.groovy
@@ -18,10 +18,12 @@ package org.gradle.integtests.tooling.r12rc1
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.tooling.ProjectConnection
import org.gradle.tooling.model.internal.outcomes.ProjectOutcomes
@TargetGradleVersion(">=1.2")
+ at LeaksFileHandles
class ProjectOutcomesModuleCrossVersionSpec extends ToolingApiSpecification {
def "modelContainsAllArchivesOnTheArchivesConfiguration"() {
given:
@@ -84,4 +86,4 @@ apply plugin: 'java'
projectOutcomes.children[0].children.empty
projectOutcomes.children[1].children.empty
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/UnsupportedOperationFeedbackCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/UnsupportedOperationFeedbackCrossVersionSpec.groovy
index b02cf8c..bfa677f 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/UnsupportedOperationFeedbackCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r12rc1/UnsupportedOperationFeedbackCrossVersionSpec.groovy
@@ -32,6 +32,6 @@ class UnsupportedOperationFeedbackCrossVersionSpec extends ToolingApiSpecificati
then:
UnsupportedOperationConfigurationException e = thrown()
- e.message.contains('Unsupported configuration: modelBuilder.forTasks().')
+ e.message.contains("The version of Gradle you are using (${targetDist.version.version}) does not support the ModelBuilder API forTasks() configuration option. Support for this is available in Gradle 1.2 and all later versions.")
}
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r15/ToolingApiConfigurationOnDemandCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r15/ToolingApiConfigurationOnDemandCrossVersionSpec.groovy
index 63ed4c8..8b27e86 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r15/ToolingApiConfigurationOnDemandCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r15/ToolingApiConfigurationOnDemandCrossVersionSpec.groovy
@@ -20,9 +20,11 @@ package org.gradle.integtests.tooling.r15
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.tooling.model.GradleProject
@TargetGradleVersion(">=1.5")
+ at LeaksFileHandles
class ToolingApiConfigurationOnDemandCrossVersionSpec extends ToolingApiSpecification {
def setup() {
@@ -61,4 +63,4 @@ class ToolingApiConfigurationOnDemandCrossVersionSpec extends ToolingApiSpecific
then:
noExceptionThrown()
}
-}
\ No newline at end of file
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildActionCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildActionCrossVersionSpec.groovy
index 81771b2..e985fa5 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildActionCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildActionCrossVersionSpec.groovy
@@ -19,6 +19,7 @@ package org.gradle.integtests.tooling.r18
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.tooling.BuildActionFailureException
import org.gradle.tooling.BuildException
import org.gradle.tooling.UnsupportedVersionException
@@ -26,6 +27,7 @@ import org.gradle.tooling.model.idea.IdeaProject
@ToolingApiVersion('>=1.8')
@TargetGradleVersion('>=1.8')
+ at LeaksFileHandles
class BuildActionCrossVersionSpec extends ToolingApiSpecification {
def "client receives the result of running a build action"() {
given:
@@ -133,6 +135,6 @@ class BuildActionCrossVersionSpec extends ToolingApiSpecification {
then:
UnsupportedVersionException e = thrown()
- e.message == "The version of Gradle you are using (${targetDist.version.version}) does not support execution of build actions provided by the tooling API client. Support for this was added in Gradle 1.8 and is available in all later versions."
+ e.message == "The version of Gradle you are using (${targetDist.version.version}) does not support the BuildActionExecuter API. Support for this is available in Gradle 1.8 and all later versions."
}
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildScriptModelCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildScriptModelCrossVersionSpec.groovy
index 2c47412..1a311dd 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildScriptModelCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r18/BuildScriptModelCrossVersionSpec.groovy
@@ -19,6 +19,7 @@ package org.gradle.integtests.tooling.r18
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.tooling.model.GradleProject
import org.gradle.tooling.model.UnsupportedMethodException
import org.gradle.tooling.model.eclipse.EclipseProject
@@ -26,6 +27,7 @@ import org.gradle.tooling.model.idea.IdeaProject
@ToolingApiVersion('>=1.8')
@TargetGradleVersion('>=1.8')
+ at LeaksFileHandles
class BuildScriptModelCrossVersionSpec extends ToolingApiSpecification {
def "GradleProject provides details about the project's build script"() {
when:
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r20/ToolingApiUnsupportedBuildJvmCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r20/ToolingApiUnsupportedBuildJvmCrossVersionSpec.groovy
index 0bbe20b..95368c6 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r20/ToolingApiUnsupportedBuildJvmCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r20/ToolingApiUnsupportedBuildJvmCrossVersionSpec.groovy
@@ -42,7 +42,7 @@ class ToolingApiUnsupportedBuildJvmCrossVersionSpec extends ToolingApiSpecificat
then:
GradleConnectionException e = thrown()
- e.message.startsWith("Could not execute build using Gradle installation")
+ e.message.startsWith("Could not execute build using Gradle ")
e.cause.message == "Gradle ${targetDist.version.version} requires Java 6 or later to run. Your build is currently configured to use Java 5."
}
@@ -54,7 +54,7 @@ class ToolingApiUnsupportedBuildJvmCrossVersionSpec extends ToolingApiSpecificat
then:
GradleConnectionException e = thrown()
- e.message.startsWith("Could not fetch model of type 'GradleProject' using Gradle installation")
+ e.message.startsWith("Could not fetch model of type 'GradleProject' using Gradle ")
e.cause.message == "Gradle ${targetDist.version.version} requires Java 6 or later to run. Your build is currently configured to use Java 5."
}
@@ -67,7 +67,20 @@ class ToolingApiUnsupportedBuildJvmCrossVersionSpec extends ToolingApiSpecificat
then:
GradleConnectionException e = thrown()
- e.message.startsWith("Could not run build action using Gradle installation")
+ e.message.startsWith("Could not run build action using Gradle ")
+ e.cause.message == "Gradle ${targetDist.version.version} requires Java 6 or later to run. Your build is currently configured to use Java 5."
+ }
+
+ @ToolingApiVersion(">=2.6")
+ def "cannot run tests when build is configured to use Java 5"() {
+ when:
+ toolingApi.withConnection { ProjectConnection connection ->
+ connection.newTestLauncher().withJvmTestClasses("SomeTest").run()
+ }
+
+ then:
+ GradleConnectionException e = thrown()
+ e.message.startsWith("Could not execute tests using Gradle ")
e.cause.message == "Gradle ${targetDist.version.version} requires Java 6 or later to run. Your build is currently configured to use Java 5."
}
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/BuildActionCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/BuildActionCrossVersionSpec.groovy
index 22996fc..425b5b4 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/BuildActionCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/BuildActionCrossVersionSpec.groovy
@@ -21,15 +21,15 @@ import org.gradle.integtests.fixtures.executer.GradleBackedArtifactBuilder
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.tooling.BuildAction
import org.gradle.tooling.BuildController
import org.gradle.tooling.ProjectConnection
-import org.gradle.test.fixtures.file.LeaksFileHandles
@ToolingApiVersion(">=1.8")
- at LeaksFileHandles
class BuildActionCrossVersionSpec extends ToolingApiSpecification {
@TargetGradleVersion(">=2.2")
+ @LeaksFileHandles("cl1 and cl2 hold action-impl.jar open")
def "can change the implementation of an action"() {
// Make sure we reuse the same daemon
toolingApi.requireIsolatedDaemons()
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/ClientShutdownCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/ClientShutdownCrossVersionSpec.groovy
index 0e293d7..ec63f8a 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/ClientShutdownCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r22/ClientShutdownCrossVersionSpec.groovy
@@ -20,6 +20,7 @@ import org.gradle.integtests.fixtures.executer.GradleExecuter
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.server.http.CyclicBarrierHttpServer
import org.gradle.tooling.GradleConnector
import org.gradle.tooling.internal.consumer.DefaultGradleConnector
@@ -113,6 +114,7 @@ task slow << { new URL("${server.uri}").text }
}
@TargetGradleVersion(">=2.2")
+ @LeaksFileHandles
def "shutdown ignores daemons that were not started by client"() {
given:
toolingApi.requireIsolatedDaemons()
@@ -132,6 +134,8 @@ task slow << { new URL("${server.uri}").text }
}
private GradleExecuter daemonExecutor() {
- targetDist.executer(temporaryFolder).withDaemonBaseDir(toolingApi.daemonBaseDir).withArguments("--daemon").requireGradleHome()
+ // Need to use the same JVM args to start daemon as those used by tooling api fixture
+ // TODO - use more sane JVM args here and for the daemons started using tooling api fixture
+ targetDist.executer(temporaryFolder).withDaemonBaseDir(toolingApi.daemonBaseDir).withBuildJvmOpts("-Xmx1024m", "-XX:MaxPermSize=256m", "-XX:+HeapDumpOnOutOfMemoryError").useDefaultBuildJvmArgs().requireDaemon()
}
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r23/StandardStreamsCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r23/StandardStreamsCrossVersionSpec.groovy
index 9c8ee98..18270ef 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r23/StandardStreamsCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r23/StandardStreamsCrossVersionSpec.groovy
@@ -35,15 +35,15 @@ class StandardStreamsCrossVersionSpec extends ToolingApiSpecification {
@TargetGradleVersion(">=2.3")
def "logging is not sent to System.out or System.err"() {
file("build.gradle") << """
-project.logger.error("error logging");
-project.logger.warn("warn logging");
-project.logger.lifecycle("lifecycle logging");
-project.logger.quiet("quiet logging");
-project.logger.info ("info logging");
-project.logger.debug("debug logging");
+project.logger.error("error log message");
+project.logger.warn("warn log message");
+project.logger.lifecycle("lifecycle log message");
+project.logger.quiet("quiet log message");
+project.logger.info ("info log message");
+project.logger.debug("debug log message");
task log << {
- println "task logging"
+ println "task log message"
}
"""
@@ -55,8 +55,8 @@ task log << {
}
then:
- !stdOutAndErr.stdOut.contains("logging")
- !stdOutAndErr.stdErr.contains("logging")
+ !stdOutAndErr.stdOut.contains("log message")
+ !stdOutAndErr.stdErr.contains("log message")
}
@TargetGradleVersion(">=2.3")
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r24/TestProgressCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r24/TestProgressCrossVersionSpec.groovy
index d4fcb18..a668041 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r24/TestProgressCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r24/TestProgressCrossVersionSpec.groovy
@@ -499,6 +499,9 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
@Requires(TestPrecondition.NOT_WINDOWS)
def "test progress event ids are unique across multiple test tasks, even when run in parallel"() {
given:
+ if (!targetDist.toolingApiEventsInEmbeddedModeSupported) {
+ toolingApi.requireDaemons()
+ }
projectDir.createFile('settings.gradle') << """
include ':sub1'
include ':sub2'
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/BuildProgressCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/BuildProgressCrossVersionSpec.groovy
index f8701fe..75e5017 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/BuildProgressCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/BuildProgressCrossVersionSpec.groovy
@@ -17,14 +17,15 @@
package org.gradle.integtests.tooling.r25
-import groovy.transform.NotYetImplemented
+import org.gradle.integtests.tooling.fixture.ProgressEvents
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
import org.gradle.tooling.BuildException
import org.gradle.tooling.ListenerFailedException
import org.gradle.tooling.ProjectConnection
-import org.gradle.tooling.events.*
+import org.gradle.tooling.events.OperationType
+import org.gradle.tooling.events.ProgressEvent
import org.gradle.tooling.model.gradle.BuildInvocations
class BuildProgressCrossVersionSpec extends ToolingApiSpecification {
@@ -53,16 +54,14 @@ class BuildProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "asking for a model and specifying some task(s) to run first"
- List<ProgressEvent> result = []
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.model(BuildInvocations).forTasks('assemble').addProgressListener({ ProgressEvent event ->
- result << event
- }, EnumSet.of(OperationType.GENERIC)).get()
+ connection.model(BuildInvocations).forTasks('assemble').addProgressListener(events, EnumSet.of(OperationType.GENERIC)).get()
}
then: "build progress events must be forwarded to the attached listeners"
- result.size() > 0
+ events.assertIsABuild()
}
@ToolingApiVersion(">=2.5")
@@ -72,16 +71,14 @@ class BuildProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "launching a build"
- List<ProgressEvent> result = []
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('assemble').addProgressListener({ ProgressEvent event ->
- result << event
- }, EnumSet.of(OperationType.GENERIC)).run()
+ connection.newBuild().forTasks('assemble').addProgressListener(events, EnumSet.of(OperationType.GENERIC)).run()
}
then: "build progress events must be forwarded to the attached listeners"
- result.size() > 0
+ events.assertIsABuild()
}
@ToolingApiVersion(">=2.5")
@@ -126,124 +123,31 @@ class BuildProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when:
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('classes').addProgressListener({ ProgressEvent event ->
- result << event
- }, EnumSet.of(OperationType.GENERIC)).run()
+ connection.newBuild().forTasks('classes').addProgressListener(events, EnumSet.of(OperationType.GENERIC)).run()
}
then:
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 6 * 2 // build running, init scripts, loading, configuring, populating task graph, executing tasks
- result.each {
- assert it.displayName == it.toString()
- assert it.descriptor.displayName == it.descriptor.toString()
- }
+ // Verify the most interesting operations; there may be others
+ def runBuild = events.operation("Run build")
+ runBuild.descriptor.name == "Run build"
+ runBuild.descriptor.parent == null
+
+ def configureBuild = events.operation("Configure build")
+ configureBuild.descriptor.name == "Configure build"
+ configureBuild.descriptor.parent == runBuild.descriptor
- def buildRunningStarted = result[0]
- buildRunningStarted instanceof StartEvent &&
- buildRunningStarted.eventTime > 0 &&
- buildRunningStarted.displayName == 'Run build started' &&
- buildRunningStarted.descriptor.name == 'Run build' &&
- buildRunningStarted.descriptor.displayName == 'Run build' &&
- buildRunningStarted.descriptor.parent == null
- def evaluatingInitScriptsStarted = result[1]
- evaluatingInitScriptsStarted instanceof StartEvent &&
- evaluatingInitScriptsStarted.eventTime > 0 &&
- evaluatingInitScriptsStarted.displayName == 'Run init scripts started' &&
- evaluatingInitScriptsStarted.descriptor.name == 'Run init scripts' &&
- evaluatingInitScriptsStarted.descriptor.displayName == 'Run init scripts' &&
- evaluatingInitScriptsStarted.descriptor.parent == buildRunningStarted.descriptor
- def evaluatingInitScriptsFinished = result[2]
- evaluatingInitScriptsFinished instanceof FinishEvent &&
- evaluatingInitScriptsFinished.eventTime > 0 &&
- evaluatingInitScriptsFinished.displayName == 'Run init scripts succeeded' &&
- evaluatingInitScriptsFinished.descriptor.name == 'Run init scripts' &&
- evaluatingInitScriptsFinished.descriptor.displayName == 'Run init scripts' &&
- evaluatingInitScriptsFinished.descriptor.parent == buildRunningStarted.descriptor &&
- evaluatingInitScriptsFinished.result instanceof SuccessResult &&
- evaluatingInitScriptsFinished.result.startTime == evaluatingInitScriptsStarted.eventTime &&
- evaluatingInitScriptsFinished.result.endTime == evaluatingInitScriptsFinished.eventTime
- def evaluatingSettingsStarted = result[3]
- evaluatingSettingsStarted instanceof StartEvent &&
- evaluatingSettingsStarted.eventTime > 0 &&
- evaluatingSettingsStarted.displayName == 'Load projects started' &&
- evaluatingSettingsStarted.descriptor.name == 'Load projects' &&
- evaluatingSettingsStarted.descriptor.displayName == 'Load projects' &&
- evaluatingSettingsStarted.descriptor.parent == buildRunningStarted.descriptor
- def evaluatingSettingsFinished = result[4]
- evaluatingSettingsFinished instanceof FinishEvent &&
- evaluatingSettingsFinished.eventTime > 0 &&
- evaluatingSettingsFinished.displayName == 'Load projects succeeded' &&
- evaluatingSettingsFinished.descriptor.name == 'Load projects' &&
- evaluatingSettingsFinished.descriptor.displayName == 'Load projects' &&
- evaluatingSettingsFinished.descriptor.parent == buildRunningStarted.descriptor &&
- evaluatingSettingsFinished.result instanceof SuccessResult &&
- evaluatingSettingsFinished.result.startTime == evaluatingSettingsStarted.eventTime &&
- evaluatingSettingsFinished.result.endTime == evaluatingSettingsFinished.eventTime
- def configuringBuildStarted = result[5]
- configuringBuildStarted instanceof StartEvent &&
- configuringBuildStarted.eventTime > 0 &&
- configuringBuildStarted.displayName == 'Configure build started' &&
- configuringBuildStarted.descriptor.name == 'Configure build' &&
- configuringBuildStarted.descriptor.displayName == 'Configure build' &&
- configuringBuildStarted.descriptor.parent == buildRunningStarted.descriptor
- def configuringBuildFinished = result[6]
- configuringBuildFinished instanceof FinishEvent &&
- configuringBuildFinished.eventTime > 0 &&
- configuringBuildFinished.displayName == 'Configure build succeeded' &&
- configuringBuildFinished.descriptor.name == 'Configure build' &&
- configuringBuildFinished.descriptor.displayName == 'Configure build' &&
- configuringBuildFinished.descriptor.parent == buildRunningStarted.descriptor &&
- configuringBuildFinished.result instanceof SuccessResult &&
- configuringBuildFinished.result.startTime == configuringBuildStarted.eventTime &&
- configuringBuildFinished.result.endTime == configuringBuildFinished.eventTime
- def populatingTaskGraphStarted = result[7]
- populatingTaskGraphStarted instanceof StartEvent &&
- populatingTaskGraphStarted.eventTime > 0 &&
- populatingTaskGraphStarted.displayName == 'Calculate task graph started' &&
- populatingTaskGraphStarted.descriptor.name == 'Calculate task graph' &&
- populatingTaskGraphStarted.descriptor.displayName == 'Calculate task graph' &&
- populatingTaskGraphStarted.descriptor.parent == buildRunningStarted.descriptor
- def populatingTaskGraphFinished = result[8]
- populatingTaskGraphFinished instanceof FinishEvent &&
- populatingTaskGraphFinished.eventTime > 0 &&
- populatingTaskGraphFinished.displayName == 'Calculate task graph succeeded' &&
- populatingTaskGraphFinished.descriptor.name == 'Calculate task graph' &&
- populatingTaskGraphFinished.descriptor.displayName == 'Calculate task graph' &&
- populatingTaskGraphFinished.descriptor.parent == buildRunningStarted.descriptor &&
- populatingTaskGraphFinished.result instanceof SuccessResult &&
- populatingTaskGraphFinished.result.startTime == populatingTaskGraphStarted.eventTime &&
- populatingTaskGraphFinished.result.endTime == populatingTaskGraphFinished.eventTime
- def executingTasksGraphStarted = result[9]
- executingTasksGraphStarted instanceof StartEvent &&
- executingTasksGraphStarted.eventTime > 0 &&
- executingTasksGraphStarted.displayName == 'Run tasks started' &&
- executingTasksGraphStarted.descriptor.name == 'Run tasks' &&
- executingTasksGraphStarted.descriptor.displayName == 'Run tasks' &&
- executingTasksGraphStarted.descriptor.parent == buildRunningStarted.descriptor
- def executingTasksFinished = result[10]
- executingTasksFinished instanceof FinishEvent &&
- executingTasksFinished.eventTime > 0 &&
- executingTasksFinished.displayName == 'Run tasks succeeded' &&
- executingTasksFinished.descriptor.name == 'Run tasks' &&
- executingTasksFinished.descriptor.displayName == 'Run tasks' &&
- executingTasksFinished.descriptor.parent == buildRunningStarted.descriptor &&
- executingTasksFinished.result instanceof SuccessResult &&
- executingTasksFinished.result.startTime == executingTasksGraphStarted.eventTime &&
- executingTasksFinished.result.endTime == executingTasksFinished.eventTime
- def buildRunningFinished = result[11]
- buildRunningFinished instanceof FinishEvent &&
- buildRunningFinished.eventTime > 0 &&
- buildRunningFinished.displayName == 'Run build succeeded' &&
- buildRunningFinished.descriptor.name == 'Run build' &&
- buildRunningFinished.descriptor.displayName == 'Run build' &&
- buildRunningFinished.descriptor.parent == null &&
- buildRunningFinished.result instanceof SuccessResult &&
- buildRunningFinished.result.startTime == buildRunningStarted.eventTime &&
- buildRunningFinished.result.endTime == buildRunningFinished.eventTime
+ def runTasks = events.operation("Run tasks")
+ runTasks.descriptor.name == "Run tasks"
+ runTasks.descriptor.parent == runBuild.descriptor
+
+ events.operations[0] == runBuild
+ events.assertHasSingleTree()
+
+ events.operations.each { it.successful }
+ events.operations.each { it.buildOperation }
}
@ToolingApiVersion(">=2.5")
@@ -268,155 +172,37 @@ class BuildProgressCrossVersionSpec extends ToolingApiSpecification {
"""
when:
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener({ ProgressEvent event ->
- result << event
- }, EnumSet.of(OperationType.GENERIC)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.GENERIC)).run()
}
then:
thrown(BuildException)
then:
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 6 * 2 // build running, init scripts, loading, configuring, populating task graph, executing tasks
- result.each {
- assert it.displayName == it.toString()
- assert it.descriptor.displayName == it.descriptor.toString()
- }
-
- def buildRunningStarted = result[0]
- buildRunningStarted instanceof StartEvent &&
- buildRunningStarted.eventTime > 0 &&
- buildRunningStarted.displayName == 'Run build started' &&
- buildRunningStarted.descriptor.name == 'Run build' &&
- buildRunningStarted.descriptor.displayName == 'Run build' &&
- buildRunningStarted.descriptor.parent == null
- def evaluatingInitScriptsStarted = result[1]
- evaluatingInitScriptsStarted instanceof StartEvent &&
- evaluatingInitScriptsStarted.eventTime > 0 &&
- evaluatingInitScriptsStarted.displayName == 'Run init scripts started' &&
- evaluatingInitScriptsStarted.descriptor.name == 'Run init scripts' &&
- evaluatingInitScriptsStarted.descriptor.displayName == 'Run init scripts' &&
- evaluatingInitScriptsStarted.descriptor.parent == buildRunningStarted.descriptor
- def evaluatingInitScriptsFinished = result[2]
- evaluatingInitScriptsFinished instanceof FinishEvent &&
- evaluatingInitScriptsFinished.eventTime > 0 &&
- evaluatingInitScriptsFinished.displayName == 'Run init scripts succeeded' &&
- evaluatingInitScriptsFinished.descriptor.name == 'Run init scripts' &&
- evaluatingInitScriptsFinished.descriptor.displayName == 'Run init scripts' &&
- evaluatingInitScriptsFinished.descriptor.parent == buildRunningStarted.descriptor &&
- evaluatingInitScriptsFinished.result instanceof SuccessResult &&
- evaluatingInitScriptsFinished.result.startTime == evaluatingInitScriptsStarted.eventTime &&
- evaluatingInitScriptsFinished.result.endTime == evaluatingInitScriptsFinished.eventTime
- def evaluatingSettingsStarted = result[3]
- evaluatingSettingsStarted instanceof StartEvent &&
- evaluatingSettingsStarted.eventTime > 0 &&
- evaluatingSettingsStarted.displayName == 'Load projects started' &&
- evaluatingSettingsStarted.descriptor.name == 'Load projects' &&
- evaluatingSettingsStarted.descriptor.displayName == 'Load projects' &&
- evaluatingSettingsStarted.descriptor.parent == buildRunningStarted.descriptor
- def evaluatingSettingsFinished = result[4]
- evaluatingSettingsFinished instanceof FinishEvent &&
- evaluatingSettingsFinished.eventTime > 0 &&
- evaluatingSettingsFinished.displayName == 'Load projects succeeded' &&
- evaluatingSettingsFinished.descriptor.name == 'Load projects' &&
- evaluatingSettingsFinished.descriptor.displayName == 'Load projects' &&
- evaluatingSettingsFinished.descriptor.parent == buildRunningStarted.descriptor &&
- evaluatingSettingsFinished.result instanceof SuccessResult &&
- evaluatingSettingsFinished.result.startTime == evaluatingSettingsStarted.eventTime &&
- evaluatingSettingsFinished.result.endTime == evaluatingSettingsFinished.eventTime
- def configuringBuildStarted = result[5]
- configuringBuildStarted instanceof StartEvent &&
- configuringBuildStarted.eventTime > 0 &&
- configuringBuildStarted.displayName == 'Configure build started' &&
- configuringBuildStarted.descriptor.name == 'Configure build' &&
- configuringBuildStarted.descriptor.displayName == 'Configure build' &&
- configuringBuildStarted.descriptor.parent == buildRunningStarted.descriptor
- def configuringBuildFinished = result[6]
- configuringBuildFinished instanceof FinishEvent &&
- configuringBuildFinished.eventTime > 0 &&
- configuringBuildFinished.displayName == 'Configure build succeeded' &&
- configuringBuildFinished.descriptor.name == 'Configure build' &&
- configuringBuildFinished.descriptor.displayName == 'Configure build' &&
- configuringBuildFinished.descriptor.parent == buildRunningStarted.descriptor &&
- configuringBuildFinished.result instanceof SuccessResult &&
- configuringBuildFinished.result.startTime == configuringBuildStarted.eventTime &&
- configuringBuildFinished.result.endTime == configuringBuildFinished.eventTime
- def populatingTaskGraphStarted = result[7]
- populatingTaskGraphStarted instanceof StartEvent &&
- populatingTaskGraphStarted.eventTime > 0 &&
- populatingTaskGraphStarted.displayName == 'Calculate task graph started' &&
- populatingTaskGraphStarted.descriptor.name == 'Calculate task graph' &&
- populatingTaskGraphStarted.descriptor.displayName == 'Calculate task graph' &&
- populatingTaskGraphStarted.descriptor.parent == buildRunningStarted.descriptor
- def populatingTaskGraphFinished = result[8]
- populatingTaskGraphFinished instanceof FinishEvent &&
- populatingTaskGraphFinished.eventTime > 0 &&
- populatingTaskGraphFinished.displayName == 'Calculate task graph succeeded' &&
- populatingTaskGraphFinished.descriptor.name == 'Calculate task graph' &&
- populatingTaskGraphFinished.descriptor.displayName == 'Calculate task graph' &&
- populatingTaskGraphFinished.descriptor.parent == buildRunningStarted.descriptor &&
- populatingTaskGraphFinished.result instanceof SuccessResult &&
- populatingTaskGraphFinished.result.startTime == populatingTaskGraphStarted.eventTime &&
- populatingTaskGraphFinished.result.endTime == populatingTaskGraphFinished.eventTime
- def executingTasksGraphStarted = result[9]
- executingTasksGraphStarted instanceof StartEvent &&
- executingTasksGraphStarted.eventTime > 0 &&
- executingTasksGraphStarted.displayName == 'Run tasks started' &&
- executingTasksGraphStarted.descriptor.name == 'Run tasks' &&
- executingTasksGraphStarted.descriptor.displayName == 'Run tasks' &&
- executingTasksGraphStarted.descriptor.parent == buildRunningStarted.descriptor
- def executingTasksFinished = result[10]
- executingTasksFinished instanceof FinishEvent &&
- executingTasksFinished.eventTime > 0 &&
- executingTasksFinished.displayName == 'Run tasks failed' &&
- executingTasksFinished.descriptor.name == 'Run tasks' &&
- executingTasksFinished.descriptor.displayName == 'Run tasks' &&
- executingTasksFinished.descriptor.parent == buildRunningStarted.descriptor &&
- executingTasksFinished.result instanceof FailureResult &&
- executingTasksFinished.result.startTime == executingTasksGraphStarted.eventTime &&
- executingTasksFinished.result.endTime == executingTasksFinished.eventTime &&
- executingTasksFinished.result.failures.size() == 1
- def buildRunningFinished = result[11]
- buildRunningFinished instanceof FinishEvent &&
- buildRunningFinished.eventTime > 0 &&
- buildRunningFinished.displayName == 'Run build failed' &&
- buildRunningFinished.descriptor.name == 'Run build' &&
- buildRunningFinished.descriptor.displayName == 'Run build' &&
- buildRunningFinished.descriptor.parent == null &&
- buildRunningFinished.result instanceof FailureResult &&
- buildRunningFinished.result.startTime == buildRunningStarted.eventTime &&
- buildRunningFinished.result.endTime == buildRunningFinished.eventTime &&
- buildRunningFinished.result.failures.size() == 1
- }
-
- @TargetGradleVersion('>=2.5')
- @ToolingApiVersion('>=2.5')
- @NotYetImplemented
- def "should receive build events from GradleBuild"() {
- buildFile << """task innerBuild(type:GradleBuild) {
- buildFile = file('other.gradle')
- tasks = ['innerTask']
- startParameter.searchUpwards = false
- }"""
- file("other.gradle") << """
- task innerTask()
- """
-
- when:
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
- withConnection { ProjectConnection connection ->
- connection.newBuild().forTasks('innerBuild').addProgressListener({ ProgressEvent event ->
- result << event
- }, EnumSet.of(OperationType.TASK)).run()
- }
-
- then:
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 7 * 2 * 2 // life-cycle for both inner and outer build
+ // The main operations; there may be others
+ def runBuild = events.operation("Run build")
+ runBuild.descriptor.parent == null
+ runBuild.failed
+ runBuild.failures.size() == 1
+
+ def configureBuild = events.operation("Configure build")
+ configureBuild.descriptor.parent == runBuild.descriptor
+ configureBuild.successful
+
+ def runTasks = events.operation("Run tasks")
+ assert runTasks.descriptor.parent == runBuild.descriptor
+ runTasks.failed
+ runTasks.failures.size() == 1
+
+ events.operations[0] == runBuild
+ events.assertHasSingleTree()
+ events.operations.each { it.buildOperation }
+
+ events.failed == [runBuild, runTasks]
+ events.successful == events.operations - [runBuild, runTasks]
}
def goodCode() {
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousBuildProgressEventsCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousBuildProgressEventsCrossVersionSpec.groovy
index 342cc60..cb804a1 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousBuildProgressEventsCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousBuildProgressEventsCrossVersionSpec.groovy
@@ -17,20 +17,18 @@
package org.gradle.integtests.tooling.r25
import org.gradle.integtests.tooling.fixture.ContinuousBuildToolingApiSpecification
+import org.gradle.integtests.tooling.fixture.ProgressEvents
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
import org.gradle.integtests.tooling.fixture.ToolingApiVersions
import org.gradle.tooling.BuildLauncher
-import org.gradle.tooling.events.FinishEvent
-import org.gradle.tooling.events.ProgressEvent
-import org.gradle.tooling.events.ProgressListener
@ToolingApiVersion(ToolingApiVersions.SUPPORTS_RICH_PROGRESS_EVENTS)
class ContinuousBuildProgressEventsCrossVersionSpec extends ContinuousBuildToolingApiSpecification {
- List<ProgressEvent> events = []
+ def events = new ProgressEvents()
void customizeLauncher(BuildLauncher launcher) {
- launcher.addProgressListener({ events << it } as ProgressListener)
+ launcher.addProgressListener(events)
}
def "client can receive appropriate logging and progress events for subsequent builds"() {
@@ -49,8 +47,7 @@ class ContinuousBuildProgressEventsCrossVersionSpec extends ContinuousBuildTooli
}
void receivedBuildEvents() {
- assert !events.isEmpty()
- assert events.last() instanceof FinishEvent
+ events.assertIsABuild()
events.clear()
}
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousUnsupportedJavaVersionCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousUnsupportedJavaVersionCrossVersionSpec.groovy
index 0cc4409..be1e37b 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousUnsupportedJavaVersionCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ContinuousUnsupportedJavaVersionCrossVersionSpec.groovy
@@ -21,12 +21,14 @@ import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
import org.gradle.integtests.tooling.fixture.ToolingApiVersions
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.tooling.GradleConnectionException
import org.gradle.util.Requires
@ToolingApiVersion(ToolingApiVersions.SUPPORTS_CANCELLATION)
@TargetGradleVersion(GradleVersions.SUPPORTS_CONTINUOUS)
@Requires(adhoc = { AvailableJavaHomes.jdk6 })
+ at LeaksFileHandles
class ContinuousUnsupportedJavaVersionCrossVersionSpec extends ToolingApiSpecification {
def "client receives error on unsupported platform"() {
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/DeploymentHandleContinuousBuildCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/DeploymentHandleContinuousBuildCrossVersionSpec.groovy
new file mode 100644
index 0000000..d70c13f
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/DeploymentHandleContinuousBuildCrossVersionSpec.groovy
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.r25
+
+import org.gradle.integtests.fixtures.executer.GradleVersions
+import org.gradle.integtests.tooling.fixture.ContinuousBuildToolingApiSpecification
+import org.gradle.integtests.tooling.fixture.TargetGradleVersion
+import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.integtests.tooling.fixture.ToolingApiVersions
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+import spock.lang.Timeout
+
+ at Timeout(120)
+ at Requires(TestPrecondition.JDK7_OR_LATER)
+ at ToolingApiVersion(ToolingApiVersions.SUPPORTS_RICH_PROGRESS_EVENTS)
+ at TargetGradleVersion(GradleVersions.SUPPORTS_DEPLOYMENT_REGISTRY)
+class DeploymentHandleContinuousBuildCrossVersionSpec extends ContinuousBuildToolingApiSpecification {
+ File triggerFile = file('triggerFile')
+ File keyFile = file('keyFile')
+
+ def setup() {
+ buildFile << """
+ import javax.inject.Inject
+ import org.gradle.deployment.internal.DeploymentHandle
+ import org.gradle.deployment.internal.DeploymentRegistry
+
+ task runDeployment(type: RunTestDeployment) {
+ triggerFile = file('${triggerFile.name}')
+ keyFile = file('${keyFile.name}')
+ }
+
+ class TestDeploymentHandle implements DeploymentHandle {
+ final File keyFile
+ boolean running = true
+
+ TestDeploymentHandle(key, File keyFile) {
+ this.keyFile = keyFile
+ keyFile.text = key
+ }
+
+ public boolean isRunning() {
+ return running
+ }
+
+ public void onNewBuild(Gradle gradle) {}
+
+ public void stop() {
+ running = false
+ keyFile.delete()
+ }
+ }
+
+ class RunTestDeployment extends DefaultTask {
+ @InputFile
+ File triggerFile
+
+ @OutputFile
+ File keyFile
+
+ @Inject
+ protected DeploymentRegistry getDeploymentRegistry() {
+ throw new UnsupportedOperationException()
+ }
+
+ @TaskAction
+ void doDeployment() {
+ // we set a different key for every build so we can detect if we
+ // somehow get a different deployment handle between builds
+ def key = System.currentTimeMillis()
+
+ TestDeploymentHandle handle = getDeploymentRegistry().get(TestDeploymentHandle.class, 'test')
+ if (handle == null) {
+ // This should only happen once (1st build), so if we get a different value in keyFile between
+ // builds then we know we can detect if we didn't get the same handle
+ handle = new TestDeploymentHandle(key, keyFile)
+ getDeploymentRegistry().register('test', handle)
+ }
+
+ println "\\nCurrent Key: \$key, Deployed Key: \$handle.keyFile.text"
+ assert handle.isRunning()
+ }
+ }
+ """
+ buildTimeout = 30
+ }
+
+ def "deployment is stopped when continuous build is cancelled" () {
+ triggerFile.text = "0"
+
+ when:
+ runBuild(["runDeployment"]) {
+ succeeds()
+ def key = file('keyFile').text
+ deploymentIsRunning(key)
+
+ file('triggerFile') << "\n#a change"
+ succeeds()
+ deploymentIsRunning(key)
+
+ file('triggerFile') << "\n#another change"
+ succeeds()
+ deploymentIsRunning(key)
+ }
+
+ then:
+ deploymentIsStopped()
+ }
+
+ void deploymentIsRunning(String key) {
+ // assert that the keyFile still exists and has the same contents (ie handle is still running)
+ assert keyFile.exists()
+ assert keyFile.text == key
+ }
+
+ void deploymentIsStopped() {
+ // assert that the deployment handle was stopped and removed the key file
+ assert !keyFile.exists()
+ }
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ProgressCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ProgressCrossVersionSpec.groovy
index 6c68cc2..cec243e 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ProgressCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/ProgressCrossVersionSpec.groovy
@@ -16,21 +16,12 @@
package org.gradle.integtests.tooling.r25
+import org.gradle.integtests.tooling.fixture.ProgressEvents
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
import org.gradle.tooling.ProjectConnection
import org.gradle.tooling.events.OperationType
-import org.gradle.tooling.events.ProgressEvent
-import org.gradle.tooling.events.ProgressListener
-import org.gradle.tooling.events.internal.DefaultFinishEvent
-import org.gradle.tooling.events.internal.DefaultStartEvent
-import org.gradle.tooling.events.task.TaskFinishEvent
-import org.gradle.tooling.events.task.TaskProgressEvent
-import org.gradle.tooling.events.task.TaskStartEvent
-import org.gradle.tooling.events.test.TestFinishEvent
-import org.gradle.tooling.events.test.TestProgressEvent
-import org.gradle.tooling.events.test.TestStartEvent
import org.gradle.tooling.model.gradle.BuildInvocations
@ToolingApiVersion(">=2.5")
@@ -42,19 +33,14 @@ class ProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "asking for a model and specifying some task(s) to run first"
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.model(BuildInvocations).forTasks('assemble').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << event
- }
- }).get()
+ connection.model(BuildInvocations).forTasks('assemble').addProgressListener(events).get()
}
then: "progress events must be forwarded to the attached listeners"
- result.size() > 0
+ events.assertIsABuild()
}
def "receive progress events when launching a build"() {
@@ -62,19 +48,14 @@ class ProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "launching a build"
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('assemble').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << event
- }
- }).run()
+ connection.newBuild().forTasks('assemble').addProgressListener(events).run()
}
then: "progress events must be forwarded to the attached listeners"
- result.size() > 0
+ events.assertIsABuild()
}
def "receive progress events when running a build action"() {
@@ -82,19 +63,14 @@ class ProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "running a build action"
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.action(new NullAction()).addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << event
- }
- }).run()
+ connection.action(new NullAction()).addProgressListener(events).run()
}
then: "progress events must be forwarded to the attached listeners"
- result.size() > 0
+ events.assertIsABuild()
}
def "register for all progress events at once"() {
@@ -102,49 +78,33 @@ class ProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "registering for all progress event types"
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << event
- }
- }, EnumSet.allOf(OperationType)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.allOf(OperationType)).run()
}
then: "all progress events must be forwarded to the attached listener"
- result.size() > 0
- result.findAll { it instanceof TestProgressEvent }.size() > 0
- result.findAll { it instanceof TaskProgressEvent }.size() > 0
- result.findAll { it.class == DefaultStartEvent || it.class == DefaultFinishEvent }.size() > 0
- result.findIndexOf { it.class == DefaultStartEvent } < result.findIndexOf { it instanceof TaskStartEvent }
- result.findIndexOf { it instanceof TaskStartEvent } < result.findIndexOf { it instanceof TestStartEvent }
- result.findLastIndexOf { it instanceof TaskFinishEvent } > result.findLastIndexOf { it instanceof TestFinishEvent }
- result.findLastIndexOf { it.class == DefaultFinishEvent } > result.findLastIndexOf { it instanceof TaskFinishEvent }
+ events.assertHasSingleTree()
+ !events.buildOperations.empty
+ !events.tests.empty
+ !events.tasks.empty
}
- def "register for subset of progress events at once"() {
+ def "register for subset of progress events"() {
given:
goodCode()
when: "registering for subset of progress event types"
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << event
- }
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).run()
}
then: "only the matching progress events must be forwarded to the attached listener"
- result.size() > 0
- result.findAll { it instanceof TestProgressEvent }.size() > 0
- result.findAll { it instanceof TaskProgressEvent }.isEmpty()
- result.findAll { it.class == DefaultStartEvent || it.class == DefaultFinishEvent }.isEmpty()
+ !events.tests.empty
+ events.operations == events.tests
}
@ToolingApiVersion(">=2.5")
@@ -154,45 +114,15 @@ class ProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "registering for all progress event types but provider only knows how to send test progress events"
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << event
- }
- }, EnumSet.allOf(OperationType)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.allOf(OperationType)).run()
}
then: "only test progress events must be forwarded to the attached listener"
- result.size() > 0
- result.findAll { it instanceof TestProgressEvent }.size() > 0
- result.findAll { it instanceof TaskProgressEvent }.isEmpty()
- result.findAll { it.class == DefaultStartEvent || it.class == DefaultFinishEvent }.isEmpty()
- }
-
- def "when listening to all progress events they are all in a hierarchy with a single root node"() {
- given:
- goodCode()
-
- when: 'listening to progress events'
- List<ProgressEvent> result = new ArrayList<ProgressEvent>()
- withConnection {
- ProjectConnection connection ->
- connection.newBuild().forTasks('build').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << event
- }
- }, EnumSet.allOf(OperationType.class)).run()
- }
-
- then: 'all events are in a hierarchy with a single root node'
- !result.isEmpty()
- def rootNodes = result.findAll { it.descriptor.parent == null }
- rootNodes.size() == 2
- rootNodes.each { it.class == DefaultStartEvent || it.class == DefaultFinishEvent }
+ !events.tests.empty
+ events.operations == events.tests
}
def goodCode() {
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TaskProgressCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TaskProgressCrossVersionSpec.groovy
index 2b04474..3f65438 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TaskProgressCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TaskProgressCrossVersionSpec.groovy
@@ -17,7 +17,7 @@
package org.gradle.integtests.tooling.r25
-import groovy.transform.NotYetImplemented
+import org.gradle.integtests.tooling.fixture.ProgressEvents
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
@@ -26,8 +26,8 @@ import org.gradle.tooling.ListenerFailedException
import org.gradle.tooling.ProjectConnection
import org.gradle.tooling.events.OperationType
import org.gradle.tooling.events.ProgressEvent
-import org.gradle.tooling.events.ProgressListener
-import org.gradle.tooling.events.task.*
+import org.gradle.tooling.events.task.TaskProgressEvent
+import org.gradle.tooling.events.task.TaskSkippedResult
import org.gradle.tooling.model.gradle.BuildInvocations
class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
@@ -56,16 +56,15 @@ class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "asking for a model and specifying some task(s) to run first"
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.model(BuildInvocations).forTasks('assemble').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).get()
+ connection.model(BuildInvocations).forTasks('assemble').addProgressListener(events, EnumSet.of(OperationType.TASK)).get()
}
then: "task progress events must be forwarded to the attached listeners"
- result.size() > 0
+ !events.tasks.empty
+ events.operations == events.tasks
}
@ToolingApiVersion(">=2.5")
@@ -75,16 +74,15 @@ class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "launching a build"
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('assemble').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
+ connection.newBuild().forTasks('assemble').addProgressListener(events, EnumSet.of(OperationType.TASK)).run()
}
then: "task progress events must be forwarded to the attached listeners"
- result.size() > 0
+ !events.tasks.empty
+ events.operations == events.tasks
}
@ToolingApiVersion(">=2.5")
@@ -94,8 +92,8 @@ class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "launching a build"
- List<TaskProgressEvent> resultsOfFirstListener = new ArrayList<TaskProgressEvent>()
- List<TaskProgressEvent> resultsOfLastListener = new ArrayList<TaskProgressEvent>()
+ List<TaskProgressEvent> resultsOfFirstListener = []
+ List<TaskProgressEvent> resultsOfLastListener = []
def stdout = new ByteArrayOutputStream()
def failure = new IllegalStateException("Throwing an exception on purpose")
withConnection {
@@ -124,132 +122,45 @@ class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
@ToolingApiVersion(">=2.5")
@TargetGradleVersion(">=2.5")
- def "receive task progress events for all tasks"() {
+ def "receive task progress events for successful tasks"() {
given:
+ goodCode()
buildFile << """
- apply plugin: 'java'
- compileJava.options.fork = true // forked as 'Gradle Test Executor 1'
- classes.enabled = false
-
- task failingTask() << { throw new RuntimeException() }
-
- """
-
- file("src/main/java/example/MyClass.java") << """
- package example;
- public class MyClass {
- public void foo() throws Exception {
- Thread.sleep(100);
- }
+ task disabled {
+ enabled = false
}
+ classes.dependsOn disabled
"""
when:
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('classes').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
+ connection.newBuild().forTasks('classes').addProgressListener(events, EnumSet.of(OperationType.TASK)).run()
}
then:
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 6 // compileJava, processResources, classes
- result.each {
- assert it.displayName == it.toString()
- assert it.descriptor.displayName == it.descriptor.toString()
- }
-
- def compileJavaStartEvent = result[0]
- compileJavaStartEvent instanceof TaskStartEvent &&
- compileJavaStartEvent.eventTime > 0 &&
- compileJavaStartEvent.displayName == "Task :compileJava started" &&
- compileJavaStartEvent.descriptor.name == ':compileJava' &&
- compileJavaStartEvent.descriptor.displayName == 'Task :compileJava' &&
- compileJavaStartEvent.descriptor.taskPath == ':compileJava' &&
- compileJavaStartEvent.descriptor.parent == null
- def compileJavaFinishEvent = result[1]
- compileJavaFinishEvent instanceof TaskFinishEvent &&
- compileJavaFinishEvent.eventTime > 0 &&
- compileJavaFinishEvent.displayName == "Task :compileJava succeeded" &&
- compileJavaFinishEvent.descriptor.name == ':compileJava' &&
- compileJavaFinishEvent.descriptor.displayName == 'Task :compileJava' &&
- compileJavaFinishEvent.descriptor.taskPath == ':compileJava' &&
- compileJavaFinishEvent.descriptor.parent == null &&
- compileJavaFinishEvent.result instanceof TaskSuccessResult &&
- compileJavaFinishEvent.result.startTime == compileJavaStartEvent.eventTime &&
- compileJavaFinishEvent.result.endTime == compileJavaFinishEvent.eventTime &&
- !compileJavaFinishEvent.result.isUpToDate()
- def processResourcesStartEvent = result[2]
- processResourcesStartEvent instanceof TaskStartEvent &&
- processResourcesStartEvent.eventTime > 0 &&
- processResourcesStartEvent.displayName == "Task :processResources started" &&
- processResourcesStartEvent.descriptor.name == ':processResources' &&
- processResourcesStartEvent.descriptor.displayName == 'Task :processResources' &&
- processResourcesStartEvent.descriptor.taskPath == ':processResources' &&
- processResourcesStartEvent.descriptor.parent == null
- def processResourcesFinishEvent = result[3]
- processResourcesFinishEvent instanceof TaskFinishEvent &&
- processResourcesFinishEvent.eventTime > 0 &&
- processResourcesFinishEvent.displayName == "Task :processResources succeeded" &&
- processResourcesFinishEvent.descriptor.name == ':processResources' &&
- processResourcesFinishEvent.descriptor.displayName == 'Task :processResources' &&
- processResourcesFinishEvent.descriptor.taskPath == ':processResources' &&
- processResourcesFinishEvent.descriptor.parent == null &&
- processResourcesFinishEvent.result instanceof TaskSuccessResult &&
- processResourcesFinishEvent.result.startTime == processResourcesStartEvent.eventTime &&
- processResourcesFinishEvent.result.endTime == processResourcesFinishEvent.eventTime &&
- processResourcesFinishEvent.result.upToDate
- def classesStartEvent = result[4]
- classesStartEvent instanceof TaskStartEvent &&
- classesStartEvent.eventTime > 0 &&
- classesStartEvent.displayName == "Task :classes started" &&
- classesStartEvent.descriptor.name == ':classes' &&
- classesStartEvent.descriptor.displayName == 'Task :classes' &&
- classesStartEvent.descriptor.taskPath == ':classes' &&
- classesStartEvent.descriptor.parent == null
- def classesFinishEvent = result[5]
- classesFinishEvent instanceof TaskFinishEvent &&
- classesFinishEvent.eventTime > 0 &&
- classesFinishEvent.displayName == "Task :classes skipped" &&
- classesFinishEvent.descriptor.name == ':classes' &&
- classesFinishEvent.descriptor.displayName == 'Task :classes' &&
- classesFinishEvent.descriptor.taskPath == ':classes' &&
- classesFinishEvent.descriptor.parent == null &&
- classesFinishEvent.result instanceof TaskSkippedResult &&
- classesFinishEvent.result.startTime == classesStartEvent.eventTime &&
- classesFinishEvent.result.endTime == classesFinishEvent.eventTime &&
- classesFinishEvent.result.skipMessage == 'SKIPPED'
- }
-
- @ToolingApiVersion(">=2.5")
- @TargetGradleVersion(">=2.5")
- def "receive task progress events for successful tasks"() {
- given:
- goodCode()
-
- when:
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
- withConnection {
- ProjectConnection connection ->
- connection.newBuild().forTasks('assemble').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
- }
-
- then:
- result.size() == 2 * tasks.size()
- assertOrderedEvents(result, tasks)
-
- where:
- tasks = [
- compileJava : ['started', 'succeeded'],
- processResources: ['started', 'up-to-date'],
- classes : ['started', 'succeeded'],
- jar : ['started', 'succeeded'],
- assemble : ['started', 'succeeded']
- ]
+ // Some tasks; there may be others
+ def compileJava = events.operation('Task :compileJava')
+ compileJava.descriptor.name == ":compileJava"
+ compileJava.descriptor.taskPath == ":compileJava"
+ !compileJava.result.upToDate
+
+ def processResources = events.operation('Task :processResources')
+ processResources.descriptor.name == ":processResources"
+ processResources.descriptor.taskPath == ":processResources"
+ processResources.result.upToDate
+
+ def disabled = events.operation('Task :disabled')
+ disabled.descriptor.name == ":disabled"
+ disabled.descriptor.taskPath == ":disabled"
+ disabled.result instanceof TaskSkippedResult
+ disabled.result.skipMessage == "SKIPPED"
+
+ def classes = events.operation('Task :classes')
+ classes.descriptor.name == ":classes"
+ classes.descriptor.taskPath == ":classes"
+ !classes.result.upToDate
}
@ToolingApiVersion(">=2.5")
@@ -274,77 +185,30 @@ class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
"""
when:
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TASK)).run()
}
then:
BuildException ex = thrown()
ex.cause.cause.message =~ /Execution failed for task ':test'/
- result.size() == 2 * tasks.size()
- assertOrderedEvents(result, tasks)
-
- where:
- tasks = [
- compileJava : ['started', 'up-to-date'],
- processResources : ['started', 'up-to-date'],
- classes : ['started', 'up-to-date'],
- compileTestJava : ['started', 'succeeded'],
- processTestResources: ['started', 'up-to-date'],
- testClasses : ['started', 'succeeded'],
- test : ['started', 'failed']
- ]
- }
- @ToolingApiVersion(">=2.5")
- @TargetGradleVersion(">=2.5")
- def "receive task progress events for disabled tasks"() {
- buildFile << """
- apply plugin: 'java'
- compileJava.options.fork = true // forked as 'Gradle Test Executor 1'
- assemble.enabled = false
- """
+ def test = events.operation("Task :test")
+ test.failed
+ test.failures.size() == 1
- file("src/main/java/example/MyClass.java") << """
- package example;
- public class MyClass {
- public void foo() throws Exception {
- Thread.sleep(100);
- }
- }
- """
-
- when:
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
- withConnection {
- ProjectConnection connection ->
- connection.newBuild().forTasks('assemble').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
- }
-
- then:
- result.size() == 2 * tasks.size()
- assertOrderedEvents(result, tasks)
-
- where:
- tasks = [
- compileJava : ['started', 'succeeded'],
- processResources: ['started', 'up-to-date'],
- classes : ['started', 'succeeded'],
- jar : ['started', 'succeeded'],
- assemble : ['started', 'skipped']
- ]
+ events.failed == [test]
}
@ToolingApiVersion(">=2.5")
@TargetGradleVersion(">=2.5")
def "receive task progress events when tasks are executed in parallel"() {
given:
+ if (!targetDist.toolingApiEventsInEmbeddedModeSupported) {
+ toolingApi.requireDaemons()
+ }
buildFile << """
@ParallelizableTask
class ParTask extends DefaultTask {
@@ -357,150 +221,43 @@ class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
"""
when:
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().withArguments("-Dorg.gradle.parallel.intra=true", '--parallel', '--max-workers=2').forTasks('parallelSleep').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
- }
-
- then:
- result.size() == 2 * tasks.size()
- assertUnorderedEvents(result, tasks)
-
- where:
- tasks = [
- para1 : ['started', 'succeeded'],
- para2 : ['started', 'succeeded'],
- parallelSleep: ['started', 'succeeded']
- ]
- }
-
- @TargetGradleVersion('>=2.5')
- @ToolingApiVersion('>=2.5')
- @NotYetImplemented
- def "should receive task events from buildSrc"() {
- buildFile << """
- apply plugin: 'java'
- task dummy()
- """
-
- file("buildSrc/build.gradle") << """
- task taskInBuildSrc()
- """
-
- when:
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
- withConnection { ProjectConnection connection ->
- connection.newBuild().forTasks('dummy').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
- }
-
- then:
- result.size() == 2 * tasks.size()
- assertOrderedEvents(result, tasks)
-
- where:
- tasks = [
- ':buildSrc:clean' : ['started', 'up-to-date'],
- ':buildSrc:compileJava' : ['started', 'up-to-date'],
- ':buildSrc:compileGroovy' : ['started', 'up-to-date'],
- ':buildSrc:processResources' : ['started', 'up-to-date'],
- ':buildSrc:classes' : ['started', 'up-to-date'],
- ':buildSrc:jar' : ['started', 'succeeded'],
- ':buildSrc:assemble' : ['started', 'succeeded'],
- ':buildSrc:compileTestJava' : ['started', 'up-to-date'],
- ':buildSrc:compileTestGroovy' : ['started', 'up-to-date'],
- ':buildSrc:processTestResources': ['started', 'up-to-date'],
- ':buildSrc:testClasses' : ['started', 'up-to-date'],
- ':buildSrc:test' : ['started', 'up-to-date'],
- ':buildSrc:build' : ['started', 'up-to-date'],
- ':dummy' : ['started', 'up-to-date']
- ]
- }
-
- @TargetGradleVersion('>=2.5')
- @ToolingApiVersion('>=2.5')
- @NotYetImplemented
- def "should receive task events from GradleBuild"() {
- buildFile << """
- task innerBuild(type:GradleBuild) {
- buildFile = file('other.gradle')
- tasks = ['innerTask']
- startParameter.searchUpwards = false
- }
- """
-
- file("other.gradle") << """
- task innerTask()
- """
-
- when:
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
- withConnection { ProjectConnection connection ->
- connection.newBuild().forTasks('innerBuild').addProgressListener({ ProgressEvent event ->
- result << (event as TaskProgressEvent)
- }, EnumSet.of(OperationType.TASK)).run()
+ connection.newBuild().withArguments("-Dorg.gradle.parallel.intra=true", '--parallel', '--max-workers=2').forTasks('parallelSleep').addProgressListener(events, EnumSet.of(OperationType.TASK)).run()
}
then:
- result.size() == 2 * tasks.size()
- assertUnorderedEvents(result, tasks)
-
- where:
- tasks = [
- ':innerTask' : ['started', 'up-to-date'],
- ':innerBuild': ['started', 'succeeded']
- ]
+ events.tasks.size() == 3
+ events.successful == events.tasks
}
@ToolingApiVersion(">=2.5")
@TargetGradleVersion(">=2.5")
- def "task operations have root build operation as parent iff build listener is attached"() {
+ def "task operations have a build operation as parent iff build listener is attached"() {
given:
goodCode()
when: 'listening to task progress events and build operation listener is attached'
- List<TaskProgressEvent> result = new ArrayList<TaskProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('assemble').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- if (event instanceof TaskProgressEvent) {
- result << (event as TaskProgressEvent)
- }
- }
- }, EnumSet.of(OperationType.GENERIC, OperationType.TASK)).run()
+ connection.newBuild().forTasks('assemble').addProgressListener(events, EnumSet.of(OperationType.GENERIC, OperationType.TASK)).run()
}
then: 'the parent of the task events is the root build operation'
- !result.isEmpty()
- result.each { def event ->
- assert event.descriptor.parent
- assert event.descriptor.parent.parent
- assert event.descriptor.parent.parent.parent == null
- }
+ def runTasks = events.operation("Run tasks")
+ events.tasks.every { it.descriptor.parent == runTasks.descriptor }
when: 'listening to task progress events when no build operation listener is attached'
- result = new ArrayList<TaskProgressEvent>()
+ events.clear()
withConnection {
ProjectConnection connection ->
- connection.newBuild().withArguments('--rerun-tasks').forTasks('assemble').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TaskProgressEvent)
- }
- }, EnumSet.of(OperationType.TASK)).run()
+ connection.newBuild().withArguments('--rerun-tasks').forTasks('assemble').addProgressListener(events, EnumSet.of(OperationType.TASK)).run()
}
then: 'the parent of the task events is null'
- !result.isEmpty()
- result.each { def event ->
- assert event.descriptor.parent == null
- }
+ events.tasks.every { it.descriptor.parent == null }
}
def goodCode() {
@@ -518,77 +275,4 @@ class TaskProgressCrossVersionSpec extends ToolingApiSpecification {
}
"""
}
-
- private static void assertUnorderedEvents(List<TaskProgressEvent> events, Map<String, List<String>> tasks) {
- assertEvents(events, tasks, false)
- }
-
- private static void assertOrderedEvents(List<TaskProgressEvent> events, Map<String, List<String>> tasks) {
- assertEvents(events, tasks, true)
- }
-
- private static void assertEvents(List<TaskProgressEvent> events, Map<String, List<String>> tasks, boolean ordered) {
- int idx = 0
- long oldEndTime = 0
- if (!ordered) {
- // reorder events to make sure we can test that all events have their expected
- // outputs
- events = events.sort { it.descriptor.taskPath }
- }
-
- tasks.each { path, List<String> states ->
- states.each { state ->
- def event = events[idx]
- assert event.eventTime > 0
- if (ordered) {
- assert event.eventTime >= oldEndTime
- }
- assert event.descriptor.taskPath == ":$path"
- assert event.descriptor.name == ":$path"
- switch (state) {
- case 'started':
- assert event instanceof TaskStartEvent
- break
- case 'up-to-date':
- assert event instanceof TaskFinishEvent
- assert event.result instanceof TaskSuccessResult
- if (ordered) {
- assert event.result.startTime >= oldEndTime
- }
- assert event.result.endTime >= event.result.startTime
- assert event.result.isUpToDate()
- break
- case 'skipped':
- assert event instanceof TaskFinishEvent
- assert event.result instanceof TaskSkippedResult
- if (ordered) {
- assert event.result.startTime >= oldEndTime
- }
- assert event.result.endTime >= event.result.startTime
- assert event.result.skipMessage == 'SKIPPED'
- break
- case 'succeeded':
- assert event instanceof TaskFinishEvent
- assert event.result instanceof TaskSuccessResult
- if (ordered) {
- assert event.result.startTime >= oldEndTime
- }
- assert event.result.endTime >= event.result.startTime
- break
- case 'failed':
- assert event instanceof TaskFinishEvent
- assert event.result instanceof TaskFailureResult
- if (ordered) {
- assert event.result.startTime >= oldEndTime
- }
- assert event.result.endTime >= event.result.startTime
- break
- default:
- throw new RuntimeException("Illegal state [$state]. Please check your test.")
- }
- oldEndTime = event.eventTime
- idx++
- }
- }
- }
}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TestProgressCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TestProgressCrossVersionSpec.groovy
index efe2e2e..a2378a1 100644
--- a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TestProgressCrossVersionSpec.groovy
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r25/TestProgressCrossVersionSpec.groovy
@@ -17,7 +17,7 @@
package org.gradle.integtests.tooling.r25
-import groovy.transform.NotYetImplemented
+import org.gradle.integtests.tooling.fixture.ProgressEvents
import org.gradle.integtests.tooling.fixture.TargetGradleVersion
import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
import org.gradle.integtests.tooling.fixture.ToolingApiVersion
@@ -27,14 +27,11 @@ import org.gradle.tooling.ProjectConnection
import org.gradle.tooling.events.OperationType
import org.gradle.tooling.events.ProgressEvent
import org.gradle.tooling.events.ProgressListener
-import org.gradle.tooling.events.task.TaskOperationDescriptor
import org.gradle.tooling.events.test.*
import org.gradle.tooling.model.gradle.BuildInvocations
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
-import java.util.concurrent.ConcurrentLinkedQueue
-
class TestProgressCrossVersionSpec extends ToolingApiSpecification {
@ToolingApiVersion(">=2.5")
@TargetGradleVersion(">=1.0-milestone-8 <2.4")
@@ -61,16 +58,15 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "asking for a model and specifying some test task(s) to run first"
- List<TestProgressEvent> result = new ArrayList<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.model(BuildInvocations.class).forTasks('test').addProgressListener({ ProgressEvent event ->
- result << (event as TestProgressEvent)
- }, EnumSet.of(OperationType.TEST)).get()
+ connection.model(BuildInvocations.class).forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).get()
}
then: "test progress events must be forwarded to the attached listeners"
- result.size() > 0
+ !events.tests.empty
+ events.operations == events.tests
}
@ToolingApiVersion(">=2.5")
@@ -80,19 +76,15 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
goodCode()
when: "launching a build"
- List<TestProgressEvent> result = new ArrayList<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TestProgressEvent)
- }
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).run()
}
then: "test progress events must be forwarded to the attached listeners"
- result.size() > 0
+ !events.tests.empty
+ events.operations == events.tests
}
@ToolingApiVersion(">=2.5")
@@ -161,105 +153,51 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
"""
when:
- List<TestProgressEvent> result = new ArrayList<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TestProgressEvent)
- }
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).run()
}
then:
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 8 // root suite, test process suite, test class suite, test method (each with a start and finish event)
- result.each {
- assert it.displayName == it.toString()
- assert it.descriptor.displayName == it.descriptor.toString()
- }
-
- def rootStartedEvent = result[0]
- rootStartedEvent instanceof TestStartEvent &&
- rootStartedEvent.eventTime > 0 &&
- rootStartedEvent.displayName == "Gradle Test Run :test started" &&
- rootStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- rootStartedEvent.descriptor.name == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.displayName == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.suiteName == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.className == null &&
- rootStartedEvent.descriptor.methodName == null &&
- rootStartedEvent.descriptor.parent == null
- def testProcessStartedEvent = result[1]
- testProcessStartedEvent instanceof TestStartEvent &&
- testProcessStartedEvent.eventTime > 0 &&
- testProcessStartedEvent.displayName == "Gradle Test Executor 2 started" &&
- testProcessStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- testProcessStartedEvent.descriptor.name == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.displayName == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.suiteName == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.className == null &&
- testProcessStartedEvent.descriptor.methodName == null &&
- testProcessStartedEvent.descriptor.parent == rootStartedEvent.descriptor
- def testClassStartedEvent = result[2]
- testClassStartedEvent instanceof TestStartEvent &&
- testClassStartedEvent.eventTime > 0 &&
- testClassStartedEvent.displayName == "Test class example.MyTest started" &&
- testClassStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- testClassStartedEvent.descriptor.name == 'example.MyTest' &&
- testClassStartedEvent.descriptor.displayName == 'Test class example.MyTest' &&
- testClassStartedEvent.descriptor.suiteName == 'example.MyTest' &&
- testClassStartedEvent.descriptor.className == 'example.MyTest' &&
- testClassStartedEvent.descriptor.methodName == null &&
- testClassStartedEvent.descriptor.parent == testProcessStartedEvent.descriptor
- def testStartedEvent = result[3]
- testStartedEvent instanceof TestStartEvent &&
- testStartedEvent.eventTime > 0 &&
- testStartedEvent.displayName == "Test foo(example.MyTest) started" &&
- testStartedEvent.descriptor.jvmTestKind == JvmTestKind.ATOMIC &&
- testStartedEvent.descriptor.name == 'foo' &&
- testStartedEvent.descriptor.displayName == 'Test foo(example.MyTest)' &&
- testStartedEvent.descriptor.suiteName == null &&
- testStartedEvent.descriptor.className == 'example.MyTest' &&
- testStartedEvent.descriptor.methodName == 'foo' &&
- testStartedEvent.descriptor.parent == testClassStartedEvent.descriptor
- def testSucceededEvent = result[4]
- testSucceededEvent instanceof TestFinishEvent &&
- testSucceededEvent.eventTime >= testSucceededEvent.result.endTime &&
- testSucceededEvent.displayName == "Test foo(example.MyTest) succeeded" &&
- testSucceededEvent.descriptor == testStartedEvent.descriptor &&
- testSucceededEvent.result instanceof TestSuccessResult &&
- testSucceededEvent.result.startTime == testStartedEvent.eventTime &&
- testSucceededEvent.result.endTime > testSucceededEvent.result.startTime &&
- testSucceededEvent.result.endTime == testSucceededEvent.eventTime
- def testClassSucceededEvent = result[5]
- testClassSucceededEvent instanceof TestFinishEvent &&
- testClassSucceededEvent.eventTime >= testClassSucceededEvent.result.endTime &&
- testClassSucceededEvent.displayName == "Test class example.MyTest succeeded" &&
- testClassSucceededEvent.descriptor == testClassStartedEvent.descriptor &&
- testClassSucceededEvent.result instanceof TestSuccessResult &&
- testClassSucceededEvent.result.startTime == testClassStartedEvent.eventTime &&
- testClassSucceededEvent.result.endTime > testClassSucceededEvent.result.startTime &&
- testClassSucceededEvent.result.endTime == testClassSucceededEvent.eventTime
- def testProcessSucceededEvent = result[6]
- testProcessSucceededEvent instanceof TestFinishEvent &&
- testProcessSucceededEvent.eventTime >= testProcessSucceededEvent.result.endTime &&
- testProcessSucceededEvent.displayName == "Gradle Test Executor 2 succeeded" &&
- testProcessSucceededEvent.descriptor == testProcessStartedEvent.descriptor &&
- testProcessSucceededEvent.result instanceof TestSuccessResult &&
- testProcessSucceededEvent.result.startTime == testProcessStartedEvent.eventTime &&
- testProcessSucceededEvent.result.endTime > testProcessSucceededEvent.result.startTime &&
- testProcessSucceededEvent.result.endTime == testProcessSucceededEvent.eventTime
- def rootSucceededEvent = result[7]
- rootSucceededEvent instanceof TestFinishEvent &&
- rootSucceededEvent.eventTime >= rootSucceededEvent.result.endTime &&
- rootSucceededEvent.displayName == "Gradle Test Run :test succeeded" &&
- rootSucceededEvent.descriptor == rootStartedEvent.descriptor &&
- rootSucceededEvent.result instanceof TestSuccessResult &&
- rootSucceededEvent.result.startTime == rootStartedEvent.eventTime &&
- rootSucceededEvent.result.endTime > rootSucceededEvent.result.startTime &&
- rootSucceededEvent.result.endTime == rootSucceededEvent.eventTime
+ events.tests.size() == 4 // root suite, test process suite, test class suite, test method
+ events.tests == events.successful
+
+ def rootSuite = events.operation("Gradle Test Run :test")
+ rootSuite.descriptor.jvmTestKind == JvmTestKind.SUITE
+ rootSuite.descriptor.name == 'Gradle Test Run :test'
+ rootSuite.descriptor.displayName == 'Gradle Test Run :test'
+ rootSuite.descriptor.suiteName == 'Gradle Test Run :test'
+ rootSuite.descriptor.className == null
+ rootSuite.descriptor.methodName == null
+ rootSuite.descriptor.parent == null
+
+ def workerSuite = events.operation("Gradle Test Executor 2")
+ workerSuite.descriptor.jvmTestKind == JvmTestKind.SUITE
+ workerSuite.descriptor.name == 'Gradle Test Executor 2'
+ workerSuite.descriptor.displayName == 'Gradle Test Executor 2'
+ workerSuite.descriptor.suiteName == 'Gradle Test Executor 2'
+ workerSuite.descriptor.className == null
+ workerSuite.descriptor.methodName == null
+ workerSuite.descriptor.parent == rootSuite.descriptor
+
+ def testClass = events.operation("Test class example.MyTest")
+ testClass.descriptor.jvmTestKind == JvmTestKind.SUITE
+ testClass.descriptor.name == 'example.MyTest'
+ testClass.descriptor.displayName == 'Test class example.MyTest'
+ testClass.descriptor.suiteName == 'example.MyTest'
+ testClass.descriptor.className == 'example.MyTest'
+ testClass.descriptor.methodName == null
+ testClass.descriptor.parent == workerSuite.descriptor
+
+ def testMethod = events.operation("Test foo(example.MyTest)")
+ testMethod.descriptor.jvmTestKind == JvmTestKind.ATOMIC
+ testMethod.descriptor.name == 'foo'
+ testMethod.descriptor.displayName == 'Test foo(example.MyTest)'
+ testMethod.descriptor.suiteName == null
+ testMethod.descriptor.className == 'example.MyTest'
+ testMethod.descriptor.methodName == 'foo'
+ testMethod.descriptor.parent == testClass.descriptor
}
@ToolingApiVersion(">=2.5")
@@ -285,111 +223,64 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
"""
when:
- List<TestProgressEvent> result = new ArrayList<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TestProgressEvent)
- }
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).run()
}
then:
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 8 // root suite, test process suite, test class suite, test method (each with a start and finish event)
- result.each {
- assert it.displayName == it.toString()
- assert it.descriptor.displayName == it.descriptor.toString()
- }
-
- def rootStartedEvent = result[0]
- rootStartedEvent instanceof TestStartEvent &&
- rootStartedEvent.eventTime > 0 &&
- rootStartedEvent.displayName == "Gradle Test Run :test started" &&
- rootStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- rootStartedEvent.descriptor.name == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.displayName == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.suiteName == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.className == null &&
- rootStartedEvent.descriptor.methodName == null &&
- rootStartedEvent.descriptor.parent == null
- def testProcessStartedEvent = result[1]
- testProcessStartedEvent instanceof TestStartEvent &&
- testProcessStartedEvent.eventTime > 0 &&
- testProcessStartedEvent.displayName == "Gradle Test Executor 2 started" &&
- testProcessStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- testProcessStartedEvent.descriptor.name == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.displayName == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.suiteName == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.className == null &&
- testProcessStartedEvent.descriptor.methodName == null &&
- testProcessStartedEvent.descriptor.parent == rootStartedEvent.descriptor
- def testClassStartedEvent = result[2]
- testClassStartedEvent instanceof TestStartEvent &&
- testClassStartedEvent.eventTime > 0 &&
- testClassStartedEvent.displayName == "Test class example.MyTest started" &&
- testClassStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- testClassStartedEvent.descriptor.name == 'example.MyTest' &&
- testClassStartedEvent.descriptor.displayName == 'Test class example.MyTest' &&
- testClassStartedEvent.descriptor.suiteName == 'example.MyTest' &&
- testClassStartedEvent.descriptor.className == 'example.MyTest' &&
- testClassStartedEvent.descriptor.methodName == null &&
- testClassStartedEvent.descriptor.parent == testProcessStartedEvent.descriptor
- def testStartedEvent = result[3]
- testStartedEvent instanceof TestStartEvent &&
- testStartedEvent.eventTime > 0 &&
- testStartedEvent.displayName == "Test foo(example.MyTest) started" &&
- testStartedEvent.descriptor.jvmTestKind == JvmTestKind.ATOMIC &&
- testStartedEvent.descriptor.name == 'foo' &&
- testStartedEvent.descriptor.displayName == 'Test foo(example.MyTest)' &&
- testStartedEvent.descriptor.suiteName == null &&
- testStartedEvent.descriptor.className == 'example.MyTest' &&
- testStartedEvent.descriptor.methodName == 'foo' &&
- testStartedEvent.descriptor.parent == testClassStartedEvent.descriptor
- def testFailedEvent = result[4]
- testFailedEvent instanceof TestFinishEvent &&
- testFailedEvent.eventTime >= testFailedEvent.result.endTime &&
- testFailedEvent.displayName == "Test foo(example.MyTest) failed" &&
- testFailedEvent.descriptor == testStartedEvent.descriptor &&
- testFailedEvent.result instanceof TestFailureResult &&
- testFailedEvent.result.startTime == testStartedEvent.eventTime &&
- testFailedEvent.result.endTime == testFailedEvent.eventTime &&
- testFailedEvent.result.failures.size() == 1 &&
- testFailedEvent.result.failures[0].message == 'broken' &&
- testFailedEvent.result.failures[0].description.startsWith("java.lang.RuntimeException: broken") &&
- testFailedEvent.result.failures[0].description.contains("at example.MyTest.foo(MyTest.java:6)") &&
- testFailedEvent.result.failures[0].causes.size() == 1 &&
- testFailedEvent.result.failures[0].causes[0].message == 'nope' &&
- testFailedEvent.result.failures[0].causes[0].causes.empty
- def testClassFailedEvent = result[5]
- testClassFailedEvent instanceof TestFinishEvent &&
- testClassFailedEvent.eventTime >= testClassFailedEvent.result.endTime &&
- testClassFailedEvent.displayName == "Test class example.MyTest failed" &&
- testClassFailedEvent.descriptor == testClassStartedEvent.descriptor &&
- testClassFailedEvent.result instanceof TestFailureResult &&
- testClassFailedEvent.result.startTime == testClassStartedEvent.eventTime &&
- testClassFailedEvent.result.endTime == testClassFailedEvent.eventTime &&
- testClassFailedEvent.result.failures.size() == 0
- def testProcessFailedEvent = result[6]
- testProcessFailedEvent instanceof TestFinishEvent &&
- testProcessFailedEvent.eventTime >= testProcessFailedEvent.result.endTime &&
- testProcessFailedEvent.displayName == "Gradle Test Executor 2 failed" &&
- testProcessFailedEvent.descriptor == testProcessStartedEvent.descriptor &&
- testProcessFailedEvent.result instanceof TestFailureResult &&
- testProcessFailedEvent.result.startTime == testProcessStartedEvent.eventTime &&
- testProcessFailedEvent.result.endTime == testProcessFailedEvent.eventTime &&
- testProcessFailedEvent.result.failures.size() == 0
- def rootFailedEvent = result[7]
- rootFailedEvent instanceof TestFinishEvent &&
- rootFailedEvent.eventTime >= rootFailedEvent.result.endTime &&
- rootFailedEvent.displayName == "Gradle Test Run :test failed" &&
- rootFailedEvent.descriptor == rootStartedEvent.descriptor &&
- rootFailedEvent.result instanceof TestFailureResult &&
- rootFailedEvent.result.startTime == rootStartedEvent.eventTime &&
- rootFailedEvent.result.endTime == rootFailedEvent.eventTime &&
- rootFailedEvent.result.failures.size() == 0
+ events.tests.size() == 4 // root suite, test process suite, test class suite, test method
+
+ def rootSuite = events.operation("Gradle Test Run :test")
+ rootSuite.descriptor.jvmTestKind == JvmTestKind.SUITE
+ rootSuite.descriptor.name == 'Gradle Test Run :test'
+ rootSuite.descriptor.displayName == 'Gradle Test Run :test'
+ rootSuite.descriptor.suiteName == 'Gradle Test Run :test'
+ rootSuite.descriptor.className == null
+ rootSuite.descriptor.methodName == null
+ rootSuite.descriptor.parent == null
+ rootSuite.result instanceof TestFailureResult
+ rootSuite.result.failures.size() == 0
+
+ def workerSuite = events.operation("Gradle Test Executor 2")
+ workerSuite.descriptor.jvmTestKind == JvmTestKind.SUITE
+ workerSuite.descriptor.name == 'Gradle Test Executor 2'
+ workerSuite.descriptor.displayName == 'Gradle Test Executor 2'
+ workerSuite.descriptor.suiteName == 'Gradle Test Executor 2'
+ workerSuite.descriptor.className == null
+ workerSuite.descriptor.methodName == null
+ workerSuite.descriptor.parent == rootSuite.descriptor
+ workerSuite.result instanceof TestFailureResult
+ workerSuite.result.failures.size() == 0
+
+ def testClass = events.operation("Test class example.MyTest")
+ testClass.descriptor.jvmTestKind == JvmTestKind.SUITE
+ testClass.descriptor.name == 'example.MyTest'
+ testClass.descriptor.displayName == 'Test class example.MyTest'
+ testClass.descriptor.suiteName == 'example.MyTest'
+ testClass.descriptor.className == 'example.MyTest'
+ testClass.descriptor.methodName == null
+ testClass.descriptor.parent == workerSuite.descriptor
+ testClass.result instanceof TestFailureResult
+ testClass.result.failures.size() == 0
+
+ def testMethod = events.operation("Test foo(example.MyTest)")
+ testMethod.descriptor.jvmTestKind == JvmTestKind.ATOMIC
+ testMethod.descriptor.name == 'foo'
+ testMethod.descriptor.displayName == 'Test foo(example.MyTest)'
+ testMethod.descriptor.suiteName == null
+ testMethod.descriptor.className == 'example.MyTest'
+ testMethod.descriptor.methodName == 'foo'
+ testMethod.descriptor.parent == testClass.descriptor
+ testMethod.result instanceof TestFailureResult
+ testMethod.result.failures.size() == 1
+ testMethod.result.failures[0].message == 'broken'
+ testMethod.result.failures[0].description.startsWith("java.lang.RuntimeException: broken")
+ testMethod.result.failures[0].description.contains("at example.MyTest.foo(MyTest.java:6)")
+ testMethod.result.failures[0].causes.size() == 1
+ testMethod.result.failures[0].causes[0].message == 'nope'
+ testMethod.result.failures[0].causes[0].causes.empty
}
@ToolingApiVersion(">=2.5")
@@ -414,101 +305,16 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
"""
when:
- List<TestProgressEvent> result = new ArrayList<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TestProgressEvent)
- }
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).run()
}
then:
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 8 // root suite, test process suite, test class suite, test method (each with a start and finish event)
- result.each {
- assert it.displayName == it.toString()
- assert it.descriptor.displayName == it.descriptor.toString()
- }
-
- def rootStartedEvent = result[0]
- rootStartedEvent instanceof TestStartEvent &&
- rootStartedEvent.eventTime > 0 &&
- rootStartedEvent.displayName == "Gradle Test Run :test started" &&
- rootStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- rootStartedEvent.descriptor.name == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.displayName == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.suiteName == 'Gradle Test Run :test' &&
- rootStartedEvent.descriptor.className == null &&
- rootStartedEvent.descriptor.methodName == null &&
- rootStartedEvent.descriptor.parent == null
- def testProcessStartedEvent = result[1]
- testProcessStartedEvent instanceof TestStartEvent &&
- testProcessStartedEvent.eventTime > 0 &&
- testProcessStartedEvent.displayName == "Gradle Test Executor 2 started" &&
- testProcessStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- testProcessStartedEvent.descriptor.name == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.displayName == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.suiteName == 'Gradle Test Executor 2' &&
- testProcessStartedEvent.descriptor.className == null &&
- testProcessStartedEvent.descriptor.methodName == null &&
- testProcessStartedEvent.descriptor.parent == rootStartedEvent.descriptor
- def testClassStartedEvent = result[2]
- testClassStartedEvent instanceof TestStartEvent &&
- testClassStartedEvent.eventTime > 0 &&
- testClassStartedEvent.displayName == "Test class example.MyTest started" &&
- testClassStartedEvent.descriptor.jvmTestKind == JvmTestKind.SUITE &&
- testClassStartedEvent.descriptor.name == 'example.MyTest' &&
- testClassStartedEvent.descriptor.displayName == "Test class example.MyTest" &&
- testClassStartedEvent.descriptor.suiteName == 'example.MyTest' &&
- testClassStartedEvent.descriptor.className == 'example.MyTest' &&
- testClassStartedEvent.descriptor.methodName == null &&
- testClassStartedEvent.descriptor.parent == testProcessStartedEvent.descriptor
- def testStartedEvent = result[3]
- testStartedEvent instanceof TestStartEvent &&
- testStartedEvent.eventTime > 0 &&
- testStartedEvent.displayName == "Test foo(example.MyTest) started" &&
- testStartedEvent.descriptor.jvmTestKind == JvmTestKind.ATOMIC &&
- testStartedEvent.descriptor.name == 'foo' &&
- testStartedEvent.descriptor.displayName == 'Test foo(example.MyTest)' &&
- testStartedEvent.descriptor.suiteName == null &&
- testStartedEvent.descriptor.className == 'example.MyTest' &&
- testStartedEvent.descriptor.methodName == 'foo' &&
- testStartedEvent.descriptor.parent == testClassStartedEvent.descriptor
- def testSkippedEvent = result[4]
- testSkippedEvent instanceof TestFinishEvent &&
- testSkippedEvent.eventTime > 0 &&
- testSkippedEvent.displayName == "Test foo(example.MyTest) skipped" &&
- testSkippedEvent.descriptor == testStartedEvent.descriptor &&
- testSkippedEvent.result instanceof TestSkippedResult &&
- testSkippedEvent.result.startTime == testStartedEvent.eventTime &&
- testSkippedEvent.result.endTime == testSkippedEvent.eventTime
- def testClassSucceededEvent = result[5]
- testClassSucceededEvent instanceof TestFinishEvent &&
- testClassSucceededEvent.eventTime >= testClassSucceededEvent.result.endTime &&
- testClassSucceededEvent.displayName == "Test class example.MyTest succeeded" &&
- testClassSucceededEvent.descriptor == testClassStartedEvent.descriptor &&
- testClassSucceededEvent.result instanceof TestSuccessResult &&
- testClassSucceededEvent.result.startTime == testClassStartedEvent.eventTime &&
- testClassSucceededEvent.result.endTime == testClassSucceededEvent.eventTime
- def testProcessSucceededEvent = result[6]
- testProcessSucceededEvent instanceof TestFinishEvent &&
- testProcessSucceededEvent.eventTime >= testProcessSucceededEvent.result.endTime &&
- testProcessSucceededEvent.displayName == "Gradle Test Executor 2 succeeded" &&
- testProcessSucceededEvent.descriptor == testProcessStartedEvent.descriptor &&
- testProcessSucceededEvent.result instanceof TestSuccessResult &&
- testProcessSucceededEvent.result.startTime == testProcessStartedEvent.eventTime &&
- testProcessSucceededEvent.result.endTime == testProcessSucceededEvent.eventTime
- def rootSucceededEvent = result[7]
- rootSucceededEvent instanceof TestFinishEvent &&
- rootSucceededEvent.eventTime >= rootSucceededEvent.result.endTime &&
- rootSucceededEvent.displayName == "Gradle Test Run :test succeeded" &&
- rootSucceededEvent.descriptor == rootStartedEvent.descriptor &&
- rootSucceededEvent.result instanceof TestSuccessResult &&
- rootSucceededEvent.result.startTime == rootStartedEvent.eventTime &&
- rootSucceededEvent.result.endTime == rootSucceededEvent.eventTime
+ events.tests.size() == 4
+ def testMethod = events.operation("Test foo(example.MyTest)")
+ testMethod.result instanceof TestSkippedResult
}
@ToolingApiVersion(">=2.5")
@@ -567,26 +373,17 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
"""
when:
- Queue<TestProgressEvent> result = new ConcurrentLinkedQueue<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TestProgressEvent)
- }
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).run()
}
- then: "start and end event is sent for each node in the test tree"
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 2 * (1 + 2 + 2 + 8) // 1 root suite, 2 test processes, 2 tests classes, 8 tests (each with a start and finish event)
-
- then: "each node in the test tree has its own description"
- result.collect { it.descriptor }.toSet().size() == 13
-
- then: "number of nodes under the root suite is equal to the number of test worker processes"
- result.findAll { it.descriptor.parent == null }.toSet().size() == 2 // 1 root suite with no further parent (start & finish events)
+ then:
+ events.tests.size() == (1 + 2 + 2 + 8) // 1 root suite, 2 worker processes, 2 tests classes, 8 tests
+ events.tests == events.successful
+ events.tests[0].descriptor.parent == null // 1 root suite with no further parent
+ events.tests.tail().every { it.descriptor.parent != null }
}
@Requires(TestPrecondition.NOT_WINDOWS)
@@ -594,6 +391,9 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
@TargetGradleVersion(">=2.4")
def "test progress event ids are unique across multiple test tasks, even when run in parallel"() {
given:
+ if (!targetDist.toolingApiEventsInEmbeddedModeSupported) {
+ toolingApi.requireDaemons()
+ }
projectDir.createFile('settings.gradle') << """
include ':sub1'
include ':sub2'
@@ -646,108 +446,60 @@ class TestProgressCrossVersionSpec extends ToolingApiSpecification {
}
when:
- Queue<TestProgressEvent> result = new ConcurrentLinkedQueue<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TestProgressEvent)
- }
- }, EnumSet.of(OperationType.TEST)).withArguments('--parallel').run()
- }
-
- then: "start and end event is sent for each node in the test tree"
- result.size() % 2 == 0 // same number of start events as finish events
- result.size() == 2 * 2 * (1 + 2 + 2 + 6) // two test tasks with each: 1 root suite, 2 test processes, 2 tests classes, 6 tests (each with a start and finish event)
-
- then: "each node in the test tree has its own description"
- result.collect { it.descriptor }.toSet().size() == 2 * 11
-
- then: "number of nodes under the root suite is equal to the number of test worker processes"
- result.findAll { it.descriptor.parent == null }.toSet().size() == 4 // 2 root suites with no further parent (start & finish events)
-
- then: "names for root suites and worker suites are consistent"
- result.findAll { it.descriptor.name =~ 'Gradle Test Run :sub[1|2]:test' }.toSet().size() == 4 // 2 root suites for 2 tasks (start & finish events)
- result.findAll { it.descriptor.name =~ 'Gradle Test Executor \\d+' }.toSet().size() == 8 // 2 test processes for each task (start & finish events)
- }
-
- @TargetGradleVersion(">=2.5")
- @ToolingApiVersion(">=2.4")
- @NotYetImplemented
- def "should receive test events from buildSrc"() {
- buildFile << """task dummy()"""
- file("buildSrc/build.gradle") << """
- apply plugin: 'java'
- repositories { mavenCentral() }
- dependencies { testCompile 'junit:junit:4.12' }
- compileTestJava.options.fork = true // forked as 'Gradle Test Executor 1'
- """
- file("buildSrc/src/test/java/example/MyTest.java") << """
- package example;
- public class MyTest {
- @org.junit.Test public void foo() throws Exception {
- org.junit.Assert.assertEquals(1, 1);
- }
- }
- """
-
- when:
- List<TestProgressEvent> result = new ArrayList<TestProgressEvent>()
- withConnection { ProjectConnection connection ->
- connection.newBuild().forTasks('dummy').addProgressListener({ ProgressEvent event ->
- result << (event as TestProgressEvent)
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).withArguments('--parallel').run()
}
then:
- !result.empty
+ events.tests.size() == 2 * (1 + 2 + 2 + 6) // two test tasks with each: 1 root suite, 2 worker processes, 2 tests classes, 6 tests
+ events.successful.size() == 8 // two test tasks with 4 tests
+ events.failed.size() == 14 // two test tasks with: 1 root suite, 2 worker processes, 2 test classes, 2 tests
+ events.tests.findAll { it.descriptor.parent == null }.size() == 2 // 2 root suites with no further parent
+ events.tests.findAll { it.descriptor.name =~ 'Gradle Test Run :sub[1|2]:test' }.toSet().size() == 2 // 2 root suites for 2 tasks
+ events.tests.findAll { it.descriptor.name =~ 'Gradle Test Executor \\d+' }.toSet().size() == 4 // 2 test processes for each task
}
@TargetGradleVersion(">=2.5")
@ToolingApiVersion(">=2.5")
- def "top-level test operation has test task as parent iff task listener is attached"() {
+ def "top-level test operation has test task as parent if task listener is attached"() {
given:
goodCode()
when: 'listening to test progress events and task listener is attached'
- List<TestProgressEvent> result = new ArrayList<TestProgressEvent>()
+ def events = new ProgressEvents()
withConnection {
ProjectConnection connection ->
- connection.newBuild().forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- if (event instanceof TestProgressEvent) {
- result << event
- }
- }
- }, EnumSet.of(OperationType.TASK, OperationType.TEST)).run()
+ connection.newBuild().forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TASK, OperationType.TEST)).run()
}
then: 'the parent of the root test progress event is the test task that triggered the tests'
- !result.isEmpty()
- [result.first(), result.last()].each { def event ->
- assert event.descriptor.parent instanceof TaskOperationDescriptor
- assert event.descriptor.parent.name == ':test'
- }
+ def test = events.operation("Task :test")
+ events.tests[0].descriptor.parent == test.descriptor
+ events.tests.tail().every { it.descriptor.parent instanceof TestOperationDescriptor }
when: 'listening to test progress events and no task listener is attached'
- result = new ArrayList<TestProgressEvent>()
+ events.clear()
withConnection {
ProjectConnection connection ->
- connection.newBuild().withArguments('--rerun-tasks').forTasks('test').addProgressListener(new ProgressListener() {
- @Override
- void statusChanged(ProgressEvent event) {
- result << (event as TestProgressEvent)
- }
- }, EnumSet.of(OperationType.TEST)).run()
+ connection.newBuild().withArguments('--rerun-tasks').forTasks('test').addProgressListener(events, EnumSet.of(OperationType.TEST)).run()
}
then: 'the parent of the root test progress event is null'
- !result.isEmpty()
- [result.first(), result.last()].each { def event ->
- assert event.descriptor.parent == null
+ events.tests[0].descriptor.parent == null
+ events.tests.tail().every { it.descriptor.parent instanceof TestOperationDescriptor }
+
+ when: 'listening to test progress events and build operation listener is attached'
+ events.clear()
+ withConnection {
+ ProjectConnection connection ->
+ connection.newBuild().withArguments('--rerun-tasks').forTasks('test').addProgressListener(events, EnumSet.of(OperationType.GENERIC, OperationType.TEST)).run()
}
+
+ then: 'the parent of the root test progress event is null'
+ events.tests[0].descriptor.parent == null
+ events.tests.tail().every { it.descriptor.parent instanceof TestOperationDescriptor }
}
def goodCode() {
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r26/BuildProgressCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r26/BuildProgressCrossVersionSpec.groovy
new file mode 100644
index 0000000..6099221
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r26/BuildProgressCrossVersionSpec.groovy
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.r26
+
+import org.gradle.integtests.tooling.fixture.ProgressEvents
+import org.gradle.integtests.tooling.fixture.TargetGradleVersion
+import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
+import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.tooling.ProjectConnection
+
+ at ToolingApiVersion(">=2.5")
+ at TargetGradleVersion(">=2.6")
+class BuildProgressCrossVersionSpec extends ToolingApiSpecification {
+ def "generates init script operation when there are init scripts"() {
+ file("init.gradle") << "println 'init'"
+
+ when:
+ def events = new ProgressEvents()
+ withConnection {
+ ProjectConnection connection ->
+ connection.newBuild()
+ .addProgressListener(events)
+ .run()
+ }
+
+ then:
+ !events.operations.find { it.descriptor.displayName == "Run init scripts" }
+
+ when:
+ events.clear()
+ withConnection {
+ ProjectConnection connection ->
+ connection.newBuild()
+ .withArguments("--init-script", file("init.gradle").toString())
+ .addProgressListener(events)
+ .run()
+ }
+
+ then:
+ def initScripts = events.operation("Run init scripts")
+ initScripts.descriptor.parent == events.operation("Run build").descriptor
+ }
+
+ def "generates buildSrc operation when there is a nested buildSrc build"() {
+ when:
+ def events = new ProgressEvents()
+ withConnection {
+ ProjectConnection connection ->
+ connection.newBuild()
+ .addProgressListener(events)
+ .run()
+ }
+
+ then:
+ !events.operations.find { it.descriptor.displayName == "Build buildSrc" }
+
+ when:
+ events.clear()
+ file("buildSrc/build.gradle") << "println 'buildSrc'"
+ withConnection {
+ ProjectConnection connection ->
+ connection.newBuild()
+ .addProgressListener(events)
+ .run()
+ }
+
+ then:
+ def buildSrc = events.operation("Build buildSrc")
+ buildSrc.descriptor.parent == events.operation("Run build").descriptor
+ }
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r26/TestLauncherCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r26/TestLauncherCrossVersionSpec.groovy
new file mode 100644
index 0000000..7033b8a
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r26/TestLauncherCrossVersionSpec.groovy
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.r26
+
+import groovy.transform.stc.ClosureParams
+import groovy.transform.stc.SimpleType
+import org.gradle.api.GradleException
+import org.gradle.integtests.tooling.TestLauncherSpec
+import org.gradle.integtests.tooling.fixture.TargetGradleVersion
+import org.gradle.integtests.tooling.fixture.TestResultHandler
+import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.tooling.*
+import org.gradle.tooling.events.ProgressEvent
+import org.gradle.tooling.events.ProgressListener
+import org.gradle.tooling.events.test.TestOperationDescriptor
+import org.gradle.tooling.exceptions.UnsupportedBuildArgumentException
+import org.gradle.util.Requires
+import org.gradle.util.TestPrecondition
+
+ at ToolingApiVersion(">=2.6")
+ at TargetGradleVersion(">=2.6")
+class TestLauncherCrossVersionSpec extends TestLauncherSpec {
+
+ def "test launcher api fires progress events"() {
+ given:
+ collectDescriptorsFromBuild()
+ when:
+ launchTests(testDescriptors("example.MyTest"));
+ then:
+ events.assertIsABuild()
+ events.operation("Task :compileJava").successful
+ events.operation("Task :processResources").successful
+ events.operation("Task :classes").successful
+ events.operation("Task :compileTestJava").successful
+ events.operation("Task :processTestResources").successful
+ events.operation("Task :testClasses").successful
+ events.operation("Task :test").successful
+ events.operation("Task :secondTest").successful
+
+ events.operation("Gradle Test Run :test").successful
+ events.operation("Gradle Test Executor 1").successful
+ events.operation("Gradle Test Run :secondTest").successful
+ events.operation("Gradle Test Executor 2").successful
+ events.tests.findAll { it.descriptor.displayName == "Test class example.MyTest" }.size() == 2
+ events.tests.findAll { it.descriptor.displayName == "Test foo(example.MyTest)" }.size() == 2
+ events.tests.findAll { it.descriptor.displayName == "Test foo2(example.MyTest)" }.size() == 2
+ events.tests.findAll { it.descriptor.displayName == "Test class example2.MyOtherTest" }.size() == 2
+ events.tests.size() == 12
+ }
+
+ def "can run specific test class passed via test descriptor"() {
+ given:
+ collectDescriptorsFromBuild()
+ when:
+ launchTests(testDescriptors("example.MyTest"));
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: null) // TODO clarify if this is by design
+ events.tests.size() == 12
+
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":secondTest")
+ }
+
+ def "can run specific test method passed via test descriptor"() {
+ given:
+ collectDescriptorsFromBuild()
+ when:
+ launchTests(testDescriptors("example.MyTest", "foo"));
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ events.tests.size() == 10
+
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ }
+
+ def "runs only test task linked in test descriptor"() {
+ given:
+ collectDescriptorsFromBuild()
+ when:
+ launchTests(testDescriptors("example.MyTest", null, ":secondTest"));
+ then:
+ assertTaskExecuted(":secondTest")
+ assertTaskNotExecuted(":test")
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ events.tests.size() == 6
+
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ }
+
+ def "tests can be executed multiple times without task being up-to-date"() {
+ given:
+ collectDescriptorsFromBuild()
+ and:
+ launchTests(testDescriptors("example.MyTest", null, ":secondTest"))
+ when:
+ launchTests(testDescriptors("example.MyTest", null, ":secondTest"));
+ then:
+ assertTaskNotUpToDate(":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTaskNotExecuted(":test")
+ }
+
+ @Requires(TestPrecondition.JDK7_OR_LATER)
+ def "can run and cancel test execution in continuous mode"() {
+ given:
+ collectDescriptorsFromBuild()
+ when:
+ withConnection { connection ->
+ withCancellation { cancellationToken ->
+ launchTests(connection, new TestResultHandler(), cancellationToken) { TestLauncher launcher ->
+ def testsToLaunch = testDescriptors("example.MyTest", null, ":secondTest")
+ launcher
+ .withTests(testsToLaunch.toArray(new TestOperationDescriptor[testsToLaunch.size()]))
+ .withArguments("-t")
+ }
+
+ waitingForBuild()
+ assertTaskExecuted(":secondTest")
+ assertTaskNotExecuted(":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo3", task: ":secondTest")
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo4", task: ":secondTest")
+ assert events.tests.size() == 6
+ events.clear()
+ changeTestSource()
+ waitingForBuild()
+ }
+ }
+
+ then:
+ assertBuildCancelled()
+ assertTaskExecuted(":secondTest")
+ assertTaskNotExecuted(":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo3", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo4", task: ":secondTest")
+ events.tests.size() == 8
+ }
+
+ public <T> T withCancellation(@ClosureParams(value = SimpleType, options = ["org.gradle.tooling.CancellationToken"]) Closure<T> cl) {
+ return cancellationTokenSource.withCancellation(cl)
+ }
+
+ def "listener errors are rethrown on client side"() {
+ given:
+ collectDescriptorsFromBuild()
+ def descriptors = testDescriptors("example.MyTest")
+ def failingProgressListener = failingProgressListener()
+ when:
+ withConnection { ProjectConnection connection ->
+ def testLauncher = connection.newTestLauncher()
+ testLauncher.addProgressListener(failingProgressListener)
+ testLauncher.withTests(descriptors.toArray(new TestOperationDescriptor[descriptors.size()]))
+ testLauncher.run()
+ };
+ then:
+ def e = thrown(ListenerFailedException)
+ e.cause.message == "failing progress listener"
+ }
+
+ def "fails with meaningful error when no tests declared"() {
+ when:
+ launchTests([])
+ then:
+ def e = thrown(TestExecutionException)
+ e.message == "No test declared for execution."
+ }
+
+ def "build succeeds if test class is only available in one test task"() {
+ given:
+ file("src/moreTests/java/more/MoreTest.java") << """
+ package more;
+ public class MoreTest {
+ @org.junit.Test public void bar() throws Exception {
+ org.junit.Assert.assertEquals(2, 2);
+ }
+ }
+ """
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestClasses("more.MoreTest")
+ }
+ then:
+ assertTaskExecuted(":secondTest")
+ assertTestExecuted(className: "more.MoreTest", methodName: "bar", task: ":secondTest")
+ assertTaskExecuted(":test")
+ events.tests.size() == 10
+ }
+
+ def "fails with meaningful error when test task no longer exists"() {
+ given:
+ collectDescriptorsFromBuild()
+ and:
+ buildFile.text = simpleJavaProject()
+ when:
+ launchTests(testDescriptors("example.MyTest", null, ":secondTest"));
+ then:
+ assertTaskNotExecuted(":secondTest")
+ assertTaskNotExecuted(":test")
+
+ def e = thrown(TestExecutionException)
+ e.cause.message == "Requested test task with path ':secondTest' cannot be found."
+ }
+
+ def "fails with meaningful error when passing invalid arguments"() {
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestClasses("example.MyTest")
+ .withArguments("--someInvalidArgument")
+ }
+ then:
+ def e = thrown(UnsupportedBuildArgumentException)
+ e.message.contains("Unknown command-line option '--someInvalidArgument'.")
+ }
+
+ def "fails with BuildException when build fails"() {
+ given:
+ buildFile << "some invalid build code"
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestClasses("example.MyTest")
+ }
+ then:
+ thrown(BuildException)
+ }
+
+ def "throws BuildCancelledException when build canceled"() {
+ given:
+ buildFile << "some invalid build code"
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestClasses("example.MyTest")
+ launcher.withCancellationToken(cancellationTokenSource.token())
+ cancellationTokenSource.cancel()
+ }
+ then:
+ thrown(BuildCancelledException)
+ }
+
+ def "can execute test class passed by name"() {
+ when:
+ launchTests { TestLauncher testLauncher ->
+ testLauncher.withJvmTestClasses("example.MyTest")
+ }
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ events.tests.size() == 12
+
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":secondTest")
+ }
+
+ def "can execute multiple test classes passed by name"() {
+ setup: "add testcase that should not be exeucted"
+ withFailingTest()
+
+ when:
+ launchTests { TestLauncher testLauncher ->
+ testLauncher.withJvmTestClasses("example.MyTest")
+ testLauncher.withJvmTestClasses("example2.MyOtherTest")
+ }
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":test")
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":secondTest")
+ events.tests.size() == 16
+
+ assertTestNotExecuted(className: "example.MyFailingTest", methodName: "fail", task: ":test")
+ assertTestNotExecuted(className: "example.MyFailingTest", methodName: "fail", task: ":secondTest")
+ }
+
+ def "runs all test tasks in multi project build when test class passed by name"() {
+ setup:
+ settingsFile << "include ':sub1', 'sub2', ':sub2:sub3', ':sub4'"
+ ["sub1", "sub2/sub3"].each { projectFolderName ->
+ file("${projectFolderName}/src/test/java/example/MyTest.java") << """
+ package example;
+ public class MyTest {
+ @org.junit.Test public void foo() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ }
+ """
+ }
+
+ file("sub2/src/test/java/example2/MyOtherTest.java") << """
+ package example2;
+ public class MyOtherTest {
+ @org.junit.Test public void bar() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ }
+ """
+ when:
+ launchTests { TestLauncher testLauncher ->
+ testLauncher.withJvmTestClasses("example.MyTest")
+ testLauncher.withJvmTestClasses("example2.MyOtherTest")
+ }
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+ assertTaskExecuted(":sub1:test")
+ assertTaskExecuted(":sub2:test")
+ assertTaskExecuted(":sub2:sub3:test")
+ assertTaskExecuted(":sub4:test")
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":test")
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":sub1:test")
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":sub2:test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":sub2:sub3:test")
+ events.tests.size() == 10 + 7 + 9
+ }
+
+ def "compatible with configure on demand"() {
+ setup:
+ 10.times {
+ settingsFile << "include ':sub$it'\n"
+ file("sub$it/src/test/java/example/MyTest.java") << """
+ package example;
+ public class MyTest {
+ @org.junit.Test public void foo() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ }
+ """
+ }
+ when:
+ launchTests { TestLauncher testLauncher ->
+ testLauncher.withArguments("--configure-on-demand")
+ testLauncher.withJvmTestClasses("example.MyTest")
+ }
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":sub0:test")
+ assertTaskExecuted(":sub1:test")
+ assertTaskExecuted(":sub2:test")
+ assertTaskExecuted(":sub3:test")
+ assertTaskExecuted(":sub4:test")
+ assertTaskExecuted(":sub5:test")
+ assertTaskExecuted(":sub6:test")
+ assertTaskExecuted(":sub7:test")
+ assertTaskExecuted(":sub8:test")
+ assertTaskExecuted(":sub9:test")
+ }
+
+ ProgressListener failingProgressListener() {
+ new ProgressListener() {
+ @Override
+ void statusChanged(ProgressEvent event) {
+ throw new GradleException("failing progress listener")
+ }
+ }
+ }
+
+ def testCode() {
+ settingsFile << "rootProject.name = 'testproject'\n"
+ buildFile.text = simpleJavaProject()
+
+ buildFile << """
+ sourceSets {
+ moreTests {
+ java.srcDir "src/test"
+ compileClasspath = compileClasspath + sourceSets.test.compileClasspath
+ runtimeClasspath = runtimeClasspath + sourceSets.test.runtimeClasspath
+ }
+ }
+
+ task secondTest(type:Test) {
+ classpath = sourceSets.moreTests.runtimeClasspath
+ testClassesDir = sourceSets.moreTests.output.classesDir
+ }
+
+ build.dependsOn secondTest
+ """
+
+ file("src/test/java/example/MyTest.java") << """
+ package example;
+ public class MyTest {
+ @org.junit.Test public void foo() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo2() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ }
+ """
+
+ file("src/test/java/example2/MyOtherTest.java") << """
+ package example2;
+ public class MyOtherTest {
+ @org.junit.Test public void bar() throws Exception {
+ org.junit.Assert.assertEquals(2, 2);
+ }
+ }
+ """
+ }
+
+ def changeTestSource() {
+ // adding two more test methods
+ file("src/test/java/example/MyTest.java").text = """
+ package example;
+ public class MyTest {
+ @org.junit.Test public void foo() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo2() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo3() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ @org.junit.Test public void foo4() throws Exception {
+ org.junit.Assert.assertEquals(1, 1);
+ }
+ }
+ """
+ }
+
+ def simpleJavaProject() {
+ """
+ allprojects{
+ apply plugin: 'java'
+ repositories { mavenCentral() }
+ dependencies { testCompile 'junit:junit:4.12' }
+ }
+ """
+ }
+
+ def testClassRemoved() {
+ file("src/test/java/example/MyTest.java").delete()
+ }
+
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r27/TestLauncherCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r27/TestLauncherCrossVersionSpec.groovy
new file mode 100644
index 0000000..bdc1241
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r27/TestLauncherCrossVersionSpec.groovy
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.r27
+
+import org.gradle.integtests.tooling.TestLauncherSpec
+import org.gradle.integtests.tooling.fixture.TargetGradleVersion
+import org.gradle.integtests.tooling.fixture.ToolingApiVersion
+import org.gradle.tooling.TestExecutionException
+import org.gradle.tooling.TestLauncher
+
+import static org.gradle.integtests.tooling.fixture.TextUtil.normaliseLineSeparators
+
+ at ToolingApiVersion(">=2.7")
+ at TargetGradleVersion(">=2.7")
+class TestLauncherCrossVersionSpec extends TestLauncherSpec {
+
+ def "can execute test methods of JVM test class"() {
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestMethods("example.MyTest", "foo")
+ }
+ then:
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ events.tests.size() == 12
+
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestNotExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest2", methodName: "baz", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":secondTest")
+ assertTestNotExecuted(className: "example2.MyOtherTest2", methodName: "baz", task: ":secondTest")
+
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestMethods("example.MyTest", "foo", "foo2")
+ launcher.withJvmTestMethods("example2.MyOtherTest", "bar")
+ }
+ then:
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":test")
+ assertTestExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":secondTest")
+ events.tests.size() == 16
+
+ assertTestNotExecuted(className: "example2.MyOtherTest2", methodName: "baz", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest2", methodName: "baz", task: ":secondTest")
+ }
+
+ @TargetGradleVersion("=2.6")
+ def "executes all methods if provider does not support selective test method execution"() {
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestMethods("example.MyTest", "foo")
+ }
+ then:
+
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ events.tests.size() == 14
+
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest2", methodName: "baz", task: ":test")
+ assertTestNotExecuted(className: "example2.MyOtherTest", methodName: "bar", task: ":secondTest")
+ assertTestNotExecuted(className: "example2.MyOtherTest2", methodName: "baz", task: ":secondTest")
+ }
+
+ def "executes all test methods if class and method is declared"() {
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestClasses("example.MyTest")
+ launcher.withJvmTestMethods("example.MyTest", "foo")
+ }
+
+ then:
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":test")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":secondTest")
+ assertTestExecuted(className: "example.MyTest", methodName: "foo2", task: ":test")
+ events.tests.size() == 14
+ }
+
+ def "fails with meaningful error when requested tests not found"() {
+ given:
+ collectDescriptorsFromBuild()
+ and:
+ testClassRemoved()
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestClasses("org.acme.NotExistingTestClass")
+ launcher.withJvmTestMethods("example.MyTest", "unknownMethod")
+ launcher.withJvmTestMethods("example.MyTest", "unknownMethod2")
+ launcher.withJvmTestMethods("example.UnknownClass", "unknownTestMethod3")
+ launcher.withTests(testDescriptors("example2.MyOtherTest", null, ":test"))
+ }
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+ def e = thrown(TestExecutionException)
+ normaliseLineSeparators(e.cause.message) == """No matching tests found in any candidate test task.
+ Requested tests:
+ Test class example2.MyOtherTest (Task: ':test')
+ Test class org.acme.NotExistingTestClass
+ Test method example.MyTest.unknownMethod()
+ Test method example.MyTest.unknownMethod2()
+ Test method example.UnknownClass.unknownTestMethod3()"""
+ }
+
+ def "fails with meaningful error when declared class has no tests"() {
+ given:
+ file("src/test/java/util/TestUtil.java") << """
+ package util;
+ public class TestUtil {
+ static void someUtilsMethod(){}
+ }
+ """
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestClasses("util.TestUtil")
+ }
+ then:
+ def e = thrown(TestExecutionException)
+ normaliseLineSeparators(e.cause.message) == """No matching tests found in any candidate test task.
+ Requested tests:
+ Test class util.TestUtil"""
+ when:
+ launchTests { TestLauncher launcher ->
+ launcher.withJvmTestMethods("util.TestUtil", "someUtilMethod")
+ }
+ then:
+ e = thrown(TestExecutionException)
+ normaliseLineSeparators(e.cause.message) == """No matching tests found in any candidate test task.
+ Requested tests:
+ Test method util.TestUtil.someUtilMethod()"""
+ }
+
+ def "throws exception with meaningful error message on failing tests"() {
+ setup:
+ withFailingTest()
+ when:
+ launchTests { TestLauncher testLauncher ->
+ testLauncher.withJvmTestClasses("example.MyFailingTest")
+ }
+
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+ assertTestExecuted(className: "example.MyFailingTest", methodName: "fail", task: ":test")
+ assertTestExecuted(className: "example.MyFailingTest", methodName: "fail2", task: ":test")
+ assertTestExecuted(className: "example.MyFailingTest", methodName: "fail", task: ":secondTest")
+ assertTestExecuted(className: "example.MyFailingTest", methodName: "fail2", task: ":secondTest")
+ def e = thrown(TestExecutionException)
+ normaliseLineSeparators(e.cause.message) == """Test failed.
+ Failed tests:
+ Test example.MyFailingTest#fail (Task: :secondTest)
+ Test example.MyFailingTest#fail2 (Task: :secondTest)
+ Test example.MyFailingTest#fail (Task: :test)
+ Test example.MyFailingTest#fail2 (Task: :test)"""
+
+ when:
+ launchTests { TestLauncher testLauncher ->
+ testLauncher.withJvmTestMethods("example.MyFailingTest", "fail")
+ }
+
+ then:
+ assertTaskExecuted(":test")
+ assertTaskExecuted(":secondTest")
+ assertTestExecuted(className: "example.MyFailingTest", methodName: "fail", task: ":test")
+ assertTestExecuted(className: "example.MyFailingTest", methodName: "fail", task: ":secondTest")
+ assertTestNotExecuted(className: "example.MyFailingTest", methodName: "fail2", task: ":test")
+ assertTestNotExecuted(className: "example.MyFailingTest", methodName: "fail2", task: ":secondTest")
+ e = thrown(TestExecutionException)
+ normaliseLineSeparators(e.cause.message) == """Test failed.
+ Failed tests:
+ Test example.MyFailingTest#fail (Task: :secondTest)
+ Test example.MyFailingTest#fail (Task: :test)"""
+ }
+
+ def testClassRemoved() {
+ file("src/test/java/example2/MyOtherTest.java").delete()
+ }
+}
diff --git a/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r27/ToolingApiEclipseLinkedResourcesCrossVersionSpec.groovy b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r27/ToolingApiEclipseLinkedResourcesCrossVersionSpec.groovy
new file mode 100644
index 0000000..d954a75
--- /dev/null
+++ b/subprojects/tooling-api/src/integTest/groovy/org/gradle/integtests/tooling/r27/ToolingApiEclipseLinkedResourcesCrossVersionSpec.groovy
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests.tooling.r27
+import org.gradle.integtests.tooling.fixture.TargetGradleVersion
+import org.gradle.integtests.tooling.fixture.ToolingApiSpecification
+import org.gradle.tooling.model.eclipse.EclipseProject
+import static org.gradle.integtests.tooling.fixture.TextUtil.normaliseFileSeparators
+
+ at TargetGradleVersion(">=2.7")
+class ToolingApiEclipseLinkedResourcesCrossVersionSpec extends ToolingApiSpecification {
+
+ def "can references sibling source folders"() {
+ given:
+ settingsFile.text = """
+include ':subprojectA'
+include ':subprojectB'
+"""
+ file('build.gradle').text = '''
+subprojects {
+ apply plugin: 'java'
+}
+'''
+ def projectBsrcSiblingFolder = file('subprojectB/src-sibling')
+ def projectBsrcFolder = file('subprojectB/src')
+ def srcRootFolder1 = file('src-root')
+ def srcRootFolder2 = file('src')
+ def srcFolder = file('subprojectA/src')
+ projectBsrcSiblingFolder.mkdirs()
+ projectBsrcFolder.mkdirs()
+ srcFolder.mkdirs()
+ srcRootFolder1.mkdirs()
+ srcRootFolder2.mkdirs()
+ file('subprojectA/build.gradle').text = """
+sourceSets {
+ main {
+ java {
+ srcDirs = ['src', '../subprojectB/src-sibling', '../src-root', '../src', '../subprojectB/src']
+ }
+ }
+}
+"""
+ when:
+ EclipseProject rootProject = withConnection { it.getModel(EclipseProject.class) }
+ EclipseProject subprojectA = rootProject.children.find {EclipseProject project -> project.name == "subprojectA"}
+ then:
+ subprojectA.linkedResources.size() == 4
+ subprojectA.sourceDirectories.size() == 5
+
+ subprojectA.linkedResources[0].name == 'src-sibling'
+ subprojectA.linkedResources[0].type == '2'
+ subprojectA.linkedResources[0].location == normaliseFileSeparators(projectBsrcSiblingFolder.getAbsolutePath())
+ subprojectA.linkedResources[0].locationUri == null
+
+ subprojectA.linkedResources[1].name == 'src-root'
+ subprojectA.linkedResources[1].type == '2'
+ subprojectA.linkedResources[1].location == normaliseFileSeparators(srcRootFolder1.getAbsolutePath())
+ subprojectA.linkedResources[1].locationUri == null
+
+ subprojectA.linkedResources[2].name == srcRootFolder1.parentFile.name + "-src"
+ subprojectA.linkedResources[2].type == '2'
+ subprojectA.linkedResources[2].location == normaliseFileSeparators(srcRootFolder2.getAbsolutePath())
+ subprojectA.linkedResources[2].locationUri == null
+
+ subprojectA.linkedResources[3].name == projectBsrcFolder.parentFile.name + "-src"
+ subprojectA.linkedResources[3].type == '2'
+ subprojectA.linkedResources[3].location == normaliseFileSeparators(projectBsrcFolder.getAbsolutePath())
+ subprojectA.linkedResources[3].locationUri == null
+
+ subprojectA.sourceDirectories[0].path == "src"
+ subprojectA.sourceDirectories[0].directory == srcFolder
+
+ subprojectA.sourceDirectories[1].path == "src-sibling"
+ subprojectA.sourceDirectories[1].directory == projectBsrcSiblingFolder
+
+ subprojectA.sourceDirectories[2].path == "src-root"
+ subprojectA.sourceDirectories[2].directory == srcRootFolder1
+
+ subprojectA.sourceDirectories[3].path == srcRootFolder1.parentFile.name + "-src"
+ subprojectA.sourceDirectories[3].directory == srcRootFolder2
+
+ subprojectA.sourceDirectories[4].path == projectBsrcFolder.parentFile.name + "-src"
+ subprojectA.sourceDirectories[4].directory == projectBsrcFolder
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildActionExecuter.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildActionExecuter.java
index a6fac9a..f4de021 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildActionExecuter.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildActionExecuter.java
@@ -17,12 +17,6 @@
package org.gradle.tooling;
import org.gradle.api.Incubating;
-import org.gradle.tooling.events.OperationType;
-
-import java.io.File;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Set;
/**
* Used to execute a {@link BuildAction} in the build process.
@@ -31,108 +25,14 @@ import java.util.Set;
* @since 1.8
*/
@Incubating
-public interface BuildActionExecuter<T> extends LongRunningOperation {
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Override
- BuildActionExecuter<T> withArguments(String... arguments);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Override
- BuildActionExecuter<T> setStandardOutput(OutputStream outputStream);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Override
- BuildActionExecuter<T> setStandardError(OutputStream outputStream);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Incubating
- @Override
- BuildActionExecuter<T> setColorOutput(boolean colorOutput);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Override
- BuildActionExecuter<T> setStandardInput(InputStream inputStream);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Override
- BuildActionExecuter<T> setJavaHome(File javaHome);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Override
- BuildActionExecuter<T> setJvmArguments(String... jvmArguments);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Override
- BuildActionExecuter<T> addProgressListener(ProgressListener listener);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.5
- */
- @Incubating
- @Override
- BuildActionExecuter<T> addProgressListener(org.gradle.tooling.events.ProgressListener listener);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.5
- */
- @Incubating
- @Override
- BuildActionExecuter<T> addProgressListener(org.gradle.tooling.events.ProgressListener listener, Set<OperationType> eventTypes);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Incubating
- @Override
- BuildActionExecuter<T> withCancellationToken(CancellationToken cancellationToken);
+public interface BuildActionExecuter<T> extends ConfigurableLauncher<BuildActionExecuter<T>> {
/**
* Runs the action, blocking until its result is available.
*
* @throws UnsupportedVersionException When the target Gradle version does not support build action execution.
* @throws org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException
- * When the target Gradle version does not support some requested configuration option such as
- * {@link #setStandardInput(java.io.InputStream)}, {@link #setJavaHome(java.io.File)},
- * {@link #setJvmArguments(String...)}.
+ * When the target Gradle version does not support some requested configuration option.
* @throws org.gradle.tooling.exceptions.UnsupportedBuildArgumentException When there is a problem with build arguments provided by {@link #withArguments(String...)}.
* @throws BuildActionFailureException When the build action fails with an exception.
* @throws BuildCancelledException When the operation was cancelled before it completed successfully.
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildLauncher.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildLauncher.java
index eeabd39..bb8d00e 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildLauncher.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/BuildLauncher.java
@@ -16,15 +16,9 @@
package org.gradle.tooling;
import org.gradle.api.Incubating;
-import org.gradle.tooling.events.OperationType;
import org.gradle.tooling.model.Launchable;
import org.gradle.tooling.model.Task;
-import java.io.File;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Set;
-
/**
* A {@code BuildLauncher} allows you to configure and execute a Gradle build.
* <p>
@@ -74,89 +68,7 @@ import java.util.Set;
*
* @since 1.0-milestone-3
*/
-public interface BuildLauncher extends LongRunningOperation {
- /**
- * {@inheritDoc}
- * @since 1.0
- */
- @Override
- BuildLauncher withArguments(String ... arguments);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-3
- */
- @Override
- BuildLauncher setStandardOutput(OutputStream outputStream);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-3
- */
- @Override
- BuildLauncher setStandardError(OutputStream outputStream);
-
- /**
- * {@inheritDoc}
- * @since 2.3
- */
- @Incubating
- @Override
- BuildLauncher setColorOutput(boolean colorOutput);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-7
- */
- @Override
- BuildLauncher setStandardInput(InputStream inputStream);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-8
- */
- @Override
- BuildLauncher setJavaHome(File javaHome);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-9
- */
- @Override
- BuildLauncher setJvmArguments(String... jvmArguments);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-3
- */
- @Override
- BuildLauncher addProgressListener(ProgressListener listener);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.5
- */
- @Incubating
- @Override
- BuildLauncher addProgressListener(org.gradle.tooling.events.ProgressListener listener);
-
- /**
- * {@inheritDoc}
- * @since 2.5
- */
- @Incubating
- @Override
- BuildLauncher addProgressListener(org.gradle.tooling.events.ProgressListener listener, Set<OperationType> eventTypes);
-
- /**
- * {@inheritDoc}
- *
- * @since 2.3
- */
- @Incubating
- @Override
- BuildLauncher withCancellationToken(CancellationToken cancellationToken);
+public interface BuildLauncher extends ConfigurableLauncher<BuildLauncher> {
/**
* Sets the tasks to be executed. If no tasks are specified, the project's default tasks are executed.
@@ -214,9 +126,7 @@ public interface BuildLauncher extends LongRunningOperation {
*
* @throws UnsupportedVersionException When the target Gradle version does not support build execution.
* @throws org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException
- * When the target Gradle version does not support some requested configuration option such as
- * {@link #setStandardInput(java.io.InputStream)}, {@link #setJavaHome(java.io.File)},
- * {@link #setJvmArguments(String...)}.
+ * When the target Gradle version does not support some requested configuration option such as {@link #withArguments(String...)}.
* @throws org.gradle.tooling.exceptions.UnsupportedBuildArgumentException When there is a problem with build arguments provided by {@link #withArguments(String...)}.
* @throws BuildException On some failure executing the Gradle build.
* @throws BuildCancelledException When the operation was cancelled before it completed successfully.
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/ConfigurableLauncher.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/ConfigurableLauncher.java
new file mode 100644
index 0000000..5140769
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/ConfigurableLauncher.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling;
+
+import org.gradle.api.Incubating;
+import org.gradle.tooling.events.OperationType;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Set;
+
+/**
+ * A {@code ConfigurableLauncher} allows you to configure a long running operation.
+ *
+ * @param <T> the ConfigurableLauncher implementation to return as part of the fluent API.
+ * @since 2.6
+ * */
+public interface ConfigurableLauncher<T extends ConfigurableLauncher> extends LongRunningOperation {
+ /**
+ * {@inheritDoc}
+ * @since 1.0
+ */
+ @Override
+ T withArguments(String ... arguments);
+
+ /**
+ * {@inheritDoc}
+ * @since 2.6
+ */
+ @Override
+ T withArguments(Iterable<String> arguments);
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0-milestone-3
+ */
+ @Override
+ T setStandardOutput(OutputStream outputStream);
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0-milestone-3
+ */
+ @Override
+ T setStandardError(OutputStream outputStream);
+
+ /**
+ * {@inheritDoc}
+ * @since 2.3
+ */
+ @Incubating
+ @Override
+ T setColorOutput(boolean colorOutput);
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0-milestone-7
+ */
+ @Override
+ T setStandardInput(InputStream inputStream);
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0-milestone-8
+ */
+ @Override
+ T setJavaHome(File javaHome);
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0-milestone-9
+ */
+ @Override
+ T setJvmArguments(String... jvmArguments);
+
+ /**
+ * {@inheritDoc}
+ * @since 2.6
+ */
+ @Override
+ T setJvmArguments(Iterable<String> jvmArguments);
+
+ /**
+ * {@inheritDoc}
+ * @since 1.0-milestone-3
+ */
+ @Override
+ T addProgressListener(ProgressListener listener);
+
+ /**
+ * {@inheritDoc}
+ * @since 2.5
+ */
+ @Incubating
+ @Override
+ T addProgressListener(org.gradle.tooling.events.ProgressListener listener);
+
+ /**
+ * {@inheritDoc}
+ * @since 2.5
+ */
+ @Incubating
+ @Override
+ T addProgressListener(org.gradle.tooling.events.ProgressListener listener, Set<OperationType> eventTypes);
+
+ /**
+ * {@inheritDoc}
+ * @since 2.6
+ */
+ @Incubating
+ @Override
+ T addProgressListener(org.gradle.tooling.events.ProgressListener listener, OperationType... operationTypes);
+
+ /**
+ * {@inheritDoc}
+ * @since 2.3
+ */
+ @Incubating
+ @Override
+ T withCancellationToken(CancellationToken cancellationToken);
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/LongRunningOperation.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/LongRunningOperation.java
index 94f90e3..a302d8c 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/LongRunningOperation.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/LongRunningOperation.java
@@ -16,6 +16,7 @@
package org.gradle.tooling;
import org.gradle.api.Incubating;
+import org.gradle.api.Nullable;
import org.gradle.tooling.events.OperationType;
import java.io.File;
@@ -63,6 +64,8 @@ public interface LongRunningOperation {
/**
* Specifies whether to generate colored (ANSI encoded) output for logging. The default is to not generate color output.
*
+ * <p>Supported by Gradle 2.3 or later. Ignored for older versions.</p>
+ *
* @param colorOutput {@code true} to request color output (using ANSI encoding).
* @return this
* @since 2.3
@@ -73,9 +76,6 @@ public interface LongRunningOperation {
/**
* Sets the {@link java.io.InputStream} that will be used as standard input for this operation.
* Defaults to an empty input stream.
- * <p>
- * If the target Gradle version does not support it the long running operation will fail with
- * {@link org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException} when the operation is started.
*
* @param inputStream The input stream
* @return this
@@ -86,9 +86,6 @@ public interface LongRunningOperation {
/**
* Specifies the Java home directory to use for this operation.
* <p>
- * If the target Gradle version does not support it the long running operation will fail eagerly with
- * {@link org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException} when the operation is started.
- * <p>
* {@link org.gradle.tooling.model.build.BuildEnvironment} model contains information such as Java or Gradle environment.
* If you want to get hold of this information you can ask tooling API to build this model.
* <p>
@@ -99,14 +96,11 @@ public interface LongRunningOperation {
* @throws IllegalArgumentException when supplied javaHome is not a valid folder.
* @since 1.0-milestone-8
*/
- LongRunningOperation setJavaHome(File javaHome) throws IllegalArgumentException;
+ LongRunningOperation setJavaHome(@Nullable File javaHome) throws IllegalArgumentException;
/**
* Specifies the Java VM arguments to use for this operation.
* <p>
- * If the target Gradle version does not support it the long running operation will fail eagerly with
- * {@link org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException} when the operation is started.
- * <p>
* {@link org.gradle.tooling.model.build.BuildEnvironment} model contains information such as Java or Gradle environment.
* If you want to get hold of this information you can ask tooling API to build this model.
* <p>
@@ -114,9 +108,23 @@ public interface LongRunningOperation {
*
* @param jvmArguments to use for the Gradle process
* @return this
- * @since 1.0-milestone-9
+ * @since 1.0-milestone-8
*/
- LongRunningOperation setJvmArguments(String... jvmArguments);
+ LongRunningOperation setJvmArguments(@Nullable String... jvmArguments);
+
+ /**
+ * Specifies the Java VM arguments to use for this operation.
+ * <p>
+ * {@link org.gradle.tooling.model.build.BuildEnvironment} model contains information such as Java or Gradle environment.
+ * If you want to get hold of this information you can ask tooling API to build this model.
+ * <p>
+ * If not configured, null, or an empty list is passed, then the reasonable default will be used.
+ *
+ * @param jvmArguments to use for the Gradle process
+ * @return this
+ * @since 2.6
+ */
+ LongRunningOperation setJvmArguments(@Nullable Iterable<String> jvmArguments);
/**
* Specify the command line build arguments. Useful mostly for running tasks via {@link BuildLauncher}.
@@ -145,15 +153,36 @@ public interface LongRunningOperation {
*
* If not configured, null, or an empty array is passed, then the reasonable default will be used.
*
+ * <p>Requires Gradle 1.0 or later.</p>
+ *
* @param arguments Gradle command line arguments
* @return this
* @since 1.0
*/
- LongRunningOperation withArguments(String... arguments);
+ LongRunningOperation withArguments(@Nullable String... arguments);
+
+ /**
+ * Specify the command line build arguments. Useful mostly for running tasks via {@link BuildLauncher}.
+ * <p>
+ * If not configured, null, or an empty list is passed, then the reasonable default will be used.
+ *
+ * <p>Requires Gradle 1.0 or later.</p>
+ *
+ * @param arguments Gradle command line arguments
+ * @return this
+ * @since 2.6
+ */
+ LongRunningOperation withArguments(@Nullable Iterable<String> arguments);
/**
* Adds a progress listener which will receive progress events as the operation runs.
*
+ * <p>This method is intended to be replaced by {@link #addProgressListener(org.gradle.tooling.events.ProgressListener)}. The new progress listener type
+ * provides much richer information and much better handling of parallel operations that run during the build, such as tasks that run in parallel.
+ * You should prefer using the new listener interface where possible. Note, however, that the new interface is supported only for Gradle 2.5 and later
+ * and is currently {@link Incubating}. It may change in later Gradle releases.
+ * </p>
+ *
* @param listener The listener
* @return this
* @since 1.0-milestone-7
@@ -163,6 +192,12 @@ public interface LongRunningOperation {
/**
* Adds a progress listener which will receive progress events of all types as the operation runs.
*
+ * <p>This method is intended to replace {@link #addProgressListener(ProgressListener)}. You should prefer using the new progress listener method where possible,
+ * as the new interface provides much richer information and much better handling of parallel operations that run during the build.
+ * </p>
+ *
+ * <p>Supported by Gradle 2.5 or later. Gradle 2.4 supports {@link OperationType#TEST} operations only. Ignored for older versions.</p>
+ *
* @param listener The listener
* @return this
* @since 2.5
@@ -173,6 +208,12 @@ public interface LongRunningOperation {
/**
* Adds a progress listener which will receive progress events as the operations of the requested type run.
*
+ * <p>This method is intended to replace {@link #addProgressListener(ProgressListener)}. You should prefer using the new progress listener method where possible,
+ * as the new interface provides much richer information and much better handling of parallel operations that run during the build.
+ * </p>
+ *
+ * <p>Supported by Gradle 2.5 or later. Gradle 2.4 supports {@link OperationType#TEST} operations only. Ignored for older versions.</p>
+ *
* @param listener The listener
* @param operationTypes The types of operations to receive progress events for.
* @return this
@@ -182,8 +223,26 @@ public interface LongRunningOperation {
LongRunningOperation addProgressListener(org.gradle.tooling.events.ProgressListener listener, Set<OperationType> operationTypes);
/**
+ * Adds a progress listener which will receive progress events as the operations of the requested type run.
+ *
+ * <p>This method is intended to replace {@link #addProgressListener(ProgressListener)}. You should prefer using the new progress listener method where possible,
+ * as the new interface provides much richer information and much better handling of parallel operations that run during the build.
+ * </p>
+ *
+ * <p>Supported by Gradle 2.5 or later. Gradle 2.4 supports {@link OperationType#TEST} operations only. Ignored for older versions.</p>
+ *
+ * @param listener The listener
+ * @param operationTypes The types of operations to receive progress events for.
+ * @return this
+ * @since 2.6
+ */
+ LongRunningOperation addProgressListener(org.gradle.tooling.events.ProgressListener listener, OperationType... operationTypes);
+
+ /**
* Sets the cancellation token to use to cancel the operation if required.
*
+ * <p>Supported by Gradle 2.1 or later. Ignored for older versions.</p>
+ *
* @since 2.1
*/
@Incubating
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/ModelBuilder.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/ModelBuilder.java
index 1d4136d..026d027 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/ModelBuilder.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/ModelBuilder.java
@@ -16,12 +16,6 @@
package org.gradle.tooling;
import org.gradle.api.Incubating;
-import org.gradle.tooling.events.OperationType;
-
-import java.io.File;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Set;
/**
* A {@code ModelBuilder} allows you to fetch a snapshot of some model for a project or a build.
@@ -68,89 +62,19 @@ import java.util.Set;
* @param <T> The type of model to build
* @since 1.0-milestone-3
*/
-public interface ModelBuilder<T> extends LongRunningOperation {
-
- /**
- * {@inheritDoc}
- * @since 1.0
- */
- @Override
- ModelBuilder<T> withArguments(String ... arguments);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-3
- */
- @Override
- ModelBuilder<T> setStandardOutput(OutputStream outputStream);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-3
- */
- @Override
- ModelBuilder<T> setStandardError(OutputStream outputStream);
-
- /**
- * {@inheritDoc}
- * @since 2.3
- */
- @Incubating
- @Override
- ModelBuilder<T> setColorOutput(boolean colorOutput);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-7
- */
- @Override
- ModelBuilder<T> setStandardInput(InputStream inputStream);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-8
- */
- @Override
- ModelBuilder<T> setJavaHome(File javaHome);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-9
- */
- @Override
- ModelBuilder<T> setJvmArguments(String... jvmArguments);
-
- /**
- * {@inheritDoc}
- * @since 1.0-milestone-3
- */
- @Override
- ModelBuilder<T> addProgressListener(ProgressListener listener);
+public interface ModelBuilder<T> extends ConfigurableLauncher<ModelBuilder<T>> {
/**
- * {@inheritDoc}
+ * Specifies the tasks to execute before building the model.
*
- * @since 2.5
- */
- @Incubating
- @Override
- ModelBuilder<T> addProgressListener(org.gradle.tooling.events.ProgressListener listener);
-
- /**
- * {@inheritDoc}
- * @since 2.5
- */
- @Incubating
- @Override
- ModelBuilder<T> addProgressListener(org.gradle.tooling.events.ProgressListener listener, Set<OperationType> eventTypes);
-
- /**
- * {@inheritDoc}
- * @since 2.3
+ * If not configured, null, or an empty array is passed, then no tasks will be executed.
+ *
+ * @param tasks The paths of the tasks to be executed. Relative paths are evaluated relative to the project for which this launcher was created.
+ * @return this
+ * @since 1.2
*/
@Incubating
- @Override
- ModelBuilder<T> withCancellationToken(CancellationToken cancellationToken);
+ ModelBuilder<T> forTasks(String... tasks);
/**
* Specifies the tasks to execute before building the model.
@@ -159,10 +83,10 @@ public interface ModelBuilder<T> extends LongRunningOperation {
*
* @param tasks The paths of the tasks to be executed. Relative paths are evaluated relative to the project for which this launcher was created.
* @return this
- * @since 1.2
+ * @since 2.6
*/
@Incubating
- ModelBuilder<T> forTasks(String... tasks);
+ ModelBuilder<T> forTasks(Iterable<String> tasks);
/**
* Fetch the model, blocking until it is available.
@@ -171,9 +95,7 @@ public interface ModelBuilder<T> extends LongRunningOperation {
* @throws UnsupportedVersionException When the target Gradle version does not support building models.
* @throws UnknownModelException When the target Gradle version or build does not support the requested model.
* @throws org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException
- * When the target Gradle version does not support some requested configuration option such as
- * {@link #setStandardInput(java.io.InputStream)}, {@link #setJavaHome(java.io.File)},
- * {@link #setJvmArguments(String...)}.
+ * When the target Gradle version does not support some requested configuration option such as {@link #withArguments(String...)}.
* @throws org.gradle.tooling.exceptions.UnsupportedBuildArgumentException When there is a problem with build arguments provided by {@link #withArguments(String...)}.
* @throws BuildException On some failure executing the Gradle build.
* @throws BuildCancelledException When the operation was cancelled before it completed successfully.
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/ProjectConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/ProjectConnection.java
index 848be09..609d188 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/ProjectConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/ProjectConnection.java
@@ -46,6 +46,7 @@ import org.gradle.api.Incubating;
* <p>All implementations of {@code ProjectConnection} are thread-safe, and may be shared by any number of threads.</p>
*
* <p>All notifications from a given {@code ProjectConnection} instance are delivered by a single thread at a time. Note, however, that the delivery thread may change over time.</p>
+ *
* @since 1.0-milestone-3
*/
public interface ProjectConnection {
@@ -86,12 +87,25 @@ public interface ProjectConnection {
/**
* Creates a launcher which can be used to execute a build.
*
+ * <p>Requires Gradle 1.0-milestone-8 or later.</p>
+ *
* @return The launcher.
* @since 1.0-milestone-3
*/
BuildLauncher newBuild();
/**
+ * Creates a test launcher which can be used to execute tests.
+ *
+ * <p>Requires Gradle 2.6 or later.</p>
+ *
+ * @return The launcher.
+ * @since 2.6
+ */
+ @Incubating
+ TestLauncher newTestLauncher();
+
+ /**
* Creates a builder which can be used to query the model of the given type.
*
* <p>Any of following models types may be available, depending on the version of Gradle being used by the target
@@ -111,6 +125,8 @@ public interface ProjectConnection {
*
* <p>A build may also expose additional custom tooling models. You can use this method to query these models.
*
+ * <p>Requires Gradle 1.0-milestone-8 or later.</p>
+ *
* @param modelType The model type
* @param <T> The model type.
* @return The builder.
@@ -122,6 +138,8 @@ public interface ProjectConnection {
* Creates an executer which can be used to run the given action. The action is serialized into the build
* process and executed, then its result is serialized back to the caller.
*
+ * <p>Requires Gradle 1.8 or later.</p>
+ *
* @param buildAction The action to run.
* @param <T> The result type.
* @return The builder.
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/TestExecutionException.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/TestExecutionException.java
new file mode 100644
index 0000000..1fa41c4
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/TestExecutionException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling;
+
+import org.gradle.api.Incubating;
+
+/**
+ * Thrown when the {@link org.gradle.tooling.TestLauncher} cannot run tests, or when one or more tests fail.
+ * <p>
+ *
+ * @since 2.6
+ */
+ at Incubating
+public class TestExecutionException extends GradleConnectionException {
+ public TestExecutionException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
+
+ public TestExecutionException(String message) {
+ super(message);
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/TestLauncher.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/TestLauncher.java
new file mode 100644
index 0000000..0b0e986
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/TestLauncher.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling;
+
+import org.gradle.api.Incubating;
+import org.gradle.tooling.events.test.TestOperationDescriptor;
+
+/**
+ *
+ * A {@code TestLauncher} allows you to execute tests in a Gradle build.
+ *
+ * @since 2.6
+ */
+ at Incubating
+public interface TestLauncher extends ConfigurableLauncher<TestLauncher> {
+
+ /**
+ * Adds tests to be executed by passing test descriptors received from a previous Gradle Run.
+ *
+ * @param descriptors The OperationDescriptor defining one or more tests.
+ * @return this
+ * @since 2.6
+ */
+ TestLauncher withTests(TestOperationDescriptor... descriptors);
+
+ /**
+ * Adds tests to be executed by passing test descriptors received from a previous Gradle Run.
+ *
+ * @param descriptors The OperationDescriptor defining one or more tests.
+ * @return this
+ * @since 2.6
+ */
+ TestLauncher withTests(Iterable<? extends TestOperationDescriptor> descriptors);
+
+ /**
+ * Adds tests to be executed declared by class name.
+ *
+ * @param testClasses The class names of the tests to be executed.
+ * @return this
+ * @since 2.6
+ */
+ TestLauncher withJvmTestClasses(String... testClasses);
+
+ /**
+ * Adds tests to be executed declared by class name.
+ *
+ * @param testClasses The class names of the tests to be executed.
+ * @return this
+ * @since 2.6
+ */
+ TestLauncher withJvmTestClasses(Iterable<String> testClasses);
+
+ /**
+ * Adds tests to be executed declared by class and method name.
+ *
+ * @param testClass The name of the class containing the methods to execute.
+ * @param methods The names of the test methods to be executed.
+ * @return this
+ * @since 2.7
+ */
+ TestLauncher withJvmTestMethods(String testClass, String... methods);
+
+ /**
+ * Adds tests to be executed declared by class and methods name.
+ *
+ * @param testClass The name of the class containing the methods to execute.
+ * @param methods The names of the test methods to be executed.
+ * @return this
+ * @since 2.7
+ */
+ TestLauncher withJvmTestMethods(String testClass, Iterable<String> methods);
+
+ /**
+ * Executes the tests, blocking until complete.
+ *
+ * @throws TestExecutionException when one or more tests fail, or no tests for execution declared or no matching tests can be found.
+ * @throws UnsupportedVersionException When the target Gradle version does not support test execution.
+ * @throws org.gradle.tooling.exceptions.UnsupportedBuildArgumentException When there is a problem with build arguments provided by {@link #withArguments(String...)}.
+ * @throws org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException
+ * When the target Gradle version does not support some requested configuration option.
+ * @throws BuildException On some failure while executing the tests in the Gradle build.
+ * @throws BuildCancelledException When the operation was cancelled before it completed successfully.
+ * @throws GradleConnectionException On some other failure using the connection.
+ * @throws IllegalStateException When the connection has been closed or is closing.
+ * @since 2.6
+ */
+ void run() throws TestExecutionException;
+
+ /**
+ * Starts executing the tests. This method returns immediately, and the result is later passed to the given handler.
+ *
+ * <p>If the operation fails, the handler's {@link ResultHandler#onFailure(GradleConnectionException)}
+ * method is called with the appropriate exception. See {@link #run()} for a description of the various exceptions that the operation may fail with.
+ *
+ * @param handler The handler to supply the result to.
+ * @throws IllegalStateException When the connection has been closed or is closing.
+ * @since 2.6
+ */
+ void run(ResultHandler<? super Void> handler);
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/OperationDescriptor.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/OperationDescriptor.java
index 27f8879..fcfdf18 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/OperationDescriptor.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/OperationDescriptor.java
@@ -17,6 +17,7 @@ package org.gradle.tooling.events;
import org.gradle.api.Incubating;
import org.gradle.api.Nullable;
+import org.gradle.internal.HasInternalProtocol;
/**
* Describes an operation for which an event has occurred.
@@ -28,6 +29,7 @@ import org.gradle.api.Nullable;
* @since 2.4
*/
@Incubating
+ at HasInternalProtocol
public interface OperationDescriptor {
/**
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/ProgressListener.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/ProgressListener.java
index c1e1c2d..0bdb9b0 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/ProgressListener.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/ProgressListener.java
@@ -22,7 +22,7 @@ import org.gradle.api.Incubating;
* A listener which is notified when operations that are executed as part of running a build make progress.
*
* @see org.gradle.tooling.LongRunningOperation#addProgressListener(ProgressListener)
- * @see org.gradle.tooling.LongRunningOperation#addProgressListener(ProgressListener, java.util.EnumSet)
+ * @see org.gradle.tooling.LongRunningOperation#addProgressListener(ProgressListener, java.util.Set)
* @since 2.5
*/
@Incubating
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/internal/DefaultOperationDescriptor.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/internal/DefaultOperationDescriptor.java
index 066c844..606a507 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/internal/DefaultOperationDescriptor.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/internal/DefaultOperationDescriptor.java
@@ -18,20 +18,23 @@ package org.gradle.tooling.events.internal;
import org.gradle.api.Nullable;
import org.gradle.tooling.events.OperationDescriptor;
+import org.gradle.tooling.internal.protocol.events.InternalOperationDescriptor;
/**
* Implementation of the {@code BuildOperationDescriptor} interface.
*/
-public class DefaultOperationDescriptor implements OperationDescriptor {
+public class DefaultOperationDescriptor implements OperationDescriptor, OperationDescriptorWrapper {
private final String name;
private final String displayName;
private final OperationDescriptor parent;
+ private InternalOperationDescriptor internalDescriptor;
- public DefaultOperationDescriptor(String name, String displayName, OperationDescriptor parent) {
- this.name = name;
- this.displayName = displayName;
+ public DefaultOperationDescriptor(InternalOperationDescriptor internalDescriptor, OperationDescriptor parent) {
+ this.name = internalDescriptor.getName();
+ this.displayName = internalDescriptor.getDisplayName();
this.parent = parent;
+ this.internalDescriptor = internalDescriptor;
}
@Override
@@ -55,4 +58,8 @@ public class DefaultOperationDescriptor implements OperationDescriptor {
return getDisplayName();
}
+ @Override
+ public InternalOperationDescriptor getInternalOperationDescriptor() {
+ return internalDescriptor;
+ }
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/internal/OperationDescriptorWrapper.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/internal/OperationDescriptorWrapper.java
new file mode 100644
index 0000000..80d161b
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/internal/OperationDescriptorWrapper.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.events.internal;
+
+import org.gradle.tooling.internal.protocol.events.InternalOperationDescriptor;
+
+public interface OperationDescriptorWrapper {
+ InternalOperationDescriptor getInternalOperationDescriptor();
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/task/internal/DefaultTaskOperationDescriptor.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/task/internal/DefaultTaskOperationDescriptor.java
index d58a10f..6a6e35c 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/task/internal/DefaultTaskOperationDescriptor.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/task/internal/DefaultTaskOperationDescriptor.java
@@ -19,6 +19,7 @@ package org.gradle.tooling.events.task.internal;
import org.gradle.tooling.events.OperationDescriptor;
import org.gradle.tooling.events.internal.DefaultOperationDescriptor;
import org.gradle.tooling.events.task.TaskOperationDescriptor;
+import org.gradle.tooling.internal.protocol.events.InternalTaskDescriptor;
/**
* Implementation of the {@code TaskOperationDescriptor} interface.
@@ -27,8 +28,8 @@ public final class DefaultTaskOperationDescriptor extends DefaultOperationDescri
private final String taskPath;
- public DefaultTaskOperationDescriptor(String name, String displayName, String taskPath, OperationDescriptor parent) {
- super(name, displayName, parent);
+ public DefaultTaskOperationDescriptor(InternalTaskDescriptor descriptor, String taskPath, OperationDescriptor parent) {
+ super(descriptor, parent);
this.taskPath = taskPath;
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultJvmTestOperationDescriptor.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultJvmTestOperationDescriptor.java
index 6e920a3..926f0ec 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultJvmTestOperationDescriptor.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultJvmTestOperationDescriptor.java
@@ -20,19 +20,19 @@ import org.gradle.api.Nullable;
import org.gradle.tooling.events.OperationDescriptor;
import org.gradle.tooling.events.test.JvmTestKind;
import org.gradle.tooling.events.test.JvmTestOperationDescriptor;
+import org.gradle.tooling.internal.protocol.events.InternalJvmTestDescriptor;
/**
* Implementation of the {@code JvmTestOperationDescriptor} interface.
*/
public final class DefaultJvmTestOperationDescriptor extends DefaultTestOperationDescriptor implements JvmTestOperationDescriptor {
-
private final JvmTestKind jvmTestKind;
private final String suiteName;
private final String className;
private final String methodName;
- public DefaultJvmTestOperationDescriptor(String name, String displayName, OperationDescriptor parent, JvmTestKind jvmTestKind, String suiteName, String className, String methodName) {
- super(name, displayName, parent);
+ public DefaultJvmTestOperationDescriptor(InternalJvmTestDescriptor internalJvmTestDescriptor, OperationDescriptor parent, JvmTestKind jvmTestKind, String suiteName, String className, String methodName) {
+ super(internalJvmTestDescriptor, parent);
this.jvmTestKind = jvmTestKind;
this.suiteName = suiteName;
this.className = className;
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultTestOperationDescriptor.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultTestOperationDescriptor.java
index 1686348..3b5d518 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultTestOperationDescriptor.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/events/test/internal/DefaultTestOperationDescriptor.java
@@ -19,14 +19,14 @@ package org.gradle.tooling.events.test.internal;
import org.gradle.tooling.events.OperationDescriptor;
import org.gradle.tooling.events.internal.DefaultOperationDescriptor;
import org.gradle.tooling.events.test.TestOperationDescriptor;
+import org.gradle.tooling.internal.protocol.events.InternalTestDescriptor;
/**
* Implementation of the {@code TestOperationDescriptor} interface.
*/
public class DefaultTestOperationDescriptor extends DefaultOperationDescriptor implements TestOperationDescriptor {
- public DefaultTestOperationDescriptor(String name, String displayName, OperationDescriptor parent) {
- super(name, displayName, parent);
+ public DefaultTestOperationDescriptor(InternalTestDescriptor internalTestDescriptor, OperationDescriptor parent) {
+ super(internalTestDescriptor, parent);
}
-
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/AbstractLongRunningOperation.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/AbstractLongRunningOperation.java
index 0b1e2c7..3f68373 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/AbstractLongRunningOperation.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/AbstractLongRunningOperation.java
@@ -16,16 +16,21 @@
package org.gradle.tooling.internal.consumer;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import org.gradle.api.Nullable;
import org.gradle.tooling.CancellationToken;
import org.gradle.tooling.LongRunningOperation;
import org.gradle.tooling.ProgressListener;
import org.gradle.tooling.events.OperationType;
import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
+import org.gradle.util.CollectionUtils;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
import java.util.EnumSet;
+import java.util.List;
import java.util.Set;
public abstract class AbstractLongRunningOperation<T extends AbstractLongRunningOperation<T>> implements LongRunningOperation {
@@ -45,9 +50,23 @@ public abstract class AbstractLongRunningOperation<T extends AbstractLongRunning
return operationParamsBuilder.setParameters(connectionParameters).build();
}
+ protected static @Nullable <T> List<T> rationalizeInput(@Nullable T[] arguments) {
+ return arguments != null && arguments.length > 0 ? Arrays.asList(arguments) : null;
+ }
+
+ protected static @Nullable <T> List<T> rationalizeInput(@Nullable Iterable<? extends T> arguments) {
+ return arguments != null && arguments.iterator().hasNext() ? CollectionUtils.toList(arguments) : null;
+ }
+
@Override
public T withArguments(String... arguments) {
- operationParamsBuilder.setArguments(arguments);
+ operationParamsBuilder.setArguments(rationalizeInput(arguments));
+ return getThis();
+ }
+
+ @Override
+ public T withArguments(Iterable<String> arguments) {
+ operationParamsBuilder.setArguments(rationalizeInput(arguments));
return getThis();
}
@@ -83,7 +102,13 @@ public abstract class AbstractLongRunningOperation<T extends AbstractLongRunning
@Override
public T setJvmArguments(String... jvmArguments) {
- operationParamsBuilder.setJvmArguments(jvmArguments);
+ operationParamsBuilder.setJvmArguments(rationalizeInput(jvmArguments));
+ return getThis();
+ }
+
+ @Override
+ public T setJvmArguments(Iterable<String> jvmArguments) {
+ operationParamsBuilder.setJvmArguments(rationalizeInput(jvmArguments));
return getThis();
}
@@ -99,6 +124,11 @@ public abstract class AbstractLongRunningOperation<T extends AbstractLongRunning
}
@Override
+ public T addProgressListener(org.gradle.tooling.events.ProgressListener listener, OperationType... operationTypes) {
+ return addProgressListener(listener, ImmutableSet.copyOf(operationTypes));
+ }
+
+ @Override
public T addProgressListener(org.gradle.tooling.events.ProgressListener listener, Set<OperationType> eventTypes) {
if (eventTypes.contains(OperationType.TEST)) {
operationParamsBuilder.addTestProgressListener(listener);
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ConnectionFactory.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ConnectionFactory.java
index dfa7b55..2b780c3 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ConnectionFactory.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ConnectionFactory.java
@@ -22,6 +22,7 @@ import org.gradle.tooling.internal.consumer.async.DefaultAsyncConsumerActionExec
import org.gradle.tooling.internal.consumer.connection.ConsumerActionExecutor;
import org.gradle.tooling.internal.consumer.connection.LazyConsumerActionExecutor;
import org.gradle.tooling.internal.consumer.connection.ProgressLoggingConsumerActionExecutor;
+import org.gradle.tooling.internal.consumer.connection.RethrowingErrorsConsumerActionExecutor;
import org.gradle.tooling.internal.consumer.loader.ToolingImplementationLoader;
public class ConnectionFactory {
@@ -38,7 +39,8 @@ public class ConnectionFactory {
public ProjectConnection create(Distribution distribution, ConnectionParameters parameters) {
ConsumerActionExecutor lazyConnection = new LazyConsumerActionExecutor(distribution, toolingImplementationLoader, loggingProvider, parameters);
ConsumerActionExecutor progressLoggingConnection = new ProgressLoggingConsumerActionExecutor(lazyConnection, loggingProvider);
- AsyncConsumerActionExecutor asyncConnection = new DefaultAsyncConsumerActionExecutor(progressLoggingConnection, executorFactory);
+ ConsumerActionExecutor rethrowingErrorsConnection = new RethrowingErrorsConsumerActionExecutor(progressLoggingConnection);
+ AsyncConsumerActionExecutor asyncConnection = new DefaultAsyncConsumerActionExecutor(rethrowingErrorsConnection, executorFactory);
return new DefaultProjectConnection(asyncConnection, parameters);
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildActionExecuter.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildActionExecuter.java
index 5559745..3224663 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildActionExecuter.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildActionExecuter.java
@@ -31,6 +31,7 @@ class DefaultBuildActionExecuter<T> extends AbstractLongRunningOperation<Default
public DefaultBuildActionExecuter(BuildAction<T> buildAction, AsyncConsumerActionExecutor connection, ConnectionParameters parameters) {
super(parameters);
+ operationParamsBuilder.setEntryPoint("BuildActionExecuter API");
this.buildAction = buildAction;
this.connection = connection;
}
@@ -55,7 +56,6 @@ class DefaultBuildActionExecuter<T> extends AbstractLongRunningOperation<Default
public T run(ConsumerConnection connection) {
T result = connection.run(buildAction, operationParameters);
- operationParameters.getBuildProgressListener().rethrowErrors();
return result;
}
}, new ResultHandlerAdapter<T>(handler) {
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildLauncher.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildLauncher.java
index f37a417..dec2c0f 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildLauncher.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultBuildLauncher.java
@@ -32,6 +32,7 @@ class DefaultBuildLauncher extends AbstractLongRunningOperation<DefaultBuildLaun
public DefaultBuildLauncher(AsyncConsumerActionExecutor connection, ConnectionParameters parameters) {
super(parameters);
+ operationParamsBuilder.setEntryPoint("BuildLauncher API");
operationParamsBuilder.setTasks(Collections.<String>emptyList());
this.connection = connection;
}
@@ -72,7 +73,8 @@ class DefaultBuildLauncher extends AbstractLongRunningOperation<DefaultBuildLaun
}
public void run(final ResultHandler<? super Void> handler) {
- final ConsumerOperationParameters operationParameters = operationParamsBuilder.setParameters(connectionParameters).build();
+ final ConsumerOperationParameters operationParameters = getConsumerOperationParameters();
+
connection.run(new ConsumerAction<Void>() {
public ConsumerOperationParameters getParameters() {
return operationParameters;
@@ -80,7 +82,6 @@ class DefaultBuildLauncher extends AbstractLongRunningOperation<DefaultBuildLaun
public Void run(ConsumerConnection connection) {
Void sink = connection.run(Void.class, operationParameters);
- operationParameters.getBuildProgressListener().rethrowErrors();
return sink;
}
}, new ResultHandlerAdapter(handler));
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultGradleConnector.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultGradleConnector.java
index 71d7441..6e5f846 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultGradleConnector.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultGradleConnector.java
@@ -121,8 +121,6 @@ public class DefaultGradleConnector extends GradleConnector {
return this;
}
-
-
public ProjectConnection connect() throws GradleConnectionException {
LOGGER.debug("Connecting from tooling API consumer version {}", GradleVersion.current().getVersion());
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultInternalJvmTestRequest.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultInternalJvmTestRequest.java
new file mode 100644
index 0000000..c7a1a23
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultInternalJvmTestRequest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer;
+
+import org.gradle.api.Nullable;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+
+public class DefaultInternalJvmTestRequest implements InternalJvmTestRequest {
+ private final String className;
+ private final String methodName;
+
+ public DefaultInternalJvmTestRequest(String className, @Nullable String methodName) {
+ this.className = className;
+ this.methodName = methodName;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ DefaultInternalJvmTestRequest that = (DefaultInternalJvmTestRequest) o;
+
+ if (className != null ? !className.equals(that.className) : that.className != null) {
+ return false;
+ }
+ return !(methodName != null ? !methodName.equals(that.methodName) : that.methodName != null);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = className != null ? className.hashCode() : 0;
+ result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultModelBuilder.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultModelBuilder.java
index d273594..38d784c 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultModelBuilder.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultModelBuilder.java
@@ -25,7 +25,6 @@ import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParamete
import org.gradle.tooling.model.UnsupportedMethodException;
import org.gradle.tooling.model.internal.Exceptions;
-import java.util.Arrays;
import java.util.List;
public class DefaultModelBuilder<T> extends AbstractLongRunningOperation<DefaultModelBuilder<T>> implements ModelBuilder<T> {
@@ -36,6 +35,7 @@ public class DefaultModelBuilder<T> extends AbstractLongRunningOperation<Default
super(parameters);
this.modelType = modelType;
this.connection = connection;
+ operationParamsBuilder.setEntryPoint("ModelBuilder API");
}
@Override
@@ -55,10 +55,8 @@ public class DefaultModelBuilder<T> extends AbstractLongRunningOperation<Default
public ConsumerOperationParameters getParameters() {
return operationParameters;
}
-
public T run(ConsumerConnection connection) {
T model = connection.run(modelType, operationParameters);
- operationParameters.getBuildProgressListener().rethrowErrors();
return model;
}
}, new ResultHandlerAdapter<T>(handler));
@@ -68,11 +66,17 @@ public class DefaultModelBuilder<T> extends AbstractLongRunningOperation<Default
// only set a non-null task list on the operationParamsBuilder if at least one task has been given to this method,
// this is needed since any non-null list, even if empty, is treated as 'execute these tasks before building the model'
// this would cause an error when fetching the BuildEnvironment model
- List<String> rationalizedTasks = tasks != null && tasks.length > 0 ? Arrays.asList(tasks) : null;
+ List<String> rationalizedTasks = rationalizeInput(tasks);
operationParamsBuilder.setTasks(rationalizedTasks);
return this;
}
+ @Override
+ public ModelBuilder<T> forTasks(Iterable<String> tasks) {
+ operationParamsBuilder.setTasks(rationalizeInput(tasks));
+ return this;
+ }
+
private class ResultHandlerAdapter<T> extends org.gradle.tooling.internal.consumer.ResultHandlerAdapter<T> {
public ResultHandlerAdapter(ResultHandler<? super T> handler) {
super(handler);
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultProjectConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultProjectConnection.java
index 198a581..50fd586 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultProjectConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultProjectConnection.java
@@ -43,6 +43,11 @@ class DefaultProjectConnection implements ProjectConnection {
return new DefaultBuildLauncher(connection, parameters);
}
+ @Override
+ public TestLauncher newTestLauncher() {
+ return new DefaultTestLauncher(connection, parameters);
+ }
+
public <T> ModelBuilder<T> model(Class<T> modelType) {
if (!modelType.isInterface()) {
throw new IllegalArgumentException(String.format("Cannot fetch a model of type '%s' as this type is not an interface.", modelType.getName()));
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultTestLauncher.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultTestLauncher.java
new file mode 100644
index 0000000..03f1ced
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/DefaultTestLauncher.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer;
+
+import com.google.common.collect.*;
+import org.gradle.api.Transformer;
+import org.gradle.tooling.ResultHandler;
+import org.gradle.tooling.TestExecutionException;
+import org.gradle.tooling.TestLauncher;
+import org.gradle.tooling.events.test.TestOperationDescriptor;
+import org.gradle.tooling.internal.consumer.async.AsyncConsumerActionExecutor;
+import org.gradle.tooling.internal.consumer.connection.ConsumerAction;
+import org.gradle.tooling.internal.consumer.connection.ConsumerConnection;
+import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+import org.gradle.util.CollectionUtils;
+
+import java.util.*;
+
+public class DefaultTestLauncher extends AbstractLongRunningOperation<DefaultTestLauncher> implements TestLauncher {
+
+ private final AsyncConsumerActionExecutor connection;
+ private final Set<TestOperationDescriptor> operationDescriptors = new LinkedHashSet<TestOperationDescriptor>();
+ private final Set<String> testClassNames = new LinkedHashSet<String>();
+ private final Set<InternalJvmTestRequest> internalJvmTestRequests = new LinkedHashSet<InternalJvmTestRequest>();
+
+ public DefaultTestLauncher(AsyncConsumerActionExecutor connection, ConnectionParameters parameters) {
+ super(parameters);
+ operationParamsBuilder.setTasks(Collections.<String>emptyList());
+ operationParamsBuilder.setEntryPoint("TestLauncher API");
+ this.connection = connection;
+ }
+
+ @Override
+ protected DefaultTestLauncher getThis() {
+ return this;
+ }
+
+ @Override
+ public TestLauncher withTests(TestOperationDescriptor... testDescriptors) {
+ withTests(Arrays.asList(testDescriptors));
+ return this;
+ }
+
+ @Override
+ public TestLauncher withTests(Iterable<? extends TestOperationDescriptor> descriptors) {
+ operationDescriptors.addAll(CollectionUtils.toList(descriptors));
+ return this;
+ }
+
+ @Override
+ public TestLauncher withJvmTestClasses(String... classNames) {
+ withJvmTestClasses(Arrays.asList(classNames));
+ return this;
+ }
+
+ @Override
+ public TestLauncher withJvmTestClasses(Iterable<String> testClasses) {
+ List<InternalJvmTestRequest> newRequests = CollectionUtils.collect(testClasses, new Transformer<InternalJvmTestRequest, String>() {
+ @Override
+ public InternalJvmTestRequest transform(String testClass) {
+ return new DefaultInternalJvmTestRequest(testClass, null);
+ }
+ });
+ internalJvmTestRequests.addAll(newRequests);
+ testClassNames.addAll(CollectionUtils.toList(testClasses));
+ return this;
+ }
+
+ @Override
+ public TestLauncher withJvmTestMethods(String testClass, String... methods) {
+ withJvmTestMethods(testClass, Arrays.asList(methods));
+ return this;
+ }
+
+ @Override
+ public TestLauncher withJvmTestMethods(final String testClass, Iterable<String> methods) {
+ List<InternalJvmTestRequest> newRequests = CollectionUtils.collect(methods, new Transformer<InternalJvmTestRequest, String>() {
+ @Override
+ public InternalJvmTestRequest transform(String methodName) {
+ return new DefaultInternalJvmTestRequest(testClass, methodName);
+ }
+ });
+ this.internalJvmTestRequests.addAll(newRequests);
+ this.testClassNames.add(testClass);
+ return this;
+ }
+
+ public void run() {
+ BlockingResultHandler<Void> handler = new BlockingResultHandler<Void>(Void.class);
+ run(handler);
+ handler.getResult();
+ }
+
+ public void run(final ResultHandler<? super Void> handler) {
+ if (operationDescriptors.isEmpty() && internalJvmTestRequests.isEmpty()) {
+ throw new TestExecutionException("No test declared for execution.");
+ }
+ final ConsumerOperationParameters operationParameters = getConsumerOperationParameters();
+ final TestExecutionRequest testExecutionRequest = new TestExecutionRequest(operationDescriptors, ImmutableList.copyOf(testClassNames), ImmutableSet.copyOf(internalJvmTestRequests));
+ connection.run(new ConsumerAction<Void>() {
+ public ConsumerOperationParameters getParameters() {
+ return operationParameters;
+ }
+
+ public Void run(ConsumerConnection connection) {
+ connection.runTests(testExecutionRequest, getParameters());
+ return null;
+ }
+ }, new ResultHandlerAdapter(handler));
+ }
+
+ private class ResultHandlerAdapter extends org.gradle.tooling.internal.consumer.ResultHandlerAdapter<Void> {
+ public ResultHandlerAdapter(ResultHandler<? super Void> handler) {
+ super(handler);
+ }
+
+ @Override
+ protected String connectionFailureMessage(Throwable failure) {
+ return String.format("Could not execute tests using %s.", connection.getDisplayName());
+ }
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ResultHandlerAdapter.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ResultHandlerAdapter.java
index 8a268fd..ffda093 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ResultHandlerAdapter.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/ResultHandlerAdapter.java
@@ -23,6 +23,8 @@ import org.gradle.tooling.internal.protocol.BuildExceptionVersion1;
import org.gradle.tooling.internal.protocol.InternalBuildCancelledException;
import org.gradle.tooling.internal.protocol.ResultHandlerVersion1;
import org.gradle.tooling.internal.protocol.exceptions.InternalUnsupportedBuildArgumentException;
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionException;
+import org.gradle.tooling.TestExecutionException;
/**
* Adapts a {@link ResultHandler} to a {@link ResultHandlerVersion1}.
@@ -51,6 +53,8 @@ abstract class ResultHandlerAdapter<T> implements ResultHandlerVersion1<T> {
handler.onFailure((GradleConnectionException) failure);
} else if (failure instanceof InternalBuildCancelledException) {
handler.onFailure(new BuildCancelledException(connectionFailureMessage(failure), failure.getCause()));
+ } else if (failure instanceof InternalTestExecutionException) {
+ handler.onFailure(new TestExecutionException(connectionFailureMessage(failure), failure.getCause()));
} else if (failure instanceof BuildExceptionVersion1) {
handler.onFailure(new BuildException(connectionFailureMessage(failure), failure.getCause()));
} else if (failure instanceof ListenerNotificationException) {
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/TestExecutionRequest.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/TestExecutionRequest.java
new file mode 100644
index 0000000..16e7515
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/TestExecutionRequest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer;
+
+import org.gradle.api.Transformer;
+import org.gradle.tooling.events.OperationDescriptor;
+import org.gradle.tooling.events.internal.OperationDescriptorWrapper;
+import org.gradle.tooling.events.test.TestOperationDescriptor;
+import org.gradle.tooling.internal.protocol.events.InternalTestDescriptor;
+import org.gradle.tooling.internal.protocol.test.InternalJvmTestRequest;
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionRequest;
+import org.gradle.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.Set;
+
+public class TestExecutionRequest implements InternalTestExecutionRequest {
+ private final Collection<InternalTestDescriptor> testDescriptors;
+ private final Collection<String> testClassNames;
+ private final Collection<InternalJvmTestRequest> internalJvmTestRequests;
+
+ public TestExecutionRequest(Iterable<TestOperationDescriptor> operationDescriptors, Collection<String> testClassNames, Set<InternalJvmTestRequest> internalJvmTestRequests) {
+ this.testDescriptors = adaptDescriptors(operationDescriptors);
+ this.testClassNames = testClassNames;
+ this.internalJvmTestRequests = internalJvmTestRequests;
+ }
+
+ @Override
+ public Collection<InternalTestDescriptor> getTestExecutionDescriptors() {
+ return testDescriptors;
+ }
+
+ public Collection<String> getTestClassNames() {
+ return testClassNames;
+ }
+
+ public Collection<InternalJvmTestRequest> getInternalJvmTestRequests() {
+ return internalJvmTestRequests;
+ }
+
+ private Collection<InternalTestDescriptor> adaptDescriptors(Iterable<TestOperationDescriptor> operationDescriptors) {
+ return CollectionUtils.collect(operationDescriptors, new Transformer<InternalTestDescriptor, OperationDescriptor>() {
+ @Override
+ public InternalTestDescriptor transform(OperationDescriptor operationDescriptor) {
+ return (InternalTestDescriptor) ((OperationDescriptorWrapper) operationDescriptor).getInternalOperationDescriptor();
+ }
+ });
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/AbstractConsumerConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/AbstractConsumerConnection.java
index 5958f30..aa319b9 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/AbstractConsumerConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/AbstractConsumerConnection.java
@@ -21,6 +21,8 @@ import org.gradle.tooling.internal.consumer.ConnectionParameters;
import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
import org.gradle.tooling.internal.consumer.versioning.VersionDetails;
import org.gradle.tooling.internal.protocol.ConnectionVersion4;
+import org.gradle.tooling.internal.consumer.TestExecutionRequest;
+import org.gradle.tooling.model.internal.Exceptions;
public abstract class AbstractConsumerConnection implements ConsumerConnection {
private final ConnectionVersion4 delegate;
@@ -59,4 +61,8 @@ public abstract class AbstractConsumerConnection implements ConsumerConnection {
public <T> T run(BuildAction<T> action, ConsumerOperationParameters operationParameters) {
return getActionRunner().run(action, operationParameters);
}
+
+ public void runTests(final TestExecutionRequest testExecutionRequest, ConsumerOperationParameters operationParameters){
+ throw Exceptions.unsupportedFeature(operationParameters.getEntryPointName(), getVersionDetails().getVersion(), "2.6");
+ }
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnection.java
index a35551f..bcbe042 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnection.java
@@ -48,7 +48,7 @@ public class BuildActionRunnerBackedConsumerConnection extends AbstractPost12Con
ModelProducer consumerConnectionBackedModelProducer = new BuildActionRunnerBackedModelProducer(adapter, getVersionDetails(), modelMapping, (BuildActionRunner) delegate);
ModelProducer producerWithGradleBuild = new GradleBuildAdapterProducer(adapter, consumerConnectionBackedModelProducer);
modelProducer = new BuildInvocationsAdapterProducer(adapter, getVersionDetails(), producerWithGradleBuild);
- actionRunner = new UnsupportedActionRunner(getVersionDetails());
+ actionRunner = new UnsupportedActionRunner(getVersionDetails().getVersion());
}
@Override
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ConnectionVersion4BackedConsumerConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ConnectionVersion4BackedConsumerConnection.java
deleted file mode 100644
index c8f7366..0000000
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ConnectionVersion4BackedConsumerConnection.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.gradle.tooling.internal.consumer.connection;
-
-import org.gradle.tooling.BuildAction;
-import org.gradle.tooling.UnsupportedVersionException;
-import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter;
-import org.gradle.tooling.internal.build.VersionOnlyBuildEnvironment;
-import org.gradle.tooling.internal.consumer.Distribution;
-import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
-import org.gradle.tooling.internal.protocol.ConnectionVersion4;
-import org.gradle.tooling.model.build.BuildEnvironment;
-
-/**
- * An adapter for unsupported connection using a {@code ConnectionVersion4} based provider.
- *
- * <p>Used for providers >= 1.0-milestone-3 and <= 1.0-milestone-7.</p>
- */
-public class ConnectionVersion4BackedConsumerConnection implements ConsumerConnection {
- private final Distribution distribution;
- private final ProtocolToModelAdapter adapter;
- private final String version;
-
- public ConnectionVersion4BackedConsumerConnection(Distribution distribution, ConnectionVersion4 delegate, ProtocolToModelAdapter adapter) {
- this.distribution = distribution;
- this.adapter = adapter;
- version = delegate.getMetaData().getVersion();
- }
-
- public void stop() {
- }
-
- public String getDisplayName() {
- return distribution.getDisplayName();
- }
-
- public <T> T run(Class<T> type, ConsumerOperationParameters operationParameters) throws UnsupportedOperationException, IllegalStateException {
- if (type.equals(BuildEnvironment.class)) {
- return adapter.adapt(type, doGetBuildEnvironment());
- }
- throw fail();
- }
-
- private Object doGetBuildEnvironment() {
- return new VersionOnlyBuildEnvironment(version);
- }
-
- public <T> T run(BuildAction<T> action, ConsumerOperationParameters operationParameters) throws UnsupportedOperationException, IllegalStateException {
- throw fail();
- }
-
- private UnsupportedVersionException fail() {
- return new UnsupportedVersionException(String.format("Support for Gradle version %s was removed in tooling API version 2.0. You should upgrade your Gradle build to use Gradle 1.0-milestone-8 or later.", version));
- }
-}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ConsumerConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ConsumerConnection.java
index 3f9d857..1db7518 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ConsumerConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ConsumerConnection.java
@@ -18,6 +18,7 @@ package org.gradle.tooling.internal.consumer.connection;
import org.gradle.internal.concurrent.Stoppable;
import org.gradle.tooling.BuildAction;
+import org.gradle.tooling.internal.consumer.TestExecutionRequest;
import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
/**
@@ -28,7 +29,7 @@ public interface ConsumerConnection extends Stoppable {
* Cleans up resources used by this connection. Blocks until complete.
*/
void stop();
-
+
String getDisplayName();
<T> T run(Class<T> type, ConsumerOperationParameters operationParameters)
@@ -36,4 +37,6 @@ public interface ConsumerConnection extends Stoppable {
<T> T run(BuildAction<T> action, ConsumerOperationParameters operationParameters)
throws UnsupportedOperationException, IllegalStateException;
+
+ void runTests(TestExecutionRequest testExecutionRequest, ConsumerOperationParameters operationParameters);
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnection.java
index 38b02b3..47d8e3a 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnection.java
@@ -34,6 +34,7 @@ import org.gradle.tooling.model.eclipse.HierarchicalEclipseProject;
import org.gradle.tooling.model.idea.BasicIdeaProject;
import org.gradle.tooling.model.idea.IdeaProject;
import org.gradle.tooling.model.internal.Exceptions;
+import org.gradle.util.GradleVersion;
/**
* An adapter for a {@link InternalConnection} based provider.
@@ -49,8 +50,12 @@ public class InternalConnectionBackedConsumerConnection extends AbstractConsumer
ModelProducer modelProducer = new InternalConnectionBackedModelProducer(adapter, getVersionDetails(), modelMapping, (InternalConnection) delegate);
modelProducer = new GradleBuildAdapterProducer(adapter, modelProducer);
modelProducer = new BuildInvocationsAdapterProducer(adapter, getVersionDetails(), modelProducer);
- this.modelProducer = new BuildExecutingModelProducer(modelProducer);
- this.actionRunner = new UnsupportedActionRunner(getVersionDetails());
+ modelProducer = new BuildExecutingModelProducer(modelProducer);
+ if (GradleVersion.version(getVersionDetails().getVersion()).compareTo(GradleVersion.version("1.0")) < 0) {
+ modelProducer = new NoCommandLineArgsModelProducer(modelProducer);
+ }
+ this.modelProducer = modelProducer;
+ this.actionRunner = new UnsupportedActionRunner(getVersionDetails().getVersion());
}
@Override
@@ -85,6 +90,22 @@ public class InternalConnectionBackedConsumerConnection extends AbstractConsumer
}
}
+ private class NoCommandLineArgsModelProducer implements ModelProducer {
+ private final ModelProducer delegate;
+
+ public NoCommandLineArgsModelProducer(ModelProducer delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public <T> T produceModel(Class<T> type, ConsumerOperationParameters operationParameters) {
+ if (operationParameters.getArguments() != null && !operationParameters.getArguments().isEmpty()) {
+ throw Exceptions.unsupportedOperationConfiguration(operationParameters.getEntryPointName() + " withArguments()", getVersionDetails().getVersion(), "1.0");
+ }
+ return delegate.produceModel(type, operationParameters);
+ }
+ }
+
private class BuildExecutingModelProducer implements ModelProducer {
private final ModelProducer delegate;
@@ -98,7 +119,7 @@ public class InternalConnectionBackedConsumerConnection extends AbstractConsumer
return null;
} else {
if (operationParameters.getTasks() != null) {
- throw Exceptions.unsupportedOperationConfiguration("modelBuilder.forTasks()", getVersionDetails().getVersion());
+ throw Exceptions.unsupportedOperationConfiguration(operationParameters.getEntryPointName() + " forTasks()", getVersionDetails().getVersion(), "1.2");
}
return delegate.produceModel(type, operationParameters);
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnection.java
index 521485b..9ae14c5 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnection.java
@@ -40,7 +40,7 @@ public class ModelBuilderBackedConsumerConnection extends AbstractPost12Consumer
modelProducer = new GradleBuildAdapterProducer(adapter, modelProducer);
modelProducer = new BuildInvocationsAdapterProducer(adapter, getVersionDetails(), modelProducer);
this.modelProducer = modelProducer;
- this.actionRunner = new UnsupportedActionRunner(getVersionDetails());
+ this.actionRunner = new UnsupportedActionRunner(getVersionDetails().getVersion());
}
@Override
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NoToolingApiConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NoToolingApiConnection.java
index 2988d5a..6a0ca6f 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NoToolingApiConnection.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NoToolingApiConnection.java
@@ -17,9 +17,10 @@
package org.gradle.tooling.internal.consumer.connection;
import org.gradle.tooling.BuildAction;
-import org.gradle.tooling.UnsupportedVersionException;
import org.gradle.tooling.internal.consumer.Distribution;
import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
+import org.gradle.tooling.internal.consumer.TestExecutionRequest;
+import org.gradle.tooling.model.internal.Exceptions;
/**
* A {@code ConsumerConnection} implementation for a Gradle version that does not support the tooling API.
@@ -41,14 +42,14 @@ public class NoToolingApiConnection implements ConsumerConnection {
}
public <T> T run(Class<T> type, ConsumerOperationParameters operationParameters) throws UnsupportedOperationException, IllegalStateException {
- throw fail();
+ throw Exceptions.unsupportedFeature(operationParameters.getEntryPointName(), distribution, "1.0-milestone-8");
}
public <T> T run(BuildAction<T> action, ConsumerOperationParameters operationParameters) throws UnsupportedOperationException, IllegalStateException {
- throw fail();
+ throw Exceptions.unsupportedFeature(operationParameters.getEntryPointName(), distribution, "1.8");
}
- private UnsupportedVersionException fail() {
- return new UnsupportedVersionException(String.format("The specified %s does not implement the tooling API. Support for the tooling API was added in Gradle 1.0-milestone-3 and is available in all later versions.", distribution.getDisplayName()));
+ public void runTests(TestExecutionRequest testExecutionRequest, ConsumerOperationParameters operationParameters) {
+ throw Exceptions.unsupportedFeature(operationParameters.getEntryPointName(), distribution, "2.6");
}
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NonCancellableConsumerConnectionAdapter.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NonCancellableConsumerConnectionAdapter.java
index c6bec6d..c6583c3 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NonCancellableConsumerConnectionAdapter.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/NonCancellableConsumerConnectionAdapter.java
@@ -18,6 +18,7 @@ package org.gradle.tooling.internal.consumer.connection;
import org.gradle.initialization.BuildCancellationToken;
import org.gradle.tooling.BuildAction;
+import org.gradle.tooling.internal.consumer.TestExecutionRequest;
import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,6 +49,10 @@ public class NonCancellableConsumerConnectionAdapter implements ConsumerConnecti
}
}
+ public void runTests(final TestExecutionRequest testExecutionRequest, ConsumerOperationParameters operationParameters){
+ delegate.runTests(testExecutionRequest, operationParameters);
+ }
+
public <T> T run(Class<T> type, ConsumerOperationParameters operationParameters) throws UnsupportedOperationException, IllegalStateException {
Runnable callback = handleCancellationPreOperation(operationParameters.getCancellationToken());
try {
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/RethrowingErrorsConsumerActionExecutor.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/RethrowingErrorsConsumerActionExecutor.java
new file mode 100644
index 0000000..2b7f69f
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/RethrowingErrorsConsumerActionExecutor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer.connection;
+
+public class RethrowingErrorsConsumerActionExecutor implements ConsumerActionExecutor {
+ private ConsumerActionExecutor delegate;
+
+ public RethrowingErrorsConsumerActionExecutor(ConsumerActionExecutor delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void stop() {
+ delegate.stop();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return delegate.getDisplayName();
+ }
+
+ @Override
+ public <T> T run(ConsumerAction<T> action) throws UnsupportedOperationException, IllegalStateException {
+ T result = delegate.run(action);
+ action.getParameters().getBuildProgressListener().rethrowErrors();
+ return result;
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/TestExecutionConsumerConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/TestExecutionConsumerConnection.java
new file mode 100644
index 0000000..aeb316d
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/TestExecutionConsumerConnection.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer.connection;
+
+import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter;
+import org.gradle.tooling.internal.consumer.parameters.BuildCancellationTokenAdapter;
+import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
+import org.gradle.tooling.internal.consumer.versioning.ModelMapping;
+import org.gradle.tooling.internal.protocol.ConnectionVersion4;
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionConnection;
+import org.gradle.tooling.internal.consumer.TestExecutionRequest;
+
+/*
+ * <p>Used for providers >= 2.6.</p>
+ */
+public class TestExecutionConsumerConnection extends ShutdownAwareConsumerConnection {
+
+ public TestExecutionConsumerConnection(ConnectionVersion4 delegate, ModelMapping modelMapping, ProtocolToModelAdapter adapter) {
+ super(delegate, modelMapping, adapter);
+ }
+
+ @Override
+ public void runTests(final TestExecutionRequest testExecutionRequest, ConsumerOperationParameters operationParameters) {
+ final BuildCancellationTokenAdapter cancellationTokenAdapter = new BuildCancellationTokenAdapter(operationParameters.getCancellationToken());
+ ((InternalTestExecutionConnection) getDelegate()).runTests(testExecutionRequest, cancellationTokenAdapter, operationParameters);
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/UnsupportedActionRunner.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/UnsupportedActionRunner.java
index 8a5dff0..0dbb3c4 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/UnsupportedActionRunner.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/UnsupportedActionRunner.java
@@ -18,17 +18,16 @@ package org.gradle.tooling.internal.consumer.connection;
import org.gradle.tooling.BuildAction;
import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
-import org.gradle.tooling.internal.consumer.versioning.VersionDetails;
import org.gradle.tooling.model.internal.Exceptions;
class UnsupportedActionRunner implements ActionRunner {
- private final VersionDetails versionDetails;
+ private final String version;
- UnsupportedActionRunner(VersionDetails versionDetails) {
- this.versionDetails = versionDetails;
+ UnsupportedActionRunner(String version) {
+ this.version = version;
}
public <T> T run(BuildAction<T> action, ConsumerOperationParameters operationParameters) {
- throw Exceptions.unsupportedFeature("execution of build actions provided by the tooling API client", versionDetails.getVersion(), "1.8");
+ throw Exceptions.unsupportedFeature(operationParameters.getEntryPointName(), version, "1.8");
}
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/UnsupportedOlderVersionConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/UnsupportedOlderVersionConnection.java
new file mode 100644
index 0000000..f1e169b
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/connection/UnsupportedOlderVersionConnection.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer.connection;
+
+import org.gradle.tooling.BuildAction;
+import org.gradle.tooling.UnsupportedVersionException;
+import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter;
+import org.gradle.tooling.internal.build.VersionOnlyBuildEnvironment;
+import org.gradle.tooling.internal.consumer.Distribution;
+import org.gradle.tooling.internal.consumer.TestExecutionRequest;
+import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters;
+import org.gradle.tooling.internal.protocol.ConnectionVersion4;
+import org.gradle.tooling.model.build.BuildEnvironment;
+import org.gradle.tooling.model.internal.Exceptions;
+
+/**
+ * An adapter for unsupported connection using a {@code ConnectionVersion4} based provider.
+ *
+ * <p>Used for providers >= 1.0-milestone-3 and <= 1.0-milestone-7.</p>
+ */
+public class UnsupportedOlderVersionConnection implements ConsumerConnection {
+ private final Distribution distribution;
+ private final ProtocolToModelAdapter adapter;
+ private final String version;
+
+ public UnsupportedOlderVersionConnection(Distribution distribution, ConnectionVersion4 delegate, ProtocolToModelAdapter adapter) {
+ this.distribution = distribution;
+ this.adapter = adapter;
+ version = delegate.getMetaData().getVersion();
+ }
+
+ public void stop() {
+ }
+
+ public String getDisplayName() {
+ return distribution.getDisplayName();
+ }
+
+ public <T> T run(Class<T> type, ConsumerOperationParameters operationParameters) throws UnsupportedOperationException, IllegalStateException {
+ if (type.equals(BuildEnvironment.class)) {
+ return adapter.adapt(type, doGetBuildEnvironment());
+ }
+ throw fail();
+ }
+
+ private Object doGetBuildEnvironment() {
+ return new VersionOnlyBuildEnvironment(version);
+ }
+
+ public <T> T run(BuildAction<T> action, ConsumerOperationParameters operationParameters) throws UnsupportedOperationException, IllegalStateException {
+ return new UnsupportedActionRunner(version).run(action, operationParameters);
+ }
+
+ public void runTests(TestExecutionRequest testExecutionRequest, ConsumerOperationParameters operationParameters) {
+ throw Exceptions.unsupportedFeature(operationParameters.getEntryPointName(), version, "2.6");
+ }
+
+ private UnsupportedVersionException fail() {
+ return new UnsupportedVersionException(String.format("Support for Gradle version %s was removed in tooling API version 2.0. You should upgrade your Gradle build to use Gradle 1.0-milestone-8 or later.", version));
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoader.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoader.java
index b8fd527..2266713 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoader.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoader.java
@@ -32,6 +32,7 @@ import org.gradle.tooling.internal.consumer.connection.*;
import org.gradle.tooling.internal.consumer.converters.ConsumerTargetTypeProvider;
import org.gradle.tooling.internal.consumer.versioning.ModelMapping;
import org.gradle.tooling.internal.protocol.*;
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,7 +67,9 @@ public class DefaultToolingImplementationLoader implements ToolingImplementation
// Adopting the connection to a refactoring friendly type that the consumer owns
AbstractConsumerConnection adaptedConnection;
- if (connection instanceof StoppableConnection) {
+ if (connection instanceof InternalTestExecutionConnection){
+ adaptedConnection = new TestExecutionConsumerConnection(connection, modelMapping, adapter);
+ } else if (connection instanceof StoppableConnection) {
adaptedConnection = new ShutdownAwareConsumerConnection(connection, modelMapping, adapter);
} else if (connection instanceof InternalCancellableConnection) {
adaptedConnection = new CancellableConsumerConnection(connection, modelMapping, adapter);
@@ -79,7 +82,7 @@ public class DefaultToolingImplementationLoader implements ToolingImplementation
} else if (connection instanceof InternalConnection) {
adaptedConnection = new InternalConnectionBackedConsumerConnection(connection, modelMapping, adapter);
} else {
- return new ConnectionVersion4BackedConsumerConnection(distribution, connection, adapter);
+ return new UnsupportedOlderVersionConnection(distribution, connection, adapter);
}
adaptedConnection.configure(connectionParameters);
if (!adaptedConnection.getVersionDetails().supportsCancellation()) {
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/BuildProgressListenerAdapter.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/BuildProgressListenerAdapter.java
index 66b1af0..bfcadef 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/BuildProgressListenerAdapter.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/BuildProgressListenerAdapter.java
@@ -198,10 +198,10 @@ public class BuildProgressListenerAdapter implements InternalBuildProgressListen
OperationDescriptor parent = getParentDescriptor(descriptor.getParentId());
if (descriptor instanceof InternalJvmTestDescriptor) {
InternalJvmTestDescriptor jvmTestDescriptor = (InternalJvmTestDescriptor) descriptor;
- return new DefaultJvmTestOperationDescriptor(descriptor.getName(), descriptor.getDisplayName(), parent,
+ return new DefaultJvmTestOperationDescriptor(jvmTestDescriptor, parent,
toJvmTestKind(jvmTestDescriptor.getTestKind()), jvmTestDescriptor.getSuiteName(), jvmTestDescriptor.getClassName(), jvmTestDescriptor.getMethodName());
} else {
- return new DefaultTestOperationDescriptor(descriptor.getName(), descriptor.getDisplayName(), parent);
+ return new DefaultTestOperationDescriptor(descriptor, parent);
}
}
@@ -217,12 +217,12 @@ public class BuildProgressListenerAdapter implements InternalBuildProgressListen
private TaskOperationDescriptor toTaskDescriptor(InternalTaskDescriptor descriptor) {
OperationDescriptor parent = getParentDescriptor(descriptor.getParentId());
- return new DefaultTaskOperationDescriptor(descriptor.getName(), descriptor.getDisplayName(), descriptor.getTaskPath(), parent);
+ return new DefaultTaskOperationDescriptor(descriptor, descriptor.getTaskPath(), parent);
}
private OperationDescriptor toDescriptor(InternalOperationDescriptor descriptor) {
OperationDescriptor parent = getParentDescriptor(descriptor.getParentId());
- return new DefaultOperationDescriptor(descriptor.getName(), descriptor.getDisplayName(), parent);
+ return new DefaultOperationDescriptor(descriptor, parent);
}
private synchronized OperationDescriptor getParentDescriptor(Object parentId) {
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParameters.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParameters.java
index 4170664..73b0274 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParameters.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParameters.java
@@ -31,7 +31,10 @@ import org.gradle.tooling.model.Task;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
public class ConsumerOperationParameters implements BuildOperationParametersVersion1, BuildParametersVersion1, BuildParameters {
@@ -45,6 +48,7 @@ public class ConsumerOperationParameters implements BuildOperationParametersVers
private final List<ProgressListener> testProgressListeners = new ArrayList<ProgressListener>();
private final List<ProgressListener> taskProgressListeners = new ArrayList<ProgressListener>();
private final List<ProgressListener> buildOperationProgressListeners = new ArrayList<ProgressListener>();
+ private String entryPoint;
private CancellationToken cancellationToken;
private ConnectionParameters parameters;
private OutputStream stdout;
@@ -60,6 +64,11 @@ public class ConsumerOperationParameters implements BuildOperationParametersVers
private Builder() {
}
+ public Builder setEntryPoint(String entryPoint) {
+ this.entryPoint = entryPoint;
+ return this;
+ }
+
public Builder setParameters(ConnectionParameters parameters) {
this.parameters = parameters;
return this;
@@ -91,13 +100,13 @@ public class ConsumerOperationParameters implements BuildOperationParametersVers
return this;
}
- public Builder setJvmArguments(String... jvmArguments) {
- this.jvmArguments = rationalizeInput(jvmArguments);
+ public Builder setJvmArguments(List<String> jvmArguments) {
+ this.jvmArguments = jvmArguments;
return this;
}
- public Builder setArguments(String[] arguments) {
- this.arguments = rationalizeInput(arguments);
+ public Builder setArguments(List<String> arguments) {
+ this.arguments = arguments;
return this;
}
@@ -151,17 +160,22 @@ public class ConsumerOperationParameters implements BuildOperationParametersVers
}
public ConsumerOperationParameters build() {
+ if (entryPoint == null) {
+ throw new IllegalStateException("No entry point specified.");
+ }
+
// create the listener adapters right when the ConsumerOperationParameters are instantiated but no earlier,
// this ensures that when multiple requests are issued that are built from the same builder, such requests do not share any state kept in the listener adapters
// e.g. if the listener adapters do per-request caching, such caching must not leak between different requests built from the same builder
ProgressListenerAdapter progressListenerAdapter = new ProgressListenerAdapter(this.legacyProgressListeners);
FailsafeBuildProgressListenerAdapter buildProgressListenerAdapter = new FailsafeBuildProgressListenerAdapter(
- new BuildProgressListenerAdapter(this.testProgressListeners, this.taskProgressListeners, this.buildOperationProgressListeners));
- return new ConsumerOperationParameters(parameters, stdout, stderr, colorOutput, stdin, javaHome, jvmArguments, arguments, tasks, launchables,
- progressListenerAdapter, buildProgressListenerAdapter, cancellationToken);
+ new BuildProgressListenerAdapter(this.testProgressListeners, this.taskProgressListeners, this.buildOperationProgressListeners));
+ return new ConsumerOperationParameters(entryPoint, parameters, stdout, stderr, colorOutput, stdin, javaHome, jvmArguments, arguments, tasks, launchables,
+ progressListenerAdapter, buildProgressListenerAdapter, cancellationToken);
}
}
+ private final String entryPointName;
private final ProgressListenerAdapter progressListener;
private final FailsafeBuildProgressListenerAdapter buildProgressListener;
private final CancellationToken cancellationToken;
@@ -179,9 +193,10 @@ public class ConsumerOperationParameters implements BuildOperationParametersVers
private final List<String> tasks;
private final List<InternalLaunchable> launchables;
- private ConsumerOperationParameters(ConnectionParameters parameters, OutputStream stdout, OutputStream stderr, Boolean colorOutput, InputStream stdin,
+ private ConsumerOperationParameters(String entryPointName, ConnectionParameters parameters, OutputStream stdout, OutputStream stderr, Boolean colorOutput, InputStream stdin,
File javaHome, List<String> jvmArguments, List<String> arguments, List<String> tasks, List<InternalLaunchable> launchables,
ProgressListenerAdapter progressListener, FailsafeBuildProgressListenerAdapter buildProgressListener, CancellationToken cancellationToken) {
+ this.entryPointName = entryPointName;
this.parameters = parameters;
this.stdout = stdout;
this.stderr = stderr;
@@ -197,10 +212,6 @@ public class ConsumerOperationParameters implements BuildOperationParametersVers
this.cancellationToken = cancellationToken;
}
- private static List<String> rationalizeInput(String[] arguments) {
- return arguments != null && arguments.length > 0 ? Arrays.asList(arguments) : null;
- }
-
private static void validateJavaHome(File javaHome) {
if (javaHome == null) {
return;
@@ -210,6 +221,10 @@ public class ConsumerOperationParameters implements BuildOperationParametersVers
}
}
+ public String getEntryPointName() {
+ return entryPointName;
+ }
+
public long getStartTime() {
return startTime;
}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/ConnectionVersion4.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/ConnectionVersion4.java
index 8ea35ec..2f46132 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/ConnectionVersion4.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/ConnectionVersion4.java
@@ -21,11 +21,12 @@ package org.gradle.tooling.internal.protocol;
* <p>The following constraints apply to implementations:
* <ul>
* <li>Implementations must be thread-safe.
+ * <li>Implementations should implement {@link org.gradle.tooling.internal.protocol.test.InternalTestExecutionConnection}. This is used by all consumer versions from 2.6-rc-1.
* <li>Implementations should implement {@link InternalCancellableConnection}. This is used by all consumer versions from 2.1-rc-1.
- * <li>Implementations should implement {@link InternalBuildActionExecutor}. This is used by all consumer versions from 1.8-rc-1.
* <li>Implementations should implement {@link ConfigurableConnection}. This is used by all consumer versions from 1.2-rc-1.
* <li>Implementations should implement {@link StoppableConnection}. This is used by all consumer versions from 2.2-rc-1.
* <li>Implementations should provide a zero-args constructor. This is used by all consumer versions from 1.0-milestone-3.
+ * <li>For backwards compatibility, implementations should implement {@link InternalBuildActionExecutor}. This is used by all consumer versions from 1.8-rc-1 to 2.0.
* <li>For backwards compatibility, implementations should implement {@link ModelBuilder}. This is used by all consumer versions from 1.6-rc-1 to 2.0.
* <li>For backwards compatibility, implementations should implement {@link BuildActionRunner}. This is used by consumer versions from 1.2-rc-1 to 1.5.
* <li>For backwards compatibility, implementations should implement {@link InternalConnection}. This is used by consumer versions from 1.0-milestone-8 to 1.1.
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalJvmTestRequest.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalJvmTestRequest.java
new file mode 100644
index 0000000..7f2555b
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalJvmTestRequest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.protocol.test;
+
+import org.gradle.api.Nullable;
+
+/**
+ * Specifies a method to be tested.
+ *
+ * DO NOT CHANGE THIS INTERFACE. It is part of the cross-version protocol.
+ *
+ * @since 2.7-rc-1
+ */
+public interface InternalJvmTestRequest {
+ String getClassName();
+ @Nullable String getMethodName();
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionConnection.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionConnection.java
new file mode 100644
index 0000000..6ecde25
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionConnection.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.protocol.test;
+
+import org.gradle.tooling.internal.protocol.BuildParameters;
+import org.gradle.tooling.internal.protocol.BuildResult;
+import org.gradle.tooling.internal.protocol.InternalCancellationToken;
+import org.gradle.tooling.internal.protocol.InternalProtocolInterface;
+
+/**
+ * Mixed into a provider connection to allow tests to be executed.
+ *
+ * DO NOT CHANGE THIS INTERFACE. It is part of the cross-version protocol.
+ *
+ * <p>Consumer compatibility: This interface is used by all consumer versions from 2.6-rc-1.</p>
+ * <p>Provider compatibility: This interface is implemented by all provider versions from 2.6-rc-1.</p>
+ *
+ * @since 2.6-rc-1
+ */
+public interface InternalTestExecutionConnection extends InternalProtocolInterface {
+ BuildResult<?> runTests(InternalTestExecutionRequest testExecutionRequest, InternalCancellationToken cancellationToken, BuildParameters operationParameters);
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionException.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionException.java
new file mode 100644
index 0000000..9c6032c
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.protocol.test;
+
+/**
+ * A wrapper thrown when a test cannot be executed. The failure will be attached as the cause of this exception.
+ *
+ * DO NOT CHANGE THIS CLASS. It is part of the cross-version protocol.
+ *
+ * @since 2.6-rc-1
+ */
+public class InternalTestExecutionException extends RuntimeException {
+ public InternalTestExecutionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionRequest.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionRequest.java
new file mode 100644
index 0000000..28891c7
--- /dev/null
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/internal/protocol/test/InternalTestExecutionRequest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.protocol.test;
+
+import org.gradle.tooling.internal.protocol.InternalProtocolInterface;
+import org.gradle.tooling.internal.protocol.events.InternalTestDescriptor;
+
+import java.util.Collection;
+
+/**
+ * DO NOT CHANGE THIS INTERFACE. It is part of the cross-version protocol.
+ *
+ * See {@code ProviderInternalTestExecutionRequest} for what the provider expects on a test execution request.
+ *
+ * @since 2.6-rc-1
+ */
+public interface InternalTestExecutionRequest extends InternalProtocolInterface {
+ Collection<InternalTestDescriptor> getTestExecutionDescriptors();
+ Collection<String> getTestClassNames();
+}
diff --git a/subprojects/tooling-api/src/main/java/org/gradle/tooling/model/internal/Exceptions.java b/subprojects/tooling-api/src/main/java/org/gradle/tooling/model/internal/Exceptions.java
index 019aa4b..240e344 100644
--- a/subprojects/tooling-api/src/main/java/org/gradle/tooling/model/internal/Exceptions.java
+++ b/subprojects/tooling-api/src/main/java/org/gradle/tooling/model/internal/Exceptions.java
@@ -19,6 +19,7 @@ package org.gradle.tooling.model.internal;
import org.gradle.tooling.UnknownModelException;
import org.gradle.tooling.UnsupportedVersionException;
import org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException;
+import org.gradle.tooling.internal.consumer.Distribution;
import org.gradle.tooling.internal.consumer.versioning.ModelMapping;
import org.gradle.tooling.internal.protocol.InternalUnsupportedModelException;
import org.gradle.tooling.model.UnsupportedMethodException;
@@ -41,12 +42,9 @@ public class Exceptions {
, method);
}
- public static UnsupportedOperationConfigurationException unsupportedOperationConfiguration(String operation, String targetVersion) {
- return new UnsupportedOperationConfigurationException(String.format("Unsupported configuration: %s."
- + "\nYou configured the LongRunningOperation (ModelBuilder or BuildLauncher) with an unsupported option."
- + "\nThe version of Gradle are using (%s) does not support this configuration option."
- + "\nTo resolve the problem you can change/upgrade the target version of Gradle."
- , operation, targetVersion));
+ public static UnsupportedOperationConfigurationException unsupportedOperationConfiguration(String operation, String targetVersion, String versionAdded) {
+ return new UnsupportedOperationConfigurationException(String.format("The version of Gradle you are using (%s) does not support the %s configuration option. Support for this is available in Gradle %s and all later versions.",
+ targetVersion, operation, versionAdded));
}
public static UnknownModelException unsupportedModel(Class<?> modelType, String targetVersion) {
@@ -65,8 +63,13 @@ public class Exceptions {
return new UnknownModelException(String.format("No model of type '%s' is available in this build.", type.getSimpleName()), failure.getCause());
}
+ public static UnsupportedVersionException unsupportedFeature(String feature, Distribution distro, String versionAdded) {
+ return new UnsupportedVersionException(String.format("The version of Gradle you are using (%s) does not support the %s. Support for this is available in Gradle %s and all later versions.",
+ distro.getDisplayName(), feature, versionAdded));
+ }
+
public static UnsupportedVersionException unsupportedFeature(String feature, String targetVersion, String versionAdded) {
- return new UnsupportedVersionException(String.format("The version of Gradle you are using (%s) does not support %s. Support for this was added in Gradle %s and is available in all later versions.",
+ return new UnsupportedVersionException(String.format("The version of Gradle you are using (%s) does not support the %s. Support for this is available in Gradle %s and all later versions.",
targetVersion, feature, versionAdded));
}
}
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/AbstractLongRunningOperationTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/AbstractLongRunningOperationTest.groovy
new file mode 100644
index 0000000..d83cc93
--- /dev/null
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/AbstractLongRunningOperationTest.groovy
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer
+
+import spock.lang.Specification
+
+class AbstractLongRunningOperationTest extends Specification {
+ def op = new TestOperation(Stub(ConnectionParameters))
+
+ def "null or empty arguments have the same meaning"() {
+ when:
+ op.withArguments(null as List)
+
+ then:
+ op.consumerOperationParameters.arguments == null
+
+ when:
+ op.withArguments([])
+
+ then:
+ op.consumerOperationParameters.arguments == null
+
+ when:
+ op.withArguments()
+
+ then:
+ op.consumerOperationParameters.arguments == null
+
+ when:
+ op.withArguments('-Dfoo')
+
+ then:
+ op.consumerOperationParameters.arguments == ['-Dfoo']
+
+ when:
+ op.withArguments(['-Dfoo'])
+
+ then:
+ op.consumerOperationParameters.arguments == ['-Dfoo']
+ }
+
+ def "null or empty jvm arguments have the same meaning"() {
+ when:
+ op.jvmArguments = null as List
+
+ then:
+ op.consumerOperationParameters.jvmArguments == null
+
+ when:
+ op.jvmArguments = null as String[]
+
+ then:
+ op.consumerOperationParameters.jvmArguments == null
+
+ when:
+ op.jvmArguments = []
+
+ then:
+ op.consumerOperationParameters.jvmArguments == null
+
+ when:
+ op.setJvmArguments()
+
+ then:
+ op.consumerOperationParameters.jvmArguments == null
+
+ when:
+ op.jvmArguments = ['-Xmx']
+
+ then:
+ op.consumerOperationParameters.jvmArguments == ['-Xmx']
+
+ when:
+ op.setJvmArguments('-Xmx')
+
+ then:
+ op.consumerOperationParameters.jvmArguments == ['-Xmx']
+ }
+
+ class TestOperation extends AbstractLongRunningOperation<TestOperation> {
+ protected TestOperation(ConnectionParameters parameters) {
+ super(parameters)
+ operationParamsBuilder.entryPoint = "test"
+ }
+
+ @Override
+ protected TestOperation getThis() {
+ return this
+ }
+ }
+}
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/DefaultTestLauncherTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/DefaultTestLauncherTest.groovy
new file mode 100644
index 0000000..1b88bae
--- /dev/null
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/DefaultTestLauncherTest.groovy
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer
+
+import org.gradle.tooling.events.test.TestOperationDescriptor
+import org.gradle.tooling.internal.consumer.async.AsyncConsumerActionExecutor
+import org.gradle.tooling.internal.consumer.connection.ConsumerAction
+import org.gradle.tooling.internal.consumer.connection.ConsumerConnection
+import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters
+import org.gradle.tooling.internal.protocol.ResultHandlerVersion1
+import spock.lang.Specification
+
+class DefaultTestLauncherTest extends Specification {
+ def executor = Mock(AsyncConsumerActionExecutor)
+ def connection = Mock(ConsumerConnection)
+ def launcher = new DefaultTestLauncher(executor, Stub(ConnectionParameters))
+
+ def "adding tests does not affect an operation in progress"() {
+ given:
+ launcher.withJvmTestClasses("test")
+ when:
+ launcher.run()
+
+ then:
+ 1 * executor.run(_, _) >> { ConsumerAction action, ResultHandlerVersion1 handler ->
+ action.run(connection)
+ handler.onComplete(null)
+ }
+ 1 * connection.runTests(_, _) >> { TestExecutionRequest request, ConsumerOperationParameters params ->
+ assert request.testClassNames == ["test"]
+ assert request.testExecutionDescriptors == []
+
+ assert request.getInternalJvmTestRequests().collect {[it.className, it.methodName]} == [["test", null]]
+
+ launcher.withJvmTestClasses("test2")
+ launcher.withTests(Stub(TestOperationDescriptor))
+
+ assert request.testClassNames == ["test"]
+ assert request.testExecutionDescriptors == []
+ assert request.getInternalJvmTestRequests().collect {[it.className, it.methodName]} == [["test", null]]
+ }
+ }
+
+ def "tests class requests are added to test request"() {
+ given:
+ launcher.withJvmTestClasses("clazz")
+ when:
+ launcher.run()
+
+ then:
+ 1 * executor.run(_, _) >> { ConsumerAction action, ResultHandlerVersion1 handler ->
+ action.run(connection)
+ handler.onComplete(null)
+ }
+ 1 * connection.runTests(_, _) >> { TestExecutionRequest request, ConsumerOperationParameters params ->
+ assert request.testClassNames == ["clazz"]
+ assert request.testExecutionDescriptors == []
+ assert request.getInternalJvmTestRequests().collect {[it.className, it.methodName]} == [["clazz", null]]
+ }
+ }
+
+ def "tests methods requests are added to test request"() {
+ given:
+ launcher.withJvmTestMethods("clazz", "method")
+ when:
+ launcher.run()
+
+ then:
+ 1 * executor.run(_, _) >> { ConsumerAction action, ResultHandlerVersion1 handler ->
+ action.run(connection)
+ handler.onComplete(null)
+ }
+ 1 * connection.runTests(_, _) >> { TestExecutionRequest request, ConsumerOperationParameters params ->
+ assert request.testClassNames == ["clazz"]
+ assert request.testExecutionDescriptors == []
+ assert request.getInternalJvmTestRequests().collect {[it.className, it.methodName]} == [["clazz", "method"]]
+ }
+ }
+}
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/DistributionFactoryTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/DistributionFactoryTest.groovy
index c67dbb6..b933f74 100644
--- a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/DistributionFactoryTest.groovy
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/DistributionFactoryTest.groovy
@@ -18,6 +18,7 @@ package org.gradle.tooling.internal.consumer
import org.gradle.initialization.BuildCancellationToken
import org.gradle.logging.ProgressLogger
import org.gradle.logging.ProgressLoggerFactory
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.util.DistributionLocator
@@ -136,6 +137,7 @@ class DistributionFactoryTest extends Specification {
dist.getToolingImplementationClasspath(progressLoggerFactory, null, cancellationToken).asFiles.name as Set == ['a.jar', 'b.jar'] as Set
}
+ @LeaksFileHandles
def usesWrapperDistributionInstalledIntoSpecifiedUserHomeDirAsImplementationClasspath() {
1 * executorFactory.create() >> executor
File customUserHome = tmpDir.file('customUserHome')
@@ -154,6 +156,7 @@ class DistributionFactoryTest extends Specification {
(result.asFiles.path as Set).every { it.contains('customUserHome')}
}
+ @LeaksFileHandles
def usesZipDistributionInstalledIntoSpecifiedUserHomeDirAsImplementationClasspath() {
1 * executorFactory.create() >> executor
File customUserHome = tmpDir.file('customUserHome')
@@ -171,6 +174,7 @@ class DistributionFactoryTest extends Specification {
(result.asFiles.path as Set).every { it.contains('customUserHome')}
}
+ @LeaksFileHandles
def reportsZipDownload() {
File customUserHome = tmpDir.file('customUserHome')
def zipFile = createZip {
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnectionTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnectionTest.groovy
index 6367575..2fc03d7 100644
--- a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnectionTest.groovy
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/BuildActionRunnerBackedConsumerConnectionTest.groovy
@@ -132,13 +132,14 @@ class BuildActionRunnerBackedConsumerConnectionTest extends Specification {
def "fails when build action requested"() {
given:
parameters.tasks >> ['a']
+ parameters.entryPointName >> "<api>"
when:
connection.run(Stub(BuildAction), parameters)
then:
UnsupportedVersionException e = thrown()
- e.message == /The version of Gradle you are using (1.2) does not support execution of build actions provided by the tooling API client. Support for this was added in Gradle 1.8 and is available in all later versions./
+ e.message == /The version of Gradle you are using (1.2) does not support the <api>. Support for this is available in Gradle 1.8 and all later versions./
}
interface TestBuildActionRunner extends ConnectionVersion4, BuildActionRunner, ConfigurableConnection {
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/ConnectionVersion4BackedConsumerConnectionTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/ConnectionVersion4BackedConsumerConnectionTest.groovy
deleted file mode 100644
index f7c7e86..0000000
--- a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/ConnectionVersion4BackedConsumerConnectionTest.groovy
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.gradle.tooling.internal.consumer.connection
-
-import org.gradle.tooling.UnsupportedVersionException
-import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter
-import org.gradle.tooling.internal.consumer.Distribution
-import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters
-import org.gradle.tooling.internal.protocol.ConnectionMetaDataVersion1
-import org.gradle.tooling.internal.protocol.ConnectionVersion4
-import org.gradle.tooling.model.GradleProject
-import org.gradle.tooling.model.build.BuildEnvironment
-import spock.lang.Specification
-
-class ConnectionVersion4BackedConsumerConnectionTest extends Specification {
- final Distribution distribution = Mock(Distribution)
- final ConsumerOperationParameters parameters = Mock()
- final ConnectionVersion4 connection = Mock()
- final ConnectionMetaDataVersion1 metaDataVersion1 = Mock()
- final ProtocolToModelAdapter adapter = new ProtocolToModelAdapter()
-
- def setup() {
- _ * connection.metaData >> metaDataVersion1
- _ * metaDataVersion1.version >> '1.0-milestoneX'
- }
-
- def "run fails"() {
- def connection = new ConnectionVersion4BackedConsumerConnection(distribution, connection, adapter)
-
- when:
- connection.run(GradleProject.class, parameters)
-
- then:
- UnsupportedVersionException e = thrown()
- e != null
- }
-
- def "partial BuildEnvirnment"() {
- def connection = new ConnectionVersion4BackedConsumerConnection(distribution, connection, adapter)
-
- when:
- def buildEnv = connection.run(BuildEnvironment.class, parameters)
-
- then:
- buildEnv.gradle.gradleVersion == '1.0-milestoneX'
- }
-}
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnectionTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnectionTest.groovy
index dabdd0d..b6f358a 100644
--- a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnectionTest.groovy
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/InternalConnectionBackedConsumerConnectionTest.groovy
@@ -125,24 +125,39 @@ class InternalConnectionBackedConsumerConnectionTest extends Specification {
def "fails when both tasks and model requested"() {
given:
parameters.tasks >> ['a']
+ parameters.entryPointName >> "<api>"
when:
connection.run(GradleProject.class, parameters)
then:
UnsupportedOperationConfigurationException e = thrown()
- e.message.startsWith("Unsupported configuration: modelBuilder.forTasks()")
+ e.message == /The version of Gradle you are using (1.0-milestone-8) does not support the <api> forTasks() configuration option. Support for this is available in Gradle 1.2 and all later versions./
+ }
+
+ def "fails when arguments specified with 1.0-m8"() {
+ given:
+ parameters.arguments >> ['-thing']
+ parameters.entryPointName >> "<api>"
+
+ when:
+ connection.run(GradleProject.class, parameters)
+
+ then:
+ UnsupportedOperationConfigurationException e = thrown()
+ e.message == /The version of Gradle you are using (1.0-milestone-8) does not support the <api> withArguments() configuration option. Support for this is available in Gradle 1.0 and all later versions./
}
def "fails when build action requested"() {
given:
parameters.tasks >> ['a']
+ parameters.entryPointName >> "<api>"
when:
connection.run(Stub(BuildAction), parameters)
then:
UnsupportedVersionException e = thrown()
- e.message == /The version of Gradle you are using (1.0-milestone-8) does not support execution of build actions provided by the tooling API client. Support for this was added in Gradle 1.8 and is available in all later versions./
+ e.message == /The version of Gradle you are using (1.0-milestone-8) does not support the <api>. Support for this is available in Gradle 1.8 and all later versions./
}
}
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnectionTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnectionTest.groovy
index 184afa3..a7f5ef1 100644
--- a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnectionTest.groovy
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/ModelBuilderBackedConsumerConnectionTest.groovy
@@ -120,13 +120,14 @@ class ModelBuilderBackedConsumerConnectionTest extends Specification {
def "fails when build action requested"() {
given:
parameters.tasks >> ['a']
+ parameters.entryPointName >> "<api>"
when:
connection.run(Stub(BuildAction), parameters)
then:
UnsupportedVersionException e = thrown()
- e.message == /The version of Gradle you are using (1.6) does not support execution of build actions provided by the tooling API client. Support for this was added in Gradle 1.8 and is available in all later versions./
+ e.message == /The version of Gradle you are using (1.6) does not support the <api>. Support for this is available in Gradle 1.8 and all later versions./
}
interface TestModelBuilder extends ModelBuilder, ConnectionVersion4, ConfigurableConnection {
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/TestExecutionConsumerConnectionTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/TestExecutionConsumerConnectionTest.groovy
new file mode 100644
index 0000000..072d7c6
--- /dev/null
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/TestExecutionConsumerConnectionTest.groovy
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.tooling.internal.consumer.connection
+
+import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter
+import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters
+import org.gradle.tooling.internal.consumer.versioning.ModelMapping
+import org.gradle.tooling.internal.protocol.ConfigurableConnection
+import org.gradle.tooling.internal.protocol.ConnectionMetaDataVersion1
+import org.gradle.tooling.internal.protocol.ConnectionVersion4
+import org.gradle.tooling.internal.protocol.InternalCancellableConnection
+import org.gradle.tooling.internal.protocol.test.InternalTestExecutionConnection
+import org.gradle.tooling.internal.consumer.TestExecutionRequest
+import spock.lang.Specification
+
+class TestExecutionConsumerConnectionTest extends Specification {
+
+ def "calls delegate connection"() {
+ given:
+ TestConnection delegate = newDelegateConnection()
+ TestExecutionConsumerConnection connection = new TestExecutionConsumerConnection(delegate, Mock(ModelMapping), Mock(ProtocolToModelAdapter))
+ TestExecutionRequest testExecutionRequest = Mock(TestExecutionRequest)
+ ConsumerOperationParameters operationParameters = Mock()
+ when:
+ connection.runTests(testExecutionRequest, operationParameters)
+
+ then:
+ 1 * delegate.runTests(testExecutionRequest, _, operationParameters)
+ }
+
+ private TestConnection newDelegateConnection() {
+ TestConnection delegate = Mock(TestConnection)
+ ConnectionMetaDataVersion1 connectionMetaData = Mock()
+ 1 * delegate.getMetaData() >> connectionMetaData
+ 1 * connectionMetaData.getVersion() >> "2.6-rc-1"
+ delegate
+ }
+
+ interface TestConnection extends InternalTestExecutionConnection, ConnectionVersion4, InternalCancellableConnection, ConfigurableConnection {}
+}
+
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/UnsupportedOlderVersionConnectionTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/UnsupportedOlderVersionConnectionTest.groovy
new file mode 100644
index 0000000..7a6a524
--- /dev/null
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/connection/UnsupportedOlderVersionConnectionTest.groovy
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.tooling.internal.consumer.connection
+
+import org.gradle.tooling.UnsupportedVersionException
+import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter
+import org.gradle.tooling.internal.consumer.Distribution
+import org.gradle.tooling.internal.consumer.parameters.ConsumerOperationParameters
+import org.gradle.tooling.internal.protocol.ConnectionMetaDataVersion1
+import org.gradle.tooling.internal.protocol.ConnectionVersion4
+import org.gradle.tooling.model.GradleProject
+import org.gradle.tooling.model.build.BuildEnvironment
+import spock.lang.Specification
+
+class UnsupportedOlderVersionConnectionTest extends Specification {
+ final Distribution distribution = Mock(Distribution)
+ final ConsumerOperationParameters parameters = Mock()
+ final ConnectionVersion4 connection = Mock()
+ final ConnectionMetaDataVersion1 metaDataVersion1 = Mock()
+ final ProtocolToModelAdapter adapter = new ProtocolToModelAdapter()
+
+ def setup() {
+ _ * connection.metaData >> metaDataVersion1
+ _ * metaDataVersion1.version >> '1.0-milestoneX'
+ }
+
+ def "run fails"() {
+ def connection = new UnsupportedOlderVersionConnection(distribution, connection, adapter)
+
+ when:
+ connection.run(GradleProject.class, parameters)
+
+ then:
+ UnsupportedVersionException e = thrown()
+ e != null
+ }
+
+ def "partial BuildEnvirnment"() {
+ def connection = new UnsupportedOlderVersionConnection(distribution, connection, adapter)
+
+ when:
+ def buildEnv = connection.run(BuildEnvironment.class, parameters)
+
+ then:
+ buildEnv.gradle.gradleVersion == '1.0-milestoneX'
+ }
+}
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoaderTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoaderTest.groovy
index eb29b22..96ddbe9 100644
--- a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoaderTest.groovy
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/loader/DefaultToolingImplementationLoaderTest.groovy
@@ -91,7 +91,7 @@ class DefaultToolingImplementationLoaderTest extends Specification {
def adaptedConnection = loader.create(distribution, loggerFactory, connectionParameters, cancellationToken)
then:
- adaptedConnection.class == ConnectionVersion4BackedConsumerConnection.class
+ adaptedConnection.class == UnsupportedOlderVersionConnection.class
}
private getToolingApiResourcesDir(Class implementation) {
diff --git a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParametersTest.groovy b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParametersTest.groovy
index dd52ae2..ddc901a 100644
--- a/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParametersTest.groovy
+++ b/subprojects/tooling-api/src/test/groovy/org/gradle/tooling/internal/consumer/parameters/ConsumerOperationParametersTest.groovy
@@ -25,50 +25,8 @@ import spock.lang.Specification
class ConsumerOperationParametersTest extends Specification {
- def "null or empty arguments have the same meaning"() {
- def params = ConsumerOperationParameters.builder()
- when:
- params.arguments = null
-
- then:
- params.build().arguments == null
-
- when:
- params.arguments = []
-
- then:
- params.build().arguments == null
-
- when:
- params.arguments = ['-Dfoo']
-
- then:
- params.build().arguments == ['-Dfoo']
- }
-
- def "null or empty jvm arguments have the same meaning"() {
- def params = ConsumerOperationParameters.builder()
- when:
- params.jvmArguments = null
-
- then:
- params.build().jvmArguments == null
-
- when:
- params.jvmArguments = []
-
- then:
- params.build().jvmArguments == null
-
- when:
- params.jvmArguments = ['-Xmx']
-
- then:
- params.build().jvmArguments == ['-Xmx']
- }
-
def "task names and empty launchables"() {
- def builder = ConsumerOperationParameters.builder()
+ def builder = ConsumerOperationParameters.builder().setEntryPoint("entry-point")
when:
builder.tasks = ['a', 'b']
def params = builder.build()
@@ -79,7 +37,7 @@ class ConsumerOperationParametersTest extends Specification {
}
def "launchables from provider"() {
- def builder = ConsumerOperationParameters.builder()
+ def builder = ConsumerOperationParameters.builder().setEntryPoint("entry-point")
when:
def launchable1 = Mock(InternalLaunchable)
def launchable2 = Mock(InternalLaunchable)
@@ -92,7 +50,7 @@ class ConsumerOperationParametersTest extends Specification {
}
def "launchables from adapters"() {
- def builder = ConsumerOperationParameters.builder()
+ def builder = ConsumerOperationParameters.builder().setEntryPoint("entry-point")
when:
def launchable1 = Mock(TaskListingLaunchable)
def paths1 = Sets.newTreeSet()
diff --git a/subprojects/tooling-api/tooling-api.gradle b/subprojects/tooling-api/tooling-api.gradle
index b76e6fe..7493c56 100644
--- a/subprojects/tooling-api/tooling-api.gradle
+++ b/subprojects/tooling-api/tooling-api.gradle
@@ -18,6 +18,7 @@ dependencies {
integTestRuntime project(':buildComparison')
integTestRuntime project(":ivy")
integTestRuntime project(":maven")
+
integTestRuntime project(":toolingApiBuilders")
}
@@ -25,7 +26,13 @@ useTestFixtures()
integTestTasks.all {
dependsOn({ rootProject.getTasksByName('publishLocalArchives', true) }, ':distributions:binZip')
+}
+
+integTest {
+ jvmArgs "-XX:MaxPermSize=500m"
+}
+forkingIntegTest {
if (isCiServer) {
maxParallelForks = Math.min(2, rootProject.maxParallelForks)
}
diff --git a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy
index b023169..ddb6f00 100644
--- a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy
+++ b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy
@@ -39,7 +39,7 @@ class LiveOutputIntegrationTest extends AbstractIntegrationTest {
@Before
void setUp() {
- NativeServicesTestFixture.initialize(executer.gradleUserHomeDir)
+ NativeServicesTestFixture.initialize()
javaprojectDir = sample.dir
}
diff --git a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/ModelTasksGradleUIIntegrationTest.groovy b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/ModelTasksGradleUIIntegrationTest.groovy
index 848e456..464a2a4 100644
--- a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/ModelTasksGradleUIIntegrationTest.groovy
+++ b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/ModelTasksGradleUIIntegrationTest.groovy
@@ -29,7 +29,7 @@ class ModelTasksGradleUIIntegrationTest extends AbstractIntegrationSpec {
GradlePluginLord gradlePluginLord = new GradlePluginLord()
def setup() {
- NativeServicesTestFixture.initialize(executer.gradleUserHomeDir)
+ NativeServicesTestFixture.initialize()
gradlePluginLord.setCurrentDirectory(temporaryFolder.testDirectory);
gradlePluginLord.setGradleHomeDirectory(distribution.gradleHomeDir);
gradlePluginLord.addCommandLineArgumentAlteringListener(new ExtraTestCommandLineOptionsListener(executer.gradleUserHomeDir))
diff --git a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/MultiprojectProjectAndTaskListIntegrationTest.groovy b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/MultiprojectProjectAndTaskListIntegrationTest.groovy
index bf2ec71..2318e65 100644
--- a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/MultiprojectProjectAndTaskListIntegrationTest.groovy
+++ b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/MultiprojectProjectAndTaskListIntegrationTest.groovy
@@ -40,7 +40,7 @@ class MultiprojectProjectAndTaskListIntegrationTest extends AbstractIntegrationT
@Before
void setUp() {
- NativeServicesTestFixture.initialize(executer.gradleUserHomeDir)
+ NativeServicesTestFixture.initialize()
gradlePluginLord.setCurrentDirectory(sample.dir);
gradlePluginLord.setGradleHomeDirectory(distribution.gradleHomeDir);
gradlePluginLord.addCommandLineArgumentAlteringListener(new ExtraTestCommandLineOptionsListener(executer.gradleUserHomeDir))
diff --git a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OpenApiUiTest.groovy b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OpenApiUiTest.groovy
index 7b22c18..cbc8e99 100644
--- a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OpenApiUiTest.groovy
+++ b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OpenApiUiTest.groovy
@@ -25,9 +25,9 @@ import org.gradle.openapi.external.foundation.favorites.FavoriteTaskVersion1
import org.gradle.openapi.external.foundation.favorites.FavoritesEditorVersion1
import org.gradle.openapi.external.ui.*
import org.gradle.openapi.wrappers.ui.SinglePaneUIWrapper
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.testfixtures.internal.NativeServicesTestFixture
-import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.util.PreconditionVerifier
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@@ -59,7 +59,7 @@ class OpenApiUiTest {
@Before
void setup() {
- NativeServicesTestFixture.initialize(buildContext.gradleUserHomeDir)
+ NativeServicesTestFixture.initialize()
temporaryFolder.file("settings.gradle") << "include 'services', 'services:webservice', 'api'"
temporaryFolder.file("build.gradle") << "allprojects { apply plugin: 'java' }"
}
diff --git a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OutputUILordTest.groovy b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OutputUILordTest.groovy
index bc7d6f1..921ca95 100644
--- a/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OutputUILordTest.groovy
+++ b/subprojects/ui/src/integTest/groovy/org/gradle/integtests/OutputUILordTest.groovy
@@ -18,7 +18,9 @@ package org.gradle.integtests
import org.gradle.integtests.fixtures.TestResources
import org.gradle.openapi.external.ui.OutputUILordVersion1
import org.gradle.openapi.external.ui.SinglePaneUIVersion1
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
+import org.gradle.testfixtures.internal.NativeServicesTestFixture
import org.gradle.util.PreconditionVerifier
import org.gradle.util.Requires
import org.gradle.util.TestPrecondition
@@ -98,7 +100,9 @@ class OutputUILordTest {
}
@Test
+ @LeaksFileHandles
void testReExecute() {
+ NativeServicesTestFixture.initialize()
SinglePaneUIVersion1 singlePane = openApi.createSinglePaneUI()
OutputUILordVersion1 outputUILord = singlePane.getOutputLord()
diff --git a/subprojects/ui/src/main/java/org/gradle/gradleplugin/foundation/GradlePluginLord.java b/subprojects/ui/src/main/java/org/gradle/gradleplugin/foundation/GradlePluginLord.java
index 653ca33..1349fe6 100644
--- a/subprojects/ui/src/main/java/org/gradle/gradleplugin/foundation/GradlePluginLord.java
+++ b/subprojects/ui/src/main/java/org/gradle/gradleplugin/foundation/GradlePluginLord.java
@@ -16,7 +16,7 @@
package org.gradle.gradleplugin.foundation;
import org.codehaus.groovy.runtime.StackTraceUtils;
-import org.gradle.api.internal.classpath.DefaultModuleRegistry;
+import org.gradle.api.internal.classpath.DefaultGradleDistributionLocator;
import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.logging.Logger;
@@ -143,7 +143,7 @@ public class GradlePluginLord {
if (gradleHomeProperty != null) {
gradleHomeDirectory = new File(gradleHomeProperty);
} else {
- gradleHomeDirectory = new DefaultModuleRegistry().getGradleHome();
+ gradleHomeDirectory = new DefaultGradleDistributionLocator().getGradleHome();
}
}
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperChecksumVerificationTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperChecksumVerificationTest.groovy
new file mode 100644
index 0000000..b9dc1f5
--- /dev/null
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperChecksumVerificationTest.groovy
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.gradle.integtests
+
+import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.internal.hash.HashUtil
+import org.gradle.test.fixtures.file.LeaksFileHandles
+import org.gradle.test.fixtures.server.http.HttpServer
+import org.junit.Rule
+
+import static org.gradle.util.TextUtil.normaliseFileAndLineSeparators
+
+ at LeaksFileHandles
+class WrapperChecksumVerificationTest extends AbstractIntegrationSpec {
+ @Rule
+ HttpServer server = new HttpServer()
+
+ def setup() {
+ executer.beforeExecute(new WrapperSetup())
+ server.allowGetOrHead('/gradle-bin.zip', distribution.binDistribution)
+ server.start()
+ }
+
+ def "wrapper execution fails when using bad checksum"() {
+ given:
+ buildFile << """
+ wrapper {
+ distributionUrl = '${server.address}/gradle-bin.zip'
+ }
+"""
+
+ succeeds('wrapper')
+
+ and:
+ file('gradle/wrapper/gradle-wrapper.properties') << 'distributionSha256Sum=bad'
+
+ when:
+ def failure = executer.usingExecutable("gradlew").withStackTraceChecksDisabled().runWithFailure()
+ def f = new File(file("user-home/wrapper/dists/gradle-bin").listFiles()[0], "gradle-bin.zip")
+
+
+ then:
+ def errorOutput = normaliseFileAndLineSeparators(failure.error)
+ errorOutput.startsWith(normaliseFileAndLineSeparators("""
+Verification of Gradle distribution failed!
+
+Your Gradle distribution may have been tampered with.
+Confirm that the 'distributionSha256Sum' property in your gradle-wrapper.properties file is correct and you are downloading the wrapper from a trusted source.
+
+ Distribution Url: ${server.address}/gradle-bin.zip
+Download Location: $f.absolutePath
+Expected checksum: 'bad'
+ Actual checksum: '${HashUtil.sha256(distribution.binDistribution).asZeroPaddedHexString(64)}'
+""".trim()))
+ }
+
+ def "wrapper successfully verifies good checksum"() {
+ given:
+ buildFile << """
+ wrapper {
+ distributionUrl = '${server.address}/gradle-bin.zip'
+ }
+"""
+
+ succeeds('wrapper')
+
+ and:
+ file('gradle/wrapper/gradle-wrapper.properties') << "distributionSha256Sum=${HashUtil.sha256(distribution.binDistribution).asZeroPaddedHexString(64)}"
+
+ when:
+ def success = executer.usingExecutable("gradlew").run()
+
+ then:
+ success.output.contains('BUILD SUCCESSFUL')
+ }
+}
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperConcurrentDownloadTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperConcurrentDownloadTest.groovy
index 7de3b06..fd97459 100644
--- a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperConcurrentDownloadTest.groovy
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperConcurrentDownloadTest.groovy
@@ -17,6 +17,7 @@ package org.gradle.integtests
import org.apache.commons.io.IOUtils
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
import org.junit.Rule
import org.junit.rules.ExternalResource
@@ -30,6 +31,7 @@ import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
+ at LeaksFileHandles
class WrapperConcurrentDownloadTest extends AbstractIntegrationSpec {
@Rule BlockingDownloadHttpServer server = new BlockingDownloadHttpServer(distribution.binDistribution)
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperCrossVersionIntegrationTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperCrossVersionIntegrationTest.groovy
index ee3323d..2d8b5f7 100644
--- a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperCrossVersionIntegrationTest.groovy
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperCrossVersionIntegrationTest.groovy
@@ -19,8 +19,10 @@ import org.gradle.integtests.fixtures.CrossVersionIntegrationSpec
import org.gradle.integtests.fixtures.executer.GradleDistribution
import org.gradle.integtests.fixtures.executer.GradleExecuter
import org.gradle.integtests.fixtures.executer.IntegrationTestBuildContext
-import org.gradle.internal.SystemProperties
+import org.gradle.test.fixtures.file.LeaksFileHandles
+import org.junit.Assume
+ at LeaksFileHandles
class WrapperCrossVersionIntegrationTest extends CrossVersionIntegrationSpec {
def setup() {
requireOwnGradleUserHomeDir()
@@ -36,13 +38,10 @@ class WrapperCrossVersionIntegrationTest extends CrossVersionIntegrationSpec {
checkWrapperWorksWith(current, previous)
}
- void checkWrapperWorksWith(GradleDistribution wrapperGenVersion, GradleDistribution executionVersion) {
- if (!wrapperGenVersion.wrapperCanExecute(executionVersion.version)) {
- println "skipping $wrapperGenVersion as its wrapper cannot execute version ${executionVersion.version.version}"
- return
- }
+ void checkWrapperWorksWith(GradleDistribution wrapperVersion, GradleDistribution executionVersion) {
+ Assume.assumeTrue("skipping $wrapperVersion as its wrapper cannot execute version ${executionVersion.version.version}", wrapperVersion.wrapperCanExecute(executionVersion.version))
- println "use wrapper from $wrapperGenVersion to build using $executionVersion"
+ println "use wrapper from $wrapperVersion to build using $executionVersion"
buildFile << """
@@ -61,40 +60,43 @@ if (wrapper.hasProperty('urlRoot')) {
println "using Java version \${System.getProperty('java.version')}"
task hello {
- doLast { println "hello from \$gradle.gradleVersion" }
+ doLast {
+ println "hello from \$gradle.gradleVersion"
+ println "using distribution at \$gradle.gradleHomeDir"
+ println "using Gradle user home at \$gradle.gradleUserHomeDir"
+ }
}
"""
- version(wrapperGenVersion).withTasks('wrapper').run()
- def result = version(executionVersion, wrapperGenVersion).usingExecutable('gradlew').withTasks('hello').run()
+ version(wrapperVersion).withTasks('wrapper').run()
+
+ def executer = version(executionVersion, wrapperVersion)
+ def result = executer.usingExecutable('gradlew').withTasks('hello').run()
+
assert result.output.contains("hello from $executionVersion.version.version")
+ assert result.output.contains("using distribution at ${executer.gradleUserHomeDir.file("wrapper/dists")}")
+ assert result.output.contains("using Gradle user home at $executer.gradleUserHomeDir")
}
GradleExecuter version(GradleDistribution runtime, GradleDistribution wrapper) {
- def executer = super.version(runtime)
+ def executer = super.version(wrapper)
+
+ if (!wrapper.supportsSpacesInGradleAndJavaOpts) {
+ // Don't use the test-specific location as this contains spaces
+ executer.withGradleUserHomeDir(new IntegrationTestBuildContext().gradleUserHomeDir)
+ }
+
/**
* We additionally pass the gradle user home as a system property.
- * Early gradle wrapper (< 1.7 don't honor --gradle-user-home command line option correctly
+ * Early gradle wrapper versions (< 1.7) don't honor the --gradle-user-home command line option correctly
* and leaking gradle dist under test into ~/.gradle/wrapper.
*/
if (!wrapper.wrapperSupportsGradleUserHomeCommandLineOption) {
- if (!wrapper.supportsSpacesInGradleAndJavaOpts) {
- // Don't use the test-specific location as this contains spaces
- executer.withGradleUserHomeDir(new IntegrationTestBuildContext().gradleUserHomeDir)
-
- def buildDirTmp = file("build/tmp")
- if (buildDirTmp.absolutePath.contains(" ")) {
- def jvmTmp = SystemProperties.instance.javaIoTmpDir
- if (jvmTmp.contains(" ")) {
- throw new IllegalStateException("Cannot run test as there is no tmp dir location available that does not contain a space in the path")
- } else {
- executer.withTmpDir(jvmTmp)
- }
- } else {
- executer.withTmpDir(buildDirTmp.absolutePath)
- }
- }
- executer.withGradleOpts("-Dgradle.user.home=${executer.gradleUserHomeDir}")
+ executer.withCommandLineGradleOpts("-Dgradle.user.home=${executer.gradleUserHomeDir}")
}
+
+ // Use isolated daemons in order to verify that using the installed distro works, and so that the daemons aren't visible to other tests, because
+ // the installed distro is deleted at the end of this test
+ executer.requireIsolatedDaemons()
return executer
}
}
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperGenerationIntegrationTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperGenerationIntegrationTest.groovy
index 6f81ed2..c1c0f2b 100644
--- a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperGenerationIntegrationTest.groovy
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperGenerationIntegrationTest.groovy
@@ -48,7 +48,7 @@ class WrapperGenerationIntegrationTest extends AbstractIntegrationSpec {
then:
// wrapper needs to be small. Let's check it's smaller than some arbitrary 'small' limit
- file("gradle/wrapper/gradle-wrapper.jar").length() < 52 * 1024
+ file("gradle/wrapper/gradle-wrapper.jar").length() < 53 * 1024
}
def "generated wrapper scripts for given version from command-line"() {
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperHttpIntegrationTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperHttpIntegrationTest.groovy
index 7d22c49..d9fc26d 100644
--- a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperHttpIntegrationTest.groovy
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperHttpIntegrationTest.groovy
@@ -18,6 +18,7 @@ package org.gradle.integtests
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.executer.GradleExecuter
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.server.http.HttpServer
import org.gradle.test.fixtures.server.http.TestProxyServer
import org.gradle.util.GradleVersion
@@ -27,6 +28,7 @@ import static org.gradle.test.matchers.UserAgentMatcher.matchesNameAndVersion
import static org.hamcrest.Matchers.containsString
import static org.junit.Assert.assertThat
+ at LeaksFileHandles
class WrapperHttpIntegrationTest extends AbstractIntegrationSpec {
@Rule HttpServer server = new HttpServer()
@Rule TestProxyServer proxyServer = new TestProxyServer(server)
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperLoggingIntegrationTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperLoggingIntegrationTest.groovy
index 76fa0ef..fcc0480 100644
--- a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperLoggingIntegrationTest.groovy
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperLoggingIntegrationTest.groovy
@@ -17,7 +17,9 @@
package org.gradle.integtests
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.test.fixtures.file.LeaksFileHandles
+ at LeaksFileHandles
class WrapperLoggingIntegrationTest extends AbstractIntegrationSpec {
void setup() {
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperProjectIntegrationTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperProjectIntegrationTest.groovy
index b755964..e9f3aad 100644
--- a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperProjectIntegrationTest.groovy
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperProjectIntegrationTest.groovy
@@ -18,12 +18,14 @@ package org.gradle.integtests
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.executer.GradleExecuter
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.hamcrest.Matchers
import spock.lang.Issue
import static org.hamcrest.Matchers.containsString
import static org.junit.Assert.assertThat
+ at LeaksFileHandles
class WrapperProjectIntegrationTest extends AbstractIntegrationSpec {
void setup() {
assert distribution.binDistribution.exists(): "bin distribution must exist to run this test, you need to run the :distributions:binZip task"
diff --git a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperUserHomeIntegrationTest.groovy b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperUserHomeIntegrationTest.groovy
index 59d0e9e..1eba91d 100644
--- a/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperUserHomeIntegrationTest.groovy
+++ b/subprojects/wrapper/src/integTest/groovy/org/gradle/integtests/WrapperUserHomeIntegrationTest.groovy
@@ -17,9 +17,11 @@
package org.gradle.integtests
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
import spock.lang.Issue
+ at LeaksFileHandles
class WrapperUserHomeIntegrationTest extends AbstractIntegrationSpec {
void setup() {
diff --git a/subprojects/wrapper/src/main/java/org/gradle/wrapper/Install.java b/subprojects/wrapper/src/main/java/org/gradle/wrapper/Install.java
index f1ce549..d128bd6 100644
--- a/subprojects/wrapper/src/main/java/org/gradle/wrapper/Install.java
+++ b/subprojects/wrapper/src/main/java/org/gradle/wrapper/Install.java
@@ -22,6 +22,7 @@ import java.util.*;
import java.util.concurrent.Callable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import java.security.MessageDigest;
public class Install {
public static final String DEFAULT_DISTRIBUTION_PATH = "wrapper/dists";
@@ -36,8 +37,9 @@ public class Install {
this.pathAssembler = pathAssembler;
}
- public File createDist(WrapperConfiguration configuration) throws Exception {
+ public File createDist(final WrapperConfiguration configuration) throws Exception {
final URI distributionUrl = configuration.getDistribution();
+ final String distributionSha256Sum = configuration.getDistributionSha256Sum();
final PathAssembler.LocalDistribution localDistribution = pathAssembler.getDistribution(configuration);
final File distDir = localDistribution.getDistributionDir();
@@ -47,7 +49,7 @@ public class Install {
public File call() throws Exception {
final File markerFile = new File(localZipFile.getParentFile(), localZipFile.getName() + ".ok");
if (distDir.isDirectory() && markerFile.isFile()) {
- return getDistributionRoot(distDir, distDir.getAbsolutePath());
+ return getAndVerifyDistributionRoot(distDir, distDir.getAbsolutePath());
}
boolean needsDownload = !localZipFile.isFile();
@@ -65,10 +67,13 @@ public class Install {
logger.log("Deleting directory " + dir.getAbsolutePath());
deleteDir(dir);
}
+
+ verifyDownloadChecksum(configuration.getDistribution().toString(), localZipFile, distributionSha256Sum);
+
logger.log("Unzipping " + localZipFile.getAbsolutePath() + " to " + distDir.getAbsolutePath());
unzip(localZipFile, distDir);
- File root = getDistributionRoot(distDir, distributionUrl.toString());
+ File root = getAndVerifyDistributionRoot(distDir, distributionUrl.toString());
setExecutablePermissions(root);
markerFile.createNewFile();
@@ -77,7 +82,34 @@ public class Install {
});
}
- private File getDistributionRoot(File distDir, String distributionDescription) {
+ private String calculateSha256Sum(File file)
+ throws Exception {
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ InputStream fis = new FileInputStream(file);
+ int n = 0;
+ byte[] buffer = new byte[4096];
+ while (n != -1) {
+ n = fis.read(buffer);
+ if (n > 0) {
+ md.update(buffer, 0, n);
+ }
+ }
+ byte byteData[] = md.digest();
+
+ StringBuffer hexString = new StringBuffer();
+ for (int i=0; i < byteData.length; i++) {
+ String hex=Integer.toHexString(0xff & byteData[i]);
+ if (hex.length() == 1) {
+ hexString.append('0');
+ }
+ hexString.append(hex);
+ }
+
+ return hexString.toString();
+ }
+
+ private File getAndVerifyDistributionRoot(File distDir, String distributionDescription)
+ throws Exception {
List<File> dirs = listDirs(distDir);
if (dirs.isEmpty()) {
throw new RuntimeException(String.format("Gradle distribution '%s' does not contain any directories. Expected to find exactly 1 directory.", distributionDescription));
@@ -88,6 +120,29 @@ public class Install {
return dirs.get(0);
}
+ private void verifyDownloadChecksum(String sourceUrl, File localZipFile, String expectedSum) throws Exception {
+ if (expectedSum != null) {
+ // if a SHA-256 hash sum has been defined in gradle-wrapper.properties, verify it here
+ String actualSum = calculateSha256Sum(localZipFile);
+ if (!expectedSum.equals(actualSum)) {
+ localZipFile.delete();
+ String message = String.format("Verification of Gradle distribution failed!%n"
+ + "%n"
+ + "Your Gradle distribution may have been tampered with.%n"
+ + "Confirm that the 'distributionSha256Sum' property in your gradle-wrapper.properties file is correct and you are downloading the wrapper from a trusted source.%n"
+ + "%n"
+ + " Distribution Url: %s%n"
+ + "Download Location: %s%n"
+ + "Expected checksum: '%s'%n"
+ + " Actual checksum: '%s'%n",
+ sourceUrl, localZipFile.getAbsolutePath(), expectedSum, actualSum
+ );
+ System.err.println(message);
+ System.exit(1);
+ }
+ }
+ }
+
private List<File> listDirs(File distDir) {
List<File> dirs = new ArrayList<File>();
if (distDir.exists()) {
diff --git a/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperConfiguration.java b/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperConfiguration.java
index c5da7f0..87f6c43 100644
--- a/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperConfiguration.java
+++ b/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperConfiguration.java
@@ -21,6 +21,7 @@ public class WrapperConfiguration {
private URI distribution;
private String distributionBase = PathAssembler.GRADLE_USER_HOME_STRING;
private String distributionPath = Install.DEFAULT_DISTRIBUTION_PATH;
+ private String distributionSha256Sum;
private String zipBase = PathAssembler.GRADLE_USER_HOME_STRING;
private String zipPath = Install.DEFAULT_DISTRIBUTION_PATH;
@@ -48,6 +49,14 @@ public class WrapperConfiguration {
this.distributionPath = distributionPath;
}
+ public String getDistributionSha256Sum() {
+ return distributionSha256Sum;
+ }
+
+ public void setDistributionSha256Sum(String distributionSha256Sum) {
+ this.distributionSha256Sum = distributionSha256Sum;
+ }
+
public String getZipBase() {
return zipBase;
}
diff --git a/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperExecutor.java b/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperExecutor.java
index aac4ff3..858005c 100644
--- a/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperExecutor.java
+++ b/subprojects/wrapper/src/main/java/org/gradle/wrapper/WrapperExecutor.java
@@ -27,8 +27,9 @@ import java.util.Properties;
public class WrapperExecutor {
public static final String DISTRIBUTION_URL_PROPERTY = "distributionUrl";
public static final String DISTRIBUTION_BASE_PROPERTY = "distributionBase";
- public static final String ZIP_STORE_BASE_PROPERTY = "zipStoreBase";
public static final String DISTRIBUTION_PATH_PROPERTY = "distributionPath";
+ public static final String DISTRIBUTION_SHA_256_SUM = "distributionSha256Sum";
+ public static final String ZIP_STORE_BASE_PROPERTY = "zipStoreBase";
public static final String ZIP_STORE_PATH_PROPERTY = "zipStorePath";
private final Properties properties;
private final File propertiesFile;
@@ -56,6 +57,7 @@ public class WrapperExecutor {
config.setDistribution(prepareDistributionUri());
config.setDistributionBase(getProperty(DISTRIBUTION_BASE_PROPERTY, config.getDistributionBase()));
config.setDistributionPath(getProperty(DISTRIBUTION_PATH_PROPERTY, config.getDistributionPath()));
+ config.setDistributionSha256Sum(getProperty(DISTRIBUTION_SHA_256_SUM, config.getDistributionSha256Sum(), false));
config.setZipBase(getProperty(ZIP_STORE_BASE_PROPERTY, config.getZipBase()));
config.setZipPath(getProperty(ZIP_STORE_PATH_PROPERTY, config.getZipPath()));
} catch (Exception e) {
@@ -128,10 +130,14 @@ public class WrapperExecutor {
}
private String getProperty(String propertyName) {
- return getProperty(propertyName, null);
+ return getProperty(propertyName, null, true);
}
private String getProperty(String propertyName, String defaultValue) {
+ return getProperty(propertyName, defaultValue, true);
+ }
+
+ private String getProperty(String propertyName, String defaultValue, boolean required) {
String value = properties.getProperty(propertyName);
if (value != null) {
return value;
@@ -139,7 +145,11 @@ public class WrapperExecutor {
if (defaultValue != null) {
return defaultValue;
}
- return reportMissingProperty(propertyName);
+ if (required) {
+ return reportMissingProperty(propertyName);
+ } else {
+ return null;
+ }
}
private String reportMissingProperty(String propertyName) {
diff --git a/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy b/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy
index 8fd1cab..df2e626 100644
--- a/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy
+++ b/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy
@@ -16,6 +16,7 @@
package org.gradle.wrapper
+import org.gradle.test.fixtures.file.LeaksFileHandles
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.junit.Before
@@ -61,6 +62,7 @@ class InstallTest extends Specification {
explodedZipDir.zipTo(new TestFile(zipDestination))
}
+ @LeaksFileHandles
def "installs distribution and reuses on subsequent access"() {
given:
_ * pathAssembler.getDistribution(configuration) >> localDistribution
@@ -90,6 +92,7 @@ class InstallTest extends Specification {
0 * download._
}
+ @LeaksFileHandles
def "recovers from download failure"() {
def failure = new RuntimeException("broken")
diff --git a/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/WrapperExecutorTest.groovy b/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/WrapperExecutorTest.groovy
index b7dad29..c7dce21 100644
--- a/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/WrapperExecutorTest.groovy
+++ b/subprojects/wrapper/src/test/groovy/org/gradle/wrapper/WrapperExecutorTest.groovy
@@ -38,6 +38,7 @@ class WrapperExecutorTest extends Specification {
properties.distributionPath = 'testDistPath'
properties.zipStoreBase = 'testZipBase'
properties.zipStorePath = 'testZipPath'
+ properties.distributionSha256Sum = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
propertiesFile.parentFile.mkdirs()
propertiesFile.withOutputStream { properties.store(it, 'header') }
}
@@ -52,6 +53,7 @@ class WrapperExecutorTest extends Specification {
wrapper.configuration.distributionPath == 'testDistPath'
wrapper.configuration.zipBase == 'testZipBase'
wrapper.configuration.zipPath == 'testZipPath'
+ wrapper.configuration.distributionSha256Sum == 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
}
def "loads wrapper meta data from specified project directory"() {
@@ -64,6 +66,7 @@ class WrapperExecutorTest extends Specification {
wrapper.configuration.distributionPath == 'testDistPath'
wrapper.configuration.zipBase == 'testZipBase'
wrapper.configuration.zipPath == 'testZipPath'
+ wrapper.configuration.distributionSha256Sum == 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
}
def "uses default meta data when properties file does not exist in project directory"() {
@@ -76,6 +79,7 @@ class WrapperExecutorTest extends Specification {
wrapper.configuration.distributionPath == Install.DEFAULT_DISTRIBUTION_PATH
wrapper.configuration.zipBase == PathAssembler.GRADLE_USER_HOME_STRING
wrapper.configuration.zipPath == Install.DEFAULT_DISTRIBUTION_PATH
+ wrapper.configuration.distributionSha256Sum == null
}
def "properties file need contain only the distribution URL"() {
@@ -83,7 +87,7 @@ class WrapperExecutorTest extends Specification {
def properties = new Properties()
properties.distributionUrl = 'http://server/test/gradle.zip'
propertiesFile.withOutputStream { properties.store(it, 'header') }
-
+
def wrapper = WrapperExecutor.forWrapperPropertiesFile(propertiesFile, System.out)
expect:
diff --git a/subprojects/wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties b/subprojects/wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties
index 74fdc73..38dfcdd 100644
--- a/subprojects/wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties
+++ b/subprojects/wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties
@@ -3,3 +3,4 @@ distributionBase=testDistBase
zipStoreBase=testZipBase
distributionPath=testDistPath
zipStorePath=testZipPath
+distributionSha256Sum=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
diff --git a/version.txt b/version.txt
index 95e3ba8..1effb00 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-2.5
+2.7
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/gradle.git
More information about the pkg-java-commits
mailing list