refactor dehub binary's flags a bit

---
type: change
message: |-
  refactor dehub binary's flags a bit

  * Make flag outputting a bit prettier, omitting the flag section in both the
    usage header and the body if that sub-command has no flags set.

  * Use a different pattern for opening up the repo, since not all sub-commands
    will want to do so.
change_hash: AK10DRu7LBGpLHRHrQ7TMqgkofz1n1DwK16sg6tOGSq8
credentials:
- type: pgp_signature
  pub_key_id: 95C46FA6A41148AC
  body: iQIzBAABAgAdFiEEJ6tQKp6olvZKJ0lwlcRvpqQRSKwFAl6IydIACgkQlcRvpqQRSKz6tA/+KmSCy+o2jRb7ZMUz2WSSyERLT9u1hC0+5u5AsJvxhFZSPiEbCrMmM6IvPzmtWpfgTV5ug9C2kbNE5ghp/ANlbmwaTNfAv6bnZjsyLWP3AdrVNNW0w6xkoE3PXUGn06xx1Yst46tnHMKc8GXtFRCLfcgetFl9Fp2w0feIIv1Aw4dP2haCnSXgdHoXloFkVfKoKD1zZo+9uJ+sTOnQhXl0JPaP2eBIgjuhVNGb/RYmhU6pHhh5kObUocCcP8Ywn/xSHOeFV+JXjPSNBnAAHLWuwtwP9bJNUNUoIQKc5WS+oiW9wsGRJZemC4IUnvft73rRrRc6+H3ESFXxP3BRELPbn52uv4BJDMAfDHRuRYbOk1vVP3+KyaUQDJC3g/z6L3xkM1MKbOsjSXAl3XRLR8iwl4GbXqKSFCLHTULzRa4roLF32sef0hQUorQAhDuNpkBBmXjpC3QrCbJgOxZdOZTlqn8IbG7uR/g2uqoBv/P6afe4wOxis4iiMCG8bJd8Zinu6lQ5ULimkf6GWEw96+6bUQnVgEQl0/8nDjzEjWgXNN+OteIS6YVeU16rC/2lrYOobXE+4hP/+RUGG7lH2KBDH1MdtWJf0jSBvtPZ7qeDuMaFZeeFHzWdEkGAkfft1TrWK/1kBhthNAKE6dtazCNzebx+7KDY0fnz3Bs3LCr7PIg=
  account: mediocregopher
This commit is contained in:
mediocregopher 2020-04-04 11:54:31 -06:00
parent 921572d053
commit d189d46667
6 changed files with 82 additions and 38 deletions

View File

