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  }