From fd1ca2dfe8d3e5828dbf83996e0d53ab5a6d3d35 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 7 Feb 2024 15:00:23 +0000 Subject: [PATCH] fs: allow Metadata calls to be called with Directory or Object This involved adding the Fs() method to DirEntry as it is needed in the metadata mapper. Unspecialised fs.Dir objects will return a new fs.Unknown from their Fs() methods as they are not specific to any given Fs. --- fs/dir.go | 8 ++++++++ fs/list/list_test.go | 1 + fs/metadata.go | 10 +++++----- fs/mimetype.go | 2 +- fs/types.go | 31 ++++++++++++++++++++++++++++--- 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/fs/dir.go b/fs/dir.go index c55bcea23..5830c6f38 100644 --- a/fs/dir.go +++ b/fs/dir.go @@ -7,6 +7,7 @@ import ( // Dir describes an unspecialized directory for directory/container/bucket lists type Dir struct { + f Info // Fs this directory is part of remote string // name of the directory modTime time.Time // modification or creation time - IsZero for unknown size int64 // size of directory and contents or -1 if unknown @@ -20,6 +21,7 @@ type Dir struct { // If the modTime is unknown pass in time.Time{} func NewDir(remote string, modTime time.Time) *Dir { return &Dir{ + f: Unknown, remote: remote, modTime: modTime, size: -1, @@ -30,6 +32,7 @@ func NewDir(remote string, modTime time.Time) *Dir { // NewDirCopy creates an unspecialized copy of the Directory object passed in func NewDirCopy(ctx context.Context, d Directory) *Dir { return &Dir{ + f: d.Fs(), remote: d.Remote(), modTime: d.ModTime(ctx), size: d.Size(), @@ -38,6 +41,11 @@ func NewDirCopy(ctx context.Context, d Directory) *Dir { } } +// Fs returns the Fs that this directory is part of +func (d *Dir) Fs() Info { + return d.f +} + // String returns the name func (d *Dir) String() string { return d.remote diff --git a/fs/list/list_test.go b/fs/list/list_test.go index 59312d898..616271746 100644 --- a/fs/list/list_test.go +++ b/fs/list/list_test.go @@ -87,6 +87,7 @@ func TestFilterAndSortCheckDirRoot(t *testing.T) { type unknownDirEntry string +func (o unknownDirEntry) Fs() fs.Info { return fs.Unknown } func (o unknownDirEntry) String() string { return string(o) } func (o unknownDirEntry) Remote() string { return string(o) } func (o unknownDirEntry) ModTime(ctx context.Context) (t time.Time) { return t } diff --git a/fs/metadata.go b/fs/metadata.go index 19b07cb63..919e7862a 100644 --- a/fs/metadata.go +++ b/fs/metadata.go @@ -63,10 +63,10 @@ func (m *Metadata) MergeOptions(options []OpenOption) { } } -// GetMetadata from an ObjectInfo +// GetMetadata from an DirEntry // // If the object has no metadata then metadata will be nil -func GetMetadata(ctx context.Context, o ObjectInfo) (metadata Metadata, err error) { +func GetMetadata(ctx context.Context, o DirEntry) (metadata Metadata, err error) { do, ok := o.(Metadataer) if !ok { return nil, nil @@ -91,7 +91,7 @@ type mapItem struct { // This runs an external program on the metadata which can be used to // map it from one form to another. -func metadataMapper(ctx context.Context, cmdLine SpaceSepList, dstFs Fs, o ObjectInfo, metadata Metadata) (newMetadata Metadata, err error) { +func metadataMapper(ctx context.Context, cmdLine SpaceSepList, dstFs Fs, o DirEntry, metadata Metadata) (newMetadata Metadata, err error) { ci := GetConfig(ctx) cmd := exec.Command(cmdLine[0], cmdLine[1:]...) in := mapItem{ @@ -145,14 +145,14 @@ func metadataMapper(ctx context.Context, cmdLine SpaceSepList, dstFs Fs, o Objec return out.Metadata, nil } -// GetMetadataOptions from an ObjectInfo and merge it with any in options +// GetMetadataOptions from an DirEntry and merge it with any in options // // If --metadata isn't in use it will return nil. // // If the object has no metadata then metadata will be nil. // // This should be passed the destination Fs for the metadata mapper -func GetMetadataOptions(ctx context.Context, dstFs Fs, o ObjectInfo, options []OpenOption) (metadata Metadata, err error) { +func GetMetadataOptions(ctx context.Context, dstFs Fs, o DirEntry, options []OpenOption) (metadata Metadata, err error) { ci := GetConfig(ctx) if !ci.Metadata { return nil, nil diff --git a/fs/mimetype.go b/fs/mimetype.go index 4ea9aab2a..a0bfcd9fe 100644 --- a/fs/mimetype.go +++ b/fs/mimetype.go @@ -54,7 +54,7 @@ func MimeTypeFromName(remote string) (mimeType string) { // MimeType returns the MimeType from the object, either by calling // the MimeTyper interface or using MimeTypeFromName -func MimeType(ctx context.Context, o ObjectInfo) (mimeType string) { +func MimeType(ctx context.Context, o DirEntry) (mimeType string) { // Read the MimeType from the optional interface if available if do, ok := o.(MimeTyper); ok { mimeType = do.MimeType(ctx) diff --git a/fs/types.go b/fs/types.go index 16afe79d8..a709f628b 100644 --- a/fs/types.go +++ b/fs/types.go @@ -102,9 +102,6 @@ type Object interface { type ObjectInfo interface { DirEntry - // Fs returns read only access to the Fs that this object is part of - Fs() Info - // Hash returns the selected checksum of the file // If no checksum is available it returns "" Hash(ctx context.Context, ty hash.Type) (string, error) @@ -117,6 +114,9 @@ type ObjectInfo interface { // a Dir or Object. These are returned from directory listings - type // assert them into the correct type. type DirEntry interface { + // Fs returns read only access to the Fs that this object is part of + Fs() Info + // String returns a description of the Object String() string @@ -332,3 +332,28 @@ type WriterAtCloser interface { io.WriterAt io.Closer } + +type unknownFs struct{} + +// Name of the remote (as passed into NewFs) +func (unknownFs) Name() string { return "unknown" } + +// Root of the remote (as passed into NewFs) +func (unknownFs) Root() string { return "" } + +// String returns a description of the FS +func (unknownFs) String() string { return "unknown" } + +// Precision of the ModTimes in this Fs +func (unknownFs) Precision() time.Duration { return ModTimeNotSupported } + +// Returns the supported hash types of the filesystem +func (unknownFs) Hashes() hash.Set { return hash.Set(hash.None) } + +// Features returns the optional features of this Fs +func (unknownFs) Features() *Features { return &Features{} } + +// Unknown holds an Info for an unknown Fs +// +// This is used when we need an Fs but don't have one. +var Unknown Info = unknownFs{}