Skip to content

Commit a5ac4fb

Browse files
authored
Merge pull request #377 from ysb33r/issue-325-alpha-dependencies
Allow script author to bypass Bundler-like strategy for resolving dependencies
2 parents 220982a + 53d8d5b commit a5ac4fb

File tree

5 files changed

+181
-11
lines changed

5 files changed

+181
-11
lines changed

core-plugin/src/integTest/groovy/com/github/jrubygradle/api/core/IvyXmlProxyServerIntegrationSpec.groovy

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,27 @@ class IvyXmlProxyServerIntegrationSpec extends Specification {
167167
findFiles ~/^jruby-openssl-0.10.2-java.gem$/
168168
}
169169

170+
@Issue('https://github.com/jruby-gradle/jruby-gradle-plugin/issues/325')
171+
void 'Resolve a prerelease GEM by excluding from GEM strategy'() {
172+
setup:
173+
withBuildFile '''
174+
gemResolverStrategy {
175+
excludeModule ~/^asciidoctor-pdf$/, ~/.+(alpha|beta).*/
176+
}
177+
178+
dependencies {
179+
something 'rubygems:asciidoctor-pdf-cjk-kai_gen_gothic:0.1.1'
180+
something 'rubygems:asciidoctor-pdf:1.5.0.alpha.8'
181+
}
182+
'''
183+
184+
when:
185+
build()
186+
187+
then:
188+
findFiles (~/^asciidoctor-pdf.*\.gem$/).size() == 3
189+
}
190+
170191
private List<File> findFiles(Pattern pat) {
171192
new File(projectDir, 'build/something').listFiles(new FilenameFilter() {
172193
@Override

core-plugin/src/main/groovy/com/github/jrubygradle/api/core/JRubyCorePlugin.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424
package com.github.jrubygradle.api.core
2525

26-
import com.github.jrubygradle.api.gems.GemGroups
26+
import com.github.jrubygradle.api.gems.GemResolverStrategy
2727
import com.github.jrubygradle.internal.gems.GemVersionResolver
2828
import groovy.transform.CompileStatic
2929
import org.gradle.api.Plugin
@@ -42,7 +42,7 @@ import org.gradle.api.plugins.ExtensionAware
4242
class JRubyCorePlugin implements Plugin<Project> {
4343
@Override
4444
void apply(Project project) {
45-
GemGroups gemGroups = project.extensions.create(GemGroups.NAME, GemGroups)
45+
GemResolverStrategy gemGroups = project.extensions.create(GemResolverStrategy.NAME, GemResolverStrategy)
4646

4747
((ExtensionAware) project.repositories).extensions.create(
4848
RepositoryHandlerExtension.NAME,

core-plugin/src/main/groovy/com/github/jrubygradle/api/core/RepositoryHandlerExtension.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424
package com.github.jrubygradle.api.core
2525

26-
import com.github.jrubygradle.api.gems.GemGroups
26+
import com.github.jrubygradle.api.gems.GemResolverStrategy
2727
import com.github.jrubygradle.internal.core.IvyXmlGlobalProxyRegistry
2828
import groovy.transform.CompileDynamic
2929
import groovy.transform.CompileStatic
@@ -111,7 +111,7 @@ class RepositoryHandlerExtension {
111111
String group
112112
) {
113113
IvyXmlProxyServer proxy = ivyProxies.registerProxy(serverUri, group)
114-
project.extensions.getByType(GemGroups).addGemGroup(group)
114+
project.extensions.getByType(GemResolverStrategy).addGemGroup(group)
115115
restrictToGems(createIvyRepo(serverUri, proxy.bindAddress), group)
116116
}
117117

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright (c) 2014-2019, R. Tyler Croy <[email protected]>,
3+
* Schalk Cronje <[email protected]>, Christian Meier, Lookout, Inc.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining
6+
* a copy of this software and associated documentation files (the
7+
* "Software"), to deal in the Software without restriction, including
8+
* without limitation the rights to use, copy, modify, merge, publish,
9+
* distribute, sublicense, and/or sell copies of the Software, and to
10+
* permit persons to whom the Software is furnished to do so, subject to
11+
* the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be
14+
* included in all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
*/
24+
package com.github.jrubygradle.api.gems
25+
26+
import com.github.jrubygradle.api.core.RepositoryHandlerExtension
27+
import groovy.transform.CompileStatic
28+
import groovy.transform.EqualsAndHashCode
29+
import org.gradle.api.artifacts.Configuration
30+
import org.gradle.api.artifacts.ModuleVersionSelector
31+
32+
import java.util.regex.Pattern
33+
34+
/** Defines groups which contains GEMs and controls GEM resolving rules.
35+
*
36+
* @author Schalk W. Cronjé
37+
*
38+
* @since 2.0
39+
*/
40+
@CompileStatic
41+
class GemResolverStrategy {
42+
43+
public static final String NAME = 'gemResolverStrategy'
44+
45+
/** Is this group/organisation a GEM group ?
46+
*
47+
* @param groupName Name of group/organisation.
48+
* @return {@code true} is group is a GEM group.
49+
*/
50+
boolean isGemGroup(final String groupName) {
51+
groups.contains(groupName)
52+
}
53+
54+
/** Add a new group for GEMs.
55+
*
56+
* @param groupName Name of group to add.
57+
*/
58+
void addGemGroup(final String groupName) {
59+
groups.add(groupName)
60+
}
61+
62+
/** Exclude a configuration from being resolved using the GEM
63+
* version resolver strategy.
64+
*
65+
* @param configs Configurations to be excluded
66+
*/
67+
void excludeConfigurations(Configuration... configs) {
68+
this.excludedConfigurations.addAll(configs*.name)
69+
}
70+
71+
/** Exclude a configuration from being resolved using the GEM
72+
* version resolver strategy.
73+
*
74+
* @param configs Configurations to be excluded
75+
*/
76+
void excludeConfigurations(String... configs) {
77+
this.excludedConfigurations.addAll(configs)
78+
}
79+
80+
/** Exclude a module from being resolved using the GEM version resolver
81+
* strategy.
82+
*
83+
* @param name Module name. Never {@code null}.
84+
* @param version Version. Can be {@code null}.
85+
*/
86+
void excludeModule(String name, String version = null) {
87+
excludedModules.add(new Matcher(
88+
module: Pattern.compile(Pattern.quote(name)),
89+
version: version ? Pattern.compile(Pattern.quote(version)) : null
90+
))
91+
}
92+
93+
/** Exclude a module from being resolved using the GEM version resolver
94+
* strategy.
95+
*
96+
* @param namePattern Pattern for name. Never {@code null}.
97+
* @param versionPattern Pattern for version. Can be {@code null}
98+
*/
99+
void excludeModule(Pattern namePattern, Pattern versionPattern = null) {
100+
excludedModules.add(new Matcher(module: namePattern, version: versionPattern))
101+
}
102+
103+
/** Whether the GEM version resolving strategy should be applied for a specific module.
104+
*
105+
* In most cases this will alsways be {@code true} unless a specific rule excludes it.
106+
*
107+
* @param mvs Module version selector
108+
* @return Whether the Bundler-like version selector atregty may be applied
109+
*/
110+
boolean useGemVersionResolver(ModuleVersionSelector mvs) {
111+
isGemGroup(mvs.group) && excludedModules.find { it.match(mvs.name, mvs.version) }
112+
}
113+
114+
/** Whether the GEM version resolving strategy should be applied to a specific configuration.
115+
*
116+
* In most cases this will always be {@code true} unless a specific rule excludes it.
117+
*
118+
* @param configurationName Name fo configuration
119+
* @return Whether the Bundler-like version selector strategy may be applied
120+
*/
121+
boolean useGemVersionResolver(String configurationName) {
122+
configurationName in excludedConfigurations
123+
}
124+
125+
@EqualsAndHashCode
126+
private class Matcher {
127+
Pattern module
128+
Pattern version
129+
130+
boolean match(String name, String ver) {
131+
name =~ module && (this.version == null || ver ==~ this.version)
132+
}
133+
}
134+
135+
private final Set<Matcher> excludedModules = [].toSet()
136+
private final Set<String> excludedConfigurations = [].toSet()
137+
private final Set<String> groups = [RepositoryHandlerExtension.DEFAULT_GROUP_NAME].toSet()
138+
}

core-plugin/src/main/groovy/com/github/jrubygradle/internal/gems/GemVersionResolver.groovy

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@
2323
*/
2424
package com.github.jrubygradle.internal.gems
2525

26+
import com.github.jrubygradle.api.gems.GemResolverStrategy
2627
import com.github.jrubygradle.api.gems.GemVersion
27-
import com.github.jrubygradle.api.gems.GemGroups
28+
import groovy.transform.CompileDynamic
2829
import groovy.transform.PackageScope
2930
import org.gradle.api.Action
3031
import org.gradle.api.GradleException
3132
import org.gradle.api.artifacts.Configuration
3233
import org.gradle.api.artifacts.DependencyResolveDetails
3334
import org.gradle.api.logging.Logger
3435
import org.gradle.api.logging.Logging
36+
import org.gradle.util.GradleVersion
3537

3638
import static com.github.jrubygradle.api.gems.GemVersion.gemVersionFromGradleIvyRequirement
3739

@@ -44,17 +46,17 @@ import static com.github.jrubygradle.api.gems.GemVersion.gemVersionFromGradleIvy
4446
* @since 2.0
4547
*/
4648
class GemVersionResolver {
47-
static void addGemResolver(Configuration cfg, GemGroups gemGroups, GemVersionResolver versionResolver) {
49+
static void addGemResolver(Configuration cfg, GemResolverStrategy gemGroups, GemVersionResolver versionResolver) {
4850
Action<DependencyResolveDetails> gemResolveRule = {
49-
GemGroups gemgrp, GemVersionResolver resolver, DependencyResolveDetails drd ->
50-
if (gemgrp.isGemGroup(drd.requested.group)) {
51+
String configName, GemResolverStrategy gemgrp, GemVersionResolver resolver, DependencyResolveDetails drd ->
52+
if (gemgrp.useGemVersionResolver(configName) && gemgrp.useGemVersionResolver(drd.requested)) {
5153
resolver.resolve(drd)
5254
}
53-
}.curry(gemGroups, versionResolver)
55+
}.curry(cfg.name, gemGroups, versionResolver)
5456
cfg.resolutionStrategy.eachDependency(gemResolveRule)
5557
}
5658

57-
GemVersionResolver(GemGroups gemGroups, Logger logger, Configuration configuration) {
59+
GemVersionResolver(GemResolverStrategy gemGroups, Logger logger, Configuration configuration) {
5860
this.gemGroups = gemGroups
5961
this.logger = logger
6062
this.configuration = configuration
@@ -81,6 +83,7 @@ class GemVersionResolver {
8183
logger.debug("${configuration} resolved ${next}")
8284

8385
details.useVersion(next.toString())
86+
withReason(details, 'Selected by GEM Version Resolver')
8487
} else {
8588
GemVersion next = gemVersionFromGradleIvyRequirement(details.requested.version)
8689
versions[details.requested.name] = next
@@ -113,12 +116,20 @@ class GemVersionResolver {
113116
)
114117
}
115118

119+
@CompileDynamic
120+
void withReason(DependencyResolveDetails drd, String reason) {
121+
if (HAS_BECAUSE_PROPERTY) {
122+
drd.because(reason)
123+
}
124+
}
125+
116126
@PackageScope
117127
static final GemVersionResolver NULL_RESOLVER = new GemVersionResolver()
118128

129+
private static final HAS_BECAUSE_PROPERTY = GradleVersion.current() >= GradleVersion.version('4.5')
119130
private static final String DBG_SEPARATOR = ' ------------------------'
120131
private final Map versions = [:]
121132
private final Configuration configuration
122133
private final Logger logger
123-
private final GemGroups gemGroups
134+
private final GemResolverStrategy gemGroups
124135
}

0 commit comments

Comments
 (0)