mirror of
https://github.com/gopasspw/gopass.git
synced 2025-12-08 19:24:54 +00:00
* feat: Allow to customize commit messages This change introduces the ability for users to customize the commit message when performing actions that modify the secret store. It adds two new flags to the `edit`, `insert`, `generate`, `copy`, `move`, and `delete` commands: - `--commit-message` (`-m`): to specify the commit message directly. - `--interactive-commit` (`-i`): to open an editor for the commit message. The default behavior of using a pre-defined commit message is preserved. * fix: Use correct commit message from context This change fixes a bug where the commit message from the context was not being used correctly in the `delete` function. --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
package action
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gopasspw/gopass/internal/action/exit"
|
|
"github.com/gopasspw/gopass/internal/tree"
|
|
"github.com/gopasspw/gopass/pkg/ctxutil"
|
|
"github.com/gopasspw/gopass/pkg/termio"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
// Copy the contents of a file to another one.
|
|
func (s *Action) Copy(c *cli.Context) error {
|
|
ctx := ctxutil.WithGlobalFlags(c)
|
|
force := c.Bool("force")
|
|
|
|
if c.Args().Len() != 2 {
|
|
return exit.Error(exit.Usage, nil, "Usage: %s cp <FROM> <TO>", s.Name)
|
|
}
|
|
|
|
from := c.Args().Get(0)
|
|
to := c.Args().Get(1)
|
|
|
|
// Check for custom commit message
|
|
commitMsg := fmt.Sprintf("Copied %s to %s", from, to)
|
|
if c.IsSet("commit-message") {
|
|
commitMsg = c.String("commit-message")
|
|
}
|
|
if c.Bool("interactive-commit") {
|
|
commitMsg = ""
|
|
}
|
|
ctx = ctxutil.WithCommitMessage(ctx, commitMsg)
|
|
|
|
return s.copy(ctx, from, to, force)
|
|
}
|
|
|
|
func (s *Action) copy(ctx context.Context, from, to string, force bool) error {
|
|
if !s.Store.Exists(ctx, from) && !s.Store.IsDir(ctx, from) {
|
|
return exit.Error(exit.NotFound, nil, "%s does not exist", from)
|
|
}
|
|
|
|
isSourceDir := s.Store.IsDir(ctx, from)
|
|
hasTrailingSlash := strings.HasSuffix(to, "/")
|
|
|
|
if isSourceDir && hasTrailingSlash {
|
|
return s.copyFlattenDir(ctx, from, to, force)
|
|
}
|
|
|
|
return s.copyRegular(ctx, from, to, force)
|
|
}
|
|
|
|
func (s *Action) copyFlattenDir(ctx context.Context, from, to string, force bool) error {
|
|
entries, err := s.Store.List(ctx, tree.INF)
|
|
if err != nil {
|
|
return exit.Error(exit.List, err, "failed to list entries in %q", from)
|
|
}
|
|
|
|
fromPrefix := from
|
|
if !strings.HasSuffix(fromPrefix, "/") {
|
|
fromPrefix += "/"
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if strings.HasPrefix(entry, fromPrefix) {
|
|
toPath := filepath.Join(to, filepath.Base(entry))
|
|
|
|
if err := s.copyRegular(ctx, entry, toPath, force); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Action) copyRegular(ctx context.Context, from, to string, force bool) error {
|
|
if !force {
|
|
if s.Store.Exists(ctx, to) && !termio.AskForConfirmation(ctx, fmt.Sprintf("%s already exists. Overwrite it?", to)) {
|
|
return exit.Error(exit.Aborted, nil, "not overwriting your current secret")
|
|
}
|
|
}
|
|
|
|
if err := s.Store.Copy(ctx, from, to); err != nil {
|
|
return exit.Error(exit.IO, err, "failed to copy from %q to %q", from, to)
|
|
}
|
|
|
|
return nil
|
|
}
|