Skip to content

Commit

Permalink
[bugfix] Copy with trailing slash at destination. (#2966)
Browse files Browse the repository at this point in the history
* [bugfix] Copy with trailing slash at destination.

Signed-off-by: Vijay Kesanakurthi <[email protected]>

* Copy with trailing slash at destination fix and test.

Signed-off-by: Vijay Kesanakurthi <[email protected]>

---------

Signed-off-by: Vijay Kesanakurthi <[email protected]>
  • Loading branch information
vijay-kesanakurthi authored Oct 11, 2024
1 parent 3c87c1b commit a5be685
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 0 deletions.
40 changes: 40 additions & 0 deletions internal/action/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package action
import (
"context"
"fmt"
"github.com/gopasspw/gopass/internal/tree"
"path/filepath"
"strings"

"github.com/gopasspw/gopass/internal/action/exit"
"github.com/gopasspw/gopass/pkg/ctxutil"
Expand Down Expand Up @@ -30,6 +33,43 @@ func (s *Action) copy(ctx context.Context, from, to string, force bool) error {
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 {

Check failure on line 71 in internal/action/copy.go

View workflow job for this annotation

GitHub Actions / lint

unnecessary leading newline (whitespace)

Check failure on line 71 in internal/action/copy.go

View workflow job for this annotation

GitHub Actions / linux

unnecessary leading newline (whitespace)

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")
Expand Down
92 changes: 92 additions & 0 deletions internal/action/copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,95 @@ func TestCopyGpg(t *testing.T) {
assert.Equal(t, "barfoo", buf.String())
buf.Reset()
}

func TestCopyWithTrailingSlash(t *testing.T) {
u := gptest.NewUnitTester(t)

ctx := config.NewContextInMemory()
ctx = ctxutil.WithInteractive(ctx, false)
ctx = ctxutil.WithAlwaysYes(ctx, true)

act, err := newMock(ctx, u.StoreDir(""))
require.NoError(t, err)
require.NotNil(t, act)
ctx = act.cfg.WithConfig(ctx)

require.NoError(t, act.cfg.Set("", "generate.autoclip", "false"))

buf := &bytes.Buffer{}
out.Stdout = buf
stdout = buf
defer func() {
stdout = os.Stdout
out.Stdout = os.Stdout
}()

color.NoColor = true

// generate foo
c := gptest.CliCtx(ctx, t, "foo")
require.NoError(t, act.Generate(c))
buf.Reset()

// copy foo bar
c = gptest.CliCtx(ctx, t, "foo", "bar")
require.NoError(t, act.Copy(c))
buf.Reset()

// copy foo bar (again, should fail)
{
ctx := ctxutil.WithAlwaysYes(ctx, false)
ctx = ctxutil.WithInteractive(ctx, false)
c.Context = ctx
require.Error(t, act.Copy(c))
buf.Reset()
}

// copy not-found still-not-there
c = gptest.CliCtx(ctx, t, "not-found", "still-not-there")
require.Error(t, act.Copy(c))
buf.Reset()

// copy
c = gptest.CliCtx(ctx, t)
require.Error(t, act.Copy(c))
buf.Reset()

// Create a directory structure
require.NoError(t, act.insertStdin(ctx, "secret/some/zab", []byte("secret"), false))
require.NoError(t, act.insertStdin(ctx, "secret/baz", []byte("another"), false))

// Test copying a directory with trailing slash
c = gptest.CliCtx(ctx, t, "secret/", "new/")
require.NoError(t, act.Copy(c))
buf.Reset()

// Verify the result
require.NoError(t, act.List(gptest.CliCtx(ctx, t)))
want := `gopass
├── bar
├── foo
├── new/
│ ├── baz
│ └── zab
└── secret/
├── baz
└── some/
└── zab
`

assert.Equal(t, want, buf.String())
buf.Reset()

// Verify content of copied files
ctx = ctxutil.WithTerminal(ctx, false)
require.NoError(t, act.show(ctx, c, "new/zab", false))
assert.Equal(t, "secret\n", buf.String())
buf.Reset()

require.NoError(t, act.show(ctx, c, "new/baz", false))
assert.Equal(t, "another\n", buf.String())
buf.Reset()

}

Check failure on line 274 in internal/action/copy_test.go

View workflow job for this annotation

GitHub Actions / lint

unnecessary trailing newline (whitespace)

Check failure on line 274 in internal/action/copy_test.go

View workflow job for this annotation

GitHub Actions / linux

unnecessary trailing newline (whitespace)

0 comments on commit a5be685

Please sign in to comment.