@ -15,7 +15,9 @@ func cmdCommit(ctx context.Context, cmd *dcmd.Cmd) {
flag := cmd.FlagSet() flag := cmd.FlagSet()
accountID := flag.String("account-id", "", "Account to accredit commit with") accountID := flag.String("account-id", "", "Account to accredit commit with")
repo := ctxRepo(ctx) var repo repo
repo.initFlags(flag)
accreditAndCommit := func(commit dehub.Commit) error { accreditAndCommit := func(commit dehub.Commit) error {
cfg, err := repo.LoadConfig() cfg, err := repo.LoadConfig()
@ -61,6 +63,10 @@ func cmdCommit(ctx context.Context, cmd *dcmd.Cmd) {
return nil, errors.New("-account-id is required") return nil, errors.New("-account-id is required")
} }
if err := repo.openRepo(); err != nil {
return nil, err
}
var err error var err error
if hasStaged, err = repo.HasStagedChanges(); err != nil { if hasStaged, err = repo.HasStagedChanges(); err != nil {
return nil, fmt.Errorf("determining if any changes have been staged: %w", err) return nil, fmt.Errorf("determining if any changes have been staged: %w", err)
@ -177,6 +183,9 @@ func cmdCombine(ctx context.Context, cmd *dcmd.Cmd) {
startRev := flag.String("start", "", "Revision of the starting commit to combine") startRev := flag.String("start", "", "Revision of the starting commit to combine")
endRev := flag.String("end", "", "Revision of the ending commit to combine") endRev := flag.String("end", "", "Revision of the ending commit to combine")
var repo repo
repo.initFlags(flag)
cmd.Run(func() (context.Context, error) { cmd.Run(func() (context.Context, error) {
if *onto == "" || if *onto == "" ||
*startRev == "" || *startRev == "" ||
@ -184,7 +193,10 @@ func cmdCombine(ctx context.Context, cmd *dcmd.Cmd) {
return nil, errors.New("-onto, -start, and -end are required") return nil, errors.New("-onto, -start, and -end are required")
} }
repo := ctxRepo(ctx) if err := repo.openRepo(); err != nil {
return nil, err
}
commits, err := repo.GetGitRevisionRange( commits, err := repo.GetGitRevisionRange(
plumbing.Revision(*startRev), plumbing.Revision(*startRev),
plumbing.Revision(*endRev), plumbing.Revision(*endRev),

View File

@ -18,13 +18,17 @@ func cmdHook(ctx context.Context, cmd *dcmd.Cmd) {
flag := cmd.FlagSet() flag := cmd.FlagSet()
preRcv := flag.Bool("pre-receive", false, "Use dehub as a server-side pre-receive hook") preRcv := flag.Bool("pre-receive", false, "Use dehub as a server-side pre-receive hook")
cmd.Run(func() (context.Context, error) { var repo repo
repo.initFlags(flag)
cmd.Run(func() (context.Context, error) {
if !*preRcv { if !*preRcv {
return nil, errors.New("must set the hook type") return nil, errors.New("must set the hook type")
} }
repo := ctxRepo(ctx) if err := repo.openRepo(); err != nil {
return nil, err
}
br := bufio.NewReader(os.Stdin) br := bufio.NewReader(os.Stdin)
for { for {

28
cmd/dehub/cmd_util.go Normal file
View File

@ -0,0 +1,28 @@
package main
import (
"flag"
"fmt"
"os"
"dehub.dev/src/dehub.git"
)
type repo struct {
bare bool
*dehub.Repo
}
func (r *repo) initFlags(flag *flag.FlagSet) {
flag.BoolVar(&r.bare, "bare", false, "If set then the repo being opened will be expected to be bare")
}
func (r *repo) openRepo() error {
var err error
if r.Repo, err = dehub.OpenRepo(".", dehub.OpenBare(r.bare)); err != nil {
wd, _ := os.Getwd()
return fmt.Errorf("opening repo at %q: %w", wd, err)
}
return nil
}

View File

@ -15,8 +15,13 @@ func cmdVerify(ctx context.Context, cmd *dcmd.Cmd) {
rev := flag.String("rev", "HEAD", "Revision of commit to verify") rev := flag.String("rev", "HEAD", "Revision of commit to verify")
branch := flag.String("branch", "", "Branch that the revision is on. If not given then the currently checked out branch is assumed") branch := flag.String("branch", "", "Branch that the revision is on. If not given then the currently checked out branch is assumed")
var repo repo
repo.initFlags(flag)
cmd.Run(func() (context.Context, error) { cmd.Run(func() (context.Context, error) {
repo := ctxRepo(ctx) if err := repo.openRepo(); err != nil {
return nil, err
}
gitCommit, err := repo.GetGitRevision(plumbing.Revision(*rev)) gitCommit, err := repo.GetGitRevision(plumbing.Revision(*rev))
if err != nil { if err != nil {

View File

@ -50,6 +50,14 @@ func (cmd *Cmd) getFlagSet() *flag.FlagSet {
return cmd.flagSet return cmd.flagSet
} }
func (cmd *Cmd) numFlags() int {
var n int
cmd.getFlagSet().VisitAll(func(*flag.Flag) {
n++
})
return n
}
// FlagSet returns a flag.Cmd instance on which parameter creation methods can // FlagSet returns a flag.Cmd instance on which parameter creation methods can
// be called, e.g. String(...) or Int(...). // be called, e.g. String(...) or Int(...).
func (cmd *Cmd) FlagSet() *flag.FlagSet { func (cmd *Cmd) FlagSet() *flag.FlagSet {
@ -77,11 +85,19 @@ func (cmd *Cmd) SubCmd(name, descr string, run func(context.Context, *Cmd)) {
} }
func (cmd *Cmd) printUsageHead(subCmdTitle string) { func (cmd *Cmd) printUsageHead(subCmdTitle string) {
hasFlags := cmd.numFlags() > 0
var title string var title string
if cmd.parent == nil { if cmd.parent == nil {
title = fmt.Sprintf("USAGE: %s [flags]", cmd.binary) title = fmt.Sprintf("USAGE: %s", cmd.binary)
if hasFlags {
title += " [flags]"
}
} else { } else {
title = fmt.Sprintf("%s [%s flags]", cmd.name, cmd.name) title = fmt.Sprintf("%s", cmd.name)
if hasFlags {
title += fmt.Sprintf(" [%s flags]", cmd.name)
}
} }
if subCmdTitle != "" { if subCmdTitle != "" {
@ -92,15 +108,20 @@ func (cmd *Cmd) printUsageHead(subCmdTitle string) {
if cmd.parent == nil { if cmd.parent == nil {
fmt.Printf("\n%s\n\n", title) fmt.Printf("\n%s\n\n", title)
fmt.Print("### FLAGS ###\n\n")
} else { } else {
cmd.parent.printUsageHead(title) cmd.parent.printUsageHead(title)
fmt.Printf("### %s FLAGS ###\n\n", strings.ToUpper(cmd.name))
} }
if hasFlags {
if cmd.parent == nil {
fmt.Print("### FLAGS ###\n\n")
} else {
fmt.Printf("### %s FLAGS ###\n\n", strings.ToUpper(cmd.name))
}
cmd.getFlagSet().PrintDefaults() cmd.getFlagSet().PrintDefaults()
fmt.Print("\n") fmt.Print("\n")
} }
}
// Run performs the comand. It starts by parsing all flags in the Cmd's FlagSet, // Run performs the comand. It starts by parsing all flags in the Cmd's FlagSet,
// and possibly exiting with a usage message if appropriate. It will then // and possibly exiting with a usage message if appropriate. It will then

View File

@ -2,44 +2,18 @@ package main
import ( import (
"context" "context"
"fmt"
"os"
"dehub.dev/src/dehub.git"
"dehub.dev/src/dehub.git/cmd/dehub/dcmd" "dehub.dev/src/dehub.git/cmd/dehub/dcmd"
) )
type cmdCtxKey int
const (
cmdCtxKeyRepo cmdCtxKey = iota
)
func ctxRepo(ctx context.Context) *dehub.Repo {
repo, ok := ctx.Value(cmdCtxKeyRepo).(*dehub.Repo)
if !ok {
panic("repo not initialized on the command context")
}
return repo
}
func main() { func main() {
cmd := dcmd.New() cmd := dcmd.New()
flag := cmd.FlagSet()
bare := flag.Bool("bare", false, "If set then dehub will expect to be working with a bare repo")
cmd.SubCmd("commit", "commits staged changes to the head of the current branch", cmdCommit) cmd.SubCmd("commit", "commits staged changes to the head of the current branch", cmdCommit)
cmd.SubCmd("verify", "verifies one or more commits as having the proper credentials", cmdVerify) cmd.SubCmd("verify", "verifies one or more commits as having the proper credentials", cmdVerify)
cmd.SubCmd("hook", "use dehub as a git hook", cmdHook) cmd.SubCmd("hook", "use dehub as a git hook", cmdHook)
cmd.SubCmd("combine", "Combine multiple change and credential commits into a single commit", cmdCombine) cmd.SubCmd("combine", "Combine multiple change and credential commits into a single commit", cmdCombine)
cmd.Run(func() (context.Context, error) { cmd.Run(func() (context.Context, error) {
repo, err := dehub.OpenRepo(".", dehub.OpenBare(*bare)) return context.Background(), nil
if err != nil {
wd, _ := os.Getwd()
return nil, fmt.Errorf("failed to OpenRepo at %q: %w", wd, err)
}
return context.WithValue(context.Background(), cmdCtxKeyRepo, repo), nil
}) })
} }