github.com/grantbow/fit@v0.7.1-0.20220916164603-1f7c88ac81e6/fitapp/utils.go (about) 1 package fitapp 2 3 import ( 4 _ "flag" // used in commented code 5 "fmt" 6 bugs "github.com/grantbow/fit/issues" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strings" 11 "testing" 12 ) 13 14 var dops = bugs.Directory(os.PathSeparator) 15 var sops = string(os.PathSeparator) 16 17 type argumentList []string 18 19 // HasArgument checks pkg global argumentList for an argument parameter. Returns true or false. 20 func (args argumentList) HasArgument(arg string) bool { 21 for _, argCandidate := range args { 22 if arg == argCandidate { 23 return true 24 } 25 } 26 return false 27 } 28 29 // GetArgument gets an argument from the pkg global argumentList. Returns a string. 30 func (args argumentList) GetArgument(argname, defaultVal string) string { 31 for idx, argCandidate := range args { 32 if argname == argCandidate { 33 // If it's the last argument, then return string 34 // "true" because we can't return idx+1, but it 35 // shouldn't be the default value when the argument 36 // isn't provided either.. 37 if idx >= len(args)-1 { 38 return "true" 39 } 40 return args[idx+1] 41 } 42 } 43 return defaultVal 44 } 45 46 // GetAndRemoveArguments returns an argumentList and corresponding values as an argumentList and a slice of strings. 47 func (args argumentList) GetAndRemoveArguments(argnames []string) (argumentList, []string) { 48 var nextArgumentType int = -1 49 matches := make([]string, len(argnames)) 50 var retArgs []string 51 for idx, argCandidate := range args { 52 // The last token was in argnames, so this one 53 // is the value. Set it in matches and reset 54 // nextArgumentType and continue to the next 55 // possible token 56 if nextArgumentType != -1 { 57 matches[nextArgumentType] = argCandidate 58 nextArgumentType = -1 59 continue 60 } 61 62 // Check if this is a argname we're looking for 63 for argidx, argname := range argnames { 64 if argname == argCandidate { 65 if idx >= len(args)-1 { 66 matches[argidx] = "true" 67 } 68 nextArgumentType = argidx 69 break 70 } 71 } 72 73 // It wasn't an argname, so add it to the return 74 if nextArgumentType == -1 { 75 retArgs = append(retArgs, argCandidate) 76 } 77 } 78 return retArgs, matches 79 } 80 81 // check will panic with an error 82 func check(e error) { 83 if e != nil { 84 // fmt.Fprintf(os.Stderr, "err: %s", err.Error()) 85 // return NoConfigError 86 panic(e) 87 } 88 } 89 90 // captureOutput accepts a function for testing and returns stdout string and stderr string. 91 func captureOutput(f func(), t *testing.T) (string, string) { 92 // Capture STDOUT with a pipe 93 stdout := os.Stdout 94 stderr := os.Stderr 95 so, op, _ := os.Pipe() //outpipe 96 oe, ep, _ := os.Pipe() //errpipe 97 defer func(stdout, stderr *os.File) { 98 os.Stdout = stdout 99 os.Stderr = stderr 100 }(stdout, stderr) 101 102 os.Stdout = op 103 os.Stderr = ep 104 105 f() 106 107 os.Stdout = stdout 108 os.Stderr = stderr 109 110 op.Close() 111 ep.Close() 112 113 errOutput, err := ioutil.ReadAll(oe) 114 if err != nil { 115 t.Error("Could not get output from stderr") 116 } 117 stdOutput, err := ioutil.ReadAll(so) 118 if err != nil { 119 t.Error("Could not get output from stdout") 120 } 121 return string(stdOutput), string(errOutput) 122 } 123 124 // fieldHandler is used for Priority, Milestone and Status, not Identifier 125 func fieldHandler(command string, args argumentList, 126 setCallback func(bugs.Issue, string, bugs.Config) error, retrieveCallback func(bugs.Issue) string, config bugs.Config) { 127 if len(args) < 1 { 128 fmt.Printf("Usage: %s %s IssueID [set %s]\n", os.Args[0], command, command) 129 return 130 } 131 132 b, err := bugs.LoadIssueByHeuristic(args[0], config) 133 if err != nil { 134 fmt.Printf("Invalid IssueID: %s\n", err.Error()) 135 return 136 } 137 if len(args) > 1 { 138 newValue := strings.Join(args[1:], " ") 139 err := setCallback(*b, newValue, config) 140 if err != nil { 141 fmt.Printf("Error setting %s: %s", command, err.Error()) 142 } 143 } else { 144 val := retrieveCallback(*b) 145 if val == "" { 146 fmt.Printf("%s not defined\n", command) 147 } else { 148 fmt.Printf("%s\n", val) 149 } 150 } 151 } 152 153 // dirDump accepts a string directory and returns a string. 154 func dirDump(dir string) string { 155 a := []string{} 156 err := filepath.Walk(dir, 157 func(path string, info os.FileInfo, err error) error { 158 if err != nil { 159 return err 160 } 161 a = append(a, fmt.Sprintf("%v", path)) 162 return nil 163 }) 164 if err != nil { 165 fmt.Printf("dirDump error %s", err.Error()) 166 } 167 //for _, file := range files { 168 // a = append(a, fmt.Sprintf("%v", file)) 169 //} 170 return strings.Join(a, ",\n") 171 } 172 173 // dirDumpFI accepts an array of os.FileInfo and returns a string 174 func dirDumpFI(files []os.FileInfo) string { 175 a := []string{} 176 for _, file := range files { 177 a = append(a, fmt.Sprintf("%v", file)) 178 } 179 return strings.Join(a, ",\n") 180 } 181 182 // SkipRootCheck is a helper function to avoid unnecessary filesystem checking. 183 func SkipRootCheck(args *[]string) bool { 184 ret := false 185 switch len(*args) { 186 case 0, 1: 187 ret = true 188 case 2: 189 if (*args)[1] == "help" || 190 (*args)[1] == "--help" || 191 (*args)[1] == "-h" || 192 (*args)[1] == "status" || 193 (*args)[1] == "version" || 194 (*args)[1] == "about" || 195 (*args)[1] == "--version" || 196 (*args)[1] == "-v" || 197 (*args)[1] == "environment" || 198 (*args)[1] == "config" || 199 (*args)[1] == "settings" || 200 (*args)[1] == "env" { 201 ret = true 202 } 203 case 3: 204 if (*args)[2] == "--help" || 205 (*args)[1] == "help" { 206 ret = true 207 } 208 } 209 return ret 210 } 211 212 // also in issues/utils.go 213 func removeFi(slice []os.FileInfo, i int) []os.FileInfo { 214 //flag.Parse() 215 //Debug("debug len " + string(len(slice)) + " i " + string(i) + " slice[0].Name() " + string(slice[0].Name()) + "\n") 216 //fmt.Printf("%+v\n", flag.Args()) // didn't seem to help, needs more work to make it active 217 // 218 //fmt.Printf("debug ok 01 \n") 219 //fmt.Printf("debug len " + string(len(slice)) + " i " + string(i) + " slice[0].Name() " + string(slice[0].Name()) + "\n") 220 //fmt.Printf("debug removeFi args len " + string(len(slice)) + " i " + string(i) + "\n") 221 if (len(slice) == 1) && (i == 0) { 222 return []os.FileInfo{} 223 } else if i < len(slice)-2 { 224 copy(slice[i:], slice[i+1:]) 225 } 226 return slice[:len(slice)-1] 227 } 228 229 // also in issues/utils.go 230 func readIssues(dirname string) []os.FileInfo { 231 //var issueList []os.FileInfo 232 fis, _ := ioutil.ReadDir(string(dirname)) 233 issueList := fis 234 for idx, fi := range issueList { 235 //Debug("debug fi " + string(fi.Name()) + "idx " + string(idx) + "\n") 236 //fmt.Printf("debug readIssues loop fi " + string(fi.Name()) + "idx " + string(idx) + "\n") 237 if fi.IsDir() != true { 238 //fmt.Printf("debug before removeFi name " + fi.Name() + " idx " + string(idx) + "\n") 239 issueList = removeFi(issueList, idx) 240 } 241 } 242 return issueList 243 } 244 245 //byDir allows sort.Sort(byDir(issues)) 246 // type and three functions are needed - also see Issue.go for type byIssue 247 // rather than a custom Len function for os.FileInfo, Len is calculated in Less 248 type byDir []os.FileInfo 249 250 func (t byDir) Len() int { 251 return len(t) 252 } 253 func (t byDir) Swap(i, j int) { 254 t[i], t[j] = t[j], t[i] 255 } 256 func (t byDir) Less(i, j int) bool { 257 return (t[i]).ModTime().Unix() < (t[j]).ModTime().Unix() 258 }