mirror of
https://github.com/gabrie30/ghorg.git
synced 2025-08-07 06:47:14 +02:00
221 lines
6.5 KiB
Go
221 lines
6.5 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/gabrie30/ghorg/colorlog"
|
|
"github.com/gabrie30/ghorg/configs"
|
|
"github.com/spf13/cobra"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
var reCloneCmd = &cobra.Command{
|
|
Use: "reclone",
|
|
Short: "Reruns one, multiple, or all preconfigured clones from configuration set in $HOME/.config/ghorg/reclone.yaml",
|
|
Long: `Allows you to set preconfigured clone commands for handling multiple users/orgs at once. See https://github.com/gabrie30/ghorg#reclone-command for setup and additional information.`,
|
|
Run: reCloneFunc,
|
|
}
|
|
|
|
type ReClone struct {
|
|
Cmd string `yaml:"cmd"`
|
|
Description string `yaml:"description"`
|
|
PostExecScript string `yaml:"post_exec_script"` // optional
|
|
}
|
|
|
|
func isQuietReClone() bool {
|
|
return os.Getenv("GHORG_RECLONE_QUIET") == "true"
|
|
}
|
|
|
|
func reCloneFunc(cmd *cobra.Command, argz []string) {
|
|
|
|
if cmd.Flags().Changed("reclone-path") {
|
|
path := cmd.Flag("reclone-path").Value.String()
|
|
os.Setenv("GHORG_RECLONE_PATH", path)
|
|
}
|
|
|
|
if cmd.Flags().Changed("quiet") {
|
|
os.Setenv("GHORG_RECLONE_QUIET", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("env-config-only") {
|
|
os.Setenv("GHORG_RECLONE_ENV_CONFIG_ONLY", "true")
|
|
}
|
|
|
|
path := configs.GhorgReCloneLocation()
|
|
yamlBytes, err := os.ReadFile(path)
|
|
if err != nil {
|
|
colorlog.PrintErrorAndExit(fmt.Sprintf("ERROR: parsing reclone.yaml, error: %v", err))
|
|
}
|
|
|
|
mapOfReClones := make(map[string]ReClone)
|
|
|
|
err = yaml.Unmarshal(yamlBytes, &mapOfReClones)
|
|
if err != nil {
|
|
colorlog.PrintErrorAndExit(fmt.Sprintf("ERROR: unmarshaling reclone.yaml, error:%v", err))
|
|
}
|
|
|
|
if cmd.Flags().Changed("list") {
|
|
colorlog.PrintInfo("**************************************************************")
|
|
colorlog.PrintInfo("**** Available reclone commands and optional descriptions ****")
|
|
colorlog.PrintInfo("**************************************************************")
|
|
fmt.Println("")
|
|
for key, value := range mapOfReClones {
|
|
colorlog.PrintInfo(fmt.Sprintf("- %s", key))
|
|
if value.Description != "" {
|
|
colorlog.PrintSubtleInfo(fmt.Sprintf(" description: %s", value.Description))
|
|
}
|
|
colorlog.PrintSubtleInfo(fmt.Sprintf(" cmd: %s", value.Cmd))
|
|
fmt.Println("")
|
|
}
|
|
os.Exit(0)
|
|
}
|
|
|
|
if len(argz) == 0 {
|
|
for rcIdentifier, reclone := range mapOfReClones {
|
|
runReClone(reclone, rcIdentifier)
|
|
}
|
|
} else {
|
|
for _, rcIdentifier := range argz {
|
|
if _, ok := mapOfReClones[rcIdentifier]; !ok {
|
|
colorlog.PrintErrorAndExit(fmt.Sprintf("ERROR: The key %v was not found in reclone.yaml", rcIdentifier))
|
|
} else {
|
|
runReClone(mapOfReClones[rcIdentifier], rcIdentifier)
|
|
}
|
|
}
|
|
}
|
|
|
|
printFinalOutput(argz, mapOfReClones)
|
|
}
|
|
|
|
func printFinalOutput(argz []string, reCloneMap map[string]ReClone) {
|
|
fmt.Println("")
|
|
colorlog.PrintSuccess("Completed! The following reclones were ran successfully...")
|
|
if len(argz) == 0 {
|
|
for key := range reCloneMap {
|
|
colorlog.PrintSuccess(fmt.Sprintf(" * %v", key))
|
|
}
|
|
} else {
|
|
for _, arg := range argz {
|
|
colorlog.PrintSuccess(fmt.Sprintf(" * %v", arg))
|
|
}
|
|
}
|
|
}
|
|
|
|
func sanitizeCmd(cmd string) string {
|
|
if strings.Contains(cmd, "-t=") {
|
|
splitCmd := strings.Split(cmd, "-t=")
|
|
firstHalf := splitCmd[0]
|
|
secondHalf := strings.Split(splitCmd[1], " ")[1:]
|
|
return firstHalf + "-t=XXXXXXX " + strings.Join(secondHalf, " ")
|
|
}
|
|
if strings.Contains(cmd, "-t ") {
|
|
splitCmd := strings.Split(cmd, "-t ")
|
|
firstHalf := splitCmd[0]
|
|
secondHalf := strings.Split(splitCmd[1], " ")[1:]
|
|
return firstHalf + "-t XXXXXXX " + strings.Join(secondHalf, " ")
|
|
}
|
|
if strings.Contains(cmd, "--token=") {
|
|
splitCmd := strings.Split(cmd, "--token=")
|
|
firstHalf := splitCmd[0]
|
|
secondHalf := strings.Split(splitCmd[1], " ")[1:]
|
|
return firstHalf + "--token=XXXXXXX " + strings.Join(secondHalf, " ")
|
|
}
|
|
if strings.Contains(cmd, "--token ") {
|
|
splitCmd := strings.Split(cmd, "--token ")
|
|
firstHalf := splitCmd[0]
|
|
secondHalf := strings.Split(splitCmd[1], " ")[1:]
|
|
return firstHalf + "--token XXXXXXX " + strings.Join(secondHalf, " ")
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
func runReClone(rc ReClone, rcIdentifier string) {
|
|
// make sure command starts with ghorg clone
|
|
splitCommand := strings.Split(rc.Cmd, " ")
|
|
ghorg, clone, remainingCommand := splitCommand[0], splitCommand[1], splitCommand[1:]
|
|
|
|
if ghorg != "ghorg" || clone != "clone" {
|
|
colorlog.PrintErrorAndExit("ERROR: Only ghorg clone commands are permitted in your reclone.yaml")
|
|
}
|
|
|
|
safeToLogCmd := sanitizeCmd(strings.Clone(rc.Cmd))
|
|
|
|
if !isQuietReClone() {
|
|
fmt.Println("")
|
|
colorlog.PrintInfo(fmt.Sprintf("Running reclone: %v", rcIdentifier))
|
|
if rc.Description != "" {
|
|
colorlog.PrintInfo(fmt.Sprintf("Description: %v", rc.Description))
|
|
fmt.Println("")
|
|
}
|
|
colorlog.PrintInfo(fmt.Sprintf("> %v", safeToLogCmd))
|
|
}
|
|
|
|
ghorgClone := exec.Command("ghorg", remainingCommand...)
|
|
|
|
if os.Getenv("GHORG_CONFIG") == "none" {
|
|
os.Setenv("GHORG_CONFIG", "")
|
|
}
|
|
|
|
os.Setenv("GHORG_RECLONE_RUNNING", "true")
|
|
defer os.Setenv("GHORG_RECLONE_RUNNING", "false")
|
|
|
|
if os.Getenv("GHORG_RECLONE_ENV_CONFIG_ONLY") == "false" {
|
|
// have to unset all ghorg envs because root command will set them on initialization of ghorg cmd
|
|
for _, e := range os.Environ() {
|
|
keyValue := strings.SplitN(e, "=", 2)
|
|
env := keyValue[0]
|
|
ghorgEnv := strings.HasPrefix(env, "GHORG_")
|
|
|
|
// skip global flags and reclone flags which are set in the conf.yaml
|
|
if env == "GHORG_COLOR" || env == "GHORG_CONFIG" || env == "GHORG_RECLONE_QUIET" || env == "GHORG_RECLONE_PATH" || env == "GHORG_RECLONE_RUNNING" {
|
|
continue
|
|
}
|
|
if ghorgEnv {
|
|
os.Unsetenv(env)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Connect ghorgClone's stdout and stderr to the current process's stdout and stderr
|
|
if !isQuietReClone() {
|
|
ghorgClone.Stdout = os.Stdout
|
|
ghorgClone.Stderr = os.Stderr
|
|
} else {
|
|
spinningSpinner.Start()
|
|
defer spinningSpinner.Stop()
|
|
ghorgClone.Stdout = nil
|
|
ghorgClone.Stderr = nil
|
|
}
|
|
|
|
err := ghorgClone.Start()
|
|
if err != nil {
|
|
spinningSpinner.Stop()
|
|
colorlog.PrintErrorAndExit(fmt.Sprintf("ERROR: Starting ghorg clone cmd: %v, err: %v", safeToLogCmd, err))
|
|
}
|
|
|
|
err = ghorgClone.Wait()
|
|
status := "success"
|
|
if err != nil {
|
|
status = "fail"
|
|
}
|
|
|
|
if rc.PostExecScript != "" {
|
|
postCmd := exec.Command(rc.PostExecScript, status, rcIdentifier)
|
|
postCmd.Stdout = os.Stdout
|
|
postCmd.Stderr = os.Stderr
|
|
errPost := postCmd.Run()
|
|
if errPost != nil {
|
|
colorlog.PrintError(fmt.Sprintf("ERROR: Running post_exec_script %s: %v", rc.PostExecScript, errPost))
|
|
}
|
|
}
|
|
|
|
|
|
if err != nil {
|
|
spinningSpinner.Stop()
|
|
colorlog.PrintErrorAndExit(fmt.Sprintf("ERROR: Running ghorg clone cmd: %v, err: %v", safeToLogCmd, err))
|
|
}
|
|
}
|