mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-16 18:41:59 -07:00
Allow limiting max conflicts (fixes #2282)
This commit is contained in:
parent
2b56961b54
commit
752533489a
@ -1135,6 +1135,7 @@ angular.module('syncthing.core')
|
|||||||
};
|
};
|
||||||
$scope.currentFolder.rescanIntervalS = 60;
|
$scope.currentFolder.rescanIntervalS = 60;
|
||||||
$scope.currentFolder.minDiskFreePct = 1;
|
$scope.currentFolder.minDiskFreePct = 1;
|
||||||
|
$scope.currentFolder.maxConflicts = -1;
|
||||||
$scope.currentFolder.order = "random";
|
$scope.currentFolder.order = "random";
|
||||||
$scope.currentFolder.fileVersioningSelector = "none";
|
$scope.currentFolder.fileVersioningSelector = "none";
|
||||||
$scope.currentFolder.trashcanClean = 0;
|
$scope.currentFolder.trashcanClean = 0;
|
||||||
@ -1156,6 +1157,7 @@ angular.module('syncthing.core')
|
|||||||
selectedDevices: {},
|
selectedDevices: {},
|
||||||
rescanIntervalS: 60,
|
rescanIntervalS: 60,
|
||||||
minDiskFreePct: 1,
|
minDiskFreePct: 1,
|
||||||
|
maxConflicts: -1,
|
||||||
order: "random",
|
order: "random",
|
||||||
fileVersioningSelector: "none",
|
fileVersioningSelector: "none",
|
||||||
trashcanClean: 0,
|
trashcanClean: 0,
|
||||||
|
File diff suppressed because one or more lines are too long
@ -111,6 +111,7 @@ type FolderConfiguration struct {
|
|||||||
ScanProgressIntervalS int `xml:"scanProgressIntervalS" json:"scanProgressIntervalS"` // Set to a negative value to disable. Value of 0 will get replaced with value of 2 (default value)
|
ScanProgressIntervalS int `xml:"scanProgressIntervalS" json:"scanProgressIntervalS"` // Set to a negative value to disable. Value of 0 will get replaced with value of 2 (default value)
|
||||||
PullerSleepS int `xml:"pullerSleepS" json:"pullerSleepS"`
|
PullerSleepS int `xml:"pullerSleepS" json:"pullerSleepS"`
|
||||||
PullerPauseS int `xml:"pullerPauseS" json:"pullerPauseS"`
|
PullerPauseS int `xml:"pullerPauseS" json:"pullerPauseS"`
|
||||||
|
MaxConflicts int `xml:"maxConflicts" json:"maxConflicts"`
|
||||||
|
|
||||||
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
Invalid string `xml:"-" json:"invalid"` // Set at runtime when there is an error, not saved
|
||||||
}
|
}
|
||||||
@ -499,14 +500,6 @@ func ChangeRequiresRestart(from, to Configuration) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertV10V11(cfg *Configuration) {
|
|
||||||
// Set minimum disk free of existing folders to 1%
|
|
||||||
for i := range cfg.Folders {
|
|
||||||
cfg.Folders[i].MinDiskFreePct = 1
|
|
||||||
}
|
|
||||||
cfg.Version = 11
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertV11V12(cfg *Configuration) {
|
func convertV11V12(cfg *Configuration) {
|
||||||
// Change listen address schema
|
// Change listen address schema
|
||||||
for i, addr := range cfg.Options.ListenAddress {
|
for i, addr := range cfg.Options.ListenAddress {
|
||||||
@ -550,9 +543,22 @@ func convertV11V12(cfg *Configuration) {
|
|||||||
cfg.Options.LocalAnnPort = 21027
|
cfg.Options.LocalAnnPort = 21027
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set MaxConflicts to unlimited
|
||||||
|
for i := range cfg.Folders {
|
||||||
|
cfg.Folders[i].MaxConflicts = -1
|
||||||
|
}
|
||||||
|
|
||||||
cfg.Version = 12
|
cfg.Version = 12
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertV10V11(cfg *Configuration) {
|
||||||
|
// Set minimum disk free of existing folders to 1%
|
||||||
|
for i := range cfg.Folders {
|
||||||
|
cfg.Folders[i].MinDiskFreePct = 1
|
||||||
|
}
|
||||||
|
cfg.Version = 11
|
||||||
|
}
|
||||||
|
|
||||||
func convertV9V10(cfg *Configuration) {
|
func convertV9V10(cfg *Configuration) {
|
||||||
// Enable auto normalization on existing folders.
|
// Enable auto normalization on existing folders.
|
||||||
for i := range cfg.Folders {
|
for i := range cfg.Folders {
|
||||||
|
@ -100,6 +100,7 @@ func TestDeviceConfig(t *testing.T) {
|
|||||||
Hashers: 0,
|
Hashers: 0,
|
||||||
AutoNormalize: true,
|
AutoNormalize: true,
|
||||||
MinDiskFreePct: 1,
|
MinDiskFreePct: 1,
|
||||||
|
MaxConflicts: -1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expectedDevices := []DeviceConfiguration{
|
expectedDevices := []DeviceConfiguration{
|
||||||
|
1
lib/config/testdata/v12.xml
vendored
1
lib/config/testdata/v12.xml
vendored
@ -3,6 +3,7 @@
|
|||||||
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
|
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
|
||||||
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
|
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
|
||||||
<minDiskFreePct>1</minDiskFreePct>
|
<minDiskFreePct>1</minDiskFreePct>
|
||||||
|
<maxConflicts>-1</maxConflicts>
|
||||||
</folder>
|
</folder>
|
||||||
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="metadata">
|
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="metadata">
|
||||||
<address>tcp://a</address>
|
<address>tcp://a</address>
|
||||||
|
@ -88,6 +88,7 @@ type rwFolder struct {
|
|||||||
pullers int
|
pullers int
|
||||||
shortID uint64
|
shortID uint64
|
||||||
order config.PullOrder
|
order config.PullOrder
|
||||||
|
maxConflicts int
|
||||||
sleep time.Duration
|
sleep time.Duration
|
||||||
pause time.Duration
|
pause time.Duration
|
||||||
|
|
||||||
@ -123,6 +124,7 @@ func newRWFolder(m *Model, shortID uint64, cfg config.FolderConfiguration) *rwFo
|
|||||||
pullers: cfg.Pullers,
|
pullers: cfg.Pullers,
|
||||||
shortID: shortID,
|
shortID: shortID,
|
||||||
order: cfg.Order,
|
order: cfg.Order,
|
||||||
|
maxConflicts: cfg.MaxConflicts,
|
||||||
|
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
queue: newJobQueue(),
|
queue: newJobQueue(),
|
||||||
@ -757,7 +759,7 @@ func (p *rwFolder) deleteFile(file protocol.FileInfo) {
|
|||||||
// of deleting. Also merge with the version vector we had, to indicate
|
// of deleting. Also merge with the version vector we had, to indicate
|
||||||
// we have resolved the conflict.
|
// we have resolved the conflict.
|
||||||
file.Version = file.Version.Merge(cur.Version)
|
file.Version = file.Version.Merge(cur.Version)
|
||||||
err = osutil.InWritableDir(moveForConflict, realName)
|
err = osutil.InWritableDir(p.moveForConflict, realName)
|
||||||
} else if p.versioner != nil {
|
} else if p.versioner != nil {
|
||||||
err = osutil.InWritableDir(p.versioner.Archive, realName)
|
err = osutil.InWritableDir(p.versioner.Archive, realName)
|
||||||
} else {
|
} else {
|
||||||
@ -1254,7 +1256,7 @@ func (p *rwFolder) performFinish(state *sharedPullerState) error {
|
|||||||
// we have resolved the conflict.
|
// we have resolved the conflict.
|
||||||
|
|
||||||
state.file.Version = state.file.Version.Merge(state.version)
|
state.file.Version = state.file.Version.Merge(state.version)
|
||||||
if err = osutil.InWritableDir(moveForConflict, state.realName); err != nil {
|
if err = osutil.InWritableDir(p.moveForConflict, state.realName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1447,7 +1449,14 @@ func removeDevice(devices []protocol.DeviceID, device protocol.DeviceID) []proto
|
|||||||
return devices
|
return devices
|
||||||
}
|
}
|
||||||
|
|
||||||
func moveForConflict(name string) error {
|
func (p *rwFolder) moveForConflict(name string) error {
|
||||||
|
if p.maxConflicts == 0 {
|
||||||
|
if err := osutil.Remove(name); err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
ext := filepath.Ext(name)
|
ext := filepath.Ext(name)
|
||||||
withoutExt := name[:len(name)-len(ext)]
|
withoutExt := name[:len(name)-len(ext)]
|
||||||
newName := withoutExt + time.Now().Format(".sync-conflict-20060102-150405") + ext
|
newName := withoutExt + time.Now().Format(".sync-conflict-20060102-150405") + ext
|
||||||
@ -1457,7 +1466,21 @@ func moveForConflict(name string) error {
|
|||||||
// the user has already moved it away, or the conflict was between a
|
// the user has already moved it away, or the conflict was between a
|
||||||
// remote modification and a local delete. In either way it does not
|
// remote modification and a local delete. In either way it does not
|
||||||
// matter, go ahead as if the move succeeded.
|
// matter, go ahead as if the move succeeded.
|
||||||
return nil
|
err = nil
|
||||||
|
}
|
||||||
|
if p.maxConflicts > -1 {
|
||||||
|
matches, gerr := osutil.Glob(withoutExt + ".sync-conflict-????????-??????" + ext)
|
||||||
|
if gerr == nil && len(matches) > p.maxConflicts {
|
||||||
|
sort.Sort(sort.Reverse(sort.StringSlice(matches)))
|
||||||
|
for _, match := range matches[p.maxConflicts:] {
|
||||||
|
gerr = osutil.Remove(match)
|
||||||
|
if gerr != nil {
|
||||||
|
l.Debugln(p, "removing extra conflict", gerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if gerr != nil {
|
||||||
|
l.Debugln(p, "globbing for conflicts", gerr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user