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.
This commit is contained in:
Nick Craig-Wood 2024-02-07 15:00:23 +00:00
parent e1032f693f
commit fd1ca2dfe8
5 changed files with 43 additions and 9 deletions

View File

@ -7,6 +7,7 @@ import (
// Dir describes an unspecialized directory for directory/container/bucket lists // Dir describes an unspecialized directory for directory/container/bucket lists
type Dir struct { type Dir struct {
f Info // Fs this directory is part of
remote string // name of the directory remote string // name of the directory
modTime time.Time // modification or creation time - IsZero for unknown modTime time.Time // modification or creation time - IsZero for unknown
size int64 // size of directory and contents or -1 if 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{} // If the modTime is unknown pass in time.Time{}
func NewDir(remote string, modTime time.Time) *Dir { func NewDir(remote string, modTime time.Time) *Dir {
return &Dir{ return &Dir{
f: Unknown,
remote: remote, remote: remote,
modTime: modTime, modTime: modTime,
size: -1, 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 // NewDirCopy creates an unspecialized copy of the Directory object passed in
func NewDirCopy(ctx context.Context, d Directory) *Dir { func NewDirCopy(ctx context.Context, d Directory) *Dir {
return &Dir{ return &Dir{
f: d.Fs(),
remote: d.Remote(), remote: d.Remote(),
modTime: d.ModTime(ctx), modTime: d.ModTime(ctx),
size: d.Size(), 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 // String returns the name
func (d *Dir) String() string { func (d *Dir) String() string {
return d.remote return d.remote

View File

@ -87,6 +87,7 @@ func TestFilterAndSortCheckDirRoot(t *testing.T) {
type unknownDirEntry string type unknownDirEntry string
func (o unknownDirEntry) Fs() fs.Info { return fs.Unknown }
func (o unknownDirEntry) String() string { return string(o) } func (o unknownDirEntry) String() string { return string(o) }
func (o unknownDirEntry) Remote() string { return string(o) } func (o unknownDirEntry) Remote() string { return string(o) }
func (o unknownDirEntry) ModTime(ctx context.Context) (t time.Time) { return t } func (o unknownDirEntry) ModTime(ctx context.Context) (t time.Time) { return t }

View File

@ -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 // 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) do, ok := o.(Metadataer)
if !ok { if !ok {
return nil, nil return nil, nil
@ -91,7 +91,7 @@ type mapItem struct {
// This runs an external program on the metadata which can be used to // This runs an external program on the metadata which can be used to
// map it from one form to another. // 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) ci := GetConfig(ctx)
cmd := exec.Command(cmdLine[0], cmdLine[1:]...) cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
in := mapItem{ in := mapItem{
@ -145,14 +145,14 @@ func metadataMapper(ctx context.Context, cmdLine SpaceSepList, dstFs Fs, o Objec
return out.Metadata, nil 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 --metadata isn't in use it will return nil.
// //
// If the object has no metadata then metadata will be nil. // If the object has no metadata then metadata will be nil.
// //
// This should be passed the destination Fs for the metadata mapper // 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) ci := GetConfig(ctx)
if !ci.Metadata { if !ci.Metadata {
return nil, nil return nil, nil

View File

@ -54,7 +54,7 @@ func MimeTypeFromName(remote string) (mimeType string) {
// MimeType returns the MimeType from the object, either by calling // MimeType returns the MimeType from the object, either by calling
// the MimeTyper interface or using MimeTypeFromName // 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 // Read the MimeType from the optional interface if available
if do, ok := o.(MimeTyper); ok { if do, ok := o.(MimeTyper); ok {
mimeType = do.MimeType(ctx) mimeType = do.MimeType(ctx)

View File

@ -102,9 +102,6 @@ type Object interface {
type ObjectInfo interface { type ObjectInfo interface {
DirEntry 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 // Hash returns the selected checksum of the file
// If no checksum is available it returns "" // If no checksum is available it returns ""
Hash(ctx context.Context, ty hash.Type) (string, error) 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 // a Dir or Object. These are returned from directory listings - type
// assert them into the correct type. // assert them into the correct type.
type DirEntry interface { 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 returns a description of the Object
String() string String() string
@ -332,3 +332,28 @@ type WriterAtCloser interface {
io.WriterAt io.WriterAt
io.Closer 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{}