1
+ /*
2
+ * Copyright 2002-2015 the original author or authors.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ package org.springframework.build.gradle
18
+
19
+ import org.gradle.api.*
20
+ import org.gradle.api.artifacts.Configuration
21
+ import org.gradle.api.artifacts.ProjectDependency ;
22
+ import org.gradle.api.artifacts.maven.Conf2ScopeMapping
23
+ import org.gradle.api.plugins.MavenPlugin
24
+ import org.gradle.plugins.ide.eclipse.EclipsePlugin
25
+ import org.gradle.plugins.ide.idea.IdeaPlugin
26
+ import org.gradle.api.invocation.*
27
+
28
+ /**
29
+ * Gradle plugin that allows projects to merged together. Primarily developed to
30
+ * allow Spring to support multiple incompatible versions of third-party
31
+ * dependencies (for example Hibernate v3 and v4).
32
+ * <p >
33
+ * The 'merge' extension should be used to define how projects are merged, for example:
34
+ * <pre class =" code" >
35
+ * configure(subprojects) {
36
+ * apply plugin: MergePlugin
37
+ * }
38
+ *
39
+ * project("myproject") {
40
+ * }
41
+ *
42
+ * project("myproject-extra") {
43
+ * merge.into = project("myproject")
44
+ * }
45
+ * </pre>
46
+ * <p >
47
+ * This plugin adds two new configurations:
48
+ * <ul >
49
+ * <li >merging - Contains the projects being merged into this project<li >
50
+ * <li >runtimeMerge - Contains all dependencies that are merge projects. These are used
51
+ * to allow an IDE to reference merge projects.</li>
52
+ * <ul >
53
+ *
54
+ * @author Rob Winch
55
+ * @author Phillip Webb
56
+ */
57
+ class MergePlugin implements Plugin<Project > {
58
+
59
+ private static boolean attachedProjectsEvaluated;
60
+
61
+ public void apply (Project project ) {
62
+ project. plugins. apply(MavenPlugin )
63
+ project. plugins. apply(EclipsePlugin )
64
+ project. plugins. apply(IdeaPlugin )
65
+
66
+ MergeModel model = project. extensions. create(" merge" , MergeModel )
67
+ model. project = project
68
+ project. configurations. create(" merging" )
69
+ Configuration runtimeMerge = project. configurations. create(" runtimeMerge" )
70
+
71
+ // Ensure the IDE can reference merged projects
72
+ project. eclipse. classpath. plusConfigurations + = [ runtimeMerge ]
73
+ project. idea. module. scopes. PROVIDED . plus + = [ runtimeMerge ]
74
+
75
+ // Hook to perform the actual merge logic
76
+ project. afterEvaluate{
77
+ if (it. merge. into != null ) {
78
+ setup(it)
79
+ }
80
+ setupIdeDependencies(it)
81
+ }
82
+
83
+ // Hook to build runtimeMerge dependencies
84
+ if (! attachedProjectsEvaluated) {
85
+ project. gradle. projectsEvaluated{
86
+ postProcessProjects(it)
87
+ }
88
+ attachedProjectsEvaluated = true ;
89
+ }
90
+ }
91
+
92
+ private void setup (Project project ) {
93
+ project. merge. into. dependencies. add(" merging" , project)
94
+ project. dependencies. add(" provided" , project. merge. into. sourceSets. main. output)
95
+ project. dependencies. add(" runtimeMerge" , project. merge. into)
96
+ setupTaskDependencies(project)
97
+ setupMaven(project)
98
+ }
99
+
100
+ private void setupTaskDependencies (Project project ) {
101
+ // invoking a task will invoke the task with the same name on 'into' project
102
+ [" sourcesJar" , " jar" , " javadocJar" , " javadoc" , " install" , " artifactoryPublish" ]. each {
103
+ def task = project. tasks. findByPath(it)
104
+ if (task) {
105
+ task. enabled = false
106
+ task. dependsOn(project. merge. into. tasks. findByPath(it))
107
+ }
108
+ }
109
+
110
+ // update 'into' project artifacts to contain the source artifact contents
111
+ project. merge. into. sourcesJar. from(project. sourcesJar. source)
112
+ project. merge. into. jar. from(project. sourceSets. main. output)
113
+ project. merge. into. javadoc {
114
+ source + = project. javadoc. source
115
+ classpath + = project. javadoc. classpath
116
+ }
117
+ }
118
+
119
+ private void setupIdeDependencies (Project project ) {
120
+ project. configurations. each { c ->
121
+ c. dependencies. findAll( { it instanceof org.gradle.api.artifacts.ProjectDependency } ). each { d ->
122
+ d. dependencyProject. merge. from. each { from ->
123
+ project. dependencies. add(" runtimeMerge" , from)
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ private void setupMaven (Project project ) {
130
+ project. configurations. each { configuration ->
131
+ Conf2ScopeMapping mapping = project. conf2ScopeMappings. getMapping([configuration])
132
+ if (mapping. scope) {
133
+ Configuration intoConfiguration = project. merge. into. configurations. create(
134
+ project. name + " -" + configuration. name)
135
+ configuration. excludeRules. each {
136
+ configuration. exclude([
137
+ (ExcludeRule . GROUP_KEY ) : it. group,
138
+ (ExcludeRule . MODULE_KEY ) : it. module])
139
+ }
140
+ configuration. dependencies. each {
141
+ def intoCompile = project. merge. into. configurations. getByName(" compile" )
142
+ // Protect against changing a compile scope dependency (SPR-10218)
143
+ if (! intoCompile. dependencies. contains(it)) {
144
+ intoConfiguration. dependencies. add(it)
145
+ }
146
+ }
147
+ def index = project. parent. childProjects. findIndexOf {p -> p. getValue() == project}
148
+ project. merge. into. install. repositories. mavenInstaller. pom. scopeMappings. addMapping(
149
+ mapping. priority + 100 + index, intoConfiguration, mapping. scope)
150
+ }
151
+ }
152
+ }
153
+
154
+ private postProcessProjects (Gradle gradle ) {
155
+ gradle. allprojects(new Action<Project > () {
156
+ public void execute (Project project ) {
157
+ project. configurations. getByName(" runtime" ). allDependencies. withType(ProjectDependency ). each{
158
+ Configuration dependsOnMergedFrom = it. dependencyProject. configurations. getByName(" merging" );
159
+ dependsOnMergedFrom. dependencies. each{ dep ->
160
+ project. dependencies. add(" runtimeMerge" , dep. dependencyProject)
161
+ }
162
+ }
163
+ }
164
+ });
165
+ }
166
+ }
167
+
168
+ class MergeModel {
169
+ Project project;
170
+ Project into;
171
+ List<Project > from = [];
172
+
173
+ public void setInto (Project into ) {
174
+ this . into = into;
175
+ into. merge. from. add(project);
176
+ }
177
+ }
0 commit comments