Skip to content

Commit 9f52194

Browse files
committed
Use common Windows Subsystem path helper for calling tools on Windows
Signed-off-by: Arthur Sengileyev <[email protected]>
1 parent bfac818 commit 9f52194

File tree

6 files changed

+77
-20
lines changed

6 files changed

+77
-20
lines changed

Diff for: cmd/limactl/copy.go

+13
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import (
88
"fmt"
99
"os"
1010
"os/exec"
11+
"path/filepath"
12+
"runtime"
1113
"strings"
1214

1315
"github.com/coreos/go-semver/semver"
16+
"github.com/lima-vm/lima/pkg/ioutilx"
1417
"github.com/lima-vm/lima/pkg/sshutil"
1518
"github.com/lima-vm/lima/pkg/store"
1619
"github.com/sirupsen/logrus"
@@ -80,6 +83,16 @@ func copyAction(cmd *cobra.Command, args []string) error {
8083
// this assumes that ssh and scp come from the same place, but scp has no -V
8184
legacySSH := sshutil.DetectOpenSSHVersion("ssh").LessThan(*semver.New("8.0.0"))
8285
for _, arg := range args {
86+
if runtime.GOOS == "windows" {
87+
if filepath.IsAbs(arg) {
88+
arg, err = ioutilx.WindowsSubsystemPath(arg)
89+
if err != nil {
90+
return err
91+
}
92+
} else {
93+
arg = filepath.ToSlash(arg)
94+
}
95+
}
8396
path := strings.Split(arg, ":")
8497
switch len(path) {
8598
case 1:

Diff for: cmd/limactl/shell.go

+17
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ import (
88
"fmt"
99
"os"
1010
"os/exec"
11+
"path"
12+
"runtime"
1113
"strconv"
1214
"strings"
1315

1416
"al.essio.dev/pkg/shellescape"
1517
"github.com/coreos/go-semver/semver"
18+
"github.com/lima-vm/lima/pkg/ioutilx"
1619
"github.com/lima-vm/lima/pkg/sshutil"
1720
"github.com/lima-vm/lima/pkg/store"
1821
"github.com/mattn/go-isatty"
@@ -92,13 +95,19 @@ func shellAction(cmd *cobra.Command, args []string) error {
9295
// FIXME: check whether y.Mounts contains the home, not just len > 0
9396
} else if len(inst.Config.Mounts) > 0 {
9497
hostCurrentDir, err := os.Getwd()
98+
if err == nil && runtime.GOOS == "windows" {
99+
hostCurrentDir, err = mountDirFromWindowsDir(hostCurrentDir)
100+
}
95101
if err == nil {
96102
changeDirCmd = fmt.Sprintf("cd %s", shellescape.Quote(hostCurrentDir))
97103
} else {
98104
changeDirCmd = "false"
99105
logrus.WithError(err).Warn("failed to get the current directory")
100106
}
101107
hostHomeDir, err := os.UserHomeDir()
108+
if err == nil && runtime.GOOS == "windows" {
109+
hostHomeDir, err = mountDirFromWindowsDir(hostHomeDir)
110+
}
102111
if err == nil {
103112
changeDirCmd = fmt.Sprintf("%s || cd %s", changeDirCmd, shellescape.Quote(hostHomeDir))
104113
} else {
@@ -189,6 +198,14 @@ func shellAction(cmd *cobra.Command, args []string) error {
189198
return sshCmd.Run()
190199
}
191200

201+
func mountDirFromWindowsDir(dir string) (string, error) {
202+
dir, err := ioutilx.WindowsSubsystemPath(dir)
203+
if err == nil && !strings.HasPrefix(dir, "/mnt/") {
204+
dir = path.Join("/mnt", dir)
205+
}
206+
return dir, err
207+
}
208+
192209
func shellBashComplete(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
193210
return bashCompleteInstanceNames(cmd)
194211
}

Diff for: hack/test-templates.sh

+5-2
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,11 @@ tmpdir="$(mktemp -d "${TMPDIR:-/tmp}"/lima-test-templates.XXXXXX)"
229229
defer "rm -rf \"$tmpdir\""
230230
tmpfile="$tmpdir/lima-hostname"
231231
rm -f "$tmpfile"
232-
# TODO support Windows path https://github.com/lima-vm/lima/issues/3215
233-
limactl cp "$NAME":/etc/hostname "$tmpfile"
232+
tmpfile_host=$tmpfile
233+
if [ "${OS_HOST}" = "Msys" ]; then
234+
tmpfile_host="$(cygpath -w "$tmpfile")"
235+
fi
236+
limactl cp "$NAME":/etc/hostname "$tmpfile_host"
234237
expected="$(limactl shell "$NAME" cat /etc/hostname)"
235238
got="$(cat "$tmpfile")"
236239
INFO "/etc/hostname: expected=${expected}, got=${got}"

Diff for: pkg/ioutilx/ioutilx.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"io"
1010
"os/exec"
11+
"path/filepath"
1112
"strings"
1213

1314
"github.com/sirupsen/logrus"
@@ -48,13 +49,11 @@ func FromUTF16leToString(r io.Reader) (string, error) {
4849
return string(out), nil
4950
}
5051

51-
func CanonicalWindowsPath(orig string) string {
52-
newPath := orig
53-
out, err := exec.Command("cygpath", "-m", orig).CombinedOutput()
52+
func WindowsSubsystemPath(orig string) (string, error) {
53+
out, err := exec.Command("cygpath", filepath.ToSlash(orig)).CombinedOutput()
5454
if err != nil {
5555
logrus.WithError(err).Errorf("failed to convert path to mingw, maybe not using Git ssh?")
56-
} else {
57-
newPath = strings.TrimSpace(string(out))
56+
return orig, err
5857
}
59-
return newPath
58+
return strings.TrimSpace(string(out)), nil
6059
}

Diff for: pkg/osutil/user.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"strings"
1515
"sync"
1616

17+
"github.com/lima-vm/lima/pkg/ioutilx"
1718
. "github.com/lima-vm/lima/pkg/must"
1819
"github.com/lima-vm/lima/pkg/version/versionutil"
1920
"github.com/sirupsen/logrus"
@@ -144,7 +145,7 @@ func LimaUser(limaVersion string, warn bool) *user.User {
144145
warnings = append(warnings, warning)
145146
limaUser.Gid = formatUidGid(gid)
146147
}
147-
home, err := call([]string{"cygpath", limaUser.HomeDir})
148+
home, err := ioutilx.WindowsSubsystemPath(limaUser.HomeDir)
148149
if err != nil {
149150
logrus.Debug(err)
150151
} else {
@@ -159,6 +160,10 @@ func LimaUser(limaVersion string, warn bool) *user.User {
159160
home += ".linux"
160161
}
161162
if !regexPath.MatchString(limaUser.HomeDir) {
163+
// Trim prefix of well known default mounts
164+
if strings.HasPrefix(home, "/mnt/") {
165+
home = strings.TrimPrefix(home, "/mnt")
166+
}
162167
warning := fmt.Sprintf("local home %q is not a valid Linux path (must match %q); using %q home instead",
163168
limaUser.HomeDir, regexPath.String(), home)
164169
warnings = append(warnings, warning)

Diff for: pkg/sshutil/sshutil.go

+31-11
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,15 @@ func DefaultPubKeys(loadDotSSH bool) ([]PubKey, error) {
9898
}
9999
if err := lockutil.WithDirLock(configDir, func() error {
100100
// no passphrase, no user@host comment
101+
privPath := filepath.Join(configDir, filenames.UserPrivateKey)
102+
if runtime.GOOS == "windows" {
103+
privPath, err = ioutilx.WindowsSubsystemPath(privPath)
104+
if err != nil {
105+
return err
106+
}
107+
}
101108
keygenCmd := exec.Command("ssh-keygen", "-t", "ed25519", "-q", "-N", "",
102-
"-C", "lima", "-f", filepath.Join(configDir, filenames.UserPrivateKey))
109+
"-C", "lima", "-f", privPath)
103110
logrus.Debugf("executing %v", keygenCmd.Args)
104111
if out, err := keygenCmd.CombinedOutput(); err != nil {
105112
return fmt.Errorf("failed to run %v: %q: %w", keygenCmd.Args, string(out), err)
@@ -171,12 +178,11 @@ func CommonOpts(sshPath string, useDotSSH bool) ([]string, error) {
171178
return nil, err
172179
}
173180
var opts []string
174-
if runtime.GOOS == "windows" {
175-
privateKeyPath = ioutilx.CanonicalWindowsPath(privateKeyPath)
176-
opts = []string{fmt.Sprintf(`IdentityFile='%s'`, privateKeyPath)}
177-
} else {
178-
opts = []string{fmt.Sprintf(`IdentityFile="%s"`, privateKeyPath)}
181+
idf, err := identityFileEntry(privateKeyPath)
182+
if err != nil {
183+
return nil, err
179184
}
185+
opts = []string{idf}
180186

181187
// Append all private keys corresponding to ~/.ssh/*.pub to keep old instances working
182188
// that had been created before lima started using an internal identity.
@@ -207,11 +213,11 @@ func CommonOpts(sshPath string, useDotSSH bool) ([]string, error) {
207213
// Fail on permission-related and other path errors
208214
return nil, err
209215
}
210-
if runtime.GOOS == "windows" {
211-
opts = append(opts, fmt.Sprintf(`IdentityFile='%s'`, privateKeyPath))
212-
} else {
213-
opts = append(opts, fmt.Sprintf(`IdentityFile="%s"`, privateKeyPath))
216+
idf, err = identityFileEntry(privateKeyPath)
217+
if err != nil {
218+
return nil, err
214219
}
220+
opts = append(opts, idf)
215221
}
216222
}
217223

@@ -256,6 +262,17 @@ func CommonOpts(sshPath string, useDotSSH bool) ([]string, error) {
256262
return opts, nil
257263
}
258264

265+
func identityFileEntry(privateKeyPath string) (string, error) {
266+
if runtime.GOOS == "windows" {
267+
privateKeyPath, err := ioutilx.WindowsSubsystemPath(privateKeyPath)
268+
if err != nil {
269+
return "", err
270+
}
271+
return fmt.Sprintf(`IdentityFile='%s'`, privateKeyPath), nil
272+
}
273+
return fmt.Sprintf(`IdentityFile="%s"`, privateKeyPath), nil
274+
}
275+
259276
// SSHOpts adds the following options to CommonOptions: User, ControlMaster, ControlPath, ControlPersist.
260277
func SSHOpts(sshPath, instDir, username string, useDotSSH, forwardAgent, forwardX11, forwardX11Trusted bool) ([]string, error) {
261278
controlSock := filepath.Join(instDir, filenames.SSHSock)
@@ -268,7 +285,10 @@ func SSHOpts(sshPath, instDir, username string, useDotSSH, forwardAgent, forward
268285
}
269286
controlPath := fmt.Sprintf(`ControlPath="%s"`, controlSock)
270287
if runtime.GOOS == "windows" {
271-
controlSock = ioutilx.CanonicalWindowsPath(controlSock)
288+
controlSock, err = ioutilx.WindowsSubsystemPath(controlSock)
289+
if err != nil {
290+
return nil, err
291+
}
272292
controlPath = fmt.Sprintf(`ControlPath='%s'`, controlSock)
273293
}
274294
opts = append(opts,

0 commit comments

Comments
 (0)