diff --git a/cmd/dehub/main.go b/cmd/dehub/main.go index 31f0a81..bbd166e 100644 --- a/cmd/dehub/main.go +++ b/cmd/dehub/main.go @@ -2,12 +2,15 @@ package main import ( "bufio" + "bytes" "dehub" "errors" "flag" "fmt" "io" + "io/ioutil" "os" + "os/exec" "strings" "gopkg.in/src-d/go-git.v4/plumbing" @@ -20,6 +23,63 @@ func exitErr(err error) { os.Exit(1) } +func tmpFileMsg() (string, error) { + editor := os.Getenv("EDITOR") + if editor == "" { + return "", errors.New("EDITOR not set, please set it or use -msg in order to create your commit message") + } else if _, err := os.Stat(editor); err != nil { + return "", fmt.Errorf("could not stat EDITOR %q: %w", editor, err) + } + + tmpf, err := ioutil.TempFile("", "") + if err != nil { + return "", fmt.Errorf("could not open temp file: %w", err) + } + tmpfName := tmpf.Name() + defer os.Remove(tmpfName) + + tmpBody := bytes.NewBufferString(` + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit.`) + + _, err = io.Copy(tmpf, tmpBody) + tmpf.Close() + if err != nil { + return "", fmt.Errorf("could not write helper message to temp file %q: %w", tmpfName, err) + } + + cmd := exec.Command(editor, tmpfName) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return "", fmt.Errorf("error running '%s %q': %w", editor, tmpfName, err) + } + + body, err := ioutil.ReadFile(tmpfName) + if err != nil { + return "", fmt.Errorf("error retrieving message body from %q: %w", tmpfName, err) + } + + bodyFiltered := new(bytes.Buffer) + bodyBR := bufio.NewReader(bytes.NewBuffer(body)) + for { + line, err := bodyBR.ReadString('\n') + if errors.Is(err, io.EOF) { + break + } else if err != nil { + return "", fmt.Errorf("error reading from buffered body: %w", err) + } + + if !strings.HasPrefix(strings.TrimSpace(line), "#") { + bodyFiltered.WriteString(line) + } + } + + return strings.TrimSpace(bodyFiltered.String()), nil +} + type subCmdCtx struct { repo func() *dehub.Repo flag *flag.FlagSet @@ -46,9 +106,19 @@ var subCmds = []subCmd{ accountID := sctx.flag.String("account-id", "", "Account to sign commit as") sctx.flagParse() - if *msg == "" || *accountID == "" { + if *accountID == "" { flag.PrintDefaults() - return errors.New("-msg and -account-id are both required") + return errors.New("-account-id is required") + } + + if *msg == "" { + var err error + if *msg, err = tmpFileMsg(); err != nil { + return fmt.Errorf("error collecting commit message from user: %w", err) + + } else if *msg == "" { + return errors.New("empty commit message, not doing anything") + } } cfg, err := sctx.repo().LoadConfig()