Run vet and lint. Make us lint clean.

This commit is contained in:
Jakob Borg 2015-04-28 22:32:10 +02:00
parent 3932884688
commit 60fcaebfdb
25 changed files with 189 additions and 133 deletions

View File

@ -78,6 +78,11 @@ func main() {
tags = []string{"noupgrade"} tags = []string{"noupgrade"}
} }
install("./cmd/...", tags) install("./cmd/...", tags)
vet("./cmd/syncthing")
vet("./internal/...")
lint("./cmd/syncthing")
lint("./internal/...")
return return
} }
@ -103,8 +108,7 @@ func main() {
build(pkg, tags) build(pkg, tags)
case "test": case "test":
pkg := "./..." test("./...")
test(pkg)
case "assets": case "assets":
assets() assets()
@ -130,6 +134,14 @@ func main() {
case "clean": case "clean":
clean() clean()
case "vet":
vet("./cmd/syncthing")
vet("./internal/...")
case "lint":
lint("./cmd/syncthing")
lint("./internal/...")
default: default:
log.Fatalf("Unknown command %q", cmd) log.Fatalf("Unknown command %q", cmd)
} }
@ -437,10 +449,7 @@ func run(cmd string, args ...string) []byte {
func runError(cmd string, args ...string) ([]byte, error) { func runError(cmd string, args ...string) ([]byte, error) {
ecmd := exec.Command(cmd, args...) ecmd := exec.Command(cmd, args...)
bs, err := ecmd.CombinedOutput() bs, err := ecmd.CombinedOutput()
if err != nil { return bytes.TrimSpace(bs), err
return nil, err
}
return bytes.TrimSpace(bs), nil
} }
func runPrint(cmd string, args ...string) { func runPrint(cmd string, args ...string) {
@ -615,3 +624,37 @@ func md5File(file string) error {
return out.Close() return out.Close()
} }
func vet(pkg string) {
bs, err := runError("go", "vet", pkg)
if err != nil && err.Error() == "exit status 3" || bytes.Contains(bs, []byte("no such tool \"vet\"")) {
// Go said there is no go vet
log.Println(`- No go vet, no vetting. Try "go get -u golang.org/x/tools/cmd/vet".`)
return
}
falseAlarmComposites := regexp.MustCompile("composite literal uses unkeyed fields")
exitStatus := regexp.MustCompile("exit status 1")
for _, line := range bytes.Split(bs, []byte("\n")) {
if falseAlarmComposites.Match(line) || exitStatus.Match(line) {
continue
}
log.Printf("%s", line)
}
}
func lint(pkg string) {
bs, err := runError("golint", pkg)
if err != nil {
log.Println(`- No golint, not linting. Try "go get -u github.com/golang/lint/golint".`)
return
}
analCommentPolicy := regexp.MustCompile(`exported (function|method|const|type|var) [^\s]+ should have comment`)
for _, line := range bytes.Split(bs, []byte("\n")) {
if analCommentPolicy.Match(line) {
continue
}
log.Printf("%s", line)
}
}

View File

@ -118,8 +118,6 @@ case "${1:-default}" in
-e "STTRACE=$STTRACE" \ -e "STTRACE=$STTRACE" \
syncthing/build:latest \ syncthing/build:latest \
sh -c './build.sh clean \ sh -c './build.sh clean \
&& go tool vet -composites=false cmd/*/*.go internal/*/*.go \
&& ( golint ./cmd/... ; golint ./internal/... ) | egrep -v "comment on exported|should have comment" \
&& ./build.sh all \ && ./build.sh all \
&& STTRACE=all ./build.sh test-cov' && STTRACE=all ./build.sh test-cov'
;; ;;
@ -138,6 +136,25 @@ case "${1:-default}" in
&& git clean -fxd .' && git clean -fxd .'
;; ;;
docker-lint)
docker run --rm -h syncthing-builder -u $(id -u) -t \
-v $(pwd):/go/src/github.com/syncthing/syncthing \
-w /go/src/github.com/syncthing/syncthing \
-e "STTRACE=$STTRACE" \
syncthing/build:latest \
sh -euxc 'go run build.go lint'
;;
docker-vet)
docker run --rm -h syncthing-builder -u $(id -u) -t \
-v $(pwd):/go/src/github.com/syncthing/syncthing \
-w /go/src/github.com/syncthing/syncthing \
-e "STTRACE=$STTRACE" \
syncthing/build:latest \
sh -euxc 'go run build.go vet'
;;
*) *)
echo "Unknown build command $1" echo "Unknown build command $1"
;; ;;

View File

