diff options
author | Arthur Axel 'fREW' Schmidt <frioux@gmail.com> | 2014-06-06 22:10:15 -0500 |
---|---|---|
committer | Jakob Borg <jakob@nym.se> | 2014-06-08 07:16:25 +0200 |
commit | 82cfd37263fc64a902fd3ad7e0afdd5acf31c322 (patch) | |
tree | 244c13654c3b7aff4732424b0ce307db0800d1fa /config | |
parent | df381fd03fb8b399c66b22133c2fe1647a1edc03 (diff) |
Allow prioritization of downloads based on name (fixes #174)
Diffstat (limited to 'config')
-rw-r--r-- | config/config.go | 59 | ||||
-rw-r--r-- | config/config_test.go | 96 |
2 files changed, 148 insertions, 7 deletions
diff --git a/config/config.go b/config/config.go index 2c8b755513..54d3512fdb 100644 --- a/config/config.go +++ b/config/config.go @@ -11,10 +11,12 @@ import ( "io" "os" "reflect" + "regexp" "sort" "strconv" "strings" + "github.com/calmh/syncthing/scanner" "code.google.com/p/go.crypto/bcrypt" "github.com/calmh/syncthing/logger" ) @@ -30,14 +32,42 @@ type Configuration struct { XMLName xml.Name `xml:"configuration" json:"-"` } +// SyncOrderPattern allows a user to prioritize file downloading based on a +// regular expression. If a file matches the Pattern the Priority will be +// assigned to the file. If a file matches more than one Pattern the +// Priorities are summed. This allows a user to, for example, prioritize files +// in a directory, as well as prioritize based on file type. The higher the +// priority the "sooner" a file will be downloaded. Files can be deprioritized +// by giving them a negative priority. While Priority is represented as an +// integer, the expected range is something like -1000 to 1000. +type SyncOrderPattern struct { + Pattern string `xml:"pattern,attr"` + Priority int `xml:"priority,attr"` + compiledPattern *regexp.Regexp +} + +func (s *SyncOrderPattern) CompiledPattern() *regexp.Regexp { + if s.compiledPattern == nil { + re, err := regexp.Compile(s.Pattern) + if err != nil { + l.Warnln("Could not compile regexp (" + s.Pattern + "): " + err.Error()) + s.compiledPattern = regexp.MustCompile("^\\0$") + } else { + s.compiledPattern = re + } + } + return s.compiledPattern +} + type RepositoryConfiguration struct { - ID string `xml:"id,attr"` - Directory string `xml:"directory,attr"` - Nodes []NodeConfiguration `xml:"node"` - ReadOnly bool `xml:"ro,attr"` - IgnorePerms bool `xml:"ignorePerms,attr"` - Invalid string `xml:"-"` // Set at runtime when there is an error, not saved - Versioning VersioningConfiguration `xml:"versioning"` + ID string `xml:"id,attr"` + Directory string `xml:"directory,attr"` + Nodes []NodeConfiguration `xml:"node"` + ReadOnly bool `xml:"ro,attr"` + IgnorePerms bool `xml:"ignorePerms,attr"` + Invalid string `xml:"-"` // Set at runtime when there is an error, not saved + Versioning VersioningConfiguration `xml:"versioning"` + SyncOrderPatterns []SyncOrderPattern `xml:"syncorder>pattern"` nodeIDs []string } @@ -92,6 +122,21 @@ func (r *RepositoryConfiguration) NodeIDs() []string { return r.nodeIDs } +func (r RepositoryConfiguration) FileRanker() func(scanner.File) int { + if len(r.SyncOrderPatterns) <= 0 { + return nil + } + return func(f scanner.File) int { + ret := 0 + for _, v := range r.SyncOrderPatterns { + if v.CompiledPattern().MatchString(f.Name) { + ret += v.Priority + } + } + return ret + } +} + type NodeConfiguration struct { NodeID string `xml:"id,attr"` Name string `xml:"name,attr,omitempty"` diff --git a/config/config_test.go b/config/config_test.go index dd876d5252..58f364a2dd 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -10,6 +10,9 @@ import ( "os" "reflect" "testing" + + "github.com/calmh/syncthing/files" + "github.com/calmh/syncthing/scanner" ) func TestDefaultValues(t *testing.T) { @@ -281,3 +284,96 @@ func TestStripNodeIs(t *testing.T) { } } } + +func TestSyncOrders(t *testing.T) { + data := []byte(` +<configuration version="2"> + <node id="AAAA-BBBB-CCCC"> + <address>dynamic</address> + </node> + <repository directory="~/Sync"> + <syncorder> + <pattern pattern="\.jpg$" priority="1" /> + </syncorder> + <node id="AAAA-BBBB-CCCC" name=""></node> + </repository> +</configuration> +`) + + expected := []SyncOrderPattern{ + { + Pattern: "\\.jpg$", + Priority: 1, + }, + } + + cfg, err := Load(bytes.NewReader(data), "n4") + if err != nil { + t.Error(err) + } + + for i := range expected { + if !reflect.DeepEqual(cfg.Repositories[0].SyncOrderPatterns[i], expected[i]) { + t.Errorf("Nodes[%d] differ;\n E: %#v\n A: %#v", i, expected[i], cfg.Repositories[0].SyncOrderPatterns[i]) + } + } +} + +func TestFileSorter(t *testing.T) { + rcfg := RepositoryConfiguration{ + SyncOrderPatterns: []SyncOrderPattern{ + {"\\.jpg$", 10, nil}, + {"\\.mov$", 5, nil}, + {"^camera-uploads", 100, nil}, + }, + } + + f := []scanner.File{ + {Name: "bar.mov"}, + {Name: "baz.txt"}, + {Name: "foo.jpg"}, + {Name: "frew/foo.jpg"}, + {Name: "frew/lol.go"}, + {Name: "frew/rofl.copter"}, + {Name: "frew/bar.mov"}, + {Name: "camera-uploads/foo.jpg"}, + {Name: "camera-uploads/hurr.pl"}, + {Name: "camera-uploads/herp.mov"}, + {Name: "camera-uploads/wee.txt"}, + } + + files.SortBy(rcfg.FileRanker()).Sort(f) + + expected := []scanner.File{ + {Name: "camera-uploads/foo.jpg"}, + {Name: "camera-uploads/herp.mov"}, + {Name: "camera-uploads/hurr.pl"}, + {Name: "camera-uploads/wee.txt"}, + {Name: "foo.jpg"}, + {Name: "frew/foo.jpg"}, + {Name: "bar.mov"}, + {Name: "frew/bar.mov"}, + {Name: "frew/lol.go"}, + {Name: "baz.txt"}, + {Name: "frew/rofl.copter"}, + } + + if !reflect.DeepEqual(f, expected) { + t.Errorf( + "\n\nexpected:\n" + + formatFiles(expected) + "\n" + + "got:\n" + + formatFiles(f) + "\n\n", + ) + } +} + +func formatFiles(f []scanner.File) string { + ret := "" + + for _, v := range f { + ret += " " + v.Name + "\n" + } + + return ret +} |