github.com/saracen/git-lfs@v2.5.2+incompatible/commands/run.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "path/filepath" 8 "strings" 9 "sync" 10 "time" 11 12 "github.com/git-lfs/git-lfs/config" 13 "github.com/spf13/cobra" 14 ) 15 16 var ( 17 commandFuncs []func() *cobra.Command 18 commandMu sync.Mutex 19 20 rootVersion bool 21 ) 22 23 // NewCommand creates a new 'git-lfs' sub command, given a command name and 24 // command run function. 25 // 26 // Each command will initialize the local storage ('.git/lfs') directory when 27 // run, unless the PreRun hook is set to nil. 28 func NewCommand(name string, runFn func(*cobra.Command, []string)) *cobra.Command { 29 return &cobra.Command{Use: name, Run: runFn, PreRun: setupHTTPLogger} 30 } 31 32 // RegisterCommand creates a direct 'git-lfs' subcommand, given a command name, 33 // a command run function, and an optional callback during the command 34 // initialization process. 35 // 36 // The 'git-lfs' command initialization is deferred until the `commands.Run()` 37 // function is called. The fn callback is passed the output from NewCommand, 38 // and gives the caller the flexibility to customize the command by adding 39 // flags, tweaking command hooks, etc. 40 func RegisterCommand(name string, runFn func(cmd *cobra.Command, args []string), fn func(cmd *cobra.Command)) { 41 commandMu.Lock() 42 commandFuncs = append(commandFuncs, func() *cobra.Command { 43 cmd := NewCommand(name, runFn) 44 if fn != nil { 45 fn(cmd) 46 } 47 return cmd 48 }) 49 commandMu.Unlock() 50 } 51 52 // Run initializes the 'git-lfs' command and runs it with the given stdin and 53 // command line args. 54 // 55 // It returns an exit code. 56 func Run() int { 57 log.SetOutput(ErrorWriter) 58 59 root := NewCommand("git-lfs", gitlfsCommand) 60 root.PreRun = nil 61 62 // Set up help/usage funcs based on manpage text 63 root.SetHelpTemplate("{{.UsageString}}") 64 root.SetHelpFunc(helpCommand) 65 root.SetUsageFunc(usageCommand) 66 67 root.Flags().BoolVarP(&rootVersion, "version", "v", false, "") 68 69 cfg = config.New() 70 71 for _, f := range commandFuncs { 72 if cmd := f(); cmd != nil { 73 root.AddCommand(cmd) 74 } 75 } 76 77 err := root.Execute() 78 closeAPIClient() 79 80 if err != nil { 81 return 127 82 } 83 return 0 84 } 85 86 func gitlfsCommand(cmd *cobra.Command, args []string) { 87 versionCommand(cmd, args) 88 if !rootVersion { 89 cmd.Usage() 90 } 91 } 92 93 func helpCommand(cmd *cobra.Command, args []string) { 94 if len(args) == 0 { 95 printHelp("git-lfs") 96 } else { 97 printHelp(args[0]) 98 } 99 } 100 101 func usageCommand(cmd *cobra.Command) error { 102 printHelp(cmd.Name()) 103 return nil 104 } 105 106 func printHelp(commandName string) { 107 if txt, ok := ManPages[commandName]; ok { 108 fmt.Fprintf(os.Stdout, "%s\n", strings.TrimSpace(txt)) 109 } else { 110 fmt.Fprintf(os.Stdout, "Sorry, no usage text found for %q\n", commandName) 111 } 112 } 113 114 func setupHTTPLogger(cmd *cobra.Command, args []string) { 115 if len(os.Getenv("GIT_LOG_STATS")) < 1 { 116 return 117 } 118 119 logBase := filepath.Join(cfg.LocalLogDir(), "http") 120 if err := os.MkdirAll(logBase, 0755); err != nil { 121 fmt.Fprintf(os.Stderr, "Error logging http stats: %s\n", err) 122 return 123 } 124 125 logFile := fmt.Sprintf("http-%d.log", time.Now().Unix()) 126 file, err := os.Create(filepath.Join(logBase, logFile)) 127 if err != nil { 128 fmt.Fprintf(os.Stderr, "Error logging http stats: %s\n", err) 129 } else { 130 getAPIClient().LogHTTPStats(file) 131 } 132 }