Merge branch 'main' into v2
* main: feat(fs, config): add support for custom filesystem type construction (#9887) build(deps): update dependencies (#10020)
This commit is contained in:
@@ -111,6 +111,7 @@ func TestDefaultValues(t *testing.T) {
|
||||
AutoNormalize: true,
|
||||
MinDiskFree: size,
|
||||
Versioning: VersioningConfiguration{
|
||||
FSType: FilesystemTypeBasic,
|
||||
CleanupIntervalS: 3600,
|
||||
Params: map[string]string{},
|
||||
},
|
||||
@@ -518,7 +519,8 @@ func TestIssue1750(t *testing.T) {
|
||||
|
||||
func TestFolderPath(t *testing.T) {
|
||||
folder := FolderConfiguration{
|
||||
Path: "~/tmp",
|
||||
FilesystemType: FilesystemTypeBasic,
|
||||
Path: "~/tmp",
|
||||
}
|
||||
|
||||
realPath := folder.Filesystem().URI()
|
||||
|
||||
@@ -8,47 +8,30 @@ package config
|
||||
|
||||
import "github.com/syncthing/syncthing/lib/fs"
|
||||
|
||||
type FilesystemType int32
|
||||
type FilesystemType string
|
||||
|
||||
const (
|
||||
FilesystemTypeBasic FilesystemType = 0
|
||||
FilesystemTypeFake FilesystemType = 1
|
||||
FilesystemTypeBasic FilesystemType = "basic"
|
||||
FilesystemTypeFake FilesystemType = "fake"
|
||||
)
|
||||
|
||||
func (t FilesystemType) String() string {
|
||||
switch t {
|
||||
case FilesystemTypeBasic:
|
||||
return "basic"
|
||||
case FilesystemTypeFake:
|
||||
return "fake"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
func (t FilesystemType) ToFS() fs.FilesystemType {
|
||||
return fs.FilesystemType(string(t))
|
||||
}
|
||||
|
||||
func (t FilesystemType) ToFS() fs.FilesystemType {
|
||||
switch t {
|
||||
case FilesystemTypeBasic:
|
||||
return fs.FilesystemTypeBasic
|
||||
case FilesystemTypeFake:
|
||||
return fs.FilesystemTypeFake
|
||||
default:
|
||||
return fs.FilesystemTypeBasic
|
||||
}
|
||||
func (t FilesystemType) String() string {
|
||||
return string(t)
|
||||
}
|
||||
|
||||
func (t FilesystemType) MarshalText() ([]byte, error) {
|
||||
return []byte(t.String()), nil
|
||||
return []byte(t), nil
|
||||
}
|
||||
|
||||
func (t *FilesystemType) UnmarshalText(bs []byte) error {
|
||||
switch string(bs) {
|
||||
case "basic":
|
||||
*t = FilesystemTypeBasic
|
||||
case "fake":
|
||||
*t = FilesystemTypeFake
|
||||
default:
|
||||
*t = FilesystemTypeBasic
|
||||
}
|
||||
*t = FilesystemType(string(bs))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *FilesystemType) ParseDefault(str string) error {
|
||||
return t.UnmarshalText([]byte(str))
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ type FolderDeviceConfiguration struct {
|
||||
type FolderConfiguration struct {
|
||||
ID string `json:"id" xml:"id,attr" nodefault:"true"`
|
||||
Label string `json:"label" xml:"label,attr" restart:"false"`
|
||||
FilesystemType FilesystemType `json:"filesystemType" xml:"filesystemType"`
|
||||
FilesystemType FilesystemType `json:"filesystemType" xml:"filesystemType" default:"basic"`
|
||||
Path string `json:"path" xml:"path,attr" default:"~"`
|
||||
Type FolderType `json:"type" xml:"type,attr"`
|
||||
Devices []FolderDeviceConfiguration `json:"devices" xml:"device"`
|
||||
|
||||
@@ -20,7 +20,7 @@ type VersioningConfiguration struct {
|
||||
Params map[string]string `json:"params" xml:"parameter" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
CleanupIntervalS int `json:"cleanupIntervalS" xml:"cleanupIntervalS" default:"3600"`
|
||||
FSPath string `json:"fsPath" xml:"fsPath"`
|
||||
FSType FilesystemType `json:"fsType" xml:"fsType"`
|
||||
FSType FilesystemType `json:"fsType" xml:"fsType" default:"basic"`
|
||||
}
|
||||
|
||||
func (c *VersioningConfiguration) Reset() {
|
||||
@@ -33,7 +33,7 @@ type internalVersioningConfiguration struct {
|
||||
Params []internalParam `xml:"param"`
|
||||
CleanupIntervalS int `xml:"cleanupIntervalS" default:"3600"`
|
||||
FSPath string `xml:"fsPath"`
|
||||
FSType FilesystemType `xml:"fsType"`
|
||||
FSType FilesystemType `xml:"fsType" default:"basic"`
|
||||
}
|
||||
|
||||
type internalParam struct {
|
||||
|
||||
@@ -19,6 +19,8 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
)
|
||||
|
||||
const FilesystemTypeBasic FilesystemType = "basic"
|
||||
|
||||
var (
|
||||
errInvalidFilenameEmpty = errors.New("name is invalid, must not be empty")
|
||||
errInvalidFilenameWindowsSpacePeriod = errors.New("name is invalid, must not end in space or period on Windows")
|
||||
@@ -56,6 +58,12 @@ type (
|
||||
groupCache = valueCache[string, *user.Group]
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterFilesystemType(FilesystemTypeBasic, func(root string, opts ...Option) (Filesystem, error) {
|
||||
return newBasicFilesystem(root, opts...), nil
|
||||
})
|
||||
}
|
||||
|
||||
func newBasicFilesystem(root string, opts ...Option) *BasicFilesystem {
|
||||
if root == "" {
|
||||
root = "." // Otherwise "" becomes "/" below
|
||||
|
||||
@@ -26,6 +26,14 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
const FilesystemTypeFake FilesystemType = "fake"
|
||||
|
||||
func init() {
|
||||
RegisterFilesystemType(FilesystemTypeFake, func(root string, opts ...Option) (Filesystem, error) {
|
||||
return newFakeFilesystem(root, opts...), nil
|
||||
})
|
||||
}
|
||||
|
||||
// see readShortAt()
|
||||
const randomBlockShift = 14 // 128k
|
||||
|
||||
|
||||
+14
-19
@@ -9,6 +9,7 @@ package fs
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -215,17 +216,6 @@ func IsPermission(err error) bool {
|
||||
// IsPathSeparator is the equivalent of os.IsPathSeparator
|
||||
var IsPathSeparator = os.IsPathSeparator
|
||||
|
||||
// Option modifies a filesystem at creation. An option might be specific
|
||||
// to a filesystem-type.
|
||||
//
|
||||
// String is used to detect options with the same effect, i.e. must be different
|
||||
// for options with different effects. Meaning if an option has parameters, a
|
||||
// representation of those must be part of the returned string.
|
||||
type Option interface {
|
||||
String() string
|
||||
apply(Filesystem) Filesystem
|
||||
}
|
||||
|
||||
func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem {
|
||||
var caseOpt Option
|
||||
var mtimeOpt Option
|
||||
@@ -246,18 +236,23 @@ func NewFilesystem(fsType FilesystemType, uri string, opts ...Option) Filesystem
|
||||
}
|
||||
opts = opts[:i]
|
||||
|
||||
// Construct file system using the registered factory function
|
||||
var fs Filesystem
|
||||
switch fsType {
|
||||
case FilesystemTypeBasic:
|
||||
fs = newBasicFilesystem(uri, opts...)
|
||||
case FilesystemTypeFake:
|
||||
fs = newFakeFilesystem(uri, opts...)
|
||||
default:
|
||||
l.Debugln("Unknown filesystem", fsType, uri)
|
||||
var err error
|
||||
filesystemFactoriesMutex.Lock()
|
||||
fsFactory, factoryFound := filesystemFactories[fsType]
|
||||
filesystemFactoriesMutex.Unlock()
|
||||
if factoryFound {
|
||||
fs, err = fsFactory(uri, opts...)
|
||||
} else {
|
||||
err = fmt.Errorf("File system type '%s' not recognized", fsType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fs = &errorFilesystem{
|
||||
fsType: fsType,
|
||||
uri: uri,
|
||||
err: errors.New("filesystem with type " + fsType.String() + " does not exist."),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-14
@@ -6,20 +6,34 @@
|
||||
|
||||
package fs
|
||||
|
||||
type FilesystemType int32
|
||||
import "sync"
|
||||
|
||||
const (
|
||||
FilesystemTypeBasic FilesystemType = 0
|
||||
FilesystemTypeFake FilesystemType = 1
|
||||
)
|
||||
type FilesystemType string
|
||||
|
||||
func (t FilesystemType) String() string {
|
||||
switch t {
|
||||
case FilesystemTypeBasic:
|
||||
return "basic"
|
||||
case FilesystemTypeFake:
|
||||
return "fake"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
// Option modifies a filesystem at creation. An option might be specific
|
||||
// to a filesystem-type.
|
||||
//
|
||||
// String is used to detect options with the same effect, i.e. must be different
|
||||
// for options with different effects. Meaning if an option has parameters, a
|
||||
// representation of those must be part of the returned string.
|
||||
type Option interface {
|
||||
String() string
|
||||
apply(Filesystem) Filesystem
|
||||
}
|
||||
|
||||
// Factory function type for constructing a custom file system. It takes the URI
|
||||
// and options as its parameters.
|
||||
type FilesystemFactory func(string, ...Option) (Filesystem, error)
|
||||
|
||||
// For each registered file system type, a function to construct a file system.
|
||||
var filesystemFactories map[FilesystemType]FilesystemFactory = make(map[FilesystemType]FilesystemFactory)
|
||||
var filesystemFactoriesMutex sync.Mutex = sync.Mutex{}
|
||||
|
||||
// Register a function to be called when a filesystem is to be constructed with
|
||||
// the specified fsType. The function will receive the URI for the file system as well
|
||||
// as all options.
|
||||
func RegisterFilesystemType(fsType FilesystemType, fn FilesystemFactory) {
|
||||
filesystemFactoriesMutex.Lock()
|
||||
defer filesystemFactoriesMutex.Unlock()
|
||||
filesystemFactories[fsType] = fn
|
||||
}
|
||||
|
||||
@@ -2773,9 +2773,10 @@ func TestIssue4903(t *testing.T) {
|
||||
folderPath := "nonexistent"
|
||||
cfg := defaultCfgWrapper.RawCopy()
|
||||
fcfg := config.FolderConfiguration{
|
||||
ID: "folder1",
|
||||
Path: folderPath,
|
||||
Paused: true,
|
||||
ID: "folder1",
|
||||
Path: folderPath,
|
||||
FilesystemType: config.FilesystemTypeBasic,
|
||||
Paused: true,
|
||||
Devices: []config.FolderDeviceConfiguration{
|
||||
{DeviceID: device1},
|
||||
},
|
||||
|
||||
@@ -677,7 +677,7 @@ func TestStopWalk(t *testing.T) {
|
||||
|
||||
// Use an errorFs as the backing fs for the rest of the interface
|
||||
// The way we get it is a bit hacky tho.
|
||||
errorFs := fs.NewFilesystem(fs.FilesystemType(-1), ".")
|
||||
errorFs := fs.NewFilesystem(fs.FilesystemType("error"), ".")
|
||||
fs := fs.NewWalkFilesystem(&infiniteFS{errorFs, 100, 100, 1e6})
|
||||
|
||||
const numHashers = 4
|
||||
|
||||
@@ -74,7 +74,7 @@ func (v external) Archive(filePath string) error {
|
||||
}
|
||||
|
||||
context := map[string]string{
|
||||
"%FOLDER_FILESYSTEM%": v.filesystem.Type().String(),
|
||||
"%FOLDER_FILESYSTEM%": string(v.filesystem.Type()),
|
||||
"%FOLDER_PATH%": v.filesystem.URI(),
|
||||
"%FILE_PATH%": filePath,
|
||||
}
|
||||
|
||||
@@ -139,10 +139,12 @@ func TestCreateVersionPath(t *testing.T) {
|
||||
}
|
||||
|
||||
folderCfg := config.FolderConfiguration{
|
||||
ID: "default",
|
||||
Path: tmpDir,
|
||||
ID: "default",
|
||||
FilesystemType: config.FilesystemTypeBasic,
|
||||
Path: tmpDir,
|
||||
Versioning: config.VersioningConfiguration{
|
||||
Type: "staggered",
|
||||
FSType: config.FilesystemTypeBasic,
|
||||
FSPath: versionsDir,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user