1package commands 2 3import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "sort" 9 "strings" 10 11 "github.com/github/hub/git" 12 "github.com/github/hub/ui" 13 "github.com/github/hub/utils" 14 "github.com/kballard/go-shellquote" 15) 16 17var cmdHelp = &Command{ 18 Run: runHelp, 19 GitExtension: true, 20 Usage: ` 21help hub 22help <COMMAND> 23help hub-<COMMAND> [--plain-text] 24`, 25 Long: `Show the help page for a command. 26 27## Options: 28 hub-<COMMAND> 29 Use this format to view help for hub extensions to an existing git command. 30 31 --plain-text 32 Skip man page lookup mechanism and display raw help text. 33 34## See also: 35 36hub(1), git-help(1) 37`, 38} 39 40var cmdListCmds = &Command{ 41 Key: "--list-cmds", 42 Run: runListCmds, 43 GitExtension: true, 44} 45 46func init() { 47 CmdRunner.Use(cmdHelp, "--help") 48 CmdRunner.Use(cmdListCmds) 49} 50 51func runHelp(helpCmd *Command, args *Args) { 52 if args.IsParamsEmpty() { 53 args.AfterFn(func() error { 54 ui.Println(helpText) 55 return nil 56 }) 57 return 58 } 59 60 p := utils.NewArgsParser() 61 p.RegisterBool("--all", "-a") 62 p.RegisterBool("--plain-text") 63 p.RegisterBool("--man", "-m") 64 p.RegisterBool("--web", "-w") 65 p.Parse(args.Params) 66 67 if p.Bool("--all") { 68 args.AfterFn(func() error { 69 ui.Printf("\nhub custom commands\n\n %s\n", strings.Join(customCommands(), " ")) 70 return nil 71 }) 72 return 73 } 74 75 isWeb := func() bool { 76 if p.Bool("--web") { 77 return true 78 } 79 if p.Bool("--man") { 80 return false 81 } 82 if f, err := git.Config("help.format"); err == nil { 83 return f == "web" || f == "html" 84 } 85 return false 86 } 87 88 cmdName := "" 89 if words := args.Words(); len(words) > 0 { 90 cmdName = words[0] 91 } 92 93 if cmdName == "hub" { 94 err := displayManPage("hub", args, isWeb()) 95 utils.Check(err) 96 return 97 } 98 99 foundCmd := lookupCmd(cmdName) 100 if foundCmd == nil { 101 return 102 } 103 104 if p.Bool("--plain-text") { 105 ui.Println(foundCmd.HelpText()) 106 os.Exit(0) 107 } 108 109 manPage := fmt.Sprintf("hub-%s", foundCmd.Name()) 110 err := displayManPage(manPage, args, isWeb()) 111 utils.Check(err) 112} 113 114func runListCmds(cmd *Command, args *Args) { 115 listOthers := false 116 parts := strings.SplitN(args.Command, "=", 2) 117 for _, kind := range strings.Split(parts[1], ",") { 118 if kind == "others" { 119 listOthers = true 120 break 121 } 122 } 123 124 if listOthers { 125 args.AfterFn(func() error { 126 ui.Println(strings.Join(customCommands(), "\n")) 127 return nil 128 }) 129 } 130} 131 132// On systems where `man` was found, invoke: 133// MANPATH={PREFIX}/share/man:$MANPATH man <page> 134// 135// otherwise: 136// less -R {PREFIX}/share/man/man1/<page>.1.txt 137func displayManPage(manPage string, args *Args, isWeb bool) error { 138 programPath, err := utils.CommandPath(args.ProgramPath) 139 if err != nil { 140 return err 141 } 142 143 if isWeb { 144 manPage += ".1.html" 145 manFile := filepath.Join(programPath, "..", "..", "share", "doc", "hub-doc", manPage) 146 args.Replace(args.Executable, "web--browse", manFile) 147 return nil 148 } 149 150 var manArgs []string 151 manProgram, _ := utils.CommandPath("man") 152 if manProgram != "" { 153 manArgs = []string{manProgram} 154 } else { 155 manPage += ".1.txt" 156 if manProgram = os.Getenv("PAGER"); manProgram != "" { 157 var err error 158 manArgs, err = shellquote.Split(manProgram) 159 if err != nil { 160 return err 161 } 162 } else { 163 manArgs = []string{"less", "-R"} 164 } 165 } 166 167 env := os.Environ() 168 if strings.HasSuffix(manPage, ".txt") { 169 manFile := filepath.Join(programPath, "..", "..", "share", "man", "man1", manPage) 170 manArgs = append(manArgs, manFile) 171 } else { 172 manArgs = append(manArgs, manPage) 173 manPath := filepath.Join(programPath, "..", "..", "share", "man") 174 env = append(env, fmt.Sprintf("MANPATH=%s:%s", manPath, os.Getenv("MANPATH"))) 175 } 176 177 c := exec.Command(manArgs[0], manArgs[1:]...) 178 c.Stdin = os.Stdin 179 c.Stdout = os.Stdout 180 c.Stderr = os.Stderr 181 c.Env = env 182 if err := c.Run(); err != nil { 183 return err 184 } 185 os.Exit(0) 186 return nil 187} 188 189func lookupCmd(name string) *Command { 190 if strings.HasPrefix(name, "hub-") { 191 return CmdRunner.Lookup(strings.TrimPrefix(name, "hub-")) 192 } else { 193 cmd := CmdRunner.Lookup(name) 194 if cmd != nil && !cmd.GitExtension { 195 return cmd 196 } else { 197 return nil 198 } 199 } 200} 201 202func customCommands() []string { 203 cmds := []string{} 204 for n, c := range CmdRunner.All() { 205 if !c.GitExtension && !strings.HasPrefix(n, "--") { 206 cmds = append(cmds, n) 207 } 208 } 209 210 sort.Strings(cmds) 211 212 return cmds 213} 214 215var helpText = ` 216These GitHub commands are provided by hub: 217 218 api Low-level GitHub API request interface 219 browse Open a GitHub page in the default browser 220 ci-status Show the status of GitHub checks for a commit 221 compare Open a compare page on GitHub 222 create Create this repository on GitHub and add GitHub as origin 223 delete Delete a repository on GitHub 224 fork Make a fork of a remote repository on GitHub and add as remote 225 gist Make a gist 226 issue List or create GitHub issues 227 pr List or checkout GitHub pull requests 228 pull-request Open a pull request on GitHub 229 release List or create GitHub releases 230 sync Fetch git objects from upstream and update branches 231` 232