summaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
authorArthur Axel 'fREW' Schmidt <frioux@gmail.com>2014-06-06 22:10:15 -0500
committerJakob Borg <jakob@nym.se>2014-06-08 07:16:25 +0200
commit82cfd37263fc64a902fd3ad7e0afdd5acf31c322 (patch)
tree244c13654c3b7aff4732424b0ce307db0800d1fa /config
parentdf381fd03fb8b399c66b22133c2fe1647a1edc03 (diff)
Allow prioritization of downloads based on name (fixes #174)
Diffstat (limited to 'config')
-rw-r--r--config/config.go59
-rw-r--r--config/config_test.go96
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
+}