Help
diff --git a/lib/config/folderconfiguration.go b/lib/config/folderconfiguration.go
index d6f4b1a04..98f95a205 100644
--- a/lib/config/folderconfiguration.go
+++ b/lib/config/folderconfiguration.go
@@ -13,6 +13,7 @@ import (
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/protocol"
+ "github.com/syncthing/syncthing/lib/util"
)
var (
@@ -24,8 +25,8 @@ var (
const DefaultMarkerName = ".stfolder"
type FolderConfiguration struct {
- ID string `xml:"id,attr" json:"id" restart:"false"`
- Label string `xml:"label,attr" json:"label"`
+ ID string `xml:"id,attr" json:"id"`
+ Label string `xml:"label,attr" json:"label" restart:"false"`
FilesystemType fs.FilesystemType `xml:"filesystemType" json:"filesystemType"`
Path string `xml:"path,attr" json:"path"`
Type FolderType `xml:"type,attr" json:"type"`
@@ -225,6 +226,25 @@ func (f *FolderConfiguration) prepare() {
}
}
+// RequiresRestartOnly returns a copy with only the attributes that require
+// restart on change.
+func (f FolderConfiguration) RequiresRestartOnly() FolderConfiguration {
+ copy := f
+
+ // Manual handling for things that are not taken care of by the tag
+ // copier, yet should not cause a restart.
+ copy.cachedFilesystem = nil
+
+ blank := FolderConfiguration{}
+ util.CopyMatchingTag(&blank, ©, "restart", func(v string) bool {
+ if len(v) > 0 && v != "false" {
+ panic(fmt.Sprintf(`unexpected tag value: %s. expected untagged or "false"`, v))
+ }
+ return v == "false"
+ })
+ return copy
+}
+
type FolderDeviceConfigurationList []FolderDeviceConfiguration
func (l FolderDeviceConfigurationList) Less(a, b int) bool {
diff --git a/lib/config/optionsconfiguration.go b/lib/config/optionsconfiguration.go
index 4f908438c..74e1df4a9 100644
--- a/lib/config/optionsconfiguration.go
+++ b/lib/config/optionsconfiguration.go
@@ -10,6 +10,8 @@ import (
"encoding/json"
"encoding/xml"
"fmt"
+
+ "github.com/syncthing/syncthing/lib/util"
)
type WeakHashSelectionMethod int
@@ -162,3 +164,17 @@ func (orig OptionsConfiguration) Copy() OptionsConfiguration {
copy(c.UnackedNotificationIDs, orig.UnackedNotificationIDs)
return c
}
+
+// RequiresRestartOnly returns a copy with only the attributes that require
+// restart on change.
+func (orig OptionsConfiguration) RequiresRestartOnly() OptionsConfiguration {
+ copy := orig
+ blank := OptionsConfiguration{}
+ util.CopyMatchingTag(&blank, ©, "restart", func(v string) bool {
+ if len(v) > 0 && v != "true" {
+ panic(fmt.Sprintf(`unexpected tag value: %s. expected untagged or "true"`, v))
+ }
+ return v != "true"
+ })
+ return copy
+}
diff --git a/lib/model/model.go b/lib/model/model.go
index cd3327cce..aa70da86b 100644
--- a/lib/model/model.go
+++ b/lib/model/model.go
@@ -33,7 +33,6 @@ import (
"github.com/syncthing/syncthing/lib/stats"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/upgrade"
- "github.com/syncthing/syncthing/lib/util"
"github.com/syncthing/syncthing/lib/versioner"
"github.com/syncthing/syncthing/lib/weakhash"
"github.com/thejerf/suture"
@@ -2445,17 +2444,8 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
}
// This folder exists on both sides. Settings might have changed.
- // Check if anything differs, apart from the label.
- toCfgCopy := toCfg
- fromCfgCopy := fromCfg
- util.CopyMatchingTag(&toCfgCopy, &fromCfgCopy, "restart", func(v string) bool {
- if len(v) > 0 && v != "false" {
- panic(fmt.Sprintf(`unexpected struct value: %s. expected untagged or "false"`, v))
- }
- return v == "false"
- })
-
- if !reflect.DeepEqual(fromCfgCopy, toCfgCopy) {
+ // Check if anything differs that requires a restart.
+ if !reflect.DeepEqual(fromCfg.RequiresRestartOnly(), toCfg.RequiresRestartOnly()) {
m.RestartFolder(toCfg)
}
@@ -2495,23 +2485,9 @@ func (m *Model) CommitConfiguration(from, to config.Configuration) bool {
}
// Some options don't require restart as those components handle it fine
- // by themselves.
-
- // Copy fields that do not have the field set to true
- util.CopyMatchingTag(&from.Options, &to.Options, "restart", func(v string) bool {
- if len(v) > 0 && v != "true" {
- panic(fmt.Sprintf(`unexpected struct value: %s. expected untagged or "true"`, v))
- }
- return v != "true"
- })
-
- // All of the other generic options require restart. Or at least they may;
- // removing this check requires going through those options carefully and
- // making sure there are individual services that handle them correctly.
- // This code is the "original" requires-restart check and protects other
- // components that haven't yet been converted to VerifyConfig/CommitConfig
- // handling.
- if !reflect.DeepEqual(from.Options, to.Options) {
+ // by themselves. Compare the options structs containing only the
+ // attributes that require restart and act apprioriately.
+ if !reflect.DeepEqual(from.Options.RequiresRestartOnly(), to.Options.RequiresRestartOnly()) {
l.Debugln(m, "requires restart, options differ")
return false
}
diff --git a/lib/util/utils.go b/lib/util/utils.go
index 9cece18b0..d2331a25e 100644
--- a/lib/util/utils.go
+++ b/lib/util/utils.go
@@ -87,6 +87,11 @@ func CopyMatchingTag(from interface{}, to interface{}, tag string, shouldCopy fu
fromField := fromStruct.Field(i)
toField := toStruct.Field(i)
+ if !toField.CanSet() {
+ // Unexported fields
+ continue
+ }
+
structTag := toType.Field(i).Tag
v := structTag.Get(tag)