Skip to content

Commit 69443ce

Browse files
committed
windows multi-drive, add absolutepath
1 parent 163a149 commit 69443ce

File tree

3 files changed

+80
-25
lines changed

3 files changed

+80
-25
lines changed

agent/ls.go

+48-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66
"os"
77
"path/filepath"
88
"runtime"
9+
"strings"
910

11+
"github.com/shirou/gopsutil/v3/disk"
1012
"golang.org/x/xerrors"
1113

1214
"github.com/coder/coder/v2/coderd/httpapi"
@@ -26,11 +28,11 @@ func (*agent) HandleLS(rw http.ResponseWriter, r *http.Request) {
2628
switch {
2729
case errors.Is(err, os.ErrNotExist):
2830
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
29-
Message: "Directory does not exist",
31+
Message: err.Error(),
3032
})
3133
case errors.Is(err, os.ErrPermission):
3234
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
33-
Message: "Permission denied",
35+
Message: err.Error(),
3436
})
3537
default:
3638
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
@@ -44,28 +46,27 @@ func (*agent) HandleLS(rw http.ResponseWriter, r *http.Request) {
4446
}
4547

4648
func listFiles(query LSQuery) (LSResponse, error) {
47-
var base string
49+
var fullPath []string
4850
switch query.Relativity {
4951
case LSRelativityHome:
5052
home, err := os.UserHomeDir()
5153
if err != nil {
5254
return LSResponse{}, xerrors.Errorf("failed to get user home directory: %w", err)
5355
}
54-
base = home
56+
fullPath = []string{home}
5557
case LSRelativityRoot:
5658
if runtime.GOOS == "windows" {
57-
// TODO: Eventually, we could have a empty path with a root base
58-
// return all drives.
59-
// C drive should be good enough for now.
60-
base = "C:\\"
59+
if len(query.Path) == 0 {
60+
return listDrives()
61+
}
6162
} else {
62-
base = "/"
63+
fullPath = []string{"/"}
6364
}
6465
default:
6566
return LSResponse{}, xerrors.Errorf("unsupported relativity type %q", query.Relativity)
6667
}
6768

68-
fullPath := append([]string{base}, query.Path...)
69+
fullPath = append(fullPath, query.Path...)
6970
absolutePathString, err := filepath.Abs(filepath.Join(fullPath...))
7071
if err != nil {
7172
return LSResponse{}, xerrors.Errorf("failed to get absolute path: %w", err)
@@ -97,12 +98,48 @@ func listFiles(query LSQuery) (LSResponse, error) {
9798
})
9899
}
99100

101+
absolutePath := pathToArray(absolutePathString)
102+
100103
return LSResponse{
104+
AbsolutePath: absolutePath,
101105
AbsolutePathString: absolutePathString,
102106
Contents: respContents,
103107
}, nil
104108
}
105109

