git-import/cmd/git-get/main.go

168 lines
3.9 KiB
Go

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 <import-url>", 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 <import-url>",
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()
}