Handle and indicate duplicate repo ID:s (fixes #153)
This commit is contained in:
parent
89f5f3bf9a
commit
dcd7d278aa
File diff suppressed because one or more lines are too long
|
@ -25,6 +25,7 @@ type RepositoryConfiguration struct {
|
||||||
Directory string `xml:"directory,attr"`
|
Directory string `xml:"directory,attr"`
|
||||||
Nodes []NodeConfiguration `xml:"node"`
|
Nodes []NodeConfiguration `xml:"node"`
|
||||||
ReadOnly bool `xml:"ro,attr"`
|
ReadOnly bool `xml:"ro,attr"`
|
||||||
|
Invalid string `xml:"-"` // Set at runtime when there is an error, not saved
|
||||||
nodeIDs []string
|
nodeIDs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,17 +172,21 @@ func readConfigXML(rd io.Reader, myID string) (Configuration, error) {
|
||||||
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
|
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
|
||||||
|
|
||||||
// Check for missing or duplicate repository ID:s
|
// Check for missing or duplicate repository ID:s
|
||||||
var seenRepos = map[string]bool{}
|
var seenRepos = map[string]*RepositoryConfiguration{}
|
||||||
for i := range cfg.Repositories {
|
for i := range cfg.Repositories {
|
||||||
if cfg.Repositories[i].ID == "" {
|
repo := &cfg.Repositories[i]
|
||||||
cfg.Repositories[i].ID = "default"
|
|
||||||
|
if repo.ID == "" {
|
||||||
|
repo.ID = "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
id := cfg.Repositories[i].ID
|
if seen, ok := seenRepos[repo.ID]; ok {
|
||||||
if seenRepos[id] {
|
seen.Invalid = "duplicate repository ID"
|
||||||
panic("duplicate repository ID " + id)
|
repo.Invalid = "duplicate repository ID"
|
||||||
|
warnf("Multiple repositories with ID %q; disabling", repo.ID)
|
||||||
|
} else {
|
||||||
|
seenRepos[repo.ID] = repo
|
||||||
}
|
}
|
||||||
seenRepos[id] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upgrade to v2 configuration if appropriate
|
// Upgrade to v2 configuration if appropriate
|
||||||
|
|
|
@ -84,6 +84,13 @@ func restGetModel(m *Model, w http.ResponseWriter, r *http.Request) {
|
||||||
var repo = qs.Get("repo")
|
var repo = qs.Get("repo")
|
||||||
var res = make(map[string]interface{})
|
var res = make(map[string]interface{})
|
||||||
|
|
||||||
|
for _, cr := range cfg.Repositories {
|
||||||
|
if cr.ID == repo {
|
||||||
|
res["invalid"] = cr.Invalid
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
globalFiles, globalDeleted, globalBytes := m.GlobalSize(repo)
|
globalFiles, globalDeleted, globalBytes := m.GlobalSize(repo)
|
||||||
res["globalFiles"], res["globalDeleted"], res["globalBytes"] = globalFiles, globalDeleted, globalBytes
|
res["globalFiles"], res["globalDeleted"], res["globalBytes"] = globalFiles, globalDeleted, globalBytes
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,9 @@ func main() {
|
||||||
m := NewModel(cfg.Options.MaxChangeKbps * 1000)
|
m := NewModel(cfg.Options.MaxChangeKbps * 1000)
|
||||||
|
|
||||||
for _, repo := range cfg.Repositories {
|
for _, repo := range cfg.Repositories {
|
||||||
|
if repo.Invalid != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
dir := expandTilde(repo.Directory)
|
dir := expandTilde(repo.Directory)
|
||||||
m.AddRepo(repo.ID, dir, repo.Nodes)
|
m.AddRepo(repo.ID, dir, repo.Nodes)
|
||||||
}
|
}
|
||||||
|
@ -260,6 +263,10 @@ func main() {
|
||||||
m.LoadIndexes(confDir)
|
m.LoadIndexes(confDir)
|
||||||
|
|
||||||
for _, repo := range cfg.Repositories {
|
for _, repo := range cfg.Repositories {
|
||||||
|
if repo.Invalid != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
dir := expandTilde(repo.Directory)
|
dir := expandTilde(repo.Directory)
|
||||||
|
|
||||||
// Safety check. If the cached index contains files but the repository
|
// Safety check. If the cached index contains files but the repository
|
||||||
|
@ -295,6 +302,10 @@ func main() {
|
||||||
go listenConnect(myID, m, tlsCfg)
|
go listenConnect(myID, m, tlsCfg)
|
||||||
|
|
||||||
for _, repo := range cfg.Repositories {
|
for _, repo := range cfg.Repositories {
|
||||||
|
if repo.Invalid != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Routine to pull blocks from other nodes to synchronize the local
|
// Routine to pull blocks from other nodes to synchronize the local
|
||||||
// repository. Does not run when we are in read only (publish only) mode.
|
// repository. Does not run when we are in read only (publish only) mode.
|
||||||
if repo.ReadOnly {
|
if repo.ReadOnly {
|
||||||
|
|
|
@ -121,6 +121,10 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($scope.model[repo].invalid !== '') {
|
||||||
|
return 'Stopped';
|
||||||
|
}
|
||||||
|
|
||||||
var state = '' + $scope.model[repo].state;
|
var state = '' + $scope.model[repo].state;
|
||||||
state = state[0].toUpperCase() + state.substr(1);
|
state = state[0].toUpperCase() + state.substr(1);
|
||||||
|
|
||||||
|
@ -136,6 +140,10 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
|
||||||
return 'text-info';
|
return 'text-info';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($scope.model[repo].invalid !== '') {
|
||||||
|
return 'text-warning';
|
||||||
|
}
|
||||||
|
|
||||||
var state = '' + $scope.model[repo].state;
|
var state = '' + $scope.model[repo].state;
|
||||||
if (state == 'idle') {
|
if (state == 'idle') {
|
||||||
return 'text-success';
|
return 'text-success';
|
||||||
|
|
|
@ -134,6 +134,7 @@
|
||||||
<ul class="list-unstyled" ng-repeat="repo in repos">
|
<ul class="list-unstyled" ng-repeat="repo in repos">
|
||||||
<li>
|
<li>
|
||||||
<span class="text-monospace">{{repo.Directory}}</span>
|
<span class="text-monospace">{{repo.Directory}}</span>
|
||||||
|
<span ng-if="repo.Invalid" class="label label-danger">Invalid: {{repo.Invalid}}</span>
|
||||||
<ul class="list-no-bullet">
|
<ul class="list-no-bullet">
|
||||||
<li>
|
<li>
|
||||||
<div class="li-column" title="Repository ID">
|
<div class="li-column" title="Repository ID">
|
||||||
|
|
Loading…
Reference in New Issue