Skip to content

Commit f597292

Browse files
committed
improved error message for some cases when .groovy/grapes cache is corrupt
1 parent dea71cc commit f597292

1 file changed

Lines changed: 64 additions & 2 deletions

File tree

  • subprojects/groovy-grape-ivy/src/main/groovy/groovy/grape/ivy

subprojects/groovy-grape-ivy/src/main/groovy/groovy/grape/ivy/GrapeIvy.groovy

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import org.apache.ivy.core.module.id.ModuleId
4242
import org.apache.ivy.core.module.id.ModuleRevisionId
4343
import org.apache.ivy.core.report.ArtifactDownloadReport
4444
import org.apache.ivy.core.report.ResolveReport
45+
import org.apache.ivy.core.resolve.IvyNode
4546
import org.apache.ivy.core.resolve.ResolveOptions
4647
import org.apache.ivy.core.settings.IvySettings
4748
import org.apache.ivy.plugins.matcher.ExactPatternMatcher
@@ -102,7 +103,8 @@ class GrapeIvy implements GrapeEngine {
102103
Message.setDefaultLogger(new PlatformLoggingMessageLogger())
103104

104105
settings = new IvySettings()
105-
settings.setVariable('user.home.url', new File(System.getProperty('user.home')).toURI().toURL() as String)
106+
def url = new File(System.getProperty('user.home')).toURI().toURL() as String
107+
settings.setVariable('user.home.url', url.endsWith("/") ? url[0..-2] : url)
106108
File grapeConfig = getLocalGrapeConfig()
107109
if (grapeConfig.exists()) {
108110
try {
@@ -451,7 +453,7 @@ class GrapeIvy implements GrapeEngine {
451453
}
452454

453455
if (report.hasError()) {
454-
throw new RuntimeException("Error grabbing Grapes -- ${report.getAllProblemMessages()}")
456+
throw new RuntimeException("Error grabbing Grapes -- ${report.getAllProblemMessages()}${diagnoseHalfPopulatedLocalM2(report)}")
455457
}
456458
if (report.getDownloadSize() && reportDownloads) {
457459
System.err.println("Downloaded ${report.getDownloadSize() >> 10} Kbytes in ${report.getDownloadTime()}ms:\n ${report.getAllArtifactsReports()*.toString().join('\n ')}")
@@ -466,6 +468,66 @@ class GrapeIvy implements GrapeEngine {
466468
report
467469
}
468470

471+
/**
472+
* When a download fails, check whether the local Maven cache has the POM but
473+
* not the primary artifact for any failed dependency. Ivy binds artifact
474+
* downloads to the resolver that resolved the descriptor, so a localm2 with
475+
* only the POM blocks the chain from falling through to Maven Central.
476+
*/
477+
private static String diagnoseHalfPopulatedLocalM2(ResolveReport report) {
478+
File m2root = new File(System.getProperty('user.home'), '.m2/repository')
479+
if (!m2root.isDirectory()) return ''
480+
StringBuilder hint = new StringBuilder()
481+
Set<String> seen = new LinkedHashSet<String>()
482+
// Artifact-level failures ("download failed: g#a;v!a.jar") — primary half-population.
483+
for (ArtifactDownloadReport adr : report.getFailedArtifactsReports()) {
484+
String classifier = (String) adr.getArtifact().getExtraAttribute('classifier')
485+
appendHintForCoord(adr.getArtifact().getModuleRevisionId(),
486+
adr.getArtifact().getName(),
487+
adr.getArtifact().getExt() ?: 'jar',
488+
classifier, m2root, hint, seen)
489+
}
490+
// Dependency-level failures ("unresolved dependency: g#a;v not found") — typical when
491+
// the JAR-only-in-localm2 case combines with a transient Central descriptor lookup miss.
492+
for (IvyNode node : report.getUnresolvedDependencies()) {
493+
appendHintForCoord(node.getId(), node.getId().getName(), 'jar', null, m2root, hint, seen)
494+
}
495+
return hint.toString()
496+
}
497+
498+
private static void appendHintForCoord(ModuleRevisionId mrid, String artName, String ext,
499+
String classifier, File m2root, StringBuilder hint,
500+
Set<String> seen) {
501+
String org = mrid.getOrganisation()
502+
String mod = mrid.getName()
503+
String rev = mrid.getRevision()
504+
String coord = "${org}:${mod}:${rev}".toString()
505+
if (!seen.add(coord)) return
506+
File dir = new File(m2root, "${org.replace('.', '/')}/${mod}/${rev}")
507+
if (!dir.isDirectory()) return
508+
File pom = new File(dir, "${mod}-${rev}.pom")
509+
String suffix = classifier ? "-${classifier}" : ''
510+
File primary = new File(dir, "${artName}-${rev}${suffix}.${ext}")
511+
if (pom.exists() && !primary.exists()) {
512+
File grapeIvyXml = new File(System.getProperty('user.home'),
513+
".groovy/grapes/${org}/${mod}/ivy-${rev}.xml")
514+
hint.append('\nHint: ').append(coord)
515+
.append(' has a POM but no ').append(ext).append(' in your local Maven cache.\n')
516+
.append('Either run: mvn dependency:get -Dartifact=').append(coord).append('\n')
517+
.append('or remove these so Grape can fetch from Maven Central:\n')
518+
.append(' ').append(dir).append('\n')
519+
.append(' ').append(grapeIvyXml).append(' (and ivy-')
520+
.append(rev).append('.xml.original, ivydata-').append(rev).append('.properties)')
521+
} else if (primary.exists() && !pom.exists()) {
522+
hint.append('\nHint: ').append(coord)
523+
.append(' has a ').append(ext).append(' but no POM in your local Maven cache.\n')
524+
.append('Ivy needs the POM to resolve the descriptor; without it the chain falls through ')
525+
.append('to Maven Central and any transient Central failure surfaces as "not found".\n')
526+
.append('Either run: mvn dependency:get -Dartifact=').append(coord).append('\n')
527+
.append('or remove ').append(dir).append(' to force a clean fetch.')
528+
}
529+
}
530+
469531
private addIvyListener() {
470532
ivyInstance.eventManager.addIvyListener { ivyEvent ->
471533
switch (ivyEvent) {

0 commit comments

Comments
 (0)