github.com/golang/dep@v0.5.4/gps/solve_failures.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gps 6 7 import ( 8 "bytes" 9 "fmt" 10 "sort" 11 "strings" 12 ) 13 14 func a2vs(a atom) string { 15 if a.v == rootRev || a.v == nil { 16 return "(root)" 17 } 18 19 return fmt.Sprintf("%s@%s", a.id, a.v) 20 } 21 22 type traceError interface { 23 traceString() string 24 } 25 26 type noVersionError struct { 27 pn ProjectIdentifier 28 fails []failedVersion 29 } 30 31 func (e *noVersionError) Error() string { 32 if len(e.fails) == 0 { 33 return fmt.Sprintf("No versions found for project %q.", e.pn.ProjectRoot) 34 } 35 36 var buf bytes.Buffer 37 fmt.Fprintf(&buf, "No versions of %s met constraints:", e.pn.ProjectRoot) 38 for _, f := range e.fails { 39 fmt.Fprintf(&buf, "\n\t%s: %s", f.v, f.f.Error()) 40 } 41 42 return buf.String() 43 } 44 45 func (e *noVersionError) traceString() string { 46 if len(e.fails) == 0 { 47 return fmt.Sprintf("No versions found") 48 } 49 50 var buf bytes.Buffer 51 fmt.Fprintf(&buf, "No versions of %s met constraints:", e.pn.ProjectRoot) 52 for _, f := range e.fails { 53 if te, ok := f.f.(traceError); ok { 54 fmt.Fprintf(&buf, "\n %s: %s", f.v, te.traceString()) 55 } else { 56 fmt.Fprintf(&buf, "\n %s: %s", f.v, f.f.Error()) 57 } 58 } 59 60 return buf.String() 61 } 62 63 // caseMismatchFailure occurs when there are import paths that differ only by 64 // case. The compiler disallows this case. 65 type caseMismatchFailure struct { 66 // goal is the depender atom that tried to introduce the case-varying name, 67 // along with the case-varying name. 68 goal dependency 69 // current is the specific casing of a ProjectRoot that is presently 70 // selected for all possible case variations of its contained unicode code 71 // points. 72 current ProjectRoot 73 // failsib is the list of active dependencies that have determined the 74 // specific casing for the target project. 75 failsib []dependency 76 } 77 78 func (e *caseMismatchFailure) Error() string { 79 if len(e.failsib) == 1 { 80 str := "Could not introduce %s due to a case-only variation: it depends on %q, but %q was already established as the case variant for that project root by depender %s" 81 return fmt.Sprintf(str, a2vs(e.goal.depender), e.goal.dep.Ident.ProjectRoot, e.current, a2vs(e.failsib[0].depender)) 82 } 83 84 var buf bytes.Buffer 85 86 str := "Could not introduce %s due to a case-only variation: it depends on %q, but %q was already established as the case variant for that project root by the following other dependers:\n" 87 fmt.Fprintf(&buf, str, a2vs(e.goal.depender), e.goal.dep.Ident.ProjectRoot, e.current) 88 89 for _, c := range e.failsib { 90 fmt.Fprintf(&buf, "\t%s\n", a2vs(c.depender)) 91 } 92 93 return buf.String() 94 } 95 96 func (e *caseMismatchFailure) traceString() string { 97 var buf bytes.Buffer 98 fmt.Fprintf(&buf, "case-only variation in dependency on %q; %q already established by:\n", e.goal.dep.Ident.ProjectRoot, e.current) 99 for _, f := range e.failsib { 100 fmt.Fprintf(&buf, "%s\n", a2vs(f.depender)) 101 } 102 103 return buf.String() 104 } 105 106 // wrongCaseFailure occurs when one or more projects - A, B, ... - depend on 107 // another project - Z - with an incorrect case variant, as indicated by the 108 // case variant used internally by Z to reference its own packages. 109 // 110 // For example, github.com/sirupsen/logrus/hooks/syslog references itself via 111 // github.com/sirupsen/logrus, establishing that as the canonical case variant. 112 type wrongCaseFailure struct { 113 // correct is the canonical representation of the ProjectRoot 114 correct ProjectRoot 115 // goal is the incorrectly-referenced target project 116 goal dependency 117 // badcase is the list of active dependencies that have specified an 118 // incorrect ProjectRoot casing for the project in question. 119 badcase []dependency 120 } 121 122 func (e *wrongCaseFailure) Error() string { 123 if len(e.badcase) == 1 { 124 str := "Could not introduce %s; imports amongst its packages establish %q as the canonical casing for root, but %s tried to import it as %q" 125 return fmt.Sprintf(str, a2vs(e.goal.depender), e.correct, a2vs(e.badcase[0].depender), e.badcase[0].dep.Ident.ProjectRoot) 126 } 127 128 var buf bytes.Buffer 129 130 str := "Could not introduce %s; imports amongst its packages establish %q as the canonical casing for root, but the following projects tried to import it as %q" 131 fmt.Fprintf(&buf, str, a2vs(e.goal.depender), e.correct, e.badcase[0].dep.Ident.ProjectRoot) 132 133 for _, c := range e.badcase { 134 fmt.Fprintf(&buf, "\t%s\n", a2vs(c.depender)) 135 } 136 137 return buf.String() 138 } 139 140 func (e *wrongCaseFailure) traceString() string { 141 var buf bytes.Buffer 142 fmt.Fprintf(&buf, "internal imports establish %q as correct casing; %q was used by:\n", e.correct, e.goal.dep.Ident.ProjectRoot) 143 for _, f := range e.badcase { 144 fmt.Fprintf(&buf, "%s\n", a2vs(f.depender)) 145 } 146 147 return buf.String() 148 } 149 150 // disjointConstraintFailure occurs when attempting to introduce an atom that 151 // itself has an acceptable version, but one of its dependency constraints is 152 // disjoint with one or more dependency constraints already active for that 153 // identifier. 154 type disjointConstraintFailure struct { 155 // goal is the dependency with the problematic constraint, forcing us to 156 // reject the atom that introduces it. 157 goal dependency 158 // failsib is the list of active dependencies that are disjoint with the 159 // goal dependency. This will be at least one, but may not be all of the 160 // active dependencies. 161 failsib []dependency 162 // nofailsib is the list of active dependencies that are NOT disjoint with 163 // the goal dependency. The total of nofailsib and failsib will always be 164 // the total number of active dependencies on target identifier. 165 nofailsib []dependency 166 // c is the current constraint on the target identifier. It is intersection 167 // of all the active dependencies' constraints. 168 c Constraint 169 } 170 171 func (e *disjointConstraintFailure) Error() string { 172 if len(e.failsib) == 1 { 173 str := "Could not introduce %s, as it has a dependency on %s with constraint %s, which has no overlap with existing constraint %s from %s" 174 return fmt.Sprintf(str, a2vs(e.goal.depender), e.goal.dep.Ident, e.goal.dep.Constraint.String(), e.failsib[0].dep.Constraint.String(), a2vs(e.failsib[0].depender)) 175 } 176 177 var buf bytes.Buffer 178 179 var sibs []dependency 180 if len(e.failsib) > 1 { 181 sibs = e.failsib 182 183 str := "Could not introduce %s, as it has a dependency on %s with constraint %s, which has no overlap with the following existing constraints:\n" 184 fmt.Fprintf(&buf, str, a2vs(e.goal.depender), e.goal.dep.Ident, e.goal.dep.Constraint.String()) 185 } else { 186 sibs = e.nofailsib 187 188 str := "Could not introduce %s, as it has a dependency on %s with constraint %s, which does not overlap with the intersection of existing constraints from other currently selected packages:\n" 189 fmt.Fprintf(&buf, str, a2vs(e.goal.depender), e.goal.dep.Ident, e.goal.dep.Constraint.String()) 190 } 191 192 for _, c := range sibs { 193 fmt.Fprintf(&buf, "\t%s from %s\n", c.dep.Constraint.String(), a2vs(c.depender)) 194 } 195 196 return buf.String() 197 } 198 199 func (e *disjointConstraintFailure) traceString() string { 200 var buf bytes.Buffer 201 fmt.Fprintf(&buf, "constraint %s on %s disjoint with other dependers:\n", e.goal.dep.Constraint.String(), e.goal.dep.Ident) 202 for _, f := range e.failsib { 203 fmt.Fprintf( 204 &buf, 205 "%s from %s (no overlap)\n", 206 f.dep.Constraint.String(), 207 a2vs(f.depender), 208 ) 209 } 210 for _, f := range e.nofailsib { 211 fmt.Fprintf( 212 &buf, 213 "%s from %s (some overlap)\n", 214 f.dep.Constraint.String(), 215 a2vs(f.depender), 216 ) 217 } 218 219 return buf.String() 220 } 221 222 // Indicates that an atom could not be introduced because one of its dep 223 // constraints does not admit the currently-selected version of the target 224 // project. 225 type constraintNotAllowedFailure struct { 226 // The dependency with the problematic constraint that could not be 227 // introduced. 228 goal dependency 229 // The (currently selected) version of the target project that was not 230 // admissible by the goal dependency. 231 v Version 232 } 233 234 func (e *constraintNotAllowedFailure) Error() string { 235 return fmt.Sprintf( 236 "Could not introduce %s, as it has a dependency on %s with constraint %s, which does not allow the currently selected version of %s", 237 a2vs(e.goal.depender), 238 e.goal.dep.Ident, 239 e.goal.dep.Constraint, 240 e.v, 241 ) 242 } 243 244 func (e *constraintNotAllowedFailure) traceString() string { 245 return fmt.Sprintf( 246 "%s depends on %s with %s, but that's already selected at %s", 247 a2vs(e.goal.depender), 248 e.goal.dep.Ident.ProjectRoot, 249 e.goal.dep.Constraint, 250 e.v, 251 ) 252 } 253 254 // versionNotAllowedFailure describes a failure where an atom is rejected 255 // because its version is not allowed by current constraints. 256 // 257 // (This is one of the more straightforward types of failures) 258 type versionNotAllowedFailure struct { 259 // goal is the atom that was rejected by current constraints. 260 goal atom 261 // failparent is the list of active dependencies that caused the atom to be 262 // rejected. Note that this only includes dependencies that actually 263 // rejected the atom, which will be at least one, but may not be all the 264 // active dependencies on the atom's identifier. 265 failparent []dependency 266 // c is the current constraint on the atom's identifier. This is the intersection 267 // of all active dependencies' constraints. 268 c Constraint 269 } 270 271 func (e *versionNotAllowedFailure) Error() string { 272 if len(e.failparent) == 1 { 273 return fmt.Sprintf( 274 "Could not introduce %s, as it is not allowed by constraint %s from project %s.", 275 a2vs(e.goal), 276 e.failparent[0].dep.Constraint.String(), 277 e.failparent[0].depender.id, 278 ) 279 } 280 281 var buf bytes.Buffer 282 283 fmt.Fprintf(&buf, "Could not introduce %s, as it is not allowed by constraints from the following projects:\n", a2vs(e.goal)) 284 285 for _, f := range e.failparent { 286 fmt.Fprintf(&buf, "\t%s from %s\n", f.dep.Constraint.String(), a2vs(f.depender)) 287 } 288 289 return buf.String() 290 } 291 292 func (e *versionNotAllowedFailure) traceString() string { 293 var buf bytes.Buffer 294 295 fmt.Fprintf(&buf, "%s not allowed by constraint %s:\n", a2vs(e.goal), e.c.String()) 296 for _, f := range e.failparent { 297 fmt.Fprintf(&buf, " %s from %s\n", f.dep.Constraint.String(), a2vs(f.depender)) 298 } 299 300 return buf.String() 301 } 302 303 type missingSourceFailure struct { 304 goal ProjectIdentifier 305 prob string 306 } 307 308 func (e *missingSourceFailure) Error() string { 309 return fmt.Sprintf(e.prob, e.goal) 310 } 311 312 type badOptsFailure string 313 314 func (e badOptsFailure) Error() string { 315 return string(e) 316 } 317 318 type sourceMismatchFailure struct { 319 // The ProjectRoot over which there is disagreement about where it should be 320 // sourced from 321 shared ProjectRoot 322 // The current value for the network source 323 current string 324 // The mismatched value for the network source 325 mismatch string 326 // The currently selected dependencies which have agreed upon/established 327 // the given network source 328 sel []dependency 329 // The atom with the constraint that has the new, incompatible network source 330 prob atom 331 } 332 333 func (e *sourceMismatchFailure) Error() string { 334 var cur []string 335 for _, c := range e.sel { 336 cur = append(cur, string(c.depender.id.ProjectRoot)) 337 } 338 339 str := "Could not introduce %s, as it depends on %s from %s, but %s is already marked as coming from %s by %s" 340 return fmt.Sprintf(str, a2vs(e.prob), e.shared, e.mismatch, e.shared, e.current, strings.Join(cur, ", ")) 341 } 342 343 func (e *sourceMismatchFailure) traceString() string { 344 var buf bytes.Buffer 345 fmt.Fprintf(&buf, "disagreement on network addr for %s:\n", e.shared) 346 347 fmt.Fprintf(&buf, " %s from %s\n", e.mismatch, e.prob.id) 348 for _, dep := range e.sel { 349 fmt.Fprintf(&buf, " %s from %s\n", e.current, dep.depender.id) 350 } 351 352 return buf.String() 353 } 354 355 type errDeppers struct { 356 err error 357 deppers []atom 358 } 359 360 // checkeeHasProblemPackagesFailure indicates that the goal atom was rejected 361 // because one or more of the packages required by its deppers had errors. 362 // 363 // "errors" includes package nonexistence, which is indicated by a nil err in 364 // the corresponding errDeppers failpkg map value. 365 // 366 // checkeeHasProblemPackagesFailure complements depHasProblemPackagesFailure; 367 // one or the other could appear to describe the same fundamental issue, 368 // depending on the order in which dependencies were visited. 369 type checkeeHasProblemPackagesFailure struct { 370 // goal is the atom that was rejected due to problematic packages. 371 goal atom 372 // failpkg is a map of package names to the error describing the problem 373 // with them, plus a list of the selected atoms that require that package. 374 failpkg map[string]errDeppers 375 } 376 377 func (e *checkeeHasProblemPackagesFailure) Error() string { 378 var buf bytes.Buffer 379 indent := "" 380 381 if len(e.failpkg) > 1 { 382 indent = "\t" 383 fmt.Fprintf( 384 &buf, "Could not introduce %s due to multiple problematic subpackages:\n", 385 a2vs(e.goal), 386 ) 387 } 388 389 for pkg, errdep := range e.failpkg { 390 var cause string 391 if errdep.err == nil { 392 cause = "is missing" 393 } else { 394 cause = fmt.Sprintf("does not contain usable Go code (%T).", errdep.err) 395 } 396 397 if len(e.failpkg) == 1 { 398 fmt.Fprintf( 399 &buf, "Could not introduce %s, as its subpackage %s %s.", 400 a2vs(e.goal), 401 pkg, 402 cause, 403 ) 404 } else { 405 fmt.Fprintf(&buf, "\tSubpackage %s %s.", pkg, cause) 406 } 407 408 if len(errdep.deppers) == 1 { 409 fmt.Fprintf( 410 &buf, " (Package is required by %s.)", 411 a2vs(errdep.deppers[0]), 412 ) 413 } else { 414 fmt.Fprintf(&buf, " Package is required by:") 415 for _, pa := range errdep.deppers { 416 fmt.Fprintf(&buf, "\n%s\t%s", indent, a2vs(pa)) 417 } 418 } 419 } 420 421 return buf.String() 422 } 423 424 func (e *checkeeHasProblemPackagesFailure) traceString() string { 425 var buf bytes.Buffer 426 427 fmt.Fprintf(&buf, "%s at %s has problem subpkg(s):\n", e.goal.id.ProjectRoot, e.goal.v) 428 for pkg, errdep := range e.failpkg { 429 if errdep.err == nil { 430 fmt.Fprintf(&buf, "\t%s is missing; ", pkg) 431 } else { 432 fmt.Fprintf(&buf, "\t%s has err (%T); ", pkg, errdep.err) 433 } 434 435 if len(errdep.deppers) == 1 { 436 fmt.Fprintf(&buf, "required by %s.", a2vs(errdep.deppers[0])) 437 } else { 438 fmt.Fprintf(&buf, " required by:") 439 for _, pa := range errdep.deppers { 440 fmt.Fprintf(&buf, "\n\t\t%s at %s", pa.id, pa.v) 441 } 442 } 443 } 444 445 return buf.String() 446 } 447 448 // depHasProblemPackagesFailure indicates that the goal dependency was rejected 449 // because there were problems with one or more of the packages the dependency 450 // requires in the atom currently selected for that dependency. (This failure 451 // can only occur if the target dependency is already selected.) 452 // 453 // "errors" includes package nonexistence, which is indicated by a nil err as 454 // the corresponding prob map value. 455 // 456 // depHasProblemPackagesFailure complements checkeeHasProblemPackagesFailure; 457 // one or the other could appear to describe the same fundamental issue, 458 // depending on the order in which dependencies were visited. 459 type depHasProblemPackagesFailure struct { 460 // goal is the dependency that was rejected due to the atom currently 461 // selected for the dependency's target id having errors (including, and 462 // probably most commonly, 463 // nonexistence) in one or more packages named by the dependency. 464 goal dependency 465 // v is the version of the currently selected atom targeted by the goal 466 // dependency. 467 v Version 468 // prob is a map of problem packages to their specific error. It does not 469 // include missing packages. 470 prob map[string]error 471 } 472 473 func (e *depHasProblemPackagesFailure) Error() string { 474 fcause := func(pkg string) string { 475 if err := e.prob[pkg]; err != nil { 476 return fmt.Sprintf("does not contain usable Go code (%T).", err) 477 } 478 return "is missing." 479 } 480 481 if len(e.prob) == 1 { 482 var pkg string 483 for pkg = range e.prob { 484 } 485 486 return fmt.Sprintf( 487 "Could not introduce %s, as it requires package %s from %s, but in version %s that package %s", 488 a2vs(e.goal.depender), 489 pkg, 490 e.goal.dep.Ident, 491 e.v, 492 fcause(pkg), 493 ) 494 } 495 496 var buf bytes.Buffer 497 fmt.Fprintf( 498 &buf, "Could not introduce %s, as it requires problematic packages from %s (current version %s):", 499 a2vs(e.goal.depender), 500 e.goal.dep.Ident, 501 e.v, 502 ) 503 504 pkgs := make([]string, len(e.prob)) 505 k := 0 506 for pkg := range e.prob { 507 pkgs[k] = pkg 508 k++ 509 } 510 sort.Strings(pkgs) 511 for _, pkg := range pkgs { 512 fmt.Fprintf(&buf, "\t%s %s", pkg, fcause(pkg)) 513 } 514 515 return buf.String() 516 } 517 518 func (e *depHasProblemPackagesFailure) traceString() string { 519 var buf bytes.Buffer 520 fcause := func(pkg string) string { 521 if err := e.prob[pkg]; err != nil { 522 return fmt.Sprintf("has parsing err (%T).", err) 523 } 524 return "is missing" 525 } 526 527 fmt.Fprintf( 528 &buf, "%s depping on %s at %s has problem subpkg(s):", 529 a2vs(e.goal.depender), 530 e.goal.dep.Ident, 531 e.v, 532 ) 533 534 pkgs := make([]string, len(e.prob)) 535 k := 0 536 for pkg := range e.prob { 537 pkgs[k] = pkg 538 k++ 539 } 540 sort.Strings(pkgs) 541 for _, pkg := range pkgs { 542 fmt.Fprintf(&buf, "\t%s %s", pkg, fcause(pkg)) 543 } 544 545 return buf.String() 546 } 547 548 // nonexistentRevisionFailure indicates that a revision constraint was specified 549 // for a given project, but that that revision does not exist in the source 550 // repository. 551 type nonexistentRevisionFailure struct { 552 goal dependency 553 r Revision 554 } 555 556 func (e *nonexistentRevisionFailure) Error() string { 557 return fmt.Sprintf( 558 "Could not introduce %s, as it requires %s at revision %s, but that revision does not exist", 559 a2vs(e.goal.depender), 560 e.goal.dep.Ident, 561 e.r, 562 ) 563 } 564 565 func (e *nonexistentRevisionFailure) traceString() string { 566 return fmt.Sprintf( 567 "%s wants missing rev %s of %s", 568 a2vs(e.goal.depender), 569 e.r, 570 e.goal.dep.Ident, 571 ) 572 }