package main import ( "context" "errors" "flag" "fmt" "net/http" "net/url" "os" "os/exec" "path/filepath" "strings" "go.jolheiser.com/git-import" "github.com/peterbourgon/ff/v3" "github.com/peterbourgon/ff/v3/ffcli" "go.jolheiser.com/beaver" ) var ( Version = "develop" fs = flag.NewFlagSet("git-get ", flag.ExitOnError) output = fs.String("out", "", "Path to clone into (default: git-import name)") author = fs.String("author", "", "Signature Author ($GIT_IMPORT_AUTHOR)") email = fs.String("email", "", "Signature Email ($GIT_IMPORT_EMAIL)") gpg = fs.String("gpg", "", "GPG key to sign with ($GIT_IMPORT_GPG)") noMeta = fs.Bool("no-meta", false, "Don't check for meta, just clone") display = fs.Bool("display", false, "Display URL instead of cloning") ssh = fs.Bool("ssh", false, "Use SSH if $GIT_SSH_COMMAND is set") insecure = fs.Bool("insecure", false, "Use HTTP instead of HTTPS by default") debug = fs.Bool("debug", false, "Debug logging") ) func main() { cmd := &ffcli.Command{ Name: "git-get", ShortUsage: "git-get ", LongHelp: fmt.Sprintf("VERSION\n %s", Version), FlagSet: fs, Options: []ff.Option{ ff.WithEnvVarPrefix("GIT_IMPORT"), }, Exec: doImport, } if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil { beaver.Error(err) } } func doImport(_ context.Context, _ []string) error { if *debug { beaver.Console.Level = beaver.DEBUG } if fs.NArg() == 0 { fs.Usage() return nil } raw := fs.Arg(0) if !strings.HasPrefix(raw, "http") { raw = fmt.Sprintf("https://%s", raw) } u, err := url.Parse(raw) if err != nil { return err } if *insecure { u.Scheme = "http" } var gitImport gimport.GitImport if *noMeta { p := strings.Split(u.Path, "/") gitImport = gimport.GitImport{ Name: p[len(p)-1], HTTP: u.String(), SSH: fmt.Sprintf("git@%s:%s.git", u.Host, u.Path[1:]), } } else { u.RawQuery = "git-import=1" beaver.Debugf("Getting git-import from %s", u.String()) res, err := http.Get(u.String()) if err != nil { return fmt.Errorf("could not request URL `%s`: %v", u.String(), err) } defer res.Body.Close() gitImport, err = gimport.ParseMetaGitImport(res.Body) if err != nil { return fmt.Errorf("could not parse: %v", err) } } beaver.Debug(gitImport) if *display { if *ssh { fmt.Println(gitImport.SSH) return nil } fmt.Println(gitImport.HTTP) return nil } return doClone(gitImport) } func doClone(gitImport gimport.GitImport) error { if *output == "" { *output = gitImport.Name } cmd := exec.Command("git", "clone", gitImport.HTTP, *output) if *ssh { if gitImport.SSH == "" { return errors.New("SSH was not provided by git-import") } if os.Getenv("GIT_SSH_COMMAND") == "" { return errors.New("no environment variable found for GIT_SSH_COMMAND") } cmd = exec.Command("git", "clone", gitImport.SSH, *output) } cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("could not clone: %v", err) } if *ssh { if err := gitConfig("core.sshCommand", os.Getenv("GIT_SSH_COMMAND")); err != nil { beaver.Errorf("could not configure SSH: %v", err) } } if *author != "" { if err := gitConfig("user.name", *author); err != nil { beaver.Errorf("could not configure author: %v", err) } } if *email != "" { if err := gitConfig("user.email", *email); err != nil { beaver.Errorf("could not configure email: %v", err) } } if *gpg != "" { if err := gitConfig("user.signingkey", *gpg); err != nil { beaver.Errorf("could not configure GPG key: %v", err) } if err := gitConfig("commit.gpgsign", "true"); err != nil { beaver.Errorf("could not configure GPG signing: %v", err) } } return nil } func gitConfig(key, value string) error { cmd := exec.Command("git", "config", "--local", key, value) cmd.Dir = filepath.Join(".", *output) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() }