github.com/git-lfs/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  }