@ -45,16 +45,16 @@ type guiError struct {
} }
var ( var (
configInSync = true configInSync = true
guiErrors = []guiError{} guiErrors = []guiError{}
guiErrorsMut sync.Mutex = sync.NewMutex() guiErrorsMut = sync.NewMutex()
startTime = time.Now() startTime = time.Now()
eventSub *events.BufferedSubscription eventSub *events.BufferedSubscription
) )
var ( var (
lastEventRequest time.Time lastEventRequest time.Time
lastEventRequestMut sync.Mutex = sync.NewMutex() lastEventRequestMut = sync.NewMutex()
) )
func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) error { func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) error {
@ -538,7 +538,7 @@ func flushResponse(s string, w http.ResponseWriter) {
} }
var cpuUsagePercent [10]float64 // The last ten seconds var cpuUsagePercent [10]float64 // The last ten seconds
var cpuUsageLock sync.RWMutex = sync.NewRWMutex() var cpuUsageLock = sync.NewRWMutex()
func restGetSystemStatus(w http.ResponseWriter, r *http.Request) { func restGetSystemStatus(w http.ResponseWriter, r *http.Request) {
var m runtime.MemStats var m runtime.MemStats

View File

@ -20,8 +20,8 @@ import (
) )
var ( var (
sessions = make(map[string]bool) sessions = make(map[string]bool)
sessionsMut sync.Mutex = sync.NewMutex() sessionsMut = sync.NewMutex()
) )
func basicAuthAndSessionMiddleware(cfg config.GUIConfiguration, next http.Handler) http.Handler { func basicAuthAndSessionMiddleware(cfg config.GUIConfiguration, next http.Handler) http.Handler {

View File

@ -19,7 +19,7 @@ import (
) )
var csrfTokens []string var csrfTokens []string
var csrfMut sync.Mutex = sync.NewMutex() var csrfMut = sync.NewMutex()
// Check for CSRF token on /rest/ URLs. If a correct one is not given, reject // Check for CSRF token on /rest/ URLs. If a correct one is not given, reject
// the request with 403. For / and /index.html, set a new CSRF cookie if none // the request with 403. For / and /index.html, set a new CSRF cookie if none

View File

@ -22,9 +22,9 @@ import (
) )
var ( var (
stdoutFirstLines []string // The first 10 lines of stdout stdoutFirstLines []string // The first 10 lines of stdout
stdoutLastLines []string // The last 50 lines of stdout stdoutLastLines []string // The last 50 lines of stdout
stdoutMut sync.Mutex = sync.NewMutex() stdoutMut = sync.NewMutex()
) )
const ( const (

View File

@ -45,28 +45,28 @@ type Configuration struct {
OriginalVersion int `xml:"-" json:"-"` // The version we read from disk, before any conversion OriginalVersion int `xml:"-" json:"-"` // The version we read from disk, before any conversion
} }
func (orig Configuration) Copy() Configuration { func (cfg Configuration) Copy() Configuration {
c := orig newCfg := cfg
// Deep copy FolderConfigurations // Deep copy FolderConfigurations
c.Folders = make([]FolderConfiguration, len(orig.Folders)) newCfg.Folders = make([]FolderConfiguration, len(cfg.Folders))
for i := range c.Folders { for i := range newCfg.Folders {
c.Folders[i] = orig.Folders[i].Copy() newCfg.Folders[i] = cfg.Folders[i].Copy()
} }
// Deep copy DeviceConfigurations // Deep copy DeviceConfigurations
c.Devices = make([]DeviceConfiguration, len(orig.Devices)) newCfg.Devices = make([]DeviceConfiguration, len(cfg.Devices))
for i := range c.Devices { for i := range newCfg.Devices {
c.Devices[i] = orig.Devices[i].Copy() newCfg.Devices[i] = cfg.Devices[i].Copy()
} }
c.Options = orig.Options.Copy() newCfg.Options = cfg.Options.Copy()
// DeviceIDs are values // DeviceIDs are values
c.IgnoredDevices = make([]protocol.DeviceID, len(orig.IgnoredDevices)) newCfg.IgnoredDevices = make([]protocol.DeviceID, len(cfg.IgnoredDevices))
copy(c.IgnoredDevices, orig.IgnoredDevices) copy(newCfg.IgnoredDevices, cfg.IgnoredDevices)
return c return newCfg
} }
type FolderConfiguration struct { type FolderConfiguration struct {
@ -89,10 +89,10 @@ type FolderConfiguration struct {
deviceIDs []protocol.DeviceID deviceIDs []protocol.DeviceID
} }
func (orig FolderConfiguration) Copy() FolderConfiguration { func (f FolderConfiguration) Copy() FolderConfiguration {
c := orig c := f
c.Devices = make([]FolderDeviceConfiguration, len(orig.Devices)) c.Devices = make([]FolderDeviceConfiguration, len(f.Devices))
copy(c.Devices, orig.Devices) copy(c.Devices, f.Devices)
return c return c
} }

View File

@ -156,7 +156,7 @@ func (w *Wrapper) SetDevice(dev DeviceConfiguration) {
w.replaces <- w.cfg.Copy() w.replaces <- w.cfg.Copy()
} }
// Devices returns a map of folders. Folder structures should not be changed, // Folders returns a map of folders. Folder structures should not be changed,
// other than for the purpose of updating via SetFolder(). // other than for the purpose of updating via SetFolder().
func (w *Wrapper) Folders() map[string]FolderConfiguration { func (w *Wrapper) Folders() map[string]FolderConfiguration {
w.mut.Lock() w.mut.Lock()
@ -220,8 +220,8 @@ func (w *Wrapper) SetGUI(gui GUIConfiguration) {
w.replaces <- w.cfg.Copy() w.replaces <- w.cfg.Copy()
} }
// Returns whether or not connection attempts from the given device should be // IgnoredDevice returns whether or not connection attempts from the given
// silently ignored. // device should be silently ignored.
func (w *Wrapper) IgnoredDevice(id protocol.DeviceID) bool { func (w *Wrapper) IgnoredDevice(id protocol.DeviceID) bool {
w.mut.Lock() w.mut.Lock()
defer w.mut.Unlock() defer w.mut.Unlock()

View File

@ -10,7 +10,6 @@
// depending on who calls us. We transform paths to wire-format (NFC and // depending on who calls us. We transform paths to wire-format (NFC and
// slashes) on the way to the database, and transform to native format // slashes) on the way to the database, and transform to native format
// (varying separator and encoding) on the way back out. // (varying separator and encoding) on the way back out.
package db package db
import ( import (
@ -131,7 +130,7 @@ func NewBlockFinder(db *leveldb.DB, cfg *config.Wrapper) *BlockFinder {
return f return f
} }
// Implements config.Handler interface // Changed implements config.Handler interface
func (f *BlockFinder) Changed(cfg config.Configuration) error { func (f *BlockFinder) Changed(cfg config.Configuration) error {
folders := make([]string, len(cfg.Folders)) folders := make([]string, len(cfg.Folders))
for i, folder := range cfg.Folders { for i, folder := range cfg.Folders {
@ -147,11 +146,11 @@ func (f *BlockFinder) Changed(cfg config.Configuration) error {
return nil return nil
} }
// An iterator function which iterates over all matching blocks for the given // Iterate takes an iterator function which iterates over all matching blocks
// hash. The iterator function has to return either true (if they are happy with // for the given hash. The iterator function has to return either true (if
// the block) or false to continue iterating for whatever reason. // they are happy with the block) or false to continue iterating for whatever
// The iterator finally returns the result, whether or not a satisfying block // reason. The iterator finally returns the result, whether or not a
// was eventually found. // satisfying block was eventually found.
func (f *BlockFinder) Iterate(hash []byte, iterFn func(string, string, int32) bool) bool { func (f *BlockFinder) Iterate(hash []byte, iterFn func(string, string, int32) bool) bool {
f.mut.RLock() f.mut.RLock()
folders := f.folders folders := f.folders
@ -172,8 +171,8 @@ func (f *BlockFinder) Iterate(hash []byte, iterFn func(string, string, int32) bo
return false return false
} }
// A method for repairing incorrect blockmap entries, removes the old entry // Fix repairs incorrect blockmap entries, removing the old entry and
// and replaces it with a new entry for the given block // replacing it with a new entry for the given block
func (f *BlockFinder) Fix(folder, file string, index int32, oldHash, newHash []byte) error { func (f *BlockFinder) Fix(folder, file string, index int32, oldHash, newHash []byte) error {
buf := make([]byte, 4) buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(index)) binary.BigEndian.PutUint32(buf, uint32(index))

View File

@ -25,7 +25,7 @@ import (
var ( var (
clockTick int64 clockTick int64
clockMut sync.Mutex = sync.NewMutex() clockMut = sync.NewMutex()
) )
func clock(v int64) int64 { func clock(v int64) int64 {
@ -976,11 +976,11 @@ func unmarshalTrunc(bs []byte, truncate bool) (FileIntf, error) {
var tf FileInfoTruncated var tf FileInfoTruncated
err := tf.UnmarshalXDR(bs) err := tf.UnmarshalXDR(bs)
return tf, err return tf, err
} else {
var tf protocol.FileInfo
err := tf.UnmarshalXDR(bs)
return tf, err
} }
var tf protocol.FileInfo
err := tf.UnmarshalXDR(bs)
return tf, err
} }
func ldbCheckGlobals(db *leveldb.DB, folder []byte) { func ldbCheckGlobals(db *leveldb.DB, folder []byte) {

View File

@ -75,8 +75,8 @@ func Convert(pattern string, flags int) (*regexp.Regexp, error) {
return regexp.Compile(pattern) return regexp.Compile(pattern)
} }
// Matches the pattern against the string, with the given flags, // Match matches the pattern against the string, with the given flags, and
// and returns true if the match is successful. // returns true if the match is successful.
func Match(pattern, s string, flags int) (bool, error) { func Match(pattern, s string, flags int) (bool, error) {
exp, err := Convert(pattern, flags) exp, err := Convert(pattern, flags)
if err != nil { if err != nil {

View File

@ -30,9 +30,8 @@ type Pattern struct {
func (p Pattern) String() string { func (p Pattern) String() string {
if p.include { if p.include {
return p.match.String() return p.match.String()
} else {
return "(?exclude)" + p.match.String()
} }
return "(?exclude)" + p.match.String()
} }
type Matcher struct { type Matcher struct {

View File

@ -125,15 +125,16 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, deviceName, clientName,
return m return m
} }
// Starts deadlock detector on the models locks which causes panics in case // StartDeadlockDetector starts a deadlock detector on the models locks which
// the locks cannot be acquired in the given timeout period. // causes panics in case the locks cannot be acquired in the given timeout
// period.
func (m *Model) StartDeadlockDetector(timeout time.Duration) { func (m *Model) StartDeadlockDetector(timeout time.Duration) {
l.Infof("Starting deadlock detector with %v timeout", timeout) l.Infof("Starting deadlock detector with %v timeout", timeout)
deadlockDetect(m.fmut, timeout) deadlockDetect(m.fmut, timeout)
deadlockDetect(m.pmut, timeout) deadlockDetect(m.pmut, timeout)
} }
// StartRW starts read/write processing on the current model. When in // StartFolderRW starts read/write processing on the current model. When in
// read/write mode the model will attempt to keep in sync with the cluster by // read/write mode the model will attempt to keep in sync with the cluster by
// pulling needed files from peer devices. // pulling needed files from peer devices.
func (m *Model) StartFolderRW(folder string) { func (m *Model) StartFolderRW(folder string) {
@ -166,9 +167,9 @@ func (m *Model) StartFolderRW(folder string) {
go p.Serve() go p.Serve()
} }
// StartRO starts read only processing on the current model. When in // StartFolderRO starts read only processing on the current model. When in
// read only mode the model will announce files to the cluster but not // read only mode the model will announce files to the cluster but not pull in
// pull in any external changes. // any external changes.
func (m *Model) StartFolderRO(folder string) { func (m *Model) StartFolderRO(folder string) {
m.fmut.Lock() m.fmut.Lock()
cfg, ok := m.folderCfgs[folder] cfg, ok := m.folderCfgs[folder]
@ -243,7 +244,7 @@ func (m *Model) ConnectionStats() map[string]interface{} {
return res return res
} }
// Returns statistics about each device // DeviceStatistics returns statistics about each device
func (m *Model) DeviceStatistics() map[string]stats.DeviceStatistics { func (m *Model) DeviceStatistics() map[string]stats.DeviceStatistics {
var res = make(map[string]stats.DeviceStatistics) var res = make(map[string]stats.DeviceStatistics)
for id := range m.cfg.Devices() { for id := range m.cfg.Devices() {
@ -252,7 +253,7 @@ func (m *Model) DeviceStatistics() map[string]stats.DeviceStatistics {
return res return res
} }
// Returns statistics about each folder // FolderStatistics returns statistics about each folder
func (m *Model) FolderStatistics() map[string]stats.FolderStatistics { func (m *Model) FolderStatistics() map[string]stats.FolderStatistics {
var res = make(map[string]stats.FolderStatistics) var res = make(map[string]stats.FolderStatistics)
for id := range m.cfg.Folders() { for id := range m.cfg.Folders() {
@ -261,7 +262,8 @@ func (m *Model) FolderStatistics() map[string]stats.FolderStatistics {
return res return res
} }
// Returns the completion status, in percent, for the given device and folder. // Completion returns the completion status, in percent, for the given device
// and folder.
func (m *Model) Completion(device protocol.DeviceID, folder string) float64 { func (m *Model) Completion(device protocol.DeviceID, folder string) float64 {
var tot int64 var tot int64
@ -375,9 +377,9 @@ func (m *Model) NeedSize(folder string) (nfiles int, bytes int64) {
return return
} }
// NeedFiles returns paginated list of currently needed files in progress, queued, // NeedFolderFiles returns paginated list of currently needed files in
// and to be queued on next puller iteration, as well as the total number of // progress, queued, and to be queued on next puller iteration, as well as the
// files currently needed. // total number of files currently needed.
func (m *Model) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, int) { func (m *Model) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, int) {
m.fmut.RLock() m.fmut.RLock()
defer m.fmut.RUnlock() defer m.fmut.RUnlock()
@ -1535,7 +1537,7 @@ func (m *Model) Availability(folder, file string) []protocol.DeviceID {
return availableDevices return availableDevices
} }
// Bump the given files priority in the job queue // BringToFront bumps the given files priority in the job queue.
func (m *Model) BringToFront(folder, file string) { func (m *Model) BringToFront(folder, file string) {
m.pmut.RLock() m.pmut.RLock()
defer m.pmut.RUnlock() defer m.pmut.RUnlock()
@ -1546,9 +1548,8 @@ func (m *Model) BringToFront(folder, file string) {
} }
} }
// Returns current folder error, or nil if the folder is healthy. // CheckFolderHealth checks the folder for common errors and returns the
// Updates the Invalid field on the folder configuration struct, and emits a // current folder error, or nil if the folder is healthy.
// ConfigSaved event which causes a GUI refresh.
func (m *Model) CheckFolderHealth(id string) error { func (m *Model) CheckFolderHealth(id string) error {
folder, ok := m.cfg.Folders()[id] folder, ok := m.cfg.Folders()[id]
if !ok { if !ok {

View File

@ -760,7 +760,7 @@ func TestGlobalDirectoryTree(t *testing.T) {
m.AddFolder(defaultFolderConfig) m.AddFolder(defaultFolderConfig)
b := func(isfile bool, path ...string) protocol.FileInfo { b := func(isfile bool, path ...string) protocol.FileInfo {
var flags uint32 = protocol.FlagDirectory flags := uint32(protocol.FlagDirectory)
blocks := []protocol.BlockInfo{} blocks := []protocol.BlockInfo{}
if isfile { if isfile {
flags = 0 flags = 0
@ -1009,7 +1009,7 @@ func TestGlobalDirectorySelfFixing(t *testing.T) {
m.AddFolder(defaultFolderConfig) m.AddFolder(defaultFolderConfig)
b := func(isfile bool, path ...string) protocol.FileInfo { b := func(isfile bool, path ...string) protocol.FileInfo {
var flags uint32 = protocol.FlagDirectory flags := uint32(protocol.FlagDirectory)
blocks := []protocol.BlockInfo{} blocks := []protocol.BlockInfo{}
if isfile { if isfile {
flags = 0 flags = 0

View File

@ -27,8 +27,8 @@ type ProgressEmitter struct {
stop chan struct{} stop chan struct{}
} }
// Creates a new progress emitter which emits DownloadProgress events every // NewProgressEmitter creates a new progress emitter which emits
// interval. // DownloadProgress events every interval.
func NewProgressEmitter(cfg *config.Wrapper) *ProgressEmitter { func NewProgressEmitter(cfg *config.Wrapper) *ProgressEmitter {
t := &ProgressEmitter{ t := &ProgressEmitter{
stop: make(chan struct{}), stop: make(chan struct{}),
@ -42,8 +42,8 @@ func NewProgressEmitter(cfg *config.Wrapper) *ProgressEmitter {
return t return t
} }
// Starts progress emitter which starts emitting DownloadProgress events as // Serve starts the progress emitter which starts emitting DownloadProgress
// the progress happens. // events as the progress happens.
func (t *ProgressEmitter) Serve() { func (t *ProgressEmitter) Serve() {
for { for {
select { select {
@ -81,7 +81,8 @@ func (t *ProgressEmitter) Serve() {
} }
} }
// Interface method to handle configuration changes // Changed implements the config.Handler Interface to handle configuration
// changes
func (t *ProgressEmitter) Changed(cfg config.Configuration) error { func (t *ProgressEmitter) Changed(cfg config.Configuration) error {
t.mut.Lock() t.mut.Lock()
defer t.mut.Unlock() defer t.mut.Unlock()
@ -93,7 +94,7 @@ func (t *ProgressEmitter) Changed(cfg config.Configuration) error {
return nil return nil
} }
// Stops the emitter. // Stop stops the emitter.
func (t *ProgressEmitter) Stop() { func (t *ProgressEmitter) Stop() {
t.stop <- struct{}{} t.stop <- struct{}{}
} }
@ -122,7 +123,7 @@ func (t *ProgressEmitter) Deregister(s *sharedPullerState) {
delete(t.registry, filepath.Join(s.folder, s.file.Name)) delete(t.registry, filepath.Join(s.folder, s.file.Name))
} }
// Returns number of bytes completed in the given folder. // BytesCompleted returns the number of bytes completed in the given folder.
func (t *ProgressEmitter) BytesCompleted(folder string) (bytes int64) { func (t *ProgressEmitter) BytesCompleted(folder string) (bytes int64) {
t.mut.Lock() t.mut.Lock()
defer t.mut.Unlock() defer t.mut.Unlock()

View File

@ -23,7 +23,7 @@ var ErrNoHome = errors.New("No home directory found - set $HOME (or the platform
// Try to keep this entire operation atomic-like. We shouldn't be doing this // Try to keep this entire operation atomic-like. We shouldn't be doing this
// often enough that there is any contention on this lock. // often enough that there is any contention on this lock.
var renameLock sync.Mutex = sync.NewMutex() var renameLock = sync.NewMutex()
// TryRename renames a file, leaving source file intact in case of failure. // TryRename renames a file, leaving source file intact in case of failure.
// Tries hard to succeed on various systems by temporarily tweaking directory // Tries hard to succeed on various systems by temporarily tweaking directory
@ -89,7 +89,8 @@ func InWritableDir(fn func(string) error, path string) error {
return fn(path) return fn(path)
} }
// On Windows, removes the read-only attribute from the target prior deletion. // Remove removes the given path. On Windows, removes the read-only attribute
// from the target prior to deletion.
func Remove(path string) error { func Remove(path string) error {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
info, err := os.Stat(path) info, err := os.Stat(path)

View File

@ -59,7 +59,7 @@ func Blocks(r io.Reader, blocksize int, sizehint int64) ([]protocol.BlockInfo, e
return blocks, nil return blocks, nil
} }
// Set the Offset field on each block // PopulateOffsets sets the Offset field on each block
func PopulateOffsets(blocks []protocol.BlockInfo) { func PopulateOffsets(blocks []protocol.BlockInfo) {
var offset int64 var offset int64
for i := range blocks { for i := range blocks {
@ -139,7 +139,7 @@ func VerifyBuffer(buf []byte, block protocol.BlockInfo) ([]byte, error) {
return hash, nil return hash, nil
} }
// BlockEqual returns whether two slices of blocks are exactly the same hash // BlocksEqual returns whether two slices of blocks are exactly the same hash
// and index pair wise. // and index pair wise.
func BlocksEqual(src, tgt []protocol.BlockInfo) bool { func BlocksEqual(src, tgt []protocol.BlockInfo) bool {
if len(tgt) != len(src) { if len(tgt) != len(src) {

View File

@ -379,15 +379,15 @@ func PermsEqual(a, b uint32) bool {
} }
} }
// If the target is missing, Unix never knows what type of symlink it is
// and Windows always knows even if there is no target.
// Which means that without this special check a Unix node would be fighting
// with a Windows node about whether or not the target is known.
// Basically, if you don't know and someone else knows, just accept it.
// The fact that you don't know means you are on Unix, and on Unix you don't
// really care what the target type is. The moment you do know, and if something
// doesn't match, that will propogate throught the cluster.
func SymlinkTypeEqual(disk, index uint32) bool { func SymlinkTypeEqual(disk, index uint32) bool {
// If the target is missing, Unix never knows what type of symlink it is
// and Windows always knows even if there is no target. Which means that
// without this special check a Unix node would be fighting with a Windows
// node about whether or not the target is known. Basically, if you don't
// know and someone else knows, just accept it. The fact that you don't
// know means you are on Unix, and on Unix you don't really care what the
// target type is. The moment you do know, and if something doesn't match,
// that will propogate throught the cluster.
if disk&protocol.FlagSymlinkMissingTarget != 0 && index&protocol.FlagSymlinkMissingTarget == 0 { if disk&protocol.FlagSymlinkMissingTarget != 0 && index&protocol.FlagSymlinkMissingTarget == 0 {
return true return true
} }

View File

@ -58,7 +58,7 @@ func TestMutex(t *testing.T) {
threshold = logThreshold threshold = logThreshold
msgmut := sync.Mutex{} msgmut := sync.Mutex{}
messages := make([]string, 0) var messages []string
l.AddHandler(logger.LevelDebug, func(_ logger.LogLevel, message string) { l.AddHandler(logger.LevelDebug, func(_ logger.LogLevel, message string) {
msgmut.Lock() msgmut.Lock()
@ -91,7 +91,7 @@ func TestRWMutex(t *testing.T) {
threshold = logThreshold threshold = logThreshold
msgmut := sync.Mutex{} msgmut := sync.Mutex{}
messages := make([]string, 0) var messages []string
l.AddHandler(logger.LevelDebug, func(_ logger.LogLevel, message string) { l.AddHandler(logger.LevelDebug, func(_ logger.LogLevel, message string) {
msgmut.Lock() msgmut.Lock()
@ -149,7 +149,7 @@ func TestWaitGroup(t *testing.T) {
threshold = logThreshold threshold = logThreshold
msgmut := sync.Mutex{} msgmut := sync.Mutex{}
messages := make([]string, 0) var messages []string
l.AddHandler(logger.LevelDebug, func(_ logger.LogLevel, message string) { l.AddHandler(logger.LevelDebug, func(_ logger.LogLevel, message string) {
msgmut.Lock() msgmut.Lock()

View File

@ -40,7 +40,6 @@ func init() {
upgradeUnlocked <- true upgradeUnlocked <- true
} }
// A wrapper around actual implementations
func To(rel Release) error { func To(rel Release) error {
select { select {
case <-upgradeUnlocked: case <-upgradeUnlocked:
@ -60,7 +59,6 @@ func To(rel Release) error {
} }
} }
// A wrapper around actual implementations
func ToURL(url string) error { func ToURL(url string) error {
select { select {
case <-upgradeUnlocked: case <-upgradeUnlocked:
@ -90,7 +88,7 @@ const (
MajorNewer = 2 // Newer by a major version (x in x.y.z or 0.x.y). MajorNewer = 2 // Newer by a major version (x in x.y.z or 0.x.y).
) )
// Returns a relation describing how a compares to b. // CompareVersions returns a relation describing how a compares to b.
func CompareVersions(a, b string) Relation { func CompareVersions(a, b string) Relation {
arel, apre := versionParts(a) arel, apre := versionParts(a)
brel, bpre := versionParts(b) brel, bpre := versionParts(b)

View File

@ -27,7 +27,8 @@ import (
"strings" "strings"
) )
// Returns the latest releases, including prereleases or not depending on the argument // LatestGithubReleases returns the latest releases, including prereleases or
// not depending on the argument
func LatestGithubReleases(version string) ([]Release, error) { func LatestGithubReleases(version string) ([]Release, error) {
resp, err := http.Get("https://api.github.com/repos/syncthing/syncthing/releases?per_page=30") resp, err := http.Get("https://api.github.com/repos/syncthing/syncthing/releases?per_page=30")
if err != nil { if err != nil {

View File

@ -27,7 +27,7 @@ import (
"github.com/syncthing/syncthing/internal/sync" "github.com/syncthing/syncthing/internal/sync"
) )
// A container for relevant properties of a UPnP InternetGatewayDevice. // An IGD is a UPnP InternetGatewayDevice.
type IGD struct { type IGD struct {
uuid string uuid string
friendlyName string friendlyName string
@ -36,27 +36,25 @@ type IGD struct {
localIPAddress string localIPAddress string
} }
// The InternetGatewayDevice's UUID.
func (n *IGD) UUID() string { func (n *IGD) UUID() string {
return n.uuid return n.uuid
} }
// The InternetGatewayDevice's friendly name.
func (n *IGD) FriendlyName() string { func (n *IGD) FriendlyName() string {
return n.friendlyName return n.friendlyName
} }
// The InternetGatewayDevice's friendly identifier (friendly name + IP address). // FriendlyIdentifier returns a friendly identifier (friendly name + IP
// address) for the IGD.
func (n *IGD) FriendlyIdentifier() string { func (n *IGD) FriendlyIdentifier() string {
return "'" + n.FriendlyName() + "' (" + strings.Split(n.URL().Host, ":")[0] + ")" return "'" + n.FriendlyName() + "' (" + strings.Split(n.URL().Host, ":")[0] + ")"
} }
// The URL of the InternetGatewayDevice's root device description.
func (n *IGD) URL() *url.URL { func (n *IGD) URL() *url.URL {
return n.url return n.url
} }
// A container for relevant properties of a UPnP service of an IGD. // An IGDService is a specific service provided by an IGD.
type IGDService struct { type IGDService struct {
serviceID string serviceID string
serviceURL string serviceURL string
@ -244,7 +242,7 @@ func parseResponse(deviceType string, resp []byte) (IGD, error) {
deviceDescriptionLocation := response.Header.Get("Location") deviceDescriptionLocation := response.Header.Get("Location")
if deviceDescriptionLocation == "" { if deviceDescriptionLocation == "" {
return IGD{}, errors.New("invalid IGD response: no location specified.") return IGD{}, errors.New("invalid IGD response: no location specified")
} }
deviceDescriptionURL, err := url.Parse(deviceDescriptionLocation) deviceDescriptionURL, err := url.Parse(deviceDescriptionLocation)
@ -255,7 +253,7 @@ func parseResponse(deviceType string, resp []byte) (IGD, error) {
deviceUSN := response.Header.Get("USN") deviceUSN := response.Header.Get("USN")
if deviceUSN == "" { if deviceUSN == "" {
return IGD{}, errors.New("invalid IGD response: USN not specified.") return IGD{}, errors.New("invalid IGD response: USN not specified")
} }
deviceUUID := strings.TrimLeft(strings.Split(deviceUSN, "::")[0], "uuid:") deviceUUID := strings.TrimLeft(strings.Split(deviceUSN, "::")[0], "uuid:")
@ -361,9 +359,8 @@ func getServiceDescriptions(rootURL string, device upnpDevice) ([]IGDService, er
if len(result) < 1 { if len(result) < 1 {
return result, errors.New("[" + rootURL + "] Malformed device description: no compatible service descriptions found.") return result, errors.New("[" + rootURL + "] Malformed device description: no compatible service descriptions found.")
} else {
return result, nil
} }
return result, nil
} }
func getIGDServices(rootURL string, device upnpDevice, wanDeviceURN string, wanConnectionURN string, serviceURNs []string) []IGDService { func getIGDServices(rootURL string, device upnpDevice, wanDeviceURN string, wanConnectionURN string, serviceURNs []string) []IGDService {
@ -488,9 +485,11 @@ func soapRequest(url, service, function, message string) ([]byte, error) {
return resp, nil return resp, nil
} }
// Add a port mapping to all relevant services on the specified InternetGatewayDevice. // AddPortMapping adds a port mapping to all relevant services on the
// Port mapping will fail and return an error if action is fails for _any_ of the relevant services. // specified InternetGatewayDevice. Port mapping will fail and return an error
// For this reason, it is generally better to configure port mapping for each individual service instead. // if action is fails for _any_ of the relevant services. For this reason, it
// is generally better to configure port mapping for each individual service
// instead.
func (n *IGD) AddPortMapping(protocol Protocol, externalPort, internalPort int, description string, timeout int) error { func (n *IGD) AddPortMapping(protocol Protocol, externalPort, internalPort int, description string, timeout int) error {
for _, service := range n.services { for _, service := range n.services {
err := service.AddPortMapping(n.localIPAddress, protocol, externalPort, internalPort, description, timeout) err := service.AddPortMapping(n.localIPAddress, protocol, externalPort, internalPort, description, timeout)
@ -501,9 +500,11 @@ func (n *IGD) AddPortMapping(protocol Protocol, externalPort, internalPort int,
return nil return nil
} }
// Delete a port mapping from all relevant services on the specified InternetGatewayDevice. // DeletePortMapping deletes a port mapping from all relevant services on the
// Port mapping will fail and return an error if action is fails for _any_ of the relevant services. // specified InternetGatewayDevice. Port mapping will fail and return an error
// For this reason, it is generally better to configure port mapping for each individual service instead. // if action is fails for _any_ of the relevant services. For this reason, it
// is generally better to configure port mapping for each individual service
// instead.
func (n *IGD) DeletePortMapping(protocol Protocol, externalPort int) error { func (n *IGD) DeletePortMapping(protocol Protocol, externalPort int) error {
for _, service := range n.services { for _, service := range n.services {
err := service.DeletePortMapping(protocol, externalPort) err := service.DeletePortMapping(protocol, externalPort)
@ -528,7 +529,7 @@ type getExternalIPAddressResponse struct {
NewExternalIPAddress string `xml:"NewExternalIPAddress"` NewExternalIPAddress string `xml:"NewExternalIPAddress"`
} }
// Add a port mapping to the specified IGD service. // AddPortMapping adds a port mapping to the specified IGD service.
func (s *IGDService) AddPortMapping(localIPAddress string, protocol Protocol, externalPort, internalPort int, description string, timeout int) error { func (s *IGDService) AddPortMapping(localIPAddress string, protocol Protocol, externalPort, internalPort int, description string, timeout int) error {
tpl := `<u:AddPortMapping xmlns:u="%s"> tpl := `<u:AddPortMapping xmlns:u="%s">
<NewRemoteHost></NewRemoteHost> <NewRemoteHost></NewRemoteHost>
@ -550,7 +551,7 @@ func (s *IGDService) AddPortMapping(localIPAddress string, protocol Protocol, ex
return nil return nil
} }
// Delete a port mapping from the specified IGD service. // DeletePortMapping deletes a port mapping from the specified IGD service.
func (s *IGDService) DeletePortMapping(protocol Protocol, externalPort int) error { func (s *IGDService) DeletePortMapping(protocol Protocol, externalPort int) error {
tpl := `<u:DeletePortMapping xmlns:u="%s"> tpl := `<u:DeletePortMapping xmlns:u="%s">
<NewRemoteHost></NewRemoteHost> <NewRemoteHost></NewRemoteHost>
@ -568,8 +569,9 @@ func (s *IGDService) DeletePortMapping(protocol Protocol, externalPort int) erro
return nil return nil
} }
// Query the IGD service for its external IP address. // GetExternalIPAddress queries the IGD service for its external IP address.
// Returns nil if the external IP address is invalid or undefined, along with any relevant errors // Returns nil if the external IP address is invalid or undefined, along with
// any relevant errors
func (s *IGDService) GetExternalIPAddress() (net.IP, error) { func (s *IGDService) GetExternalIPAddress() (net.IP, error) {
tpl := `<u:GetExternalIPAddress xmlns:u="%s" />` tpl := `<u:GetExternalIPAddress xmlns:u="%s" />`

View File

@ -21,13 +21,11 @@ func init() {
Factories["external"] = NewExternal Factories["external"] = NewExternal
} }
// The type holds our configuration
type External struct { type External struct {
command string command string
folderPath string folderPath string
} }
// The constructor function takes a map of parameters and creates the type.
func NewExternal(folderID, folderPath string, params map[string]string) Versioner { func NewExternal(folderID, folderPath string, params map[string]string) Versioner {
command := params["command"] command := params["command"]
@ -42,8 +40,8 @@ func NewExternal(folderID, folderPath string, params map[string]string) Versione
return s return s
} }
// Move away the named file to a version archive. If this function returns // Archive moves the named file away to a version archive. If this function
// nil, the named file does not exist any more (has been archived). // returns nil, the named file does not exist any more (has been archived).
func (v External) Archive(filePath string) error { func (v External) Archive(filePath string) error {
_, err := osutil.Lstat(filePath) _, err := osutil.Lstat(filePath)
if os.IsNotExist(err) { if os.IsNotExist(err) {

View File

@ -19,13 +19,11 @@ func init() {
Factories["simple"] = NewSimple Factories["simple"] = NewSimple
} }
// The type holds our configuration
type Simple struct { type Simple struct {
keep int keep int
folderPath string folderPath string
} }
// The constructor function takes a map of parameters and creates the type.
func NewSimple(folderID, folderPath string, params map[string]string) Versioner { func NewSimple(folderID, folderPath string, params map[string]string) Versioner {
keep, err := strconv.Atoi(params["keep"]) keep, err := strconv.Atoi(params["keep"])
if err != nil { if err != nil {
@ -43,8 +41,8 @@ func NewSimple(folderID, folderPath string, params map[string]string) Versioner
return s return s
} }
// Move away the named file to a version archive. If this function returns // Archive moves the named file away to a version archive. If this function
// nil, the named file does not exist any more (has been archived). // returns nil, the named file does not exist any more (has been archived).
func (v Simple) Archive(filePath string) error { func (v Simple) Archive(filePath string) error {
fileInfo, err := osutil.Lstat(filePath) fileInfo, err := osutil.Lstat(filePath)
if os.IsNotExist(err) { if os.IsNotExist(err) {

View File

@ -27,7 +27,6 @@ type Interval struct {
end int64 end int64
} }
// The type holds our configuration
type Staggered struct { type Staggered struct {
versionsPath string versionsPath string
cleanInterval int64 cleanInterval int64
@ -62,7 +61,6 @@ func (v Staggered) renameOld() {
} }
} }
// The constructor function takes a map of parameters and creates the type.
func NewStaggered(folderID, folderPath string, params map[string]string) Versioner { func NewStaggered(folderID, folderPath string, params map[string]string) Versioner {
maxAge, err := strconv.ParseInt(params["maxAge"], 10, 0) maxAge, err := strconv.ParseInt(params["maxAge"], 10, 0)
if err != nil { if err != nil {
@ -271,8 +269,8 @@ func (v Staggered) expire(versions []string) {
} }
} }
// Move away the named file to a version archive. If this function returns // Archive moves the named file away to a version archive. If this function
// nil, the named file does not exist any more (has been archived). // returns nil, the named file does not exist any more (has been archived).
func (v Staggered) Archive(filePath string) error { func (v Staggered) Archive(filePath string) error {
if debug { if debug {
l.Debugln("Waiting for lock on ", v.versionsPath) l.Debugln("Waiting for lock on ", v.versionsPath)