git-import/main.go

193 lines
4.1 KiB
Go

package main
import (
"errors"
"fmt"
"net/http"
"net/url"
"os"
"os/exec"
"github.com/urfave/cli/v2"
"go.jolheiser.com/beaver"
)
var (
Version = "develop"
output string
author string
email string
gpg string
display bool
ssh bool
insecure bool
debug bool
)
func main() {
app := cli.NewApp()
app.Name = "git-import"
app.Usage = "Import from vanity git URLs"
app.Version = Version
app.Flags = []cli.Flag{
&cli.BoolFlag{
Name: "display",
Aliases: []string{"d"},
Usage: "Display URL instead of cloning",
Destination: &display,
},
&cli.BoolFlag{
Name: "ssh",
Aliases: []string{"s"},
Usage: "Use SSH if available",
Destination: &ssh,
},
&cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "Path to output (default: git-import name)",
Destination: &output,
},
&cli.StringFlag{
Name: "author",
Aliases: []string{"a"},
Usage: "Signature author",
Destination: &author,
},
&cli.StringFlag{
Name: "email",
Aliases: []string{"e"},
Usage: "Signature email",
Destination: &email,
},
&cli.StringFlag{
Name: "gpg",
Aliases: []string{"g"},
Usage: "GPG key to sign with",
Destination: &gpg,
},
&cli.BoolFlag{
Name: "insecure",
Usage: "Use HTTP instead of HTTPS by default",
Destination: &insecure,
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug logging",
Destination: &debug,
},
}
app.Action = doImport
if err := app.Run(os.Args); err != nil {
beaver.Error(err)
}
}
func doImport(ctx *cli.Context) error {
if ctx.NArg() < 1 {
return errors.New("must specify an import URL")
}
if debug {
beaver.Console.Level = beaver.DEBUG
}
importURL := ctx.Args().First()
u, err := url.Parse(importURL)
if err != nil {
return err
}
if u.Scheme == "" {
u.Scheme = "https"
if insecure {
u.Scheme = "http"
}
}
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 := 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 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 := os.Chdir(output); err != nil {
return fmt.Errorf("could not change to `%s` directory. Git config will not store SSH command", output)
}
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.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}