Compare commits
54 Commits
v0.9.0-bet
...
v0.9.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1be4b8bb5d | ||
|
|
c832fc9917 | ||
|
|
4797a94689 | ||
|
|
6948903084 | ||
|
|
94164611ae | ||
|
|
ae298e8902 | ||
|
|
3d8771ecb0 | ||
|
|
28db264e90 | ||
|
|
6af9fa4b81 | ||
|
|
60b4d05860 | ||
|
|
7b93839ed1 | ||
|
|
fdb11d7c06 | ||
|
|
5651847877 | ||
|
|
e1442290b6 | ||
|
|
c45b18cc75 | ||
|
|
bb2ad77987 | ||
|
|
68b1ffec19 | ||
|
|
bc2bb22673 | ||
|
|
83d707fc4b | ||
|
|
175b32e56c | ||
|
|
97b4a6553b | ||
|
|
4ade30e681 | ||
|
|
4e03b4f191 | ||
|
|
bfe1d1d4ca | ||
|
|
8918de85fd | ||
|
|
5e237aecae | ||
|
|
13291ad481 | ||
|
|
a47ee86bee | ||
|
|
62d703f967 | ||
|
|
b2c196e5c7 | ||
|
|
4be6a54bc0 | ||
|
|
8ce8476547 | ||
|
|
d82caf6bd4 | ||
|
|
8ea1e302c3 | ||
|
|
a8799efa94 | ||
|
|
0cfac4e021 | ||
|
|
f6c9642d72 | ||
|
|
5a07f9ddee | ||
|
|
9db75e91ac | ||
|
|
f288e00c37 | ||
|
|
c9edd31993 | ||
|
|
5a7780ab5f | ||
|
|
ac0fba99ad | ||
|
|
6f724a113c | ||
|
|
327cd4cb87 | ||
|
|
25de3a2590 | ||
|
|
06208a703a | ||
|
|
56afba6606 | ||
|
|
d65bbf2113 | ||
|
|
b8bfc9b732 | ||
|
|
cec3bad373 | ||
|
|
9312e3c7de | ||
|
|
43e7435c41 | ||
|
|
f34f5e41a4 |
@@ -11,8 +11,8 @@ script:
|
||||
- ./build.sh test-cov
|
||||
|
||||
after_success:
|
||||
- goveralls -coverprofile=coverage.out -service=travis-ci -package=calmh/syncthing -repotoken="$COVERALS_TOKEN"
|
||||
- goveralls -coverprofile=coverage.out -service=travis-ci -package=syncthing/syncthing -repotoken="$COVERALLS_TOKEN"
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: "zEV2h2XtKHNLVdXJjM4LA/VjMfLVydm6goF+ARit+nOSGxGoH7f7jIdzJzhxgh7shKG93q61eLO1Tug+WBMYB2EpBuYnTB5AIMYhCDwNI8C4uBV6c3brHfcrie7MASNao8TID2QScASKNFFWvjv/i1Ccn5ztxdcQuhSsNjGZp8A="
|
||||
secure: "TSPJDsokGCQhKLjgG3c58qHn8Qxhh4zEkWFf0XIOOY2nlDVzdgXDsC+Nq0YaP4106Ee4FgkSefsUTQV5lq/IyYW8elgqlgghjOtOi6RJa14eIS9Yy5Bkx6MXn0QfZX/lG+sy42pKSNk43y9GWx/qrt4nkfTtTvI5cXgwDGYdmX8="
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
## Reporting Bugs
|
||||
|
||||
Please file bugs in the [Github Issue
|
||||
Tracker](https://github.com/syncthing/syncthing/issues). Include at
|
||||
least the following:
|
||||
|
||||
- What happened
|
||||
|
||||
- What did you expect to happen instead of what *did* happen, if it's
|
||||
not crazy obvious
|
||||
|
||||
- What operating system, operating system version and version of
|
||||
Syncthing you are running
|
||||
|
||||
- The same for other connected nodes, where relevant
|
||||
|
||||
- Screenshot if the issue concerns something visible in the GUI
|
||||
|
||||
- Console log entries, where possible and relevant
|
||||
|
||||
If you're not sure whether something is relevant, erring on the side of
|
||||
too much information will never get you yelled at. :)
|
||||
|
||||
## Contributing Translations
|
||||
|
||||
All translations are done via
|
||||
[Transifex](https://www.transifex.com/projects/p/syncthing/). If you
|
||||
wish to contribute to a translation, just head over there and sign up.
|
||||
Before every release, the language resources are updated from the
|
||||
latest info on Transifex.
|
||||
|
||||
## Contributing Code
|
||||
|
||||
Please do contribute! If you want to contribute but are unsure where to
|
||||
start, the [Contributions Needed
|
||||
topic](http://discourse.syncthing.net/t/contributions-needed/49)
|
||||
lists areas in need of attention.
|
||||
topic](http://discourse.syncthing.net/t/49) lists areas in need of
|
||||
attention. In general, any open issues are fair game!
|
||||
|
||||
## Licensing
|
||||
|
||||
@@ -16,8 +49,8 @@ to add yourself as a separate commit in your first pull request.
|
||||
|
||||
## Building
|
||||
|
||||
[See the
|
||||
documentation](http://discourse.syncthing.net/t/building-syncthing/44)
|
||||
[See the documentation](http://discourse.syncthing.net/t/44) on how to
|
||||
get started with a build environment.
|
||||
|
||||
## Branches
|
||||
|
||||
@@ -44,7 +77,9 @@ Yes please!
|
||||
|
||||
## Style
|
||||
|
||||
`go fmt`
|
||||
- `go fmt`
|
||||
|
||||
- Unix line breaks
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -53,4 +88,3 @@ Yes please!
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@ Audrius Butkevicius <audrius.butkevicius@gmail.com>
|
||||
Arthur Axel fREW Schmidt <frew@afoolishmanifesto.com>
|
||||
Ben Sidhom <bsidhom@gmail.com>
|
||||
Brandon Philips <brandon@ifup.org>
|
||||
Gilli Sigurdsson <gilli@vx.is>
|
||||
James Patterson <jamespatterson@operamail.com>
|
||||
Jens Diemer <github.com@jensdiemer.de>
|
||||
Philippe Schommers <philippe@schommers.be>
|
||||
Ryan Sullivan <kayoticsully@gmail.com>
|
||||
Tully Robinson <tully@tojr.org>
|
||||
Veeti Paananen <veeti.paananen@rojekti.fi>
|
||||
|
||||
12
Godeps/Godeps.json
generated
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"ImportPath": "github.com/calmh/syncthing",
|
||||
"ImportPath": "github.com/syncthing/syncthing",
|
||||
"GoVersion": "go1.3",
|
||||
"Packages": [
|
||||
"./cmd/..."
|
||||
@@ -22,13 +22,13 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/go.text/transform",
|
||||
"Comment": "null-88",
|
||||
"Rev": "1506dcc33592c369c3be7bd30b38f90445b86deb"
|
||||
"Comment": "null-89",
|
||||
"Rev": "df15baaf13e3f62b6b7a901e74caa3818a7c0a7c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/go.text/unicode/norm",
|
||||
"Comment": "null-88",
|
||||
"Rev": "1506dcc33592c369c3be7bd30b38f90445b86deb"
|
||||
"Comment": "null-89",
|
||||
"Rev": "df15baaf13e3f62b6b7a901e74caa3818a7c0a7c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/snappy-go/snappy",
|
||||
@@ -41,7 +41,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/calmh/xdr",
|
||||
"Rev": "89d756f35ba26bcdd47ca25cf9795b3b8d1e1852"
|
||||
"Rev": "694859acb207675085232438780db923ceb43e96"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/juju/ratelimit",
|
||||
|
||||
212
Godeps/_workspace/src/code.google.com/p/go.text/unicode/norm/maketables.go
generated
vendored
@@ -11,7 +11,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
@@ -24,6 +23,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"code.google.com/p/go.text/internal/ucd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -63,31 +64,7 @@ var localFiles = flag.Bool("local",
|
||||
|
||||
var logger = log.New(os.Stderr, "", log.Lshortfile)
|
||||
|
||||
// UnicodeData.txt has form:
|
||||
// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
|
||||
// 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
|
||||
// See http://unicode.org/reports/tr44/ for full explanation
|
||||
// The fields:
|
||||
const (
|
||||
FCodePoint = iota
|
||||
FName
|
||||
FGeneralCategory
|
||||
FCanonicalCombiningClass
|
||||
FBidiClass
|
||||
FDecompMapping
|
||||
FDecimalValue
|
||||
FDigitValue
|
||||
FNumericValue
|
||||
FBidiMirrored
|
||||
FUnicode1Name
|
||||
FISOComment
|
||||
FSimpleUppercaseMapping
|
||||
FSimpleLowercaseMapping
|
||||
FSimpleTitlecaseMapping
|
||||
NumField
|
||||
|
||||
MaxChar = 0x10FFFF // anything above this shouldn't exist
|
||||
)
|
||||
const MaxChar = 0x10FFFF // anything above this shouldn't exist
|
||||
|
||||
// Quick Check properties of runes allow us to quickly
|
||||
// determine whether a rune may occur in a normal form.
|
||||
@@ -232,7 +209,7 @@ func openReader(file string) (input io.ReadCloser) {
|
||||
return
|
||||
}
|
||||
|
||||
func parseDecomposition(s string, skipfirst bool) (a []rune, e error) {
|
||||
func parseDecomposition(s string, skipfirst bool) (a []rune, err error) {
|
||||
decomp := strings.Split(s, " ")
|
||||
if len(decomp) > 0 && skipfirst {
|
||||
decomp = decomp[1:]
|
||||
@@ -247,56 +224,31 @@ func parseDecomposition(s string, skipfirst bool) (a []rune, e error) {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func parseCharacter(line string) {
|
||||
field := strings.Split(line, ";")
|
||||
if len(field) != NumField {
|
||||
logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
|
||||
}
|
||||
x, err := strconv.ParseUint(field[FCodePoint], 16, 64)
|
||||
point := int(x)
|
||||
if err != nil {
|
||||
logger.Fatalf("%.5s...: %s", line, err)
|
||||
}
|
||||
if point == 0 {
|
||||
return // not interesting and we use 0 as unset
|
||||
}
|
||||
if point > MaxChar {
|
||||
logger.Fatalf("%5s: Rune %X > MaxChar (%X)", line, point, MaxChar)
|
||||
return
|
||||
}
|
||||
state := SNormal
|
||||
switch {
|
||||
case strings.Index(field[FName], ", First>") > 0:
|
||||
state = SFirst
|
||||
case strings.Index(field[FName], ", Last>") > 0:
|
||||
state = SLast
|
||||
}
|
||||
firstChar := lastChar + 1
|
||||
lastChar = rune(point)
|
||||
if state != SLast {
|
||||
firstChar = lastChar
|
||||
}
|
||||
x, err = strconv.ParseUint(field[FCanonicalCombiningClass], 10, 64)
|
||||
if err != nil {
|
||||
logger.Fatalf("%U: bad ccc field: %s", int(x), err)
|
||||
}
|
||||
ccc := uint8(x)
|
||||
decmap := field[FDecompMapping]
|
||||
exp, e := parseDecomposition(decmap, false)
|
||||
isCompat := false
|
||||
if e != nil {
|
||||
if len(decmap) > 0 {
|
||||
exp, e = parseDecomposition(decmap, true)
|
||||
if e != nil {
|
||||
logger.Fatalf(`%U: bad decomp |%v|: "%s"`, int(x), decmap, e)
|
||||
func loadUnicodeData() {
|
||||
f := openReader("UnicodeData.txt")
|
||||
defer f.Close()
|
||||
p := ucd.New(f)
|
||||
for p.Next() {
|
||||
r := p.Rune(ucd.CodePoint)
|
||||
char := &chars[r]
|
||||
|
||||
char.ccc = uint8(p.Uint(ucd.CanonicalCombiningClass))
|
||||
decmap := p.String(ucd.DecompMapping)
|
||||
|
||||
exp, err := parseDecomposition(decmap, false)
|
||||
isCompat := false
|
||||
if err != nil {
|
||||
if len(decmap) > 0 {
|
||||
exp, err = parseDecomposition(decmap, true)
|
||||
if err != nil {
|
||||
logger.Fatalf(`%U: bad decomp |%v|: "%s"`, r, decmap, err)
|
||||
}
|
||||
isCompat = true
|
||||
}
|
||||
isCompat = true
|
||||
}
|
||||
}
|
||||
for i := firstChar; i <= lastChar; i++ {
|
||||
char := &chars[i]
|
||||
char.name = field[FName]
|
||||
char.codePoint = i
|
||||
|
||||
char.name = p.String(ucd.Name)
|
||||
char.codePoint = r
|
||||
char.forms[FCompatibility].decomp = exp
|
||||
if !isCompat {
|
||||
char.forms[FCanonical].decomp = exp
|
||||
@@ -306,24 +258,9 @@ func parseCharacter(line string) {
|
||||
if len(decmap) > 0 {
|
||||
char.forms[FCompatibility].decomp = exp
|
||||
}
|
||||
char.ccc = ccc
|
||||
char.state = SMissing
|
||||
if i == lastChar {
|
||||
char.state = state
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func loadUnicodeData() {
|
||||
f := openReader("UnicodeData.txt")
|
||||
defer f.Close()
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
parseCharacter(scanner.Text())
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
logger.Fatal(scanner.Err())
|
||||
if err := p.Err(); err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,47 +291,22 @@ func compactCCC() {
|
||||
}
|
||||
}
|
||||
|
||||
var singlePointRe = regexp.MustCompile(`^([0-9A-F]+) *$`)
|
||||
|
||||
// CompositionExclusions.txt has form:
|
||||
// 0958 # ...
|
||||
// See http://unicode.org/reports/tr44/ for full explanation
|
||||
func parseExclusion(line string) int {
|
||||
comment := strings.Index(line, "#")
|
||||
if comment >= 0 {
|
||||
line = line[0:comment]
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return 0
|
||||
}
|
||||
matches := singlePointRe.FindStringSubmatch(line)
|
||||
if len(matches) != 2 {
|
||||
logger.Fatalf("%s: %d matches (expected 1)\n", line, len(matches))
|
||||
}
|
||||
point, err := strconv.ParseUint(matches[1], 16, 64)
|
||||
if err != nil {
|
||||
logger.Fatalf("%.5s...: %s", line, err)
|
||||
}
|
||||
return int(point)
|
||||
}
|
||||
|
||||
func loadCompositionExclusions() {
|
||||
f := openReader("CompositionExclusions.txt")
|
||||
defer f.Close()
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
point := parseExclusion(scanner.Text())
|
||||
if point == 0 {
|
||||
continue
|
||||
}
|
||||
c := &chars[point]
|
||||
p := ucd.New(f)
|
||||
for p.Next() {
|
||||
c := &chars[p.Rune(0)]
|
||||
if c.excludeInComp {
|
||||
logger.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint)
|
||||
}
|
||||
c.excludeInComp = true
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
log.Fatal(scanner.Err())
|
||||
if e := p.Err(); e != nil {
|
||||
logger.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -988,8 +900,6 @@ func verifyComputed() {
|
||||
}
|
||||
}
|
||||
|
||||
var qcRe = regexp.MustCompile(`([0-9A-F\.]+) *; (NF.*_QC); ([YNM]) #.*`)
|
||||
|
||||
// Use values in DerivedNormalizationProps.txt to compare against the
|
||||
// values we computed.
|
||||
// DerivedNormalizationProps.txt has form:
|
||||
@@ -999,27 +909,13 @@ var qcRe = regexp.MustCompile(`([0-9A-F\.]+) *; (NF.*_QC); ([YNM]) #.*`)
|
||||
func testDerived() {
|
||||
f := openReader("DerivedNormalizationProps.txt")
|
||||
defer f.Close()
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
qc := qcRe.FindStringSubmatch(line)
|
||||
if qc == nil {
|
||||
continue
|
||||
}
|
||||
rng := strings.Split(qc[1], "..")
|
||||
i, err := strconv.ParseUint(rng[0], 16, 64)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
j := i
|
||||
if len(rng) > 1 {
|
||||
j, err = strconv.ParseUint(rng[1], 16, 64)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
p := ucd.New(f)
|
||||
for p.Next() {
|
||||
r := p.Rune(0)
|
||||
c := &chars[r]
|
||||
|
||||
var ftype, mode int
|
||||
qt := strings.TrimSpace(qc[2])
|
||||
qt := p.String(1)
|
||||
switch qt {
|
||||
case "NFC_QC":
|
||||
ftype, mode = FCanonical, MComposed
|
||||
@@ -1030,10 +926,10 @@ func testDerived() {
|
||||
case "NFKD_QC":
|
||||
ftype, mode = FCompatibility, MDecomposed
|
||||
default:
|
||||
log.Fatalf(`Unexpected quick check type "%s"`, qt)
|
||||
continue
|
||||
}
|
||||
var qr QCResult
|
||||
switch qc[3] {
|
||||
switch p.String(2) {
|
||||
case "Y":
|
||||
qr = QCYes
|
||||
case "N":
|
||||
@@ -1041,27 +937,15 @@ func testDerived() {
|
||||
case "M":
|
||||
qr = QCMaybe
|
||||
default:
|
||||
log.Fatalf(`Unexpected quick check value "%s"`, qc[3])
|
||||
log.Fatalf(`Unexpected quick check value "%s"`, p.String(2))
|
||||
}
|
||||
var lastFailed bool
|
||||
// Verify current
|
||||
for ; i <= j; i++ {
|
||||
c := &chars[int(i)]
|
||||
c.forms[ftype].verified[mode] = true
|
||||
curqr := c.forms[ftype].quickCheck[mode]
|
||||
if curqr != qr {
|
||||
if !lastFailed {
|
||||
logger.Printf("%s: %.4X..%.4X -- %s\n",
|
||||
qt, int(i), int(j), line[0:50])
|
||||
}
|
||||
logger.Printf("%U: FAILED %s (was %v need %v)\n",
|
||||
int(i), qt, curqr, qr)
|
||||
lastFailed = true
|
||||
}
|
||||
if got := c.forms[ftype].quickCheck[mode]; got != qr {
|
||||
logger.Printf("%U: FAILED %s (was %v need %v)\n", r, qt, got, qr)
|
||||
}
|
||||
c.forms[ftype].verified[mode] = true
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
logger.Fatal(scanner.Err())
|
||||
if err := p.Err(); err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
// Any unspecified value must be QCYes. Verify this.
|
||||
for i, c := range chars {
|
||||
|
||||
1
Godeps/_workspace/src/github.com/calmh/xdr/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
coverage.out
|
||||
19
Godeps/_workspace/src/github.com/calmh/xdr/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
language: go
|
||||
go:
|
||||
- tip
|
||||
|
||||
install:
|
||||
- export PATH=$PATH:$HOME/gopath/bin
|
||||
- go get code.google.com/p/go.tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
script:
|
||||
- ./generate.sh
|
||||
- go test -coverprofile=coverage.out
|
||||
|
||||
after_success:
|
||||
- goveralls -coverprofile=coverage.out -service=travis-ci -package=calmh/xdr -repotoken="$COVERALLS_TOKEN"
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: SmgnrGfp2zLrA44ChRMpjPeujubt9veZ8Fx/OseMWECmacyV5N/TuDhzIbwo6QwV4xB0sBacoPzvxQbJRVjNKsPiSu72UbcQmQ7flN4Tf7nW09tSh1iW8NgrpBCq/3UYLoBu2iPBEBKm93IK0aGNAKs6oEkB0fU27iTVBwiTXOY=
|
||||
19
Godeps/_workspace/src/github.com/calmh/xdr/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2014 Jakob Borg.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
- The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
12
Godeps/_workspace/src/github.com/calmh/xdr/README.md
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
xdr
|
||||
===
|
||||
|
||||
[](https://travis-ci.org/calmh/xdr)
|
||||
[](https://coveralls.io/r/calmh/xdr?branch=master)
|
||||
[](http://godoc.org/github.com/calmh/xdr)
|
||||
[](http://opensource.org/licenses/MIT)
|
||||
|
||||
This is an XDR encoding/decoding library. It uses code generation and
|
||||
not reflection. It supports the IPDR bastardized XDR format when built
|
||||
with `-tags ipdr`.
|
||||
|
||||
25
Godeps/_workspace/src/github.com/calmh/xdr/encdec_test.go
generated
vendored
@@ -5,8 +5,12 @@ package xdr_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
|
||||
"github.com/calmh/xdr"
|
||||
)
|
||||
|
||||
// Contains all supported types
|
||||
@@ -22,6 +26,25 @@ type TestStruct struct {
|
||||
UI64 uint64
|
||||
BS []byte
|
||||
S string
|
||||
C Opaque
|
||||
}
|
||||
|
||||
type Opaque [32]byte
|
||||
|
||||
func (u *Opaque) encodeXDR(w *xdr.Writer) (int, error) {
|
||||
return w.WriteRaw(u[:])
|
||||
}
|
||||
|
||||
func (u *Opaque) decodeXDR(r *xdr.Reader) (int, error) {
|
||||
return r.ReadRaw(u[:])
|
||||
}
|
||||
|
||||
func (Opaque) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
var u Opaque
|
||||
for i := range u[:] {
|
||||
u[i] = byte(rand.Int())
|
||||
}
|
||||
return reflect.ValueOf(u)
|
||||
}
|
||||
|
||||
func TestEncDec(t *testing.T) {
|
||||
@@ -39,7 +62,7 @@ func TestEncDec(t *testing.T) {
|
||||
t0.I32 != t1.I32 || t0.UI32 != t1.UI32 ||
|
||||
t0.I64 != t1.I64 || t0.UI64 != t1.UI64 ||
|
||||
bytes.Compare(t0.BS, t1.BS) != 0 ||
|
||||
t0.S != t1.S {
|
||||
t0.S != t1.S || t0.C != t1.C {
|
||||
t.Logf("%#v", t0)
|
||||
t.Logf("%#v", t1)
|
||||
return false
|
||||
|
||||
8
Godeps/_workspace/src/github.com/calmh/xdr/encdec_xdr_test.go
generated
vendored
@@ -52,6 +52,8 @@ TestStruct Structure:
|
||||
\ S (variable length) \
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Opaque |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
struct TestStruct {
|
||||
@@ -66,6 +68,7 @@ struct TestStruct {
|
||||
unsigned hyper UI64;
|
||||
opaque BS<>;
|
||||
string S<>;
|
||||
Opaque C;
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -98,6 +101,10 @@ func (o TestStruct) encodeXDR(xw *xdr.Writer) (int, error) {
|
||||
xw.WriteUint64(o.UI64)
|
||||
xw.WriteBytes(o.BS)
|
||||
xw.WriteString(o.S)
|
||||
_, err := o.C.encodeXDR(xw)
|
||||
if err != nil {
|
||||
return xw.Tot(), err
|
||||
}
|
||||
return xw.Tot(), xw.Error()
|
||||
}
|
||||
|
||||
@@ -124,5 +131,6 @@ func (o *TestStruct) decodeXDR(xr *xdr.Reader) error {
|
||||
o.UI64 = xr.ReadUint64()
|
||||
o.BS = xr.ReadBytes()
|
||||
o.S = xr.ReadString()
|
||||
(&o.C).decodeXDR(xr)
|
||||
return xr.Error()
|
||||
}
|
||||
|
||||
6
Godeps/_workspace/src/github.com/calmh/xdr/xdr_test.go
generated
vendored
@@ -67,7 +67,7 @@ func TestReadBytesMaxInto(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadBytesMaxIntoNil(t *testing.T) {
|
||||
func TestReadStringMax(t *testing.T) {
|
||||
for tot := 42; tot < 72; tot++ {
|
||||
for max := 0; max < 128; max++ {
|
||||
var b = new(bytes.Buffer)
|
||||
@@ -77,8 +77,8 @@ func TestReadBytesMaxIntoNil(t *testing.T) {
|
||||
var toWrite = make([]byte, tot)
|
||||
w.WriteBytes(toWrite)
|
||||
|
||||
var bs = r.ReadBytesMaxInto(max, nil)
|
||||
var read = len(bs)
|
||||
var str = r.ReadStringMax(max)
|
||||
var read = len(str)
|
||||
|
||||
if max == 0 || tot <= max {
|
||||
if read != tot {
|
||||
|
||||
10
README.md
@@ -1,9 +1,9 @@
|
||||
syncthing
|
||||
=========
|
||||
|
||||
[](https://travis-ci.org/calmh/syncthing)
|
||||
[](https://coveralls.io/r/calmh/syncthing?branch=master)
|
||||
[](http://godoc.org/github.com/calmh/syncthing)
|
||||
[](https://travis-ci.org/syncthing/syncthing)
|
||||
[](https://coveralls.io/r/syncthing/syncthing?branch=master)
|
||||
[](http://godoc.org/github.com/syncthing/syncthing)
|
||||
[](http://opensource.org/licenses/MIT)
|
||||
|
||||
This is the `syncthing` project. The following are the project goals:
|
||||
@@ -12,7 +12,7 @@ This is the `syncthing` project. The following are the project goals:
|
||||
number of collaborating nodes. The protocol should be well defined,
|
||||
unambiguous, easily understood, free to use, efficient, secure and
|
||||
language neutral. This is the [Block Exchange
|
||||
Protocol](https://github.com/calmh/syncthing/blob/master/protocol/PROTOCOL.md).
|
||||
Protocol](https://github.com/syncthing/syncthing/blob/master/protocol/PROTOCOL.md).
|
||||
|
||||
2. Provide the reference implementation to demonstrate the usability of
|
||||
said protocol. This is the `syncthing` utility. It is the hope that
|
||||
@@ -50,4 +50,4 @@ under the [Creative Commons Attribution 4.0 International
|
||||
License](http://creativecommons.org/licenses/by/4.0/).
|
||||
|
||||
All code is licensed under the [MIT
|
||||
License](https://github.com/calmh/syncthing/blob/master/LICENSE).
|
||||
License](https://github.com/syncthing/syncthing/blob/master/LICENSE).
|
||||
|
||||
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 1008 B After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 6.4 KiB |
BIN
assets/logo-text-128.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/logo-text-256.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
assets/logo-text-64.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 12 KiB |
1421
assets/logo.ai
1549
assets/logo.pdf
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
23
build.sh
@@ -4,7 +4,11 @@ export COPYFILE_DISABLE=true
|
||||
export GO386=387 # Don't use SSE on 32 bit builds
|
||||
|
||||
distFiles=(README.md LICENSE CONTRIBUTORS) # apart from the binary itself
|
||||
|
||||
# replace "...-12-g123abc" with "...+12-g123abc" to remain semver compatible-ish
|
||||
version=$(git describe --always --dirty)
|
||||
version=$(echo "$version" | sed 's/-\([0-9]\{1,3\}-g[0-9a-f]\{5,10\}\)/+\1/')
|
||||
|
||||
date=$(git show -s --format=%ct)
|
||||
user=$(whoami)
|
||||
host=$(hostname)
|
||||
@@ -47,7 +51,7 @@ test-cov() {
|
||||
test() {
|
||||
check
|
||||
go vet ./...
|
||||
godep go test -cpu=1,2,4 ./...
|
||||
godep go test -cpu=1,2,4 $* ./...
|
||||
}
|
||||
|
||||
sign() {
|
||||
@@ -93,7 +97,6 @@ setup() {
|
||||
go get -v code.google.com/p/go.tools/cmd/vet
|
||||
go get -v github.com/mattn/goveralls
|
||||
go get -v github.com/tools/godep
|
||||
GOPATH="$GOPATH:$(godep path)" go get -v -t ./...
|
||||
}
|
||||
|
||||
xdr() {
|
||||
@@ -111,7 +114,7 @@ translate() {
|
||||
|
||||
transifex() {
|
||||
pushd gui
|
||||
go run ../cmd/transifexdl/main.go > valid-langs.js
|
||||
go run ../cmd/transifexdl/main.go
|
||||
popd
|
||||
assets
|
||||
}
|
||||
@@ -133,7 +136,7 @@ case "$1" in
|
||||
;;
|
||||
|
||||
test)
|
||||
test
|
||||
test -short
|
||||
;;
|
||||
|
||||
test-cov)
|
||||
@@ -142,28 +145,28 @@ case "$1" in
|
||||
|
||||
tar)
|
||||
rm -f *.tar.gz *.zip
|
||||
test || exit 1
|
||||
test -short || exit 1
|
||||
assets
|
||||
build
|
||||
|
||||
eval $(go env)
|
||||
name="syncthing-$GOOS-$GOARCH-$version"
|
||||
name="syncthing-${GOOS/darwin/macosx}-$GOARCH-$version"
|
||||
|
||||
tarDist "$name"
|
||||
;;
|
||||
|
||||
all)
|
||||
rm -f *.tar.gz *.zip
|
||||
test || exit 1
|
||||
test -short || exit 1
|
||||
assets
|
||||
|
||||
for os in darwin-amd64 linux-386 linux-amd64 freebsd-amd64 windows-amd64 windows-386 solaris-amd64 ; do
|
||||
for os in darwin-amd64 freebsd-amd64 freebsd-386 linux-amd64 linux-386 windows-amd64 windows-386 solaris-amd64 ; do
|
||||
export GOOS=${os%-*}
|
||||
export GOARCH=${os#*-}
|
||||
|
||||
build
|
||||
|
||||
name="syncthing-$os-$version"
|
||||
name="syncthing-${os/darwin/macosx}-$version"
|
||||
case $GOOS in
|
||||
windows)
|
||||
zipDist "$name"
|
||||
@@ -202,7 +205,7 @@ case "$1" in
|
||||
tag=$(git describe)
|
||||
shopt -s nullglob
|
||||
for f in *.tar.gz *.zip *.asc ; do
|
||||
relup calmh/syncthing "$tag" "$f"
|
||||
relup syncthing/syncthing "$tag" "$f"
|
||||
done
|
||||
;;
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/calmh/syncthing/files"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/files"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@ import (
|
||||
|
||||
"crypto/tls"
|
||||
"code.google.com/p/go.crypto/bcrypt"
|
||||
"github.com/calmh/syncthing/auto"
|
||||
"github.com/calmh/syncthing/config"
|
||||
"github.com/calmh/syncthing/events"
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/calmh/syncthing/model"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/calmh/syncthing/upgrade"
|
||||
"github.com/syncthing/syncthing/auto"
|
||||
"github.com/syncthing/syncthing/config"
|
||||
"github.com/syncthing/syncthing/events"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/model"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/upgrade"
|
||||
"github.com/vitrun/qart/qr"
|
||||
)
|
||||
|
||||
@@ -57,7 +57,7 @@ const (
|
||||
|
||||
func init() {
|
||||
l.AddHandler(logger.LevelWarn, showGuiError)
|
||||
sub := events.Default.Subscribe(^events.EventType(events.ItemStarted | events.ItemCompleted))
|
||||
sub := events.Default.Subscribe(events.AllEvents)
|
||||
eventSub = events.NewBufferedSubscription(sub, 1000)
|
||||
}
|
||||
|
||||
@@ -384,7 +384,7 @@ func restGetSystem(w http.ResponseWriter, r *http.Request) {
|
||||
res["myID"] = myID.String()
|
||||
res["goroutines"] = runtime.NumGoroutine()
|
||||
res["alloc"] = m.Alloc
|
||||
res["sys"] = m.Sys
|
||||
res["sys"] = m.Sys - m.HeapReleased
|
||||
res["tilde"] = expandTilde("~")
|
||||
if cfg.Options.GlobalAnnEnabled && discoverer != nil {
|
||||
res["extAnnounceOK"] = discoverer.ExtAnnounceOK()
|
||||
@@ -502,6 +502,7 @@ func restGetLang(w http.ResponseWriter, r *http.Request) {
|
||||
langs = append(langs, l[:2])
|
||||
}
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
json.NewEncoder(w).Encode(langs)
|
||||
}
|
||||
|
||||
@@ -514,7 +515,7 @@ func restPostUpgrade(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if upgrade.CompareVersions(rel.Tag, Version) == 1 {
|
||||
err = upgrade.UpgradeTo(rel)
|
||||
err = upgrade.UpgradeTo(rel, GoArchExtra)
|
||||
if err != nil {
|
||||
l.Warnln(err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
@@ -526,8 +527,8 @@ func restPostUpgrade(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func getQR(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
text := r.FormValue("text")
|
||||
var qs = r.URL.Query()
|
||||
var text = qs.Get("text")
|
||||
code, err := qr.Encode(text, qr.M)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid", 500)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/osutil"
|
||||
"github.com/syncthing/syncthing/osutil"
|
||||
)
|
||||
|
||||
var csrfTokens []string
|
||||
@@ -43,6 +43,12 @@ func csrfMiddleware(prefix string, next http.Handler) http.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == "GET" {
|
||||
// Allow GET requests unconditionally
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the CSRF token
|
||||
token := r.Header.Get("X-CSRF-Token")
|
||||
if !validCsrfToken(token) {
|
||||
|
||||
@@ -26,16 +26,16 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/config"
|
||||
"github.com/calmh/syncthing/discover"
|
||||
"github.com/calmh/syncthing/events"
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/calmh/syncthing/model"
|
||||
"github.com/calmh/syncthing/osutil"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/calmh/syncthing/upgrade"
|
||||
"github.com/calmh/syncthing/upnp"
|
||||
"github.com/juju/ratelimit"
|
||||
"github.com/syncthing/syncthing/config"
|
||||
"github.com/syncthing/syncthing/discover"
|
||||
"github.com/syncthing/syncthing/events"
|
||||
"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"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
@@ -47,6 +47,7 @@ var (
|
||||
BuildHost = "unknown"
|
||||
BuildUser = "unknown"
|
||||
LongVersion string
|
||||
GoArchExtra string // "", "v5", "v6", "v7"
|
||||
)
|
||||
|
||||
var l = logger.DefaultLogger
|
||||
@@ -54,7 +55,7 @@ var l = logger.DefaultLogger
|
||||
func init() {
|
||||
if Version != "unknown-dev" {
|
||||
// If not a generic dev build, version string should come from git describe
|
||||
exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-beta\d+)?(-\d+-g[0-9a-f]+)?(-dirty)?$`)
|
||||
exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\+\d+-g[0-9a-f]+)?(-dirty)?$`)
|
||||
if !exp.MatchString(Version) {
|
||||
l.Fatalf("Invalid version string %q;\n\tdoes not match regexp %v", Version, exp)
|
||||
}
|
||||
@@ -135,12 +136,16 @@ func main() {
|
||||
var showVersion bool
|
||||
var doUpgrade bool
|
||||
var doUpgradeCheck bool
|
||||
var generateDir string
|
||||
var noBrowser bool
|
||||
flag.StringVar(&confDir, "home", getDefaultConfDir(), "Set configuration directory")
|
||||
flag.BoolVar(&reset, "reset", false, "Prepare to resync from cluster")
|
||||
flag.BoolVar(&showVersion, "version", false, "Show version")
|
||||
flag.BoolVar(&doUpgrade, "upgrade", false, "Perform upgrade")
|
||||
flag.BoolVar(&doUpgradeCheck, "upgrade-check", false, "Check for available upgrade")
|
||||
flag.BoolVar(&noBrowser, "no-browser", false, "Do not start browser")
|
||||
flag.IntVar(&logFlags, "logflags", logFlags, "Set log flags")
|
||||
flag.StringVar(&generateDir, "generate", "", "Generate key in specified dir")
|
||||
flag.Usage = usageFor(flag.CommandLine, usage, extraUsage)
|
||||
flag.Parse()
|
||||
|
||||
@@ -151,10 +156,29 @@ func main() {
|
||||
|
||||
l.SetFlags(logFlags)
|
||||
|
||||
var err error
|
||||
lockPort, err = getLockPort()
|
||||
if err != nil {
|
||||
l.Fatalln("Opening lock port:", err)
|
||||
if generateDir != "" {
|
||||
dir := expandTilde(generateDir)
|
||||
|
||||
info, err := os.Stat(dir)
|
||||
l.FatalErr(err)
|
||||
if !info.IsDir() {
|
||||
l.Fatalln(dir, "is not a directory")
|
||||
}
|
||||
|
||||
cert, err := loadCert(dir, "")
|
||||
if err == nil {
|
||||
l.Warnln("Key exists; will not overwrite.")
|
||||
l.Infoln("Node ID:", protocol.NewNodeID(cert.Certificate[0]))
|
||||
return
|
||||
}
|
||||
|
||||
newCertificate(dir, "")
|
||||
cert, err = loadCert(dir, "")
|
||||
l.FatalErr(err)
|
||||
if err == nil {
|
||||
l.Infoln("Node ID:", protocol.NewNodeID(cert.Certificate[0]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if doUpgrade || doUpgradeCheck {
|
||||
@@ -171,7 +195,7 @@ func main() {
|
||||
l.Infof("Upgrade available (current %q < latest %q)", Version, rel.Tag)
|
||||
|
||||
if doUpgrade {
|
||||
err = upgrade.UpgradeTo(rel)
|
||||
err = upgrade.UpgradeTo(rel, GoArchExtra)
|
||||
if err != nil {
|
||||
l.Fatalln("Upgrade:", err) // exits 1
|
||||
}
|
||||
@@ -182,6 +206,12 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
lockPort, err = getLockPort()
|
||||
if err != nil {
|
||||
l.Fatalln("Opening lock port:", err)
|
||||
}
|
||||
|
||||
if len(os.Getenv("GOGC")) == 0 {
|
||||
debug.SetGCPercent(25)
|
||||
}
|
||||
@@ -393,12 +423,21 @@ nextRepo:
|
||||
if err != nil {
|
||||
l.Fatalln("Cannot start GUI:", err)
|
||||
}
|
||||
if cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 {
|
||||
if !noBrowser && cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 {
|
||||
openURL(fmt.Sprintf("%s://%s:%d", proto, hostOpen, addr.Port))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear out old indexes for other nodes. Otherwise we'll start up and
|
||||
// start needing a bunch of files which are nowhere to be found. This
|
||||
// needs to be changed when we correctly do persistent indexes.
|
||||
for _, repoCfg := range cfg.Repositories {
|
||||
for _, node := range repoCfg.NodeIDs() {
|
||||
m.Index(node, repoCfg.ID, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the repository and update the local model before establishing any
|
||||
// connections to other nodes.
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ func certSeed(bs []byte) int64 {
|
||||
}
|
||||
|
||||
func newCertificate(dir string, prefix string) {
|
||||
l.Infoln("Generating RSA certificate and key...")
|
||||
l.Infoln("Generating RSA key and certificate...")
|
||||
|
||||
priv, err := rsa.GenerateKey(rand.Reader, tlsRSABits)
|
||||
l.FatalErr(err)
|
||||
@@ -67,11 +67,9 @@ func newCertificate(dir string, prefix string) {
|
||||
l.FatalErr(err)
|
||||
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
certOut.Close()
|
||||
l.Okln("Created RSA certificate file")
|
||||
|
||||
keyOut, err := os.OpenFile(filepath.Join(dir, prefix+"key.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
l.FatalErr(err)
|
||||
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
||||
keyOut.Close()
|
||||
l.Okln("Created RSA key file")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/model"
|
||||
"github.com/syncthing/syncthing/model"
|
||||
)
|
||||
|
||||
// Current version number of the usage report, for acceptance purposes. If
|
||||
@@ -51,7 +51,7 @@ func reportData(m *model.Model) map[string]interface{} {
|
||||
|
||||
var mem runtime.MemStats
|
||||
runtime.ReadMemStats(&mem)
|
||||
res["memoryUsageMiB"] = mem.Sys / 1024 / 1024
|
||||
res["memoryUsageMiB"] = (mem.Sys - mem.HeapReleased) / 1024 / 1024
|
||||
|
||||
var perf float64
|
||||
for i := 0; i < 5; i++ {
|
||||
|
||||
@@ -9,10 +9,13 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type stat struct {
|
||||
@@ -31,6 +34,12 @@ func main() {
|
||||
log.Fatal("Need environment variables TRANSIFEX_USER and TRANSIFEX_PASS")
|
||||
}
|
||||
|
||||
curValidLangs := map[string]bool{}
|
||||
for _, lang := range loadValidLangs() {
|
||||
curValidLangs[lang] = true
|
||||
}
|
||||
log.Println(curValidLangs)
|
||||
|
||||
resp := req("https://www.transifex.com/api/2/project/syncthing/resource/gui/stats")
|
||||
|
||||
var stats map[string]stat
|
||||
@@ -43,10 +52,12 @@ func main() {
|
||||
var langs []string
|
||||
for code, stat := range stats {
|
||||
shortCode := code[:2]
|
||||
if pct := 100 * stat.Translated / (stat.Translated + stat.Untranslated); pct < 95 {
|
||||
log.Printf("Skipping language %q (too low completion ratio %d%%)", shortCode, pct)
|
||||
os.Remove("lang-" + shortCode + ".json")
|
||||
continue
|
||||
if !curValidLangs[shortCode] {
|
||||
if pct := 100 * stat.Translated / (stat.Translated + stat.Untranslated); pct < 95 {
|
||||
log.Printf("Skipping language %q (too low completion ratio %d%%)", shortCode, pct)
|
||||
os.Remove("lang-" + shortCode + ".json")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
langs = append(langs, shortCode)
|
||||
@@ -72,9 +83,18 @@ func main() {
|
||||
fd.Close()
|
||||
}
|
||||
|
||||
saveValidLangs(langs)
|
||||
}
|
||||
|
||||
func saveValidLangs(langs []string) {
|
||||
sort.Strings(langs)
|
||||
fmt.Print("var validLangs = ")
|
||||
json.NewEncoder(os.Stdout).Encode(langs)
|
||||
fd, err := os.Create("valid-langs.js")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Fprint(fd, "var validLangs = ")
|
||||
json.NewEncoder(fd).Encode(langs)
|
||||
fd.Close()
|
||||
}
|
||||
|
||||
func userPass() (string, string) {
|
||||
@@ -97,3 +117,27 @@ func req(url string) *http.Response {
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func loadValidLangs() []string {
|
||||
fd, err := os.Open("valid-langs.js")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer fd.Close()
|
||||
bs, err := ioutil.ReadAll(fd)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var langs []string
|
||||
exp := regexp.MustCompile(`\[([a-z",]+)\]`)
|
||||
if matches := exp.FindSubmatch(bs); len(matches) == 2 {
|
||||
langs = strings.Split(string(matches[1]), ",")
|
||||
for i := range langs {
|
||||
// Remove quotes
|
||||
langs[i] = langs[i][1 : len(langs[i])-1]
|
||||
}
|
||||
}
|
||||
|
||||
return langs
|
||||
}
|
||||
|
||||
@@ -10,12 +10,14 @@ import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/go.net/html"
|
||||
)
|
||||
|
||||
var trans = make(map[string]string)
|
||||
var attrRe = regexp.MustCompile(`\{\{'([^']+)'\s+\|\s+translate\}\}`)
|
||||
|
||||
func generalNode(n *html.Node) {
|
||||
translate := false
|
||||
@@ -24,6 +26,10 @@ func generalNode(n *html.Node) {
|
||||
if a.Key == "translate" {
|
||||
translate = true
|
||||
break
|
||||
} else {
|
||||
if matches := attrRe.FindStringSubmatch(a.Val); len(matches) == 2 {
|
||||
translation(matches[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if n.Type == html.TextNode {
|
||||
@@ -44,12 +50,7 @@ func generalNode(n *html.Node) {
|
||||
|
||||
func inTranslate(n *html.Node) {
|
||||
if n.Type == html.TextNode {
|
||||
v := strings.TrimSpace(n.Data)
|
||||
if _, ok := trans[v]; !ok {
|
||||
av := strings.Replace(v, "{%", "{{", -1)
|
||||
av = strings.Replace(av, "%}", "}}", -1)
|
||||
trans[v] = av
|
||||
}
|
||||
translation(n.Data)
|
||||
} else {
|
||||
log.Println("translate node with non-text child <")
|
||||
log.Println(n)
|
||||
@@ -60,6 +61,15 @@ func inTranslate(n *html.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func translation(v string) {
|
||||
v = strings.TrimSpace(v)
|
||||
if _, ok := trans[v]; !ok {
|
||||
av := strings.Replace(v, "{%", "{{", -1)
|
||||
av = strings.Replace(av, "%}", "}}", -1)
|
||||
trans[v] = av
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fd, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
|
||||
@@ -15,14 +15,14 @@ import (
|
||||
"strconv"
|
||||
|
||||
"code.google.com/p/go.crypto/bcrypt"
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
var l = logger.DefaultLogger
|
||||
|
||||
type Configuration struct {
|
||||
Version int `xml:"version,attr" default:"2"`
|
||||
Version int `xml:"version,attr" default:"3"`
|
||||
Repositories []RepositoryConfiguration `xml:"repository"`
|
||||
Nodes []NodeConfiguration `xml:"node"`
|
||||
GUI GUIConfiguration `xml:"gui"`
|
||||
@@ -296,6 +296,11 @@ func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
|
||||
convertV1V2(&cfg)
|
||||
}
|
||||
|
||||
// Upgrade to v3 configuration if appropriate
|
||||
if cfg.Version == 2 {
|
||||
convertV2V3(&cfg)
|
||||
}
|
||||
|
||||
// Hash old cleartext passwords
|
||||
if len(cfg.GUI.Password) > 0 && cfg.GUI.Password[0] != '$' {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(cfg.GUI.Password), 0)
|
||||
@@ -333,13 +338,24 @@ func Load(rd io.Reader, myID protocol.NodeID) (Configuration, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func convertV2V3(cfg *Configuration) {
|
||||
// In previous versions, compression was always on. When upgrading, enable
|
||||
// compression on all existing new. New nodes will get compression on by
|
||||
// default by the GUI.
|
||||
for i := range cfg.Nodes {
|
||||
cfg.Nodes[i].Compression = true
|
||||
}
|
||||
|
||||
// The global discovery format and port number changed in v0.9. Having the
|
||||
// default announce server but old port number is guaranteed to be legacy.
|
||||
if cfg.Options.GlobalAnnServer == "announce.syncthing.net:22025" {
|
||||
cfg.Options.GlobalAnnServer = "announce.syncthing.net:22026"
|
||||
}
|
||||
|
||||
return cfg, err
|
||||
cfg.Version = 3
|
||||
}
|
||||
|
||||
func convertV1V2(cfg *Configuration) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
var node1, node2, node3, node4 protocol.NodeID
|
||||
@@ -91,7 +91,21 @@ func TestNodeConfig(t *testing.T) {
|
||||
</configuration>
|
||||
`)
|
||||
|
||||
for i, data := range [][]byte{v1data, v2data} {
|
||||
v3data := []byte(`
|
||||
<configuration version="3">
|
||||
<repository id="test" directory="~/Sync" ro="true" ignorePerms="false">
|
||||
<node id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" compression="false"></node>
|
||||
<node id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2" compression="false"></node>
|
||||
</repository>
|
||||
<node id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="true">
|
||||
<address>a</address>
|
||||
</node>
|
||||
<node id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2" name="node two" compression="true">
|
||||
<address>b</address>
|
||||
</node>
|
||||
</configuration>`)
|
||||
|
||||
for i, data := range [][]byte{v1data, v2data, v3data} {
|
||||
cfg, err := Load(bytes.NewReader(data), node1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -107,20 +121,22 @@ func TestNodeConfig(t *testing.T) {
|
||||
}
|
||||
expectedNodes := []NodeConfiguration{
|
||||
{
|
||||
NodeID: node1,
|
||||
Name: "node one",
|
||||
Addresses: []string{"a"},
|
||||
NodeID: node1,
|
||||
Name: "node one",
|
||||
Addresses: []string{"a"},
|
||||
Compression: true,
|
||||
},
|
||||
{
|
||||
NodeID: node4,
|
||||
Name: "node two",
|
||||
Addresses: []string{"b"},
|
||||
NodeID: node4,
|
||||
Name: "node two",
|
||||
Addresses: []string{"b"},
|
||||
Compression: true,
|
||||
},
|
||||
}
|
||||
expectedNodeIDs := []protocol.NodeID{node1, node4}
|
||||
|
||||
if cfg.Version != 2 {
|
||||
t.Errorf("%d: Incorrect version %d != 2", i, cfg.Version)
|
||||
if cfg.Version != 3 {
|
||||
t.Errorf("%d: Incorrect version %d != 3", i, cfg.Version)
|
||||
}
|
||||
if !reflect.DeepEqual(cfg.Repositories, expectedRepos) {
|
||||
t.Errorf("%d: Incorrect Repositories\n A: %#v\n E: %#v", i, cfg.Repositories, expectedRepos)
|
||||
@@ -222,16 +238,19 @@ func TestNodeAddressesDynamic(t *testing.T) {
|
||||
name, _ := os.Hostname()
|
||||
expected := []NodeConfiguration{
|
||||
{
|
||||
NodeID: node1,
|
||||
Addresses: []string{"dynamic"},
|
||||
NodeID: node1,
|
||||
Addresses: []string{"dynamic"},
|
||||
Compression: true,
|
||||
},
|
||||
{
|
||||
NodeID: node2,
|
||||
Addresses: []string{"dynamic"},
|
||||
NodeID: node2,
|
||||
Addresses: []string{"dynamic"},
|
||||
Compression: true,
|
||||
},
|
||||
{
|
||||
NodeID: node3,
|
||||
Addresses: []string{"dynamic"},
|
||||
NodeID: node3,
|
||||
Addresses: []string{"dynamic"},
|
||||
Compression: true,
|
||||
},
|
||||
{
|
||||
NodeID: node4,
|
||||
@@ -252,7 +271,7 @@ func TestNodeAddressesDynamic(t *testing.T) {
|
||||
|
||||
func TestNodeAddressesStatic(t *testing.T) {
|
||||
data := []byte(`
|
||||
<configuration version="2">
|
||||
<configuration version="3">
|
||||
<node id="AIR6LPZ7K4PTTUXQSMUUCPQ5YWOEDFIIQJUG7772YQXXR5YD6AWQ">
|
||||
<address>192.0.2.1</address>
|
||||
<address>192.0.2.2</address>
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/beacon"
|
||||
"github.com/calmh/syncthing/events"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/beacon"
|
||||
"github.com/syncthing/syncthing/events"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
type Discoverer struct {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -23,7 +23,6 @@ const (
|
||||
LocalIndexUpdated
|
||||
RemoteIndexUpdated
|
||||
ItemStarted
|
||||
ItemCompleted
|
||||
StateChanged
|
||||
|
||||
AllEvents = ^EventType(0)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/events"
|
||||
"github.com/syncthing/syncthing/events"
|
||||
)
|
||||
|
||||
var timeout = 100 * time.Millisecond
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -2,11 +2,12 @@ package files
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/calmh/syncthing/lamport"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/lamport"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||
@@ -121,6 +122,8 @@ type deletionHandler func(db dbReader, batch dbWriter, repo, node, name []byte,
|
||||
type fileIterator func(f protocol.FileInfo) bool
|
||||
|
||||
func ldbGenericReplace(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo, deleteFn deletionHandler) uint64 {
|
||||
defer runtime.GC()
|
||||
|
||||
sort.Sort(fileList(fs)) // sort list on name, same as on disk
|
||||
|
||||
start := nodeKey(repo, node, nil) // before all repo/node files
|
||||
@@ -246,6 +249,8 @@ func ldbReplaceWithDelete(db *leveldb.DB, repo, node []byte, fs []protocol.FileI
|
||||
}
|
||||
|
||||
func ldbUpdate(db *leveldb.DB, repo, node []byte, fs []protocol.FileInfo) uint64 {
|
||||
defer runtime.GC()
|
||||
|
||||
batch := new(leveldb.Batch)
|
||||
snap, err := db.GetSnapshot()
|
||||
if err != nil {
|
||||
@@ -414,6 +419,8 @@ func ldbWithHave(db *leveldb.DB, repo, node []byte, fn fileIterator) {
|
||||
}
|
||||
|
||||
func ldbWithAllRepo(db *leveldb.DB, repo []byte, fn func(node []byte, f protocol.FileInfo) bool) {
|
||||
defer runtime.GC()
|
||||
|
||||
start := nodeKey(repo, nil, nil) // before all repo/node files
|
||||
limit := nodeKey(repo, protocol.LocalNodeID[:], []byte{0xff, 0xff, 0xff, 0xff}) // after all repo/node files
|
||||
snap, err := db.GetSnapshot()
|
||||
@@ -530,6 +537,8 @@ func ldbGetGlobal(db *leveldb.DB, repo, file []byte) protocol.FileInfo {
|
||||
}
|
||||
|
||||
func ldbWithGlobal(db *leveldb.DB, repo []byte, fn fileIterator) {
|
||||
defer runtime.GC()
|
||||
|
||||
start := globalKey(repo, nil)
|
||||
limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
|
||||
snap, err := db.GetSnapshot()
|
||||
@@ -597,6 +606,8 @@ func ldbAvailability(db *leveldb.DB, repo, file []byte) []protocol.NodeID {
|
||||
}
|
||||
|
||||
func ldbWithNeed(db *leveldb.DB, repo, node []byte, fn fileIterator) {
|
||||
defer runtime.GC()
|
||||
|
||||
start := globalKey(repo, nil)
|
||||
limit := globalKey(repo, []byte{0xff, 0xff, 0xff, 0xff})
|
||||
snap, err := db.GetSnapshot()
|
||||
|
||||
@@ -8,8 +8,8 @@ package files
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/calmh/syncthing/lamport"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/lamport"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/calmh/syncthing/files"
|
||||
"github.com/calmh/syncthing/lamport"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/files"
|
||||
"github.com/syncthing/syncthing/lamport"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
"github.com/syndtr/goleveldb/leveldb/storage"
|
||||
)
|
||||
|
||||
26
gui/app.js
@@ -168,6 +168,9 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
|
||||
OutBytesTotal: 0,
|
||||
Address: arg.data.addr,
|
||||
};
|
||||
$scope.completion[arg.data.id] = {
|
||||
_total: 100,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -284,6 +287,11 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
|
||||
$scope.config.Options.ListenStr = $scope.config.Options.ListenAddress.join(', ');
|
||||
|
||||
$scope.nodes = $scope.config.Nodes;
|
||||
$scope.nodes.forEach(function (nodeCfg) {
|
||||
$scope.completion[nodeCfg.NodeID] = {
|
||||
_total: 100,
|
||||
};
|
||||
});
|
||||
$scope.nodes.sort(nodeCompare);
|
||||
|
||||
$scope.repos = repoMap($scope.config.Repositories);
|
||||
@@ -506,8 +514,6 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
|
||||
|
||||
$scope.restart = function () {
|
||||
restarting = true;
|
||||
$scope.restartingTitle = "Restarting"
|
||||
$scope.restartingBody = "Syncthing is restarting."
|
||||
$('#restarting').modal({backdrop: 'static', keyboard: false});
|
||||
$http.post(urlbase + '/restart');
|
||||
$scope.configInSync = true;
|
||||
@@ -529,14 +535,13 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
|
||||
};
|
||||
|
||||
$scope.upgrade = function () {
|
||||
$scope.restartingTitle = "Upgrading"
|
||||
$scope.restartingBody = "Syncthing is upgrading."
|
||||
$('#restarting').modal({backdrop: 'static', keyboard: false});
|
||||
restarting = true;
|
||||
$('#upgrading').modal({backdrop: 'static', keyboard: false});
|
||||
$http.post(urlbase + '/upgrade').success(function () {
|
||||
restarting = true;
|
||||
$scope.restartingBody = "Syncthing is restarting into the new version."
|
||||
$('#restarting').modal({backdrop: 'static', keyboard: false});
|
||||
$('#upgrading').modal('hide');
|
||||
}).error(function () {
|
||||
$('#restarting').modal('hide');
|
||||
$('#upgrading').modal('hide');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -790,6 +795,10 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca
|
||||
$('#about').modal('show');
|
||||
};
|
||||
|
||||
$scope.showReportPreview = function () {
|
||||
$scope.reportPreview = true;
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
setInterval($scope.refresh, 10000);
|
||||
});
|
||||
@@ -1035,7 +1044,6 @@ syncthing.directive('validNodeid', function($http) {
|
||||
if (resp.error) {
|
||||
ctrl.$setValidity('validNodeid', false);
|
||||
} else {
|
||||
scope.currentNode.NodeID = resp.id;
|
||||
ctrl.$setValidity('validNodeid', true);
|
||||
}
|
||||
});
|
||||
|
||||
BIN
gui/favicon.png
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.4 KiB |
@@ -15,12 +15,17 @@
|
||||
|
||||
<title>Syncthing | {{thisNodeName()}}</title>
|
||||
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="raleway.css" rel="stylesheet">
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding-bottom: 70px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-family: "Raleway", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
ul+h5 {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
@@ -95,7 +100,8 @@
|
||||
|
||||
<nav class="navbar navbar-top navbar-default" role="navigation">
|
||||
<div class="container">
|
||||
<span class="navbar-brand"><img class="logo" src="st-logo-128.png" width="32" height="32" /> Syncthing<small class="hidden-xs"> <span class="text-muted">|</span> {{thisNodeName()}}</small></span>
|
||||
<span class="navbar-brand"><img class="logo" src="logo-text-64.png" height="32" width="117"/></span>
|
||||
<p class="navbar-text hidden-xs">{{thisNodeName()}}</p>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li ng-if="upgradeInfo.newer">
|
||||
<button type="button" class="btn navbar-btn btn-default" href="" ng-click="upgrade()">
|
||||
@@ -153,7 +159,7 @@
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#repositories" href="#repo-{{$index}}">
|
||||
<span class="glyphicon glyphicon-hdd"></span> {{repo.Directory | shortPath}}
|
||||
<span class="glyphicon glyphicon-hdd"></span> {{repo.ID}}
|
||||
<span class="pull-right hidden-xs" ng-switch="repoStatus(repo.ID)">
|
||||
<span translate ng-switch-when="unknown">Unknown</span>
|
||||
<span translate ng-switch-when="stopped">Stopped</span>
|
||||
@@ -367,10 +373,10 @@
|
||||
<div class="container">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a class="navbar-link" href="http://discourse.syncthing.net/"><span translate>Support / Forum</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/calmh/syncthing/releases"><span translate>Latest Release</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing/releases"><span translate>Latest Release</span></a></li>
|
||||
<li><a class="navbar-link" href="http://discourse.syncthing.net/category/documentation"><span translate>Documentation</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/calmh/syncthing/issues"><span translate>Bugs</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/calmh/syncthing"><span translate>Source Code</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing/issues"><span translate>Bugs</span></a></li>
|
||||
<li><a class="navbar-link" href="https://github.com/syncthing/syncthing"><span translate>Source Code</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -385,8 +391,12 @@
|
||||
|
||||
<!-- Restarting modal -->
|
||||
|
||||
<modal id="restarting" icon="refresh" title="{{restartingTitle}}" status="info">
|
||||
<p>{{restartingBody}} <span translate>Please wait</span>…</p>
|
||||
<modal id="restarting" icon="refresh" title="{{'Restarting' | translate}}" status="info">
|
||||
<p><span translate>Syncthing is restarting.</span> <span translate>Please wait</span>...</p>
|
||||
</modal>
|
||||
|
||||
<modal id="upgrading" icon="refresh" title="{{'Upgrading' | translate}}" status="info">
|
||||
<p><span translate>Syncthing is upgrading.</span> <span translate>Please wait</span>...</p>
|
||||
</modal>
|
||||
|
||||
<!-- Shutdown modal -->
|
||||
@@ -399,7 +409,7 @@
|
||||
|
||||
<modal id="idqr" large="yes" status="info" close="yes" icon="qrcode" title="{{'Node Identification' | translate}} — {{nodeName(thisNode())}}">
|
||||
<div class="well well-sm text-monospace text-center">{{myID}}</div>
|
||||
<img ng-if="myID" class="center-block img-thumbnail" src="qr/{{myID}}"/>
|
||||
<img ng-if="myID" class="center-block img-thumbnail" src="qr/?text={{myID}}"/>
|
||||
</modal>
|
||||
|
||||
<!-- Node editor modal -->
|
||||
@@ -421,7 +431,7 @@
|
||||
<span translate ng-if="nodeEditor.nodeID.$valid || nodeEditor.nodeID.$pristine">The node ID to enter here can be found in the "Edit > Show ID" dialog on the other node. Spaces and dashes are optional (ignored).</span>
|
||||
<span translate ng-show="!editingExisting && (nodeEditor.nodeID.$valid || nodeEditor.nodeID.$pristine)">When adding a new node, keep in mind that this node must be added on the other side too.</span>
|
||||
<span translate ng-if="nodeEditor.nodeID.$error.required && nodeEditor.nodeID.$dirty">The node ID cannot be blank.</span>
|
||||
<span translate ng-if="nodeEditor.nodeID.$error.validNodeid && nodeEditor.nodeID.$dirty">The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.</span>
|
||||
<span translate ng-if="nodeEditor.nodeID.$error.validNodeid && nodeEditor.nodeID.$dirty">The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -682,8 +692,8 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p translate>The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.</p>
|
||||
<p translate translate-value-url="https://data.syncthing.net">The aggregated statistics are publicly available at {{url}}</p>
|
||||
<button translate type="button" class="btn btn-default" ng-show="!reportPreview" ng-click="reportPreview = true">Preview Usage Report</button>
|
||||
<p translate translate-value-url="https://data.syncthing.net">The aggregated statistics are publicly available at {%url%}.</p>
|
||||
<button translate type="button" class="btn btn-default" ng-show="!reportPreview" ng-click="showReportPreview()">Preview Usage Report</button>
|
||||
<pre ng-if="reportPreview"><small>{{reportData | json}}</small></pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -709,7 +719,7 @@
|
||||
<!-- About modal -->
|
||||
|
||||
<modal id="about" large="yes" close="yes" status="info" title="About">
|
||||
<h1 class="text-center"><img src="st-logo-128.png" style="vertical-align: -16px" width="64" height="64"/> Syncthing<br/><small>{{version}}</small></h1>
|
||||
<h1 class="text-center"><img alt="Syncthing" title="Syncthing" src="logo-text-256.png" style="vertical-align: -16px" height="100" width="366"/><br/><small>{{version}}</small></h1>
|
||||
<hr/>
|
||||
|
||||
<p translate>Copyright © 2014 Jakob Borg and the following Contributors:</p>
|
||||
@@ -722,6 +732,7 @@
|
||||
<li>Audrius Butkevicius</li>
|
||||
<li>Ben Sidhom</li>
|
||||
<li>Brandon Philips</li>
|
||||
<li>Gilli Sigurdsson</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
@@ -730,6 +741,7 @@
|
||||
<li>Jens Diemer</li>
|
||||
<li>Philippe Schommers</li>
|
||||
<li>Ryan Sullivan</li>
|
||||
<li>Tully Robinson</li>
|
||||
<li>Veeti Paananen</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
120
gui/lang-da.json
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"API Key": "API-nøgle",
|
||||
"About": "Om",
|
||||
"Add Node": "Tilføj node",
|
||||
"Add Repository": "Tilføj lager",
|
||||
"Address": "Adresse",
|
||||
"Addresses": "Adresser",
|
||||
"Allow Anonymous Usage Reporting?": "Tillad anonym brugerstatistik?",
|
||||
"Announce Server": "Opslagsserver",
|
||||
"Anonymous Usage Reporting": "Anonym brugerstatistik",
|
||||
"Bugs": "Fejl",
|
||||
"CPU Utilization": "CPU-forbrug",
|
||||
"Close": "Luk",
|
||||
"Connection Error": "Tilslutnings fejl",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg og følgende bidragsydere:",
|
||||
"Delete": "Slet",
|
||||
"Disconnected": "Ikke tilsluttet",
|
||||
"Documentation": "Dokumentation",
|
||||
"Download Rate": "Downloadhastighed",
|
||||
"Edit": "Rediger",
|
||||
"Edit Node": "Rediger node",
|
||||
"Edit Repository": "Rediger lager",
|
||||
"Enable UPnP": "Anvend UPnP",
|
||||
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Angiv kommaseparerat \"ip:port\"-adresser eller ordet \"dynamic\" for at benytte automatisk opslag.",
|
||||
"Error": "Fejl",
|
||||
"File Versioning": "Filversionering",
|
||||
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Filrettigheder tages der ikke hensyn til ved synkronisering. Anvend på FAT-filsystemer.",
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Filer flyttes til et datostemplet versionsnavn i et .stversions-bibliotek, når de bliver opdateret eller slettet af syncthing.",
|
||||
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Filer beskyttes mod ændringer fra andre noder, men ændringer på denne node bliver sendt til hele clusteret.",
|
||||
"Folder": "Bibliotek",
|
||||
"GUI Authentication Password": "GUI-kodeord",
|
||||
"GUI Authentication User": "GUI-brugernavn",
|
||||
"GUI Listen Addresses": "GUI-lytteadresse",
|
||||
"Generate": "Opret",
|
||||
"Global Discovery": "Globalt opslag",
|
||||
"Global Discovery Server": "Global opslagsserver",
|
||||
"Global Repository": "Global lagring",
|
||||
"Idle": "Inaktiv",
|
||||
"Ignore Permissions": "Ignorér filrettigheder",
|
||||
"Keep Versions": "Behold versioner",
|
||||
"Latest Release": "Seneste udgivelse",
|
||||
"Local Discovery": "Lokal opslag",
|
||||
"Local Discovery Port": "Lokal opslagsport",
|
||||
"Local Repository": "Lokal lagring",
|
||||
"Master Repo": "Hovedlagring",
|
||||
"Max File Change Rate (KiB/s)": "Højeste filændringshastighed (KiB/s)",
|
||||
"Max Outstanding Requests": "Parallelitet",
|
||||
"No": "Nej",
|
||||
"Node ID": "Node ID",
|
||||
"Node Identification": "Node identifikation",
|
||||
"Node Name": "Nodenavn",
|
||||
"Notice": "OBS",
|
||||
"OK": "OK",
|
||||
"Offline": "Offline",
|
||||
"Online": "Online",
|
||||
"Out Of Sync": "Ude af sync",
|
||||
"Outgoing Rate Limit (KiB/s)": "Udgående hastighedsbegrænsning (KiB/s)",
|
||||
"Override Changes": "Overskriv ændringer",
|
||||
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Sti til lagring på din lokale computer. Hvis biblioteket ikke findes vil det blive oprettet. Tegnet tilde (~) kan bruges som genvej til",
|
||||
"Please wait": "Vent venligst",
|
||||
"Preview Usage Report": "Forhåndsvisning af forbrugsrapport",
|
||||
"RAM Utilization": "RAM-forbrug",
|
||||
"Reconnect Interval (s)": "Gentilslutningsinterval (s)",
|
||||
"Repository ID": "Lagrings-ID",
|
||||
"Repository Master": "Hovedlagring",
|
||||
"Repository Path": "Sti til lagring",
|
||||
"Rescan Interval (s)": "Genscanningsinterval (s)",
|
||||
"Restart": "Genstart",
|
||||
"Restart Needed": "Programmet kræver genstart",
|
||||
"Restarting": "Genstarter",
|
||||
"Save": "Gem",
|
||||
"Scanning": "Opdaterer",
|
||||
"Select the nodes to share this repository with.": "Vælg hvilke noder denne lagring skal deles med.",
|
||||
"Settings": "Indstillinger",
|
||||
"Share With Nodes": "Del med noderne",
|
||||
"Shared With": "Delt med",
|
||||
"Short identifier for the repository. Must be the same on all cluster nodes.": "Kort identifikation for denne lagring. Skal være ens på alle noder i clusteret.",
|
||||
"Show ID": "Vis ID",
|
||||
"Shown instead of Node ID in the cluster status.": "Vises i stedet for node-ID under clusterstatus.",
|
||||
"Shutdown": "Luk ned",
|
||||
"Source Code": "Kildekode",
|
||||
"Start Browser": "Start browser",
|
||||
"Stopped": "Stoppet",
|
||||
"Support / Forum": "Support / Forum",
|
||||
"Sync Protocol Listen Addresses": "Lytteadresser for indgående forbindelser",
|
||||
"Synchronization": "Synkronisering",
|
||||
"Syncing": "Synkroniserer",
|
||||
"Syncthing has been shut down.": "Syncthing er blevet lukket ned.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing indeholder følgende software eller dele heraf:",
|
||||
"Syncthing is restarting.": "Syncthing genstarter",
|
||||
"Syncthing is upgrading.": "Syncthing opgradere",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ud til at være stoppet eller oplever problemer med din internetforbindels. Prøver igen...",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Samlet statistik er offentligt tilgængelig på {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Konfigurationen er gemt, men ikke aktiveret. Syncthing skal genstarte for at aktivere den nye konfiguration.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Den krypterede forbrugsrapport sendes dagligt. Den benyttes til at spore anvendte platforme, lagringsstørrelser og versioner. Hvis det typen af opsamlet data ændres på et senere tidspunkt, vil du blive spurgt om tilladelse igen.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Det indtastede node ID ser ikke gyldigt ud. Det skal være en 52 tegn streng, bestående af tal og bogstaver, eventuelt med mellemrum og bindestreger.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Det indtastede node ID ser ikke gyldigt ud. Det skal være en 52 eller 56 tegn streng, bestående af tal og bogstaver, eventuelt med mellemrum og bindestreger.",
|
||||
"The node ID cannot be blank.": "Node-ID'et kan ikke være blankt.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Node-ID'et som skal bruges her, kan du finde i \"Rediger > Vis ID\"-dialogen på den anden node. Mellemrum og bindestreg er valgfri (ignoreres).",
|
||||
"The number of old versions to keep, per file.": "Antallet af gamle versioner som gemmes, per fil.",
|
||||
"The number of versions must be a number and cannot be blank.": "Antallet af versioner skal være et tal, og kan ikke være blankt.",
|
||||
"The repository ID cannot be blank.": "Lagrings-ID kan ikke være blankt.",
|
||||
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Lagrings-ID'et skal være en kort identificierende streng (64 karaktere eller mindre) bestående af bogstav-, tal-, punktum- (.), bindestreg- (-) og understregskaraktere (_).",
|
||||
"The repository ID must be unique.": "Lagrings-ID'et skal være unikt.",
|
||||
"The repository path cannot be blank.": "Lagringsstien kan ikke være blank.",
|
||||
"Unknown": "Ukendt",
|
||||
"Up to Date": "Fuldt opdateret",
|
||||
"Upgrade To {%version%}": "Opgradér til {{version}}",
|
||||
"Upgrading": "Opgradere",
|
||||
"Upload Rate": "Uploadhastighed",
|
||||
"Usage": "Forbrug",
|
||||
"Use Compression": "Anvend komprimering",
|
||||
"Use HTTPS for GUI": "Anvend HTTPS til GUI adgang",
|
||||
"Version": "Version",
|
||||
"When adding a new node, keep in mind that this node must be added on the other side too.": "Når du tilføjer en ny node skal du huske, at den også skal tilføjes på den anden side.",
|
||||
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Når du tilføjer en ny node skal du huske, at lagrings-ID'et bliver brugt til at knytte noder sammen. De er følsomme for store og små bogstaver og skal matche på alle noder.",
|
||||
"Yes": "Ja",
|
||||
"You must keep at least one version.": "Du skal beholde mindst én version.",
|
||||
"items": "poster"
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
"Bugs": "Fehler",
|
||||
"CPU Utilization": "Prozessorauslastung",
|
||||
"Close": "Schließen",
|
||||
"Connection Error": "Verbindungsfehler",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg und folgende Unterstützer:",
|
||||
"Delete": "Löschen",
|
||||
"Disconnected": "Verbindung getrennt",
|
||||
@@ -46,6 +47,7 @@
|
||||
"Max Outstanding Requests": "Max. ausstehende Anfragen",
|
||||
"No": "Nein",
|
||||
"Node ID": "Knoten-ID",
|
||||
"Node Identification": "Knoten Identifikation",
|
||||
"Node Name": "Knoten-Name",
|
||||
"Notice": "Benachrichtigung",
|
||||
"OK": "Ok",
|
||||
@@ -65,6 +67,7 @@
|
||||
"Rescan Interval (s)": "Suchintervall (s)",
|
||||
"Restart": "Neustart",
|
||||
"Restart Needed": "Neustart notwendig",
|
||||
"Restarting": "Wird neu gestartet",
|
||||
"Save": "Speichern",
|
||||
"Scanning": "Überprüfe",
|
||||
"Select the nodes to share this repository with.": "Wähle die Knoten aus, mit denen du dieses Verzeichnis teilen willst.",
|
||||
@@ -84,11 +87,14 @@
|
||||
"Syncing": "Synchronisiere",
|
||||
"Syncthing has been shut down.": "Syncthing wurde heruntergefahren.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing enthält die folgende Software oder Teile davon:",
|
||||
"Syncthing is restarting.": "Syncthing wird neu gestartet",
|
||||
"Syncthing is upgrading.": "Syncthing wird aktualisiert",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing scheint nicht erreichbar zu sein oder es gibt ein Problem mit Ihrer Internetverbindung. Versuche erneut...",
|
||||
"The aggregated statistics are publicly available at {{url}}": "Die aggregierten Statistiken sind öffentlich verfügbar unter {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Die aggregierten Statistiken sind öffentlich verfügbar unter {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Die Konfiguration wurde gespeichert, aber nicht aktiviert. Syncthing muss neugestartet werden um die neue Konfiguration zu aktivieren.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Der verschlüsselte Benutzungsbericht wird täglich gesendet. Er wird benutzt um Statistiken über verwendete Betriebssysteme, Verzeichnis-Größen und Programm-Versionen zu erstellen. Sobald der Bericht in Zukunft weitere Daten erfasst, wird dir dieses Fenster erneut angezeigt.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Die eingegebene Knoten-ID scheint nicht gültig zu sein. Sie sollte eine 52 Stellen lange Zeichenkette aus Buchstaben und Zahlen sein. Leerzeichen und Striche sind optional (werden ignoriert).",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Die eingegebene Knoten-ID scheint nicht gültig zu sein. Es sollte eine 52 oder 56 stellige Zeichenkette aus Buchstaben und Nummern sein. Leerzeichen und Bindestriche sind optional.",
|
||||
"The node ID cannot be blank.": "Die Knoten-ID darf nicht leer sein.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Die hier einzutragende Knoten-ID kann im \"Bearbeiten > Zeige ID\"-Dialog auf dem anderen Knoten gefunden werden. Leerzeichen und Striche sind optional (werden ignoriert).",
|
||||
"The number of old versions to keep, per file.": "Anzahl der alten Versionen, die von jeder Datei gespeichert werden sollen.",
|
||||
@@ -100,6 +106,7 @@
|
||||
"Unknown": "Unbekannt",
|
||||
"Up to Date": "Aktuell",
|
||||
"Upgrade To {%version%}": "Upgrade auf {{version}}",
|
||||
"Upgrading": "Wird aktualisiert",
|
||||
"Upload Rate": "Uploadgeschwindigkeit",
|
||||
"Usage": "Benutzung",
|
||||
"Use Compression": "Benutze Komprimierung",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"Bugs": "Bugs",
|
||||
"CPU Utilization": "Χρήση CPU",
|
||||
"Close": "Τέλος",
|
||||
"Connection Error": "Σφάλμα Σύνδεσης",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg και οι παρακάτω Συνεισφορείς:",
|
||||
"Delete": "Διαγραφή",
|
||||
"Disconnected": "Αποσυνδεδεμένος",
|
||||
@@ -32,7 +33,7 @@
|
||||
"GUI Listen Addresses": "GUI Listen Addresses",
|
||||
"Generate": "Δημιουργία",
|
||||
"Global Discovery": "Global Discovery",
|
||||
"Global Discovery Server": "Global Discovery Server",
|
||||
"Global Discovery Server": "Διακομιστής Ανεύρεσης Κόμβου",
|
||||
"Global Repository": "Global Repository",
|
||||
"Idle": "Ανενεργός",
|
||||
"Ignore Permissions": "Ignore Permissions",
|
||||
@@ -46,6 +47,7 @@
|
||||
"Max Outstanding Requests": "Max Outstanding Requests",
|
||||
"No": "Αριθμός",
|
||||
"Node ID": "ID Κόμβου",
|
||||
"Node Identification": "Ταυτοποίηση Κόμβου",
|
||||
"Node Name": "Όνομα Κόμβου",
|
||||
"Notice": "Notice",
|
||||
"OK": "OK",
|
||||
@@ -65,8 +67,9 @@
|
||||
"Rescan Interval (s)": "Rescan Interval (s)",
|
||||
"Restart": "Επανεκκίνηση",
|
||||
"Restart Needed": "Απαιτείται Επανεκκίνηση",
|
||||
"Restarting": "Επανεκκίνηση",
|
||||
"Save": "Αποθήκευση",
|
||||
"Scanning": "Scanning",
|
||||
"Scanning": "Σάρρωση",
|
||||
"Select the nodes to share this repository with.": "Επιλογή των κόμβων με τους οποίους θα διαμοιραστεί αυτό το αποθετήριο.",
|
||||
"Settings": "Ρυθμίσεις",
|
||||
"Share With Nodes": "Διαμοιρασμός με Κόμβους",
|
||||
@@ -81,14 +84,17 @@
|
||||
"Support / Forum": "Υποστήριξη / Forum",
|
||||
"Sync Protocol Listen Addresses": "Sync Protocol Listen Addresses",
|
||||
"Synchronization": "Συγχρονισμός",
|
||||
"Syncing": "Syncing",
|
||||
"Syncing": "Συγχρονισμός",
|
||||
"Syncthing has been shut down.": "Syncthing έχει απενεργοποιηθεί.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing includes the following software or portions thereof:",
|
||||
"Syncthing is restarting.": "Το Syncthing επανεκκινεί.",
|
||||
"Syncthing is upgrading.": "Το Syncthing αναβαθμίζεται.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…",
|
||||
"The aggregated statistics are publicly available at {{url}}": "The aggregated statistics are publicly available at {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Τα στατιστικά που έχουν συλλεγεί είναι διαθέσιμα στο κοινό, στο {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Το ID Κόμβου δεν είναι έγκυρο. Θα πρέπει να είναι αλφαριθμιτικό με 52 ή 56 χαρακτήρες και να αποτελείται από γράμματα και αριθμούς, που προαιρετικά χωρίζονται με κενά και παύλες.",
|
||||
"The node ID cannot be blank.": "The node ID cannot be blank.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Το ID Κόμβου μπορείτε να βρείτε στο μενού \"Επεξεργασία > Εμφάνιση ID\" του άλλου κόμβου. Κενά και παύλες είναι προαιρετικά (αγνοούνται).",
|
||||
"The number of old versions to keep, per file.": "The number of old versions to keep, per file.",
|
||||
@@ -100,6 +106,7 @@
|
||||
"Unknown": "Άγνωστο",
|
||||
"Up to Date": "Ενημερώμενο",
|
||||
"Upgrade To {%version%}": "Αναβάθμιση στην έκδοση {{version}}",
|
||||
"Upgrading": "Αναβάθμιση",
|
||||
"Upload Rate": "Upload Rate",
|
||||
"Usage": "Usage",
|
||||
"Use Compression": "Χρήση συμπίεσης",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"Bugs": "Bugs",
|
||||
"CPU Utilization": "CPU Utilization",
|
||||
"Close": "Close",
|
||||
"Connection Error": "Connection Error",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg and the following Contributors:",
|
||||
"Delete": "Delete",
|
||||
"Disconnected": "Disconnected",
|
||||
@@ -46,6 +47,7 @@
|
||||
"Max Outstanding Requests": "Max Outstanding Requests",
|
||||
"No": "No",
|
||||
"Node ID": "Node ID",
|
||||
"Node Identification": "Node Identification",
|
||||
"Node Name": "Node Name",
|
||||
"Notice": "Notice",
|
||||
"OK": "OK",
|
||||
@@ -65,6 +67,7 @@
|
||||
"Rescan Interval (s)": "Rescan Interval (s)",
|
||||
"Restart": "Restart",
|
||||
"Restart Needed": "Restart Needed",
|
||||
"Restarting": "Restarting",
|
||||
"Save": "Save",
|
||||
"Scanning": "Scanning",
|
||||
"Select the nodes to share this repository with.": "Select the nodes to share this repository with.",
|
||||
@@ -84,11 +87,14 @@
|
||||
"Syncing": "Syncing",
|
||||
"Syncthing has been shut down.": "Syncthing has been shut down.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing includes the following software or portions thereof:",
|
||||
"Syncthing is restarting.": "Syncthing is restarting.",
|
||||
"Syncthing is upgrading.": "Syncthing is upgrading.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…",
|
||||
"The aggregated statistics are publicly available at {{url}}": "The aggregated statistics are publicly available at {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "The aggregated statistics are publicly available at {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.",
|
||||
"The node ID cannot be blank.": "The node ID cannot be blank.",
|
||||
"The node ID to enter here can be found in the \"Edit \u003e Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "The node ID to enter here can be found in the \"Edit \u003e Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).",
|
||||
"The number of old versions to keep, per file.": "The number of old versions to keep, per file.",
|
||||
@@ -100,6 +106,7 @@
|
||||
"Unknown": "Unknown",
|
||||
"Up to Date": "Up to Date",
|
||||
"Upgrade To {%version%}": "Upgrade To {{version}}",
|
||||
"Upgrading": "Upgrading",
|
||||
"Upload Rate": "Upload Rate",
|
||||
"Usage": "Usage",
|
||||
"Use Compression": "Use Compression",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"Bugs": "Errores",
|
||||
"CPU Utilization": "Uso de la CPU",
|
||||
"Close": "Cerrar",
|
||||
"Connection Error": "Connection Error",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Derechos de autor © 2014 Jakob Borg y los siguientes colaboradores:",
|
||||
"Delete": "Suprimir",
|
||||
"Disconnected": "Desconectado",
|
||||
@@ -46,6 +47,7 @@
|
||||
"Max Outstanding Requests": "Cantidad máxima de peticiones pendientes",
|
||||
"No": "No",
|
||||
"Node ID": "Nodo ID",
|
||||
"Node Identification": "Node Identification",
|
||||
"Node Name": "Nodo nombre",
|
||||
"Notice": "Aviso",
|
||||
"OK": "OK",
|
||||
@@ -65,6 +67,7 @@
|
||||
"Rescan Interval (s)": "Intervalo de reescaneo (s)",
|
||||
"Restart": "Reiniciar",
|
||||
"Restart Needed": "Es necesario reiniciar",
|
||||
"Restarting": "Restarting",
|
||||
"Save": "Guardar",
|
||||
"Scanning": "Actualización",
|
||||
"Select the nodes to share this repository with.": "Seleccione los nodos con los cuales compartir el repositorio.",
|
||||
@@ -84,11 +87,14 @@
|
||||
"Syncing": "Sincronización",
|
||||
"Syncthing has been shut down.": "La sincronización esta apagada",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing incluye los siguientes softwares o partes de ellos:",
|
||||
"Syncthing is restarting.": "Syncthing is restarting.",
|
||||
"Syncthing is upgrading.": "Syncthing is upgrading.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing parece estar apagado, o hay un problema con su conexión de Internet. Reintentando...",
|
||||
"The aggregated statistics are publicly available at {{url}}": "Las estadísticas acumuladas están públicamente disponibles en {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Las estadísticas acumuladas están públicamente disponibles en {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuración ha sido guardada pero no activada.\nSyncthing debe reiniciarse para activar la nueva configuración.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "El reporte de uso se envía encriptado diariamente. Se utiliza para hacer un seguimiento de plataformas comunes, tamaño de repositorios y versión de aplicaciones. Si el conjunto de datos cambia sera notificado mediante este dialogo nuevamente.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "El ID de nodo ingresado no es valido. Debe ser una cadena de al menos 52 caracteres consistente en letras y números, con espacios y guiones opcionales.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "El ID de nodo ingresado no es valido. Debe ser una cadena de 52 o de 56 caracteres consistente en letras y números, con espacios y guiones opcionales.",
|
||||
"The node ID cannot be blank.": "El ID de nodo no puede estar vacío.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "El ID de nodo a ingresar aquí puede verse en la opción de menú \"Edición > Mostrar ID\" del otro nodo. Espacios y guiones son opcionales (ignorados).",
|
||||
"The number of old versions to keep, per file.": "El numero de versiones anteriores a conservar, por archivo.",
|
||||
@@ -100,9 +106,10 @@
|
||||
"Unknown": "Desconocido",
|
||||
"Up to Date": "Actualizado",
|
||||
"Upgrade To {%version%}": "Actualizar a {{version}}",
|
||||
"Upgrading": "Upgrading",
|
||||
"Upload Rate": "Tasa de subida",
|
||||
"Usage": "Utilización",
|
||||
"Use Compression": "Use Compression",
|
||||
"Use Compression": "Usar compresión",
|
||||
"Use HTTPS for GUI": "Usar HTTPS para la GUI",
|
||||
"Version": "Versión",
|
||||
"When adding a new node, keep in mind that this node must be added on the other side too.": "Al agregar un nuevo nodo, recuerde que este nodo debe ser agregado en el otro lado también.",
|
||||
|
||||
@@ -5,17 +5,18 @@
|
||||
"Add Repository": "Ajouter un répertoire",
|
||||
"Address": "Adresse",
|
||||
"Addresses": "Adresses",
|
||||
"Allow Anonymous Usage Reporting?": "Autoriser le rapport anonyme de statistiques d'utilisation?",
|
||||
"Allow Anonymous Usage Reporting?": "Autoriser le rapport anonyme de statistiques d'utilisation ?",
|
||||
"Announce Server": "Serveur d'annonce",
|
||||
"Anonymous Usage Reporting": "Rapport anonyme de statistiques d'utilisation",
|
||||
"Bugs": "Bugs",
|
||||
"CPU Utilization": "Utilisation du CPU",
|
||||
"Close": "Fermer",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg et les contributeurs suivants:",
|
||||
"Connection Error": "Erreur de connexion",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg et les contributeurs suivants :",
|
||||
"Delete": "Supprimer",
|
||||
"Disconnected": "Déconnecté",
|
||||
"Documentation": "Documentation",
|
||||
"Download Rate": "Débit de téléchargement",
|
||||
"Download Rate": "Débit de réception",
|
||||
"Edit": "Éditer",
|
||||
"Edit Node": "Éditer le nœud",
|
||||
"Edit Repository": "Éditer le répertoire",
|
||||
@@ -23,8 +24,8 @@
|
||||
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Entrer les adresses \"ip:port\" séparées par une virgule ou \"dynamic\" afin d'activer la recherche automatique de l'adresse.",
|
||||
"Error": "Erreur",
|
||||
"File Versioning": "Versions de fichier",
|
||||
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Les permissions de fichier sont ignorées lors de la recherche de changements. À utiliser sur les systèmes de fichiers en FAT.",
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Les fichiers sont datés et déplacés dans le dossier .stversions lors de leurs remplacements ou suppressions par syncthing.",
|
||||
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Les permissions de fichier sont ignorées lors de la recherche de changements. À utiliser sur les systèmes de fichiers de type FAT.",
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Les fichiers sont datés et déplacés dans le dossier .stversions lors de leur remplacement ou suppression par syncthing.",
|
||||
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Les fichiers sont protégés des changements réalisés sur les autres nœuds, mais les changements réalisés sur ce nœud seront transférés au reste du cluster.",
|
||||
"Folder": "Dossier",
|
||||
"GUI Authentication Password": "Mot de passe d'authentification GUI",
|
||||
@@ -43,9 +44,10 @@
|
||||
"Local Repository": "Dossier local",
|
||||
"Master Repo": "Dossier maître",
|
||||
"Max File Change Rate (KiB/s)": "Débit maximum de changement de fichier (KiB/s)",
|
||||
"Max Outstanding Requests": "Nombre maximum de demandes conccurentes de blocs de fichier",
|
||||
"Max Outstanding Requests": "Nombre maximum de demandes concurrentes de blocs de fichier",
|
||||
"No": "Non",
|
||||
"Node ID": "ID du nœud",
|
||||
"Node Identification": "Identification du nœud",
|
||||
"Node Name": "Nom du nœud",
|
||||
"Notice": "Notification",
|
||||
"OK": "OK",
|
||||
@@ -65,8 +67,9 @@
|
||||
"Rescan Interval (s)": "Intervalle de rescan (s)",
|
||||
"Restart": "Redémarrer",
|
||||
"Restart Needed": "Redémarrage nécessaire",
|
||||
"Restarting": "Redémarrage",
|
||||
"Save": "Sauver",
|
||||
"Scanning": "Scanning",
|
||||
"Scanning": "En cours de scan",
|
||||
"Select the nodes to share this repository with.": "Sélectionner les nœuds qui partageront ce répertoire.",
|
||||
"Settings": "Configuration",
|
||||
"Share With Nodes": "Partager avec les nœuds",
|
||||
@@ -84,29 +87,33 @@
|
||||
"Syncing": "En cours de synchronisation",
|
||||
"Syncthing has been shut down.": "Syncthing a été éteint.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing inclut les logiciels, ou portion de ceux-ci, suivants:",
|
||||
"Syncthing is restarting.": "Syncthing est cours de redémarrage.",
|
||||
"Syncthing is upgrading.": "Syncthing est cours de mise à jour.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing semble être éteint, ou il y a un problème avec votre connexion Internet. Nouvelle tentative ...",
|
||||
"The aggregated statistics are publicly available at {{url}}": "Les statistiques agrégées sont disponibles publiquement à l'adresse {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Les statistiques agrégées sont disponibles publiquement à l'adresse {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuration a été sauvée mais pas activée. Syncthing doit redémarrer afin d'activer la nouvelle configuration.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Le rapport d'utilisation chiffré est envoyé quotidiennement. Il sert à répertorier les plateformes utilisées, la taille des répertoires et les versions de l'application. Si le jeu de données rapportées devait être changé, il vous sera demandé de le valider de nouveau via ce dialogue.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "L'ID du nœud ne semble pas être valide. Il devrait ressembler à une chaine de 52 caractères comprenant lettres et chiffres, avec des espaces et des traits d'union optionnels.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "L'ID du nœud inséré ne semble pas être valide. Il devrait ressembler à une chaîne de 52 ou 56 comprenant lettres et chiffres, avec des espaces et des traits d'union optionnels.",
|
||||
"The node ID cannot be blank.": "L'ID du nœud ne peut être vide.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "L'ID du nœud à insérer peut être trouvé à travers le menu \"Éditer > Montrer l'ID\" des autres nœuds. Les espaces et les traits d'union sont optionnels (ils seront ignorés).",
|
||||
"The number of old versions to keep, per file.": "Le nombre d'anciennes versions à garder, par fichier.",
|
||||
"The number of versions must be a number and cannot be blank.": "Le nombre de version doit être un nombre et ne peut pas être vide.",
|
||||
"The repository ID cannot be blank.": "L'ID du répertoire ne peut être vide.",
|
||||
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "L'ID du répertoire doit un identifiant court (64 caractères ou moins) comprenant des lettres, nombres, points (.), trait d'union (-) et tiret bas (_).",
|
||||
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "L'ID du répertoire doit être un identifiant court (64 caractères ou moins) comprenant des lettres, nombres, points (.), trait d'union (-) et tiret bas (_).",
|
||||
"The repository ID must be unique.": "L'ID du répertoire doit être unique.",
|
||||
"The repository path cannot be blank.": "Le chemin du répertoire ne peut pas être vide.",
|
||||
"Unknown": "Inconnu",
|
||||
"Up to Date": "Synchronistation à jour",
|
||||
"Up to Date": "Synchronisation à jour",
|
||||
"Upgrade To {%version%}": "Upgrader vers {{version}}",
|
||||
"Upgrading": "Mise à jour de Syncthing",
|
||||
"Upload Rate": "Débit d'envoi",
|
||||
"Usage": "Utilisation",
|
||||
"Use Compression": "Utiliser la compression",
|
||||
"Use HTTPS for GUI": "Utiliser l'HTTPS pour le GUI",
|
||||
"Version": "Version",
|
||||
"When adding a new node, keep in mind that this node must be added on the other side too.": "Lorsqu'un nœud est ajouté, gardez à l'esprit que ce nœud doit aussi être ajouté de l'autre coté.",
|
||||
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Lorsqu'un nouveau répertoire est ajouté, gardez à l'esprit que l'ID du répertoire est utilisé pour lier les répertoires à travers les nœuds. Ils sont sensibles à la case et doivent être semblables à travers tous les nœuds.",
|
||||
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Lorsqu'un nouveau répertoire est ajouté, gardez à l'esprit que l'ID du répertoire est utilisé pour lier les répertoires à travers les nœuds. Ils sont sensibles à la casse et doivent être identiques à travers tous les nœuds.",
|
||||
"Yes": "Oui",
|
||||
"You must keep at least one version.": "Vous devez garder au minimum une version.",
|
||||
"items": "éléments"
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
"Address": "Indirizzo",
|
||||
"Addresses": "Indirizzi",
|
||||
"Allow Anonymous Usage Reporting?": "Abilitare Statistiche Anonime di Utilizzo?",
|
||||
"Announce Server": "Server di Ricerca Globale dei Nodi",
|
||||
"Announce Server": "Server di Presenza Globale dei Nodi",
|
||||
"Anonymous Usage Reporting": "Statistiche Anonime di Utilizzo",
|
||||
"Bugs": "Bug",
|
||||
"CPU Utilization": "Utilizzo della CPU",
|
||||
"Close": "Chiudi",
|
||||
"Connection Error": "Connection Error",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg e i seguenti Collaboratori:",
|
||||
"Delete": "Elimina",
|
||||
"Disconnected": "Disconnesso",
|
||||
@@ -32,7 +33,7 @@
|
||||
"GUI Listen Addresses": "Indirizzi dell'Interfaccia Grafica",
|
||||
"Generate": "Genera",
|
||||
"Global Discovery": "Individuazione Globale",
|
||||
"Global Discovery Server": "Global Discovery Server",
|
||||
"Global Discovery Server": "Server di Ricerca Globale",
|
||||
"Global Repository": "Deposito Globale",
|
||||
"Idle": "Inattivo",
|
||||
"Ignore Permissions": "Ignora Permessi",
|
||||
@@ -46,6 +47,7 @@
|
||||
"Max Outstanding Requests": "Numero Massimo di Richieste Simultanee per i Blocchi di File",
|
||||
"No": "No",
|
||||
"Node ID": "ID Nodo",
|
||||
"Node Identification": "Node Identification",
|
||||
"Node Name": "Nome Nodo",
|
||||
"Notice": "Avviso",
|
||||
"OK": "OK",
|
||||
@@ -65,6 +67,7 @@
|
||||
"Rescan Interval (s)": "Intervallo di Scansione dei File (s)",
|
||||
"Restart": "Riavvia",
|
||||
"Restart Needed": "Riavvio Necessario",
|
||||
"Restarting": "Restarting",
|
||||
"Save": "Salva",
|
||||
"Scanning": "Scansione in corso",
|
||||
"Select the nodes to share this repository with.": "Seleziona i nodi con i quali vuoi condividere questo deposito.",
|
||||
@@ -84,11 +87,14 @@
|
||||
"Syncing": "Sincronizzazione in corso",
|
||||
"Syncthing has been shut down.": "Syncthing è stato arrestato.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing include i seguenti software o porzioni di questi:",
|
||||
"Syncthing is restarting.": "Syncthing is restarting.",
|
||||
"Syncthing is upgrading.": "Syncthing is upgrading.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing sembra inattivo, oppure c'è un problema con la tua connessione a Internet. Nuovo tentativo…",
|
||||
"The aggregated statistics are publicly available at {{url}}": "Le statistiche aggregate sono disponibili pubblicamente su {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Le statistiche aggregate sono disponibili pubblicamente su {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configurazione è stata salvata ma non attivata. Devi riavviare Syncthing per attivare la nuova configurazione.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Quotidianamente il software invia le statistiche di utilizzo in forma criptata. Questi dati riguardano i sistemi operativi utilizzati, le dimensioni dei depositi e le versioni del software. Se i dati riportati cambiano verrà mostrata di nuovo questa finestra di dialogo.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "L'ID del nodo inserito non sembra valido. Dovrebbe essere una stringa di 52 caratteri costituita da lettere e numeri, con spazi e trattini opzionali.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "L'ID del nodo inserito non sembra valido. Dovrebbe essere una stringa di 52 o 56 caratteri costituita da lettere e numeri, con spazi e trattini opzionali.",
|
||||
"The node ID cannot be blank.": "L'ID del nodo non può essere vuoto.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Trova l'ID del nodo nella finestra di dialogo \"Modifica > Mostra ID\" dell'altro nodo e poi inseriscilo qui. Gli spazi e i trattini sono opzionali (ignorati).",
|
||||
"The number of old versions to keep, per file.": "Il numero di vecchie versioni da mantenere, per file.",
|
||||
@@ -100,6 +106,7 @@
|
||||
"Unknown": "Sconosciuto",
|
||||
"Up to Date": "Sincronizzato",
|
||||
"Upgrade To {%version%}": "Aggiorna Alla {{version}}",
|
||||
"Upgrading": "Upgrading",
|
||||
"Upload Rate": "Velocità Upload",
|
||||
"Usage": "Utilizzo",
|
||||
"Use Compression": "Utilizza Compressione",
|
||||
|
||||
120
gui/lang-nl.json
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"API Key": "API-sleutel",
|
||||
"About": "Over",
|
||||
"Add Node": "Voeg node toe",
|
||||
"Add Repository": "Voeg repository toe",
|
||||
"Address": "Adres",
|
||||
"Addresses": "Adressen",
|
||||
"Allow Anonymous Usage Reporting?": "Bijhouden van anonieme gebruikers statistieken toestaan?",
|
||||
"Announce Server": "Aankondigings Server",
|
||||
"Anonymous Usage Reporting": "Bijhouden anonieme gebruikers statistieken",
|
||||
"Bugs": "Fouten",
|
||||
"CPU Utilization": "CPU Gebruik",
|
||||
"Close": "Sluiten",
|
||||
"Connection Error": "Verbindingsfout",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg en de onderstaande bijdragers:",
|
||||
"Delete": "Verwijderen",
|
||||
"Disconnected": "Niet Verbonden",
|
||||
"Documentation": "Documentatie",
|
||||
"Download Rate": "Downloadsnelheid",
|
||||
"Edit": "Bewerk",
|
||||
"Edit Node": "Bewerk node",
|
||||
"Edit Repository": "Repository Bijwerken",
|
||||
"Enable UPnP": "UPnP aanzetten",
|
||||
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Geef, gescheiden door komma's, \"ip:port\" adressen of \"dynamic\" voor het automatische vinden van de addressen.",
|
||||
"Error": "Fout",
|
||||
"File Versioning": "Versiebeheer",
|
||||
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Bestands permissiebits worden genegeerd wanneer naar veranderingen wordt gekeken. Gebruik dit op FAT bestandsystemen",
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Bestanden worden naar de .stversions map verplaatst met een tijdsaanduiding, wanneer ze aangepast of verwijderd worden door syncthing.",
|
||||
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Bestanden zijn beschermd tegen verandering gedaan op andere nodes, maar veranderingen op deze node worden naar de rest van het cluster gestuurd",
|
||||
"Folder": "Map",
|
||||
"GUI Authentication Password": "GUI Authentificatie Wachtwoord",
|
||||
"GUI Authentication User": "GUI Authentificatie Gebruikersnaam",
|
||||
"GUI Listen Addresses": "GUI Inkomend adres",
|
||||
"Generate": "Genereer",
|
||||
"Global Discovery": "Globaal zoeken",
|
||||
"Global Discovery Server": "Globale zoekserver",
|
||||
"Global Repository": "Globale repository",
|
||||
"Idle": "Klaar",
|
||||
"Ignore Permissions": "Rechten negeren",
|
||||
"Keep Versions": "Versies behouden",
|
||||
"Latest Release": "Laatste uitgave",
|
||||
"Local Discovery": "Lokaal zoeken",
|
||||
"Local Discovery Port": "Lokaal zoeken-poort",
|
||||
"Local Repository": "Lokale repository",
|
||||
"Master Repo": "Tegen veranderingen beschermen",
|
||||
"Max File Change Rate (KiB/s)": "Maximale bestands uitwisselsnelheid (KiB/s)",
|
||||
"Max Outstanding Requests": "Maximaal aantal openstaande aanvragen",
|
||||
"No": "Nee",
|
||||
"Node ID": "Node ID",
|
||||
"Node Identification": "Node Identificatie",
|
||||
"Node Name": "Node naam",
|
||||
"Notice": "Notificatie",
|
||||
"OK": "OK",
|
||||
"Offline": "Offline",
|
||||
"Online": "Online",
|
||||
"Out Of Sync": "Niet gesynchroniseerd",
|
||||
"Outgoing Rate Limit (KiB/s)": "Uitgaande snelheidslimiet (KiB/s)",
|
||||
"Override Changes": "Veranderingen overschrijven",
|
||||
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Pad naar de repository op de lokale computer. Word aangemaakt indien deze niet bestaat. Het tilde (~) karakter kan gebruikt worden als afkorting voor",
|
||||
"Please wait": "Even geduld",
|
||||
"Preview Usage Report": "Bekijk gebruikers statistieken",
|
||||
"RAM Utilization": "RAM gebruik",
|
||||
"Reconnect Interval (s)": "Herverbind-interval (s)",
|
||||
"Repository ID": "Repository ID",
|
||||
"Repository Master": "Hoofd repository",
|
||||
"Repository Path": "Pad van repository",
|
||||
"Rescan Interval (s)": "Herscan interval (s)",
|
||||
"Restart": "Herstart",
|
||||
"Restart Needed": "Herstart nodig",
|
||||
"Restarting": "Herstarten",
|
||||
"Save": "Bewaar",
|
||||
"Scanning": "Aan het zoeken",
|
||||
"Select the nodes to share this repository with.": "Selecteer de nodes om deze repository mee te delen",
|
||||
"Settings": "Instellingen",
|
||||
"Share With Nodes": "Deel met nodes",
|
||||
"Shared With": "Gedeeld met",
|
||||
"Short identifier for the repository. Must be the same on all cluster nodes.": "Korte naam voor de repository. Moet hetzelfde zijn op alle nodes in het cluster.",
|
||||
"Show ID": "Toon ID",
|
||||
"Shown instead of Node ID in the cluster status.": "Wordt weergegeven i.p.v. het node ID in de cluster status",
|
||||
"Shutdown": "Sluit af",
|
||||
"Source Code": "Broncode",
|
||||
"Start Browser": "Start browser",
|
||||
"Stopped": "Gestopt",
|
||||
"Support / Forum": "Support / Forum",
|
||||
"Sync Protocol Listen Addresses": "Synchronisatie protocol luister adres",
|
||||
"Synchronization": "Synchronisatie",
|
||||
"Syncing": "Aan het synchroniseren",
|
||||
"Syncthing has been shut down.": "Syncthing is afgesloten",
|
||||
"Syncthing includes the following software or portions thereof:": "De volgende software of delen daarvan zijn onderdeel van syncthing:",
|
||||
"Syncthing is restarting.": "Syncthing is aan het herstarten.",
|
||||
"Syncthing is upgrading.": "Syncthing is aan het upgraden.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing lijkt afgesloten te zijn, of er is een verbindingsprobleem met het internet. Nieuwe poging....",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "The verzamelde statistieken zijn publiek beschikbaar op {{url}}",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "De configuratie is opslagen maar nog niet actief. Syncthing moet opnieuw opgestart worden om de nieuwe configuratie te activeren.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "De versleutelde gebruikers statistieken worden dagelijks verstuurd. Deze worden gebruikt om veelgebruikte platformen, repo groottes en app versies bij te houden. Als er nieuwe statistieken worden bijgehouden, wordt dit venster weer getoond.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Het ingevoerde node ID lijkt niet valide te zijn. Het moet een 52 karakter lange string zijn bestaande uit letters en cijfers, spaties en streepjes zijn optioneel.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Het ingevoerde node ID lijkt niet valide te zijn. Het moet een 52 of 56 karakter lange string zijn, bestaande uit letters en cijfers, spaties en streepjes zijn optioneel.",
|
||||
"The node ID cannot be blank.": "Er moet een node ID ingevoerd worden",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Het node ID dat ingevoerd moet worden kan op de andere node gevonden via \"Bewerk > Toon ID\". Spaties en streepjes zijn toegestaan (worden genegeerd).",
|
||||
"The number of old versions to keep, per file.": "Het aantal versies dat bewaard moet worden per file.",
|
||||
"The number of versions must be a number and cannot be blank.": "Het aantal nummers moet een getal zijn en mag niet leeg blijven.",
|
||||
"The repository ID cannot be blank.": "Er moet een repository ID ingevoerd worden.",
|
||||
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Het repository ID moet een korte naam zijn (met 64 karakters of minder) en mag alleen bestaan uit cijfers, letters, punten (.), streepjes (-) en liggende streepjes (_). ",
|
||||
"The repository ID must be unique.": "Het repository ID moet uniek zijn.",
|
||||
"The repository path cannot be blank.": "Het repository ID moet ingevuld worden.",
|
||||
"Unknown": "Onbekend",
|
||||
"Up to Date": "Gesynchroniseerd",
|
||||
"Upgrade To {%version%}": "Upgrade naar {{version}}",
|
||||
"Upgrading": "Bezig met upgrade",
|
||||
"Upload Rate": "Upload snelheid",
|
||||
"Usage": "Gebruik",
|
||||
"Use Compression": "Compressie gebruiken",
|
||||
"Use HTTPS for GUI": "Gebruik HTTPS voor de GUI",
|
||||
"Version": "Versie",
|
||||
"When adding a new node, keep in mind that this node must be added on the other side too.": "Bedenk bij het toevoegen van een nieuwe node dat deze node ook toegevoegd moet worden aan de kant van de nieuwe node.",
|
||||
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Bedenk bij het toevoegen van een nieuwe repository dat het repository ID de repositores met elkaar verbindt tussen de nodes. Ze zijn hoofdlettergevoelig en moeten exact dezelfde naam hebben op alle nodes.",
|
||||
"Yes": "Ja",
|
||||
"You must keep at least one version.": "Minstens 1 versie moet bewaard blijven.",
|
||||
"items": "objecten"
|
||||
}
|
||||
119
gui/lang-pt.json
@@ -1,112 +1,119 @@
|
||||
{
|
||||
"API Key": "Chave API",
|
||||
"About": "Acerca de",
|
||||
"Add Node": "Adicionar Nó",
|
||||
"Add Repository": "Adicionar Repositório",
|
||||
"API Key": "Chave da API",
|
||||
"About": "Acerca da aplicação",
|
||||
"Add Node": "Adicionar nó",
|
||||
"Add Repository": "Adicionar repositório",
|
||||
"Address": "Endereço",
|
||||
"Addresses": "Endereços",
|
||||
"Allow Anonymous Usage Reporting?": "Permitir Envio de Relatórios Anónimos?",
|
||||
"Allow Anonymous Usage Reporting?": "Permitir envio de relatórios anónimos de utilização?",
|
||||
"Announce Server": "Servidor de anúncios",
|
||||
"Anonymous Usage Reporting": "Envio de Relatórios Anónimos",
|
||||
"Anonymous Usage Reporting": "Enviar de relatórios anónimos de utilização",
|
||||
"Bugs": "Erros",
|
||||
"CPU Utilization": "Utilização da CPU",
|
||||
"Close": "Fechar",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Direitos Reservados © 2014 Jakob Borg e os seguintes Contribuidores:",
|
||||
"Delete": "Apagar",
|
||||
"Connection Error": "Erro de ligação",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Direitos reservados © 2014 Jakob Borg e os seguintes contribuidores:",
|
||||
"Delete": "Eliminar",
|
||||
"Disconnected": "Desconectado",
|
||||
"Documentation": "Documentação",
|
||||
"Download Rate": "Taxa de transferência",
|
||||
"Download Rate": "Velocidade de recepção",
|
||||
"Edit": "Editar",
|
||||
"Edit Node": "Editar Nó",
|
||||
"Edit Repository": "Editar Repositório",
|
||||
"Edit Node": "Editar nó",
|
||||
"Edit Repository": "Editar repositório",
|
||||
"Enable UPnP": "Activar UPnP",
|
||||
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduza endereços \"ip:porto\" separados por vírgulas ou \"dynamic\" para o descobrimento automático do endereço.",
|
||||
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "Introduza endereços \"ip:porto\" separados por vírgulas ou \"dynamic\" para descobrir automaticamente o endereço.",
|
||||
"Error": "Erro",
|
||||
"File Versioning": "Gestão de versões",
|
||||
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "As permissões do ficheiro são ignoradas na pesquisa por mudanças. Utilize nos sistemas de ficheiros FAT.",
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Os ficheiros são movidos para versões carimbadas com o tempo numa pasta .stversions quando substituídos ou apagados por syncthing.",
|
||||
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Os ficheiros são protegidos de mudanças feitas em outros nós, mas alterações feitas neste nó serão enviadas para o resto do agrupamento.",
|
||||
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "As permissões do ficheiro são ignoradas ao procurar alterações. Utilize nos sistemas de ficheiros FAT.",
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Os ficheiros são movidos para versões carimbadas com o tempo numa pasta .stversions quando substituídos ou apagados pelo syncthing.",
|
||||
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Os ficheiros são protegidos das alterações feitas noutros nós, mas alterações feitas neste nó serão enviadas para o resto do agrupamento.",
|
||||
"Folder": "Pasta",
|
||||
"GUI Authentication Password": "Senha de Autenticação GUI",
|
||||
"GUI Authentication User": "Utilizador de autenticação GUI",
|
||||
"GUI Listen Addresses": "Endereço de escuta GUI",
|
||||
"GUI Authentication Password": "Senha da autenticação na interface gráfica",
|
||||
"GUI Authentication User": "Utilizador da autenticação na interface gráfica",
|
||||
"GUI Listen Addresses": "Endereço de escuta da interface gráfica",
|
||||
"Generate": "Gerar",
|
||||
"Global Discovery": "Descoberta Global",
|
||||
"Global Discovery Server": "Servidor de Descoberta Global",
|
||||
"Global Repository": "Repositório Global",
|
||||
"Global Discovery": "Busca global",
|
||||
"Global Discovery Server": "Servidor da busca global",
|
||||
"Global Repository": "Repositório global",
|
||||
"Idle": "Em espera",
|
||||
"Ignore Permissions": "Ignorar Permissões",
|
||||
"Keep Versions": "Manter Versões",
|
||||
"Ignore Permissions": "Ignorar permissões",
|
||||
"Keep Versions": "Manter versões",
|
||||
"Latest Release": "Última versão",
|
||||
"Local Discovery": "Descoberta Local",
|
||||
"Local Discovery Port": "Porto de Descoberta Local",
|
||||
"Local Discovery": "Busca local",
|
||||
"Local Discovery Port": "Porto da busca local",
|
||||
"Local Repository": "Repositório local",
|
||||
"Master Repo": "Repositório Mestre",
|
||||
"Max File Change Rate (KiB/s)": "Taxa máxima de troca de ficheiros (KiB/s)",
|
||||
"Master Repo": "Repositório mestre",
|
||||
"Max File Change Rate (KiB/s)": "Velocidade máxima de alterações de ficheiros (KiB/s)",
|
||||
"Max Outstanding Requests": "Número máximo de pedidos pendentes",
|
||||
"No": "Não",
|
||||
"Node ID": "ID do Nó",
|
||||
"Node Name": "Nome do Nó",
|
||||
"Node ID": "ID do nó",
|
||||
"Node Identification": "Identificação do nó",
|
||||
"Node Name": "Nome do nó",
|
||||
"Notice": "Nota",
|
||||
"OK": "OK",
|
||||
"Offline": "Desconectado",
|
||||
"Online": "Conectado",
|
||||
"Out Of Sync": "Não sincronizado",
|
||||
"Outgoing Rate Limit (KiB/s)": "Limite da taxa de envio (KiB/s)",
|
||||
"Override Changes": "Sobrepor Mudanças",
|
||||
"Outgoing Rate Limit (KiB/s)": "Limite da velocidade de envio (KiB/s)",
|
||||
"Override Changes": "Sobrepor alterações",
|
||||
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Caminho para o repositório no computador local. Será criado se não existir. O carácter (~) pode ser utilizado como atalho para",
|
||||
"Please wait": "Aguarde",
|
||||
"Preview Usage Report": "Visualização de Relatório",
|
||||
"Preview Usage Report": "Pré-visualizar relatório de utilização",
|
||||
"RAM Utilization": "Utilização da RAM",
|
||||
"Reconnect Interval (s)": "Intervalo de reestabelecimento de ligação (s)",
|
||||
"Repository ID": "ID do Repositório",
|
||||
"Repository Master": "Repositório Mestre",
|
||||
"Repository Path": "Caminho do Repositório",
|
||||
"Rescan Interval (s)": "Intervalo de monitorização (s)",
|
||||
"Repository ID": "ID do repositório",
|
||||
"Repository Master": "Repositório mestre",
|
||||
"Repository Path": "Caminho do repositório",
|
||||
"Rescan Interval (s)": "Intervalo entre varrimentos (s)",
|
||||
"Restart": "Reiniciar",
|
||||
"Restart Needed": "É preciso reiniciar",
|
||||
"Restarting": "Reiniciando",
|
||||
"Save": "Gravar",
|
||||
"Scanning": "Varrendo",
|
||||
"Select the nodes to share this repository with.": "Seleccione os nós com os quais vai partilhar este repositório.",
|
||||
"Settings": "Configurações",
|
||||
"Share With Nodes": "Partilhar com Nós",
|
||||
"Shared With": "Partilhado Com",
|
||||
"Share With Nodes": "Partilhar com os nós",
|
||||
"Shared With": "Partilhado com",
|
||||
"Short identifier for the repository. Must be the same on all cluster nodes.": "Identificador curto para o repositório. Tem que ser igual em todos os nós do agrupamento.",
|
||||
"Show ID": "Mostrar ID",
|
||||
"Shown instead of Node ID in the cluster status.": "Mostrado ao invés do ID do Nó no estado do agrupamento.",
|
||||
"Shown instead of Node ID in the cluster status.": "Apresentado ao invés do ID do nó no estado do agrupamento.",
|
||||
"Shutdown": "Desligar",
|
||||
"Source Code": "Código Fonte",
|
||||
"Start Browser": "Iniciar Navegador",
|
||||
"Source Code": "Código fonte",
|
||||
"Start Browser": "Iniciar navegador",
|
||||
"Stopped": "Parado",
|
||||
"Support / Forum": "Suporte / Fórum",
|
||||
"Sync Protocol Listen Addresses": "Endereços de escuta do protocolo de sincronização",
|
||||
"Synchronization": "Sincronização",
|
||||
"Syncing": "Sincronizando",
|
||||
"Syncthing has been shut down.": "Syncthing foi desligado.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing inclui as seguintes aplicações ou partes delas:",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing parece estar em baixo, ou então existe um problema com a sua ligação à Internet. Tentando novamente...",
|
||||
"The aggregated statistics are publicly available at {{url}}": "As estatísticas agrupadas estão disponíveis publicamente em {{url}}",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "A configuração foi gravada mas não activada. Syncthing tem que reiniciar para activar a nova configuração.",
|
||||
"Syncing": "A Sincronizar",
|
||||
"Syncthing has been shut down.": "O Syncthing foi desligado.",
|
||||
"Syncthing includes the following software or portions thereof:": "O Syncthing inclui as seguintes aplicações ou partes delas:",
|
||||
"Syncthing is restarting.": "O Syncthing está a reiniciar.",
|
||||
"Syncthing is upgrading.": "O Syncthing está a actualizar-se.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "O Syncthing parece estar em baixo, ou então existe um problema com a sua ligação à Internet. Tentando novamente...",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "As estatísticas agrupadas estão disponíveis publicamente em {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "A configuração foi gravada mas não activada. O Syncthing tem que reiniciar para activar a nova configuração.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "O relatório de utilização cifrado é enviado diariamente. É utilizado para seguir plataformas comuns, tamanhos de repositórios e versões da aplicação. Se o conjunto de dados do relatório for alterado, será notificado novamente através desta janela.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "O ID do nó indicado não parece ser válido. Deveria conter uma palavra de 52 caracteres constituída por letras e números, com espaços e traços opcionais. ",
|
||||
"The node ID cannot be blank.": "O ID do nó não pode ser vazio.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "O ID do nó fornecido não parece ser válido. Deveria ser um texto com 52 ou 56 caracteres constituídos por letras e números, com espaços e traços opcionais.",
|
||||
"The node ID cannot be blank.": "O ID do nó não pode estar vazio.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "O ID do nó a introduzir pode ser encontrado no diálogo \"Editar > Mostrar ID\" no outro nó. Espaços e traços são opcionais (ignorados).",
|
||||
"The number of old versions to keep, per file.": "O número de versões antigas a manter, por ficheiro.",
|
||||
"The number of versions must be a number and cannot be blank.": "O número de versões tem que ser um número e não pode ser vazio.",
|
||||
"The repository ID cannot be blank.": "O ID do repositório não pode ser vazio.",
|
||||
"The number of versions must be a number and cannot be blank.": "O número de versões tem que ser um número e não pode estar vazio.",
|
||||
"The repository ID cannot be blank.": "O ID do repositório não pode estar vazio.",
|
||||
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "O ID do repositório tem que ser um identificador curto (64 caracteres ou menos) e consiste em letras, números e os caracteres ponto (.), traço (-) e (_).",
|
||||
"The repository ID must be unique.": "O ID do repositório tem que ser único.",
|
||||
"The repository path cannot be blank.": "O caminho do repositório não pode ser vazio.",
|
||||
"The repository path cannot be blank.": "O caminho do repositório não pode estar vazio.",
|
||||
"Unknown": "Desconhecido",
|
||||
"Up to Date": "Actualizado",
|
||||
"Upgrade To {%version%}": "Atualizar para {{version}}",
|
||||
"Upgrade To {%version%}": "Actualizar para {{version}}",
|
||||
"Upgrading": "Actualizando",
|
||||
"Upload Rate": "Taxa de envio",
|
||||
"Usage": "Utilização",
|
||||
"Use Compression": "Usar Compressão",
|
||||
"Use HTTPS for GUI": "Utilizar HTTPS para GUI",
|
||||
"Use Compression": "Usar compressão",
|
||||
"Use HTTPS for GUI": "Utilizar HTTPS na interface gráfica",
|
||||
"Version": "Versão",
|
||||
"When adding a new node, keep in mind that this node must be added on the other side too.": "Quando adicionar um novo nó, lembre-se que este nó tem que ser adicionado do outro lado também.",
|
||||
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Quando adicionar um novo repositório, lembre-se que o ID do Repositório é utilizado para juntar os repositórios entre nós. São sensíveis às maiúsculas e minúsculas e tem que corresponder exactamente entre todos os nós.",
|
||||
"When adding a new node, keep in mind that this node must be added on the other side too.": "Quando adicionar um novo nó, lembre-se que este nó tem que ser adicionado no outro lado também.",
|
||||
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Quando adicionar um novo repositório, lembre-se que o ID do repositório é utilizado para juntar os repositórios entre nós. Os ID's são sensíveis às maiúsculas e minúsculas e têm que corresponder exactamente entre todos os nós.",
|
||||
"Yes": "Sim",
|
||||
"You must keep at least one version.": "Tem que manter pelo menos uma versão.",
|
||||
"items": "itens"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"Bugs": "Ошибки",
|
||||
"CPU Utilization": "Загрузка ЦПУ",
|
||||
"Close": "Закрыть",
|
||||
"Connection Error": "Connection Error",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Все права защищены © 2014 Jakob Borg и следующие участники:",
|
||||
"Delete": "Удалить",
|
||||
"Disconnected": "Нет соединения",
|
||||
@@ -46,6 +47,7 @@
|
||||
"Max Outstanding Requests": "Максимальное количество исходящих запросов",
|
||||
"No": "Нет",
|
||||
"Node ID": "ID Узла",
|
||||
"Node Identification": "Node Identification",
|
||||
"Node Name": "Имя Узла",
|
||||
"Notice": "Внимание",
|
||||
"OK": "ОК",
|
||||
@@ -65,6 +67,7 @@
|
||||
"Rescan Interval (s)": "Интервал между сканированием (сек)",
|
||||
"Restart": "Перезапуск",
|
||||
"Restart Needed": "Требуется перезапуск",
|
||||
"Restarting": "Restarting",
|
||||
"Save": "Сохранить",
|
||||
"Scanning": "Сканирование",
|
||||
"Select the nodes to share this repository with.": "Выберите узлы для которых будет доступен данный репозиторий.",
|
||||
@@ -84,11 +87,14 @@
|
||||
"Syncing": "Синхронизация",
|
||||
"Syncthing has been shut down.": "Syncthing выключен.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing включает в себя следующее ПО или его части:",
|
||||
"Syncthing is restarting.": "Syncthing is restarting.",
|
||||
"Syncthing is upgrading.": "Syncthing is upgrading.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Кажется, Syncthing не запущен или есть проблемы с подключением к Интернету. Переподключаюсь...",
|
||||
"The aggregated statistics are publicly available at {{url}}": "Суммарная статистика общедоступна на {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Суммарная статистика общедоступна на {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Конфигурация была сохранена но не активирована. Для активации новой конфигурации необходимо рестартовать Syncthing.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Зашифрованные отчёты об использовании отправляются ежедневно. Они используются для отслеживания проблем, размеров репозиториев и версий Syncthing. Если набор данных в отчёте будет изменён, то вы получите уведомление об этом в этом диалоге.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Введённый ID узла выглядит неправильно: ID должен быть строкой, длинной 52 символа, обязательно содержащей группы букв и цифр которые могут быть разделены пробелами или тире.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.",
|
||||
"The node ID cannot be blank.": "ID узла не может быть пустым.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "ID узла можно узнать в окне \"Редактировать > Показать ID\" на требуемом узле. Пробелы и тире используются для удобства и не обязательны (игнорируются).",
|
||||
"The number of old versions to keep, per file.": "Количество хранимых версий файла.",
|
||||
@@ -100,6 +106,7 @@
|
||||
"Unknown": "Неизвестно",
|
||||
"Up to Date": "Обновлено",
|
||||
"Upgrade To {%version%}": "Обновить до {{version}}",
|
||||
"Upgrading": "Upgrading",
|
||||
"Upload Rate": "Скорость отдачи",
|
||||
"Usage": "Справка",
|
||||
"Use Compression": "Использовать сжатие",
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
"Announce Server": "Uppslagningsserver",
|
||||
"Anonymous Usage Reporting": "Anonym användarstatistik",
|
||||
"Bugs": "Buggar",
|
||||
"CPU Utilization": "CPU-utnyttjande",
|
||||
"CPU Utilization": "CPU-användning",
|
||||
"Close": "Stäng",
|
||||
"Connection Error": "Anslutningsproblem",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Copyright © 2014 Jakob Borg och de följande medarbetarna:",
|
||||
"Delete": "Radera",
|
||||
"Disconnected": "Ej ansluten",
|
||||
"Documentation": "Dokumentation",
|
||||
"Download Rate": "Nerladdningshastighet",
|
||||
"Download Rate": "Nedladdningshastighet",
|
||||
"Edit": "Redigera",
|
||||
"Edit Node": "Redigera nod",
|
||||
"Edit Repository": "Redigera lagring",
|
||||
@@ -29,7 +30,7 @@
|
||||
"Folder": "Katalog",
|
||||
"GUI Authentication Password": "GUI-lösenord",
|
||||
"GUI Authentication User": "GUI-användare",
|
||||
"GUI Listen Addresses": "GUI-address",
|
||||
"GUI Listen Addresses": "GUI-adress",
|
||||
"Generate": "Skapa",
|
||||
"Global Discovery": "Global uppslagning",
|
||||
"Global Discovery Server": "Global uppslagningsserver",
|
||||
@@ -46,6 +47,7 @@
|
||||
"Max Outstanding Requests": "Paralellitet",
|
||||
"No": "Nej",
|
||||
"Node ID": "Nod-ID",
|
||||
"Node Identification": "Nod-identifiering",
|
||||
"Node Name": "Nodnamn",
|
||||
"Notice": "OBS",
|
||||
"OK": "OK",
|
||||
@@ -57,7 +59,7 @@
|
||||
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Sökväg till katalogen på din dator. Kommer att skapas om det inte finns. Tecknet tilde (~) kan användas som en genväg för",
|
||||
"Please wait": "Var god vänta",
|
||||
"Preview Usage Report": "Förhandsgranska statistik",
|
||||
"RAM Utilization": "Minnesutnyttjande",
|
||||
"RAM Utilization": "Minnesanvändning",
|
||||
"Reconnect Interval (s)": "Anslutningsintervall (s)",
|
||||
"Repository ID": "Lagrings-ID",
|
||||
"Repository Master": "Huvudlagring",
|
||||
@@ -65,6 +67,7 @@
|
||||
"Rescan Interval (s)": "Förnyelseintervall (s)",
|
||||
"Restart": "Starta om",
|
||||
"Restart Needed": "Omstart behövs",
|
||||
"Restarting": "Startar om",
|
||||
"Save": "Spara",
|
||||
"Scanning": "Uppdaterar",
|
||||
"Select the nodes to share this repository with.": "Välj vilka noder förvaringen ska delas med.",
|
||||
@@ -80,15 +83,18 @@
|
||||
"Stopped": "Stoppad",
|
||||
"Support / Forum": "Support / Forum",
|
||||
"Sync Protocol Listen Addresses": "Address för inkommande anslutningar",
|
||||
"Synchronization": "Synkronisation",
|
||||
"Synchronization": "Synkronisering",
|
||||
"Syncing": "Synkroniserar",
|
||||
"Syncthing has been shut down.": "Syncthing har stängts ner.",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing innehåller de följande mjukvarupaketen eller delar därav:",
|
||||
"Syncthing is restarting.": "Syncthing startar om.",
|
||||
"Syncthing is upgrading.": "Syncthing uppgraderas.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing verkar avstängd, eller så är där ett problem med din Internetanslutning. Försöker igen...",
|
||||
"The aggregated statistics are publicly available at {{url}}": "Aggregerad statistik finns publikt tillgänglig på {{url}}",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "Aggregerad statistik finns publikt tillgänglig på {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Konfigurationen har sparats men inte aktiverats. Syncthing måste startas om för att aktivera den nya konfigurationen.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Den krypterade användarstatistiken skickas dagligen. Den används för att spåra vanliga plattformar, lagringsstorlekar och versioner. Om datan som rapporteras ändras så kommer du att bli tillfrågad igen.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Det inmatade nod-ID:t verkar inte korrekt. Det ska vara en 52 teckens sträng bestående av siffror och bokstäver, eventuellt med mellanrum och bindestreck.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Det inmatade nod-ID:t verkar inte korrekt. Det ska vara en 52 eller 56 teckens sträng bestående av siffror och bokstäver, eventuellt med mellanrum och bindestreck.",
|
||||
"The node ID cannot be blank.": "Nod-ID:t kan inte vara blankt.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Nod-ID:t som behövs här kan du hitta i \"Redigera > Visa ID\"-dialogen på den andra noden. Mellanrum och bindestreck är valfria (ignoreras).",
|
||||
"The number of old versions to keep, per file.": "Antalet gamla versioner som ska behållas, per fil.",
|
||||
@@ -100,6 +106,7 @@
|
||||
"Unknown": "Okänt",
|
||||
"Up to Date": "Helt uppdaterad",
|
||||
"Upgrade To {%version%}": "Uppgradera till {{version}}",
|
||||
"Upgrading": "Uppgraderar",
|
||||
"Upload Rate": "Uppladdningshastighet",
|
||||
"Usage": "Användande",
|
||||
"Use Compression": "Använd komprimering",
|
||||
|
||||
120
gui/lang-tr.json
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"API Key": "API Anahtarı",
|
||||
"About": "Hakkında",
|
||||
"Add Node": "Düğüm ekle",
|
||||
"Add Repository": "Depo ekle",
|
||||
"Address": "Adres",
|
||||
"Addresses": "Adresler",
|
||||
"Allow Anonymous Usage Reporting?": "Anonim kullanım raporlarına izin ver ?",
|
||||
"Announce Server": "Duyuru Sunucusu",
|
||||
"Anonymous Usage Reporting": "Anonim Kullanım Raporlama",
|
||||
"Bugs": "Hatalar",
|
||||
"CPU Utilization": "İşlemci Kullanımı",
|
||||
"Close": "Kapat",
|
||||
"Connection Error": "Connection Error",
|
||||
"Copyright © 2014 Jakob Borg and the following Contributors:": "Telif Hakkı © 2014 Jakob Borg ve Katkıda Bulunanlar",
|
||||
"Delete": "Sil",
|
||||
"Disconnected": "Bağlantı Kesildi",
|
||||
"Documentation": "Dökümanlar",
|
||||
"Download Rate": "İndirme Hızı",
|
||||
"Edit": "Düzenle",
|
||||
"Edit Node": "Düğümü Düzenle",
|
||||
"Edit Repository": "Depoyu düzenle",
|
||||
"Enable UPnP": "UPnP Etkinleştir",
|
||||
"Enter comma separated \"ip:port\" addresses or \"dynamic\" to perform automatic discovery of the address.": "IP adresleri eklemek için virgül ile ayırarak \"ip:port\" yazın, ya da \"dynamic\" yazarak otomatik bulma işlemini seçin.",
|
||||
"Error": "Hata",
|
||||
"File Versioning": "Dosya Sürümlendirme",
|
||||
"File permission bits are ignored when looking for changes. Use on FAT filesystems.": "Değişimleri yoklarken dosya izin bilgilerini ihmal et. FAT dosya sistemlerinde kullanın.",
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.": "Dosyalar syncthing tarafından değiştirildiğinde ya da silindiğinde, tarih damgalı sürümleri .stversions dizinine taşınır.",
|
||||
"Files are protected from changes made on other nodes, but changes made on this node will be sent to the rest of the cluster.": "Dosyalar diğer düğümlerde yapılan değişikliklerden korunur, ancak bu düğümdeki değişiklikler kümedeki diğer düğümlere gönderilir.",
|
||||
"Folder": "Dizin",
|
||||
"GUI Authentication Password": "Kullanıcı arayüzü şifresi",
|
||||
"GUI Authentication User": "Kullanıcı arayüzü kullanıcı ismi",
|
||||
"GUI Listen Addresses": "Kullanıcı arayüzü bağlantı adresi",
|
||||
"Generate": "Oluştur",
|
||||
"Global Discovery": "Küresel Keşif",
|
||||
"Global Discovery Server": "Küresel Keşif Sunucusu",
|
||||
"Global Repository": "Global Depo",
|
||||
"Idle": "Boşta",
|
||||
"Ignore Permissions": "İzinleri yoksay",
|
||||
"Keep Versions": "Sürüm tut",
|
||||
"Latest Release": "En son sürüm",
|
||||
"Local Discovery": "Yerel bulma",
|
||||
"Local Discovery Port": "Yerel bulma portları",
|
||||
"Local Repository": "Yerel Depo",
|
||||
"Master Repo": "Master Depo",
|
||||
"Max File Change Rate (KiB/s)": "Mak. Dosya değiştirme oranı (KB/sn)",
|
||||
"Max Outstanding Requests": "Maks Öncellikli İstekler",
|
||||
"No": "Hayır",
|
||||
"Node ID": "Düğüm ID",
|
||||
"Node Identification": "Node Identification",
|
||||
"Node Name": "Düğüm İsmi",
|
||||
"Notice": "Uyarı",
|
||||
"OK": "Tamam",
|
||||
"Offline": "Çevrim dışı",
|
||||
"Online": "Çevrim içi",
|
||||
"Out Of Sync": "Senkronize değil",
|
||||
"Outgoing Rate Limit (KiB/s)": "Yükleme Oranı Limiti (KB/sn)",
|
||||
"Override Changes": "Değişiklikleri Geçersiz kıl",
|
||||
"Path to the repository on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Yerel bilgisayardaki depoya ulaşım yolu. Dizin yoksa yaratılacak. (~) karakterinin kısayol olarak kullanılabileceği yol",
|
||||
"Please wait": "Lütfen Bekleyin",
|
||||
"Preview Usage Report": "Kullanım raporunu gözden geçir",
|
||||
"RAM Utilization": "RAM Kullanımı",
|
||||
"Reconnect Interval (s)": "Yeniden bağlanma süresi (sn)",
|
||||
"Repository ID": "Depo ID",
|
||||
"Repository Master": "Master Depo",
|
||||
"Repository Path": "Depo Yolu",
|
||||
"Rescan Interval (s)": "Yeni tarama süresi (sn)",
|
||||
"Restart": "Yeniden Başlat",
|
||||
"Restart Needed": "Yeniden başlatma gereklidir",
|
||||
"Restarting": "Restarting",
|
||||
"Save": "Kaydet",
|
||||
"Scanning": "Taranıyor",
|
||||
"Select the nodes to share this repository with.": "Bu depo ile paylaşılacak olan düğümü seçin.",
|
||||
"Settings": "Ayarlar",
|
||||
"Share With Nodes": "Düğüm ile paylaş",
|
||||
"Shared With": "ile paylaş",
|
||||
"Short identifier for the repository. Must be the same on all cluster nodes.": "Depo için kısa tanımlayıcı. Tüm küme düğümlerinde aynı olmalı.",
|
||||
"Show ID": "ID Göster",
|
||||
"Shown instead of Node ID in the cluster status.": "Küme durumu yerine Düğüm ID göster.",
|
||||
"Shutdown": "Kapat",
|
||||
"Source Code": "Kaynak Kodu",
|
||||
"Start Browser": "Tarayıcıyı Başlat",
|
||||
"Stopped": "Durduruldu",
|
||||
"Support / Forum": "Destek / Forum",
|
||||
"Sync Protocol Listen Addresses": "Sync Protokol Dinleme Adresleri",
|
||||
"Synchronization": "Senkronizasyon",
|
||||
"Syncing": "Senkronize ediliyor",
|
||||
"Syncthing has been shut down.": "Syncthing durduruldu",
|
||||
"Syncthing includes the following software or portions thereof:": "Syncthing aşağıdaki yazılımları veya bunların bölümlerini içermektedir:",
|
||||
"Syncthing is restarting.": "Syncthing is restarting.",
|
||||
"Syncthing is upgrading.": "Syncthing is upgrading.",
|
||||
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing görünüşe durdu veya internetin bağlantınızda problem var. Tekrar deniyor....",
|
||||
"The aggregated statistics are publicly available at {%url%}.": "The aggregated statistics are publicly available at {{url}}.",
|
||||
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Ayarlar kaydedildi ancak aktifleştirilmedi. Aktifleştirmek için Syncthing yeniden başlatılmalı.",
|
||||
"The encrypted usage report is sent daily. It is used to track common platforms, repo sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Şifrelenmiş kullanım bilgisi günlük olarak gönderilir. Platform, depo büyüklüğü ve uygulama sürümü hakkında bilgi toplanır. Toplanan bilgi çeşidi değişecek olursa, sizden tekrar onay istenecek.",
|
||||
"The entered node ID does not look valid. It should be a 52 character string consisting of letters and numbers, with spaces and dashes being optional.": "Girilen düğüm ID'si geçerli gibi gözükmüyor. 52 karakter uzunluğunda, harf ve rakamlardan oluşmalı. Boşlukların ve kısa çizgilerin olup olmaması önemli değildir.",
|
||||
"The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "The entered node ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.",
|
||||
"The node ID cannot be blank.": "Düğüm ID'si boş olamaz.",
|
||||
"The node ID to enter here can be found in the \"Edit > Show ID\" dialog on the other node. Spaces and dashes are optional (ignored).": "Buraya girilecek düğüm ID'si diğer düğümde \"Düzenle > ID Göster\" menüsünden bulunabilir. Boşluk ve kısa çizginin olup olmaması önemli değildir. (İhmal edilir)",
|
||||
"The number of old versions to keep, per file.": "Dosya başına saklanacak eski sürüm.",
|
||||
"The number of versions must be a number and cannot be blank.": "Sürümlerin sayısı sayı olmalı ve boş bırakılamaz.",
|
||||
"The repository ID cannot be blank.": "Depo ID boş bırakılamaz.",
|
||||
"The repository ID must be a short identifier (64 characters or less) consisting of letters, numbers and the the dot (.), dash (-) and underscode (_) characters only.": "Depo ID uzun olmamalı (64 karakter ya da daha az). Sadece harf, rakam, nokta (.), kısa çizgi (-) ve alt çizgi (_) kullanabilirsiniz.",
|
||||
"The repository ID must be unique.": "Depo ID'si benzersiz olmalıdır.",
|
||||
"The repository path cannot be blank.": "Depo yolu boş bırakılamaz.",
|
||||
"Unknown": "Bilinmiyor",
|
||||
"Up to Date": "Güncel",
|
||||
"Upgrade To {%version%}": "{{version}} sürümüne yükselt",
|
||||
"Upgrading": "Upgrading",
|
||||
"Upload Rate": "Yükleme Oranı",
|
||||
"Usage": "Kullanım",
|
||||
"Use Compression": "Sıkıştırma kullan",
|
||||
"Use HTTPS for GUI": "GUI için HTTPS kullan",
|
||||
"Version": "Sürüm",
|
||||
"When adding a new node, keep in mind that this node must be added on the other side too.": "Yeni bir düğüm eklendiğinde unutmayın ki; bu düğüm diğer tarafa da eklenmelidir.",
|
||||
"When adding a new repository, keep in mind that the Repository ID is used to tie repositories together between nodes. They are case sensitive and must match exactly between all nodes.": "Unutmayın ki; Depo ID, depoları düğümler arasında bağlamak için kullanılıyor. Büyük - küçük harf duyarlı, ve bütün düğümlerde aynı olmalı.",
|
||||
"Yes": "Evet",
|
||||
"You must keep at least one version.": "En az bir sürümü tutmalısınız.",
|
||||
"items": "öğeler"
|
||||
}
|
||||
BIN
gui/logo-text-256.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
gui/logo-text-64.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
@@ -10,7 +10,7 @@
|
||||
<div class="modal-body" ng-transclude>
|
||||
</div>
|
||||
<div ng-if="close" class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Close</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> <span translate>Close</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
BIN
gui/raleway-400.ttf
Normal file
BIN
gui/raleway-700.ttf
Normal file
12
gui/raleway.css
Normal file
@@ -0,0 +1,12 @@
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Raleway'), url(raleway-400.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Raleway';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Raleway Bold'), local('Raleway-Bold'), url(raleway-700.ttf) format('truetype');
|
||||
}
|
||||
|
Before Width: | Height: | Size: 17 KiB |
@@ -1 +1 @@
|
||||
var validLangs = ["de","el","en","es","fr","it","pt","ru","sv"]
|
||||
var validLangs = ["da","de","el","en","es","fr","it","nl","pt","ru","sv","tr"]
|
||||
|
||||
@@ -3,5 +3,3 @@
|
||||
./test-http.sh || exit
|
||||
./test-merge.sh || exit
|
||||
./test-delupd.sh || exit
|
||||
# ./test-folders.sh || exit
|
||||
./test-reconnect.sh || exit
|
||||
|
||||
264
integration/common_test.go
Normal file
@@ -0,0 +1,264 @@
|
||||
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
|
||||
// All rights reserved. Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build integration
|
||||
|
||||
package integration_test
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
mr "math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
type syncthingProcess struct {
|
||||
log string
|
||||
argv []string
|
||||
port int
|
||||
|
||||
cmd *exec.Cmd
|
||||
logfd *os.File
|
||||
}
|
||||
|
||||
func (p *syncthingProcess) start() error {
|
||||
if p.logfd == nil {
|
||||
logfd, err := os.Create(p.log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.logfd = logfd
|
||||
}
|
||||
|
||||
cmd := exec.Command("../bin/syncthing", p.argv...)
|
||||
cmd.Stdout = p.logfd
|
||||
cmd.Stderr = p.logfd
|
||||
cmd.Env = append(env, fmt.Sprintf("STPROFILER=:%d", p.port+1000))
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.cmd = cmd
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *syncthingProcess) stop() {
|
||||
p.cmd.Process.Kill()
|
||||
p.cmd.Wait()
|
||||
}
|
||||
|
||||
func (p *syncthingProcess) peerCompletion() (map[string]int, error) {
|
||||
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/rest/debug/peerCompletion", p.port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
comp := map[string]int{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&comp)
|
||||
return comp, err
|
||||
}
|
||||
|
||||
type fileGenerator struct {
|
||||
files int
|
||||
maxexp int
|
||||
srcname string
|
||||
}
|
||||
|
||||
func generateFiles(dir string, files, maxexp int, srcname string) error {
|
||||
fd, err := os.Open(srcname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < files; i++ {
|
||||
n := randomName()
|
||||
p0 := filepath.Join(dir, string(n[0]), n[0:2])
|
||||
err = os.MkdirAll(p0, 0755)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
s := 1 << uint(mr.Intn(maxexp))
|
||||
a := 128 * 1024
|
||||
if a > s {
|
||||
a = s
|
||||
}
|
||||
s += mr.Intn(a)
|
||||
|
||||
src := io.LimitReader(&inifiteReader{fd}, int64(s))
|
||||
|
||||
p1 := filepath.Join(p0, n)
|
||||
dst, err := os.Create(p1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(dst, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dst.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.Chmod(p1, os.FileMode(mr.Intn(0777)|0400))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t := time.Now().Add(-time.Duration(mr.Intn(30*86400)) * time.Second)
|
||||
err = os.Chtimes(p1, t, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func randomName() string {
|
||||
var b [16]byte
|
||||
rand.Reader.Read(b[:])
|
||||
return fmt.Sprintf("%x", b[:])
|
||||
}
|
||||
|
||||
type inifiteReader struct {
|
||||
rd io.ReadSeeker
|
||||
}
|
||||
|
||||
func (i *inifiteReader) Read(bs []byte) (int, error) {
|
||||
n, err := i.rd.Read(bs)
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
i.rd.Seek(0, 0)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// rm -rf
|
||||
func removeAll(dirs ...string) error {
|
||||
for _, dir := range dirs {
|
||||
err := os.RemoveAll(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compare a number of directories. Returns nil if the contents are identical,
|
||||
// otherwise an error describing the first found difference.
|
||||
func compareDirectories(dirs ...string) error {
|
||||
chans := make([]chan fileInfo, len(dirs))
|
||||
for i := range chans {
|
||||
chans[i] = make(chan fileInfo)
|
||||
}
|
||||
abort := make(chan struct{})
|
||||
|
||||
for i := range dirs {
|
||||
startWalker(dirs[i], chans[i], abort)
|
||||
}
|
||||
|
||||
res := make([]fileInfo, len(dirs))
|
||||
for {
|
||||
numDone := 0
|
||||
for i := range chans {
|
||||
fi, ok := <-chans[i]
|
||||
if !ok {
|
||||
numDone++
|
||||
}
|
||||
res[i] = fi
|
||||
}
|
||||
|
||||
for i := 1; i < len(res); i++ {
|
||||
if res[i] != res[0] {
|
||||
close(abort)
|
||||
return fmt.Errorf("Mismatch; %#v (%s) != %#v (%s)", res[i], dirs[i], res[0], dirs[0])
|
||||
}
|
||||
}
|
||||
|
||||
if numDone == len(dirs) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fileInfo struct {
|
||||
name string
|
||||
mode os.FileMode
|
||||
mod time.Time
|
||||
hash [16]byte
|
||||
}
|
||||
|
||||
func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) {
|
||||
walker := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rn, _ := filepath.Rel(dir, path)
|
||||
if rn == "." {
|
||||
return nil
|
||||
}
|
||||
|
||||
var f fileInfo
|
||||
if info.IsDir() {
|
||||
f = fileInfo{
|
||||
name: rn,
|
||||
mode: info.Mode(),
|
||||
// hash and modtime zero for directories
|
||||
}
|
||||
} else {
|
||||
f = fileInfo{
|
||||
name: rn,
|
||||
mode: info.Mode(),
|
||||
mod: info.ModTime(),
|
||||
}
|
||||
sum, err := md5file(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.hash = sum
|
||||
}
|
||||
|
||||
select {
|
||||
case res <- f:
|
||||
return nil
|
||||
case <-abort:
|
||||
return errors.New("abort")
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
filepath.Walk(dir, walker)
|
||||
close(res)
|
||||
}()
|
||||
}
|
||||
|
||||
func md5file(fname string) (hash [16]byte, err error) {
|
||||
f, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := md5.New()
|
||||
io.Copy(h, f)
|
||||
hb := h.Sum(nil)
|
||||
copy(hash[:], hb)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
<reconnectionIntervalS>5</reconnectionIntervalS>
|
||||
<maxChangeKbps>10000</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
<upnpEnabled>true</upnpEnabled>
|
||||
<upnpEnabled>false</upnpEnabled>
|
||||
<urAccepted>-1</urAccepted>
|
||||
</options>
|
||||
</configuration>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<reconnectionIntervalS>5</reconnectionIntervalS>
|
||||
<maxChangeKbps>10000</maxChangeKbps>
|
||||
<startBrowser>false</startBrowser>
|
||||
<upnpEnabled>true</upnpEnabled>
|
||||
<upnpEnabled>false</upnpEnabled>
|
||||
<urAccepted>-1</urAccepted>
|
||||
</options>
|
||||
</configuration>
|
||||
|
||||
@@ -9,6 +9,7 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -27,16 +28,19 @@ var (
|
||||
)
|
||||
|
||||
var jsonEndpoints = []string{
|
||||
"/rest/model?repo=default",
|
||||
"/rest/model/version?repo=default",
|
||||
"/rest/need",
|
||||
"/rest/connections",
|
||||
"/rest/completion?node=I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU&repo=default",
|
||||
"/rest/config",
|
||||
"/rest/config/sync",
|
||||
"/rest/system",
|
||||
"/rest/connections",
|
||||
"/rest/errors",
|
||||
// "/rest/discovery",
|
||||
"/rest/events",
|
||||
"/rest/lang",
|
||||
"/rest/model/version?repo=default",
|
||||
"/rest/model?repo=default",
|
||||
"/rest/need",
|
||||
"/rest/nodeid?id=I6KAH7666SLLLB5PFXSOAUFJCDZCYAOMLEKCP2GB32BV5RQST3PSROAU",
|
||||
"/rest/report",
|
||||
"/rest/system",
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -61,17 +65,21 @@ func main() {
|
||||
|
||||
var tests []testing.InternalTest
|
||||
tests = append(tests, testing.InternalTest{"TestGetIndex", TestGetIndex})
|
||||
tests = append(tests, testing.InternalTest{"TestGetVersion", TestGetVersion})
|
||||
tests = append(tests, testing.InternalTest{"TestGetVersionNoCSRF", TestGetVersion})
|
||||
tests = append(tests, testing.InternalTest{"TestJSONEndpoints", TestJSONEndpoints})
|
||||
if len(authUser) > 0 || len(apiKey) > 0 {
|
||||
tests = append(tests, testing.InternalTest{"TestPOSTNoCSRF", TestPOSTNoCSRF})
|
||||
|
||||
if len(authUser) > 0 {
|
||||
// If we expect authentication, verify that it fails with the wrong password and wrong API key
|
||||
tests = append(tests, testing.InternalTest{"TestJSONEndpointsNoAuth", TestJSONEndpointsNoAuth})
|
||||
tests = append(tests, testing.InternalTest{"TestJSONEndpointsIncorrectAuth", TestJSONEndpointsIncorrectAuth})
|
||||
}
|
||||
|
||||
if len(csrfToken) > 0 {
|
||||
tests = append(tests, testing.InternalTest{"TestJSONEndpointsNoCSRF", TestJSONEndpointsNoCSRF})
|
||||
// If we have a CSRF token, verify that POST succeeds with it
|
||||
tests = append(tests, testing.InternalTest{"TestPOSTWithCSRF", TestPOSTWithCSRF})
|
||||
}
|
||||
|
||||
fmt.Printf("Testing HTTP: CSRF=%v, API=%v, Auth=%v\n", len(csrfToken) > 0, len(apiKey) > 0, len(authUser) > 0)
|
||||
testing.Main(matcher, tests, nil, nil)
|
||||
}
|
||||
|
||||
@@ -145,33 +153,54 @@ func TestJSONEndpoints(t *testing.T) {
|
||||
for _, p := range jsonEndpoints {
|
||||
res, err := get(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
t.Errorf("Status %d != 200 for %q", res.StatusCode, p)
|
||||
continue
|
||||
}
|
||||
if ct := res.Header.Get("Content-Type"); ct != "application/json; charset=utf-8" {
|
||||
t.Errorf("Content-Type %q != \"application/json\" for %q", ct, p)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONEndpointsNoCSRF(t *testing.T) {
|
||||
for _, p := range jsonEndpoints {
|
||||
r, err := http.NewRequest("GET", "http://"+target+p, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(authUser) > 0 {
|
||||
r.SetBasicAuth(authUser, authPass)
|
||||
}
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.StatusCode != 403 && res.StatusCode != 401 {
|
||||
t.Fatalf("Status %d != 403/401 for %q", res.StatusCode, p)
|
||||
}
|
||||
func TestPOSTNoCSRF(t *testing.T) {
|
||||
r, err := http.NewRequest("POST", "http://"+target+"/rest/error/clear", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(authUser) > 0 {
|
||||
r.SetBasicAuth(authUser, authPass)
|
||||
}
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.StatusCode != 403 && res.StatusCode != 401 {
|
||||
t.Fatalf("Status %d != 403/401 for POST", res.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPOSTWithCSRF(t *testing.T) {
|
||||
r, err := http.NewRequest("POST", "http://"+target+"/rest/error/clear", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(csrfToken) > 0 {
|
||||
r.Header.Set("X-CSRF-Token", csrfToken)
|
||||
}
|
||||
if len(authUser) > 0 {
|
||||
r.SetBasicAuth(authUser, authPass)
|
||||
}
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
t.Fatalf("Status %d != 200 for POST", res.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,17 +208,20 @@ func TestJSONEndpointsNoAuth(t *testing.T) {
|
||||
for _, p := range jsonEndpoints {
|
||||
r, err := http.NewRequest("GET", "http://"+target+p, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if len(csrfToken) > 0 {
|
||||
r.Header.Set("X-CSRF-Token", csrfToken)
|
||||
}
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if res.StatusCode != 403 && res.StatusCode != 401 {
|
||||
t.Fatalf("Status %d != 403/401 for %q", res.StatusCode, p)
|
||||
t.Errorf("Status %d != 403/401 for %q", res.StatusCode, p)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,7 +230,8 @@ func TestJSONEndpointsIncorrectAuth(t *testing.T) {
|
||||
for _, p := range jsonEndpoints {
|
||||
r, err := http.NewRequest("GET", "http://"+target+p, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if len(csrfToken) > 0 {
|
||||
r.Header.Set("X-CSRF-Token", csrfToken)
|
||||
@@ -206,10 +239,12 @@ func TestJSONEndpointsIncorrectAuth(t *testing.T) {
|
||||
r.SetBasicAuth("wronguser", "wrongpass")
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if res.StatusCode != 403 && res.StatusCode != 401 {
|
||||
t.Fatalf("Status %d != 403/401 for %q", res.StatusCode, p)
|
||||
t.Errorf("Status %d != 403/401 for %q", res.StatusCode, p)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,9 +257,6 @@ func get(path string) (*http.Response, error) {
|
||||
if len(authUser) > 0 {
|
||||
r.SetBasicAuth(authUser, authPass)
|
||||
}
|
||||
if len(csrfToken) > 0 {
|
||||
r.Header.Set("X-CSRF-Token", csrfToken)
|
||||
}
|
||||
if len(apiKey) > 0 {
|
||||
r.Header.Set("X-API-Key", apiKey)
|
||||
}
|
||||
|
||||
141
integration/reconnect_test.go
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
|
||||
// All rights reserved. Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build integration
|
||||
|
||||
package integration_test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
apiKey = "abc123" // Used when talking to the processes under test
|
||||
id1 = "I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"
|
||||
id2 = "JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"
|
||||
)
|
||||
|
||||
var env = []string{
|
||||
"HOME=.",
|
||||
"STTRACE=model",
|
||||
}
|
||||
|
||||
func TestRestartBothDuringTransfer(t *testing.T) {
|
||||
// Give the receiver some time to rot with needed files but
|
||||
// without any peer. This triggers
|
||||
// https://github.com/syncthing/syncthing/issues/463
|
||||
testRestartDuringTransfer(t, true, true, 10*time.Second, 0)
|
||||
}
|
||||
|
||||
func TestRestartReceiverDuringTransfer(t *testing.T) {
|
||||
testRestartDuringTransfer(t, false, true, 0, 0)
|
||||
}
|
||||
|
||||
func TestRestartSenderDuringTransfer(t *testing.T) {
|
||||
testRestartDuringTransfer(t, true, false, 0, 0)
|
||||
}
|
||||
|
||||
func testRestartDuringTransfer(t *testing.T, restartSender, restartReceiver bool, senderDelay, receiverDelay time.Duration) {
|
||||
t.Log("Cleaning...")
|
||||
err := removeAll("s1", "s2", "f1/index", "f2/index")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log("Generating files...")
|
||||
err = generateFiles("s1", 1000, 20, "../bin/syncthing")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log("Starting up...")
|
||||
sender := syncthingProcess{ // id1
|
||||
log: "1.out",
|
||||
argv: []string{"-home", "f1"},
|
||||
port: 8081,
|
||||
}
|
||||
err = sender.start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
receiver := syncthingProcess{ // id2
|
||||
log: "2.out",
|
||||
argv: []string{"-home", "f2"},
|
||||
port: 8082,
|
||||
}
|
||||
err = receiver.start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Give them time to start up
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
var prevComp int
|
||||
for {
|
||||
comp, err := sender.peerCompletion()
|
||||
if err != nil {
|
||||
sender.stop()
|
||||
receiver.stop()
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
curComp := comp[id2]
|
||||
|
||||
if curComp == 100 {
|
||||
sender.stop()
|
||||
receiver.stop()
|
||||
break
|
||||
}
|
||||
|
||||
if curComp > prevComp {
|
||||
if restartReceiver {
|
||||
t.Logf("Stopping receiver...")
|
||||
receiver.stop()
|
||||
}
|
||||
|
||||
if restartSender {
|
||||
t.Logf("Stopping sender...")
|
||||
sender.stop()
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
if restartReceiver {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
time.Sleep(receiverDelay)
|
||||
t.Logf("Starting receiver...")
|
||||
receiver.start()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
if restartSender {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
time.Sleep(senderDelay)
|
||||
t.Logf("Starting sender...")
|
||||
sender.start()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
prevComp = curComp
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
t.Log("Comparing directories...")
|
||||
err = compareDirectories("s1", "s2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,7 @@ alterFiles() {
|
||||
for i in 1 12-2 23-3 ; do
|
||||
# Delete some files
|
||||
pushd "s$i" >/dev/null
|
||||
chmod 755 ro-test
|
||||
nfiles=$(find . -type f | wc -l)
|
||||
if [[ $nfiles -ge 300 ]] ; then
|
||||
todelete=$(( $nfiles - 300 ))
|
||||
@@ -107,6 +108,10 @@ alterFiles() {
|
||||
../genfiles -maxexp 22 -files 200
|
||||
echo " $i: append to large file"
|
||||
dd if=large-$i bs=1024k count=4 >> large-$i 2>/dev/null
|
||||
echo " $i: new files in ro directory"
|
||||
uuidgen > ro-test/$(uuidgen)
|
||||
chmod 500 ro-test
|
||||
|
||||
../md5r -l | sort | grep -v .stversions > ../md5-$i
|
||||
popd >/dev/null
|
||||
done
|
||||
@@ -118,6 +123,7 @@ alterFiles() {
|
||||
}
|
||||
|
||||
rm -rf h?/*.idx.gz h?/index
|
||||
chmod -R u+w s? s??-?
|
||||
rm -rf s? s??-?
|
||||
mkdir s1 s2 s3 s12-1 s12-2 s23-2 s23-3
|
||||
|
||||
@@ -126,6 +132,10 @@ for i in 1 12-2 23-3; do
|
||||
pushd "s$i" >/dev/null
|
||||
echo " $i: random nonoverlapping"
|
||||
../genfiles -maxexp 22 -files 400
|
||||
echo " $i: ro directory"
|
||||
mkdir ro-test
|
||||
uuidgen > ro-test/$(uuidgen)
|
||||
chmod 500 ro-test
|
||||
popd >/dev/null
|
||||
done
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved.
|
||||
# Use of this source code is governed by an MIT-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
id1=I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU
|
||||
id2=JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU
|
||||
|
||||
go build json.go
|
||||
go build md5r.go
|
||||
go build genfiles.go
|
||||
|
||||
start() {
|
||||
echo "Starting..."
|
||||
STTRACE=model,scanner STPROFILER=":9091" syncthing -home "f1" > 1.out 2>&1 &
|
||||
STTRACE=model,scanner STPROFILER=":9092" syncthing -home "f2" > 2.out 2>&1 &
|
||||
sleep 1
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo "Stopping..."
|
||||
for i in 1 2 ; do
|
||||
curl -HX-API-Key:abc123 -X POST "http://localhost:808$i/rest/shutdown"
|
||||
done
|
||||
sleep 1
|
||||
}
|
||||
|
||||
setup() {
|
||||
echo "Setting up..."
|
||||
rm -rf s? s??-?
|
||||
rm -rf f?/*.idx.gz f?/index
|
||||
mkdir -p s1
|
||||
pushd s1 >/dev/null
|
||||
../genfiles
|
||||
../md5r > ../md5-1
|
||||
popd >/dev/null
|
||||
}
|
||||
|
||||
testConvergence() {
|
||||
torestart="$1"
|
||||
prevcomp=0
|
||||
|
||||
while true ; do
|
||||
sleep 5
|
||||
comp=$(curl -HX-API-Key:abc123 -s "http://localhost:8081/rest/debug/peerCompletion" | ./json "$id2")
|
||||
comp=${comp:-0}
|
||||
echo $comp / 100
|
||||
|
||||
if [[ $comp == 100 ]] ; then
|
||||
echo Done
|
||||
break
|
||||
fi
|
||||
|
||||
# Restart if the destination has made some progress
|
||||
if [[ $comp -gt $prevcomp ]] ; then
|
||||
prevcomp=$comp
|
||||
curl -HX-API-Key:abc123 -X POST "http://localhost:$torestart/rest/restart"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Verifying..."
|
||||
|
||||
pushd s2 >/dev/null
|
||||
../md5r | grep -v .stversions > ../md5-2
|
||||
popd >/dev/null
|
||||
|
||||
if ! cmp md5-1 md5-2 ; then
|
||||
echo Repos differ
|
||||
stop
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo Testing reconnects during pull where the source node restarts
|
||||
setup
|
||||
start
|
||||
testConvergence 8081
|
||||
stop
|
||||
|
||||
echo Testing reconnects during pull where the destination node restarts
|
||||
setup
|
||||
start
|
||||
testConvergence 8082
|
||||
stop
|
||||
|
||||
exit 0
|
||||
@@ -3,7 +3,7 @@ package luhn_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/calmh/syncthing/luhn"
|
||||
"github.com/syncthing/syncthing/luhn"
|
||||
)
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
package model
|
||||
|
||||
import "github.com/calmh/syncthing/protocol"
|
||||
import "github.com/syncthing/syncthing/protocol"
|
||||
|
||||
type bqAdd struct {
|
||||
file protocol.FileInfo
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -15,12 +15,12 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/config"
|
||||
"github.com/calmh/syncthing/events"
|
||||
"github.com/calmh/syncthing/files"
|
||||
"github.com/calmh/syncthing/lamport"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
"github.com/syncthing/syncthing/config"
|
||||
"github.com/syncthing/syncthing/events"
|
||||
"github.com/syncthing/syncthing/files"
|
||||
"github.com/syncthing/syncthing/lamport"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/scanner"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
@@ -199,7 +199,15 @@ func (m *Model) ConnectionStats() map[string]ConnectionInfo {
|
||||
// Returns the completion status, in percent, for the given node and repo.
|
||||
func (m *Model) Completion(node protocol.NodeID, repo string) float64 {
|
||||
var tot int64
|
||||
m.repoFiles[repo].WithGlobal(func(f protocol.FileInfo) bool {
|
||||
|
||||
m.rmut.RLock()
|
||||
rf, ok := m.repoFiles[repo]
|
||||
m.rmut.RUnlock()
|
||||
if !ok {
|
||||
return 0 // Repo doesn't exist, so we hardly have any of it
|
||||
}
|
||||
|
||||
rf.WithGlobal(func(f protocol.FileInfo) bool {
|
||||
if !protocol.IsDeleted(f.Flags) {
|
||||
var size int64
|
||||
if protocol.IsDirectory(f.Flags) {
|
||||
@@ -212,8 +220,12 @@ func (m *Model) Completion(node protocol.NodeID, repo string) float64 {
|
||||
return true
|
||||
})
|
||||
|
||||
if tot == 0 {
|
||||
return 100 // Repo is empty, so we have all of it
|
||||
}
|
||||
|
||||
var need int64
|
||||
m.repoFiles[repo].WithNeed(node, func(f protocol.FileInfo) bool {
|
||||
rf.WithNeed(node, func(f protocol.FileInfo) bool {
|
||||
if !protocol.IsDeleted(f.Flags) {
|
||||
var size int64
|
||||
if protocol.IsDirectory(f.Flags) {
|
||||
@@ -359,7 +371,7 @@ func (m *Model) IndexUpdate(nodeID protocol.NodeID, repo string, fs []protocol.F
|
||||
}
|
||||
|
||||
if !m.repoSharedWith(repo, nodeID) {
|
||||
l.Warnf("Unexpected repository ID %q sent from node %q; ensure that the repository exists and that this node is selected under \"Share With\" in the repository configuration.", repo, nodeID)
|
||||
l.Infof("Update for unexpected repository ID %q sent from node %q; ensure that the repository exists and that this node is selected under \"Share With\" in the repository configuration.", repo, nodeID)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/config"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/config"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
"github.com/syndtr/goleveldb/leveldb/storage"
|
||||
)
|
||||
|
||||
@@ -7,16 +7,17 @@ package model
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/config"
|
||||
"github.com/calmh/syncthing/events"
|
||||
"github.com/calmh/syncthing/osutil"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/calmh/syncthing/scanner"
|
||||
"github.com/calmh/syncthing/versioner"
|
||||
"github.com/syncthing/syncthing/config"
|
||||
"github.com/syncthing/syncthing/events"
|
||||
"github.com/syncthing/syncthing/osutil"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/scanner"
|
||||
"github.com/syncthing/syncthing/versioner"
|
||||
)
|
||||
|
||||
type requestResult struct {
|
||||
@@ -72,6 +73,7 @@ type puller struct {
|
||||
blocks chan bqBlock
|
||||
requestResults chan requestResult
|
||||
versioner versioner.Versioner
|
||||
errors int
|
||||
}
|
||||
|
||||
func newPuller(repoCfg config.RepositoryConfiguration, model *Model, slots int, cfg *config.Configuration) *puller {
|
||||
@@ -128,6 +130,7 @@ func (p *puller) run() {
|
||||
|
||||
prevVer, queued = p.queueNeededBlocks(prevVer)
|
||||
if queued > 0 {
|
||||
p.errors = 0
|
||||
|
||||
pull:
|
||||
for {
|
||||
@@ -145,6 +148,11 @@ func (p *puller) run() {
|
||||
if debug {
|
||||
l.Debugf("%q: pulling loop needs more blocks", p.repoCfg.ID)
|
||||
}
|
||||
|
||||
if p.errors > 0 && p.errors >= queued {
|
||||
break pull
|
||||
}
|
||||
|
||||
prevVer, _ = p.queueNeededBlocks(prevVer)
|
||||
b, ok = p.bq.get()
|
||||
}
|
||||
@@ -179,6 +187,12 @@ func (p *puller) run() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.errors > 0 && p.errors >= queued {
|
||||
l.Warnf("All remaining files failed to sync. Stopping repo %q.", p.repoCfg.ID)
|
||||
invalidateRepo(p.cfg, p.repoCfg.ID, errors.New("too many errors, check logs"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if changed {
|
||||
@@ -365,7 +379,8 @@ func (p *puller) handleBlock(b bqBlock) bool {
|
||||
}
|
||||
err = os.MkdirAll(path, os.FileMode(f.Flags&0777))
|
||||
if err != nil {
|
||||
l.Warnf("Create folder: %q: %v", path, err)
|
||||
p.errors++
|
||||
l.Infof("mkdir: error: %q: %v", path, err)
|
||||
}
|
||||
}
|
||||
} else if debug {
|
||||
@@ -384,13 +399,13 @@ func (p *puller) handleBlock(b bqBlock) bool {
|
||||
fp := filepath.Join(p.repoCfg.Directory, f.Name)
|
||||
t := time.Unix(f.Modified, 0)
|
||||
err := os.Chtimes(fp, t, t)
|
||||
if debug && err != nil {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
if err != nil {
|
||||
l.Infof("chtimes: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
if !p.repoCfg.IgnorePerms && protocol.HasPermissionBits(f.Flags) {
|
||||
err = os.Chmod(fp, os.FileMode(f.Flags&0777))
|
||||
if debug && err != nil {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
if err != nil {
|
||||
l.Infof("chmod: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,16 +439,20 @@ func (p *puller) handleBlock(b bqBlock) bool {
|
||||
_, err := os.Stat(dirName)
|
||||
if err != nil {
|
||||
err = os.MkdirAll(dirName, 0777)
|
||||
} else {
|
||||
// We need to make sure the directory is writeable so we can create files in it
|
||||
if (dirName != p.repoCfg.Directory) {
|
||||
err = os.Chmod(dirName, 0777)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
l.Infof("mkdir: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
|
||||
of.file, of.err = os.Create(of.temp)
|
||||
if of.err != nil {
|
||||
if debug {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, of.err)
|
||||
}
|
||||
p.errors++
|
||||
l.Infof("create: error: %q / %q: %v", p.repoCfg.ID, f.Name, of.err)
|
||||
if !b.last {
|
||||
p.openFiles[f.Name] = of
|
||||
}
|
||||
@@ -482,9 +501,8 @@ func (p *puller) handleCopyBlock(b bqBlock) {
|
||||
var exfd *os.File
|
||||
exfd, of.err = os.Open(of.filepath)
|
||||
if of.err != nil {
|
||||
if debug {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, of.err)
|
||||
}
|
||||
p.errors++
|
||||
l.Infof("open: error: %q / %q: %v", p.repoCfg.ID, f.Name, of.err)
|
||||
of.file.Close()
|
||||
of.file = nil
|
||||
|
||||
@@ -500,9 +518,8 @@ func (p *puller) handleCopyBlock(b bqBlock) {
|
||||
_, of.err = of.file.WriteAt(bs, b.Offset)
|
||||
}
|
||||
if of.err != nil {
|
||||
if debug {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, of.err)
|
||||
}
|
||||
p.errors++
|
||||
l.Infof("write: error: %q / %q: %v", p.repoCfg.ID, f.Name, of.err)
|
||||
exfd.Close()
|
||||
of.file.Close()
|
||||
of.file = nil
|
||||
@@ -585,7 +602,13 @@ func (p *puller) handleEmptyBlock(b bqBlock) {
|
||||
l.Debugf("pull: delete %q", f.Name)
|
||||
}
|
||||
os.Remove(of.temp)
|
||||
|
||||
// Ensure the file and the directory it is in is writeable so we can remove the file
|
||||
dirName := filepath.Dir(of.filepath)
|
||||
os.Chmod(of.filepath, 0666)
|
||||
if (dirName != p.repoCfg.Directory) {
|
||||
os.Chmod(dirName, 0777)
|
||||
}
|
||||
if p.versioner != nil {
|
||||
if debug {
|
||||
l.Debugln("pull: deleting with versioner")
|
||||
@@ -630,10 +653,17 @@ func (p *puller) queueNeededBlocks(prevVer uint64) (uint64, int) {
|
||||
}
|
||||
|
||||
queued := 0
|
||||
files := make([]protocol.FileInfo, 0, indexBatchSize)
|
||||
for _, f := range p.model.NeedFilesRepo(p.repoCfg.ID) {
|
||||
if _, ok := p.openFiles[f.Name]; ok {
|
||||
continue
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
|
||||
perm := rand.Perm(len(files))
|
||||
for _, idx := range perm {
|
||||
f := files[idx]
|
||||
lf := p.model.CurrentRepoFile(p.repoCfg.ID, f.Name)
|
||||
have, need := scanner.BlockDiff(lf.Blocks, f.Blocks)
|
||||
if debug {
|
||||
@@ -646,6 +676,7 @@ func (p *puller) queueNeededBlocks(prevVer uint64) (uint64, int) {
|
||||
need: need,
|
||||
})
|
||||
}
|
||||
|
||||
if debug && queued > 0 {
|
||||
l.Debugf("%q: queued %d items", p.repoCfg.ID, queued)
|
||||
}
|
||||
@@ -663,16 +694,19 @@ func (p *puller) closeFile(f protocol.FileInfo) {
|
||||
}
|
||||
|
||||
of := p.openFiles[f.Name]
|
||||
of.file.Close()
|
||||
err := of.file.Close()
|
||||
if err != nil {
|
||||
p.errors++
|
||||
l.Infof("close: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
defer os.Remove(of.temp)
|
||||
|
||||
delete(p.openFiles, f.Name)
|
||||
|
||||
fd, err := os.Open(of.temp)
|
||||
if err != nil {
|
||||
if debug {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
p.errors++
|
||||
l.Infof("open: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
return
|
||||
}
|
||||
hb, _ := scanner.Blocks(fd, scanner.StandardBlockSize)
|
||||
@@ -687,20 +721,22 @@ func (p *puller) closeFile(f protocol.FileInfo) {
|
||||
|
||||
for i := range hb {
|
||||
if bytes.Compare(hb[i].Hash, f.Blocks[i].Hash) != 0 {
|
||||
l.Debugf("pull: %q / %q: block %d hash mismatch\n\thave: %x\n\twant: %x", p.repoCfg.ID, f.Name, i, hb[i].Hash, f.Blocks[i].Hash)
|
||||
if debug {
|
||||
l.Debugf("pull: %q / %q: block %d hash mismatch\n have: %x\n want: %x", p.repoCfg.ID, f.Name, i, hb[i].Hash, f.Blocks[i].Hash)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t := time.Unix(f.Modified, 0)
|
||||
err = os.Chtimes(of.temp, t, t)
|
||||
if debug && err != nil {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
if err != nil {
|
||||
l.Infof("chtimes: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
if !p.repoCfg.IgnorePerms && protocol.HasPermissionBits(f.Flags) {
|
||||
err = os.Chmod(of.temp, os.FileMode(f.Flags&0777))
|
||||
if debug && err != nil {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
if err != nil {
|
||||
l.Infof("chmod: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -722,7 +758,8 @@ func (p *puller) closeFile(f protocol.FileInfo) {
|
||||
if err := osutil.Rename(of.temp, of.filepath); err == nil {
|
||||
p.model.updateLocal(p.repoCfg.ID, f)
|
||||
} else {
|
||||
l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
p.errors++
|
||||
l.Infof("rename: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/luhn"
|
||||
"github.com/syncthing/syncthing/luhn"
|
||||
)
|
||||
|
||||
type NodeID [32]byte
|
||||
|
||||
@@ -7,6 +7,7 @@ package protocol
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -17,7 +18,6 @@ import (
|
||||
"testing/quick"
|
||||
|
||||
"github.com/calmh/xdr"
|
||||
pretty "github.com/tonnerre/golang-pretty"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -251,6 +251,11 @@ func TestElementSizeExceededNested(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMarshalIndexMessage(t *testing.T) {
|
||||
var quickCfg = &quick.Config{MaxCountScale: 10}
|
||||
if testing.Short() {
|
||||
quickCfg = nil
|
||||
}
|
||||
|
||||
f := func(m1 IndexMessage) bool {
|
||||
for _, f := range m1.Files {
|
||||
for i := range f.Blocks {
|
||||
@@ -264,22 +269,32 @@ func TestMarshalIndexMessage(t *testing.T) {
|
||||
return testMarshal(t, "index", &m1, &IndexMessage{})
|
||||
}
|
||||
|
||||
if err := quick.Check(f, &quick.Config{MaxCountScale: 10}); err != nil {
|
||||
if err := quick.Check(f, quickCfg); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalRequestMessage(t *testing.T) {
|
||||
var quickCfg = &quick.Config{MaxCountScale: 10}
|
||||
if testing.Short() {
|
||||
quickCfg = nil
|
||||
}
|
||||
|
||||
f := func(m1 RequestMessage) bool {
|
||||
return testMarshal(t, "request", &m1, &RequestMessage{})
|
||||
}
|
||||
|
||||
if err := quick.Check(f, &quick.Config{MaxCountScale: 10}); err != nil {
|
||||
if err := quick.Check(f, quickCfg); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalResponseMessage(t *testing.T) {
|
||||
var quickCfg = &quick.Config{MaxCountScale: 10}
|
||||
if testing.Short() {
|
||||
quickCfg = nil
|
||||
}
|
||||
|
||||
f := func(m1 ResponseMessage) bool {
|
||||
if len(m1.Data) == 0 {
|
||||
m1.Data = nil
|
||||
@@ -287,27 +302,37 @@ func TestMarshalResponseMessage(t *testing.T) {
|
||||
return testMarshal(t, "response", &m1, &ResponseMessage{})
|
||||
}
|
||||
|
||||
if err := quick.Check(f, &quick.Config{MaxCountScale: 10}); err != nil {
|
||||
if err := quick.Check(f, quickCfg); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalClusterConfigMessage(t *testing.T) {
|
||||
var quickCfg = &quick.Config{MaxCountScale: 10}
|
||||
if testing.Short() {
|
||||
quickCfg = nil
|
||||
}
|
||||
|
||||
f := func(m1 ClusterConfigMessage) bool {
|
||||
return testMarshal(t, "clusterconfig", &m1, &ClusterConfigMessage{})
|
||||
}
|
||||
|
||||
if err := quick.Check(f, &quick.Config{MaxCountScale: 10}); err != nil {
|
||||
if err := quick.Check(f, quickCfg); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalCloseMessage(t *testing.T) {
|
||||
var quickCfg = &quick.Config{MaxCountScale: 10}
|
||||
if testing.Short() {
|
||||
quickCfg = nil
|
||||
}
|
||||
|
||||
f := func(m1 CloseMessage) bool {
|
||||
return testMarshal(t, "close", &m1, &CloseMessage{})
|
||||
}
|
||||
|
||||
if err := quick.Check(f, &quick.Config{MaxCountScale: 10}); err != nil {
|
||||
if err := quick.Check(f, quickCfg); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -321,12 +346,10 @@ func testMarshal(t *testing.T, prefix string, m1, m2 message) bool {
|
||||
var buf bytes.Buffer
|
||||
|
||||
failed := func(bc []byte) {
|
||||
f, _ := os.Create(prefix + "-1.txt")
|
||||
pretty.Fprintf(f, "%# v", m1)
|
||||
f.Close()
|
||||
f, _ = os.Create(prefix + "-2.txt")
|
||||
pretty.Fprintf(f, "%# v", m2)
|
||||
f.Close()
|
||||
bs, _ := json.MarshalIndent(m1, "", " ")
|
||||
ioutil.WriteFile(prefix+"-1.txt", bs, 0644)
|
||||
bs, _ = json.MarshalIndent(m2, "", " ")
|
||||
ioutil.WriteFile(prefix+"-2.txt", bs, 0644)
|
||||
if len(bc) > 0 {
|
||||
f, _ := os.Create(prefix + "-data.txt")
|
||||
fmt.Fprint(f, hex.Dump(bc))
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
// The parallell hasher reads FileInfo structures from the inbox, hashes the
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
const StandardBlockSize = 128 * 1024
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
var blocksTestData = []struct {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"strings"
|
||||
"code.google.com/p/go.text/unicode/norm"
|
||||
|
||||
"github.com/calmh/syncthing/lamport"
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/lamport"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
type Walker struct {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/calmh/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/protocol"
|
||||
)
|
||||
|
||||
var testdata = []struct {
|
||||
|
||||
17
upgrade/debug.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
|
||||
// All rights reserved. Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package upgrade
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
debug = strings.Contains(os.Getenv("STTRACE"), "upgrade") || os.Getenv("STTRACE") == "all"
|
||||
l = logger.DefaultLogger
|
||||
)
|
||||
@@ -114,7 +114,8 @@ func CompareVersions(a, b string) int {
|
||||
// Split a version into parts.
|
||||
// "1.2.3-beta.2" -> []int{1, 2, 3}, []interface{}{"beta", 2}
|
||||
func versionParts(v string) ([]int, []interface{}) {
|
||||
parts := strings.SplitN(v, "-", 2)
|
||||
parts := strings.SplitN(v, "+", 2)
|
||||
parts = strings.SplitN(parts[0], "-", 2)
|
||||
fields := strings.Split(parts[0], ".")
|
||||
|
||||
release := make([]int, len(fields))
|
||||
|
||||
@@ -23,17 +23,27 @@ import (
|
||||
"bitbucket.org/kardianos/osext"
|
||||
)
|
||||
|
||||
var GoArchExtra string // "", "v5", "v6", "v7"
|
||||
|
||||
// Upgrade to the given release, saving the previous binary with a ".old" extension.
|
||||
func UpgradeTo(rel Release) error {
|
||||
func UpgradeTo(rel Release, archExtra string) error {
|
||||
path, err := osext.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", runtime.GOOS, runtime.GOARCH, GoArchExtra, rel.Tag)
|
||||
osName := runtime.GOOS
|
||||
if osName == "darwin" {
|
||||
// We call the darwin release bundles macosx because that makes more
|
||||
// sense for people downloading them
|
||||
osName = "macosx"
|
||||
}
|
||||
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", osName, runtime.GOARCH, archExtra, rel.Tag)
|
||||
if debug {
|
||||
l.Debugf("expected release asset %q", expectedRelease)
|
||||
}
|
||||
for _, asset := range rel.Assets {
|
||||
if debug {
|
||||
l.Debugln("considering release", asset)
|
||||
}
|
||||
if strings.HasPrefix(asset.Name, expectedRelease) {
|
||||
if strings.HasSuffix(asset.Name, ".tar.gz") {
|
||||
fname, err := readTarGZ(asset.URL, filepath.Dir(path))
|
||||
@@ -60,7 +70,7 @@ func UpgradeTo(rel Release) error {
|
||||
|
||||
// Returns the latest release, including prereleases or not depending on the argument
|
||||
func LatestRelease(prerelease bool) (Release, error) {
|
||||
resp, err := http.Get("https://api.github.com/repos/calmh/syncthing/releases?per_page=10")
|
||||
resp, err := http.Get("https://api.github.com/repos/syncthing/syncthing/releases?per_page=10")
|
||||
if err != nil {
|
||||
return Release{}, err
|
||||
}
|
||||
@@ -91,6 +101,10 @@ func LatestRelease(prerelease bool) (Release, error) {
|
||||
}
|
||||
|
||||
func readTarGZ(url string, dir string) (string, error) {
|
||||
if debug {
|
||||
l.Debugf("loading %q", url)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -123,6 +137,9 @@ func readTarGZ(url string, dir string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if debug {
|
||||
l.Debugf("considering file %q", hdr.Name)
|
||||
}
|
||||
|
||||
if path.Base(hdr.Name) == "syncthing" {
|
||||
of, err := ioutil.TempFile(dir, "syncthing")
|
||||
|
||||
@@ -28,6 +28,9 @@ var testcases = []struct {
|
||||
{"1.0.0-beta.2", "1.0.0-beta.11", -1},
|
||||
{"1.0.0-beta.11", "1.0.0-rc.1", -1},
|
||||
{"1.0.0-rc.1", "1.0.0", -1},
|
||||
{"1.0.0+45", "1.0.0+23-dev-foo", 0},
|
||||
{"1.0.0-beta.23+45", "1.0.0-beta.23+23-dev-foo", 0},
|
||||
{"1.0.0-beta.3+99", "1.0.0-beta.24+0", -1},
|
||||
}
|
||||
|
||||
func TestCompareVersions(t *testing.T) {
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// All rights reserved. Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows solaris noupgrade
|
||||
// +build solaris noupgrade
|
||||
|
||||
package upgrade
|
||||
|
||||
func UpgradeTo(rel Release) error {
|
||||
func UpgradeTo(rel Release, extra string) error {
|
||||
return ErrUpgradeUnsupported
|
||||
}
|
||||
|
||||
|
||||
166
upgrade/upgrade_windows.go
Executable file
@@ -0,0 +1,166 @@
|
||||
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
|
||||
// All rights reserved. Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows,!noupgrade
|
||||
|
||||
package upgrade
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"bitbucket.org/kardianos/osext"
|
||||
)
|
||||
|
||||
// Upgrade to the given release, saving the previous binary with a ".old" extension.
|
||||
func UpgradeTo(rel Release, archExtra string) error {
|
||||
path, err := osext.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expectedRelease := fmt.Sprintf("syncthing-%s-%s%s-%s.", runtime.GOOS, runtime.GOARCH, archExtra, rel.Tag)
|
||||
if debug {
|
||||
l.Debugf("expected release asset %q", expectedRelease)
|
||||
}
|
||||
for _, asset := range rel.Assets {
|
||||
if debug {
|
||||
l.Debugln("considering release", asset)
|
||||
}
|
||||
if strings.HasPrefix(asset.Name, expectedRelease) {
|
||||
if strings.HasSuffix(asset.Name, ".zip") {
|
||||
fname, err := readZip(asset.URL, filepath.Dir(path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
old := path + ".old"
|
||||
|
||||
os.Remove(old)
|
||||
err = os.Rename(path, old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Rename(fname, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ErrVersionUnknown
|
||||
}
|
||||
|
||||
// Returns the latest release, including prereleases or not depending on the argument
|
||||
func LatestRelease(prerelease bool) (Release, error) {
|
||||
resp, err := http.Get("https://api.github.com/repos/syncthing/syncthing/releases?per_page=10")
|
||||
if err != nil {
|
||||
return Release{}, err
|
||||
}
|
||||
if resp.StatusCode > 299 {
|
||||
return Release{}, fmt.Errorf("API call returned HTTP error: %s", resp.Status)
|
||||
}
|
||||
|
||||
var rels []Release
|
||||
json.NewDecoder(resp.Body).Decode(&rels)
|
||||
resp.Body.Close()
|
||||
|
||||
if len(rels) == 0 {
|
||||
return Release{}, ErrVersionUnknown
|
||||
}
|
||||
|
||||
if prerelease {
|
||||
// We are a beta version. Use the latest.
|
||||
return rels[0], nil
|
||||
} else {
|
||||
// We are a regular release. Only consider non-prerelease versions for upgrade.
|
||||
for _, rel := range rels {
|
||||
if !rel.Prerelease {
|
||||
return rel, nil
|
||||
}
|
||||
}
|
||||
return Release{}, ErrVersionUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func readZip(url, dir string) (string, error) {
|
||||
if debug {
|
||||
l.Debugf("loading %q", url)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Add("Accept", "application/octet-stream")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
archive, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
for _, file := range archive.File {
|
||||
|
||||
if debug {
|
||||
l.Debugf("considering file %q", file.Name)
|
||||
}
|
||||
|
||||
if path.Base(file.Name) == "syncthing.exe" {
|
||||
infile, err := file.Open()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
outfile, err := ioutil.TempFile(dir, "syncthing")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, err = io.Copy(outfile, infile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = infile.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = outfile.Close()
|
||||
if err != nil {
|
||||
os.Remove(outfile.Name())
|
||||
return "", err
|
||||
}
|
||||
|
||||
os.Chmod(outfile.Name(), file.Mode())
|
||||
return outfile.Name(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("No upgrade found")
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/calmh/syncthing/logger"
|
||||
"github.com/syncthing/syncthing/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||