package repostatus import ( "errors" "fmt" "io/ioutil" "os" "os/exec" "os/user" "path/filepath" "regexp" "strconv" "strings" "time" "go.wit.com/lib/gui/shell" "go.wit.com/log" ) func run(path string, thing string, cmdline string) string { parts := strings.Split(cmdline, " ") // Create the command cmd := exec.Command(thing, parts...) // Set the working directory cmd.Dir = path // Execute the command output, err := cmd.CombinedOutput() tmp := string(output) tmp = strings.TrimSpace(tmp) if err != nil { log.Log(WARN, "run()", path, thing, cmdline, "=", tmp) log.Error(err, "cmd error'd out", parts) return "" } // Print the output log.Log(INFO, "run()", path, thing, cmdline, "=", tmp) return tmp } // goes in one directory so it gets remote branch names func listFiles(directory string) []string { var files []string fileInfo, err := os.ReadDir(directory) if err != nil { log.Error(err) return nil } for _, file := range fileInfo { if file.IsDir() { dirname := file.Name() newdir, _ := os.ReadDir(directory + "/" + dirname) for _, file := range newdir { if !file.IsDir() { files = append(files, dirname+"/"+file.Name()) } } } else { files = append(files, file.Name()) } } return files } /* // string handling examples that might be helpful for normalizeInt() isAlpha := regexp.MustCompile(`^[A-Za-z]+$`).MatchString for _, username := range []string{"userone", "user2", "user-three"} { if !isAlpha(username) { log.Log(GUI, "%q is not valid\n", username) } } const alpha = "abcdefghijklmnopqrstuvwxyz" func alphaOnly(s string) bool { for _, char := range s { if !strings.Contains(alpha, strings.ToLower(string(char))) { return false } } return true } */ func normalizeVersion(s string) string { // reg, err := regexp.Compile("[^a-zA-Z0-9]+") parts := strings.Split(s, "-") if len(parts) == 0 { return "" } reg, err := regexp.Compile("[^0-9.]+") if err != nil { log.Log(WARN, "normalizeVersion() regexp.Compile() ERROR =", err) return parts[0] } clean := reg.ReplaceAllString(parts[0], "") log.Log(INFO, "normalizeVersion() s =", clean) return clean } func splitVersion(version string) (a, b, c string) { tmp := normalizeVersion(version) parts := strings.Split(tmp, ".") switch len(parts) { case 1: return parts[0], "", "" case 2: return parts[0], parts[1], "" default: return parts[0], parts[1], parts[2] } } func (rs *RepoStatus) RunCmdEcho(parts []string) (error, string) { log.Info("RunCmdEcho()", parts) return rs.RunCmd(parts) } func (rs *RepoStatus) RunCmd(parts []string) (error, string) { path := rs.realPath.String() err, _, output := shell.RunCmd(path, parts) if err != nil { log.Log(WARN, "cmd:", parts) log.Log(WARN, "ouptput:", output) log.Log(WARN, "failed with error:", err) } return err, output } // temp hack. fix this func runCmd(path string, parts []string) (error, bool, string) { return shell.RunCmd(path, parts) } func RunCmd(workingpath string, parts []string) (error, bool, string) { if len(parts) == 0 { log.Warn("command line was empty") return errors.New("empty"), false, "" } if parts[0] == "" { log.Warn("command line was empty") return errors.New("empty"), false, "" } thing := parts[0] parts = parts[1:] log.Log(INFO, "working path =", workingpath, "thing =", thing, "cmdline =", parts) // Create the command cmd := exec.Command(thing, parts...) // Set the working directory cmd.Dir = workingpath // Execute the command output, err := cmd.CombinedOutput() if err != nil { if thing == "git" { log.Log(INFO, "git ERROR. maybe okay", workingpath, "thing =", thing, "cmdline =", parts) log.Log(INFO, "git ERROR. maybe okay err =", err) if err.Error() == "exit status 1" { log.Log(INFO, "git ERROR. normal exit status 1") if parts[0] == "diff-index" { log.Log(INFO, "git normal diff-index when repo dirty") return nil, false, "git diff-index exit status 1" } } } log.Log(WARN, "ERROR working path =", workingpath, "thing =", thing, "cmdline =", parts) log.Log(WARN, "ERROR working path =", workingpath, "thing =", thing, "cmdline =", parts) log.Log(WARN, "ERROR working path =", workingpath, "thing =", thing, "cmdline =", parts) log.Error(err) log.Warn("output was", string(output)) log.Warn("cmd exited with error", err) // panic("fucknuts") return err, false, string(output) /* todo: see if there is a way to get the exit value // The command failed (non-zero exit status) if exitErr, ok := err.(*exec.ExitError); ok { // Assert that it is an exec.ExitError and get the exit code if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { log.Warn("Exit Status: %d\n", status.ExitStatus()) } } else { log.Warn("cmd.Run() failed with %s\n", err) } */ } tmp := string(output) tmp = strings.TrimSpace(tmp) // Print the output return nil, true, tmp } // Set the path to the package func getfiles(pathToPackage string) { // List files in the directory err := filepath.Walk(pathToPackage, nil) // compiles but crashes if err == nil { log.Log(INFO, "directory ok", pathToPackage) } else { log.Warn("directory wrong", pathToPackage) } } func IsDirectory(path string) bool { info, err := os.Stat(path) if err != nil { return false } return info.IsDir() } func (rs *RepoStatus) Exists(filename string) bool { usr, err := user.Current() if err != nil { log.Error(err, "Exists() error: could not determine what your username is") return false } testf := filepath.Join(usr.HomeDir, "go/src/", rs.String(), filename) if Exists(testf) { return true } return false } func (rs *RepoStatus) mtime(filename string) (time.Time, error) { pathf := filepath.Join(rs.Path(), filename) statf, err := os.Stat(pathf) if err == nil { return statf.ModTime(), nil } log.Log(REPOWARN, "mtime() error", pathf, err) return time.Now(), err } // returns true if the file exists func Exists(file string) bool { _, err := os.Stat(file) if err != nil { return false } return true } func readFileToString(filename string) (string, error) { data, err := ioutil.ReadFile(filename) if err != nil { return "", err } return strings.TrimSpace(string(data)), nil } // converts a git for-each-ref date. "Wed Feb 7 10:13:38 2024 -0600" func getGitDateStamp(gitdefault string) (time.Time, string, string) { // now := time.Now().Format("Wed Feb 7 10:13:38 2024 -0600") const gitLayout = "Mon Jan 2 15:04:05 2006 -0700" tagTime, err := time.Parse(gitLayout, gitdefault) if err != nil { log.Warn("GOT THIS IN PARSE AAA." + gitdefault + ".AAA") log.Warn(err) return time.Now(), "Feb 1 12:34:56 1978 -0600", "" } return tagTime, gitdefault, getDurationStamp(tagTime) } func getRawDateStamp(raw string) (time.Time, string, string) { parts := strings.Split(raw, " ") if len(parts) == 0 { // raw was blank here // return "Jan 4 1977", "40y" // eh, why not. it'll be easy to grep for this return time.Now(), "Jan 4 1977", "40y" // eh, why not. it'll be easy to grep for this } i, err := strconv.ParseInt(parts[0], 10, 64) // base 10 string, return int64 if err != nil { log.Warn("Error converting timestamp:", raw) log.Warn("Error converting timestamp err =", err) return time.Now(), "", "" } // Parse the Unix timestamp into a time.Time object gitTagDate := time.Unix(i, 0) return gitTagDate, gitTagDate.UTC().Format("2006/01/02 15:04:05 UTC"), getDurationStamp(gitTagDate) } func getDurationStamp(t time.Time) string { // Get the current time currentTime := time.Now() // Calculate the duration between t current time duration := currentTime.Sub(t) return formatDuration(duration) } func formatDuration(d time.Duration) string { seconds := int(d.Seconds()) % 60 minutes := int(d.Minutes()) % 60 hours := int(d.Hours()) % 24 days := int(d.Hours()) / 24 years := int(d.Hours()) / (24 * 365) result := "" if years > 0 { result += fmt.Sprintf("%dy ", years) return result } if days > 0 { result += fmt.Sprintf("%dd ", days) return result } if hours > 0 { result += fmt.Sprintf("%dh ", hours) return result } if minutes > 0 { result += fmt.Sprintf("%dm ", minutes) return result } if seconds > 0 { result += fmt.Sprintf("%ds", seconds) } return result } func (rs *RepoStatus) XtermNohup(cmdline string) { shell.XtermCmd(rs.Path(), []string{cmdline}) } func (rs *RepoStatus) Xterm(cmdline string) { shell.XtermCmd(rs.Path(), []string{cmdline}) } func (rs *RepoStatus) XtermWait(cmdline string) { shell.XtermCmdWait(rs.Path(), []string{cmdline}) } /* func (rs *RepoStatus) XtermNohup(args []string) { var argsX = []string{"xterm", "-geometry", "120x40"} argsX = append(argsX, "-e", "bash", "-c") argsX = append(argsX, args...) log.Info("xterm cmd=", argsX) // set less to not exit on small diff's os.Setenv("LESS", "-+F -+X -R") cmd := exec.Command("nohup", argsX...) path := rs.realPath.String() cmd.Dir = path log.Info("path =", path) log.Info("cmd =", strings.Join(args, " ")) if err := cmd.Run(); err != nil { log.Info("xterm.Run() failed") log.Info("path =", path) log.Info("cmd =", argsX) } else { log.Info("xterm.Run() worked") log.Info("path =", path) log.Info("cmd =", argsX) } } */ /* func (rs *RepoStatus) Xterm(args []string) { var argsX = []string{"-geometry", "120x40"} argsX = append(argsX, "-e", "bash", "-c") argsX = append(argsX, args...) log.Info("xterm cmd=", argsX) // set less to not exit on small diff's os.Setenv("LESS", "-+F -+X -R") cmd := exec.Command("xterm", argsX...) path := rs.realPath.String() cmd.Dir = path if err := cmd.Run(); err != nil { log.Info("xterm.Run() failed") log.Info("path =", path) log.Info("cmd = xterm", argsX) } else { log.Info("xterm.Run() worked") log.Info("path =", path) log.Info("cmd = xterm", argsX) } } */ /* func (rs *RepoStatus) XtermHold(args []string) { var argsX = []string{"-hold", "-geometry", "120x40"} tmp := strings.Join(args, " ") + ";bash" argsX = append(argsX, "-e", "bash", "-c", tmp) argsX = append(argsX, args...) log.Info("xterm cmd=", argsX) // set less to not exit on small diff's os.Setenv("LESS", "-+F -+X -R") cmd := exec.Command("xterm", argsX...) path := rs.realPath.String() cmd.Dir = path if err := cmd.Run(); err != nil { log.Info("xterm.Run() failed") log.Info("path =", path) log.Info("cmd = xterm", argsX) } else { log.Info("xterm.Run() worked") log.Info("path =", path) log.Info("cmd = xterm", argsX) } } */ func (rs *RepoStatus) XtermBash(args []string) { var argsX = []string{"-geometry", "120x40"} tmp := strings.Join(args, " ") + ";bash" argsX = append(argsX, "-e", "bash", "-c", tmp) argsX = append(argsX, args...) log.Info("xterm cmd=", argsX) // set less to not exit on small diff's os.Setenv("LESS", "-+F -+X -R") cmd := exec.Command("xterm", argsX...) path := rs.realPath.String() cmd.Dir = path if err := cmd.Run(); err != nil { log.Log(WARN, "xterm.Run() failed") log.Log(WARN, "path =", path) log.Log(WARN, "cmd = xterm", argsX) } else { log.Log(WARN, "xterm.Run() worked") log.Log(WARN, "path =", path) log.Log(WARN, "cmd = xterm", argsX) } } func (rs *RepoStatus) DoAll(all [][]string) bool { for _, cmd := range all { log.Log(WARN, "doAll() RUNNING: cmd =", cmd) err, out := rs.RunCmd(cmd) if err != nil { log.Log(WARN, "doAll() err =", err) log.Log(WARN, "doAll() out =", out) return false } } return true } func ScanGitDirectories(srcDir string) []string { var all []string err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { if err != nil { log.Log(REPOWARN, "Error accessing path:", path, err) return nil } // Check if the path is a directory and has a .git subdirectory if info.IsDir() && IsGitDir(path) { all = append(all, path) } return nil }) if err != nil { log.Log(REPOWARN, "Error walking the path:", srcDir, err) } return all }