From d41fe65a698f108f875bbeee389fcba314a29440 Mon Sep 17 00:00:00 2001 From: Dominik Schulz Date: Thu, 13 Jan 2022 20:58:11 +0100 Subject: [PATCH] Pass git commands directly to git (#2102) This allows using all git commands. RELEASE_NOTES=[ENHANCEMENT] gopass git invokes git directly Fixes #2097 Signed-off-by: Dominik Schulz --- internal/action/commands.go | 175 ++++++++++++++---------------------- internal/action/git.go | 32 +++++++ internal/store/root/rcs.go | 1 + main_test.go | 4 +- 4 files changed, 101 insertions(+), 111 deletions(-) create mode 100644 internal/action/git.go diff --git a/internal/action/commands.go b/internal/action/commands.go index 87496922ee..71758d37de 100644 --- a/internal/action/commands.go +++ b/internal/action/commands.go @@ -431,119 +431,18 @@ func (s *Action) GetCommands() []*cli.Command { }, }, { - Name: "git", - Usage: "Run a git command inside a password store (init, remote, push, pull)", - ArgsUsage: "[init|remote|push|pull]", + Name: "git", + Usage: "Run a git command inside a password store", Description: "" + "If the password store is a git repository, execute a git command " + - "specified by git-command-args." + - "WARNING: Deprecated. Please use gopass sync.", + "specified by git-command-args.", Hidden: true, - Subcommands: []*cli.Command{ - { - Name: "init", - Usage: "Init git repo", - Description: "Create and initialize a new git repo in the store", - Before: s.IsInitialized, - Action: s.RCSInit, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "store", - Usage: "Store to operate on", - }, - &cli.StringFlag{ - Name: "sign-key", - Usage: "GPG Key to sign commits", - }, - &cli.StringFlag{ - Name: "name", - Aliases: []string{"username"}, - Usage: "Git Author Name", - }, - &cli.StringFlag{ - Name: "email", - Aliases: []string{"useremail"}, - Usage: "Git Author Email", - }, - &cli.StringFlag{ - Name: "storage", - Usage: fmt.Sprintf("Select storage backend %v", backend.StorageRegistry.Backends()), - Value: "gitfs", - }, - }, - }, - { - Name: "remote", - Usage: "Manage git remotes", - Description: "These subcommands can be used to manage git remotes", - Before: s.IsInitialized, - Subcommands: []*cli.Command{ - { - Name: "add", - Usage: "Add git remote", - Description: "Add a new git remote", - Before: s.IsInitialized, - Action: s.RCSAddRemote, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "store", - Usage: "Store to operate on", - }, - }, - }, - { - Name: "remove", - Usage: "Remove git remote", - Description: "Remove a git remote", - Before: s.IsInitialized, - Action: s.RCSRemoveRemote, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "store", - Usage: "Store to operate on", - }, - }, - }, - }, - }, - { - Name: "push", - Usage: "Push to remote", - Description: "Push to a git remote", - Before: s.IsInitialized, - Action: s.RCSPush, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "store", - Usage: "Store to operate on", - }, - }, - }, - { - Name: "pull", - Usage: "Pull from remote", - Description: "Pull from a git remote", - Before: s.IsInitialized, - Action: s.RCSPull, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "store", - Usage: "Store to operate on", - }, - }, - }, - { - Name: "status", - Usage: "RCS status", - Description: "Show the RCS status", - Before: s.IsInitialized, - Action: s.RCSStatus, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "store", - Usage: "Store to operate on", - }, - }, + Before: s.IsInitialized, + Action: s.Git, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "store", + Usage: "Store to operate on", }, }, }, @@ -811,6 +710,62 @@ func (s *Action) GetCommands() []*cli.Command { Before: s.IsInitialized, Action: s.Process, }, + { + Name: "rcs", + Usage: "Run a RCS command inside a password store", + ArgsUsage: "[init|push|pull]", + Description: "" + + "If the password store is a git repository, execute a git command " + + "specified by git-command-args.", + Hidden: true, + Subcommands: []*cli.Command{ + { + Name: "init", + Usage: "Init RCS repo", + Description: "Create and initialize a new RCS repo in the store", + Before: s.IsInitialized, + Action: s.RCSInit, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "store", + Usage: "Store to operate on", + }, + &cli.StringFlag{ + Name: "sign-key", + Usage: "GPG Key to sign commits", + }, + &cli.StringFlag{ + Name: "name", + Aliases: []string{"username"}, + Usage: "Git Author Name", + }, + &cli.StringFlag{ + Name: "email", + Aliases: []string{"useremail"}, + Usage: "Git Author Email", + }, + &cli.StringFlag{ + Name: "storage", + Usage: fmt.Sprintf("Select storage backend %v", set.Filter(backend.StorageRegistry.Backends(), "fs")), + Value: "gitfs", + }, + }, + }, + { + Name: "status", + Usage: "RCS status", + Description: "Show the RCS status", + Before: s.IsInitialized, + Action: s.RCSStatus, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "store", + Usage: "Store to operate on", + }, + }, + }, + }, + }, { Name: "recipients", Usage: "Edit recipient permissions", diff --git a/internal/action/git.go b/internal/action/git.go new file mode 100644 index 0000000000..e2a22404c4 --- /dev/null +++ b/internal/action/git.go @@ -0,0 +1,32 @@ +package action + +import ( + "os" + "os/exec" + "strings" + + "github.com/gopasspw/gopass/internal/out" + "github.com/gopasspw/gopass/pkg/ctxutil" + "github.com/urfave/cli/v2" +) + +// Git passes the git command to the underlying backend. +func (s *Action) Git(c *cli.Context) error { + ctx := ctxutil.WithGlobalFlags(c) + store := c.String("store") + + sub, err := s.Store.GetSubStore(store) + if err != nil || sub == nil { + return ExitError(ExitGit, err, "failed to get sub store %s: %s", store, err) + } + + args := c.Args().Slice() + out.Noticef(ctx, "Running 'git %s' in %s...", strings.Join(args, " "), sub.Path()) + cmd := exec.CommandContext(ctx, "git", args...) + cmd.Dir = sub.Path() + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + + return cmd.Run() +} diff --git a/internal/store/root/rcs.go b/internal/store/root/rcs.go index 5e12f267c1..41f42669c4 100644 --- a/internal/store/root/rcs.go +++ b/internal/store/root/rcs.go @@ -61,6 +61,7 @@ func (r *Store) GetRevision(ctx context.Context, name, revision string) (context } // RCSStatus show the git status. +// TODO this should likely iterate over all stores func (r *Store) RCSStatus(ctx context.Context, name string) error { store, name := r.getStore(name) out.Printf(ctx, "Store: %s", store.Path()) diff --git a/main_test.go b/main_test.go index 9aea85a305..59591d53c1 100644 --- a/main_test.go +++ b/main_test.go @@ -68,6 +68,7 @@ var commandsWithError = set.Map([]string{ ".fscopy", ".fsmove", ".generate", + ".git", ".git.push", ".git.pull", ".git.status", @@ -84,6 +85,7 @@ var commandsWithError = set.Map([]string{ ".move", ".otp", ".process", + ".rcs.status", ".recipients.add", ".recipients.remove", ".show", @@ -126,7 +128,7 @@ func TestGetCommands(t *testing.T) { c.Context = ctx commands := getCommands(act, app) - assert.Equal(t, 39, len(commands)) + assert.Equal(t, 40, len(commands)) prefix := "" testCommands(t, c, commands, prefix)