http: Update interfaces for List/ListR/Put/Update

This commit is contained in:
Nick Craig-Wood 2017-06-19 15:05:09 +01:00
parent 83b642e98f
commit afc8cc550a

View file

@ -16,15 +16,15 @@ import (
"path" "path"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"golang.org/x/net/html"
"github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/net/html"
) )
var errorReadOnly = errors.New("http remotes are read only")
func init() { func init() {
fsi := &fs.RegInfo{ fsi := &fs.RegInfo{
Name: "http", Name: "http",
@ -32,10 +32,10 @@ func init() {
NewFs: NewFs, NewFs: NewFs,
Options: []fs.Option{{ Options: []fs.Option{{
Name: "endpoint", Name: "endpoint",
Help: "http host to connect to", Help: "URL of http host to connect to",
Optional: false, Optional: false,
Examples: []fs.OptionExample{{ Examples: []fs.OptionExample{{
Value: "example.com", Value: "https://example.com",
Help: "Connect to example.com", Help: "Connect to example.com",
}}, }},
}}, }},
@ -278,24 +278,34 @@ func (f *Fs) readDir(p string) ([]*entry, error) {
return entries, nil return entries, nil
} }
func (f *Fs) list(out fs.ListOpts, dir string, level int, wg *sync.WaitGroup, tokens chan struct{}) { // List the objects and directories in dir into entries. The
defer wg.Done() // entries can be returned in any order but should be for a
// take a token // complete directory.
<-tokens //
// return it when done // dir should be "" to list the root, and should not have
defer func() { // trailing slashes.
tokens <- struct{}{} //
}() // This should return ErrDirNotFound if the directory isn't
// found.
func (f *Fs) List(dir string) (entries fs.DirEntries, err error) {
endpoint := path.Join(f.root, dir)
if !strings.HasSuffix(dir, "/") {
endpoint += "/"
}
ok, err := f.dirExists(endpoint)
if err != nil {
return nil, errors.Wrap(err, "List failed")
}
if !ok {
return nil, fs.ErrorDirNotFound
}
httpDir := path.Join(f.root, dir) httpDir := path.Join(f.root, dir)
if !strings.HasSuffix(dir, "/") { if !strings.HasSuffix(dir, "/") {
httpDir += "/" httpDir += "/"
} }
infos, err := f.readDir(httpDir) infos, err := f.readDir(httpDir)
if err != nil { if err != nil {
err = errors.Wrapf(err, "error listing %q", dir) return nil, errors.Wrapf(err, "error listing %q", dir)
fs.Errorf(f, "Listing failed: %v", err)
out.SetError(err)
return
} }
for _, info := range infos { for _, info := range infos {
remote := "" remote := ""
@ -305,19 +315,13 @@ func (f *Fs) list(out fs.ListOpts, dir string, level int, wg *sync.WaitGroup, to
remote = info.Name() remote = info.Name()
} }
if info.IsDir() { if info.IsDir() {
if out.IncludeDirectory(remote) { dir := &fs.Dir{
dir := &fs.Dir{ Name: remote,
Name: remote, When: info.ModTime(),
When: info.ModTime(), Bytes: 0,
Bytes: 0, Count: 0,
Count: 0,
}
out.AddDir(dir)
if level < out.Level() {
wg.Add(1)
go f.list(out, remote, level+1, wg, tokens)
}
} }
entries = append(entries, dir)
} else { } else {
file := &Object{ file := &Object{
fs: f, fs: f,
@ -327,41 +331,19 @@ func (f *Fs) list(out fs.ListOpts, dir string, level int, wg *sync.WaitGroup, to
if err = file.stat(); err != nil { if err = file.stat(); err != nil {
continue continue
} }
out.Add(file) entries = append(entries, file)
} }
} }
return entries, nil
} }
// List the files and directories starting at <dir> // Put in to the remote path with the modTime given of the given size
func (f *Fs) List(out fs.ListOpts, dir string) { //
endpoint := path.Join(f.root, dir) // May create the object even if it returns an error - if so
if !strings.HasSuffix(dir, "/") { // will return the object and the error, otherwise will return
endpoint += "/" // nil and the error
} func (f *Fs) Put(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
ok, err := f.dirExists(endpoint) return nil, errorReadOnly
if err != nil {
out.SetError(errors.Wrap(err, "List failed"))
return
}
if !ok {
out.SetError(fs.ErrorDirNotFound)
return
}
// tokens to control the concurrency
tokens := make(chan struct{}, fs.Config.Checkers)
for i := 0; i < fs.Config.Checkers; i++ {
tokens <- struct{}{}
}
wg := new(sync.WaitGroup)
wg.Add(1)
f.list(out, dir, 1, wg, tokens)
wg.Wait()
out.Finished()
}
// Put data from <in> into a new remote http file object described by <src.Remote()> and <src.ModTime()>
func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) {
return nil, nil
} }
// Fs is the filesystem this remote http file object is located within // Fs is the filesystem this remote http file object is located within
@ -442,7 +424,7 @@ func (o *Object) stat() error {
// //
// it also updates the info field // it also updates the info field
func (o *Object) SetModTime(modTime time.Time) error { func (o *Object) SetModTime(modTime time.Time) error {
return nil return errorReadOnly
} }
// Storable returns whether the remote http file is a regular file (not a directory, symbolic link, block device, character device, named pipe, etc) // Storable returns whether the remote http file is a regular file (not a directory, symbolic link, block device, character device, named pipe, etc)
@ -502,22 +484,22 @@ func (f *Fs) Hashes() fs.HashSet {
// Mkdir makes the root directory of the Fs object // Mkdir makes the root directory of the Fs object
func (f *Fs) Mkdir(dir string) error { func (f *Fs) Mkdir(dir string) error {
return nil return errorReadOnly
} }
// Remove a remote http file object // Remove a remote http file object
func (o *Object) Remove() error { func (o *Object) Remove() error {
return nil return errorReadOnly
} }
// Rmdir removes the root directory of the Fs object // Rmdir removes the root directory of the Fs object
func (f *Fs) Rmdir(dir string) error { func (f *Fs) Rmdir(dir string) error {
return nil return errorReadOnly
} }
// Update a remote http file using the data <in> and ModTime from <src> // Update in to the object with the modTime given of the given size
func (o *Object) Update(in io.Reader, src fs.ObjectInfo) error { func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
return nil return errorReadOnly
} }
// Check the interfaces are satisfied // Check the interfaces are satisfied