Skip to content

Commit 08216d6

Browse files
authored
Merge pull request #15519 from msharran/issue/15338
`minikube cp` now supports providing directory as a target
2 parents a4a1ba5 + 955d386 commit 08216d6

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

cmd/minikube/cmd/cp.go

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717
package cmd
1818

1919
import (
20+
"path/filepath"
21+
2022
"github.com/pkg/errors"
2123
"github.com/spf13/cobra"
2224

@@ -56,8 +58,10 @@ Example Command : "minikube cp a.txt /home/docker/b.txt" +
5658
minikube cp <source file path> <target file absolute path> (example: "minikube cp a/b.txt /copied.txt")`)
5759
}
5860

59-
src := newRemotePath(args[0])
60-
dst := newRemotePath(args[1])
61+
srcPath := args[0]
62+
dstPath := setDstFileNameFromSrc(args[1], srcPath)
63+
src := newRemotePath(srcPath)
64+
dst := newRemotePath(dstPath)
6165
validateArgs(src, dst)
6266

6367
co := mustload.Running(ClusterFlagValue())
@@ -83,6 +87,54 @@ Example Command : "minikube cp a.txt /home/docker/b.txt" +
8387
func init() {
8488
}
8589

90+
// setDstFileNameFromSrc sets the src filename as dst filename
91+
// when the dst file name is not provided and ends with a `/`.
92+
// Otherwise this function is a no-op and returns the passed dst.
93+
func setDstFileNameFromSrc(dst, src string) string {
94+
srcPath := newRemotePath(src)
95+
dstPath := newRemotePath(dst)
96+
guestToHost := srcPath.node != "" && dstPath.node == ""
97+
guestToGuest := srcPath.node != "" && dstPath.node != ""
98+
99+
// Since Host can be any OS and Guest can only be linux, use
100+
// filepath and path respectively
101+
var dd, df, sf string
102+
switch {
103+
case guestToHost:
104+
_, sf = pt.Split(src)
105+
dd, df = filepath.Split(dst)
106+
case guestToGuest:
107+
_, sf = pt.Split(src)
108+
dd, df = pt.Split(dst)
109+
default:
110+
_, sf = filepath.Split(src)
111+
dd, df = pt.Split(dst)
112+
}
113+
114+
// if dst is empty, dd and df will be empty, so return dst
115+
// validation will be happening in `validateArgs`
116+
if dd == "" && df == "" {
117+
return ""
118+
}
119+
120+
// if filename is already provided, return dst
121+
if df != "" {
122+
return dst
123+
}
124+
125+
// if src filename is empty, return dst
126+
if sf == "" {
127+
return dst
128+
}
129+
130+
// https://github.com/kubernetes/minikube/pull/15519/files#r1261750910
131+
if guestToHost {
132+
return filepath.Join(dd, sf)
133+
}
134+
135+
return pt.Join(dd, sf)
136+
}
137+
86138
// split path to node name and file path
87139
func newRemotePath(path string) *remotePath {
88140
// if destination path is not a absolute path, trying to parse with <node>:<abs path> format

cmd/minikube/cmd/cp_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,26 @@ func TestParsePath(t *testing.T) {
6060
}
6161
}
6262
}
63+
64+
func TestSetDstFileNameFromSrc(t *testing.T) {
65+
cases := []struct {
66+
src string
67+
dst string
68+
want string
69+
}{
70+
{"./a/b", "/c/", "/c/b"},
71+
{"./a/b", "node:/c/", "node:/c/b"},
72+
{"./a", "/c/", "/c/a"},
73+
{"", "/c/", "/c/"},
74+
{"./a/b", "", ""},
75+
{"./a/b", "/c", "/c"},
76+
{"./a/", "/c/", "/c/"},
77+
}
78+
79+
for _, c := range cases {
80+
got := setDstFileNameFromSrc(c.dst, c.src)
81+
if c.want != got {
82+
t.Fatalf("wrong dst path for src=%s & dst=%s. want: %q, got: %q", c.src, c.dst, c.want, got)
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)