github.com/sdboyer/gps@v0.16.3/trace.go (about) 1 package gps 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/sdboyer/gps/pkgtree" 9 ) 10 11 const ( 12 successChar = "✓" 13 successCharSp = successChar + " " 14 failChar = "✗" 15 failCharSp = failChar + " " 16 backChar = "←" 17 innerIndent = " " 18 ) 19 20 func (s *solver) traceCheckPkgs(bmi bimodalIdentifier) { 21 if s.tl == nil { 22 return 23 } 24 25 prefix := getprei(len(s.vqs) + 1) 26 s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("? revisit %s to add %v pkgs", bmi.id.errString(), len(bmi.pl)), prefix, prefix)) 27 } 28 29 func (s *solver) traceCheckQueue(q *versionQueue, bmi bimodalIdentifier, cont bool, offset int) { 30 if s.tl == nil { 31 return 32 } 33 34 prefix := getprei(len(s.vqs) + offset) 35 vlen := strconv.Itoa(len(q.pi)) 36 if !q.allLoaded { 37 vlen = "at least " + vlen 38 } 39 40 // TODO(sdboyer) how...to list the packages in the limited space we have? 41 var verb string 42 indent := "" 43 if cont { 44 // Continue is an "inner" message.. indenting 45 verb = "continue" 46 vlen = vlen + " more" 47 indent = innerIndent 48 } else { 49 verb = "attempt" 50 } 51 52 s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("%s? %s %s with %v pkgs; %s versions to try", indent, verb, bmi.id.errString(), len(bmi.pl), vlen), prefix, prefix)) 53 } 54 55 // traceStartBacktrack is called with the bmi that first failed, thus initiating 56 // backtracking 57 func (s *solver) traceStartBacktrack(bmi bimodalIdentifier, err error, pkgonly bool) { 58 if s.tl == nil { 59 return 60 } 61 62 var msg string 63 if pkgonly { 64 msg = fmt.Sprintf("%s%s could not add %v pkgs to %s; begin backtrack", innerIndent, backChar, len(bmi.pl), bmi.id.errString()) 65 } else { 66 msg = fmt.Sprintf("%s%s no more versions of %s to try; begin backtrack", innerIndent, backChar, bmi.id.errString()) 67 } 68 69 prefix := getprei(len(s.sel.projects)) 70 s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix)) 71 } 72 73 // traceBacktrack is called when a package or project is poppped off during 74 // backtracking 75 func (s *solver) traceBacktrack(bmi bimodalIdentifier, pkgonly bool) { 76 if s.tl == nil { 77 return 78 } 79 80 var msg string 81 if pkgonly { 82 msg = fmt.Sprintf("%s backtrack: popped %v pkgs from %s", backChar, len(bmi.pl), bmi.id.errString()) 83 } else { 84 msg = fmt.Sprintf("%s backtrack: no more versions of %s to try", backChar, bmi.id.errString()) 85 } 86 87 prefix := getprei(len(s.sel.projects)) 88 s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix)) 89 } 90 91 // Called just once after solving has finished, whether success or not 92 func (s *solver) traceFinish(sol solution, err error) { 93 if s.tl == nil { 94 return 95 } 96 97 if err == nil { 98 var pkgcount int 99 for _, lp := range sol.Projects() { 100 pkgcount += len(lp.pkgs) 101 } 102 s.tl.Printf("%s%s found solution with %v packages from %v projects", innerIndent, successChar, pkgcount, len(sol.Projects())) 103 } else { 104 s.tl.Printf("%s%s solving failed", innerIndent, failChar) 105 } 106 } 107 108 // traceSelectRoot is called just once, when the root project is selected 109 func (s *solver) traceSelectRoot(ptree pkgtree.PackageTree, cdeps []completeDep) { 110 if s.tl == nil { 111 return 112 } 113 114 // This duplicates work a bit, but we're in trace mode and it's only once, 115 // so who cares 116 rm, _ := ptree.ToReachMap(true, true, false, s.rd.ig) 117 118 s.tl.Printf("Root project is %q", s.rd.rpt.ImportRoot) 119 120 var expkgs int 121 for _, cdep := range cdeps { 122 expkgs += len(cdep.pl) 123 } 124 125 // TODO(sdboyer) include info on ignored pkgs/imports, etc. 126 s.tl.Printf(" %v transitively valid internal packages", len(rm)) 127 s.tl.Printf(" %v external packages imported from %v projects", expkgs, len(cdeps)) 128 s.tl.Printf("(0) " + successCharSp + "select (root)") 129 } 130 131 // traceSelect is called when an atom is successfully selected 132 func (s *solver) traceSelect(awp atomWithPackages, pkgonly bool) { 133 if s.tl == nil { 134 return 135 } 136 137 var msg string 138 if pkgonly { 139 msg = fmt.Sprintf("%s%s include %v more pkgs from %s", innerIndent, successChar, len(awp.pl), a2vs(awp.a)) 140 } else { 141 msg = fmt.Sprintf("%s select %s w/%v pkgs", successChar, a2vs(awp.a), len(awp.pl)) 142 } 143 144 prefix := getprei(len(s.sel.projects) - 1) 145 s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix)) 146 } 147 148 func (s *solver) traceInfo(args ...interface{}) { 149 if s.tl == nil { 150 return 151 } 152 153 if len(args) == 0 { 154 panic("must pass at least one param to traceInfo") 155 } 156 157 preflen := len(s.sel.projects) 158 var msg string 159 switch data := args[0].(type) { 160 case string: 161 msg = tracePrefix(innerIndent+fmt.Sprintf(data, args[1:]...), " ", " ") 162 case traceError: 163 preflen++ 164 // We got a special traceError, use its custom method 165 msg = tracePrefix(innerIndent+data.traceString(), " ", failCharSp) 166 case error: 167 // Regular error; still use the x leader but default Error() string 168 msg = tracePrefix(innerIndent+data.Error(), " ", failCharSp) 169 default: 170 // panic here because this can *only* mean a stupid internal bug 171 panic(fmt.Sprintf("canary - unknown type passed as first param to traceInfo %T", data)) 172 } 173 174 prefix := getprei(preflen) 175 s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix)) 176 } 177 178 func getprei(i int) string { 179 var s string 180 if i < 10 { 181 s = fmt.Sprintf("(%d) ", i) 182 } else if i < 100 { 183 s = fmt.Sprintf("(%d) ", i) 184 } else { 185 s = fmt.Sprintf("(%d) ", i) 186 } 187 return s 188 } 189 190 func tracePrefix(msg, sep, fsep string) string { 191 parts := strings.Split(strings.TrimSuffix(msg, "\n"), "\n") 192 for k, str := range parts { 193 if k == 0 { 194 parts[k] = fsep + str 195 } else { 196 parts[k] = sep + str 197 } 198 } 199 200 return strings.Join(parts, "\n") 201 }