110+
func listDrives() (LSResponse, error) {
111+
aa, err := disk.Partitions(true)
112+
if err != nil {
113+
return LSResponse{}, xerrors.Errorf("failed to get partitions: %w", err)
114+
}
115+
contents := make([]LSFile, 0, len(aa))
116+
for _, a := range aa {
117+
name := a.Mountpoint + string(os.PathSeparator)
118+
contents = append(contents, LSFile{
119+
Name: name,
120+
AbsolutePathString: name,
121+
IsDir: true,
122+
})
123+
}
124+
125+
return LSResponse{
126+
AbsolutePath: []string{},
127+
AbsolutePathString: "",
128+
Contents: contents,
129+
}, nil
130+
}
131+
132+
func pathToArray(path string) []string {
133+
out := strings.FieldsFunc(path, func(r rune) bool {
134+
return r == os.PathSeparator
135+
})
136+
// Drive letters on Windows should have a trailing separator.
137+
if runtime.GOOS == "windows" && len(out) > 0 {
138+
out[0] += string(os.PathSeparator)
139+
}
140+
return out
141+
}
142+
106143
type LSQuery struct {
107144
// e.g. [], ["repos", "coder"],
108145
Path []string `json:"path"`
@@ -112,6 +149,7 @@ type LSQuery struct {
112149
}
113150

114151
type LSResponse struct {
152+
AbsolutePath []string `json:"absolute_path"`
115153
// Returned so clients can display the full path to the user, and
116154
// copy it to configure file sync
117155
// e.g. Windows: "C:\\Users\\coder"

agent/ls_internal_test.go

+31-14
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"os"
55
"path/filepath"
66
"runtime"
7-
"strings"
87
"testing"
98

109
"github.com/stretchr/testify/require"
@@ -90,9 +89,9 @@ func TestListFilesSuccess(t *testing.T) {
9089
},
9190
{
9291
name: "root",
93-
baseFunc: func(t *testing.T) string {
92+
baseFunc: func(*testing.T) string {
9493
if runtime.GOOS == "windows" {
95-
return "C:\\"
94+
return ""
9695
}
9796
return "/"
9897
},
@@ -116,12 +115,18 @@ func TestListFilesSuccess(t *testing.T) {
116115
err = os.Mkdir(downloadsDir, 0o755)
117116
require.NoError(t, err)
118117

119-
rel, err := filepath.Rel(base, tmpDir)
120-
require.NoError(t, err)
121-
relComponents := pathToArray(rel)
118+
var queryComponents []string
119+
// We can't get an absolute path relative to empty string on Windows.
120+
if runtime.GOOS == "windows" && base == "" {
121+
queryComponents = pathToArray(tmpDir)
122+
} else {
123+
rel, err := filepath.Rel(base, tmpDir)
124+
require.NoError(t, err)
125+
queryComponents = pathToArray(rel)
126+
}
122127

123128
query := LSQuery{
124-
Path: relComponents,
129+
Path: queryComponents,
125130
Relativity: tc.relativity,
126131
}
127132
resp, err := listFiles(query)
@@ -149,7 +154,7 @@ func TestListFilesSuccess(t *testing.T) {
149154
}
150155
}
151156

152-
func TestListFilesWindowsRoot(t *testing.T) {
157+
func TestListFilesListDrives(t *testing.T) {
153158
t.Parallel()
154159

155160
if runtime.GOOS != "windows" {
@@ -162,11 +167,23 @@ func TestListFilesWindowsRoot(t *testing.T) {
162167
}
163168
resp, err := listFiles(query)
164169
require.NoError(t, err)
165-
require.Equal(t, "C:\\", resp.AbsolutePathString)
166-
}
167-
168-
func pathToArray(path string) []string {
169-
return strings.FieldsFunc(path, func(r rune) bool {
170-
return r == os.PathSeparator
170+
require.Contains(t, resp.Contents, LSFile{
171+
Name: "C:\\",
172+
AbsolutePathString: "C:\\",
173+
IsDir: true,
171174
})
175+
176+
query = LSQuery{
177+
Path: []string{"C:\\"},
178+
Relativity: LSRelativityRoot,
179+
}
180+
resp, err = listFiles(query)
181+
require.NoError(t, err)
182+
183+
query = LSQuery{
184+
Path: resp.AbsolutePath,
185+
Relativity: LSRelativityRoot,
186+
}
187+
resp, err = listFiles(query)
188+
require.NoError(t, err)
172189
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ require (
401401
github.com/ryanuber/go-glob v1.0.0 // indirect
402402
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
403403
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
404-
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
404+
github.com/shirou/gopsutil/v3 v3.24.4
405405
github.com/shoenig/go-m1cpu v0.1.6 // indirect
406406
github.com/sirupsen/logrus v1.9.3 // indirect
407407
github.com/spaolacci/murmur3 v1.1.0 // indirect

0 commit comments

Comments
 (0)