mirror of https://github.com/databricks/cli.git
This commit is contained in:
parent
cf04ef8550
commit
7529c8a4ca
|
@ -18,11 +18,8 @@ type LocalClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLocalClient(root string) (Filer, error) {
|
func NewLocalClient(root string) (Filer, error) {
|
||||||
if runtime.GOOS == "windows" && root == "/" {
|
if runtime.GOOS == "windows" {
|
||||||
// Windows file systems do not have a "root" directory. Instead paths require
|
return &LocalClient{root: WindowsRootPath{root}}, nil
|
||||||
// a Volume/Drive letter specified. This allows us to refer to files across
|
|
||||||
// different drives from a single client
|
|
||||||
return &LocalClient{root: NopRootPath{}}, nil
|
|
||||||
}
|
}
|
||||||
return &LocalClient{
|
return &LocalClient{
|
||||||
root: NewUnixRootPath(root),
|
root: NewUnixRootPath(root),
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
package filer
|
package filer
|
||||||
|
|
||||||
|
// RootPath can be joined with a relative path and ensures that
|
||||||
|
// the returned path is always a strict child of the root path.
|
||||||
type RootPath interface {
|
type RootPath interface {
|
||||||
|
// Join returns the specified path name joined to the root.
|
||||||
|
// It returns an error if the resulting path is not a strict child of the root path.
|
||||||
Join(string) (string, error)
|
Join(string) (string, error)
|
||||||
|
|
||||||
Root() string
|
Root() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnixRootPath can be joined with a relative path and ensures that
|
|
||||||
// the returned path is always a strict child of the root path.
|
|
||||||
type UnixRootPath struct {
|
type UnixRootPath struct {
|
||||||
rootPath string
|
rootPath string
|
||||||
}
|
}
|
||||||
|
@ -20,8 +18,6 @@ func NewUnixRootPath(name string) UnixRootPath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join returns the specified path name joined to the root.
|
|
||||||
// It returns an error if the resulting path is not a strict child of the root path.
|
|
||||||
func (p UnixRootPath) Join(name string) (string, error) {
|
func (p UnixRootPath) Join(name string) (string, error) {
|
||||||
absPath := path.Join(p.rootPath, name)
|
absPath := path.Join(p.rootPath, name)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package filer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WindowsRootPath struct {
|
||||||
|
rootPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWindowsRootPath(name string) WindowsRootPath {
|
||||||
|
// Windows file systems do not have a "root" directory. Instead paths require
|
||||||
|
// a Volume/Drive letter specified. If a user of this struct specifies "/" then
|
||||||
|
// we treat it as the "root" and skip any validation
|
||||||
|
if name == "/" {
|
||||||
|
return WindowsRootPath{""}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WindowsRootPath{filepath.Clean(name)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join returns the specified path name joined to the root.
|
||||||
|
// It returns an error if the resulting path is not a strict child of the root path.
|
||||||
|
func (p WindowsRootPath) Join(name string) (string, error) {
|
||||||
|
absPath := filepath.Join(p.rootPath, name)
|
||||||
|
|
||||||
|
// Don't allow escaping the specified root using relative paths.
|
||||||
|
if !strings.HasPrefix(absPath, p.rootPath) {
|
||||||
|
return "", fmt.Errorf("relative path escapes root: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return absPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p WindowsRootPath) Root() string {
|
||||||
|
return p.rootPath
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package filer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWindowsRootPathForRoot(t *testing.T) {
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
t.Skip("this test is meant for windows")
|
||||||
|
}
|
||||||
|
|
||||||
|
rp := NewWindowsRootPath("/")
|
||||||
|
|
||||||
|
// Assert root value returned
|
||||||
|
assert.Equal(t, "", rp.Root())
|
||||||
|
|
||||||
|
// case: absolute windows path
|
||||||
|
path, err := rp.Join(`c:\a\b`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, `c:\a\b`, path)
|
||||||
|
|
||||||
|
// case: absolute windows path following file URI scheme
|
||||||
|
path, err = rp.Join(`D:/a/b`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, `D:/a/b`, path)
|
||||||
|
|
||||||
|
// case: relative windows paths
|
||||||
|
path, err = rp.Join(`c:a\b`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, `c:a\b`, path)
|
||||||
|
|
||||||
|
path, err = rp.Join(`c:a`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, `c:a`, path)
|
||||||
|
|
||||||
|
// case: relative windows paths following file URI scheme
|
||||||
|
path, err = rp.Join(`c:a/b`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, `C:a/b`, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWindowsRootPath(t *testing.T) {
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
t.Skip("this test is meant for windows")
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
rp := NewWindowsRootPath(t.TempDir())
|
||||||
|
|
||||||
|
// Assert root value returned
|
||||||
|
assert.Equal(t, tmpDir, rp.Root())
|
||||||
|
|
||||||
|
path, err := rp.Join(`a\b\c`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tmpDir+`\a\b`, path)
|
||||||
|
|
||||||
|
path, err = rp.Join("a/b")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tmpDir + `\a/b`, path)
|
||||||
|
}
|
Loading…
Reference in New Issue