diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go
index 682d3700..c159e004 100644
--- a/cmd/syncthing/gui.go
+++ b/cmd/syncthing/gui.go
@@ -361,8 +361,9 @@ func restPostConfig(m *model.Model, w http.ResponseWriter, r *http.Request) {
// Activate and save
+ newCfg.Location = cfg.Location
+ newCfg.Save()
cfg = newCfg
- saveConfig()
}
}
diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go
index 61f3d678..70ec15d6 100644
--- a/cmd/syncthing/main.go
+++ b/cmd/syncthing/main.go
@@ -33,7 +33,6 @@ import (
"github.com/syncthing/syncthing/files"
"github.com/syncthing/syncthing/logger"
"github.com/syncthing/syncthing/model"
- "github.com/syncthing/syncthing/osutil"
"github.com/syncthing/syncthing/protocol"
"github.com/syncthing/syncthing/upgrade"
"github.com/syncthing/syncthing/upnp"
@@ -310,21 +309,14 @@ func syncthingMain() {
// Prepare to be able to save configuration
cfgFile := filepath.Join(confDir, "config.xml")
- go saveConfigLoop(cfgFile)
var myName string
// Load the configuration file, if it exists.
// If it does not, create a template.
- cf, err := os.Open(cfgFile)
+ cfg, err = config.Load(cfgFile, myID)
if err == nil {
- // Read config.xml
- cfg, err = config.Load(cf, myID)
- if err != nil {
- l.Fatalln(err)
- }
- cf.Close()
myCfg := cfg.GetNodeConfiguration(myID)
if myCfg == nil || myCfg.Name == "" {
myName, _ = os.Hostname()
@@ -336,7 +328,7 @@ func syncthingMain() {
myName, _ = os.Hostname()
defaultRepo := filepath.Join(getHomeDir(), "Sync")
- cfg, err = config.Load(nil, myID)
+ cfg = config.New(cfgFile, myID)
cfg.Repositories = []config.RepositoryConfiguration{
{
ID: "default",
@@ -361,7 +353,7 @@ func syncthingMain() {
l.FatalErr(err)
cfg.Options.ListenAddress = []string{fmt.Sprintf("0.0.0.0:%d", port)}
- saveConfig()
+ cfg.Save()
l.Infof("Edit %s to taste or use the GUI\n", cfgFile)
}
@@ -745,40 +737,6 @@ func shutdown() {
stop <- exitSuccess
}
-var saveConfigCh = make(chan struct{})
-
-func saveConfigLoop(cfgFile string) {
- for _ = range saveConfigCh {
- fd, err := os.Create(cfgFile + ".tmp")
- if err != nil {
- l.Warnln("Saving config:", err)
- continue
- }
-
- err = config.Save(fd, cfg)
- if err != nil {
- l.Warnln("Saving config:", err)
- fd.Close()
- continue
- }
-
- err = fd.Close()
- if err != nil {
- l.Warnln("Saving config:", err)
- continue
- }
-
- err = osutil.Rename(cfgFile+".tmp", cfgFile)
- if err != nil {
- l.Warnln("Saving config:", err)
- }
- }
-}
-
-func saveConfig() {
- saveConfigCh <- struct{}{}
-}
-
func listenConnect(myID protocol.NodeID, m *model.Model, tlsCfg *tls.Config) {
var conns = make(chan *tls.Conn)
diff --git a/config/config.go b/config/config.go
index ec61c266..12684538 100644
--- a/config/config.go
+++ b/config/config.go
@@ -8,7 +8,6 @@ package config
import (
"encoding/xml"
"fmt"
- "io"
"os"
"reflect"
"sort"
@@ -16,12 +15,14 @@ import (
"code.google.com/p/go.crypto/bcrypt"
"github.com/syncthing/syncthing/logger"
+ "github.com/syncthing/syncthing/osutil"
"github.com/syncthing/syncthing/protocol"
)
var l = logger.DefaultLogger
type Configuration struct {
+ Location string `xml:"-" json:"-"`
Version int `xml:"version,attr" default:"3"`
Repositories []RepositoryConfiguration `xml:"repository"`
Nodes []NodeConfiguration `xml:"node"`
@@ -227,14 +228,38 @@ func fillNilSlices(data interface{}) error {
return nil
}
-func Save(wr io.Writer, cfg Configuration) error {
- e := xml.NewEncoder(wr)
- e.Indent("", " ")
- err := e.Encode(cfg)
+func (cfg *Configuration) Save() error {
+ fd, err := os.Create(cfg.Location + ".tmp")
if err != nil {
+ l.Warnln("Saving config:", err)
return err
}
- _, err = wr.Write([]byte("\n"))
+
+ e := xml.NewEncoder(fd)
+ e.Indent("", " ")
+ err = e.Encode(cfg)
+ if err != nil {
+ fd.Close()
+ return err
+ }
+ _, err = fd.Write([]byte("\n"))
+
+ if err != nil {
+ l.Warnln("Saving config:", err)
+ fd.Close()
+ return err
+ }
+
+ err = fd.Close()
+ if err != nil {
+ l.Warnln("Saving config:", err)
+ return err
+ }
+
+ err = osutil.Rename(cfg.Location+".tmp", cfg.Location)
+ if err != nil {
+ l.Warnln("Saving config:", err)
+ }
return err
}
@@ -252,18 +277,7 @@ func uniqueStrings(ss []string) []string {
return us
}
-func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
- var cfg Configuration
-
- setDefaults(&cfg)
- setDefaults(&cfg.Options)
- setDefaults(&cfg.GUI)
-
- var err error
- if rd != nil {
- err = xml.NewDecoder(rd).Decode(&cfg)
- }
-
+func (cfg *Configuration) prepare(myID protocol.NodeID) {
fillNilSlices(&cfg.Options)
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
@@ -312,17 +326,17 @@ func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
// Upgrade to v2 configuration if appropriate
if cfg.Version == 1 {
- convertV1V2(&cfg)
+ convertV1V2(cfg)
}
// Upgrade to v3 configuration if appropriate
if cfg.Version == 2 {
- convertV2V3(&cfg)
+ convertV2V3(cfg)
}
// Upgrade to v4 configuration if appropriate
if cfg.Version == 3 {
- convertV3V4(&cfg)
+ convertV3V4(cfg)
}
// Hash old cleartext passwords
@@ -368,6 +382,39 @@ func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
n.Addresses = []string{"dynamic"}
}
}
+}
+
+func New(location string, myID protocol.NodeID) Configuration {
+ var cfg Configuration
+
+ cfg.Location = location
+
+ setDefaults(&cfg)
+ setDefaults(&cfg.Options)
+ setDefaults(&cfg.GUI)
+
+ cfg.prepare(myID)
+
+ return cfg
+}
+
+func Load(location string, myID protocol.NodeID) (Configuration, error) {
+ var cfg Configuration
+
+ cfg.Location = location
+
+ setDefaults(&cfg)
+ setDefaults(&cfg.Options)
+ setDefaults(&cfg.GUI)
+
+ fd, err := os.Open(location)
+ if err != nil {
+ return Configuration{}, err
+ }
+ err = xml.NewDecoder(fd).Decode(&cfg)
+ fd.Close()
+
+ cfg.prepare(myID)
return cfg, err
}
diff --git a/config/config_test.go b/config/config_test.go
index 696baecb..6a6f8956 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -5,8 +5,6 @@
package config
import (
- "bytes"
- "io"
"os"
"reflect"
"testing"
@@ -40,10 +38,7 @@ func TestDefaultValues(t *testing.T) {
UPnPRenewal: 30,
}
- cfg, err := Load(bytes.NewReader(nil), node1)
- if err != io.EOF {
- t.Error(err)
- }
+ cfg := New("test", node1)
if !reflect.DeepEqual(cfg.Options, expected) {
t.Errorf("Default config differs;\n E: %#v\n A: %#v", expected, cfg.Options)
@@ -51,84 +46,8 @@ func TestDefaultValues(t *testing.T) {
}
func TestNodeConfig(t *testing.T) {
- v1data := []byte(`
-
-
-
- a
-
-
- b
-
-
- a
-
-
- b
-
-
-
- true
- 600
-
-
-`)
-
- v2data := []byte(`
-
-
-
-
-
-
-
-
-
-
- a
-
-
- b
-
-
- 600
-
-
-`)
-
- v3data := []byte(`
-
-
-
-
-
-
- a
-
-
- b
-
-
- 600
-
-`)
-
- v4data := []byte(`
-
-
-
-
-
-
- a
-
-
- b
-
-`)
-
- for i, data := range [][]byte{v1data, v2data, v3data, v4data} {
- cfg, err := Load(bytes.NewReader(data), node1)
+ for i, ver := range []string{"v1", "v2", "v3", "v4"} {
+ cfg, err := Load("testdata/"+ver+".xml", node1)
if err != nil {
t.Error(err)
}
@@ -181,14 +100,7 @@ func TestNodeConfig(t *testing.T) {
}
func TestNoListenAddress(t *testing.T) {
- data := []byte(`
-
-
-
-
-`)
-
- cfg, err := Load(bytes.NewReader(data), node1)
+ cfg, err := Load("testdata/nolistenaddress.xml", node1)
if err != nil {
t.Error(err)
}
@@ -200,26 +112,6 @@ func TestNoListenAddress(t *testing.T) {
}
func TestOverriddenValues(t *testing.T) {
- data := []byte(`
-
- :23000
- false
- syncthing.nym.se:22026
- false
- false
- 42123
- quux:3232
- 32
- 1234
- 6000
- false
- false
- 60
- 15
-
-
-`)
-
expected := OptionsConfiguration{
ListenAddress: []string{":23000"},
GlobalAnnServer: "syncthing.nym.se:22026",
@@ -236,7 +128,7 @@ func TestOverriddenValues(t *testing.T) {
UPnPRenewal: 15,
}
- cfg, err := Load(bytes.NewReader(data), node1)
+ cfg, err := Load("testdata/overridenvalues.xml", node1)
if err != nil {
t.Error(err)
}
@@ -247,19 +139,6 @@ func TestOverriddenValues(t *testing.T) {
}
func TestNodeAddressesDynamic(t *testing.T) {
- data := []byte(`
-
-
-
-
-
-
-
- dynamic
-
-
-`)
-
name, _ := os.Hostname()
expected := []NodeConfiguration{
{
@@ -284,7 +163,7 @@ func TestNodeAddressesDynamic(t *testing.T) {
},
}
- cfg, err := Load(bytes.NewReader(data), node4)
+ cfg, err := Load("testdata/nodeaddressesdynamic.xml", node4)
if err != nil {
t.Error(err)
}
@@ -295,23 +174,6 @@ func TestNodeAddressesDynamic(t *testing.T) {
}
func TestNodeAddressesStatic(t *testing.T) {
- data := []byte(`
-
-
- 192.0.2.1
- 192.0.2.2
-
-
- 192.0.2.3:6070
- [2001:db8::42]:4242
-
-
- [2001:db8::44]:4444
- 192.0.2.4:6090
-
-
-`)
-
name, _ := os.Hostname()
expected := []NodeConfiguration{
{
@@ -333,7 +195,7 @@ func TestNodeAddressesStatic(t *testing.T) {
},
}
- cfg, err := Load(bytes.NewReader(data), node4)
+ cfg, err := Load("testdata/nodeaddressesstatic.xml", node4)
if err != nil {
t.Error(err)
}
@@ -344,18 +206,7 @@ func TestNodeAddressesStatic(t *testing.T) {
}
func TestVersioningConfig(t *testing.T) {
- data := []byte(`
-
-
-
-
-
-
-
-
- `)
-
- cfg, err := Load(bytes.NewReader(data), node4)
+ cfg, err := Load("testdata/versioningconfig.xml", node4)
if err != nil {
t.Error(err)
}
@@ -376,3 +227,67 @@ func TestVersioningConfig(t *testing.T) {
t.Errorf("vc.Params differ;\n E: %#v\n A: %#v", expected, vc.Params)
}
}
+
+func TestNewSaveLoad(t *testing.T) {
+ path := "testdata/temp.xml"
+ os.Remove(path)
+
+ exists := func(path string) bool {
+ _, err := os.Stat(path)
+ return err == nil
+ }
+
+ cfg := New(path, node1)
+
+ // To make the equality pass later
+ cfg.XMLName.Local = "configuration"
+
+ if exists(path) {
+ t.Error(path, "exists")
+ }
+
+ err := cfg.Save()
+ if err != nil {
+ t.Error(err)
+ }
+ if !exists(path) {
+ t.Error(path, "does not exist")
+ }
+
+ cfg2, err := Load(path, node1)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if !reflect.DeepEqual(cfg, cfg2) {
+ t.Errorf("Configs are not equal;\n E: %#v\n A: %#v", cfg, cfg2)
+ }
+
+ cfg.GUI.User = "test"
+ cfg.Save()
+
+ cfg2, err = Load(path, node1)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if cfg2.GUI.User != "test" || !reflect.DeepEqual(cfg, cfg2) {
+ t.Errorf("Configs are not equal;\n E: %#v\n A: %#v", cfg, cfg2)
+ }
+
+ os.Remove(path)
+}
+
+func TestPrepare(t *testing.T) {
+ var cfg Configuration
+
+ if cfg.Repositories != nil || cfg.Nodes != nil || cfg.Options.ListenAddress != nil {
+ t.Error("Expected nil")
+ }
+
+ cfg.prepare(node1)
+
+ if cfg.Repositories == nil || cfg.Nodes == nil || cfg.Options.ListenAddress == nil {
+ t.Error("Unexpected nil")
+ }
+}
diff --git a/config/testdata/nodeaddressesdynamic.xml b/config/testdata/nodeaddressesdynamic.xml
new file mode 100755
index 00000000..fe506c83
--- /dev/null
+++ b/config/testdata/nodeaddressesdynamic.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ dynamic
+
+
diff --git a/config/testdata/nodeaddressesstatic.xml b/config/testdata/nodeaddressesstatic.xml
new file mode 100755
index 00000000..23c15928
--- /dev/null
+++ b/config/testdata/nodeaddressesstatic.xml
@@ -0,0 +1,14 @@
+
+
+ 192.0.2.1
+ 192.0.2.2
+
+
+ 192.0.2.3:6070
+ [2001:db8::42]:4242
+
+
+ [2001:db8::44]:4444
+ 192.0.2.4:6090
+
+
diff --git a/config/testdata/nolistenaddress.xml b/config/testdata/nolistenaddress.xml
new file mode 100755
index 00000000..ab9f87b0
--- /dev/null
+++ b/config/testdata/nolistenaddress.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/config/testdata/overridenvalues.xml b/config/testdata/overridenvalues.xml
new file mode 100755
index 00000000..034a662b
--- /dev/null
+++ b/config/testdata/overridenvalues.xml
@@ -0,0 +1,18 @@
+
+
+ :23000
+ false
+ syncthing.nym.se:22026
+ false
+ false
+ 42123
+ quux:3232
+ 32
+ 1234
+ 6000
+ false
+ false
+ 60
+ 15
+
+
diff --git a/config/testdata/v1.xml b/config/testdata/v1.xml
new file mode 100755
index 00000000..2365effb
--- /dev/null
+++ b/config/testdata/v1.xml
@@ -0,0 +1,20 @@
+
+
+
+ a
+
+
+ b
+
+
+ a
+
+
+ b
+
+
+
+ true
+ 600
+
+
diff --git a/config/testdata/v2.xml b/config/testdata/v2.xml
new file mode 100755
index 00000000..bfddd25e
--- /dev/null
+++ b/config/testdata/v2.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+ a
+
+
+ b
+
+
+ 600
+
+
diff --git a/config/testdata/v3.xml b/config/testdata/v3.xml
new file mode 100755
index 00000000..0f527fae
--- /dev/null
+++ b/config/testdata/v3.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ a
+
+
+ b
+
+
+ 600
+
+
diff --git a/config/testdata/v4.xml b/config/testdata/v4.xml
new file mode 100755
index 00000000..73d6649d
--- /dev/null
+++ b/config/testdata/v4.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ a
+
+
+ b
+
+
diff --git a/config/testdata/versioningconfig.xml b/config/testdata/versioningconfig.xml
new file mode 100755
index 00000000..c98be30b
--- /dev/null
+++ b/config/testdata/versioningconfig.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/model/model_test.go b/model/model_test.go
index d7238cea..0a417fcf 100644
--- a/model/model_test.go
+++ b/model/model_test.go
@@ -266,7 +266,7 @@ func TestNodeRename(t *testing.T) {
ClientVersion: "v0.9.4",
}
- cfg, _ := config.Load(nil, node1)
+ cfg := config.New("test", node1)
cfg.Nodes = []config.NodeConfiguration{
{
NodeID: node1,