github.com/whyrusleeping/gx@v0.14.3/ui.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "encoding/json" 6 "fmt" 7 "os" 8 "strconv" 9 "strings" 10 "text/tabwriter" 11 12 gx "github.com/whyrusleeping/gx/gxutil" 13 . "github.com/whyrusleeping/stump" 14 ) 15 16 func promptUser(query string) string { 17 fmt.Printf("%s ", query) 18 scan := bufio.NewScanner(os.Stdin) 19 scan.Scan() 20 return scan.Text() 21 } 22 23 func yesNoPrompt(prompt string, def bool) bool { 24 opts := "[y/N]" 25 if def { 26 opts = "[Y/n]" 27 } 28 29 fmt.Printf("%s %s ", prompt, opts) 30 scan := bufio.NewScanner(os.Stdin) 31 for scan.Scan() { 32 val := strings.ToLower(scan.Text()) 33 switch val { 34 case "": 35 return def 36 case "y": 37 return true 38 case "n": 39 return false 40 default: 41 fmt.Println("please type 'y' or 'n'") 42 } 43 } 44 45 panic("unexpected termination of stdin") 46 } 47 48 func jsonPrint(i interface{}) { 49 out, _ := json.MarshalIndent(i, "", " ") 50 outs, err := strconv.Unquote(string(out)) // for printing out raw strings 51 if err != nil { 52 outs = string(out) 53 } 54 Log(outs) 55 } 56 57 type depTreeNode struct { 58 this *gx.Dependency 59 children []*depTreeNode 60 } 61 62 func genDepsTree(pm *gx.PM, pkg *gx.Package) (*depTreeNode, error) { 63 64 complete := make(map[string]*depTreeNode) 65 66 var rec func(pkg *gx.Package) (*depTreeNode, error) 67 rec = func(pkg *gx.Package) (*depTreeNode, error) { 68 cur := new(depTreeNode) 69 cur.this = new(gx.Dependency) 70 cur.this.Name = pkg.Name 71 72 err := pkg.ForEachDep(func(dep *gx.Dependency, dpkg *gx.Package) error { 73 sub := complete[dep.Hash] 74 if sub == nil { 75 var err error 76 sub, err = rec(dpkg) 77 if err != nil { 78 return err 79 } 80 complete[dep.Hash] = sub 81 } 82 83 sub.this = dep 84 cur.children = append(cur.children, sub) 85 86 return nil 87 }) 88 89 return cur, err 90 } 91 92 return rec(pkg) 93 } 94 95 func (dtn *depTreeNode) matches(filter string) bool { 96 if filter == "" { 97 return true 98 } 99 100 if dtn.this.Hash == filter || dtn.this.Name == filter { 101 return true 102 } 103 104 for _, c := range dtn.children { 105 if c.matches(filter) { 106 return true 107 } 108 } 109 return false 110 } 111 112 const ( 113 tBar = "│" 114 tEnd = "└" 115 tDash = "─" 116 tTree = "├" 117 ) 118 119 func (dtn *depTreeNode) printFiltered(filter string, quiet, collapse bool) { 120 tabw := tabwriter.NewWriter(os.Stdout, 12, 4, 1, ' ', 0) 121 122 printed := make(map[string]bool) 123 var rec func(*depTreeNode, string) 124 rec = func(p *depTreeNode, prefix string) { 125 if len(p.children) == 0 { 126 return 127 } 128 129 var toprint []*depTreeNode 130 for _, n := range p.children { 131 if n.matches(filter) { 132 toprint = append(toprint, n) 133 } 134 } 135 if printed[p.this.Hash] && collapse { 136 toprint = []*depTreeNode{ 137 { 138 this: &gx.Dependency{ 139 Name: "...", 140 }, 141 }, 142 } 143 } 144 for i, n := range toprint { 145 last := i == len(toprint)-1 146 dep := n.this 147 label := dep.Hash 148 if !quiet { 149 pref := tTree 150 if last { 151 pref = tEnd 152 } 153 154 label = fmt.Sprintf("%s%s \033[1m%s\033[0m\t%s\t%s", pref, tDash, dep.Name, dep.Hash, dep.Version) 155 } 156 157 fmt.Fprintln(tabw, prefix+label) 158 159 nextPref := prefix + tBar + " " 160 if last { 161 nextPref = prefix + " " 162 } 163 rec(n, nextPref) 164 } 165 166 printed[p.this.Hash] = true 167 } 168 169 rec(dtn, "") 170 171 tabw.Flush() 172 }