Fix golint warnings

This commit is contained in:
Nick Craig-Wood 2015-09-22 18:47:16 +01:00
parent 2ed158aba3
commit e9c915e6fe
24 changed files with 421 additions and 361 deletions

View File

@ -10,6 +10,11 @@ test: rclone
go test ./...
cd fs && ./test_all.sh
check: rclone
go vet ./...
errcheck ./...
golint ./...
doc: rclone.1 MANUAL.html MANUAL.txt
rclone.1: MANUAL.md
@ -52,7 +57,7 @@ serve:
tag:
@echo "Old tag is $(LAST_TAG)"
@echo "New tag is $(NEW_TAG)"
echo -e "package fs\n const Version = \"$(NEW_TAG)\"\n" | gofmt > fs/version.go
echo -e "package fs\n\n// Version of rclone\nconst Version = \"$(NEW_TAG)\"\n" | gofmt > fs/version.go
perl -lpe 's/VERSION/${NEW_TAG}/g; s/DATE/'`date -I`'/g;' docs/content/downloads.md.in > docs/content/downloads.md
git tag $(NEW_TAG)
@echo "Add this to changelog in docs/content/changelog.md"

View File

@ -4,9 +4,12 @@ Required software for making a release
* Run `gox -build-toolchain`
* This assumes you have your own source checkout
* pandoc for making the html and man pages
* errcheck - go get github.com/kisielk/errcheck
* golint - go get github.com/golang/lint
Making a release
* go get -u -f -v ./...
* make check
* make test
* make tag
* edit docs/content/changelog.md

View File

