github.com/nkprince007/lab@v0.6.2-0.20171218071646-19d68b56f403/cmd/root.go (about) 1 package cmd 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "os" 8 "os/exec" 9 "strconv" 10 "strings" 11 "syscall" 12 "text/template" 13 "unicode" 14 15 "github.com/pkg/errors" 16 "github.com/spf13/cobra" 17 gitconfig "github.com/tcnksm/go-gitconfig" 18 "github.com/zaquestion/lab/internal/git" 19 lab "github.com/zaquestion/lab/internal/gitlab" 20 ) 21 22 // RootCmd represents the base command when called without any subcommands 23 var RootCmd = &cobra.Command{ 24 Use: "lab", 25 Short: "A Git Wrapper for GitLab", 26 Long: ``, 27 Run: func(cmd *cobra.Command, args []string) { 28 formatChar := "\n" 29 if git.IsHub { 30 formatChar = "" 31 } 32 33 git := git.New() 34 git.Stdout = nil 35 git.Stderr = nil 36 usage, _ := git.CombinedOutput() 37 fmt.Printf("%s%sThese GitLab commands are provided by lab:\n%s\n\n", string(usage), formatChar, labUsage(cmd)) 38 }, 39 } 40 41 func trimRightSpace(s string) string { 42 return strings.TrimRightFunc(s, unicode.IsSpace) 43 } 44 45 func rpad(s string, padding int) string { 46 template := fmt.Sprintf("%%-%ds", padding) 47 return fmt.Sprintf(template, s) 48 } 49 50 var templateFuncs = template.FuncMap{ 51 "trimTrailingWhitespaces": trimRightSpace, 52 "rpad": rpad, 53 } 54 55 const labUsageTmpl = `{{range .Commands}}{{if (and (or .IsAvailableCommand (ne .Name "help")) (and (ne .Name "clone") (ne .Name "version")))}} 56 {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}` 57 58 func labUsage(c *cobra.Command) string { 59 t := template.New("top") 60 t.Funcs(templateFuncs) 61 template.Must(t.Parse(labUsageTmpl)) 62 63 var buf bytes.Buffer 64 err := t.Execute(&buf, c) 65 if err != nil { 66 c.Println(err) 67 } 68 return buf.String() 69 } 70 71 // parseArgsRemote returns the remote and a number if parsed. Many commands 72 // accept a remote to operate on and number such as a page id 73 func parseArgsRemote(args []string) (string, int64, error) { 74 if len(args) == 2 { 75 n, err := strconv.ParseInt(args[1], 0, 64) 76 if err != nil { 77 return "", 0, err 78 } 79 ok, err := git.IsRemote(args[0]) 80 if err != nil { 81 return "", 0, err 82 } else if !ok { 83 return "", 0, errors.Errorf("%s is not a valid remote", args[0]) 84 } 85 return args[0], n, nil 86 } 87 if len(args) == 1 { 88 ok, err := git.IsRemote(args[0]) 89 if err != nil { 90 return "", 0, err 91 } 92 if ok { 93 return args[0], 0, nil 94 } 95 n, err := strconv.ParseInt(args[0], 0, 64) 96 if err == nil { 97 return "", n, nil 98 } 99 return "", 0, errors.Errorf("%s is not a valid remote or number", args[0]) 100 } 101 return "", 0, nil 102 } 103 104 var ( 105 // Will be updated to upstream in init() if "upstream" remote exists 106 forkedFromRemote = "origin" 107 // Will be updated to lab.User() in init() if forkedFrom is "origin" 108 forkRemote = "origin" 109 ) 110 111 // Execute adds all child commands to the root command and sets flags appropriately. 112 // This is called by main.main(). It only needs to happen once to the rootCmd. 113 func Execute() { 114 _, err := gitconfig.Local("remote.upstream.url") 115 if err == nil { 116 forkedFromRemote = "upstream" 117 } 118 119 if forkedFromRemote == "origin" { 120 // Check if the user fork exists 121 _, err = gitconfig.Local("remote." + lab.User() + ".url") 122 if err == nil { 123 forkRemote = lab.User() 124 } 125 } 126 if cmd, _, err := RootCmd.Find(os.Args[1:]); err != nil || cmd.Use == "clone" { 127 // Determine if any undefined flags were passed to "clone" 128 if cmd.Use == "clone" && len(os.Args) > 2 { 129 // ParseFlags will err in these cases 130 err = cmd.ParseFlags(os.Args[1:]) 131 if err == nil { 132 if err := RootCmd.Execute(); err != nil { 133 // Execute has already logged the error 134 os.Exit(1) 135 } 136 return 137 } 138 } 139 140 // Passthrough to git for any unrecognised commands 141 git := git.New(os.Args[1:]...) 142 err = git.Run() 143 if exiterr, ok := err.(*exec.ExitError); ok { 144 if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { 145 os.Exit(status.ExitStatus()) 146 } 147 } 148 if err != nil { 149 log.Fatal(err) 150 } 151 return 152 } 153 if err := RootCmd.Execute(); err != nil { 154 // Execute has already logged the error 155 os.Exit(1) 156 } 157 }