Support recursive directory uploads
All checks were successful
Build / Test and build (push) Successful in 5m41s
All checks were successful
Build / Test and build (push) Successful in 5m41s
This commit is contained in:
@@ -9,6 +9,8 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -203,6 +205,55 @@ func TestUploadMultipartFlow(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMkdirAllCreatesMissingRemoteDirectories(t *testing.T) {
|
||||
directories := map[string]bool{"/apps/bdrclone": true}
|
||||
var created []string
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/rest/2.0/xpan/file" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
switch r.URL.Query().Get("method") {
|
||||
case "list":
|
||||
parent := r.URL.Query().Get("dir")
|
||||
entries := make([]File, 0)
|
||||
for directory := range directories {
|
||||
if directory != parent && path.Dir(directory) == parent {
|
||||
entries = append(entries, File{Path: directory, ServerFilename: path.Base(directory), IsDir: 1})
|
||||
}
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"errno": 0, "list": entries})
|
||||
case "create":
|
||||
if err := r.ParseForm(); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
directory := r.Form.Get("path")
|
||||
if r.Form.Get("isdir") != "1" {
|
||||
t.Errorf("isdir = %q", r.Form.Get("isdir"))
|
||||
}
|
||||
directories[directory] = true
|
||||
created = append(created, directory)
|
||||
_ = json.NewEncoder(w).Encode(File{Path: directory, ServerFilename: path.Base(directory), IsDir: 1})
|
||||
default:
|
||||
http.Error(w, "unexpected method", http.StatusBadRequest)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
client := New(testConfig("token"), WithEndpoints(server.URL, server.URL, server.URL))
|
||||
if err := client.MkdirAll(context.Background(), "/backup/mac/photos"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := client.MkdirAll(context.Background(), "/backup/mac/photos"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := []string{"/apps/bdrclone/backup", "/apps/bdrclone/backup/mac", "/apps/bdrclone/backup/mac/photos"}
|
||||
if !reflect.DeepEqual(created, want) {
|
||||
t.Fatalf("created = %q, want %q", created, want)
|
||||
}
|
||||
}
|
||||
|
||||
func testConfig(token string) *config.Config {
|
||||
return &config.Config{
|
||||
ClientID: "client", ClientSecret: "secret", AccessToken: token,
|
||||
|
||||
@@ -66,6 +66,38 @@ func (c *Client) Mkdir(ctx context.Context, name string) (File, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Client) MkdirAll(ctx context.Context, name string) error {
|
||||
target := path.Clean("/" + strings.TrimPrefix(name, "/"))
|
||||
if target == "/" {
|
||||
return nil
|
||||
}
|
||||
current := "/"
|
||||
for _, component := range strings.Split(strings.TrimPrefix(target, "/"), "/") {
|
||||
current = path.Join(current, component)
|
||||
if err := c.EnsureDirectory(ctx, current); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) EnsureDirectory(ctx context.Context, name string) error {
|
||||
entry, err := c.Stat(ctx, name)
|
||||
if err == nil {
|
||||
if !entry.IsDirectory() {
|
||||
return fmt.Errorf("remote path exists and is not a directory: %s", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !errors.Is(err, ErrNotFound) {
|
||||
return fmt.Errorf("check remote directory %s: %w", name, err)
|
||||
}
|
||||
if _, err := c.Mkdir(ctx, name); err != nil {
|
||||
return fmt.Errorf("create remote directory %s: %w", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Delete(ctx context.Context, name string) error {
|
||||
remote := c.RemotePath(name)
|
||||
if remote == c.root {
|
||||
|
||||
Reference in New Issue
Block a user