@ -1,4 +1,5 @@
// Amazon Cloud Drive interface
// Package amazonclouddrive provides an interface to the Amazon Cloud
// Drive object storage system.
package amazonclouddrive
/*
@ -59,7 +60,7 @@ var (
// Register with Fs
func init() {
fs.Register(&fs.FsInfo{
fs.Register(&fs.Info{
Name: "amazon cloud drive",
NewFs: NewFs,
Config: func(name string) {
@ -98,12 +99,12 @@ type FsObjectAcd struct {
// ------------------------------------------------------------
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
func (f *FsAcd) Name() string {
return f.name
}
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
func (f *FsAcd) Root() string {
return f.root
}
@ -242,17 +243,17 @@ func (f *FsAcd) newFsObjectWithInfo(remote string, info *acd.Node) fs.Object {
return o
}
// Return an FsObject from a path
// NewFsObject returns an FsObject from a path
//
// May return nil if an error occurred
func (f *FsAcd) NewFsObject(remote string) fs.Object {
return f.newFsObjectWithInfo(remote, nil)
}
// FindLeaf finds a directory of name leaf in the folder with ID pathId
func (f *FsAcd) FindLeaf(pathId, leaf string) (pathIdOut string, found bool, err error) {
//fs.Debug(f, "FindLeaf(%q, %q)", pathId, leaf)
folder := acd.FolderFromId(pathId, f.c.Nodes)
// FindLeaf finds a directory of name leaf in the folder with ID pathID
func (f *FsAcd) FindLeaf(pathID, leaf string) (pathIDOut string, found bool, err error) {
//fs.Debug(f, "FindLeaf(%q, %q)", pathID, leaf)
folder := acd.FolderFromId(pathID, f.c.Nodes)
var resp *http.Response
var subFolder *acd.Folder
err = f.pacer.Call(func() (bool, error) {
@ -276,10 +277,10 @@ func (f *FsAcd) FindLeaf(pathId, leaf string) (pathIdOut string, found bool, err
return *subFolder.Id, true, nil
}
// CreateDir makes a directory with pathId as parent and name leaf
func (f *FsAcd) CreateDir(pathId, leaf string) (newId string, err error) {
//fmt.Printf("CreateDir(%q, %q)\n", pathId, leaf)
folder := acd.FolderFromId(pathId, f.c.Nodes)
// CreateDir makes a directory with pathID as parent and name leaf
func (f *FsAcd) CreateDir(pathID, leaf string) (newID string, err error) {
//fmt.Printf("CreateDir(%q, %q)\n", pathID, leaf)
folder := acd.FolderFromId(pathID, f.c.Nodes)
var resp *http.Response
var info *acd.Folder
err = f.pacer.Call(func() (bool, error) {
@ -305,8 +306,8 @@ type listAllFn func(*acd.Node) bool
// Lists the directory required calling the user function on each item found
//
// If the user fn ever returns true then it early exits with found = true
func (f *FsAcd) listAll(dirId string, title string, directoriesOnly bool, filesOnly bool, fn listAllFn) (found bool, err error) {
query := "parents:" + dirId
func (f *FsAcd) listAll(dirID string, title string, directoriesOnly bool, filesOnly bool, fn listAllFn) (found bool, err error) {
query := "parents:" + dirID
if directoriesOnly {
query += " AND kind:" + folderKind
} else if filesOnly {
@ -358,11 +359,11 @@ OUTER:
//
// This fetches the minimum amount of stuff but does more API calls
// which makes it slow
func (f *FsAcd) listDirRecursive(dirId string, path string, out fs.ObjectsChan) error {
func (f *FsAcd) listDirRecursive(dirID string, path string, out fs.ObjectsChan) error {
var subError error
// Make the API request
var wg sync.WaitGroup
_, err := f.listAll(dirId, "", false, false, func(node *acd.Node) bool {
_, err := f.listAll(dirID, "", false, false, func(node *acd.Node) bool {
// Recurse on directories
switch *node.Kind {
case folderKind:
@ -398,7 +399,7 @@ func (f *FsAcd) listDirRecursive(dirId string, path string, out fs.ObjectsChan)
return nil
}
// Walk the path returning a channel of FsObjects
// List walks the path returning a channel of FsObjects
func (f *FsAcd) List() fs.ObjectsChan {
out := make(fs.ObjectsChan, fs.Config.Checkers)
go func() {
@ -418,7 +419,7 @@ func (f *FsAcd) List() fs.ObjectsChan {
return out
}
// Lists the containers
// ListDir lists the directories
func (f *FsAcd) ListDir() fs.DirChan {
out := make(fs.DirChan, fs.Config.Checkers)
go func() {
@ -546,7 +547,7 @@ func (f *FsAcd) Rmdir() error {
return f.purgeCheck(true)
}
// Return the precision
// Precision return the precision of this Fs
func (f *FsAcd) Precision() time.Duration {
return fs.ModTimeNotSupported
}
@ -585,7 +586,7 @@ func (f *FsAcd) Purge() error {
// ------------------------------------------------------------
// Return the parent Fs
// Fs returns the parent Fs
func (o *FsObjectAcd) Fs() fs.Fs {
return o.acd
}
@ -598,7 +599,7 @@ func (o *FsObjectAcd) String() string {
return o.remote
}
// Return the remote path
// Remote returns the remote path
func (o *FsObjectAcd) Remote() string {
return o.remote
}
@ -661,13 +662,13 @@ func (o *FsObjectAcd) ModTime() time.Time {
return modTime
}
// Sets the modification time of the local fs object
// SetModTime sets the modification time of the local fs object
func (o *FsObjectAcd) SetModTime(modTime time.Time) {
// FIXME not implemented
return
}
// Is this object storable
// Storable returns a boolean showing whether this object storable
func (o *FsObjectAcd) Storable() bool {
return true
}

View File

@ -1,4 +1,4 @@
// dircache provides a simple cache for caching directory to path lookups
// Package dircache provides a simple cache for caching directory to path lookups
package dircache
// _methods are called without the lock
@ -23,13 +23,13 @@ type DirCache struct {
foundRoot bool // Whether we have found the root or not
}
// DirCache describes an interface for doing the low level directory work
// DirCacher describes an interface for doing the low level directory work
type DirCacher interface {
FindLeaf(pathID, leaf string) (pathIDOut string, found bool, err error)
CreateDir(pathID, leaf string) (newID string, err error)
}
// Make a new DirCache
// New makes a DirCache
//
// The cache is safe for concurrent use
func New(root string, trueRootID string, fs DirCacher) *DirCache {
@ -49,7 +49,7 @@ func (dc *DirCache) _get(path string) (id string, ok bool) {
return
}
// Gets an ID given a path
// Get an ID given a path
func (dc *DirCache) Get(path string) (id string, ok bool) {
dc.mu.RLock()
id, ok = dc._get(path)
@ -91,7 +91,7 @@ func (dc *DirCache) Flush() {
dc.mu.Unlock()
}
// Splits a path into directory, leaf
// SplitPath splits a path into directory, leaf
//
// Path shouldn't start or end with a /
//
@ -108,7 +108,8 @@ func SplitPath(path string) (directory, leaf string) {
return
}
// Finds the directory passed in returning the directory ID starting from pathID
// FindDir finds the directory passed in returning the directory ID
// starting from pathID
//
// Path shouldn't start or end with a /
//
@ -207,7 +208,7 @@ func (dc *DirCache) FindPath(path string, create bool) (leaf, directoryID string
return
}
// Finds the root directory if not already found
// FindRoot finds the root directory if not already found
//
// Resets the root directory
//
@ -268,7 +269,8 @@ func (dc *DirCache) RootParentID() (string, error) {
return dc.rootParentID, nil
}
// Resets the root directory to the absolute root and clears the DirCache
// ResetRoot resets the root directory to the absolute root and clears
// the DirCache
func (dc *DirCache) ResetRoot() {
dc.mu.Lock()
defer dc.mu.Unlock()

View File

@ -1,4 +1,4 @@
// Drive interface
// Package drive interfaces with the Google Drive object storage system
package drive
// FIXME need to deal with some corner cases
@ -61,7 +61,7 @@ var (
// Register with Fs
func init() {
fs.Register(&fs.FsInfo{
fs.Register(&fs.Info{
Name: "drive",
NewFs: NewFs,
Config: func(name string) {
@ -106,12 +106,12 @@ type FsObjectDrive struct {
// ------------------------------------------------------------
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
func (f *FsDrive) Name() string {
return f.name
}
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
func (f *FsDrive) Root() string {
return f.root
}
@ -170,10 +170,10 @@ type listAllFn func(*drive.File) bool
// If the user fn ever returns true then it early exits with found = true
//
// Search params: https://developers.google.com/drive/search-parameters
func (f *FsDrive) listAll(dirId string, title string, directoriesOnly bool, filesOnly bool, fn listAllFn) (found bool, err error) {
func (f *FsDrive) listAll(dirID string, title string, directoriesOnly bool, filesOnly bool, fn listAllFn) (found bool, err error) {
query := fmt.Sprintf("trashed=false")
if dirId != "" {
query += fmt.Sprintf(" and '%s' in parents", dirId)
if dirID != "" {
query += fmt.Sprintf(" and '%s' in parents", dirID)
}
if title != "" {
// Escaping the backslash isn't documented but seems to work
@ -321,35 +321,35 @@ func (f *FsDrive) newFsObjectWithInfo(remote string, info *drive.File) fs.Object
return fs
}
// Return an FsObject from a path
// NewFsObject returns an FsObject from a path
//
// May return nil if an error occurred
func (f *FsDrive) NewFsObject(remote string) fs.Object {
return f.newFsObjectWithInfo(remote, nil)
}
// FindLeaf finds a directory of name leaf in the folder with ID pathId
func (f *FsDrive) FindLeaf(pathId, leaf string) (pathIdOut string, found bool, err error) {
// Find the leaf in pathId
found, err = f.listAll(pathId, leaf, true, false, func(item *drive.File) bool {
// FindLeaf finds a directory of name leaf in the folder with ID pathID
func (f *FsDrive) FindLeaf(pathID, leaf string) (pathIDOut string, found bool, err error) {
// Find the leaf in pathID
found, err = f.listAll(pathID, leaf, true, false, func(item *drive.File) bool {
if item.Title == leaf {
pathIdOut = item.Id
pathIDOut = item.Id
return true
}
return false
})
return pathIdOut, found, err
return pathIDOut, found, err
}
// CreateDir makes a directory with pathId as parent and name leaf
func (f *FsDrive) CreateDir(pathId, leaf string) (newId string, err error) {
// CreateDir makes a directory with pathID as parent and name leaf
func (f *FsDrive) CreateDir(pathID, leaf string) (newID string, err error) {
// fmt.Println("Making", path)
// Define the metadata for the directory we are going to create.
createInfo := &drive.File{
Title: leaf,
Description: leaf,
MimeType: driveFolderType,
Parents: []*drive.ParentReference{{Id: pathId}},
Parents: []*drive.ParentReference{{Id: pathID}},
}
var info *drive.File
err = f.pacer.Call(func() (bool, error) {
@ -368,11 +368,11 @@ func (f *FsDrive) CreateDir(pathId, leaf string) (newId string, err error) {
//
// This fetches the minimum amount of stuff but does more API calls
// which makes it slow
func (f *FsDrive) listDirRecursive(dirId string, path string, out fs.ObjectsChan) error {
func (f *FsDrive) listDirRecursive(dirID string, path string, out fs.ObjectsChan) error {
var subError error
// Make the API request
var wg sync.WaitGroup
_, err := f.listAll(dirId, "", false, false, func(item *drive.File) bool {
_, err := f.listAll(dirID, "", false, false, func(item *drive.File) bool {
// Recurse on directories
if item.MimeType == driveFolderType {
wg.Add(1)
@ -388,7 +388,6 @@ func (f *FsDrive) listDirRecursive(dirId string, path string, out fs.ObjectsChan
}
}()
return false
} else {
// If item has no MD5 sum it isn't stored on drive, so ignore it
if item.Md5Checksum != "" {
@ -417,7 +416,7 @@ func (f *FsDrive) listDirRecursive(dirId string, path string, out fs.ObjectsChan
//
// This is fast in terms of number of API calls, but slow in terms of
// fetching more data than it needs
func (f *FsDrive) listDirFull(dirId string, path string, out fs.ObjectsChan) error {
func (f *FsDrive) listDirFull(dirID string, path string, out fs.ObjectsChan) error {
// Orphans waiting for their parent
orphans := make(map[string][]*drive.File)
@ -457,12 +456,12 @@ func (f *FsDrive) listDirFull(dirId string, path string, out fs.ObjectsChan) err
// fmt.Printf("no parents %s %s: %#v\n", item.Title, item.Id, item)
return false
}
parentId := item.Parents[0].Id
directory, ok := f.dirCache.GetInv(parentId)
parentID := item.Parents[0].Id
directory, ok := f.dirCache.GetInv(parentID)
if !ok {
// Haven't found the parent yet so add to orphans
// fmt.Printf("orphan[%s] %s %s\n", parentId, item.Title, item.Id)
orphans[parentId] = append(orphans[parentId], item)
// fmt.Printf("orphan[%s] %s %s\n", parentID, item.Title, item.Id)
orphans[parentID] = append(orphans[parentID], item)
} else {
outputItem(item, directory)
}
@ -478,7 +477,7 @@ func (f *FsDrive) listDirFull(dirId string, path string, out fs.ObjectsChan) err
return nil
}
// Walk the path returning a channel of FsObjects
// List walks the path returning a channel of FsObjects
func (f *FsDrive) List() fs.ObjectsChan {
out := make(fs.ObjectsChan, fs.Config.Checkers)
go func() {
@ -502,7 +501,7 @@ func (f *FsDrive) List() fs.ObjectsChan {
return out
}
// Walk the path returning a channel of FsObjects
// ListDir walks the path returning a channel of directories
func (f *FsDrive) ListDir() fs.DirChan {
out := make(fs.DirChan, fs.Config.Checkers)
go func() {
@ -543,7 +542,7 @@ func (f *FsDrive) createFileInfo(remote string, modTime time.Time, size int64) (
bytes: size,
}
leaf, directoryId, err := f.dirCache.FindPath(remote, true)
leaf, directoryID, err := f.dirCache.FindPath(remote, true)
if err != nil {
return nil, nil, err
}
@ -552,7 +551,7 @@ func (f *FsDrive) createFileInfo(remote string, modTime time.Time, size int64) (
createInfo := &drive.File{
Title: leaf,
Description: leaf,
Parents: []*drive.ParentReference{{Id: directoryId}},
Parents: []*drive.ParentReference{{Id: directoryID}},
MimeType: fs.MimeType(o),
ModifiedDate: modTime.Format(timeFormatOut),
}
@ -638,8 +637,8 @@ func (f *FsDrive) Rmdir() error {
return nil
}
// Return the precision
func (fs *FsDrive) Precision() time.Duration {
// Precision of the object storage system
func (f *FsDrive) Precision() time.Duration {
return time.Millisecond
}
@ -714,7 +713,7 @@ func (f *FsDrive) Purge() error {
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantMove
func (dstFs *FsDrive) Move(src fs.Object, remote string) (fs.Object, error) {
func (f *FsDrive) Move(src fs.Object, remote string) (fs.Object, error) {
srcObj, ok := src.(*FsObjectDrive)
if !ok {
fs.Debug(src, "Can't move - not same remote type")
@ -722,13 +721,13 @@ func (dstFs *FsDrive) Move(src fs.Object, remote string) (fs.Object, error) {
}
// Temporary FsObject under construction
dstObj, dstInfo, err := dstFs.createFileInfo(remote, srcObj.ModTime(), srcObj.bytes)
dstObj, dstInfo, err := f.createFileInfo(remote, srcObj.ModTime(), srcObj.bytes)
if err != nil {
return nil, err
}
// Do the move
info, err := dstFs.svc.Files.Patch(srcObj.id, dstInfo).SetModifiedDate(true).Do()
info, err := f.svc.Files.Patch(srcObj.id, dstInfo).SetModifiedDate(true).Do()
if err != nil {
return nil, err
}
@ -737,14 +736,15 @@ func (dstFs *FsDrive) Move(src fs.Object, remote string) (fs.Object, error) {
return dstObj, nil
}
// Move src to this remote using server side move operations.
// DirMove moves src directory to this remote using server side move
// operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (dstFs *FsDrive) DirMove(src fs.Fs) error {
func (f *FsDrive) DirMove(src fs.Fs) error {
srcFs, ok := src.(*FsDrive)
if !ok {
fs.Debug(srcFs, "Can't move directory - not same remote type")
@ -752,14 +752,14 @@ func (dstFs *FsDrive) DirMove(src fs.Fs) error {
}
// Check if destination exists
dstFs.dirCache.ResetRoot()
err := dstFs.dirCache.FindRoot(false)
f.dirCache.ResetRoot()
err := f.dirCache.FindRoot(false)
if err == nil {
return fs.ErrorDirExists
}
// Find ID of parent
leaf, directoryId, err := dstFs.dirCache.FindPath(dstFs.root, true)
leaf, directoryID, err := f.dirCache.FindPath(f.root, true)
if err != nil {
return err
}
@ -767,9 +767,9 @@ func (dstFs *FsDrive) DirMove(src fs.Fs) error {
// Do the move
patch := drive.File{
Title: leaf,
Parents: []*drive.ParentReference{{Id: directoryId}},
Parents: []*drive.ParentReference{{Id: directoryID}},
}
_, err = dstFs.svc.Files.Patch(srcFs.dirCache.RootID(), &patch).Do()
_, err = f.svc.Files.Patch(srcFs.dirCache.RootID(), &patch).Do()
if err != nil {
return err
}
@ -779,7 +779,7 @@ func (dstFs *FsDrive) DirMove(src fs.Fs) error {
// ------------------------------------------------------------
// Return the parent Fs
// Fs returns the parent Fs
func (o *FsObjectDrive) Fs() fs.Fs {
return o.drive
}
@ -792,7 +792,7 @@ func (o *FsObjectDrive) String() string {
return o.remote
}
// Return the remote path
// Remote returns the remote path
func (o *FsObjectDrive) Remote() string {
return o.remote
}
@ -822,12 +822,12 @@ func (o *FsObjectDrive) readMetaData() (err error) {
return nil
}
leaf, directoryId, err := o.drive.dirCache.FindPath(o.remote, false)
leaf, directoryID, err := o.drive.dirCache.FindPath(o.remote, false)
if err != nil {
return err
}
found, err := o.drive.listAll(directoryId, leaf, false, true, func(item *drive.File) bool {
found, err := o.drive.listAll(directoryID, leaf, false, true, func(item *drive.File) bool {
if item.Title == leaf {
o.setMetaData(item)
return true
@ -863,7 +863,7 @@ func (o *FsObjectDrive) ModTime() time.Time {
return modTime
}
// Sets the modification time of the drive fs object
// SetModTime sets the modification time of the drive fs object
func (o *FsObjectDrive) SetModTime(modTime time.Time) {
err := o.readMetaData()
if err != nil {
@ -890,7 +890,7 @@ func (o *FsObjectDrive) SetModTime(modTime time.Time) {
o.setMetaData(info)
}
// Is this object storable
// Storable returns a boolean as to whether this object is storable
func (o *FsObjectDrive) Storable() bool {
return true
}

View File

@ -52,8 +52,8 @@ type resumableUpload struct {
// Upload the io.Reader in of size bytes with contentType and info
func (f *FsDrive) Upload(in io.Reader, size int64, contentType string, info *drive.File, remote string) (*drive.File, error) {
fileId := info.Id
var body io.Reader = nil
fileID := info.Id
var body io.Reader
body, err := googleapi.WithoutDataWrapper.JSONReader(info)
if err != nil {
return nil, err
@ -63,7 +63,7 @@ func (f *FsDrive) Upload(in io.Reader, size int64, contentType string, info *dri
params.Set("uploadType", "resumable")
urls := "https://www.googleapis.com/upload/drive/v2/files"
method := "POST"
if fileId != "" {
if fileID != "" {
params.Set("setModifiedDate", "true")
urls += "/{fileId}"
method = "PUT"
@ -71,7 +71,7 @@ func (f *FsDrive) Upload(in io.Reader, size int64, contentType string, info *dri
urls += "?" + params.Encode()
req, _ := http.NewRequest(method, urls, body)
googleapi.Expand(req.URL, map[string]string{
"fileId": fileId,
"fileId": fileID,
})
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
req.Header.Set("X-Upload-Content-Type", contentType)

View File

@ -1,4 +1,4 @@
// Dropbox interface
// Package dropbox provides an interface to Dropbox object storage
package dropbox
/*
@ -44,7 +44,7 @@ var (
// Register with Fs
func init() {
fs.Register(&fs.FsInfo{
fs.Register(&fs.Info{
Name: "dropbox",
NewFs: NewFs,
Config: configHelper,
@ -112,12 +112,12 @@ type FsObjectDropbox struct {
// ------------------------------------------------------------
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
func (f *FsDropbox) Name() string {
return f.name
}
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
func (f *FsDropbox) Root() string {
return f.root
}
@ -217,7 +217,7 @@ func (f *FsDropbox) newFsObjectWithInfo(remote string, info *dropbox.Entry) fs.O
return o
}
// Return an FsObject from a path
// NewFsObject returns an FsObject from a path
//
// May return nil if an error occurred
func (f *FsDropbox) NewFsObject(remote string) fs.Object {
@ -243,7 +243,7 @@ func (f *FsDropbox) list(out fs.ObjectsChan) {
// Track path component case, it could be different for entries coming from DropBox API
// See https://www.dropboxforum.com/hc/communities/public/questions/201665409-Wrong-character-case-of-folder-name-when-calling-listFolder-using-Sync-API?locale=en-us
// and https://github.com/ncw/rclone/issues/53
nameTree := NewNameTree()
nameTree := newNameTree()
cursor := ""
for {
deltaPage, err := f.db.Delta(cursor, f.slashRoot)
@ -317,7 +317,7 @@ func (f *FsDropbox) list(out fs.ObjectsChan) {
nameTree.WalkFiles(f.root, walkFunc)
}
// Walk the path returning a channel of FsObjects
// List walks the path returning a channel of FsObjects
func (f *FsDropbox) List() fs.ObjectsChan {
out := make(fs.ObjectsChan, fs.Config.Checkers)
go func() {
@ -327,7 +327,7 @@ func (f *FsDropbox) List() fs.ObjectsChan {
return out
}
// Walk the path returning a channel of FsObjects
// ListDir walks the path returning a channel of FsObjects
func (f *FsDropbox) ListDir() fs.DirChan {
out := make(fs.DirChan, fs.Config.Checkers)
go func() {
@ -412,7 +412,7 @@ func (f *FsDropbox) Rmdir() error {
return f.Purge()
}
// Return the precision
// Precision returns the precision
func (f *FsDropbox) Precision() time.Duration {
return fs.ModTimeNotSupported
}
@ -466,7 +466,7 @@ func (f *FsDropbox) Purge() error {
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantMove
func (dstFs *FsDropbox) Move(src fs.Object, remote string) (fs.Object, error) {
func (f *FsDropbox) Move(src fs.Object, remote string) (fs.Object, error) {
srcObj, ok := src.(*FsObjectDropbox)
if !ok {
fs.Debug(src, "Can't move - not same remote type")
@ -474,11 +474,11 @@ func (dstFs *FsDropbox) Move(src fs.Object, remote string) (fs.Object, error) {
}
// Temporary FsObject under construction
dstObj := &FsObjectDropbox{dropbox: dstFs, remote: remote}
dstObj := &FsObjectDropbox{dropbox: f, remote: remote}
srcPath := srcObj.remotePath()
dstPath := dstObj.remotePath()
entry, err := dstFs.db.Move(srcPath, dstPath)
entry, err := f.db.Move(srcPath, dstPath)
if err != nil {
return nil, fmt.Errorf("Move failed: %s", err)
}
@ -486,14 +486,14 @@ func (dstFs *FsDropbox) Move(src fs.Object, remote string) (fs.Object, error) {
return dstObj, nil
}
// Move src to this remote using server side move operations.
// DirMove moves src to this remote using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (dstFs *FsDropbox) DirMove(src fs.Fs) error {
func (f *FsDropbox) DirMove(src fs.Fs) error {
srcFs, ok := src.(*FsDropbox)
if !ok {
fs.Debug(srcFs, "Can't move directory - not same remote type")
@ -501,13 +501,13 @@ func (dstFs *FsDropbox) DirMove(src fs.Fs) error {
}
// Check if destination exists
entry, err := dstFs.db.Metadata(dstFs.slashRoot, false, false, "", "", metadataLimit)
entry, err := f.db.Metadata(f.slashRoot, false, false, "", "", metadataLimit)
if err == nil && !entry.IsDeleted {
return fs.ErrorDirExists
}
// Do the move
_, err = dstFs.db.Move(srcFs.slashRoot, dstFs.slashRoot)
_, err = f.db.Move(srcFs.slashRoot, f.slashRoot)
if err != nil {
return fmt.Errorf("MoveDir failed: %v", err)
}
@ -516,7 +516,7 @@ func (dstFs *FsDropbox) DirMove(src fs.Fs) error {
// ------------------------------------------------------------
// Return the parent Fs
// Fs returns the parent Fs
func (o *FsObjectDropbox) Fs() fs.Fs {
return o.dropbox
}
@ -529,7 +529,7 @@ func (o *FsObjectDropbox) String() string {
return o.remote
}
// Return the remote path
// Remote returns the remote path
func (o *FsObjectDropbox) Remote() string {
return o.remote
}
@ -618,7 +618,7 @@ func (o *FsObjectDropbox) ModTime() time.Time {
return o.modTime
}
// Sets the modification time of the local fs object
// SetModTime sets the modification time of the local fs object
//
// Commits the datastore
func (o *FsObjectDropbox) SetModTime(modTime time.Time) {
@ -626,7 +626,7 @@ func (o *FsObjectDropbox) SetModTime(modTime time.Time) {
return
}
// Is this object storable
// Storable returns whether this object is storable
func (o *FsObjectDropbox) Storable() bool {
return true
}

View File

@ -9,9 +9,9 @@ import (
"github.com/stacktic/dropbox"
)
type NameTreeNode struct {
type nameTreeNode struct {
// Map from lowercase directory name to tree node
Directories map[string]*NameTreeNode
Directories map[string]*nameTreeNode
// Map from file name (case sensitive) to dropbox entry
Files map[string]*dropbox.Entry
@ -22,27 +22,26 @@ type NameTreeNode struct {
// ------------------------------------------------------------
func newNameTreeNode(caseCorrectName string) *NameTreeNode {
return &NameTreeNode{
func newNameTreeNode(caseCorrectName string) *nameTreeNode {
return &nameTreeNode{
CaseCorrectName: caseCorrectName,
Directories: make(map[string]*NameTreeNode),
Directories: make(map[string]*nameTreeNode),
Files: make(map[string]*dropbox.Entry),
}
}
func NewNameTree() *NameTreeNode {
func newNameTree() *nameTreeNode {
return newNameTreeNode("")
}
func (tree *NameTreeNode) String() string {
func (tree *nameTreeNode) String() string {
if len(tree.CaseCorrectName) == 0 {
return "NameTreeNode/<root>"
} else {
return fmt.Sprintf("NameTreeNode/%q", tree.CaseCorrectName)
return "nameTreeNode/<root>"
}
return fmt.Sprintf("nameTreeNode/%q", tree.CaseCorrectName)
}
func (tree *NameTreeNode) getTreeNode(path string) *NameTreeNode {
func (tree *nameTreeNode) getTreeNode(path string) *nameTreeNode {
if len(path) == 0 {
// no lookup required, just return root
return tree
@ -70,7 +69,7 @@ func (tree *NameTreeNode) getTreeNode(path string) *NameTreeNode {
return current
}
func (tree *NameTreeNode) PutCaseCorrectDirectoryName(parentPath string, caseCorrectDirectoryName string) {
func (tree *nameTreeNode) PutCaseCorrectDirectoryName(parentPath string, caseCorrectDirectoryName string) {
if len(caseCorrectDirectoryName) == 0 {
fs.Stats.Error()
fs.ErrorLog(tree, "PutCaseCorrectDirectoryName: empty caseCorrectDirectoryName is not allowed (parentPath: %q)", parentPath)
@ -98,7 +97,7 @@ func (tree *NameTreeNode) PutCaseCorrectDirectoryName(parentPath string, caseCor
}
}
func (tree *NameTreeNode) PutFile(parentPath string, caseCorrectFileName string, dropboxEntry *dropbox.Entry) {
func (tree *nameTreeNode) PutFile(parentPath string, caseCorrectFileName string, dropboxEntry *dropbox.Entry) {
node := tree.getTreeNode(parentPath)
if node == nil {
return
@ -113,7 +112,7 @@ func (tree *NameTreeNode) PutFile(parentPath string, caseCorrectFileName string,
node.Files[caseCorrectFileName] = dropboxEntry
}
func (tree *NameTreeNode) GetPathWithCorrectCase(path string) *string {
func (tree *nameTreeNode) GetPathWithCorrectCase(path string) *string {
if path == "" {
empty := ""
return &empty
@ -144,9 +143,9 @@ func (tree *NameTreeNode) GetPathWithCorrectCase(path string) *string {
return &resultString
}
type NameTreeFileWalkFunc func(caseCorrectFilePath string, entry *dropbox.Entry)
type nameTreeFileWalkFunc func(caseCorrectFilePath string, entry *dropbox.Entry)
func (tree *NameTreeNode) walkFilesRec(currentPath string, walkFunc NameTreeFileWalkFunc) {
func (tree *nameTreeNode) walkFilesRec(currentPath string, walkFunc nameTreeFileWalkFunc) {
var prefix string
if currentPath == "" {
prefix = ""
@ -170,7 +169,7 @@ func (tree *NameTreeNode) walkFilesRec(currentPath string, walkFunc NameTreeFile
}
}
func (tree *NameTreeNode) WalkFiles(rootPath string, walkFunc NameTreeFileWalkFunc) {
func (tree *nameTreeNode) WalkFiles(rootPath string, walkFunc nameTreeFileWalkFunc) {
node := tree.getTreeNode(rootPath)
if node == nil {
return

View File

@ -1,10 +1,10 @@
package dropbox_test
package dropbox
import (
"github.com/ncw/rclone/dropbox"
"testing"
"github.com/ncw/rclone/fs"
dropboxapi "github.com/stacktic/dropbox"
"testing"
)
func assert(t *testing.T, shouldBeTrue bool, failMessage string) {
@ -16,7 +16,7 @@ func assert(t *testing.T, shouldBeTrue bool, failMessage string) {
func TestPutCaseCorrectDirectoryName(t *testing.T) {
errors := fs.Stats.GetErrors()
tree := dropbox.NewNameTree()
tree := newNameTree()
tree.PutCaseCorrectDirectoryName("a/b", "C")
assert(t, tree.CaseCorrectName == "", "Root CaseCorrectName should be empty")
@ -36,7 +36,7 @@ func TestPutCaseCorrectDirectoryName(t *testing.T) {
func TestPutCaseCorrectDirectoryNameEmptyComponent(t *testing.T) {
errors := fs.Stats.GetErrors()
tree := dropbox.NewNameTree()
tree := newNameTree()
tree.PutCaseCorrectDirectoryName("/a", "C")
tree.PutCaseCorrectDirectoryName("b/", "C")
tree.PutCaseCorrectDirectoryName("a//b", "C")
@ -47,7 +47,7 @@ func TestPutCaseCorrectDirectoryNameEmptyComponent(t *testing.T) {
func TestPutCaseCorrectDirectoryNameEmptyParent(t *testing.T) {
errors := fs.Stats.GetErrors()
tree := dropbox.NewNameTree()
tree := newNameTree()
tree.PutCaseCorrectDirectoryName("", "C")
c := tree.Directories["c"]
@ -59,7 +59,7 @@ func TestPutCaseCorrectDirectoryNameEmptyParent(t *testing.T) {
func TestGetPathWithCorrectCase(t *testing.T) {
errors := fs.Stats.GetErrors()
tree := dropbox.NewNameTree()
tree := newNameTree()
tree.PutCaseCorrectDirectoryName("a", "C")
assert(t, tree.GetPathWithCorrectCase("a/c") == nil, "Path for 'a' should not be available")
@ -72,7 +72,7 @@ func TestGetPathWithCorrectCase(t *testing.T) {
func TestPutAndWalk(t *testing.T) {
errors := fs.Stats.GetErrors()
tree := dropbox.NewNameTree()
tree := newNameTree()
tree.PutFile("a", "F", &dropboxapi.Entry{Path: "xxx"})
tree.PutCaseCorrectDirectoryName("", "A")
@ -92,7 +92,7 @@ func TestPutAndWalk(t *testing.T) {
func TestPutAndWalkWithPrefix(t *testing.T) {
errors := fs.Stats.GetErrors()
tree := dropbox.NewNameTree()
tree := newNameTree()
tree.PutFile("a", "F", &dropboxapi.Entry{Path: "xxx"})
tree.PutCaseCorrectDirectoryName("", "A")
@ -112,7 +112,7 @@ func TestPutAndWalkWithPrefix(t *testing.T) {
func TestPutAndWalkIncompleteTree(t *testing.T) {
errors := fs.Stats.GetErrors()
tree := dropbox.NewNameTree()
tree := newNameTree()
tree.PutFile("a", "F", &dropboxapi.Entry{Path: "xxx"})
walkFunc := func(caseCorrectFilePath string, entry *dropboxapi.Entry) {

View File

@ -70,7 +70,7 @@ func (ip *inProgress) get(name string) *Account {
// Strings returns all the strings in the stringSet
func (ss stringSet) Strings() []string {
strings := make([]string, 0, len(ss))
for name, _ := range ss {
for name := range ss {
var out string
if acc := Stats.inProgress.get(name); acc != nil {
out = acc.String()
@ -89,7 +89,7 @@ func (ss stringSet) String() string {
return strings.Join(ss.Strings(), "\n")
}
// Stats limits and accounts all transfers
// StatsInfo limits and accounts all transfers
type StatsInfo struct {
lock sync.RWMutex
bytes int64
@ -117,12 +117,12 @@ func (s *StatsInfo) String() string {
s.lock.RLock()
defer s.lock.RUnlock()
dt := time.Now().Sub(s.start)
dt_seconds := dt.Seconds()
dtSeconds := dt.Seconds()
speed := 0.0
if dt > 0 {
speed = float64(s.bytes) / 1024 / dt_seconds
speed = float64(s.bytes) / 1024 / dtSeconds
}
dt_rounded := dt - (dt % (time.Second / 10))
dtRounded := dt - (dt % (time.Second / 10))
buf := &bytes.Buffer{}
fmt.Fprintf(buf, `
Transferred: %10d Bytes (%7.2f kByte/s)
@ -135,7 +135,7 @@ Elapsed time: %10v
s.errors,
s.checks,
s.transfers,
dt_rounded)
dtRounded)
if len(s.checking) > 0 {
fmt.Fprintf(buf, "Checking:\n%s\n", s.checking)
}
@ -199,7 +199,7 @@ func (s *StatsInfo) Errored() bool {
func (s *StatsInfo) Error() {
s.lock.Lock()
defer s.lock.Unlock()
s.errors += 1
s.errors++
}
// Checking adds a check into the stats
@ -214,7 +214,7 @@ func (s *StatsInfo) DoneChecking(o Object) {
s.lock.Lock()
defer s.lock.Unlock()
delete(s.checking, o.Remote())
s.checks += 1
s.checks++
}
// GetTransfers reads the number of transfers
@ -236,7 +236,7 @@ func (s *StatsInfo) DoneTransferring(o Object) {
s.lock.Lock()
defer s.lock.Unlock()
delete(s.transferring, o.Remote())
s.transfers += 1
s.transfers++
}
// Account limits and accounts for one transfer
@ -324,7 +324,7 @@ func (file *Account) Read(p []byte) (n int, err error) {
return
}
// Returns bytes read as well as the size.
// Progress returns bytes read as well as the size.
// Size can be <= 0 if the size is unknown.
func (file *Account) Progress() (bytes, size int64) {
if file == nil {

View File

@ -26,17 +26,18 @@ const (
configFileName = ".rclone.conf"
)
// SizeSuffix is parsed by flag with k/M/G suffixes
type SizeSuffix int64
// Global
var (
// Config file
// ConfigFile is the config file data structure
ConfigFile *goconfig.ConfigFile
// Home directory
// HomeDir is the home directory of the user
HomeDir = configHome()
// Config file path
// ConfigPath points to the config file
ConfigPath = path.Join(HomeDir, configFileName)
// Global config
// Config is the global config
Config = &ConfigInfo{}
// Flags
verbose = pflag.BoolP("verbose", "v", false, "Print lots more stuff")
@ -145,7 +146,7 @@ func Reveal(y string) string {
return string(x)
}
// Filesystem config options
// ConfigInfo is filesystem config options
type ConfigInfo struct {
Verbose bool
Quiet bool
@ -192,7 +193,7 @@ func (ci *ConfigInfo) Transport() http.RoundTripper {
return t
}
// Transport returns an http.Client with the correct timeouts
// Client returns an http.Client with the correct timeouts
func (ci *ConfigInfo) Client() *http.Client {
return &http.Client{
Transport: ci.Transport(),
@ -220,7 +221,7 @@ func configHome() string {
return ""
}
// Loads the config file
// LoadConfig loads the config file
func LoadConfig() {
// Read some flags if set
//
@ -255,7 +256,7 @@ func LoadConfig() {
startTokenBucket()
}
// Save configuration file.
// SaveConfig saves configuration file.
func SaveConfig() {
err := goconfig.SaveConfigFile(ConfigFile, ConfigPath)
if err != nil {
@ -267,7 +268,7 @@ func SaveConfig() {
}
}
// Show an overview of the config file
// ShowRemotes shows an overview of the config file
func ShowRemotes() {
remotes := ConfigFile.GetSectionList()
if len(remotes) == 0 {
@ -288,7 +289,7 @@ func ChooseRemote() string {
return Choose("remote", remotes, nil, false)
}
// Read some input
// ReadLine reads some input
func ReadLine() string {
buf := bufio.NewReader(os.Stdin)
line, err := buf.ReadString('\n')
@ -320,7 +321,7 @@ func Command(commands []string) byte {
}
}
// Asks the user for Yes or No and returns true or false
// Confirm asks the user for Yes or No and returns true or false
func Confirm() bool {
return Command([]string{"yYes", "nNo"}) == 'y'
}
@ -357,7 +358,7 @@ func Choose(what string, defaults, help []string, newOk bool) string {
}
}
// Show the contents of the remote
// ShowRemote shows the contents of the remote
func ShowRemote(name string) {
fmt.Printf("--------------------\n")
fmt.Printf("[%s]\n", name)
@ -367,7 +368,7 @@ func ShowRemote(name string) {
fmt.Printf("--------------------\n")
}
// Print the contents of the remote and ask if it is OK
// OkRemote prints the contents of the remote and ask if it is OK
func OkRemote(name string) bool {
ShowRemote(name)
switch i := Command([]string{"yYes this is OK", "eEdit this remote", "dDelete this remote"}); i {
@ -384,7 +385,7 @@ func OkRemote(name string) bool {
return false
}
// Runs the config helper for the remote if needed
// RemoteConfig runs the config helper for the remote if needed
func RemoteConfig(name string) {
fmt.Printf("Remote config\n")
fsName := ConfigFile.MustValue(name, "type")
@ -400,7 +401,7 @@ func RemoteConfig(name string) {
}
}
// Choose an option
// ChooseOption asks the user to choose an option
func ChooseOption(o *Option) string {
fmt.Println(o.Help)
if len(o.Examples) > 0 {
@ -416,7 +417,7 @@ func ChooseOption(o *Option) string {
return ReadLine()
}
// Make a new remote
// NewRemote make a new remote from its name
func NewRemote(name string) {
fmt.Printf("What type of source is it?\n")
types := []string{}
@ -440,7 +441,7 @@ func NewRemote(name string) {
EditRemote(name)
}
// Edit a remote
// EditRemote gets the user to edit a remote
func EditRemote(name string) {
ShowRemote(name)
fmt.Printf("Edit remote\n")
@ -462,13 +463,13 @@ func EditRemote(name string) {
SaveConfig()
}
// Delete a remote
// DeleteRemote gets the user to delete a remote
func DeleteRemote(name string) {
ConfigFile.DeleteSection(name)
SaveConfig()
}
// Edit the config file interactively
// EditConfig edits the config file interactively
func EditConfig() {
for {
haveRemotes := len(ConfigFile.GetSectionList()) != 0

View File

@ -1,4 +1,4 @@
// Generic file system interface for rclone object storage systems
// Package fs is a generic file system interface for rclone object storage systems
package fs
import (
@ -12,26 +12,27 @@ import (
// Constants
const (
// User agent for Fs which can set it
// UserAgent for Fs which can set it
UserAgent = "rclone/" + Version
// Very large precision value to show mod time isn't supported
// ModTimeNotSupported is a very large precision value to show
// mod time isn't supported on this Fs
ModTimeNotSupported = 100 * 365 * 24 * time.Hour
)
// Globals
var (
// Filesystem registry
fsRegistry []*FsInfo
// Error returned by NewFs if not found in config file
NotFoundInConfigFile = fmt.Errorf("Didn't find section in config file")
fsRegistry []*Info
// ErrorNotFoundInConfigFile is returned by NewFs if not found in config file
ErrorNotFoundInConfigFile = fmt.Errorf("Didn't find section in config file")
ErrorCantCopy = fmt.Errorf("Can't copy object - incompatible remotes")
ErrorCantMove = fmt.Errorf("Can't copy object - incompatible remotes")
ErrorCantDirMove = fmt.Errorf("Can't copy directory - incompatible remotes")
ErrorDirExists = fmt.Errorf("Can't copy directory - destination already exists")
)
// Filesystem info
type FsInfo struct {
// Info information about a filesystem
type Info struct {
// Name of this fs
Name string
// Create a new file system. If root refers to an existing
@ -44,7 +45,7 @@ type FsInfo struct {
Options []Option
}
// An options for a Fs
// Option is describes an option for the config wizard
type Option struct {
Name string
Help string
@ -52,7 +53,7 @@ type Option struct {
Examples []OptionExample
}
// An example for an option
// OptionExample describes an example for an Option
type OptionExample struct {
Value string
Help string
@ -61,16 +62,16 @@ type OptionExample struct {
// Register a filesystem
//
// Fs modules should use this in an init() function
func Register(info *FsInfo) {
func Register(info *Info) {
fsRegistry = append(fsRegistry, info)
}
// A Filesystem, describes the local filesystem and the remote object store
// Fs is the interface a cloud storage system must provide
type Fs interface {
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
Name() string
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
Root() string
// String returns a description of the FS
@ -79,10 +80,10 @@ type Fs interface {
// List the Fs into a channel
List() ObjectsChan
// List the Fs directories/buckets/containers into a channel
// ListDir lists the Fs directories/buckets/containers into a channel
ListDir() DirChan
// Find the Object at remote. Returns nil if can't be found
// NewFsObject finds the Object at remote. Returns nil if can't be found
NewFsObject(remote string) Object
// Put in to the remote path with the modTime given of the given size
@ -92,12 +93,12 @@ type Fs interface {
// nil and the error
Put(in io.Reader, remote string, modTime time.Time, size int64) (Object, error)
// Make the directory (container, bucket)
// Mkdir makes the directory (container, bucket)
//
// Shouldn't return an error if it already exists
Mkdir() error
// Remove the directory (container, bucket) if empty
// Rmdir removes the directory (container, bucket) if empty
//
// Return an error if it doesn't exist or isn't empty
Rmdir() error
@ -106,8 +107,7 @@ type Fs interface {
Precision() time.Duration
}
// A filesystem like object which can either be a remote object or a
// local file/directory
// Object is a filesystem like object provided by an Fs
type Object interface {
// String returns a description of the Object
String() string
@ -145,7 +145,7 @@ type Object interface {
Remove() error
}
// Optional interfaces
// Purger is an optional interfaces for Fs
type Purger interface {
// Purge all files in the root and the root directory
//
@ -156,6 +156,7 @@ type Purger interface {
Purge() error
}
// Copier is an optional interface for Fs
type Copier interface {
// Copy src to this remote using server side copy operations.
//
@ -169,6 +170,7 @@ type Copier interface {
Copy(src Object, remote string) (Object, error)
}
// Mover is an optional interface for Fs
type Mover interface {
// Move src to this remote using server side move operations.
//
@ -182,8 +184,10 @@ type Mover interface {
Move(src Object, remote string) (Object, error)
}
// DirMover is an optional interface for Fs
type DirMover interface {
// Move src to this remote using server side move operations.
// DirMove moves src to this remote using server side move
// operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
@ -193,7 +197,8 @@ type DirMover interface {
DirMove(src Fs) error
}
// An optional interface for error as to whether the operation should be retried
// Retry is optional interface for error as to whether the operation
// should be retried at a high level.
//
// This should be returned from Update or Put methods as required
type Retry interface {
@ -201,7 +206,7 @@ type Retry interface {
Retry() bool
}
// A type of error
// retryError is a type of error
type retryError string
// Error interface
@ -228,7 +233,7 @@ type plainRetryError struct {
}
// Retry interface
func (_ plainRetryError) Retry() bool {
func (err plainRetryError) Retry() bool {
return true
}
@ -240,21 +245,22 @@ func RetryError(err error) error {
return plainRetryError{err}
}
// A channel of Objects
// ObjectsChan is a channel of Objects
type ObjectsChan chan Object
// A slice of Objects
// Objects is a slice of Object~s
type Objects []Object
// A pair of Objects
// ObjectPair is a pair of Objects used to describe a potential copy
// operation.
type ObjectPair struct {
src, dst Object
}
// A channel of ObjectPair
// ObjectPairChan is a channel of ObjectPair
type ObjectPairChan chan ObjectPair
// A structure of directory/container/bucket lists
// Dir describes a directory for directory/container/bucket lists
type Dir struct {
Name string // name of the directory
When time.Time // modification or creation time - IsZero for unknown
@ -262,13 +268,13 @@ type Dir struct {
Count int64 // number of objects -1 for unknown
}
// A channel of Dir objects
// DirChan is a channel of Dir objects
type DirChan chan *Dir
// Finds a FsInfo object for the name passed in
// Find looks for an Info object for the name passed in
//
// Services are looked up in the config file
func Find(name string) (*FsInfo, error) {
func Find(name string) (*Info, error) {
for _, item := range fsRegistry {
if item.Name == name {
return item, nil
@ -297,7 +303,7 @@ func NewFs(path string) (Fs, error) {
var err error
fsName, err = ConfigFile.GetValue(configName, "type")
if err != nil {
return nil, NotFoundInConfigFile
return nil, ErrorNotFoundInConfigFile
}
}
fs, err := Find(fsName)
@ -309,7 +315,7 @@ func NewFs(path string) (Fs, error) {
return fs.NewFs(configName, fsPath)
}
// Outputs log for object
// OutputLog logs for an object
func OutputLog(o interface{}, text string, args ...interface{}) {
description := ""
if o != nil {
@ -319,22 +325,23 @@ func OutputLog(o interface{}, text string, args ...interface{}) {
log.Print(description + out)
}
// Write debuging output for this Object or Fs
// Debug writes debuging output for this Object or Fs
func Debug(o interface{}, text string, args ...interface{}) {
if Config.Verbose {
OutputLog(o, text, args...)
}
}
// Write log output for this Object or Fs
// Log writes log output for this Object or Fs
func Log(o interface{}, text string, args ...interface{}) {
if !Config.Quiet {
OutputLog(o, text, args...)
}
}
// Write error log output for this Object or Fs
// Unconditionally logs a message regardless of Config.Quiet or Config.Verbose
// ErrorLog writes error log output for this Object or Fs. It
// unconditionally logs a message regardless of Config.Quiet or
// Config.Verbose.
func ErrorLog(o interface{}, text string, args ...interface{}) {
OutputLog(o, text, args...)
}

View File

@ -6,7 +6,8 @@ import (
"time"
)
// This defines a Limited Fs which can only return the Objects passed in from the Fs passed in
// Limited defines a Fs which can only return the Objects passed in
// from the Fs passed in
type Limited struct {
objects []Object
fs Fs
@ -21,12 +22,12 @@ func NewLimited(fs Fs, objects ...Object) Fs {
return f
}
// The name of the remote (as passed into NewFs)
// Name is name of the remote (as passed into NewFs)
func (f *Limited) Name() string {
return f.fs.Name() // return name of underlying remote
}
// The root of the remote (as passed into NewFs)
// Root is the root of the remote (as passed into NewFs)
func (f *Limited) Root() string {
return f.fs.Root() // return root of underlying remote
}
@ -48,14 +49,14 @@ func (f *Limited) List() ObjectsChan {
return out
}
// List the Fs directories/buckets/containers into a channel
// ListDir lists the Fs directories/buckets/containers into a channel
func (f *Limited) ListDir() DirChan {
out := make(DirChan, Config.Checkers)
close(out)
return out
}
// Find the Object at remote. Returns nil if can't be found
// NewFsObject finds the Object at remote. Returns nil if can't be found
func (f *Limited) NewFsObject(remote string) Object {
for _, obj := range f.objects {
if obj.Remote() == remote {
@ -78,13 +79,13 @@ func (f *Limited) Put(in io.Reader, remote string, modTime time.Time, size int64
return obj, obj.Update(in, modTime, size)
}
// Make the directory (container, bucket)
// Mkdir make the directory (container, bucket)
func (f *Limited) Mkdir() error {
// All directories are already made - just ignore
return nil
}
// Remove the directory (container, bucket) if empty
// Rmdir removes the directory (container, bucket) if empty
func (f *Limited) Rmdir() error {
// Ignore this in a limited fs
return nil

View File

@ -10,16 +10,16 @@ import (
const separator = "------------------------------------------------------------"
// An http transport which logs the traffic
type loggedTransport struct {
// LoggedTransport is an http transport which logs the traffic
type LoggedTransport struct {
wrapped http.RoundTripper
logBody bool
}
// NewLoggedTransport wraps the transport passed in and logs all roundtrips
// including the body if logBody is set.
func NewLoggedTransport(transport http.RoundTripper, logBody bool) *loggedTransport {
return &loggedTransport{
func NewLoggedTransport(transport http.RoundTripper, logBody bool) *LoggedTransport {
return &LoggedTransport{
wrapped: transport,
logBody: logBody,
}
@ -28,7 +28,7 @@ func NewLoggedTransport(transport http.RoundTripper, logBody bool) *loggedTransp
// CancelRequest cancels an in-flight request by closing its
// connection. CancelRequest should only be called after RoundTrip has
// returned.
func (t *loggedTransport) CancelRequest(req *http.Request) {
func (t *LoggedTransport) CancelRequest(req *http.Request) {
if wrapped, ok := t.wrapped.(interface {
CancelRequest(*http.Request)
}); ok {
@ -38,7 +38,7 @@ func (t *loggedTransport) CancelRequest(req *http.Request) {
}
// RoundTrip implements the RoundTripper interface.
func (t *loggedTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
func (t *LoggedTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
buf, _ := httputil.DumpRequest(req, t.logBody)
log.Println(separator)
log.Println("HTTP REQUEST")

View File

@ -11,7 +11,8 @@ import (
"time"
)
// Work out modify window for fses passed in - sets Config.ModifyWindow
// CalculateModifyWindow works out modify window for Fses passed in -
// sets Config.ModifyWindow
//
// This is the largest modify window of all the fses in use, and the
// user configured value
@ -39,7 +40,7 @@ func Md5sumsEqual(src, dst string) bool {
return src == dst
}
// Check the two files to see if the MD5sums are the same
// CheckMd5sums checks the two files to see if the MD5sums are the same
//
// Returns two bools, the first of which is equality and the second of
// which is true if either of the MD5SUMs were unset.
@ -71,7 +72,7 @@ func CheckMd5sums(src, dst Object) (equal bool, unset bool, err error) {
return Md5sumsEqual(srcMd5, dstMd5), false, nil
}
// Checks to see if the src and dst objects are equal by looking at
// Equal checks to see if the src and dst objects are equal by looking at
// size, mtime and MD5SUM
//
// If the src and dst size are different then it is considered to be
@ -139,7 +140,7 @@ func Equal(src, dst Object) bool {
return true
}
// Returns a guess at the mime type from the extension
// MimeType returns a guess at the mime type from the extension
func MimeType(o Object) string {
mimeType := mime.TypeByExtension(path.Ext(o.Remote()))
if mimeType == "" {
@ -281,7 +282,7 @@ func checkOne(pair ObjectPair, out ObjectPairChan) {
out <- pair
}
// Read Objects~s on in send to out if they need uploading
// PairChecker reads Objects~s on in send to out if they need transferring.
//
// FIXME potentially doing lots of MD5SUMS at once
func PairChecker(in ObjectPairChan, out ObjectPairChan, wg *sync.WaitGroup) {
@ -294,7 +295,7 @@ func PairChecker(in ObjectPairChan, out ObjectPairChan, wg *sync.WaitGroup) {
}
}
// Read Objects on in and copy them
// PairCopier reads Objects on in and copies them.
func PairCopier(in ObjectPairChan, fdst Fs, wg *sync.WaitGroup) {
defer wg.Done()
for pair := range in {
@ -309,7 +310,8 @@ func PairCopier(in ObjectPairChan, fdst Fs, wg *sync.WaitGroup) {
}
}
// Read Objects on in and move them if possible, or copy them if not
// PairMover reads Objects on in and moves them if possible, or copies
// them if not
func PairMover(in ObjectPairChan, fdst Fs, wg *sync.WaitGroup) {
defer wg.Done()
// See if we have Move available
@ -343,14 +345,14 @@ func PairMover(in ObjectPairChan, fdst Fs, wg *sync.WaitGroup) {
}
}
// Delete all the files passed in the channel
func DeleteFiles(to_be_deleted ObjectsChan) {
// DeleteFiles removes all the files passed in the channel
func DeleteFiles(toBeDeleted ObjectsChan) {
var wg sync.WaitGroup
wg.Add(Config.Transfers)
for i := 0; i < Config.Transfers; i++ {
go func() {
defer wg.Done()
for dst := range to_be_deleted {
for dst := range toBeDeleted {
if Config.DryRun {
Debug(dst, "Not deleting as --dry-run")
} else {
@ -385,8 +387,8 @@ func readFilesMap(fs Fs) map[string]Object {
return files
}
// Returns true if fdst and fsrc point to the same underlying Fs
func FsSame(fdst, fsrc Fs) bool {
// Same returns true if fdst and fsrc point to the same underlying Fs
func Same(fdst, fsrc Fs) bool {
return fdst.Name() == fsrc.Name() && fdst.Root() == fsrc.Root()
}
@ -396,7 +398,7 @@ func FsSame(fdst, fsrc Fs) bool {
//
// If DoMove is true then files will be moved instead of copied
func syncCopyMove(fdst, fsrc Fs, Delete bool, DoMove bool) error {
if FsSame(fdst, fsrc) {
if Same(fdst, fsrc) {
ErrorLog(fdst, "Nothing to do as source and destination are the same")
return nil
}
@ -414,22 +416,22 @@ func syncCopyMove(fdst, fsrc Fs, Delete bool, DoMove bool) error {
delFiles := readFilesMap(fdst)
// Read source files checking them off against dest files
to_be_checked := make(ObjectPairChan, Config.Transfers)
to_be_uploaded := make(ObjectPairChan, Config.Transfers)
toBeChecked := make(ObjectPairChan, Config.Transfers)
toBeUploaded := make(ObjectPairChan, Config.Transfers)
var checkerWg sync.WaitGroup
checkerWg.Add(Config.Checkers)
for i := 0; i < Config.Checkers; i++ {
go PairChecker(to_be_checked, to_be_uploaded, &checkerWg)
go PairChecker(toBeChecked, toBeUploaded, &checkerWg)
}
var copierWg sync.WaitGroup
copierWg.Add(Config.Transfers)
for i := 0; i < Config.Transfers; i++ {
if DoMove {
go PairMover(to_be_uploaded, fdst, &copierWg)
go PairMover(toBeUploaded, fdst, &copierWg)
} else {
go PairCopier(to_be_uploaded, fdst, &copierWg)
go PairCopier(toBeUploaded, fdst, &copierWg)
}
}
@ -439,18 +441,18 @@ func syncCopyMove(fdst, fsrc Fs, Delete bool, DoMove bool) error {
dst, found := delFiles[remote]
if found {
delete(delFiles, remote)
to_be_checked <- ObjectPair{src, dst}
toBeChecked <- ObjectPair{src, dst}
} else {
// No need to check since doesn't exist
to_be_uploaded <- ObjectPair{src, nil}
toBeUploaded <- ObjectPair{src, nil}
}
}
close(to_be_checked)
close(toBeChecked)
}()
Log(fdst, "Waiting for checks to finish")
checkerWg.Wait()
close(to_be_uploaded)
close(toBeUploaded)
Log(fdst, "Waiting for transfers to finish")
copierWg.Wait()
@ -474,19 +476,19 @@ func syncCopyMove(fdst, fsrc Fs, Delete bool, DoMove bool) error {
return nil
}
// Syncs fsrc into fdst
// Sync fsrc into fdst
func Sync(fdst, fsrc Fs) error {
return syncCopyMove(fdst, fsrc, true, false)
}
// Copies fsrc into fdst
// CopyDir copies fsrc into fdst
func CopyDir(fdst, fsrc Fs) error {
return syncCopyMove(fdst, fsrc, false, false)
}
// Moves fsrc into fdst
// MoveDir moves fsrc into fdst
func MoveDir(fdst, fsrc Fs) error {
if FsSame(fdst, fsrc) {
if Same(fdst, fsrc) {
ErrorLog(fdst, "Nothing to do as source and destination are the same")
return nil
}
@ -517,7 +519,7 @@ func MoveDir(fdst, fsrc Fs) error {
return Purge(fsrc)
}
// Checks the files in fsrc and fdst according to Size and MD5SUM
// Check the files in fsrc and fdst according to Size and MD5SUM
func Check(fdst, fsrc Fs) error {
Log(fdst, "Building file list")
@ -597,7 +599,7 @@ func Check(fdst, fsrc Fs) error {
return nil
}
// List the Fs to the supplied function
// ListFn lists the Fs to the supplied function
//
// Lists in parallel which may get them out of order
func ListFn(f Fs, fn func(Object)) error {
@ -639,7 +641,7 @@ func List(f Fs, w io.Writer) error {
})
}
// List the Fs to the supplied writer
// ListLong lists the Fs to the supplied writer
//
// Shows size, mod time and path
//
@ -653,7 +655,7 @@ func ListLong(f Fs, w io.Writer) error {
})
}
// List the Fs to the supplied writer
// Md5sum list the Fs to the supplied writer
//
// Produces the same output as the md5sum command
//
@ -671,7 +673,7 @@ func Md5sum(f Fs, w io.Writer) error {
})
}
// List the directories/buckets/containers in the Fs to the supplied writer
// ListDir lists the directories/buckets/containers in the Fs to the supplied writer
func ListDir(f Fs, w io.Writer) error {
for dir := range f.ListDir() {
syncFprintf(w, "%12d %13s %9d %s\n", dir.Bytes, dir.When.Format("2006-01-02 15:04:05"), dir.Count, dir.Name)
@ -679,7 +681,7 @@ func ListDir(f Fs, w io.Writer) error {
return nil
}
// Makes a destination directory or container
// Mkdir makes a destination directory or container
func Mkdir(f Fs) error {
err := f.Mkdir()
if err != nil {
@ -689,7 +691,7 @@ func Mkdir(f Fs) error {
return nil
}
// Removes a container but not if not empty
// Rmdir removes a container but not if not empty
func Rmdir(f Fs) error {
if Config.DryRun {
Log(f, "Not deleting as dry run is set")
@ -703,7 +705,7 @@ func Rmdir(f Fs) error {
return nil
}
// Removes a container and all of its contents
// Purge removes a container and all of its contents
//
// FIXME doesn't delete local directories
func Purge(f Fs) error {

View File

@ -1,3 +1,4 @@
package fs
// Version of rclone
const Version = "v1.20"

View File

@ -1,4 +1,4 @@
// Utilities for testing the Fs
// Package fstest provides utilities for testing the Fs
package fstest
// FIXME put name of test FS in Fs structure
@ -22,7 +22,7 @@ func init() {
}
// Represents an item for checking
// Item represents an item for checking
type Item struct {
Path string
Md5sum string
@ -31,7 +31,8 @@ type Item struct {
WinPath string
}
// Checks the times are equal within the precision, returns the delta and a flag
// CheckTimeEqualWithPrecision checks the times are equal within the
// precision, returns the delta and a flag
func CheckTimeEqualWithPrecision(t0, t1 time.Time, precision time.Duration) (time.Duration, bool) {
dt := t0.Sub(t1)
if dt >= precision || dt <= -precision {
@ -40,7 +41,7 @@ func CheckTimeEqualWithPrecision(t0, t1 time.Time, precision time.Duration) (tim
return dt, true
}
// check the mod time to the given precision
// CheckModTime checks the mod time to the given precision
func (i *Item) CheckModTime(t *testing.T, obj fs.Object, modTime time.Time, precision time.Duration) {
dt, ok := CheckTimeEqualWithPrecision(modTime, i.ModTime, precision)
if !ok {
@ -48,6 +49,7 @@ func (i *Item) CheckModTime(t *testing.T, obj fs.Object, modTime time.Time, prec
}
}
// Check checks all the attributes of the object are correct
func (i *Item) Check(t *testing.T, obj fs.Object, precision time.Duration) {
if obj == nil {
t.Fatalf("Object is nil")
@ -66,14 +68,14 @@ func (i *Item) Check(t *testing.T, obj fs.Object, precision time.Duration) {
i.CheckModTime(t, obj, obj.ModTime(), precision)
}
// Represents all items for checking
// Items represents all items for checking
type Items struct {
byName map[string]*Item
byNameAlt map[string]*Item
items []Item
}
// Make an Items
// NewItems makes an Items
func NewItems(items []Item) *Items {
is := &Items{
byName: make(map[string]*Item),
@ -88,7 +90,7 @@ func NewItems(items []Item) *Items {
return is
}
// Check off an item
// Find checks off an item
func (is *Items) Find(t *testing.T, obj fs.Object, precision time.Duration) {
i, ok := is.byName[obj.Remote()]
if !ok {
@ -103,7 +105,7 @@ func (is *Items) Find(t *testing.T, obj fs.Object, precision time.Duration) {
i.Check(t, obj, precision)
}
// Check all done
// Done checks all finished
func (is *Items) Done(t *testing.T) {
if len(is.byName) != 0 {
for name := range is.byName {
@ -113,7 +115,8 @@ func (is *Items) Done(t *testing.T) {
}
}
// Checks the fs to see if it has the expected contents
// CheckListingWithPrecision checks the fs to see if it has the
// expected contents with the given precision.
func CheckListingWithPrecision(t *testing.T, f fs.Fs, items []Item, precision time.Duration) {
is := NewItems(items)
oldErrors := fs.Stats.GetErrors()
@ -143,13 +146,13 @@ func CheckListingWithPrecision(t *testing.T, f fs.Fs, items []Item, precision ti
}
}
// Checks the fs to see if it has the expected contents
// CheckListing checks the fs to see if it has the expected contents
func CheckListing(t *testing.T, f fs.Fs, items []Item) {
precision := f.Precision()
CheckListingWithPrecision(t, f, items, precision)
}
// Parse a time string or explode
// Time parses a time string or logs a fatal error
func Time(timeString string) time.Time {
t, err := time.Parse(time.RFC3339Nano, timeString)
if err != nil {
@ -158,7 +161,7 @@ func Time(timeString string) time.Time {
return t
}
// Create a random string
// RandomString create a random string for test purposes
func RandomString(n int) string {
source := "abcdefghijklmnopqrstuvwxyz0123456789"
out := make([]byte, n)
@ -168,7 +171,7 @@ func RandomString(n int) string {
return string(out)
}
// Creates a temporary directory name for local remotes
// LocalRemote creates a temporary directory name for local remotes
func LocalRemote() (path string, err error) {
path, err = ioutil.TempDir("", "rclone")
if err == nil {
@ -179,7 +182,7 @@ func LocalRemote() (path string, err error) {
return
}
// Make a random bucket or subdirectory name
// RandomRemoteName makes a random bucket or subdirectory name
//
// Returns a random remote name plus the leaf name
func RandomRemoteName(remoteName string) (string, string, error) {
@ -202,7 +205,7 @@ func RandomRemoteName(remoteName string) (string, string, error) {
return remoteName, leafName, nil
}
// Make a random bucket or subdirectory on the remote
// RandomRemote makes a random bucket or subdirectory on the remote
//
// Call the finalise function returned to Purge the fs at the end (and
// the parent if necessary)
@ -241,6 +244,7 @@ func RandomRemote(remoteName string, subdir bool) (fs.Fs, func(), error) {
return remote, finalise, nil
}
// TestMkdir tests Mkdir works
func TestMkdir(t *testing.T, remote fs.Fs) {
err := fs.Mkdir(remote)
if err != nil {
@ -249,6 +253,7 @@ func TestMkdir(t *testing.T, remote fs.Fs) {
CheckListing(t, remote, []Item{})
}
// TestPurge tests Purge works
func TestPurge(t *testing.T, remote fs.Fs) {
err := fs.Purge(remote)
if err != nil {
@ -257,6 +262,7 @@ func TestPurge(t *testing.T, remote fs.Fs) {
CheckListing(t, remote, []Item{})
}
// TestRmdir tests Rmdir works
func TestRmdir(t *testing.T, remote fs.Fs) {
err := fs.Rmdir(remote)
if err != nil {

View File

@ -1,9 +1,9 @@
// Generic tests for testing the Fs and Object interfaces
// Package fstests provides generic tests for testing the Fs and Object interfaces
//
// Run go generate to write the tests for the remotes
package fstests
//go:generate go run gen_tests.go
package fstests
import (
"bytes"
@ -23,9 +23,11 @@ import (
var (
remote fs.Fs
// RemoteName should be set to the name of the remote for testing
RemoteName = ""
subRemoteName = ""
subRemoteLeaf = ""
// NilObject should be set to a nil Object from the Fs under test
NilObject fs.Object
file1 = fstest.Item{
ModTime: fstest.Time("2001-02-03T04:05:06.499999999Z"),
@ -42,6 +44,7 @@ func init() {
flag.StringVar(&RemoteName, "remote", "", "Set this to override the default remote name (eg s3:)")
}
// TestInit tests basic intitialisation
func TestInit(t *testing.T) {
var err error
fs.LoadConfig()
@ -60,7 +63,7 @@ func TestInit(t *testing.T) {
}
remote, err = fs.NewFs(subRemoteName)
if err == fs.NotFoundInConfigFile {
if err == fs.ErrorNotFoundInConfigFile {
log.Printf("Didn't find %q in config file - skipping tests", RemoteName)
return
}
@ -76,8 +79,7 @@ func skipIfNotOk(t *testing.T) {
}
}
// String returns a description of the FS
// TestFsString tests the String method
func TestFsString(t *testing.T) {
skipIfNotOk(t)
str := remote.String()
@ -86,18 +88,13 @@ func TestFsString(t *testing.T) {
}
}
type TestFile struct {
ModTime time.Time
Path string
Size int64
Md5sum string
}
// TestFsRmdirEmpty tests deleting an empty directory
func TestFsRmdirEmpty(t *testing.T) {
skipIfNotOk(t)
fstest.TestRmdir(t, remote)
}
// TestFsRmdirNotFound tests deleting a non existent directory
func TestFsRmdirNotFound(t *testing.T) {
skipIfNotOk(t)
err := remote.Rmdir()
@ -106,17 +103,20 @@ func TestFsRmdirNotFound(t *testing.T) {
}
}
// TestFsMkdir tests tests making a directory
func TestFsMkdir(t *testing.T) {
skipIfNotOk(t)
fstest.TestMkdir(t, remote)
fstest.TestMkdir(t, remote)
}
// TestFsListEmpty tests listing an empty directory
func TestFsListEmpty(t *testing.T) {
skipIfNotOk(t)
fstest.CheckListing(t, remote, []fstest.Item{})
}
// TestFsListDirEmpty tests listing the directories from an empty directory
func TestFsListDirEmpty(t *testing.T) {
skipIfNotOk(t)
for obj := range remote.ListDir() {
@ -124,6 +124,7 @@ func TestFsListDirEmpty(t *testing.T) {
}
}
// TestFsNewFsObjectNotFound tests not finding a object
func TestFsNewFsObjectNotFound(t *testing.T) {
skipIfNotOk(t)
if remote.NewFsObject("potato") != nil {
@ -156,16 +157,19 @@ func testPut(t *testing.T, file *fstest.Item) {
file.Check(t, obj, remote.Precision())
}
// TestFsPutFile1 tests putting a file
func TestFsPutFile1(t *testing.T) {
skipIfNotOk(t)
testPut(t, &file1)
}
// TestFsPutFile2 tests putting a file into a subdirectory
func TestFsPutFile2(t *testing.T) {
skipIfNotOk(t)
testPut(t, &file2)
}
// TestFsListDirFile2 tests the files are correctly uploaded
func TestFsListDirFile2(t *testing.T) {
skipIfNotOk(t)
found := false
@ -181,6 +185,7 @@ func TestFsListDirFile2(t *testing.T) {
}
}
// TestFsListDirRoot tests that DirList works in the root
func TestFsListDirRoot(t *testing.T) {
skipIfNotOk(t)
rootRemote, err := fs.NewFs(RemoteName)
@ -198,6 +203,7 @@ func TestFsListDirRoot(t *testing.T) {
}
}
// TestFsListRoot tests List works in the root
func TestFsListRoot(t *testing.T) {
skipIfNotOk(t)
rootRemote, err := fs.NewFs(RemoteName)
@ -237,22 +243,26 @@ func TestFsListRoot(t *testing.T) {
t.Errorf("Didn't find %q (%v) and %q (%v) or no files (count %d)", f1, found1, f2, found2, count)
}
// TestFsListFile1 tests file present
func TestFsListFile1(t *testing.T) {
skipIfNotOk(t)
fstest.CheckListing(t, remote, []fstest.Item{file1, file2})
}
// TestFsNewFsObject tests NewFsObject
func TestFsNewFsObject(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
file1.Check(t, obj, remote.Precision())
}
// TestFsListFile1and2 tests two files present
func TestFsListFile1and2(t *testing.T) {
skipIfNotOk(t)
fstest.CheckListing(t, remote, []fstest.Item{file1, file2})
}
// TestFsCopy tests Copy
func TestFsCopy(t *testing.T) {
skipIfNotOk(t)
@ -288,6 +298,7 @@ func TestFsCopy(t *testing.T) {
}
// TestFsMove tests Move
func TestFsMove(t *testing.T) {
skipIfNotOk(t)
@ -333,6 +344,8 @@ func TestFsMove(t *testing.T) {
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
// TestFsDirMove tests DirMove
func TestFsDirMove(t *testing.T) {
skipIfNotOk(t)
@ -377,6 +390,7 @@ func TestFsDirMove(t *testing.T) {
fstest.CheckListing(t, newRemote, []fstest.Item{})
}
// TestFsRmdirFull tests removing a non empty directory
func TestFsRmdirFull(t *testing.T) {
skipIfNotOk(t)
err := remote.Rmdir()
@ -385,6 +399,7 @@ func TestFsRmdirFull(t *testing.T) {
}
}
// TestFsPrecision tests the Precision of the Fs
func TestFsPrecision(t *testing.T) {
skipIfNotOk(t)
precision := remote.Precision()
@ -397,6 +412,7 @@ func TestFsPrecision(t *testing.T) {
// FIXME check expected precision
}
// TestObjectString tests the Object String method
func TestObjectString(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -411,6 +427,7 @@ func TestObjectString(t *testing.T) {
}
}
// TestObjectFs tests the object can be found
func TestObjectFs(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -419,6 +436,7 @@ func TestObjectFs(t *testing.T) {
}
}
// TestObjectRemote tests the Remote is correct
func TestObjectRemote(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -427,6 +445,7 @@ func TestObjectRemote(t *testing.T) {
}
}
// TestObjectMd5sum tests the MD5SUM of the object is correct
func TestObjectMd5sum(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -439,12 +458,14 @@ func TestObjectMd5sum(t *testing.T) {
}
}
// TestObjectModTime tests the ModTime of the object is correct
func TestObjectModTime(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
file1.CheckModTime(t, obj, obj.ModTime(), remote.Precision())
}
// TestObjectSetModTime tests that SetModTime works
func TestObjectSetModTime(t *testing.T) {
skipIfNotOk(t)
newModTime := fstest.Time("2011-12-13T14:15:16.999999999Z")
@ -456,6 +477,7 @@ func TestObjectSetModTime(t *testing.T) {
TestObjectModTime(t)
}
// TestObjectSize tests that Size works
func TestObjectSize(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -464,6 +486,7 @@ func TestObjectSize(t *testing.T) {
}
}
// TestObjectOpen tests that Open works
func TestObjectOpen(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -489,6 +512,7 @@ func TestObjectOpen(t *testing.T) {
}
}
// TestObjectUpdate tests that Update works
func TestObjectUpdate(t *testing.T) {
skipIfNotOk(t)
buf := bytes.NewBufferString(fstest.RandomString(200))
@ -508,6 +532,7 @@ func TestObjectUpdate(t *testing.T) {
file1.Check(t, obj, remote.Precision())
}
// TestObjectStorable tests that Storable works
func TestObjectStorable(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -516,6 +541,7 @@ func TestObjectStorable(t *testing.T) {
}
}
// TestLimitedFs tests that a LimitedFs is created
func TestLimitedFs(t *testing.T) {
skipIfNotOk(t)
remoteName := subRemoteName + "/" + file2.Path
@ -532,6 +558,7 @@ func TestLimitedFs(t *testing.T) {
}
}
// TestLimitedFsNotFound tests that a LimitedFs is not created if no object
func TestLimitedFsNotFound(t *testing.T) {
skipIfNotOk(t)
remoteName := subRemoteName + "/not found.txt"
@ -546,6 +573,7 @@ func TestLimitedFsNotFound(t *testing.T) {
}
}
// TestObjectRemove tests Remove
func TestObjectRemove(t *testing.T) {
skipIfNotOk(t)
obj := findObject(t, file1.Path)
@ -556,6 +584,7 @@ func TestObjectRemove(t *testing.T) {
fstest.CheckListing(t, remote, []fstest.Item{file2})
}
// TestObjectPurge tests Purge
func TestObjectPurge(t *testing.T) {
skipIfNotOk(t)
fstest.TestPurge(t, remote)
@ -565,6 +594,7 @@ func TestObjectPurge(t *testing.T) {
}
}
// TestFinalise tidies up after the previous tests
func TestFinalise(t *testing.T) {
skipIfNotOk(t)
if strings.HasPrefix(RemoteName, "/") {

View File

@ -1,4 +1,4 @@
// Google Cloud Storage interface
// Package googlecloudstorage provides an interface to Google Cloud Storage
package googlecloudstorage
/*
@ -55,7 +55,7 @@ var (
// Register with Fs
func init() {
fs.Register(&fs.FsInfo{
fs.Register(&fs.Info{
Name: "google cloud storage",
NewFs: NewFs,
Config: func(name string) {
@ -144,12 +144,12 @@ type FsObjectStorage struct {
// ------------------------------------------------------------
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
func (f *FsStorage) Name() string {
return f.name
}
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
func (f *FsStorage) Root() string {
if f.root == "" {
return f.bucket
@ -254,7 +254,7 @@ func (f *FsStorage) newFsObjectWithInfo(remote string, info *storage.Object) fs.
return o
}
// Return an FsObject from a path
// NewFsObject returns an FsObject from a path
//
// May return nil if an error occurred
func (f *FsStorage) NewFsObject(remote string) fs.Object {
@ -302,7 +302,7 @@ func (f *FsStorage) list(directories bool, fn func(string, *storage.Object)) {
}
}
// Walk the path returning a channel of FsObjects
// List walks the path returning a channel of FsObjects
func (f *FsStorage) List() fs.ObjectsChan {
out := make(fs.ObjectsChan, fs.Config.Checkers)
if f.bucket == "" {
@ -324,7 +324,7 @@ func (f *FsStorage) List() fs.ObjectsChan {
return out
}
// Lists the buckets
// ListDir lists the buckets
func (f *FsStorage) ListDir() fs.DirChan {
out := make(fs.DirChan, fs.Config.Checkers)
if f.bucket == "" {
@ -412,8 +412,8 @@ func (f *FsStorage) Rmdir() error {
return f.svc.Buckets.Delete(f.bucket).Do()
}
// Return the precision
func (fs *FsStorage) Precision() time.Duration {
// Precision returns the precision
func (f *FsStorage) Precision() time.Duration {
return time.Nanosecond
}
@ -451,7 +451,7 @@ func (f *FsStorage) Copy(src fs.Object, remote string) (fs.Object, error) {
// ------------------------------------------------------------
// Return the parent Fs
// Fs returns the parent Fs
func (o *FsObjectStorage) Fs() fs.Fs {
return o.storage
}
@ -464,7 +464,7 @@ func (o *FsObjectStorage) String() string {
return o.remote
}
// Return the remote path
// Remote returns the remote path
func (o *FsObjectStorage) Remote() string {
return o.remote
}
@ -499,9 +499,8 @@ func (o *FsObjectStorage) setMetaData(info *storage.Object) {
if err == nil {
o.modTime = modTime
return
} else {
fs.Debug(o, "Failed to read mtime from metadata: %s", err)
}
fs.Debug(o, "Failed to read mtime from metadata: %s", err)
}
// Fallback to the Updated time
@ -549,7 +548,7 @@ func metadataFromModTime(modTime time.Time) map[string]string {
return metadata
}
// Sets the modification time of the local fs object
// SetModTime sets the modification time of the local fs object
func (o *FsObjectStorage) SetModTime(modTime time.Time) {
// This only adds metadata so will perserve other metadata
object := storage.Object{
@ -565,7 +564,7 @@ func (o *FsObjectStorage) SetModTime(modTime time.Time) {
o.setMetaData(newObject)
}
// Is this object storable
// Storable returns a boolean as to whether this object is storable
func (o *FsObjectStorage) Storable() bool {
return true
}

View File

@ -1,4 +1,4 @@
// Local filesystem interface
// Package local provides a filesystem interface
package local
import (
@ -10,19 +10,19 @@ import (
"io/ioutil"
"os"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
"time"
"unicode/utf8"
"github.com/ncw/rclone/fs"
"regexp"
"runtime"
"strings"
)
// Register with Fs
func init() {
fs.Register(&fs.FsInfo{
fs.Register(&fs.Info{
Name: "local",
NewFs: NewFs,
})
@ -71,12 +71,12 @@ func NewFs(name, root string) (fs.Fs, error) {
return f, nil
}
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
func (f *FsLocal) Name() string {
return f.name
}
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
func (f *FsLocal) Root() string {
return f.root
}
@ -110,7 +110,7 @@ func (f *FsLocal) newFsObjectWithInfo(remote string, info os.FileInfo) fs.Object
return o
}
// Return an FsObject from a path
// NewFsObject returns an FsObject from a path
//
// May return nil if an error occurred
func (f *FsLocal) NewFsObject(remote string) fs.Object {
@ -195,7 +195,7 @@ func (f *FsLocal) cleanUtf8(name string) string {
return name
}
// Walk the path returning a channel of FsObjects
// ListDir walks the path returning a channel of FsObjects
func (f *FsLocal) ListDir() fs.DirChan {
out := make(fs.DirChan, fs.Config.Checkers)
go func() {
@ -220,7 +220,7 @@ func (f *FsLocal) ListDir() fs.DirChan {
fs.Stats.Error()
fs.ErrorLog(f, "Failed to open directory: %s: %s", path, err)
} else {
dir.Count += 1
dir.Count++
dir.Bytes += fi.Size()
}
return nil
@ -238,7 +238,7 @@ func (f *FsLocal) ListDir() fs.DirChan {
return out
}
// Puts the FsObject to the local filesystem
// Put the FsObject to the local filesystem
func (f *FsLocal) Put(in io.Reader, remote string, modTime time.Time, size int64) (fs.Object, error) {
// Temporary FsObject under construction - info filled in by Update()
o := f.newFsObject(remote)
@ -262,7 +262,7 @@ func (f *FsLocal) Rmdir() error {
return os.Remove(f.root)
}
// Return the precision
// Precision of the file system
func (f *FsLocal) Precision() (precision time.Duration) {
f.precisionOk.Do(func() {
f.precision = f.readPrecision()
@ -347,7 +347,7 @@ func (f *FsLocal) Purge() error {
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantMove
func (dstFs *FsLocal) Move(src fs.Object, remote string) (fs.Object, error) {
func (f *FsLocal) Move(src fs.Object, remote string) (fs.Object, error) {
srcObj, ok := src.(*FsObjectLocal)
if !ok {
fs.Debug(src, "Can't move - not same remote type")
@ -355,7 +355,7 @@ func (dstFs *FsLocal) Move(src fs.Object, remote string) (fs.Object, error) {
}
// Temporary FsObject under construction
dstObj := dstFs.newFsObject(remote)
dstObj := f.newFsObject(remote)
// Check it is a file if it exists
err := dstObj.lstat()
@ -389,14 +389,15 @@ func (dstFs *FsLocal) Move(src fs.Object, remote string) (fs.Object, error) {
return dstObj, nil
}
// Move src to this remote using server side move operations.
// DirMove moves src directory to this remote using server side move
// operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (dstFs *FsLocal) DirMove(src fs.Fs) error {
func (f *FsLocal) DirMove(src fs.Fs) error {
srcFs, ok := src.(*FsLocal)
if !ok {
fs.Debug(srcFs, "Can't move directory - not same remote type")
@ -413,18 +414,18 @@ func (dstFs *FsLocal) DirMove(src fs.Fs) error {
}
// Check if destination exists
_, err = os.Lstat(dstFs.root)
_, err = os.Lstat(f.root)
if !os.IsNotExist(err) {
return fs.ErrorDirExists
}
// Do the move
return os.Rename(srcFs.root, dstFs.root)
return os.Rename(srcFs.root, f.root)
}
// ------------------------------------------------------------
// Return the parent Fs
// Fs returns the parent Fs
func (o *FsObjectLocal) Fs() fs.Fs {
return o.local
}
@ -437,7 +438,7 @@ func (o *FsObjectLocal) String() string {
return o.remote
}
// Return the remote path
// Remote returns the remote path
func (o *FsObjectLocal) Remote() string {
return o.local.cleanUtf8(o.remote)
}
@ -480,7 +481,7 @@ func (o *FsObjectLocal) ModTime() time.Time {
return o.info.ModTime()
}
// Sets the modification time of the local fs object
// SetModTime sets the modification time of the local fs object
func (o *FsObjectLocal) SetModTime(modTime time.Time) {
err := os.Chtimes(o.path, modTime, modTime)
if err != nil {
@ -495,7 +496,7 @@ func (o *FsObjectLocal) SetModTime(modTime time.Time) {
}
}
// Is this object storable
// Storable returns a boolean showing if this object is storable
func (o *FsObjectLocal) Storable() bool {
mode := o.info.Mode()
if mode&(os.ModeSymlink|os.ModeNamedPipe|os.ModeSocket|os.ModeDevice) != 0 {

View File

@ -210,24 +210,24 @@ func Config(name string, config *oauth2.Config) error {
return err
}
state := fmt.Sprintf("%x", stateBytes)
authUrl := config.AuthCodeURL(state)
authURL := config.AuthCodeURL(state)
// Prepare webserver
server := authServer{
state: state,
bindAddress: bindAddress,
authUrl: authUrl,
authURL: authURL,
}
if useWebServer {
server.code = make(chan string, 1)
go server.Start()
defer server.Stop()
authUrl = "http://" + bindAddress + "/auth"
authURL = "http://" + bindAddress + "/auth"
}
// Generate a URL for the user to visit for authorization.
_ = open.Start(authUrl)
fmt.Printf("If your browser doesn't open automatically go to the following link: %s\n", authUrl)
_ = open.Start(authURL)
fmt.Printf("If your browser doesn't open automatically go to the following link: %s\n", authURL)
fmt.Printf("Log in and authorize rclone for access\n")
var authCode string
@ -258,7 +258,7 @@ type authServer struct {
listener net.Listener
bindAddress string
code chan string
authUrl string
authURL string
}
// startWebServer runs an internal web server to receive config details
@ -274,7 +274,7 @@ func (s *authServer) Start() {
return
})
mux.HandleFunc("/auth", func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, s.authUrl, 307)
http.Redirect(w, req, s.authURL, 307)
return
})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {

View File

@ -35,6 +35,7 @@ var (
retries = pflag.IntP("retries", "", 3, "Retry operations this many times if they fail")
)
// Command holds info about the current running command
type Command struct {
Name string
Help string
@ -59,6 +60,7 @@ func (cmd *Command) checkArgs(args []string) {
}
}
// Commands is a slice of possible Command~s
var Commands = []Command{
{
Name: "copy",
@ -249,7 +251,7 @@ func fatal(message string, args ...interface{}) {
os.Exit(1)
}
// Parse the command line flags
// ParseFlags parses the command line flags
func ParseFlags() {
pflag.Usage = syntaxError
pflag.Parse()
@ -272,7 +274,7 @@ func ParseFlags() {
}
}
// Parse the command from the command line
// ParseCommand parses the command from the command line
func ParseCommand() (*Command, []string) {
args := pflag.Args()
if len(args) < 1 {
@ -318,7 +320,7 @@ func ParseCommand() (*Command, []string) {
return command, args
}
// Create a Fs from a name
// NewFs creates a Fs from a name
func NewFs(remote string) fs.Fs {
f, err := fs.NewFs(remote)
if err != nil {
@ -328,7 +330,7 @@ func NewFs(remote string) fs.Fs {
return f
}
// Print the stats every statsInterval
// StartStats prints the stats every statsInterval
func StartStats() {
if *statsInterval <= 0 {
return

View File

@ -1,4 +1,4 @@
// S3 interface
// Package s3 provides an interface to Amazon S3 oject storage
package s3
// FIXME need to prevent anything but ListDir working for s3://
@ -35,7 +35,7 @@ import (
// Register with Fs
func init() {
fs.Register(&fs.FsInfo{
fs.Register(&fs.Info{
Name: "s3",
NewFs: NewFs,
// AWS endpoints: http://docs.amazonwebservices.com/general/latest/gr/rande.html#s3_region
@ -153,12 +153,12 @@ type FsObjectS3 struct {
// ------------------------------------------------------------
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
func (f *FsS3) Name() string {
return f.name
}
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
func (f *FsS3) Root() string {
if f.root == "" {
return f.bucket
@ -192,15 +192,15 @@ func s3ParsePath(path string) (bucket, directory string, err error) {
// s3Connection makes a connection to s3
func s3Connection(name string) (*s3.S3, error) {
// Make the auth
accessKeyId := fs.ConfigFile.MustValue(name, "access_key_id")
if accessKeyId == "" {
accessKeyID := fs.ConfigFile.MustValue(name, "access_key_id")
if accessKeyID == "" {
return nil, errors.New("access_key_id not found")
}
secretAccessKey := fs.ConfigFile.MustValue(name, "secret_access_key")
if secretAccessKey == "" {
return nil, errors.New("secret_access_key not found")
}
auth := credentials.NewStaticCredentials(accessKeyId, secretAccessKey, "")
auth := credentials.NewStaticCredentials(accessKeyID, secretAccessKey, "")
endpoint := fs.ConfigFile.MustValue(name, "endpoint")
region := fs.ConfigFile.MustValue(name, "region")
@ -226,7 +226,7 @@ func s3Connection(name string) (*s3.S3, error) {
if req.Service.Config.Credentials == credentials.AnonymousCredentials {
return
}
sign(accessKeyId, secretAccessKey, req.HTTPRequest)
sign(accessKeyID, secretAccessKey, req.HTTPRequest)
}
c.Handlers.Sign.Clear()
c.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
@ -239,7 +239,7 @@ func s3Connection(name string) (*s3.S3, error) {
return c, nil
}
// NewFsS3 contstructs an FsS3 from the path, bucket:path
// NewFs contstructs an FsS3 from the path, bucket:path
func NewFs(name, root string) (fs.Fs, error) {
bucket, directory, err := s3ParsePath(root)
if err != nil {
@ -310,7 +310,7 @@ func (f *FsS3) newFsObjectWithInfo(remote string, info *s3.Object) fs.Object {
return o
}
// Return an FsObject from a path
// NewFsObject returns an FsObject from a path
//
// May return nil if an error occurred
func (f *FsS3) NewFsObject(remote string) fs.Object {
@ -384,7 +384,7 @@ func (f *FsS3) list(directories bool, fn func(string, *s3.Object)) {
}
}
// Walk the path returning a channel of FsObjects
// List walks the path returning a channel of FsObjects
func (f *FsS3) List() fs.ObjectsChan {
out := make(fs.ObjectsChan, fs.Config.Checkers)
if f.bucket == "" {
@ -405,7 +405,7 @@ func (f *FsS3) List() fs.ObjectsChan {
return out
}
// Lists the buckets
// ListDir lists the buckets
func (f *FsS3) ListDir() fs.DirChan {
out := make(fs.DirChan, fs.Config.Checkers)
if f.bucket == "" {
@ -486,7 +486,7 @@ func (f *FsS3) Rmdir() error {
return err
}
// Return the precision
// Precision of the remote
func (f *FsS3) Precision() time.Duration {
return time.Nanosecond
}
@ -524,7 +524,7 @@ func (f *FsS3) Copy(src fs.Object, remote string) (fs.Object, error) {
// ------------------------------------------------------------
// Return the parent Fs
// Fs returns the parent Fs
func (o *FsObjectS3) Fs() fs.Fs {
return o.s3
}
@ -537,7 +537,7 @@ func (o *FsObjectS3) String() string {
return o.remote
}
// Return the remote path
// Remote returns the remote path
func (o *FsObjectS3) Remote() string {
return o.remote
}
@ -619,7 +619,7 @@ func (o *FsObjectS3) ModTime() time.Time {
return modTime
}
// Sets the modification time of the local fs object
// SetModTime sets the modification time of the local fs object
func (o *FsObjectS3) SetModTime(modTime time.Time) {
err := o.readMetaData()
if err != nil {
@ -648,7 +648,7 @@ func (o *FsObjectS3) SetModTime(modTime time.Time) {
}
}
// Is this object storable
// Storable raturns a boolean indicating if this object is storable
func (o *FsObjectS3) Storable() bool {
return true
}

View File

@ -1,4 +1,4 @@
// Swift interface
// Package swift provides an interface to the Swift object storage system
package swift
import (
@ -16,7 +16,7 @@ import (
// Register with Fs
func init() {
fs.Register(&fs.FsInfo{
fs.Register(&fs.Info{
Name: "swift",
NewFs: NewFs,
Options: []fs.Option{{
@ -76,12 +76,12 @@ type FsObjectSwift struct {
// ------------------------------------------------------------
// The name of the remote (as passed into NewFs)
// Name of the remote (as passed into NewFs)
func (f *FsSwift) Name() string {
return f.name
}
// The root of the remote (as passed into NewFs)
// Root of the remote (as passed into NewFs)
func (f *FsSwift) Root() string {
if f.root == "" {
return f.container
@ -122,14 +122,14 @@ func swiftConnection(name string) (*swift.Connection, error) {
if apiKey == "" {
return nil, errors.New("key not found")
}
authUrl := fs.ConfigFile.MustValue(name, "auth")
if authUrl == "" {
authURL := fs.ConfigFile.MustValue(name, "auth")
if authURL == "" {
return nil, errors.New("auth not found")
}
c := &swift.Connection{
UserName: userName,
ApiKey: apiKey,
AuthUrl: authUrl,
AuthUrl: authURL,
UserAgent: fs.UserAgent,
Tenant: fs.ConfigFile.MustValue(name, "tenant"),
Region: fs.ConfigFile.MustValue(name, "region"),
@ -201,7 +201,7 @@ func (f *FsSwift) newFsObjectWithInfo(remote string, info *swift.Object) fs.Obje
return fs
}
// Return an FsObject from a path
// NewFsObject returns an FsObject from a path
//
// May return nil if an error occurred
func (f *FsSwift) NewFsObject(remote string) fs.Object {
@ -249,7 +249,7 @@ func (f *FsSwift) list(directories bool, fn func(string, *swift.Object)) {
}
}
// Walk the path returning a channel of FsObjects
// List walks the path returning a channel of FsObjects
func (f *FsSwift) List() fs.ObjectsChan {
out := make(fs.ObjectsChan, fs.Config.Checkers)
if f.container == "" {
@ -271,7 +271,7 @@ func (f *FsSwift) List() fs.ObjectsChan {
return out
}
// Lists the containers
// ListDir lists the containers
func (f *FsSwift) ListDir() fs.DirChan {
out := make(fs.DirChan, fs.Config.Checkers)
if f.container == "" {
@ -331,8 +331,8 @@ func (f *FsSwift) Rmdir() error {
return f.c.ContainerDelete(f.container)
}
// Return the precision
func (fs *FsSwift) Precision() time.Duration {
// Precision of the remote
func (f *FsSwift) Precision() time.Duration {
return time.Nanosecond
}
@ -361,7 +361,7 @@ func (f *FsSwift) Copy(src fs.Object, remote string) (fs.Object, error) {
// ------------------------------------------------------------
// Return the parent Fs
// Fs returns the parent Fs
func (o *FsObjectSwift) Fs() fs.Fs {
return o.swift
}
@ -374,7 +374,7 @@ func (o *FsObjectSwift) String() string {
return o.remote
}
// Return the remote path
// Remote returns the remote path
func (o *FsObjectSwift) Remote() string {
return o.remote
}
@ -426,7 +426,7 @@ func (o *FsObjectSwift) ModTime() time.Time {
return modTime
}
// Sets the modification time of the local fs object
// SetModTime sets the modification time of the local fs object
func (o *FsObjectSwift) SetModTime(modTime time.Time) {
err := o.readMetaData()
if err != nil {
@ -442,7 +442,7 @@ func (o *FsObjectSwift) SetModTime(modTime time.Time) {
}
}
// Is this object storable
// Storable returns if this object is storable
func (o *FsObjectSwift) Storable() bool {
return true
}