mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 16:34:30 +01:00
fs: implement MetadataInfo to show info about metadata in help and rc
Info about this will appear in operations/fsinfo and in the backend help (`rclone help backend s3`).
This commit is contained in:
parent
6a0e021dac
commit
0652ec95db
25
cmd/help.go
25
cmd/help.go
@ -6,6 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
@ -362,4 +363,28 @@ func showBackend(name string) {
|
|||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if backend.MetadataInfo != nil {
|
||||||
|
fmt.Printf("### Metadata\n\n")
|
||||||
|
fmt.Printf("%s\n\n", strings.TrimSpace(backend.MetadataInfo.Help))
|
||||||
|
if len(backend.MetadataInfo.System) > 0 {
|
||||||
|
fmt.Printf("Here are the possible system metadata items for the %s backend.\n\n", backend.Name)
|
||||||
|
keys := []string{}
|
||||||
|
for k := range backend.MetadataInfo.System {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
fmt.Printf("| Name | Help | Type | Example | Read Only |\n")
|
||||||
|
fmt.Printf("|------|------|------|---------|-----------|\n")
|
||||||
|
for _, k := range keys {
|
||||||
|
v := backend.MetadataInfo.System[k]
|
||||||
|
ro := "N"
|
||||||
|
if v.ReadOnly {
|
||||||
|
ro = "**Y**"
|
||||||
|
}
|
||||||
|
fmt.Printf("| %s | %s | %s | %s | %s |\n", k, v.Help, v.Type, v.Example, ro)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
fmt.Printf("See the [metadata](/docs/#metadata) docs for more info.\n\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,20 @@ import "context"
|
|||||||
// See docs/content/metadata.md for the interpretation of the keys
|
// See docs/content/metadata.md for the interpretation of the keys
|
||||||
type Metadata map[string]string
|
type Metadata map[string]string
|
||||||
|
|
||||||
|
// MetadataHelp represents help for a bit of system metadata
|
||||||
|
type MetadataHelp struct {
|
||||||
|
Help string
|
||||||
|
Type string
|
||||||
|
Example string
|
||||||
|
ReadOnly bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadataInfo is help for the whole metadata for this backend.
|
||||||
|
type MetadataInfo struct {
|
||||||
|
System map[string]MetadataHelp
|
||||||
|
Help string
|
||||||
|
}
|
||||||
|
|
||||||
// Set k to v on m
|
// Set k to v on m
|
||||||
//
|
//
|
||||||
// If m is nil, then it will get made
|
// If m is nil, then it will get made
|
||||||
|
@ -2278,21 +2278,30 @@ type FsInfo struct {
|
|||||||
|
|
||||||
// Features returns the optional features of this Fs
|
// Features returns the optional features of this Fs
|
||||||
Features map[string]bool
|
Features map[string]bool
|
||||||
|
|
||||||
|
// MetadataInfo returns info about the metadata for this backend
|
||||||
|
MetadataInfo *fs.MetadataInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFsInfo gets the information (FsInfo) about a given Fs
|
// GetFsInfo gets the information (FsInfo) about a given Fs
|
||||||
func GetFsInfo(f fs.Fs) *FsInfo {
|
func GetFsInfo(f fs.Fs) *FsInfo {
|
||||||
|
features := f.Features()
|
||||||
info := &FsInfo{
|
info := &FsInfo{
|
||||||
Name: f.Name(),
|
Name: f.Name(),
|
||||||
Root: f.Root(),
|
Root: f.Root(),
|
||||||
String: f.String(),
|
String: f.String(),
|
||||||
Precision: f.Precision(),
|
Precision: f.Precision(),
|
||||||
Hashes: make([]string, 0, 4),
|
Hashes: make([]string, 0, 4),
|
||||||
Features: f.Features().Enabled(),
|
Features: features.Enabled(),
|
||||||
|
MetadataInfo: nil,
|
||||||
}
|
}
|
||||||
for _, hashType := range f.Hashes().Array() {
|
for _, hashType := range f.Hashes().Array() {
|
||||||
info.Hashes = append(info.Hashes, hashType.String())
|
info.Hashes = append(info.Hashes, hashType.String())
|
||||||
}
|
}
|
||||||
|
fsInfo, _, _, _, err := fs.ParseRemote(fs.ConfigString(f))
|
||||||
|
if err == nil && fsInfo != nil && fsInfo.MetadataInfo != nil {
|
||||||
|
info.MetadataInfo = fsInfo.MetadataInfo
|
||||||
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,46 +413,103 @@ This returns info about the remote passed in;
|
|||||||
|
|
||||||
` + "```" + `
|
` + "```" + `
|
||||||
{
|
{
|
||||||
// optional features and whether they are available or not
|
// optional features and whether they are available or not
|
||||||
"Features": {
|
"Features": {
|
||||||
"About": true,
|
"About": true,
|
||||||
"BucketBased": false,
|
"BucketBased": false,
|
||||||
"CanHaveEmptyDirectories": true,
|
"BucketBasedRootOK": false,
|
||||||
"CaseInsensitive": false,
|
"CanHaveEmptyDirectories": true,
|
||||||
"ChangeNotify": false,
|
"CaseInsensitive": false,
|
||||||
"CleanUp": false,
|
"ChangeNotify": false,
|
||||||
"Copy": false,
|
"CleanUp": false,
|
||||||
"DirCacheFlush": false,
|
"Command": true,
|
||||||
"DirMove": true,
|
"Copy": false,
|
||||||
"DuplicateFiles": false,
|
"DirCacheFlush": false,
|
||||||
"GetTier": false,
|
"DirMove": true,
|
||||||
"ListR": false,
|
"Disconnect": false,
|
||||||
"MergeDirs": false,
|
"DuplicateFiles": false,
|
||||||
"Move": true,
|
"GetTier": false,
|
||||||
"OpenWriterAt": true,
|
"IsLocal": true,
|
||||||
"PublicLink": false,
|
"ListR": false,
|
||||||
"Purge": true,
|
"MergeDirs": false,
|
||||||
"PutStream": true,
|
"MetadataInfo": true,
|
||||||
"PutUnchecked": false,
|
"Move": true,
|
||||||
"ReadMimeType": false,
|
"OpenWriterAt": true,
|
||||||
"ServerSideAcrossConfigs": false,
|
"PublicLink": false,
|
||||||
"SetTier": false,
|
"Purge": true,
|
||||||
"SetWrapper": false,
|
"PutStream": true,
|
||||||
"UnWrap": false,
|
"PutUnchecked": false,
|
||||||
"WrapFs": false,
|
"ReadMetadata": true,
|
||||||
"WriteMimeType": false
|
"ReadMimeType": false,
|
||||||
},
|
"ServerSideAcrossConfigs": false,
|
||||||
// Names of hashes available
|
"SetTier": false,
|
||||||
"Hashes": [
|
"SetWrapper": false,
|
||||||
"MD5",
|
"Shutdown": false,
|
||||||
"SHA-1",
|
"SlowHash": true,
|
||||||
"DropboxHash",
|
"SlowModTime": false,
|
||||||
"QuickXorHash"
|
"UnWrap": false,
|
||||||
],
|
"UserInfo": false,
|
||||||
"Name": "local", // Name as created
|
"UserMetadata": true,
|
||||||
"Precision": 1, // Precision of timestamps in ns
|
"WrapFs": false,
|
||||||
"Root": "/", // Path as created
|
"WriteMetadata": true,
|
||||||
"String": "Local file system at /" // how the remote will appear in logs
|
"WriteMimeType": false
|
||||||
|
},
|
||||||
|
// Names of hashes available
|
||||||
|
"Hashes": [
|
||||||
|
"md5",
|
||||||
|
"sha1",
|
||||||
|
"whirlpool",
|
||||||
|
"crc32",
|
||||||
|
"sha256",
|
||||||
|
"dropbox",
|
||||||
|
"mailru",
|
||||||
|
"quickxor"
|
||||||
|
],
|
||||||
|
"Name": "local", // Name as created
|
||||||
|
"Precision": 1, // Precision of timestamps in ns
|
||||||
|
"Root": "/", // Path as created
|
||||||
|
"String": "Local file system at /", // how the remote will appear in logs
|
||||||
|
// Information about the system metadata for this backend
|
||||||
|
"MetadataInfo": {
|
||||||
|
"System": {
|
||||||
|
"atime": {
|
||||||
|
"Help": "Time of last access",
|
||||||
|
"Type": "RFC 3339",
|
||||||
|
"Example": "2006-01-02T15:04:05.999999999Z07:00"
|
||||||
|
},
|
||||||
|
"btime": {
|
||||||
|
"Help": "Time of file birth (creation)",
|
||||||
|
"Type": "RFC 3339",
|
||||||
|
"Example": "2006-01-02T15:04:05.999999999Z07:00"
|
||||||
|
},
|
||||||
|
"gid": {
|
||||||
|
"Help": "Group ID of owner",
|
||||||
|
"Type": "decimal number",
|
||||||
|
"Example": "500"
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"Help": "File type and mode",
|
||||||
|
"Type": "octal, unix style",
|
||||||
|
"Example": "0100664"
|
||||||
|
},
|
||||||
|
"mtime": {
|
||||||
|
"Help": "Time of last modification",
|
||||||
|
"Type": "RFC 3339",
|
||||||
|
"Example": "2006-01-02T15:04:05.999999999Z07:00"
|
||||||
|
},
|
||||||
|
"rdev": {
|
||||||
|
"Help": "Device ID (if special file)",
|
||||||
|
"Type": "hexadecimal",
|
||||||
|
"Example": "1abc"
|
||||||
|
},
|
||||||
|
"uid": {
|
||||||
|
"Help": "User ID of owner",
|
||||||
|
"Type": "decimal number",
|
||||||
|
"Example": "500"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Help": "Textual help string\n"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
` + "```" + `
|
` + "```" + `
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ type RegInfo struct {
|
|||||||
Aliases []string
|
Aliases []string
|
||||||
// Hide - if set don't show in the configurator
|
// Hide - if set don't show in the configurator
|
||||||
Hide bool
|
Hide bool
|
||||||
|
// MetadataInfo help about the metadata in use in this backend
|
||||||
|
MetadataInfo *MetadataInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileName returns the on disk file name for this backend
|
// FileName returns the on disk file name for this backend
|
||||||
|
@ -1384,8 +1384,13 @@ func Run(t *testing.T, opt *Opt) {
|
|||||||
skipIfNotOk(t)
|
skipIfNotOk(t)
|
||||||
features := f.Features()
|
features := f.Features()
|
||||||
obj := findObject(ctx, t, f, file1.Path)
|
obj := findObject(ctx, t, f, file1.Path)
|
||||||
do, ok := obj.(fs.Metadataer)
|
do, objectHasMetadata := obj.(fs.Metadataer)
|
||||||
if !ok {
|
if objectHasMetadata || features.ReadMetadata || features.WriteMetadata || features.UserMetadata {
|
||||||
|
fsInfo, _, _, _, err := fs.ParseRemote(fs.ConfigString(f))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, fsInfo.MetadataInfo, "Object declares metadata support but no MetadataInfo in RegInfo")
|
||||||
|
}
|
||||||
|
if !objectHasMetadata {
|
||||||
require.False(t, features.ReadMetadata, "Features.ReadMetadata is set but Object.Metadata method not found")
|
require.False(t, features.ReadMetadata, "Features.ReadMetadata is set but Object.Metadata method not found")
|
||||||
t.Skip("Metadata method not supported")
|
t.Skip("Metadata method not supported")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user