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