diff --git a/commands/add.go b/commands/add.go index 8b5facaf..17fbbc93 100644 --- a/commands/add.go +++ b/commands/add.go @@ -3,9 +3,7 @@ package commands import ( "github.com/spf13/cobra" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/input" - "github.com/MichaelMure/git-bug/util/interrupt" ) type addOptions struct { @@ -19,9 +17,10 @@ func newAddCommand() *cobra.Command { options := addOptions{} cmd := &cobra.Command{ - Use: "add", - Short: "Create a new bug.", - PreRunE: loadRepoEnsureUser(env), + Use: "add", + Short: "Create a new bug.", + PreRunE: loadBackendEnsureUser(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runAdd(env, options) }, @@ -41,13 +40,7 @@ func newAddCommand() *cobra.Command { } func runAdd(env *Env, opts addOptions) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - + var err error if opts.messageFile != "" && opts.message == "" { opts.title, opts.message, err = input.BugCreateFileInput(opts.messageFile) if err != nil { @@ -56,7 +49,7 @@ func runAdd(env *Env, opts addOptions) error { } if opts.messageFile == "" && (opts.message == "" || opts.title == "") { - opts.title, opts.message, err = input.BugCreateEditorInput(backend, opts.title, opts.message) + opts.title, opts.message, err = input.BugCreateEditorInput(env.backend, opts.title, opts.message) if err == input.ErrEmptyTitle { env.out.Println("Empty title, aborting.") @@ -67,7 +60,7 @@ func runAdd(env *Env, opts addOptions) error { } } - b, _, err := backend.NewBug(opts.title, opts.message) + b, _, err := env.backend.NewBug(opts.title, opts.message) if err != nil { return err } diff --git a/commands/bridge.go b/commands/bridge.go index 8a2cf38b..46b3d9ec 100644 --- a/commands/bridge.go +++ b/commands/bridge.go @@ -4,17 +4,16 @@ import ( "github.com/spf13/cobra" "github.com/MichaelMure/git-bug/bridge" - "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newBridgeCommand() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "bridge", - Short: "Configure and use bridges to other bug trackers.", - PreRunE: loadRepo(env), + Use: "bridge", + Short: "Configure and use bridges to other bug trackers.", + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridge(env) }, @@ -31,14 +30,7 @@ func newBridgeCommand() *cobra.Command { } func runBridge(env *Env) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - - configured, err := bridge.ConfiguredBridges(backend) + configured, err := bridge.ConfiguredBridges(env.backend) if err != nil { return err } diff --git a/commands/bridge_auth.go b/commands/bridge_auth.go index e51b9b9d..db4c5212 100644 --- a/commands/bridge_auth.go +++ b/commands/bridge_auth.go @@ -9,18 +9,17 @@ import ( text "github.com/MichaelMure/go-term-text" "github.com/MichaelMure/git-bug/bridge/core/auth" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/util/colors" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newBridgeAuthCommand() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "auth", - Short: "List all known bridge authentication credentials.", - PreRunE: loadRepo(env), + Use: "auth", + Short: "List all known bridge authentication credentials.", + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridgeAuth(env) }, @@ -35,14 +34,7 @@ func newBridgeAuthCommand() *cobra.Command { } func runBridgeAuth(env *Env) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - - creds, err := auth.List(backend) + creds, err := auth.List(env.backend) if err != nil { return err } diff --git a/commands/bridge_auth_addtoken.go b/commands/bridge_auth_addtoken.go index dde7a6dd..55edd919 100644 --- a/commands/bridge_auth_addtoken.go +++ b/commands/bridge_auth_addtoken.go @@ -14,7 +14,6 @@ import ( "github.com/MichaelMure/git-bug/bridge/core" "github.com/MichaelMure/git-bug/bridge/core/auth" "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/util/interrupt" ) type bridgeAuthAddTokenOptions struct { @@ -28,9 +27,10 @@ func newBridgeAuthAddTokenCommand() *cobra.Command { options := bridgeAuthAddTokenOptions{} cmd := &cobra.Command{ - Use: "add-token []", - Short: "Store a new token", - PreRunE: loadRepoEnsureUser(env), + Use: "add-token []", + Short: "Store a new token", + PreRunE: loadBackendEnsureUser(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridgeAuthAddToken(env, options, args) }, @@ -64,13 +64,6 @@ func runBridgeAuthAddToken(env *Env, opts bridgeAuthAddTokenOptions, args []stri return fmt.Errorf("flag --login is required") } - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - if !core.TargetExist(opts.target) { return fmt.Errorf("unknown target") } @@ -93,11 +86,12 @@ func runBridgeAuthAddToken(env *Env, opts bridgeAuthAddTokenOptions, args []stri } var user *cache.IdentityCache + var err error if opts.user == "" { - user, err = backend.GetUserIdentity() + user, err = env.backend.GetUserIdentity() } else { - user, err = backend.ResolveIdentityPrefix(opts.user) + user, err = env.backend.ResolveIdentityPrefix(opts.user) } if err != nil { return err diff --git a/commands/bridge_auth_show.go b/commands/bridge_auth_show.go index f8b15c9a..408a6cf1 100644 --- a/commands/bridge_auth_show.go +++ b/commands/bridge_auth_show.go @@ -9,17 +9,16 @@ import ( "github.com/spf13/cobra" "github.com/MichaelMure/git-bug/bridge/core/auth" - "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newBridgeAuthShow() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "show", - Short: "Display an authentication credential.", - PreRunE: loadRepo(env), + Use: "show", + Short: "Display an authentication credential.", + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridgeAuthShow(env, args) }, @@ -30,13 +29,6 @@ func newBridgeAuthShow() *cobra.Command { } func runBridgeAuthShow(env *Env, args []string) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - cred, err := auth.LoadWithPrefix(env.repo, args[0]) if err != nil { return err diff --git a/commands/bridge_configure.go b/commands/bridge_configure.go index 83555b0c..ecdb6502 100644 --- a/commands/bridge_configure.go +++ b/commands/bridge_configure.go @@ -12,9 +12,7 @@ import ( "github.com/MichaelMure/git-bug/bridge" "github.com/MichaelMure/git-bug/bridge/core" "github.com/MichaelMure/git-bug/bridge/core/auth" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/repository" - "github.com/MichaelMure/git-bug/util/interrupt" ) type bridgeConfigureOptions struct { @@ -86,7 +84,8 @@ git bug bridge configure \ --target=github \ --url=https://github.com/michaelmure/git-bug \ --token=$(TOKEN)`, - PreRunE: loadRepo(env), + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridgeConfigure(env, options) }, @@ -111,12 +110,7 @@ git bug bridge configure \ } func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) + var err error if (opts.tokenStdin || opts.token != "" || opts.params.CredPrefix != "") && (opts.name == "" || opts.target == "") { @@ -156,7 +150,7 @@ func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error { } } - b, err := bridge.NewBridge(backend, opts.target, opts.name) + b, err := bridge.NewBridge(env.backend, opts.target, opts.name) if err != nil { return err } diff --git a/commands/bridge_pull.go b/commands/bridge_pull.go index dc8825fa..bb705582 100644 --- a/commands/bridge_pull.go +++ b/commands/bridge_pull.go @@ -13,7 +13,6 @@ import ( "github.com/MichaelMure/git-bug/bridge" "github.com/MichaelMure/git-bug/bridge/core" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/util/interrupt" ) @@ -27,9 +26,10 @@ func newBridgePullCommand() *cobra.Command { options := bridgePullOptions{} cmd := &cobra.Command{ - Use: "pull []", - Short: "Pull updates.", - PreRunE: loadRepo(env), + Use: "pull []", + Short: "Pull updates.", + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridgePull(env, options, args) }, @@ -50,19 +50,13 @@ func runBridgePull(env *Env, opts bridgePullOptions, args []string) error { return fmt.Errorf("only one of --no-resume and --since flags should be used") } - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - var b *core.Bridge + var err error if len(args) == 0 { - b, err = bridge.DefaultBridge(backend) + b, err = bridge.DefaultBridge(env.backend) } else { - b, err = bridge.LoadBridge(backend, args[0]) + b, err = bridge.LoadBridge(env.backend, args[0]) } if err != nil { diff --git a/commands/bridge_push.go b/commands/bridge_push.go index 73df87fb..7061a5ca 100644 --- a/commands/bridge_push.go +++ b/commands/bridge_push.go @@ -10,7 +10,6 @@ import ( "github.com/MichaelMure/git-bug/bridge" "github.com/MichaelMure/git-bug/bridge/core" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/util/interrupt" ) @@ -18,9 +17,10 @@ func newBridgePushCommand() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "push []", - Short: "Push updates.", - PreRunE: loadRepoEnsureUser(env), + Use: "push []", + Short: "Push updates.", + PreRunE: loadBackendEnsureUser(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridgePush(env, args) }, @@ -31,19 +31,13 @@ func newBridgePushCommand() *cobra.Command { } func runBridgePush(env *Env, args []string) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - var b *core.Bridge + var err error if len(args) == 0 { - b, err = bridge.DefaultBridge(backend) + b, err = bridge.DefaultBridge(env.backend) } else { - b, err = bridge.LoadBridge(backend, args[0]) + b, err = bridge.LoadBridge(env.backend, args[0]) } if err != nil { diff --git a/commands/bridge_rm.go b/commands/bridge_rm.go index 4ff963db..9f93c37a 100644 --- a/commands/bridge_rm.go +++ b/commands/bridge_rm.go @@ -4,17 +4,16 @@ import ( "github.com/spf13/cobra" "github.com/MichaelMure/git-bug/bridge" - "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newBridgeRm() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "rm ", - Short: "Delete a configured bridge.", - PreRunE: loadRepo(env), + Use: "rm ", + Short: "Delete a configured bridge.", + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runBridgeRm(env, args) }, @@ -25,14 +24,7 @@ func newBridgeRm() *cobra.Command { } func runBridgeRm(env *Env, args []string) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - - err = bridge.RemoveBridge(backend, args[0]) + err := bridge.RemoveBridge(env.backend, args[0]) if err != nil { return err } diff --git a/commands/comment.go b/commands/comment.go index 82e7d9f6..e81405a6 100644 --- a/commands/comment.go +++ b/commands/comment.go @@ -4,19 +4,18 @@ import ( text "github.com/MichaelMure/go-term-text" "github.com/spf13/cobra" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/commands/select" "github.com/MichaelMure/git-bug/util/colors" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newCommentCommand() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "comment []", - Short: "Display or add comments to a bug.", - PreRunE: loadRepo(env), + Use: "comment []", + Short: "Display or add comments to a bug.", + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runComment(env, args) }, @@ -28,14 +27,7 @@ func newCommentCommand() *cobra.Command { } func runComment(env *Env, args []string) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - - b, args, err := _select.ResolveBug(backend, args) + b, args, err := _select.ResolveBug(env.backend, args) if err != nil { return err } diff --git a/commands/comment_add.go b/commands/comment_add.go index 1a560b5e..47366d00 100644 --- a/commands/comment_add.go +++ b/commands/comment_add.go @@ -3,10 +3,8 @@ package commands import ( "github.com/spf13/cobra" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/commands/select" "github.com/MichaelMure/git-bug/input" - "github.com/MichaelMure/git-bug/util/interrupt" ) type commentAddOptions struct { @@ -19,9 +17,10 @@ func newCommentAddCommand() *cobra.Command { options := commentAddOptions{} cmd := &cobra.Command{ - Use: "add []", - Short: "Add a new comment to a bug.", - PreRunE: loadRepoEnsureUser(env), + Use: "add []", + Short: "Add a new comment to a bug.", + PreRunE: loadBackendEnsureUser(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runCommentAdd(env, options, args) }, @@ -40,14 +39,7 @@ func newCommentAddCommand() *cobra.Command { } func runCommentAdd(env *Env, opts commentAddOptions, args []string) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - - b, args, err := _select.ResolveBug(backend, args) + b, args, err := _select.ResolveBug(env.backend, args) if err != nil { return err } @@ -60,7 +52,7 @@ func runCommentAdd(env *Env, opts commentAddOptions, args []string) error { } if opts.messageFile == "" && opts.message == "" { - opts.message, err = input.BugCommentEditorInput(backend, "") + opts.message, err = input.BugCommentEditorInput(env.backend, "") if err == input.ErrEmptyMessage { env.err.Println("Empty message, aborting.") return nil diff --git a/commands/deselect.go b/commands/deselect.go index 22a5f55d..23f77e2d 100644 --- a/commands/deselect.go +++ b/commands/deselect.go @@ -3,9 +3,7 @@ package commands import ( "github.com/spf13/cobra" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/commands/select" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newDeselectCommand() *cobra.Command { @@ -19,7 +17,8 @@ git bug comment git bug status git bug deselect `, - PreRunE: loadRepo(env), + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runDeselect(env) }, @@ -29,14 +28,7 @@ git bug deselect } func runDeselect(env *Env) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - - err = _select.Clear(backend) + err := _select.Clear(env.backend) if err != nil { return err } diff --git a/commands/env.go b/commands/env.go index daba8420..c3596c2d 100644 --- a/commands/env.go +++ b/commands/env.go @@ -5,14 +5,21 @@ import ( "io" "os" + "github.com/spf13/cobra" + + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/cache" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" + "github.com/MichaelMure/git-bug/util/interrupt" ) // Env is the environment of a command type Env struct { - repo repository.ClockedRepo - out out - err out + repo repository.ClockedRepo + backend *cache.RepoCache + out out + err out } func newEnv() *Env { @@ -38,3 +45,106 @@ func (o out) Print(a ...interface{}) { func (o out) Println(a ...interface{}) { _, _ = fmt.Fprintln(o, a...) } + +// loadRepo is a pre-run function that load the repository for use in a command +func loadRepo(env *Env) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + cwd, err := os.Getwd() + if err != nil { + return fmt.Errorf("unable to get the current working directory: %q", err) + } + + env.repo, err = repository.NewGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader}) + if err == repository.ErrNotARepo { + return fmt.Errorf("%s must be run from within a git repo", rootCommandName) + } + + if err != nil { + return err + } + + return nil + } +} + +// loadRepoEnsureUser is the same as loadRepo, but also ensure that the user has configured +// an identity. Use this pre-run function when an error after using the configured user won't +// do. +func loadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + err := loadRepo(env)(cmd, args) + if err != nil { + return err + } + + _, err = identity.GetUserIdentity(env.repo) + if err != nil { + return err + } + + return nil + } +} + +// loadBackend is a pre-run function that load the repository and the backend for use in a command +// When using this function you also need to use closeBackend as a post-run +func loadBackend(env *Env) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + err := loadRepo(env)(cmd, args) + if err != nil { + return err + } + + env.backend, err = cache.NewRepoCache(env.repo) + if err != nil { + return err + } + + cleaner := func(env *Env) interrupt.CleanerFunc { + return func() error { + if env.backend != nil { + err := env.backend.Close() + env.backend = nil + return err + } + return nil + } + } + + // Cleanup properly on interrupt + interrupt.RegisterCleaner(cleaner(env)) + return nil + } +} + +// loadBackendEnsureUser is the same as loadBackend, but also ensure that the user has configured +// an identity. Use this pre-run function when an error after using the configured user won't +// do. +func loadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + err := loadRepo(env)(cmd, args) + if err != nil { + return err + } + + _, err = identity.GetUserIdentity(env.repo) + if err != nil { + return err + } + + return nil + } +} + +// closeBackend is a post-run function that will close the backend properly +// if it has been opened. +func closeBackend(env *Env) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + if env.backend == nil { + return nil + } + err := env.backend.Close() + env.backend = nil + return err + } +} diff --git a/commands/label.go b/commands/label.go index e48be18e..de7bdb3a 100644 --- a/commands/label.go +++ b/commands/label.go @@ -3,18 +3,17 @@ package commands import ( "github.com/spf13/cobra" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/commands/select" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newLabelCommand() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "label []", - Short: "Display, add or remove labels to/from a bug.", - PreRunE: loadRepo(env), + Use: "label []", + Short: "Display, add or remove labels to/from a bug.", + PreRunE: loadBackend(env), + PostRunE: closeBackend(env), RunE: func(cmd *cobra.Command, args []string) error { return runLabel(env, args) }, @@ -27,14 +26,7 @@ func newLabelCommand() *cobra.Command { } func runLabel(env *Env, args []string) error { - backend, err := cache.NewRepoCache(env.repo) - if err != nil { - return err - } - defer backend.Close() - interrupt.RegisterCleaner(backend.Close) - - b, args, err := _select.ResolveBug(backend, args) + b, args, err := _select.ResolveBug(env.backend, args) if err != nil { return err } diff --git a/commands/label_add.go b/commands/label_add.go index 83a9f064..05a27948 100644 --- a/commands/label_add.go +++ b/commands/label_add.go @@ -3,18 +3,17 @@ package commands import ( "github.com/spf13/cobra" - "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/commands/select" - "github.com/MichaelMure/git-bug/util/interrupt" ) func newLabelAddCommand() *cobra.Command { env := newEnv() cmd := &cobra.Command{ - Use: "add []