mirror of
https://github.com/syncthing/syncthing.git
synced 2026-01-03 19:39:20 -05:00
Compare commits
98 Commits
v2.0.0-rc.
...
v2.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
755daaa7b7 | ||
|
|
33b5c3c62e | ||
|
|
ffb30392e8 | ||
|
|
7a76685d7e | ||
|
|
370bbb8f26 | ||
|
|
9ea6c9c3c3 | ||
|
|
8f117a4417 | ||
|
|
bbf48ae334 | ||
|
|
fcf4916086 | ||
|
|
5d8033343f | ||
|
|
c74d2a9872 | ||
|
|
3da84804b6 | ||
|
|
5b75c6ddcb | ||
|
|
ae03854575 | ||
|
|
ad196173d0 | ||
|
|
d682220305 | ||
|
|
29e10e00d2 | ||
|
|
34f61ce464 | ||
|
|
adcbd31e62 | ||
|
|
431da839cf | ||
|
|
836045ee87 | ||
|
|
49462448d0 | ||
|
|
e3424ad503 | ||
|
|
5703423c00 | ||
|
|
356ec26c87 | ||
|
|
d37cb02e40 | ||
|
|
953944e54e | ||
|
|
6e26fab3a0 | ||
|
|
532e30eb6b | ||
|
|
54bb987fae | ||
|
|
74367d2f66 | ||
|
|
0f6750c8f5 | ||
|
|
c8c38f735f | ||
|
|
fa4bd5c057 | ||
|
|
36fb5425a5 | ||
|
|
32a913c0ff | ||
|
|
e8cfc8acfb | ||
|
|
7c07610ab2 | ||
|
|
ff88430efb | ||
|
|
06dd8ee6d7 | ||
|
|
c0aa7b436c | ||
|
|
b80fa9dcd2 | ||
|
|
95187bcc64 | ||
|
|
f2a5b62733 | ||
|
|
385ca6772c | ||
|
|
88c307b65b | ||
|
|
9d425b0588 | ||
|
|
cf84a260ca | ||
|
|
c4e024c7e3 | ||
|
|
c5a29b5b26 | ||
|
|
4c64843d60 | ||
|
|
b4ff96d754 | ||
|
|
21c5ac2161 | ||
|
|
6fc0b41f97 | ||
|
|
0b0b2143ed | ||
|
|
af64140c61 | ||
|
|
1c68062231 | ||
|
|
4d92855d76 | ||
|
|
1c6f542cb7 | ||
|
|
b28066c85d | ||
|
|
71c8a2c36f | ||
|
|
e4ab7b4ff3 | ||
|
|
8b978d4712 | ||
|
|
7b319111d3 | ||
|
|
cb7cea93a2 | ||
|
|
20257faf54 | ||
|
|
c14abebd68 | ||
|
|
b1a1a90045 | ||
|
|
8afc9855f2 | ||
|
|
4215058911 | ||
|
|
9fb1a18dbf | ||
|
|
064213ceb8 | ||
|
|
0211251b34 | ||
|
|
1903da569b | ||
|
|
b6a7beca1f | ||
|
|
7b83e7403e | ||
|
|
1915a470e9 | ||
|
|
0b100296e1 | ||
|
|
e6ed3acf5f | ||
|
|
9f95bf3573 | ||
|
|
b05ece0681 | ||
|
|
5381178c46 | ||
|
|
e7f4f8306c | ||
|
|
9922a3abd9 | ||
|
|
40ab668a73 | ||
|
|
10d20c4800 | ||
|
|
700bb75016 | ||
|
|
e25de22705 | ||
|
|
ef6d561c66 | ||
|
|
3c92999406 | ||
|
|
e61b8a1ae8 | ||
|
|
706409d2f3 | ||
|
|
e9133ef82b | ||
|
|
67ba20d777 | ||
|
|
21da0d7890 | ||
|
|
ebbe57d0ab | ||
|
|
9cf8fca03f | ||
|
|
f4abc71dcc |
2
.github/workflows/build-infra-dockers.yaml
vendored
2
.github/workflows/build-infra-dockers.yaml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
- infra-*
|
||||
|
||||
env:
|
||||
GO_VERSION: "~1.24.0"
|
||||
GO_VERSION: "~1.25.0"
|
||||
CGO_ENABLED: "0"
|
||||
BUILD_USER: docker
|
||||
BUILD_HOST: github.syncthing.net
|
||||
|
||||
328
.github/workflows/build-syncthing.yaml
vendored
328
.github/workflows/build-syncthing.yaml
vendored
@@ -13,9 +13,9 @@ env:
|
||||
# The go version to use for builds. We set check-latest to true when
|
||||
# installing, so we get the latest patch version that matches the
|
||||
# expression.
|
||||
GO_VERSION: "~1.24.0"
|
||||
GO_VERSION: "~1.25.0"
|
||||
|
||||
# Optimize compatibility on the slow archictures.
|
||||
# Optimize compatibility on the slow architectures.
|
||||
GOMIPS: softfloat
|
||||
GOARM: "6"
|
||||
|
||||
@@ -26,7 +26,8 @@ env:
|
||||
BUILD_USER: builder
|
||||
BUILD_HOST: github.syncthing.net
|
||||
|
||||
TAGS: "netgo osusergo sqlite_omit_load_extension sqlite_dbstat"
|
||||
TAGS: "sqlite_omit_load_extension sqlite_dbstat"
|
||||
TAGS_LINUX: "sqlite_omit_load_extension sqlite_dbstat netgo osusergo"
|
||||
|
||||
# A note on actions and third party code... The actions under actions/ (like
|
||||
# `uses: actions/checkout`) are maintained by GitHub, and we need to trust
|
||||
@@ -37,6 +38,58 @@ env:
|
||||
|
||||
jobs:
|
||||
|
||||
#
|
||||
# Source
|
||||
#
|
||||
|
||||
facts:
|
||||
name: Gather common facts
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.get-version.outputs.version }}
|
||||
release-kind: ${{ steps.get-version.outputs.release-kind }}
|
||||
release-generation: ${{ steps.get-version.outputs.release-generation }}
|
||||
go-version: ${{ steps.get-go.outputs.go-version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get Syncthing version
|
||||
id: get-version
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
echo "Version: $version"
|
||||
|
||||
kind=stable
|
||||
if [[ $version == *-rc.[0-9] || $version == *-rc.[0-9][0-9] ]] ; then
|
||||
kind=candidate
|
||||
elif [[ $version == *-* ]] ; then
|
||||
kind=nightly
|
||||
fi
|
||||
echo "release-kind=$kind" >> "$GITHUB_OUTPUT"
|
||||
echo "Release kind: $kind"
|
||||
|
||||
generation=v1
|
||||
if [[ $version == v2.* ]] ; then
|
||||
generation=v2
|
||||
fi
|
||||
echo "release-generation=$generation" >> "$GITHUB_OUTPUT"
|
||||
echo "Release generation: $generation"
|
||||
- name: Get Go version
|
||||
id: get-go
|
||||
run: |
|
||||
go version
|
||||
echo "go-version=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_OUTPUT
|
||||
|
||||
#
|
||||
# Tests for all platforms. Runs a matrix build on Windows, Linux and Mac,
|
||||
# with the list of expected supported Go versions (current, previous).
|
||||
@@ -50,7 +103,7 @@ jobs:
|
||||
runner: ["windows-latest", "ubuntu-latest", "macos-latest"]
|
||||
# The oldest version in this list should match what we have in our go.mod.
|
||||
# Variables don't seem to be supported here, or we could have done something nice.
|
||||
go: ["~1.23.0", "~1.24.0"]
|
||||
go: ["~1.24.0", "~1.25.0"]
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- name: Set git to use LF
|
||||
@@ -123,17 +176,18 @@ jobs:
|
||||
package-windows:
|
||||
name: Package for Windows
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -142,7 +196,7 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-windows-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-windows-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -154,7 +208,7 @@ jobs:
|
||||
go run build.go -tags "${{env.TAGS}}" -goos windows -goarch amd64 -cc "zig cc -target x86_64-windows" zip $tgt
|
||||
go run build.go -tags "${{env.TAGS}}" -goos windows -goarch 386 -cc "zig cc -target x86-windows" zip $tgt
|
||||
go run build.go -tags "${{env.TAGS}}" -goos windows -goarch arm64 -cc "zig cc -target aarch64-windows" zip $tgt
|
||||
# go run build.go -tags "${{env.TAGS}}" -goos windows -goarch arm -cc "zig cc -target thumb-windows" zip $tgt # failes with linker errors
|
||||
# go run build.go -tags "${{env.TAGS}}" -goos windows -goarch arm -cc "zig cc -target thumb-windows" zip $tgt # fails with linker errors
|
||||
done
|
||||
env:
|
||||
CGO_ENABLED: "1"
|
||||
@@ -231,22 +285,18 @@ jobs:
|
||||
package-linux:
|
||||
name: Package for Linux
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -255,25 +305,25 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Create packages
|
||||
run: |
|
||||
sudo apt-get install -y gcc-mips64-linux-gnuabi64 gcc-mips64el-linux-gnuabi64
|
||||
for tgt in syncthing stdiscosrv strelaysrv ; do
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch 386 -cc "zig cc -target x86-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch arm -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips -cc "zig cc -target mips-linux-musleabi" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mipsle -cc "zig cc -target mipsel-linux-musleabi" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips64 -cc mips64-linux-gnuabi64-gcc tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips64le -cc mips64el-linux-gnuabi64-gcc tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch riscv64 -cc "zig cc -target riscv64-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch s390x -cc "zig cc -target s390x-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch loong64 -cc "zig cc -target loongarch64-linux-musl" tar "$tgt"
|
||||
# go run build.go -tags "${{env.TAGS}}" -goos linux -goarch ppc64 -cc "zig cc -target powerpc64-linux-musl" tar "$tgt" # fails with linkmode not supported
|
||||
go run build.go -tags "${{env.TAGS}}" -goos linux -goarch ppc64le -cc "zig cc -target powerpc64le-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch 386 -cc "zig cc -target x86-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch arm -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch mips -cc "zig cc -target mips-linux-musleabi" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch mipsle -cc "zig cc -target mipsel-linux-musleabi" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch mips64 -cc mips64-linux-gnuabi64-gcc tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch mips64le -cc mips64el-linux-gnuabi64-gcc tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch riscv64 -cc "zig cc -target riscv64-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch s390x -cc "zig cc -target s390x-linux-musl" tar "$tgt"
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch loong64 -cc "zig cc -target loongarch64-linux-musl" tar "$tgt"
|
||||
# go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch ppc64 -cc "zig cc -target powerpc64-linux-musl" tar "$tgt" # fails with linkmode not supported
|
||||
go run build.go -tags "${{env.TAGS_LINUX}}" -goos linux -goarch ppc64le -cc "zig cc -target powerpc64le-linux-musl" tar "$tgt"
|
||||
done
|
||||
env:
|
||||
CGO_ENABLED: "1"
|
||||
@@ -297,32 +347,27 @@ jobs:
|
||||
name: Package for macOS
|
||||
if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v'))
|
||||
environment: release
|
||||
runs-on: macos-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}
|
||||
runs-on: macos-latest
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Import signing certificate
|
||||
if: env.CODESIGN_IDENTITY != ''
|
||||
@@ -432,29 +477,25 @@ jobs:
|
||||
package-cross:
|
||||
name: Package cross compiled
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-cross-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-cross-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Create packages
|
||||
run: |
|
||||
@@ -502,33 +543,33 @@ jobs:
|
||||
package-source:
|
||||
name: Package source code
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Package source
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "$version" > RELEASE
|
||||
echo "$VERSION" > RELEASE
|
||||
|
||||
go mod vendor
|
||||
go run build.go assets
|
||||
|
||||
cd ..
|
||||
|
||||
tar c -z -f "syncthing-source-$version.tar.gz" \
|
||||
tar c -z -f "syncthing-source-$VERSION.tar.gz" \
|
||||
--exclude .git \
|
||||
syncthing
|
||||
|
||||
mv "syncthing-source-$version.tar.gz" syncthing
|
||||
mv "syncthing-source-$VERSION.tar.gz" syncthing
|
||||
|
||||
- name: Archive artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -550,27 +591,26 @@ jobs:
|
||||
- package-macos
|
||||
- package-cross
|
||||
- package-source
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: syncthing/release-tools
|
||||
path: tools
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Install signing tool
|
||||
run: |
|
||||
@@ -597,9 +637,6 @@ jobs:
|
||||
sha256sum "${files[@]}" > sha256sum.txt
|
||||
popd
|
||||
|
||||
version=$(go run build.go version)
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
- name: Sign shasum files
|
||||
uses: docker://ghcr.io/kastelo/ezapt:latest
|
||||
with:
|
||||
@@ -635,22 +672,18 @@ jobs:
|
||||
package-debian:
|
||||
name: Package for Debian
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
@@ -667,14 +700,15 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-debian-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-debian-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Package for Debian (CGO)
|
||||
run: |
|
||||
for tgt in syncthing stdiscosrv strelaysrv ; do
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch arm -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS_LINUX}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS_LINUX}}" -goos linux -goarch armel -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS_LINUX}}" -goos linux -goarch armhf -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt"
|
||||
go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS_LINUX}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" deb "$tgt"
|
||||
done
|
||||
env:
|
||||
BUILD_USER: debian
|
||||
@@ -697,13 +731,13 @@ jobs:
|
||||
environment: release
|
||||
needs:
|
||||
- sign-for-upgrade
|
||||
- facts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: syncthing/release-tools
|
||||
path: tools
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -713,9 +747,8 @@ jobs:
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Create release json
|
||||
run: |
|
||||
@@ -735,7 +768,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v packages objstore:nightly
|
||||
args: sync -v --no-update-modtime packages objstore:nightly
|
||||
|
||||
#
|
||||
# Push release artifacts to Spaces
|
||||
@@ -750,6 +783,10 @@ jobs:
|
||||
needs:
|
||||
- sign-for-upgrade
|
||||
- package-debian
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -771,14 +808,8 @@ jobs:
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
- name: Push to object store (${{ env.VERSION }})
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
@@ -791,7 +822,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v packages objstore:release/${{ env.VERSION }}
|
||||
args: sync -v --no-update-modtime packages objstore:release/${{ env.VERSION }}
|
||||
|
||||
- name: Push to object store (latest)
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
@@ -804,9 +835,9 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v objstore:release/${{ env.VERSION }} objstore:release/latest
|
||||
args: sync -v --no-update-modtime objstore:release/${{ env.VERSION }} objstore:release/latest
|
||||
|
||||
- name: Create GitHub release and push binaries
|
||||
- name: Create GitHub releases and push binaries
|
||||
run: |
|
||||
maybePrerelease=""
|
||||
if [[ $VERSION == *-* ]]; then
|
||||
@@ -814,19 +845,33 @@ jobs:
|
||||
fi
|
||||
export GH_PROMPT_DISABLED=1
|
||||
if ! gh release view --json name "$VERSION" >/dev/null 2>&1 ; then
|
||||
gh release create \
|
||||
"$VERSION" \
|
||||
gh release create "$VERSION" \
|
||||
$maybePrerelease \
|
||||
--title "$VERSION" \
|
||||
--notes-from-tag
|
||||
fi
|
||||
gh release upload "$VERSION" \
|
||||
gh release upload --clobber "$VERSION" \
|
||||
packages/*.asc packages/*.json \
|
||||
packages/syncthing-*.tar.gz \
|
||||
packages/syncthing-*.zip \
|
||||
packages/syncthing*.deb
|
||||
packages/syncthing_*.deb
|
||||
|
||||
PKGS=$(pwd)/packages
|
||||
cd /tmp # gh will not release for repo x while inside repo y
|
||||
for repo in relaysrv discosrv ; do
|
||||
export GH_REPO="syncthing/$repo"
|
||||
if ! gh release view --json name "$VERSION" >/dev/null 2>&1 ; then
|
||||
gh release create "$VERSION" \
|
||||
$maybePrerelease \
|
||||
--title "$VERSION" \
|
||||
--notes "https://github.com/syncthing/syncthing/releases/tag/$VERSION"
|
||||
fi
|
||||
gh release upload --clobber "$VERSION" \
|
||||
$PKGS/*.asc \
|
||||
$PKGS/*${repo}*
|
||||
done
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
|
||||
|
||||
#
|
||||
# Push Debian/APT archive
|
||||
@@ -838,12 +883,14 @@ jobs:
|
||||
environment: release
|
||||
needs:
|
||||
- package-debian
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
RELEASE_GENERATION: ${{ needs.facts.outputs.release-generation }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- name: Download packages
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -851,26 +898,14 @@ jobs:
|
||||
name: debian-packages
|
||||
path: packages
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
echo "Version: $version"
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
# Decide whether packages should go to stable, candidate or nightly
|
||||
- name: Prepare packages
|
||||
run: |
|
||||
kind=stable
|
||||
if [[ $VERSION == v2* ]] ; then
|
||||
kind=v2
|
||||
elif [[ $VERSION == *-rc.[0-9] ]] ; then
|
||||
kind=candidate
|
||||
elif [[ $VERSION == *-* ]] ; then
|
||||
kind=nightly
|
||||
if [[ $RELEASE_KIND == stable && $RELEASE_GENERATION == v2 ]] ; then
|
||||
RELEASE_KIND=stable-v2
|
||||
fi
|
||||
echo "Kind: $kind"
|
||||
mkdir -p packages/syncthing/$kind
|
||||
mv packages/*.deb packages/syncthing/$kind
|
||||
mkdir -p packages/syncthing/$RELEASE_KIND
|
||||
mv packages/*.deb packages/syncthing/$RELEASE_KIND
|
||||
|
||||
- name: Pull archive
|
||||
uses: docker://docker.io/rclone/rclone:latest
|
||||
@@ -906,7 +941,7 @@ jobs:
|
||||
RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
|
||||
RCLONE_CONFIG_OBJSTORE_ACL: public-read
|
||||
with:
|
||||
args: sync -v dists objstore:apt/dists
|
||||
args: sync -v --no-update-modtime dists objstore:apt/dists
|
||||
|
||||
#
|
||||
# Build and push (except for PRs) to GHCR.
|
||||
@@ -918,6 +953,11 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
needs:
|
||||
- facts
|
||||
env:
|
||||
VERSION: ${{ needs.facts.outputs.version }}
|
||||
RELEASE_KIND: ${{ needs.facts.outputs.release-kind }}
|
||||
strategy:
|
||||
matrix:
|
||||
pkg:
|
||||
@@ -936,20 +976,11 @@ jobs:
|
||||
image: discosrv
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: Get actual Go version
|
||||
run: |
|
||||
go version
|
||||
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
|
||||
|
||||
- uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -958,20 +989,20 @@ jobs:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }}
|
||||
|
||||
- name: Build binaries (CGO)
|
||||
run: |
|
||||
# amd64
|
||||
go run build.go -goos linux -goarch amd64 -tags "${{env.TAGS}}" -cc "zig cc -target x86_64-linux-musl" -no-upgrade build ${{ matrix.pkg }}
|
||||
go run build.go -goos linux -goarch amd64 -tags "${{env.TAGS_LINUX}}" -cc "zig cc -target x86_64-linux-musl" -no-upgrade build ${{ matrix.pkg }}
|
||||
mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-amd64
|
||||
|
||||
# arm64
|
||||
go run build.go -goos linux -goarch arm64 -tags "${{env.TAGS}}" -cc "zig cc -target aarch64-linux-musl" -no-upgrade build ${{ matrix.pkg }}
|
||||
go run build.go -goos linux -goarch arm64 -tags "${{env.TAGS_LINUX}}" -cc "zig cc -target aarch64-linux-musl" -no-upgrade build ${{ matrix.pkg }}
|
||||
mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-arm64
|
||||
|
||||
# arm
|
||||
go run build.go -goos linux -goarch arm -tags "${{env.TAGS}}" -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" -no-upgrade build ${{ matrix.pkg }}
|
||||
go run build.go -goos linux -goarch arm -tags "${{env.TAGS_LINUX}}" -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" -no-upgrade build ${{ matrix.pkg }}
|
||||
mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-arm
|
||||
env:
|
||||
CGO_ENABLED: "1"
|
||||
@@ -990,8 +1021,7 @@ jobs:
|
||||
|
||||
- name: Set version tags
|
||||
run: |
|
||||
version=$(go run build.go version)
|
||||
version=${version#v}
|
||||
version=${VERSION#v}
|
||||
repo=ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}
|
||||
ref="${{github.ref_name}}"
|
||||
ref=${ref//\//-} # slashes to dashes
|
||||
@@ -1010,9 +1040,7 @@ jobs:
|
||||
fi
|
||||
|
||||
echo Pushing to $tags
|
||||
|
||||
echo "DOCKER_TAGS=$tags" >> $GITHUB_ENV
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
@@ -1057,14 +1085,15 @@ jobs:
|
||||
govulncheck:
|
||||
runs-on: ubuntu-latest
|
||||
name: Run govulncheck
|
||||
needs:
|
||||
- facts
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version: ${{ needs.facts.outputs.go-version }}
|
||||
cache: false
|
||||
check-latest: true
|
||||
|
||||
- name: run govulncheck
|
||||
run: |
|
||||
@@ -1079,6 +1108,7 @@ jobs:
|
||||
golangci:
|
||||
runs-on: ubuntu-latest
|
||||
name: Run golangci-lint
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
|
||||
18
.github/workflows/mirrors.yaml
vendored
Normal file
18
.github/workflows/mirrors.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Mirrors
|
||||
|
||||
on: [push, delete]
|
||||
|
||||
jobs:
|
||||
codeberg:
|
||||
name: Mirror to Codeberg
|
||||
if: github.repository_owner == 'syncthing'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: yesolutions/mirror-action@master
|
||||
with:
|
||||
REMOTE: ssh://git@codeberg.org/${{ github.repository }}.git
|
||||
GIT_SSH_PRIVATE_KEY: ${{ secrets.CODEBERG_PUSH_KEY }}
|
||||
GIT_SSH_NO_VERIFY_HOST: "true"
|
||||
7
.github/workflows/release-syncthing.yaml
vendored
7
.github/workflows/release-syncthing.yaml
vendored
@@ -51,3 +51,10 @@ jobs:
|
||||
git config --global user.email 'release@syncthing.net'
|
||||
git tag -a -F notes.md --cleanup=whitespace "$NEXT"
|
||||
git push origin "$NEXT"
|
||||
|
||||
- name: Trigger the build
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
with:
|
||||
workflow: build-syncthing.yaml
|
||||
ref: refs/tags/${{ env.NEXT }}
|
||||
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
|
||||
|
||||
@@ -8,12 +8,14 @@ linters:
|
||||
- exhaustive
|
||||
- exhaustruct
|
||||
- forbidigo
|
||||
- funcorder
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- goconst
|
||||
- gocyclo
|
||||
- godot
|
||||
- godox
|
||||
- gomoddirectives
|
||||
- inamedparam
|
||||
@@ -25,6 +27,7 @@ linters:
|
||||
- musttag
|
||||
- nestif
|
||||
- nlreturn
|
||||
- noinlineerr
|
||||
- nonamedreturns
|
||||
- paralleltest
|
||||
- prealloc
|
||||
@@ -40,6 +43,7 @@ linters:
|
||||
- whitespace
|
||||
- wrapcheck
|
||||
- wsl
|
||||
- wsl_v5
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
@@ -49,12 +53,23 @@ linters:
|
||||
- std-error-handling
|
||||
paths:
|
||||
- internal/gen
|
||||
- internal/db/olddb
|
||||
- cmd/dev
|
||||
- repos
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
- _test\.go$
|
||||
rules:
|
||||
# relax the slog rules for debug lines, for now
|
||||
- linters: [sloglint]
|
||||
source: Debug
|
||||
settings:
|
||||
sloglint:
|
||||
context: "scope"
|
||||
static-msg: true
|
||||
msg-style: capitalized
|
||||
key-naming-case: camel
|
||||
formatters:
|
||||
enable:
|
||||
- gofumpt
|
||||
|
||||
6
AUTHORS
6
AUTHORS
@@ -56,10 +56,12 @@ Anthony Goeckner <agoeckner@users.noreply.github.com>
|
||||
Antoine Lamielle (0x010C) <antoine.lamielle@0x010c.fr> <gh@0x010c.fr>
|
||||
Anur <anurnomeru@163.com>
|
||||
Aranjedeath <Aranjedeath@users.noreply.github.com>
|
||||
ardevd <ardevd@users.noreply.github.com>
|
||||
Arkadiusz Tymiński <gevleeog@gmail.com>
|
||||
Aroun <login@b-vo.fr>
|
||||
Arthur Axel fREW Schmidt (frioux) <frew@afoolishmanifesto.com> <frioux@gmail.com>
|
||||
Artur Zubilewicz <AkaZecik@users.noreply.github.com>
|
||||
Ashish Bhate <bhate.ashish@gmail.com>
|
||||
Aurélien Rainone <476650+arl@users.noreply.github.com>
|
||||
BAHADIR YILMAZ <bahadiryilmaz32@gmail.com>
|
||||
Bart De Vries (mogwa1) <devriesb@gmail.com>
|
||||
@@ -93,6 +95,7 @@ Daniel Barczyk <46358936+DanielBarczyk@users.noreply.github.com>
|
||||
Daniel Bergmann (brgmnn) <dan.arne.bergmann@gmail.com> <brgmnn@users.noreply.github.com>
|
||||
Daniel Martí (mvdan) <mvdan@mvdan.cc>
|
||||
Daniel Padrta <64928366+danpadcz@users.noreply.github.com>
|
||||
Daniil Gentili <daniil@daniil.it>
|
||||
Darshil Chanpura (dtchanpura) <dtchanpura@gmail.com> <dcprime314@gmail.com>
|
||||
dashangcun <907225865@qq.com>
|
||||
David Rimmer (dinosore) <dinosore@dbrsoftware.co.uk>
|
||||
@@ -192,6 +195,7 @@ Luke Hamburg <1992842+luckman212@users.noreply.github.com>
|
||||
luzpaz <luzpaz@users.noreply.github.com>
|
||||
Majed Abdulaziz (majedev) <majed.alhajry@gmail.com>
|
||||
Marc Laporte (marclaporte) <marc@marclaporte.com> <marc@laporte.name>
|
||||
Marcel Meyer <mm.marcelmeyer@gmail.com>
|
||||
Marcin Dziadus (marcindziadus) <dziadus.marcin@gmail.com>
|
||||
Marcus B Spencer <marcus@marcusspencer.xyz> <marcus@marcusspencer.us>
|
||||
Marcus Legendre <marcus.legendre@gmail.com>
|
||||
@@ -252,6 +256,7 @@ Philippe Schommers (filoozoom) <philippe@schommers.be>
|
||||
Phill Luby (pluby) <phill.luby@newredo.com>
|
||||
Piotr Bejda (piobpl) <piotrb10@gmail.com>
|
||||
polyfloyd <polyfloyd@users.noreply.github.com>
|
||||
pullmerge <166967364+pullmerge@users.noreply.github.com>
|
||||
Quentin Hibon <qh.public@yahoo.com>
|
||||
Rahmi Pruitt <rjpruitt16@gmail.com>
|
||||
red_led <red-led@users.noreply.github.com>
|
||||
@@ -312,5 +317,6 @@ xarx00 <xarx00@users.noreply.github.com>
|
||||
Xavier O. (damajor) <damajor@gmail.com>
|
||||
xjtdy888 (xjtdy888) <xjtdy888@163.com> <xjtdy888@gmail.com>
|
||||
Yannic A. (eipiminus1) <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>
|
||||
yparitcher <y@paritcher.com>
|
||||
佛跳墙 <daoquan@qq.com>
|
||||
落心 <luoxin.ttt@gmail.com>
|
||||
|
||||
7
build.go
7
build.go
@@ -870,7 +870,6 @@ func testmocks() {
|
||||
"github.com/syncthing/syncthing/lib/connections",
|
||||
"github.com/syncthing/syncthing/lib/discover",
|
||||
"github.com/syncthing/syncthing/lib/events",
|
||||
"github.com/syncthing/syncthing/lib/logger",
|
||||
"github.com/syncthing/syncthing/lib/model",
|
||||
"github.com/syncthing/syncthing/lib/protocol",
|
||||
}
|
||||
@@ -901,6 +900,7 @@ func weblate() {
|
||||
func ldflags(tags []string) string {
|
||||
b := new(strings.Builder)
|
||||
b.WriteString("-w")
|
||||
b.WriteString(" -buildid=")
|
||||
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Version=%s", version)
|
||||
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.Stamp=%d", buildStamp())
|
||||
fmt.Fprintf(b, " -X github.com/syncthing/syncthing/lib/build.User=%s", buildUser())
|
||||
@@ -922,6 +922,9 @@ func rmr(paths ...string) {
|
||||
}
|
||||
|
||||
func getReleaseVersion() (string, error) {
|
||||
if ver := os.Getenv("VERSION"); ver != "" {
|
||||
return strings.TrimSpace(ver), nil
|
||||
}
|
||||
bs, err := os.ReadFile("RELEASE")
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -966,7 +969,7 @@ func getGitVersion() (string, error) {
|
||||
}
|
||||
|
||||
func getVersion() string {
|
||||
// First try for a RELEASE file,
|
||||
// First try for a RELEASE file or $VERSION env var,
|
||||
if ver, err := getReleaseVersion(); err == nil {
|
||||
return ver
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ type cli struct {
|
||||
SentryQueue int `help:"Maximum number of reports to queue for sending to Sentry" default:"64" env:"SENTRY_QUEUE"`
|
||||
DiskQueue int `help:"Maximum number of reports to queue for writing to disk" default:"64" env:"DISK_QUEUE"`
|
||||
MetricsListen string `help:"HTTP listen address for metrics" default:":8081" env:"METRICS_LISTEN_ADDRESS"`
|
||||
IngorePatterns string `help:"File containing ignore patterns (regexp)" env:"IGNORE_PATTERNS" type:"existingfile"`
|
||||
IgnorePatterns string `help:"File containing ignore patterns (regexp)" env:"IGNORE_PATTERNS" type:"existingfile"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -68,9 +68,9 @@ func main() {
|
||||
go ss.Serve(context.Background())
|
||||
|
||||
var ip *ignorePatterns
|
||||
if params.IngorePatterns != "" {
|
||||
if params.IgnorePatterns != "" {
|
||||
var err error
|
||||
ip, err = loadIgnorePatterns(params.IngorePatterns)
|
||||
ip, err = loadIgnorePatterns(params.IgnorePatterns)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load ignore patterns: %v", err)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -31,7 +32,6 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/rand"
|
||||
"github.com/syncthing/syncthing/lib/relay/client"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
"github.com/syncthing/syncthing/lib/tlsutil"
|
||||
)
|
||||
|
||||
@@ -115,7 +115,7 @@ var (
|
||||
|
||||
requests chan request
|
||||
|
||||
mut = sync.NewRWMutex()
|
||||
mut sync.RWMutex
|
||||
knownRelays = make([]*relay, 0)
|
||||
permanentRelays = make([]*relay, 0)
|
||||
evictionTimers = make(map[string]*time.Timer)
|
||||
@@ -620,7 +620,7 @@ func createTestCertificate() tls.Certificate {
|
||||
}
|
||||
|
||||
certFile, keyFile := filepath.Join(tmpDir, "cert.pem"), filepath.Join(tmpDir, "key.pem")
|
||||
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv", 20*365)
|
||||
cert, err := tlsutil.NewCertificate(certFile, keyFile, "relaypoolsrv", 20*365, false)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to create test X509 key pair:", err)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -28,8 +27,6 @@ func init() {
|
||||
{URL: "known2"},
|
||||
{URL: "known3"},
|
||||
}
|
||||
|
||||
mut = new(sync.RWMutex)
|
||||
}
|
||||
|
||||
// Regression test: handleGetRequest should not modify permanentRelays.
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -104,7 +104,7 @@ func refreshStats() {
|
||||
mut.RUnlock()
|
||||
|
||||
now := time.Now()
|
||||
wg := sync.NewWaitGroup()
|
||||
var wg sync.WaitGroup
|
||||
|
||||
results := make(chan statsFetchResult, len(relays))
|
||||
for _, rel := range relays {
|
||||
@@ -173,7 +173,7 @@ func fetchStats(relay *relay) *stats {
|
||||
|
||||
var stats stats
|
||||
|
||||
if json.NewDecoder(response.Body).Decode(&stats); err != nil {
|
||||
if err := json.NewDecoder(response.Body).Decode(&stats); err != nil {
|
||||
return nil
|
||||
}
|
||||
return &stats
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/alecthomas/kong"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
_ "github.com/syncthing/syncthing/lib/automaxprocs"
|
||||
"github.com/syncthing/syncthing/lib/httpcache"
|
||||
"github.com/syncthing/syncthing/lib/upgrade"
|
||||
@@ -58,10 +59,10 @@ func server(params *cli) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("metrics: %w", err)
|
||||
}
|
||||
slog.Info("Metrics listener started", "addr", params.MetricsListen)
|
||||
slog.Info("Metrics listener started", slogutil.Address(params.MetricsListen))
|
||||
go func() {
|
||||
if err := http.Serve(metricsListen, mux); err != nil {
|
||||
slog.Warn("Metrics server returned", "error", err)
|
||||
slog.Warn("Metrics server returned", slogutil.Error(err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -75,9 +76,9 @@ func server(params *cli) error {
|
||||
|
||||
go func() {
|
||||
for range time.NewTicker(params.CacheTime).C {
|
||||
slog.Info("Refreshing cached releases", "url", params.URL)
|
||||
slog.Info("Refreshing cached releases", slogutil.URI(params.URL))
|
||||
if err := cache.Update(context.Background()); err != nil {
|
||||
slog.Error("Failed to refresh cached releases", "url", params.URL, "error", err)
|
||||
slog.Error("Failed to refresh cached releases", slogutil.URI(params.URL), slogutil.Error(err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -109,7 +110,7 @@ func server(params *cli) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("listen: %w", err)
|
||||
}
|
||||
slog.Info("Main listener started", "addr", params.Listen)
|
||||
slog.Info("Main listener started", slogutil.Address(params.Listen))
|
||||
|
||||
return srv.Serve(srvListener)
|
||||
}
|
||||
@@ -137,7 +138,7 @@ func (p *githubReleases) serveReleases(w http.ResponseWriter, req *http.Request)
|
||||
osv := req.Header.Get("Syncthing-Os-Version")
|
||||
if ua != "" && osv != "" {
|
||||
// We should determine the compatibility of the releases.
|
||||
rels = filterForCompabitility(rels, ua, osv)
|
||||
rels = filterForCompatibility(rels, ua, osv)
|
||||
} else {
|
||||
metricFilterCalls.WithLabelValues("no-ua-or-osversion").Inc()
|
||||
}
|
||||
@@ -201,17 +202,21 @@ func (p *proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// looking for a prerelease at all.
|
||||
func filterForLatest(rels []upgrade.Release) []upgrade.Release {
|
||||
var filtered []upgrade.Release
|
||||
var havePre bool
|
||||
havePre := make(map[string]bool)
|
||||
haveStable := make(map[string]bool)
|
||||
for _, rel := range rels {
|
||||
if !rel.Prerelease {
|
||||
// We found a stable version, we're good now.
|
||||
major, _, _ := strings.Cut(rel.Tag, ".")
|
||||
if !rel.Prerelease && !haveStable[major] {
|
||||
// Remember the first non-pre for each major
|
||||
filtered = append(filtered, rel)
|
||||
break
|
||||
haveStable[major] = true
|
||||
continue
|
||||
}
|
||||
if rel.Prerelease && !havePre {
|
||||
// We remember the first prerelease we find.
|
||||
if rel.Prerelease && !havePre[major] && !haveStable[major] {
|
||||
// We remember the first prerelease we find, unless we've
|
||||
// already found a non-pre of the same major.
|
||||
filtered = append(filtered, rel)
|
||||
havePre = true
|
||||
havePre[major] = true
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
@@ -219,7 +224,7 @@ func filterForLatest(rels []upgrade.Release) []upgrade.Release {
|
||||
|
||||
var userAgentOSArchExp = regexp.MustCompile(`^syncthing.*\(.+ (\w+)-(\w+)\)$`)
|
||||
|
||||
func filterForCompabitility(rels []upgrade.Release, ua, osv string) []upgrade.Release {
|
||||
func filterForCompatibility(rels []upgrade.Release, ua, osv string) []upgrade.Release {
|
||||
osArch := userAgentOSArchExp.FindStringSubmatch(ua)
|
||||
if len(osArch) != 3 {
|
||||
metricFilterCalls.WithLabelValues("bad-os-arch").Inc()
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/syncthing/syncthing/internal/blob"
|
||||
"github.com/syncthing/syncthing/internal/blob/azureblob"
|
||||
"github.com/syncthing/syncthing/internal/blob/s3"
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
"github.com/syncthing/syncthing/lib/geoip"
|
||||
"github.com/syncthing/syncthing/lib/ur/contract"
|
||||
@@ -104,23 +105,23 @@ func (cli *CLI) Run() error {
|
||||
|
||||
urListener, err := net.Listen("tcp", cli.Listen)
|
||||
if err != nil {
|
||||
slog.Error("Failed to listen (usage reports)", "error", err)
|
||||
slog.Error("Failed to listen (usage reports)", slogutil.Error(err))
|
||||
return err
|
||||
}
|
||||
slog.Info("Listening (usage reports)", "address", urListener.Addr())
|
||||
slog.Info("Listening (usage reports)", slogutil.Address(urListener.Addr()))
|
||||
|
||||
internalListener, err := net.Listen("tcp", cli.ListenInternal)
|
||||
if err != nil {
|
||||
slog.Error("Failed to listen (internal)", "error", err)
|
||||
slog.Error("Failed to listen (internal)", slogutil.Error(err))
|
||||
return err
|
||||
}
|
||||
slog.Info("Listening (internal)", "address", internalListener.Addr())
|
||||
slog.Info("Listening (internal)", slogutil.Address(internalListener.Addr()))
|
||||
|
||||
var geo *geoip.Provider
|
||||
if cli.GeoIPAccountID != 0 && cli.GeoIPLicenseKey != "" {
|
||||
geo, err = geoip.NewGeoLite2CityProvider(context.Background(), cli.GeoIPAccountID, cli.GeoIPLicenseKey, os.TempDir())
|
||||
if err != nil {
|
||||
slog.Error("Failed to load GeoIP", "error", err)
|
||||
slog.Error("Failed to load GeoIP", slogutil.Error(err))
|
||||
return err
|
||||
}
|
||||
go geo.Serve(context.TODO())
|
||||
@@ -132,20 +133,20 @@ func (cli *CLI) Run() error {
|
||||
if cli.S3Endpoint != "" {
|
||||
blobs, err = s3.NewSession(cli.S3Endpoint, cli.S3Region, cli.S3Bucket, cli.S3AccessKeyID, cli.S3SecretKey)
|
||||
if err != nil {
|
||||
slog.Error("Failed to create S3 session", "error", err)
|
||||
slog.Error("Failed to create S3 session", slogutil.Error(err))
|
||||
return err
|
||||
}
|
||||
} else if cli.AzureBlobAccount != "" {
|
||||
blobs, err = azureblob.NewBlobStore(cli.AzureBlobAccount, cli.AzureBlobKey, cli.AzureBlobContainer)
|
||||
if err != nil {
|
||||
slog.Error("Failed to create Azure blob store", "error", err)
|
||||
slog.Error("Failed to create Azure blob store", slogutil.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Stat(cli.DumpFile); err != nil && blobs != nil {
|
||||
if err := cli.downloadDumpFile(blobs); err != nil {
|
||||
slog.Error("Failed to download dump file", "error", err)
|
||||
slog.Error("Failed to download dump file", slogutil.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +168,7 @@ func (cli *CLI) Run() error {
|
||||
go func() {
|
||||
for range time.Tick(cli.DumpInterval) {
|
||||
if err := cli.saveDumpFile(srv, blobs); err != nil {
|
||||
slog.Error("Failed to write dump file", "error", err)
|
||||
slog.Error("Failed to write dump file", slogutil.Error(err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -307,7 +308,7 @@ func (s *server) handleNewData(w http.ResponseWriter, r *http.Request) {
|
||||
lr := &io.LimitedReader{R: r.Body, N: 40 * 1024}
|
||||
bs, _ := io.ReadAll(lr)
|
||||
if err := json.Unmarshal(bs, &rep); err != nil {
|
||||
log.Error("Failed to decode JSON", "error", err)
|
||||
log.Error("Failed to decode JSON", slogutil.Error(err))
|
||||
http.Error(w, "JSON Decode Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -317,7 +318,7 @@ func (s *server) handleNewData(w http.ResponseWriter, r *http.Request) {
|
||||
rep.Address = addr
|
||||
|
||||
if err := rep.Validate(); err != nil {
|
||||
log.Error("Failed to validate report", "error", err)
|
||||
log.Error("Failed to validate report", slogutil.Error(err))
|
||||
http.Error(w, "Validation Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -394,7 +395,7 @@ func (s *server) load(r io.Reader) {
|
||||
if err := dec.Decode(&rep); errors.Is(err, io.EOF) {
|
||||
break
|
||||
} else if err != nil {
|
||||
slog.Error("Failed to load record", "error", err)
|
||||
slog.Error("Failed to load record", slogutil.Error(err))
|
||||
break
|
||||
}
|
||||
s.addReport(&rep)
|
||||
|
||||
@@ -115,7 +115,7 @@ func BenchmarkAPIRequests(b *testing.B) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(api.handler))
|
||||
|
||||
kf := b.TempDir() + "/cert"
|
||||
crt, err := tlsutil.NewCertificate(kf+".crt", kf+".key", "localhost", 7)
|
||||
crt, err := tlsutil.NewCertificate(kf+".crt", kf+".key", "localhost", 7, true)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func main() {
|
||||
cert, err = tls.LoadX509KeyPair(cli.Cert, cli.Key)
|
||||
if os.IsNotExist(err) {
|
||||
log.Println("Failed to load keypair. Generating one, this might take a while...")
|
||||
cert, err = tlsutil.NewCertificate(cli.Cert, cli.Key, "stdiscosrv", 20*365)
|
||||
cert, err = tlsutil.NewCertificate(cli.Cert, cli.Key, "stdiscosrv", 20*365, false)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to generate X509 key pair:", err)
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ func main() {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
log.Println("Failed to load keypair. Generating one, this might take a while...")
|
||||
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv", 20*365)
|
||||
cert, err = tlsutil.NewCertificate(certFile, keyFile, "strelaysrv", 20*365, false)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to generate X509 key pair:", err)
|
||||
}
|
||||
|
||||
@@ -8,11 +8,14 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
)
|
||||
|
||||
func startBlockProfiler() {
|
||||
@@ -20,10 +23,10 @@ func startBlockProfiler() {
|
||||
if profiler == nil {
|
||||
panic("Couldn't find block profiler")
|
||||
}
|
||||
l.Debugln("Starting block profiling")
|
||||
slog.Debug("Starting block profiling")
|
||||
go func() {
|
||||
err := saveBlockingProfiles(profiler) // Only returns on error
|
||||
l.Warnln("Block profiler failed:", err)
|
||||
slog.Error("Block profiler failed", slogutil.Error(err))
|
||||
panic("Block profiler failed")
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -131,15 +131,6 @@ func prettyPrintResponse(response *http.Response) error {
|
||||
return prettyPrintJSON(data)
|
||||
}
|
||||
|
||||
func nulString(bs []byte) string {
|
||||
for i := range bs {
|
||||
if bs[i] == 0 {
|
||||
return string(bs[:i])
|
||||
}
|
||||
}
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
func normalizePath(path string) string {
|
||||
return filepath.ToSlash(filepath.Clean(path))
|
||||
}
|
||||
|
||||
@@ -11,12 +11,15 @@ import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -33,7 +36,7 @@ const (
|
||||
func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
|
||||
files, err := filepath.Glob(filepath.Join(dir, "panic-*.log"))
|
||||
if err != nil {
|
||||
l.Warnln("Failed to list panic logs:", err)
|
||||
slog.ErrorContext(ctx, "Failed to list panic logs", slogutil.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -48,7 +51,7 @@ func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
|
||||
}
|
||||
|
||||
if err := uploadPanicLog(ctx, urlBase, file); err != nil {
|
||||
l.Warnln("Reporting crash:", err)
|
||||
slog.ErrorContext(ctx, "Reporting crash", slogutil.Error(err))
|
||||
} else {
|
||||
// Rename the log so we don't have to try to report it again. This
|
||||
// succeeds, or it does not. There is no point complaining about it.
|
||||
@@ -71,7 +74,7 @@ func uploadPanicLog(ctx context.Context, urlBase, file string) error {
|
||||
data = filterLogLines(data)
|
||||
|
||||
hash := fmt.Sprintf("%x", sha256.Sum256(data))
|
||||
l.Infof("Reporting crash found in %s (report ID %s) ...\n", filepath.Base(file), hash[:8])
|
||||
slog.InfoContext(ctx, "Reporting crash", slogutil.FilePath(filepath.Base(file)), slog.String("id", hash[:8]))
|
||||
|
||||
url := fmt.Sprintf("%s/%s", urlBase, hash)
|
||||
headReq, err := http.NewRequest(http.MethodHead, url, nil)
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
import "github.com/syncthing/syncthing/internal/slogutil"
|
||||
|
||||
var l = logger.DefaultLogger.NewFacility("main", "Main package")
|
||||
func init() { slogutil.RegisterPackage("Main package") }
|
||||
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/locations"
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/syncthing"
|
||||
)
|
||||
@@ -29,7 +29,7 @@ type CLI struct {
|
||||
NoPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup" env:"STNOPORTPROBING"`
|
||||
}
|
||||
|
||||
func (c *CLI) Run(l logger.Logger) error {
|
||||
func (c *CLI) Run() error {
|
||||
// Support reading the password from a pipe or similar
|
||||
if c.GUIPassword == "-" {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
@@ -40,13 +40,13 @@ func (c *CLI) Run(l logger.Logger) error {
|
||||
c.GUIPassword = string(password)
|
||||
}
|
||||
|
||||
if err := Generate(l, locations.GetBaseDir(locations.ConfigBaseDir), c.GUIUser, c.GUIPassword, c.NoPortProbing); err != nil {
|
||||
if err := Generate(locations.GetBaseDir(locations.ConfigBaseDir), c.GUIUser, c.GUIPassword, c.NoPortProbing); err != nil {
|
||||
return fmt.Errorf("failed to generate config and keys: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Generate(l logger.Logger, confDir, guiUser, guiPassword string, skipPortProbing bool) error {
|
||||
func Generate(confDir, guiUser, guiPassword string, skipPortProbing bool) error {
|
||||
dir, err := fs.ExpandTilde(confDir)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -61,15 +61,16 @@ func Generate(l logger.Logger, confDir, guiUser, guiPassword string, skipPortPro
|
||||
certFile, keyFile := locations.Get(locations.CertFile), locations.Get(locations.KeyFile)
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err == nil {
|
||||
l.Warnln("Key exists; will not overwrite.")
|
||||
slog.Warn("Key exists; will not overwrite")
|
||||
} else {
|
||||
cert, err = syncthing.GenerateCertificate(certFile, keyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create certificate: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
myID = protocol.NewDeviceID(cert.Certificate[0])
|
||||
l.Infoln("Device ID:", myID)
|
||||
slog.Info("Calculated device ID", slog.String("device", myID.String()))
|
||||
|
||||
cfgFile := locations.Get(locations.ConfigFile)
|
||||
cfg, _, err := config.Load(cfgFile, myID, events.NoopLogger)
|
||||
@@ -87,7 +88,7 @@ func Generate(l logger.Logger, confDir, guiUser, guiPassword string, skipPortPro
|
||||
|
||||
var updateErr error
|
||||
waiter, err := cfg.Modify(func(cfg *config.Configuration) {
|
||||
updateErr = updateGUIAuthentication(l, &cfg.GUI, guiUser, guiPassword)
|
||||
updateErr = updateGUIAuthentication(&cfg.GUI, guiUser, guiPassword)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("modify config: %w", err)
|
||||
@@ -103,17 +104,17 @@ func Generate(l logger.Logger, confDir, guiUser, guiPassword string, skipPortPro
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateGUIAuthentication(l logger.Logger, guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
|
||||
func updateGUIAuthentication(guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
|
||||
if guiUser != "" && guiCfg.User != guiUser {
|
||||
guiCfg.User = guiUser
|
||||
l.Infoln("Updated GUI authentication user name:", guiUser)
|
||||
slog.Info("Updated GUI authentication user", "name", guiUser)
|
||||
}
|
||||
|
||||
if guiPassword != "" && guiCfg.Password != guiPassword {
|
||||
if err := guiCfg.SetPassword(guiPassword); err != nil {
|
||||
return fmt.Errorf("failed to set GUI authentication password: %w", err)
|
||||
}
|
||||
l.Infoln("Updated GUI authentication password.")
|
||||
slog.Info("Updated GUI authentication password")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,18 +8,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
)
|
||||
|
||||
func startHeapProfiler() {
|
||||
l.Debugln("Starting heap profiling")
|
||||
slog.Debug("Starting heap profiling")
|
||||
go func() {
|
||||
err := saveHeapProfiles(1) // Only returns on error
|
||||
l.Warnln("Heap profiler failed:", err)
|
||||
slog.Error("Heap profiler failed", slogutil.Error(err))
|
||||
panic("Heap profiler failed")
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"net/http"
|
||||
_ "net/http/pprof" // Need to import this to support STPROFILER.
|
||||
"net/url"
|
||||
@@ -40,6 +41,7 @@ import (
|
||||
"github.com/syncthing/syncthing/cmd/syncthing/generate"
|
||||
"github.com/syncthing/syncthing/internal/db"
|
||||
"github.com/syncthing/syncthing/internal/db/sqlite"
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
_ "github.com/syncthing/syncthing/lib/automaxprocs"
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
@@ -47,7 +49,6 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/locations"
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
@@ -61,20 +62,8 @@ const (
|
||||
|
||||
const (
|
||||
extraUsage = `
|
||||
The --logflags value is a sum of the following:
|
||||
|
||||
1 Date
|
||||
2 Time
|
||||
4 Microsecond time
|
||||
8 Long filename
|
||||
16 Short filename
|
||||
|
||||
I.e. to prefix each log line with time and filename, set --logflags=18 (2 + 16
|
||||
from above). The value 0 is used to disable all of the above. The default is
|
||||
to show date and time (3).
|
||||
|
||||
Logging always happens to the command line (stdout) and optionally to the
|
||||
file at the path specified by --logfile=path. In addition to an path, the special
|
||||
file at the path specified by --log-file=path. In addition to an path, the special
|
||||
values "default" and "-" may be used. The former logs to DATADIR/syncthing.log
|
||||
(see --data), which is the default on Windows, and the latter only to stdout,
|
||||
no file, which is the default anywhere else.
|
||||
@@ -87,11 +76,10 @@ The following environment variables modify Syncthing's behavior in ways that
|
||||
are mostly useful for developers. Use with care. See also the --debug-* options
|
||||
above.
|
||||
|
||||
STTRACE A comma separated string of facilities to trace. The valid
|
||||
facility strings are listed below.
|
||||
|
||||
STLOCKTHRESHOLD Used for debugging internal deadlocks; sets debug
|
||||
sensitivity. Use only under direction of a developer.
|
||||
STTRACE A comma separated string of packages to trace or change log
|
||||
level for. The valid package strings are listed below. A log
|
||||
level (DEBUG, INFO, WARN or ERROR) can be added after each
|
||||
package, separated by a colon. Ex: "model:WARN,nat:DEBUG".
|
||||
|
||||
STVERSIONEXTRA Add extra information to the version string in logs and the
|
||||
version line in the GUI. Can be set to the name of a wrapper
|
||||
@@ -106,8 +94,8 @@ above.
|
||||
of CPU usage (i.e. performance).
|
||||
|
||||
|
||||
Debugging Facilities
|
||||
--------------------
|
||||
Logging Facilities
|
||||
------------------
|
||||
|
||||
The following are valid values for the STTRACE variable:
|
||||
|
||||
@@ -167,11 +155,12 @@ type serveCmd struct {
|
||||
Audit bool `help:"Write events to audit file" env:"STAUDIT"`
|
||||
AuditFile string `name:"auditfile" help:"Specify audit file (use \"-\" for stdout, \"--\" for stderr)" placeholder:"PATH" env:"STAUDITFILE"`
|
||||
DBMaintenanceInterval time.Duration `help:"Database maintenance interval" default:"8h" env:"STDBMAINTENANCEINTERVAL"`
|
||||
DBDeleteRetentionInterval time.Duration `help:"Database deleted item retention interval" default:"4320h" env:"STDBDELETERETENTIONINTERVAL"`
|
||||
DBDeleteRetentionInterval time.Duration `help:"Database deleted item retention interval" default:"10920h" env:"STDBDELETERETENTIONINTERVAL"`
|
||||
GUIAddress string `name:"gui-address" help:"Override GUI address (e.g. \"http://192.0.2.42:8443\")" placeholder:"URL" env:"STGUIADDRESS"`
|
||||
GUIAPIKey string `name:"gui-apikey" help:"Override GUI API key" placeholder:"API-KEY" env:"STGUIAPIKEY"`
|
||||
LogFile string `name:"logfile" help:"Log file name (see below)" default:"${logFile}" placeholder:"PATH" env:"STLOGFILE"`
|
||||
LogFlags int `name:"logflags" help:"Select information in log line prefix (see below)" default:"${logFlags}" placeholder:"BITS" env:"STLOGFLAGS"`
|
||||
LogFile string `name:"log-file" aliases:"logfile" help:"Log file name (see below)" default:"${logFile}" placeholder:"PATH" env:"STLOGFILE"`
|
||||
LogFlags int `name:"logflags" help:"Deprecated option that does nothing, kept for compatibility" hidden:""`
|
||||
LogLevel slog.Level `help:"Log level for all packages (DEBUG,INFO,WARN,ERROR)" env:"STLOGLEVEL" default:"INFO"`
|
||||
LogMaxFiles int `name:"log-max-old-files" help:"Number of old files to keep (zero to keep only current)" default:"${logMaxFiles}" placeholder:"N" env:"STLOGMAXOLDFILES"`
|
||||
LogMaxSize int `help:"Maximum size of any file (zero to disable log rotation)" default:"${logMaxSize}" placeholder:"BYTES" env:"STLOGMAXSIZE"`
|
||||
NoBrowser bool `help:"Do not start browser" env:"STNOBROWSER"`
|
||||
@@ -180,7 +169,6 @@ type serveCmd struct {
|
||||
NoUpgrade bool `help:"Disable automatic upgrades" env:"STNOUPGRADE"`
|
||||
Paused bool `help:"Start with all devices and folders paused" env:"STPAUSED"`
|
||||
Unpaused bool `help:"Start with all devices and folders unpaused" env:"STUNPAUSED"`
|
||||
Verbose bool `help:"Print verbose log output" env:"STVERBOSE"`
|
||||
|
||||
// Debug options below
|
||||
DebugGUIAssetsDir string `help:"Directory to load GUI assets from" placeholder:"PATH" env:"STGUIASSETS"`
|
||||
@@ -199,14 +187,9 @@ type serveCmd struct {
|
||||
func defaultVars() kong.Vars {
|
||||
vars := kong.Vars{}
|
||||
|
||||
vars["logFlags"] = strconv.Itoa(logger.DefaultFlags)
|
||||
vars["logMaxSize"] = strconv.Itoa(10 << 20) // 10 MiB
|
||||
vars["logMaxFiles"] = "3" // plus the current one
|
||||
|
||||
if os.Getenv("STTRACE") != "" {
|
||||
vars["logFlags"] = strconv.Itoa(logger.DebugFlags)
|
||||
}
|
||||
|
||||
// On non-Windows, we explicitly default to "-" which means stdout. On
|
||||
// Windows, the "default" options.logFile will later be replaced with the
|
||||
// default path, unless the user has manually specified "-" or
|
||||
@@ -234,13 +217,13 @@ func main() {
|
||||
defaultVars(),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
slog.Error("Parsing startup", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
kongplete.Complete(parser)
|
||||
ctx, err := parser.Parse(os.Args[1:])
|
||||
parser.FatalIfErrorf(err)
|
||||
ctx.BindTo(l, (*logger.Logger)(nil)) // main logger available to subcommands
|
||||
err = ctx.Run()
|
||||
parser.FatalIfErrorf(err)
|
||||
}
|
||||
@@ -252,15 +235,13 @@ func helpHandler(options kong.HelpOptions, ctx *kong.Context) error {
|
||||
if ctx.Command() == "serve" {
|
||||
// Help was requested for `syncthing serve`, so we add our extra
|
||||
// usage info afte the normal options output.
|
||||
fmt.Printf(extraUsage, debugFacilities())
|
||||
fmt.Printf(extraUsage, logPackages())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// serveCmd.Run() is the entrypoint for `syncthing serve`
|
||||
func (c *serveCmd) Run() error {
|
||||
l.SetFlags(c.LogFlags)
|
||||
|
||||
if c.GUIAddress != "" {
|
||||
// The config picks this up from the environment.
|
||||
os.Setenv("STGUIADDRESS", c.GUIAddress)
|
||||
@@ -274,6 +255,9 @@ func (c *serveCmd) Run() error {
|
||||
osutil.HideConsole()
|
||||
}
|
||||
|
||||
// The default log level for all packages
|
||||
slogutil.SetDefaultLevel(c.LogLevel)
|
||||
|
||||
// Treat an explicitly empty log file name as no log file
|
||||
if c.LogFile == "" {
|
||||
c.LogFile = "-"
|
||||
@@ -281,7 +265,7 @@ func (c *serveCmd) Run() error {
|
||||
if c.LogFile != "default" {
|
||||
// We must set this *after* expandLocations above.
|
||||
if err := locations.Set(locations.LogFile, c.LogFile); err != nil {
|
||||
l.Warnln("Setting log file path:", err)
|
||||
slog.Error("Failed to set log file path", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
}
|
||||
@@ -290,7 +274,7 @@ func (c *serveCmd) Run() error {
|
||||
// The asset dir is blank if STGUIASSETS wasn't set, in which case we
|
||||
// should look for extra assets in the default place.
|
||||
if err := locations.Set(locations.GUIAssets, c.DebugGUIAssetsDir); err != nil {
|
||||
l.Warnln("Setting GUI assets path:", err)
|
||||
slog.Error("Failed to set GUI assets path", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
}
|
||||
@@ -298,7 +282,7 @@ func (c *serveCmd) Run() error {
|
||||
// Ensure that our config and data directories exist.
|
||||
for _, loc := range []locations.BaseDirEnum{locations.ConfigBaseDir, locations.DataBaseDir} {
|
||||
if err := syncthing.EnsureDir(locations.GetBaseDir(loc), 0o700); err != nil {
|
||||
l.Warnln("Failed to ensure directory exists:", err)
|
||||
slog.Error("Failed to ensure directory exists", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
}
|
||||
@@ -321,29 +305,27 @@ func openGUI() error {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
l.Warnln("Browser: GUI is currently disabled")
|
||||
slog.Error("Browser: GUI is currently disabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func debugFacilities() string {
|
||||
facilities := l.Facilities()
|
||||
func logPackages() string {
|
||||
packages := slogutil.PackageDescrs()
|
||||
|
||||
// Get a sorted list of names
|
||||
var names []string
|
||||
names := slices.Sorted(maps.Keys(packages))
|
||||
maxLen := 0
|
||||
for name := range facilities {
|
||||
names = append(names, name)
|
||||
for _, name := range names {
|
||||
if len(name) > maxLen {
|
||||
maxLen = len(name)
|
||||
}
|
||||
}
|
||||
slices.Sort(names)
|
||||
|
||||
// Format the choices
|
||||
b := new(bytes.Buffer)
|
||||
for _, name := range names {
|
||||
fmt.Fprintf(b, " %-*s - %s\n", maxLen, name, facilities[name])
|
||||
fmt.Fprintf(b, " %-*s - %s\n", maxLen, name, packages[name])
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
@@ -371,7 +353,7 @@ func checkUpgrade() (upgrade.Release, error) {
|
||||
return upgrade.Release{}, &errNoUpgrade{build.Version, release.Tag}
|
||||
}
|
||||
|
||||
l.Infof("Upgrade available (current %q < latest %q)", build.Version, release.Tag)
|
||||
slog.Info("Upgrade available", "current", build.Version, "latest", release.Tag)
|
||||
return release, nil
|
||||
}
|
||||
|
||||
@@ -403,9 +385,11 @@ func upgradeViaRest() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -426,13 +410,9 @@ func (c *serveCmd) syncthingMain() {
|
||||
startPerfStats()
|
||||
}
|
||||
|
||||
// Set a log prefix similar to the ID we will have later on, or early log
|
||||
// lines look ugly.
|
||||
l.SetPrefix("[start] ")
|
||||
|
||||
// Print our version information up front, so any crash that happens
|
||||
// early etc. will have it available.
|
||||
l.Infoln(build.LongVersion)
|
||||
slog.Info(build.LongVersion) //nolint:sloglint
|
||||
|
||||
// Ensure that we have a certificate and key.
|
||||
cert, err := syncthing.LoadOrGenerateCertificate(
|
||||
@@ -440,7 +420,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
locations.Get(locations.KeyFile),
|
||||
)
|
||||
if err != nil {
|
||||
l.Warnln("Failed to load/generate certificate:", err)
|
||||
slog.Error("Failed to load/generate certificate", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -448,10 +428,10 @@ func (c *serveCmd) syncthingMain() {
|
||||
lf := flock.New(locations.Get(locations.LockFile))
|
||||
locked, err := lf.TryLock()
|
||||
if err != nil {
|
||||
l.Warnln("Failed to acquire lock:", err)
|
||||
slog.Error("Failed to acquire lock", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
} else if !locked {
|
||||
l.Warnln("Failed to acquire lock: is another Syncthing instance already running?")
|
||||
slog.Error("Failed to acquire lock: is another Syncthing instance already running?")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -460,7 +440,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
|
||||
// earlyService is a supervisor that runs the services needed for or
|
||||
// before app startup; the event logger, and the config service.
|
||||
spec := svcutil.SpecWithDebugLogger(l)
|
||||
spec := svcutil.SpecWithDebugLogger()
|
||||
earlyService := suture.New("early", spec)
|
||||
earlyService.ServeBackground(ctx)
|
||||
|
||||
@@ -469,7 +449,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
|
||||
cfgWrapper, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, c.AllowNewerConfig, c.NoPortProbing)
|
||||
if err != nil {
|
||||
l.Warnln("Failed to initialize config:", err)
|
||||
slog.Error("Failed to initialize config", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
earlyService.Add(cfgWrapper)
|
||||
@@ -481,7 +461,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
|
||||
if build.IsCandidate && !upgrade.DisabledByCompilation && !c.NoUpgrade {
|
||||
cfgWrapper.Modify(func(cfg *config.Configuration) {
|
||||
l.Infoln("Automatic upgrade is always enabled for candidate releases.")
|
||||
slog.Info("Automatic upgrade is always enabled for candidate releases")
|
||||
if cfg.Options.AutoUpgradeIntervalH == 0 || cfg.Options.AutoUpgradeIntervalH > 24 {
|
||||
cfg.Options.AutoUpgradeIntervalH = 12
|
||||
// Set the option into the config as well, as the auto upgrade
|
||||
@@ -493,13 +473,13 @@ func (c *serveCmd) syncthingMain() {
|
||||
}
|
||||
|
||||
if err := syncthing.TryMigrateDatabase(c.DBDeleteRetentionInterval); err != nil {
|
||||
l.Warnln("Failed to migrate old-style database:", err)
|
||||
slog.Error("Failed to migrate old-style database", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
sdb, err := syncthing.OpenDatabase(locations.Get(locations.Database), c.DBDeleteRetentionInterval)
|
||||
if err != nil {
|
||||
l.Warnln("Error opening database:", err)
|
||||
slog.Error("Error opening database", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -516,12 +496,12 @@ func (c *serveCmd) syncthingMain() {
|
||||
}
|
||||
if err != nil {
|
||||
if _, ok := err.(*errNoUpgrade); ok || err == errTooEarlyUpgradeCheck || err == errTooEarlyUpgrade {
|
||||
l.Debugln("Initial automatic upgrade:", err)
|
||||
slog.Debug("Initial automatic upgrade", slogutil.Error(err))
|
||||
} else {
|
||||
l.Infoln("Initial automatic upgrade:", err)
|
||||
slog.Info("Initial automatic upgrade", slogutil.Error(err))
|
||||
}
|
||||
} else {
|
||||
l.Infof("Upgraded to %q, should exit now.", release.Tag)
|
||||
slog.Info("Upgraded, should exit now", "newVersion", release.Tag)
|
||||
os.Exit(svcutil.ExitUpgrade.AsInt())
|
||||
}
|
||||
}
|
||||
@@ -536,18 +516,17 @@ func (c *serveCmd) syncthingMain() {
|
||||
NoUpgrade: c.NoUpgrade,
|
||||
ProfilerAddr: c.DebugProfilerListen,
|
||||
ResetDeltaIdxs: c.DebugResetDeltaIdxs,
|
||||
Verbose: c.Verbose,
|
||||
DBMaintenanceInterval: c.DBMaintenanceInterval,
|
||||
}
|
||||
|
||||
if c.Audit || cfgWrapper.Options().AuditEnabled {
|
||||
l.Infoln("Auditing is enabled.")
|
||||
slog.Info("Auditing is enabled")
|
||||
|
||||
auditFile := cfgWrapper.Options().AuditFile
|
||||
|
||||
// Ignore config option if command-line option is set
|
||||
if c.AuditFile != "" {
|
||||
l.Debugln("Using the audit file from the command-line parameter.")
|
||||
slog.Debug("Using the audit file from the command-line parameter", slogutil.FilePath(c.AuditFile))
|
||||
auditFile = c.AuditFile
|
||||
}
|
||||
|
||||
@@ -556,7 +535,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
|
||||
app, err := syncthing.New(cfgWrapper, sdb, evLogger, cert, appOpts)
|
||||
if err != nil {
|
||||
l.Warnln("Failed to start Syncthing:", err)
|
||||
slog.Error("Failed to start Syncthing", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
@@ -569,11 +548,11 @@ func (c *serveCmd) syncthingMain() {
|
||||
if c.DebugProfileCPU {
|
||||
f, err := os.Create(fmt.Sprintf("cpu-%d.pprof", os.Getpid()))
|
||||
if err != nil {
|
||||
l.Warnln("Creating profile:", err)
|
||||
slog.Error("Failed to create profile", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
l.Warnln("Starting profile:", err)
|
||||
slog.Error("Failed to start profile", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
}
|
||||
@@ -593,7 +572,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
status := app.Wait()
|
||||
|
||||
if status == svcutil.ExitError {
|
||||
l.Warnln("Syncthing stopped with error:", app.Error())
|
||||
slog.Error("Syncthing stopped with error", slogutil.Error(app.Error()))
|
||||
}
|
||||
|
||||
if c.DebugProfileCPU {
|
||||
@@ -611,8 +590,7 @@ func setupSignalHandling(app *syncthing.App) {
|
||||
// Exit cleanly with "restarting" code on SIGHUP.
|
||||
|
||||
restartSign := make(chan os.Signal, 1)
|
||||
sigHup := syscall.Signal(1)
|
||||
signal.Notify(restartSign, sigHup)
|
||||
signal.Notify(restartSign, syscall.SIGHUP)
|
||||
go func() {
|
||||
<-restartSign
|
||||
app.Stop(svcutil.ExitRestart)
|
||||
@@ -662,13 +640,13 @@ func auditWriter(auditFile string) io.Writer {
|
||||
}
|
||||
fd, err = os.OpenFile(auditFile, auditFlags, 0o600)
|
||||
if err != nil {
|
||||
l.Warnln("Audit:", err)
|
||||
slog.Error("Failed to open audit file", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
auditDest = auditFile
|
||||
}
|
||||
|
||||
l.Infoln("Audit log in", auditDest)
|
||||
slog.Info("Writing audit log", slogutil.FilePath(auditDest))
|
||||
|
||||
return fd
|
||||
}
|
||||
@@ -678,7 +656,7 @@ func (c *serveCmd) autoUpgradePossible() bool {
|
||||
return false
|
||||
}
|
||||
if c.NoUpgrade {
|
||||
l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.")
|
||||
slog.Info("No automatic upgrades; STNOUPGRADE environment variable defined")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -695,7 +673,7 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger)
|
||||
continue
|
||||
}
|
||||
if cfg.Options().AutoUpgradeEnabled() {
|
||||
l.Infof("Connected to device %s with a newer version (current %q < remote %q). Checking for upgrades.", data["id"], build.Version, data["clientVersion"])
|
||||
slog.Info("Connected to device with a newer version; checking for upgrades", slog.String("device", data["id"]), slog.String("ourVersion", build.Version), slog.String("theirVersion", data["clientVersion"]))
|
||||
}
|
||||
case <-timer.C:
|
||||
}
|
||||
@@ -715,7 +693,7 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger)
|
||||
if err != nil {
|
||||
// Don't complain too loudly here; we might simply not have
|
||||
// internet connectivity, or the upgrade server might be down.
|
||||
l.Infoln("Automatic upgrade:", err)
|
||||
slog.Info("Automatic upgrade", slogutil.Error(err))
|
||||
timer.Reset(checkInterval)
|
||||
continue
|
||||
}
|
||||
@@ -726,15 +704,15 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger)
|
||||
continue
|
||||
}
|
||||
|
||||
l.Infof("Automatic upgrade (current %q < latest %q)", build.Version, rel.Tag)
|
||||
slog.Info("Automatic upgrade", "current", build.Version, "latest", rel.Tag)
|
||||
err = upgrade.To(rel)
|
||||
if err != nil {
|
||||
l.Warnln("Automatic upgrade:", err)
|
||||
slog.Error("Automatic upgrade failed", slogutil.Error(err))
|
||||
timer.Reset(checkInterval)
|
||||
continue
|
||||
}
|
||||
sub.Unsubscribe()
|
||||
l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
|
||||
slog.Error("Automatically upgraded, restarting in 1 minute", slog.String("newVersion", rel.Tag))
|
||||
time.Sleep(time.Minute)
|
||||
app.Stop(svcutil.ExitUpgrade)
|
||||
return
|
||||
@@ -787,22 +765,22 @@ func cleanConfigDirectory() {
|
||||
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, locations.GetBaseDir(locations.ConfigBaseDir))
|
||||
files, err := fs.Glob(pat)
|
||||
if err != nil {
|
||||
l.Infoln("Cleaning:", err)
|
||||
slog.Warn("Failed to clean config directory", slogutil.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
info, err := fs.Lstat(file)
|
||||
if err != nil {
|
||||
l.Infoln("Cleaning:", err)
|
||||
slog.Warn("Failed to clean config directory", slogutil.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
if time.Since(info.ModTime()) > dur {
|
||||
if err = fs.RemoveAll(file); err != nil {
|
||||
l.Infoln("Cleaning:", err)
|
||||
slog.Warn("Failed to clean config directory", slogutil.Error(err))
|
||||
} else {
|
||||
l.Infoln("Cleaned away old file", filepath.Base(file))
|
||||
slog.Warn("Cleaned away old file", slogutil.FilePath(filepath.Base(file)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -819,7 +797,7 @@ func setPauseState(cfgWrapper config.Wrapper, paused bool) {
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
l.Warnln("Cannot adjust paused state:", err)
|
||||
slog.Error("Cannot adjust paused state", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
}
|
||||
@@ -846,7 +824,7 @@ func (deviceIDCmd) Run() error {
|
||||
locations.Get(locations.KeyFile),
|
||||
)
|
||||
if err != nil {
|
||||
l.Warnln("Error reading device ID:", err)
|
||||
slog.Error("Failed to read device ID", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
@@ -869,7 +847,7 @@ type upgradeCmd struct {
|
||||
func (u upgradeCmd) Run() error {
|
||||
if u.CheckOnly {
|
||||
if _, err := checkUpgrade(); err != nil {
|
||||
l.Warnln("Checking for upgrade:", err)
|
||||
slog.Error("Failed to check for upgrade", slogutil.Error(err))
|
||||
os.Exit(exitCodeForUpgrade(err))
|
||||
}
|
||||
return nil
|
||||
@@ -878,10 +856,10 @@ func (u upgradeCmd) Run() error {
|
||||
if u.From != "" {
|
||||
err := upgrade.ToURL(u.From)
|
||||
if err != nil {
|
||||
l.Warnln("Error while Upgrading:", err)
|
||||
slog.Error("Failed to upgrade", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
l.Infoln("Upgraded from", u.From)
|
||||
slog.Info("Upgraded", "from", u.From)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -890,20 +868,24 @@ func (u upgradeCmd) Run() error {
|
||||
lf := flock.New(locations.Get(locations.LockFile))
|
||||
var locked bool
|
||||
locked, err = lf.TryLock()
|
||||
if err != nil {
|
||||
l.Warnln("Upgrade:", err)
|
||||
// ErrNotExist is a valid error if this is a new/blank installation
|
||||
// without a config dir, in which case we can proceed with a normal
|
||||
// non-API upgrade.
|
||||
switch {
|
||||
case err != nil && !os.IsNotExist(err):
|
||||
slog.Error("Failed to lock for upgrade", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
} else if locked {
|
||||
case locked:
|
||||
err = upgradeViaRest()
|
||||
} else {
|
||||
default:
|
||||
err = upgrade.To(release)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
l.Warnln("Upgrade:", err)
|
||||
slog.Error("Failed to check for upgrade", slogutil.Error(err))
|
||||
os.Exit(exitCodeForUpgrade(err))
|
||||
}
|
||||
l.Infof("Upgraded to %q", release.Tag)
|
||||
slog.Info("Upgraded", "to", release.Tag)
|
||||
os.Exit(svcutil.ExitUpgrade.AsInt())
|
||||
return nil
|
||||
}
|
||||
@@ -912,26 +894,28 @@ type browserCmd struct{}
|
||||
|
||||
func (browserCmd) Run() error {
|
||||
if err := openGUI(); err != nil {
|
||||
l.Warnln("Failed to open web UI:", err)
|
||||
slog.Error("Failed to open web UI", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type debugCmd struct {
|
||||
ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
|
||||
DatabaseStatistics databaseStatsCmd `cmd:"" help:"Display database size statistics"`
|
||||
ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
|
||||
DatabaseStatistics databaseStatsCmd `cmd:"" help:"Display database size statistics"`
|
||||
DatabaseCounts databaseCountsCmd `cmd:"" help:"Display database folder counts"`
|
||||
DatabaseFile databaseFileCmd `cmd:"" help:"Display database file metadata"`
|
||||
}
|
||||
|
||||
type resetDatabaseCmd struct{}
|
||||
|
||||
func (resetDatabaseCmd) Run() error {
|
||||
l.Infoln("Removing database in", locations.Get(locations.Database))
|
||||
slog.Info("Removing database", slogutil.FilePath(locations.Get(locations.Database)))
|
||||
if err := os.RemoveAll(locations.Get(locations.Database)); err != nil {
|
||||
l.Warnln("Resetting database:", err)
|
||||
slog.Error("Failed to reset database", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
l.Infoln("Successfully reset database - it will be rebuilt after next start.")
|
||||
slog.Info("Reset database - it will be rebuilt after next start")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -955,6 +939,33 @@ func (c databaseStatsCmd) Run() error {
|
||||
return tw.Flush()
|
||||
}
|
||||
|
||||
type databaseCountsCmd struct {
|
||||
Folder string `arg:"" required:""`
|
||||
}
|
||||
|
||||
func (c databaseCountsCmd) Run() error {
|
||||
db, err := sqlite.Open(locations.Get(locations.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.DebugCounts(os.Stdout, c.Folder)
|
||||
}
|
||||
|
||||
type databaseFileCmd struct {
|
||||
Folder string `arg:"" required:""`
|
||||
File string `arg:"" required:""`
|
||||
}
|
||||
|
||||
func (c databaseFileCmd) Run() error {
|
||||
db, err := sqlite.Open(locations.Get(locations.Database))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.DebugFilePattern(os.Stdout, c.Folder, c.File)
|
||||
}
|
||||
|
||||
func (c databaseStatsCmd) printStat(w io.Writer, s *sqlite.DatabaseStatistics) {
|
||||
for _, table := range s.Tables {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%8d KiB\t%5.01f %%\n", s.Name, cmp.Or(s.FolderID, "-"), table.Name, table.Size/1024, float64(table.Size-table.Unused)*100/float64(table.Size))
|
||||
|
||||
@@ -11,26 +11,28 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/locations"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/svcutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
)
|
||||
|
||||
var (
|
||||
stdoutFirstLines []string // The first 10 lines of stdout
|
||||
stdoutLastLines []string // The last 50 lines of stdout
|
||||
stdoutMut = sync.NewMutex()
|
||||
stdoutMut sync.Mutex
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -44,8 +46,6 @@ const (
|
||||
)
|
||||
|
||||
func (c *serveCmd) monitorMain() {
|
||||
l.SetPrefix("[monitor] ")
|
||||
|
||||
var dst io.Writer = os.Stdout
|
||||
|
||||
logFile := locations.Get(locations.LogFile)
|
||||
@@ -64,7 +64,7 @@ func (c *serveCmd) monitorMain() {
|
||||
fileDst, err = open(logFile)
|
||||
}
|
||||
if err != nil {
|
||||
l.Warnln("Failed to set up logging to file, proceeding with logging to stdout only:", err)
|
||||
slog.Error("Failed to set up logging to file, proceeding with logging to stdout only", slogutil.Error(err))
|
||||
} else {
|
||||
if build.IsWindows {
|
||||
// Translate line breaks to Windows standard
|
||||
@@ -78,14 +78,14 @@ func (c *serveCmd) monitorMain() {
|
||||
// Log to both stdout and file.
|
||||
dst = io.MultiWriter(dst, fileDst)
|
||||
|
||||
l.Infof(`Log output saved to file "%s"`, logFile)
|
||||
slog.Info("Saved log output", slogutil.FilePath(logFile))
|
||||
}
|
||||
}
|
||||
|
||||
args := os.Args
|
||||
binary, err := getBinary(args[0])
|
||||
if err != nil {
|
||||
l.Warnln("Error starting the main Syncthing process:", err)
|
||||
slog.Error("Failed to start the main Syncthing process", slogutil.Error(err))
|
||||
panic("Error starting the main Syncthing process")
|
||||
}
|
||||
var restarts [restartCounts]time.Time
|
||||
@@ -102,7 +102,7 @@ func (c *serveCmd) monitorMain() {
|
||||
maybeReportPanics()
|
||||
|
||||
if t := time.Since(restarts[0]); t < restartLoopThreshold {
|
||||
l.Warnf("%d restarts in %v; not retrying further", restartCounts, t)
|
||||
slog.Error("Too many restarts; not retrying further", slog.Int("count", restartCounts), slog.Any("interval", t))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
@@ -122,10 +122,10 @@ func (c *serveCmd) monitorMain() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
l.Debugln("Starting syncthing")
|
||||
slog.Debug("Starting syncthing")
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
l.Warnln("Error starting the main Syncthing process:", err)
|
||||
slog.Error("Failed to start the main Syncthing process", slogutil.Error(err))
|
||||
panic("Error starting the main Syncthing process")
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ func (c *serveCmd) monitorMain() {
|
||||
stdoutLastLines = make([]string, 0, 50)
|
||||
stdoutMut.Unlock()
|
||||
|
||||
wg := sync.NewWaitGroup()
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
@@ -158,13 +158,13 @@ func (c *serveCmd) monitorMain() {
|
||||
stopped := false
|
||||
select {
|
||||
case s := <-stopSign:
|
||||
l.Infof("Signal %d received; exiting", s)
|
||||
slog.Info("Received signal; exiting", "signal", s)
|
||||
cmd.Process.Signal(sigTerm)
|
||||
err = <-exit
|
||||
stopped = true
|
||||
|
||||
case s := <-restartSign:
|
||||
l.Infof("Signal %d received; restarting", s)
|
||||
slog.Info("Received signal; restarting", "signal", s)
|
||||
cmd.Process.Signal(sigHup)
|
||||
err = <-exit
|
||||
|
||||
@@ -184,9 +184,9 @@ func (c *serveCmd) monitorMain() {
|
||||
if exitCode == svcutil.ExitUpgrade.AsInt() {
|
||||
// Restart the monitor process to release the .old
|
||||
// binary as part of the upgrade process.
|
||||
l.Infoln("Restarting monitor...")
|
||||
slog.Info("Restarting monitor...")
|
||||
if err = restartMonitor(binary, args); err != nil {
|
||||
l.Warnln("Restart:", err)
|
||||
slog.Error("Failed to restart monitor", slogutil.Error(err))
|
||||
}
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
@@ -196,7 +196,7 @@ func (c *serveCmd) monitorMain() {
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
l.Infoln("Syncthing exited:", err)
|
||||
slog.Info("Syncthing exited", slogutil.Error(err))
|
||||
time.Sleep(restartPause)
|
||||
|
||||
if first {
|
||||
@@ -238,47 +238,29 @@ func copyStderr(stderr io.Reader, dst io.Writer) {
|
||||
return
|
||||
}
|
||||
|
||||
if panicFd == nil {
|
||||
dst.Write([]byte(line))
|
||||
dst.Write([]byte(line))
|
||||
|
||||
if strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:") {
|
||||
panicFd, err = os.Create(locations.GetTimestamped(locations.PanicLog))
|
||||
if err != nil {
|
||||
l.Warnln("Create panic log:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
l.Warnf("Panic detected, writing to \"%s\"", panicFd.Name())
|
||||
if strings.Contains(line, "leveldb") && strings.Contains(line, "corrupt") {
|
||||
l.Warnln(`
|
||||
*********************************************************************************
|
||||
* Crash due to corrupt database. *
|
||||
* *
|
||||
* This crash usually occurs due to one of the following reasons: *
|
||||
* - Syncthing being stopped abruptly (killed/loss of power) *
|
||||
* - Bad hardware (memory/disk issues) *
|
||||
* - Software that affects disk writes (SSD caching software and similar) *
|
||||
* *
|
||||
* Please see the following URL for instructions on how to recover: *
|
||||
* https://docs.syncthing.net/users/faq.html#my-syncthing-database-is-corrupt *
|
||||
*********************************************************************************
|
||||
`)
|
||||
} else {
|
||||
l.Warnln("Please check for existing issues with similar panic message at https://github.com/syncthing/syncthing/issues/")
|
||||
l.Warnln("If no issue with similar panic message exists, please create a new issue with the panic log attached")
|
||||
}
|
||||
|
||||
stdoutMut.Lock()
|
||||
for _, line := range stdoutFirstLines {
|
||||
panicFd.WriteString(line)
|
||||
}
|
||||
panicFd.WriteString("...\n")
|
||||
for _, line := range stdoutLastLines {
|
||||
panicFd.WriteString(line)
|
||||
}
|
||||
stdoutMut.Unlock()
|
||||
if panicFd == nil && (strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:")) {
|
||||
panicFd, err = os.Create(locations.GetTimestamped(locations.PanicLog))
|
||||
if err != nil {
|
||||
slog.Error("Failed to create panic log", slogutil.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
slog.Error("Panic detected, writing to file", slogutil.FilePath(panicFd.Name()))
|
||||
slog.Info("Please check for existing issues with similar panic message at https://github.com/syncthing/syncthing/issues/")
|
||||
slog.Info("If no issue with similar panic message exists, please create a new issue with the panic log attached")
|
||||
|
||||
stdoutMut.Lock()
|
||||
for _, line := range stdoutFirstLines {
|
||||
panicFd.WriteString(line)
|
||||
}
|
||||
panicFd.WriteString("...\n")
|
||||
for _, line := range stdoutLastLines {
|
||||
panicFd.WriteString(line)
|
||||
}
|
||||
stdoutMut.Unlock()
|
||||
|
||||
panicFd.WriteString("Panic at " + time.Now().Format(time.RFC3339) + "\n")
|
||||
}
|
||||
|
||||
@@ -448,7 +430,6 @@ func newAutoclosedFile(name string, closeDelay, maxOpenTime time.Duration) (*aut
|
||||
name: name,
|
||||
closeDelay: closeDelay,
|
||||
maxOpenTime: maxOpenTime,
|
||||
mut: sync.NewMutex(),
|
||||
closed: make(chan struct{}),
|
||||
closeTimer: time.NewTimer(time.Minute),
|
||||
}
|
||||
@@ -556,7 +537,7 @@ func maybeReportPanics() {
|
||||
// Try to get a config to see if/where panics should be reported.
|
||||
cfg, err := loadOrDefaultConfig()
|
||||
if err != nil {
|
||||
l.Warnln("Couldn't load config; not reporting crash")
|
||||
slog.Error("Couldn't load config; not reporting crash")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -576,7 +557,7 @@ func maybeReportPanics() {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(panicUploadNoticeWait):
|
||||
l.Warnln("Uploading crash reports is taking a while, please wait...")
|
||||
slog.Warn("Uploading crash reports is taking a while, please wait")
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -32,3 +32,10 @@
|
||||
darwin: "20"
|
||||
linux: "3.2"
|
||||
windows: "10.0"
|
||||
|
||||
- runtime: go1.25
|
||||
requirements:
|
||||
# macOS 12 (Monterey) per https://tip.golang.org/doc/go1.25#darwin
|
||||
darwin: "21"
|
||||
linux: "3.2"
|
||||
windows: "10.0"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Name=Syncthing Web UI
|
||||
GenericName=File synchronization UI
|
||||
Comment=Opens Syncthing's Web UI in the default browser (Syncthing must already be started).
|
||||
Exec=syncthing --browser-only
|
||||
Exec=syncthing browser
|
||||
Icon=syncthing
|
||||
Terminal=false
|
||||
Type=Application
|
||||
|
||||
@@ -7,7 +7,7 @@ StartLimitBurst=4
|
||||
|
||||
[Service]
|
||||
User=%i
|
||||
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0
|
||||
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart
|
||||
Restart=on-failure
|
||||
RestartSec=1
|
||||
SuccessExitStatus=3 4
|
||||
|
||||
@@ -18,4 +18,4 @@ env STNORESTART=yes
|
||||
respawn
|
||||
|
||||
# the syncthing command Upstart is to execute when it is started up
|
||||
exec $SYNCTHING_EXE -no-browser
|
||||
exec $SYNCTHING_EXE --no-browser
|
||||
|
||||
72
go.mod
72
go.mod
@@ -1,15 +1,16 @@
|
||||
module github.com/syncthing/syncthing
|
||||
|
||||
go 1.23.0
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1
|
||||
github.com/alecthomas/kong v1.11.0
|
||||
github.com/aws/aws-sdk-go v1.55.7
|
||||
github.com/AudriusButkevicius/recli v0.0.7
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2
|
||||
github.com/alecthomas/kong v1.12.1
|
||||
github.com/aws/aws-sdk-go v1.55.8
|
||||
github.com/calmh/incontainer v1.0.0
|
||||
github.com/calmh/xdr v1.2.0
|
||||
github.com/ccding/go-stun v0.1.5
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/d4l3k/messagediff v1.2.1
|
||||
github.com/getsentry/raven-go v0.2.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.11
|
||||
@@ -22,50 +23,50 @@ require (
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/maruel/panicparse/v2 v2.5.0
|
||||
github.com/mattn/go-sqlite3 v1.14.28
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2
|
||||
github.com/mattn/go-sqlite3 v1.14.31
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.3
|
||||
github.com/maxmind/geoipupdate/v6 v6.1.0
|
||||
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75
|
||||
github.com/oschwald/geoip2-golang v1.11.0
|
||||
github.com/oschwald/geoip2-golang v1.13.0
|
||||
github.com/pierrec/lz4/v4 v4.1.22
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/prometheus/client_golang v1.23.0
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1
|
||||
github.com/quic-go/quic-go v0.52.0
|
||||
github.com/rabbitmq/amqp091-go v1.10.0
|
||||
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9
|
||||
github.com/shirou/gopsutil/v4 v4.25.4
|
||||
github.com/shirou/gopsutil/v4 v4.25.7
|
||||
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
|
||||
github.com/thejerf/suture/v4 v4.0.6
|
||||
github.com/urfave/cli v1.22.16
|
||||
github.com/urfave/cli v1.22.17
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
|
||||
github.com/willabides/kongplete v0.4.0
|
||||
github.com/wlynxg/anet v0.0.5
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
golang.org/x/crypto v0.38.0
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
|
||||
golang.org/x/net v0.40.0
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/text v0.25.0
|
||||
golang.org/x/time v0.11.0
|
||||
golang.org/x/tools v0.33.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
modernc.org/sqlite v1.37.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/exp v0.0.0-20250811191247-51f88131bc50
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/text v0.28.0
|
||||
golang.org/x/time v0.12.0
|
||||
golang.org/x/tools v0.36.0
|
||||
google.golang.org/protobuf v1.36.7
|
||||
modernc.org/sqlite v1.38.2
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.3 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
@@ -87,28 +88,29 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/posener/complete v1.2.3 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||
github.com/tklauser/numcpus v0.9.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.uber.org/mock v0.5.2 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.62.1 // indirect
|
||||
modernc.org/libc v1.66.3 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.9.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
)
|
||||
|
||||
// https://github.com/gobwas/glob/pull/55
|
||||
replace github.com/gobwas/glob v0.2.3 => github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b
|
||||
|
||||
// https://github.com/mattn/go-sqlite3/pull/1338
|
||||
replace github.com/mattn/go-sqlite3 v1.14.28 => github.com/calmh/go-sqlite3 v1.14.29-0.20250520105817-2e94cda3f7f8
|
||||
replace github.com/mattn/go-sqlite3 v1.14.31 => github.com/calmh/go-sqlite3 v1.14.32-0.20250812195006-80712c77b76a
|
||||
|
||||
168
go.sum
168
go.sum
@@ -1,38 +1,38 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f h1:GmH5lT+moM7PbAJFBq57nH9WJ+wRnBXr/tyaYWbSAx8=
|
||||
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f/go.mod h1:Nhfib1j/VFnLrXL9cHgA+/n2O6P5THuWelOnbfPNd78=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0 h1:OVoM452qUFBrX+URdH3VpR299ma4kfom0yB0URYky9g=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4=
|
||||
github.com/AudriusButkevicius/recli v0.0.7 h1:9zjbYlTupi+W5SJXm2cR2sV2mJAIg1sIfDcsW7hrkPM=
|
||||
github.com/AudriusButkevicius/recli v0.0.7/go.mod h1:Nhfib1j/VFnLrXL9cHgA+/n2O6P5THuWelOnbfPNd78=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0 h1:LR0kAX9ykz8G4YgLCaRDVJ3+n43R8MneB5dTy2konZo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0/go.mod h1:DWAciXemNf++PQJLeXUB4HHH5OpsAh12HZnu2wXE1jA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 h1:FwladfywkNirM+FZYLBR2kBz5C8Tg0fw5w5Y7meRXWI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2/go.mod h1:vv5Ad0RrIoT1lJFdWBZwt4mB1+j+V8DUroixmKDTCdk=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/kong v1.11.0 h1:y++1gI7jf8O7G7l4LZo5ASFhrhJvzc+WgF/arranEmM=
|
||||
github.com/alecthomas/kong v1.11.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
|
||||
github.com/alecthomas/kong v1.12.1 h1:iq6aMJDcFYP9uFrLdsiZQ2ZMmcshduyGv4Pek0MQPW0=
|
||||
github.com/alecthomas/kong v1.12.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
|
||||
github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=
|
||||
github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b h1:Fjm4GuJ+TGMgqfGHN42IQArJb77CfD/mAwLbDUoJe6g=
|
||||
github.com/calmh/glob v0.0.0-20220615080505-1d823af5017b/go.mod h1:91K7jfEsgJSyfSrX+gmrRfZMtntx6JsHolWubGXDopg=
|
||||
github.com/calmh/go-sqlite3 v1.14.29-0.20250520105817-2e94cda3f7f8 h1:oNVrBJGXkD334ToEmxJz8G6LhzD1/sMA4twMHsMLzQo=
|
||||
github.com/calmh/go-sqlite3 v1.14.29-0.20250520105817-2e94cda3f7f8/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/calmh/go-sqlite3 v1.14.32-0.20250812195006-80712c77b76a h1:lTe5qJApKNO+zZCa3/P/7UxM4c58CXWOegv9eODPWvs=
|
||||
github.com/calmh/go-sqlite3 v1.14.32-0.20250812195006-80712c77b76a/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/calmh/incontainer v1.0.0 h1:g2cTUtZuFGmMGX8GoykPkN1Judj2uw8/3/aEtq4Z/rg=
|
||||
github.com/calmh/incontainer v1.0.0/go.mod h1:eOhqnw15c9X+4RNBe0W3HlUZFfX16O0EDsCOInTndHY=
|
||||
github.com/calmh/xdr v1.2.0 h1:GaGSNH4ZDw9kNdYqle6+RcAENiaQ8/611Ok+jQbBEeU=
|
||||
@@ -50,8 +50,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
|
||||
github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -59,8 +59,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
|
||||
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
@@ -85,8 +85,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
@@ -102,7 +102,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
@@ -168,8 +167,8 @@ github.com/maruel/panicparse/v2 v2.5.0/go.mod h1:DA2fDiBk63bKfBf4CVZP9gb4fuvzdPb
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2 h1:yVCLo4+ACVroOEr4iFU1iH46Ldlzz2rTuu18Ra7M8sU=
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2/go.mod h1:VzB2VoMh1Y32/QqDfg9ZJYHj99oM4LiGtqPZydTiQSQ=
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.3 h1:Eaq36EIyJNp7b3qDhjV7jmDVq/yPeW2v4pTqzGbOGB4=
|
||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.11.3/go.mod h1:6KKUoQBZBW6PDXJtNfqeEjPXMj/ITTk+cWK9t9uS5+E=
|
||||
github.com/maxmind/geoipupdate/v6 v6.1.0 h1:sdtTHzzQNJlXF5+fd/EoPTucRHyMonYt/Cok8xzzfqA=
|
||||
github.com/maxmind/geoipupdate/v6 v6.1.0/go.mod h1:cZYCDzfMzTY4v6dKRdV7KTB6SStxtn3yFkiJ1btTGGc=
|
||||
github.com/miscreant/miscreant.go v0.0.0-20200214223636-26d376326b75 h1:cUVxyR+UfmdEAZGJ8IiKld1O0dbGotEnkMolG5hfMSY=
|
||||
@@ -194,10 +193,10 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
|
||||
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
|
||||
github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
|
||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI=
|
||||
github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||
@@ -215,14 +214,14 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
|
||||
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||
@@ -241,8 +240,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
|
||||
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw=
|
||||
github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1JqVM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
@@ -254,7 +253,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/syncthing/notify v0.0.0-20250528144937-c7027d4f7465 h1:yhxdTGmFkAM2TFA65c3NgGwpnIkUM8oVqPX2e9S7IVg=
|
||||
@@ -263,17 +261,19 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
|
||||
github.com/thejerf/suture/v4 v4.0.6 h1:QsuCEsCqb03xF9tPAsWAj8QOAJBgQI1c0VqJNaingg8=
|
||||
github.com/thejerf/suture/v4 v4.0.6/go.mod h1:gu9Y4dXNUWFrByqRt30Rm9/UZ0wzRSt9AJS6xu/ZGxU=
|
||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||
github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
|
||||
github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
|
||||
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
|
||||
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
|
||||
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
|
||||
github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ=
|
||||
github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo=
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0 h1:okhMind4q9H1OxF44gNegWkiP4H/gsTFLalHFa4OOUI=
|
||||
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0/go.mod h1:TTbGUfE+cXXceWtbTHq6lqcTvYPBKLNejBEbnUsQJtU=
|
||||
github.com/willabides/kongplete v0.4.0 h1:eivXxkp5ud5+4+NVN9e4goxC5mSh3n1RHov+gsblM2g=
|
||||
github.com/willabides/kongplete v0.4.0/go.mod h1:0P0jtWD9aTsqPSUAl4de35DLghrr57XcayPyvqSi2X8=
|
||||
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
@@ -283,16 +283,20 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20250811191247-51f88131bc50 h1:3yiSh9fhy5/RhCSntf4Sy0Tnx50DmMpQ4MQdKKk4yg4=
|
||||
golang.org/x/exp v0.0.0-20250811191247-51f88131bc50/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -301,13 +305,13 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -330,23 +334,23 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -360,8 +364,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@@ -377,29 +381,31 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic=
|
||||
modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU=
|
||||
modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/cc/v4 v4.26.2 h1:991HMkLjJzYBIfha6ECZdjrIYz2/1ayr+FL8GN+CNzM=
|
||||
modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
||||
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
|
||||
modernc.org/fileutil v1.3.8 h1:qtzNm7ED75pd1C7WgAGcK4edm4fvhtBsEiI/0NQ54YM=
|
||||
modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s=
|
||||
modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ=
|
||||
modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g=
|
||||
modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI=
|
||||
modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM=
|
||||
modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek=
|
||||
modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
"Show diff with previous version": "أظهر الفرق مقارنةً بالنسخة السابقة",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "يُعرَض بدلا من المُعرِّف ضمن العناقيد. سيُروَّج للأجهزة الأخرى على أنه اسم أساسي محتمل.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "يُعرَض بدلا من المُعرِّف ضمن العناقيد. إذا تُرك فارغا، سيُحدَّث إلى الاسم المختار من قِبَل الجهاز.",
|
||||
"Shutdown": "إغلاق",
|
||||
"Shut Down": "إغلاق",
|
||||
"Shutdown Complete": "أُغلِق",
|
||||
"Simple": "بسيط",
|
||||
"Simple File Versioning": "التقسيم البسيط لإصدارات الملفات",
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
"Show ID": "Паказаць ID",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
|
||||
"Shutdown": "Выключыць",
|
||||
"Shut Down": "Выключыць",
|
||||
"Shutdown Complete": "Выключэньне завершанае",
|
||||
"Simple File Versioning": "Простае захоўваньне вэрсій",
|
||||
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Научете повече",
|
||||
"Learn more at {%url%}": "Научете повече на {{url}}",
|
||||
"Limit": "Ограничение",
|
||||
"Limit Bandwidth in LAN": "Огранич. на скоростта в местната мрежа",
|
||||
"Listener Failures": "Грешки при очакване на връзка",
|
||||
"Listener Status": "Очакване на връзка",
|
||||
"Listeners": "Очакване на връзка",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Показване на разликите с предходната версия",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "В списъка на устройствата се показва вместо идентификатор. Ще бъде предложено на другите устройства като име по подразбиране.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "В списъка на устройствата се показва вместо идентификатор. Ако бъде оставено празно ще бъде променено на името, което носи устройството.",
|
||||
"Shutdown": "Изключване",
|
||||
"Shut Down": "Изключване",
|
||||
"Shutdown Complete": "Спирането завършено",
|
||||
"Simple": "Обикновени",
|
||||
"Simple File Versioning": "Обикновени версии",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"Allowed Networks": "Xarxes permeses",
|
||||
"Alphabetic": "Alfabètic",
|
||||
"Altered by ignoring deletes.": "S'ha alterat ignorant les supressions.",
|
||||
"Always turned on when the folder type is \"{%foldertype%}\".": "Sempre activat quan el tipus de carpeta és \"{{foldertype}}\".",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Una ordre externa gestiona la versió. Ha d'eliminar el fitxer de la carpeta compartida. Si el camí a l'aplicació conté espais, s'ha de citar.",
|
||||
"Anonymous Usage Reporting": "Informe anònim d'ús",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "El format de l'informe d'ús anònim ha canviat. Voleu canviar a aquest nou format?",
|
||||
@@ -52,6 +53,7 @@
|
||||
"Body:": "Cos de text:",
|
||||
"Bugs": "Errors (Bugs)",
|
||||
"Cancel": "Cancel·la",
|
||||
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "No es pot habilitar quan el tipus de carpeta és \"{{foldertype}}\".",
|
||||
"Changelog": "Historial de canvis",
|
||||
"Clean out after": "Netejar després",
|
||||
"Cleaning Versions": "Netejant versions",
|
||||
@@ -368,7 +370,7 @@
|
||||
"Show diff with previous version": "Mostra la diferència amb la versió anterior",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrat en comptes del ID del Node en l'estat del cluster. Serà advertit als altres dispositius com un nom opcional per defecte.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrat en comptes del ID del Node en l'estat del cluster. S'actualitzarà al nom del dispositiu si es deixa buit.",
|
||||
"Shutdown": "Apaga",
|
||||
"Shut Down": "Apaga",
|
||||
"Shutdown Complete": "Apagat complet",
|
||||
"Simple": "Simple",
|
||||
"Simple File Versioning": "Versionat de Fitxers Senzill",
|
||||
|
||||
@@ -353,7 +353,7 @@
|
||||
"Show diff with previous version": "Mostrar les diferències amb la versió prèvia",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrat en lloc de l'ID del dispositiu en l'estat del grup (cluster). S'anunciarà als altres dispositius com el nom opcional per defecte.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrat en lloc de l'ID del dispositiu en l'estat del grup (cluster). S'actualitzarà al nom que el dispositiu anuncia si es deixa buit.",
|
||||
"Shutdown": "Apagar",
|
||||
"Shut Down": "Apagar",
|
||||
"Shutdown Complete": "Apagar completament",
|
||||
"Simple": "Senzill",
|
||||
"Simple File Versioning": "Versionat de fitxers senzill",
|
||||
|
||||
@@ -360,7 +360,7 @@
|
||||
"Show diff with previous version": "Ukázat rozdíl oproti předchozí verzi",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Zobrazeno místo identifikátoru zařízení na náhledu stavu clusteru. Bude odesíláno ostatním zařízením jako výchozí název zařízení.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Zobrazeno místo identifikátoru zařízení na náhledu stavu clusteru. Pokud nebude vyplněno, bude nastaveno na název, který zařízení odesílá.",
|
||||
"Shutdown": "Vypnout",
|
||||
"Shut Down": "Vypnout",
|
||||
"Shutdown Complete": "Vypnutí dokončeno",
|
||||
"Simple": "Jednoduché",
|
||||
"Simple File Versioning": "Jednoduchá správa verzí souborů",
|
||||
|
||||
@@ -368,7 +368,7 @@
|
||||
"Show diff with previous version": "Vis forskelle fra tidligere version",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vises i stedet for enheds-ID i klyngestatus. Vil blive sendt til andre enheder som valgfrit standardnavn.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vises i stedet for enheds-ID i klyngestatus. Vil blive opdateret til det navn, som enheden sender, hvis det ikke er udfyldt.",
|
||||
"Shutdown": "Luk ned",
|
||||
"Shut Down": "Luk ned",
|
||||
"Shutdown Complete": "Nedlukning fuldført",
|
||||
"Simple": "Enkel",
|
||||
"Simple File Versioning": "Simpel filversionering",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Mehr erfahren",
|
||||
"Learn more at {%url%}": "Erfahren Sie mehr unter {{url}}",
|
||||
"Limit": "Limit",
|
||||
"Limit Bandwidth in LAN": "Bandbreite im LAN begrenzen",
|
||||
"Listener Failures": "Fehler bei Listener",
|
||||
"Listener Status": "Status der Listener",
|
||||
"Listeners": "Zuhörer",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Unterschied zur vorherigen Version anzeigen",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wird anstelle der Gerätekennung im Verbundstatus angezeigt. Wird anderen Geräten als optionaler Standardname bekannt gegeben.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wird anstelle der Gerätekennung im Verbundstatus angezeigt. Wird auf den Namen aktualisiert, den das Gerät anzeigt, wenn er leer bleibt.",
|
||||
"Shutdown": "Herunterfahren",
|
||||
"Shut Down": "Herunterfahren",
|
||||
"Shutdown Complete": "Vollständig heruntergefahren",
|
||||
"Simple": "Einfach",
|
||||
"Simple File Versioning": "Einfache Dateiversionierung",
|
||||
|
||||
@@ -368,7 +368,7 @@
|
||||
"Show diff with previous version": "Εμφάνιση διαφορών με προηγούμενη έκδοση",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Θα φαίνεται αντί για την ταυτότητα της συσκευής στην προβολή της κατάστασης ολόκληρης της συστάδας. Θα γνωστοποιείται σαν το προαιρετικό όνομα της συσκευής.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Θα φαίνεται αντί για την ταυτότητα της συσκευής στην προβολή της κατάστασης ολόκληρης της συστάδας. Θα ενημερώνεται αυτόματα αν αλλάξει το όνομα της συσκευής.",
|
||||
"Shutdown": "Απενεργοποίηση",
|
||||
"Shut Down": "Απενεργοποίηση",
|
||||
"Shutdown Complete": "Πλήρης απενεργοποίηση",
|
||||
"Simple": "Απλό",
|
||||
"Simple File Versioning": "Απλή τήρηση εκδόσεων",
|
||||
|
||||
@@ -353,7 +353,7 @@
|
||||
"Show diff with previous version": "Show diff with previous version",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
|
||||
"Shutdown": "Shutdown",
|
||||
"Shut Down": "Shut Down",
|
||||
"Shutdown Complete": "Shutdown Complete",
|
||||
"Simple": "Simple",
|
||||
"Simple File Versioning": "Simple File Versioning",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Learn more",
|
||||
"Learn more at {%url%}": "Learn more at {{url}}",
|
||||
"Limit": "Limit",
|
||||
"Limit Bandwidth in LAN": "Limit Bandwidth in LAN",
|
||||
"Listener Failures": "Listener Failures",
|
||||
"Listener Status": "Listener Status",
|
||||
"Listeners": "Listeners",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Show diff with previous version",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
|
||||
"Shutdown": "Shutdown",
|
||||
"Shut Down": "Shut Down",
|
||||
"Shutdown Complete": "Shutdown Complete",
|
||||
"Simple": "Simple",
|
||||
"Simple File Versioning": "Simple File Versioning",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Custom Range",
|
||||
"Danger!": "Danger!",
|
||||
"Database Location": "Database Location",
|
||||
"Debug": "Debug",
|
||||
"Debugging Facilities": "Debugging Facilities",
|
||||
"Default": "Default",
|
||||
"Default Configuration": "Default Configuration",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Incorrect configuration may damage your folder contents and render Syncthing inoperable.",
|
||||
"Incorrect user name or password.": "Incorrect user name or password.",
|
||||
"Info": "Info",
|
||||
"Internally used paths:": "Internally used paths:",
|
||||
"Introduced By": "Introduced By",
|
||||
"Introducer": "Introducer",
|
||||
@@ -227,6 +229,7 @@
|
||||
"Learn more": "Learn more",
|
||||
"Learn more at {%url%}": "Learn more at {{url}}",
|
||||
"Limit": "Limit",
|
||||
"Limit Bandwidth in LAN": "Limit Bandwidth in LAN",
|
||||
"Listener Failures": "Listener Failures",
|
||||
"Listener Status": "Listener Status",
|
||||
"Listeners": "Listeners",
|
||||
@@ -370,7 +373,7 @@
|
||||
"Show diff with previous version": "Show diff with previous version",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.",
|
||||
"Shutdown": "Shutdown",
|
||||
"Shut Down": "Shut Down",
|
||||
"Shutdown Complete": "Shutdown Complete",
|
||||
"Simple": "Simple",
|
||||
"Simple File Versioning": "Simple File Versioning",
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
"Show diff with previous version": "Montri diferenco kun antaŭa versio",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Montrita anstataŭ ID de Aparato en la statuso de la grupo. Estos anoncita al aliaj aparatoj kiel laŭvola defaŭlta nomo.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Montri anstataŭ ID de Aparato en la statuso de la grupo. Estos ĝisdatigita al la nomo de la aparato sciigante se ĝi estas lasita malplena.",
|
||||
"Shutdown": "Sistemfermo",
|
||||
"Shut Down": "Sistemfermo",
|
||||
"Shutdown Complete": "Sistemfermo Tuta",
|
||||
"Simple File Versioning": "Simpla Versionado de Dosieroj",
|
||||
"Single level wildcard (matches within a directory only)": "Ununivela ĵokero (egalas nur ene de dosierujo)",
|
||||
|
||||
@@ -368,7 +368,7 @@
|
||||
"Show diff with previous version": "Mostrar la diferencia con la versión anterior",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Se muestra en lugar del ID del dispositivo en el estado del grupo (cluster). Se notificará a los otros dispositivos como nombre opcional por defecto.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Se muestra en lugar del ID del dispositivo en el estado del grupo (cluster). Se actualizará al nombre que el dispositivo anuncia si se deja vacío.",
|
||||
"Shutdown": "Apagar",
|
||||
"Shut Down": "Apagar",
|
||||
"Shutdown Complete": "Apagar completamente",
|
||||
"Simple": "Sencillo",
|
||||
"Simple File Versioning": "Versionado simple de fichero",
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
{
|
||||
"A device with that ID is already added.": "Sellise seadme ID'ga seade on juba lisatud.",
|
||||
"A device with that ID is already added.": "Sellise tunnusega seade on juba lisatud.",
|
||||
"A negative number of days doesn't make sense.": "Negatiivne päevade arv ei ole loogiline.",
|
||||
"API Key": "API Võti",
|
||||
"API Key": "API võti",
|
||||
"About": "Rakenduse teave",
|
||||
"Action": "Tegevus",
|
||||
"Actions": "Tegevused",
|
||||
"Add": "Lisa",
|
||||
"Add Device": "Lisa seade",
|
||||
"Add Folder": "Lisa kaust",
|
||||
"Add new folder?": "Lisa uus kaust?",
|
||||
"Add Remote Device": "Lisa kaugseade",
|
||||
"Add new folder?": "Kas lisad uue kausta?",
|
||||
"Address": "Aadress",
|
||||
"Addresses": "Aadressid",
|
||||
"All Data": "Kõik andmed",
|
||||
"All Time": "Kõik ajad",
|
||||
"Allowed Networks": "Lubatud võrgud",
|
||||
"Alphabetic": "Tähestikuline",
|
||||
"Apply": "Rakenda",
|
||||
"Automatic upgrades": "Automaatsed uuendused",
|
||||
"Be careful!": "Ettevaatust!",
|
||||
"Cancel": "Loobu",
|
||||
@@ -47,7 +50,7 @@
|
||||
"Folder Label": "Kausta Silt",
|
||||
"Folder Type": "Kausta Tüüp",
|
||||
"Folders": "Kaustad",
|
||||
"GUI": "GUI",
|
||||
"GUI": "Kasutajaliides",
|
||||
"GUI Authentication Password": "GUI Autentimise Salasõna",
|
||||
"GUI Authentication User": "GUI Autentimise Kasutajatunnus",
|
||||
"GUI Theme": "GUI Teema",
|
||||
@@ -75,7 +78,7 @@
|
||||
"New Folder": "Uus Kaust",
|
||||
"Newest First": "Uusimad Ennem",
|
||||
"No": "Ei",
|
||||
"OK": "OK",
|
||||
"OK": "Sobib",
|
||||
"Oldest First": "Vanimad Ennem",
|
||||
"Options": "Valikud",
|
||||
"Outgoing Rate Limit (KiB/s)": "Väljuva Kiiruse Piirang (KiB/s)",
|
||||
@@ -116,7 +119,7 @@
|
||||
"The device ID cannot be blank.": "Seadme ID ei tohi olla tühi.",
|
||||
"The folder ID cannot be blank.": "Kausta ID ei tohi olla tühi.",
|
||||
"The folder ID must be unique.": "Kausta ID peab olema unikaalne.",
|
||||
"The folder path cannot be blank.": "Kausta asukoht ei tohi olla tühi!",
|
||||
"The folder path cannot be blank.": "Kausta asukoht ei tohi olla tühi.",
|
||||
"The following items could not be synchronized.": "Järgnevaid üksusi ei õnnestunud sünkroniseerida.",
|
||||
"The maximum age must be a number and cannot be blank.": "Maksimaalne vanus peab olema arv ning ei tohi olla tühi.",
|
||||
"Unknown": "Teadmata",
|
||||
|
||||
@@ -309,7 +309,7 @@
|
||||
"Show diff with previous version": "Erakutsi aurreko bertsioarekiko aldeak",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Tresnaren ID-aren ordez erakutsia, taldearen egoeran. Beste tresneri erakutsia izanen da, izen erabilgarri bat bezala",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Tresnaren ID-aren ordez erakutsia, taldearen egoeran. Hutsa utzia balin bada, urrun den tresnak proposatu izenarekin aktualizatua izanen da",
|
||||
"Shutdown": "Geldi",
|
||||
"Shut Down": "Geldi",
|
||||
"Shutdown Complete": "Gelditua!",
|
||||
"Simple File Versioning": "Bertsioen segitze sinplifikatua",
|
||||
"Single level wildcard (matches within a directory only)": "Hein bakar bateko jokerra (karpetaren barnean bakarrik dagokiona)",
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
"Show diff with previous version": "Näytä muutokset edelliseen versioon",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Näytetään ryhmän tiedoissa laitteen ID:n sijaan. Ilmoitetaan muille laitteille vaihtoehtoisena oletusnimenä.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Näytetään ryhmän tiedoissa laitteen ID:n sijaan. Tyhjä nimi päivitetään laitteen ilmoittamaksi nimeksi.",
|
||||
"Shutdown": "Sammuta",
|
||||
"Shut Down": "Sammuta",
|
||||
"Shutdown Complete": "Sammutus valmis",
|
||||
"Simple File Versioning": "Yksinkertainen tiedostoversiointi",
|
||||
"Single level wildcard (matches within a directory only)": "Yksitasoinen jokerimerkki (vaikuttaa vain kyseisen kansion sisällä)",
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
"Show diff with previous version": "Ipakita ang diff sa nakaraang bersyon",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Ipinapakita sa halip na Device ID sa status ng cluster. Ia-advertise sa iba pang mga device bilang opsyonal na default na pangalan.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Ipinapakita sa halip na Device ID sa status ng cluster. Ia-update sa pangalan na ina-advertise ng device kung iiwanang walang laman.",
|
||||
"Shutdown": "I-shutdown",
|
||||
"Shut Down": "I-shutdown",
|
||||
"Shutdown Complete": "Tapos na ang Shutdown",
|
||||
"Simple": "Simple",
|
||||
"Simple File Versioning": "Simpleng File Versioning",
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
"Show QR": "Afficher l'image QR",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Sera diffusé aux autres appareils comme nom convivial optionnel par défaut.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Si laissé vide, il sera renseigné par le nom convivial proposé par l'appareil distant.",
|
||||
"Shutdown": "Arrêter",
|
||||
"Shut Down": "Arrêter",
|
||||
"Shutdown Complete": "Arrêté !",
|
||||
"Simple File Versioning": "Suivi simplifié des versions",
|
||||
"Single level wildcard (matches within a directory only)": "Joker à un seul niveau (correspond uniquement à l’intérieur du répertoire)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "En savoir plus",
|
||||
"Learn more at {%url%}": "Si vous souhaitez en savoir plus, c'est ici (en anglais) : {{url}}",
|
||||
"Limit": "Limite",
|
||||
"Limit Bandwidth in LAN": "Limiter la bande passante locale (LAN)",
|
||||
"Listener Failures": "Échecs de l'écouteur",
|
||||
"Listener Status": "État de l'écouteur",
|
||||
"Listeners": "Écoute",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Afficher les différences avec la version précédente",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Affiché à la place de l'ID de l'appareil dans l'état du groupe. Sera diffusé aux autres appareils comme nom convivial optionnel par défaut.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Nom convivial local affiché à la place de l'ID de l'appareil dans la plupart des écrans. Si laissé vide, c'est le nom convivial local de l'appareil distant qui sera utilisé. (Modifiable ultérieurement).",
|
||||
"Shutdown": "Arrêter",
|
||||
"Shut Down": "Arrêter",
|
||||
"Shutdown Complete": "Arrêt complet",
|
||||
"Simple": "Suivi simplifié",
|
||||
"Simple File Versioning": "Suivi simplifié des versions",
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
"Show diff with previous version": "Ferskil (diff) mei de foarige ferzje sjen litte",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wurd ynstee fan apparaat-ID sjen litten by de bondeltastân. Wurd nei oare apparaten advertearre as in mooglike standertnamme.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wurd yn de bondeltastân sjen litten ynstee fan apparaat-ID. Wannear't leech litten wurd, wurd it fernijt nei de namme die it apparaat útstjoert.",
|
||||
"Shutdown": "Ofslute",
|
||||
"Shut Down": "Ofslute",
|
||||
"Shutdown Complete": "Ofsluten klear",
|
||||
"Simple File Versioning": "Ienfâldich triemferzjebehear",
|
||||
"Single level wildcard (matches within a directory only)": "Inkel-nivo jokerteken (wildcard) (fergeliket allinnich binnen in map)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Faigh tuilleadh eolais",
|
||||
"Learn more at {%url%}": "Tuilleadh eolais ag {{url}}",
|
||||
"Limit": "Teorainn",
|
||||
"Limit Bandwidth in LAN": "Teorainn a chur ar an bandaleithead i LAN",
|
||||
"Listener Failures": "Teipeanna an Éisteora",
|
||||
"Listener Status": "Stádas an éisteora",
|
||||
"Listeners": "Éisteoirí",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Taispeáin diff leis an leagan roimhe seo",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Taispeántar é in ionad ID gléis i stádas na braisle. Fógrófar é do ghléasanna eile mar ainm réamhshocraithe roghnach.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Taispeántar é in ionad ID gléis i stádas na braisle. Déanfar é a nuashonrú go dtí an t-ainm a fhógraíonn an gléas má fhágtar folamh é.",
|
||||
"Shutdown": "Múchadh",
|
||||
"Shut Down": "Múchadh",
|
||||
"Shutdown Complete": "Múchadh Críochnaithe",
|
||||
"Simple": "Simplí",
|
||||
"Simple File Versioning": "Leagan Simplí Comhad",
|
||||
|
||||
@@ -323,7 +323,7 @@
|
||||
"Show diff with previous version": "Mostrar a diferencia coa versión anterior",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrado en lugar do ID de Dispositivo no estado do clúster. Anunciarase a outros dispositivos como nome por defecto opcional.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrado en lugar do ID de Dispositivo no estado do clúster. Actualizarase ao nome que anuncia o dispositivo de se deixar baleiro.",
|
||||
"Shutdown": "Apagar",
|
||||
"Shut Down": "Apagar",
|
||||
"Shutdown Complete": "Apagado Completado",
|
||||
"Simple": "Simple",
|
||||
"Simple File Versioning": "Versionado de Ficheiros Sinxelo",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"Allowed Networks": "רשתות מורשות",
|
||||
"Alphabetic": "אלפביתי",
|
||||
"Altered by ignoring deletes.": "השתנה על ידי התעלמות ממחיקות.",
|
||||
"Always turned on when the folder type is \"{%foldertype%}\".": "תמיד מופעל כאשר סוג התיקייה הוא \"{{foldertype}}\".",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "פקודה חיצונית מטפלת בניהול הגרסאות. היא חייבת להסיר את הקובץ מהתיקייה המשותפת. אם הנתיב ליישום מכיל רווחים, יש לצטט אותו.",
|
||||
"Anonymous Usage Reporting": "דיווח שימוש אנונימי",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "פורמט דוח שימוש אנונימי השתנה. האם ברצונך לעבור לפורמט החדש?",
|
||||
@@ -52,6 +53,7 @@
|
||||
"Body:": "גוף:",
|
||||
"Bugs": "באגים",
|
||||
"Cancel": "ביטול",
|
||||
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "לא ניתן לאפשור כאשר סוג התיקייה הוא \"{{foldertype}}\".",
|
||||
"Changelog": "יומן שינויים",
|
||||
"Clean out after": "נקה לאחר",
|
||||
"Cleaning Versions": "מנקה גרסאות",
|
||||
@@ -225,6 +227,7 @@
|
||||
"Learn more": "למד עוד",
|
||||
"Learn more at {%url%}": "למד עוד באתר {{url}}",
|
||||
"Limit": "מגבלה",
|
||||
"Limit Bandwidth in LAN": "הגבלת רוחב פס ברשת תקשורת מקומית (LAN)",
|
||||
"Listener Failures": "כשלי מאזין",
|
||||
"Listener Status": "מצב מאזין",
|
||||
"Listeners": "מאזינים",
|
||||
@@ -368,7 +371,7 @@
|
||||
"Show diff with previous version": "הצג הבדל עם הגרסה הקודמת",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "מוצג במקום מזהה ההתקן במצב האשכול. יפורסם להתקנים אחרים כשם ברירת מחדל אופציונלי.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "מוצג במקום מזהה ההתקן במצב האשכול. יעודכן לשם שההתקן מפרסם אם נותר ריק.",
|
||||
"Shutdown": "כיבוי",
|
||||
"Shut Down": "כיבוי",
|
||||
"Shutdown Complete": "הכיבוי הושלם",
|
||||
"Simple": "פשוט",
|
||||
"Simple File Versioning": "ניהול גרסאות קבצים פשוט",
|
||||
|
||||
@@ -368,7 +368,7 @@
|
||||
"Show diff with previous version": "पिछले संस्करण के साथ अंतर दिखाएं",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "समूह स्थिति में उपकरण ID के बजाय दिखाया गया। वैकल्पिक तयशुदा नाम के रूप में अन्य उपकरणों पर विज्ञापित किया जाएगा।",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "समूह स्थिति में उपकरण ID के बजाय दिखाया गया। खाली छोड़े जाने पर उपकरण द्वारा विज्ञापित नाम में अद्यतित कर दिया जाएगा।",
|
||||
"Shutdown": "शटडाउन",
|
||||
"Shut Down": "शटडाउन",
|
||||
"Shutdown Complete": "शटडाउन पूर्ण",
|
||||
"Simple": "सरल",
|
||||
"Simple File Versioning": "सरल फाइल संस्करण",
|
||||
|
||||
@@ -345,7 +345,7 @@
|
||||
"Show diff with previous version": "Előző verzió eltérésének megjelenítése",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Az eszközazonosító helyett jelenik meg. A többi eszközön alapértelmezett névként használható.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Az eszközazonosító helyett jelenik meg. Üresen hagyva az eszköz saját neve lesz alkalmazva.",
|
||||
"Shutdown": "Leállítás",
|
||||
"Shut Down": "Leállítás",
|
||||
"Shutdown Complete": "Leállítás kész",
|
||||
"Simple": "Egyszerű",
|
||||
"Simple File Versioning": "Egyszerű fájlverzió-követés",
|
||||
|
||||
@@ -322,7 +322,7 @@
|
||||
"Show diff with previous version": "Tampilkan perbedaan dengan versi sebelumnya",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Ditampilkan sebagai ganti ID Perangkat dalam status gugus. Akan diumumkan ke perangkat lain sebagai nama bawaan opsional.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Ditampilkan sebagai ganti ID Perangkat dalam status gugus. Akan diubah menjadi nama yang perangkat umumkan jika tidak diisi.",
|
||||
"Shutdown": "Matikan",
|
||||
"Shut Down": "Matikan",
|
||||
"Shutdown Complete": "Pematian Selesai",
|
||||
"Simple File Versioning": "Pemversian Berkas Sederhana",
|
||||
"Single level wildcard (matches within a directory only)": "Wildcard tingkat tunggal (cocok hanya dalam satu direktori saja)",
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
"Show diff with previous version": "Mostra le differenze con la versione precedente",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Visibile al posto dell'ID Dispositivo nello stato del cluster. Negli altri dispositivi verrà presentato come nome predefinito opzionale.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Visibile al posto dell'ID Dispositivo nello stato del cluster. Se viene lasciato vuoto, verrà utilizzato il nome proposto dal dispositivo.",
|
||||
"Shutdown": "Arresta",
|
||||
"Shut Down": "Arresta",
|
||||
"Shutdown Complete": "Arresto Eseguito",
|
||||
"Simple": "Semplice",
|
||||
"Simple File Versioning": "Controllo Versione Semplice",
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
"Show diff with previous version": "前バージョンとの差分を表示",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "ステータス画面でデバイスIDの代わりに表示されます。他のデバイスに対してもデフォルトの名前として通知されます。",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "ステータス画面でデバイスIDの代わりに表示されます。空欄にすると相手側デバイスが通知してきた名前で更新されます。",
|
||||
"Shutdown": "シャットダウン",
|
||||
"Shut Down": "シャットダウン",
|
||||
"Shutdown Complete": "シャットダウン完了",
|
||||
"Simple File Versioning": "単純バージョン管理",
|
||||
"Single level wildcard (matches within a directory only)": "ワイルドカード (単一のディレクトリ内だけでマッチします)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "더 알아보기",
|
||||
"Learn more at {%url%}": "자세한 내용은 {{url}}을 참조하십시오.",
|
||||
"Limit": "제한",
|
||||
"Limit Bandwidth in LAN": "근거리 통신망(LAN)에 속도 제한 적용",
|
||||
"Listener Failures": "대기자 실패",
|
||||
"Listener Status": "대기자 현황",
|
||||
"Listeners": "대기자",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "이전 버전과의 diff 보기",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "기기 아이디를 대신해 기기 목록에서 나타납니다. 다른 기기에 선택적 기본값 이름으로 통보됩니다.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "기기 아이디를 대신해 기기 목록에서 나타납니다. 비워 둘 경우 다른 기기에서 통보받은 이름으로 갱신됩니다.",
|
||||
"Shutdown": "종료",
|
||||
"Shut Down": "종료",
|
||||
"Shutdown Complete": "종료 완료",
|
||||
"Simple": "간단",
|
||||
"Simple File Versioning": "간단한 파일 버전 관리",
|
||||
|
||||
@@ -337,7 +337,7 @@
|
||||
"Show diff with previous version": "Rodyti skirtumus su ankstesne versija",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Grupės būsenoje rodomas vietoje įrenginio vardo. Kiti įrenginiai matys kaip pasirinktinį vardą.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Grupės būsenoje rodomas vietoje įrenginio vardo. Bus atnaujintas į įrenginio vardą jei nieko neįrašysite.",
|
||||
"Shutdown": "Išjungti",
|
||||
"Shut Down": "Išjungti",
|
||||
"Shutdown Complete": "Sėkmingai išjungta",
|
||||
"Simple File Versioning": "Supaprastintas versijų valdymas",
|
||||
"Single level wildcard (matches within a directory only)": "Vieno lygio pakaitos simbolis (atitinka tik vieną katalogo lygį)",
|
||||
|
||||
@@ -339,7 +339,7 @@
|
||||
"Show diff with previous version": "Vis diff med forrige version",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vis i stedet for enhets-ID i gruppestatus. Vil bli kringkastet til andre enheter som et valgfritt forvalgsnavn.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vist i stedet for mappe-ID i gruppestatus. Vil bli oppdatert til navnet enheten kringkaster dersom tomt.",
|
||||
"Shutdown": "Avslutt",
|
||||
"Shut Down": "Avslutt",
|
||||
"Shutdown Complete": "Avslutning fullført",
|
||||
"Simple": "Enkel",
|
||||
"Simple File Versioning": "Enkel versjonskontroll",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"Allowed Networks": "Toegestane netwerken",
|
||||
"Alphabetic": "Alfabetisch",
|
||||
"Altered by ignoring deletes.": "Veranderd door het negeren van verwijderingen.",
|
||||
"Always turned on when the folder type is \"{%foldertype%}\".": "Altijd aanzetten als het map-type \"{{foldertype}}\" is.",
|
||||
"An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Een externe opdracht regelt het versiebeheer. Hij moet het bestand verwijderen uit de gedeelde map. Als het pad naar de toepassing spaties bevat, moet dit tussen aanhalingstekens geplaatst worden.",
|
||||
"Anonymous Usage Reporting": "Anonieme gebruikersstatistieken",
|
||||
"Anonymous usage report format has changed. Would you like to move to the new format?": "Het formaat voor anonieme gebruikersrapporten is gewijzigd. Wil je naar het nieuwe formaat overschakelen?",
|
||||
@@ -52,6 +53,7 @@
|
||||
"Body:": "Inhoud:",
|
||||
"Bugs": "Bugs",
|
||||
"Cancel": "Annuleren",
|
||||
"Cannot be enabled when the folder type is \"{%foldertype%}\".": "Kan niet aangezet worden als het map-type \"{{foldertype}}\" is.",
|
||||
"Changelog": "Wijzigingenlogboek",
|
||||
"Clean out after": "Opruimen na",
|
||||
"Cleaning Versions": "Versies opruimen",
|
||||
@@ -225,8 +227,9 @@
|
||||
"Learn more": "Lees meer",
|
||||
"Learn more at {%url%}": "Meer informatie op {{url}}",
|
||||
"Limit": "Begrenzing",
|
||||
"Listener Failures": "Luisteraarfouten",
|
||||
"Listener Status": "Luisteraarstatus",
|
||||
"Limit Bandwidth in LAN": "Beperk de bandbreedte op het lokale netwerk",
|
||||
"Listener Failures": "Luisteraarsfouten",
|
||||
"Listener Status": "Luisteraarsstatus",
|
||||
"Listeners": "Luisteraars",
|
||||
"Loading data...": "Gegevens laden...",
|
||||
"Loading...": "Laden...",
|
||||
@@ -368,7 +371,7 @@
|
||||
"Show diff with previous version": "Verschil met vorige versie weergeven",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Weergegeven in plaats van de apparaat-ID in de cluster-status. Zal aan andere apparaten voorgesteld worden als een optionele standaardnaam.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Weergegeven in plaats van de apparaat-ID in de clusterstatus. Zal bijgewerkt worden met de naam die het apparaat voorstelt wanneer leeg gelaten.",
|
||||
"Shutdown": "Afsluiten",
|
||||
"Shut Down": "Afsluiten",
|
||||
"Shutdown Complete": "Afsluiten voltooid",
|
||||
"Simple": "Eenvoudig",
|
||||
"Simple File Versioning": "Eenvoudig versiebeheer",
|
||||
@@ -386,6 +389,7 @@
|
||||
"Staggered File Versioning": "Gespreid versiebeheer",
|
||||
"Start Browser": "Browser starten",
|
||||
"Statistics": "Statistieken",
|
||||
"Stay logged in": "Blijf aangemeld",
|
||||
"Stopped": "Gestopt",
|
||||
"Stores and syncs only encrypted data. Folders on all connected devices need to be set up with the same password or be of type \"{%receiveEncrypted%}\" too.": "Bewaart en synchroniseert alleen versleutelde gegevens. Mappen op alle verbonden apparaten moeten met hetzelfde wachtwoord ingesteld worden of ook van het type \"{{receiveEncrypted}}\" zijn.",
|
||||
"Subject:": "Onderwerp:",
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
"Show QR": "Vis QR",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vist i staden for einings-ID-en i klyngjestatusen. Vil verta kringkasta til dei andre einingane som eit valfritt standardnamn.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vist i staden for mappe-ID-en i klyngjestatuses. Vil verta oppdatert til namnet eininga kringkastar dersom tomt.",
|
||||
"Shutdown": "Slå Av",
|
||||
"Shut Down": "Slå Av",
|
||||
"Shutdown Complete": "Slått av",
|
||||
"Simple File Versioning": "Enkel filutgåvehandtering",
|
||||
"Single level wildcard (matches within a directory only)": "Enkeltnivå-jokerteikn (søkjer berre i éi mappe)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Dowiedz się więcej",
|
||||
"Learn more at {%url%}": "Dowiedz się więcej na {{url}}",
|
||||
"Limit": "Ograniczenie",
|
||||
"Limit Bandwidth in LAN": "Ogranicz przepustowość w sieci lokalnej LAN",
|
||||
"Listener Failures": "Błędy nasłuchujących",
|
||||
"Listener Status": "Stan nasłuchujących",
|
||||
"Listeners": "Nasłuchujący",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Pokaż diff z poprzednią wersją",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Widoczna na liście urządzeń zamiast identyfikatora urządzenia. Będzie anonsowana do innych urządzeń jako opcjonalna nazwa domyślna.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Widoczna na liście urządzeń zamiast identyfikatora urządzenia. Zostanie zaktualizowana do nazwy anonsowanej przez urządzenie, jeżeli pozostanie pusta.",
|
||||
"Shutdown": "Wyłącz",
|
||||
"Shut Down": "Wyłącz",
|
||||
"Shutdown Complete": "Wyłączanie ukończone",
|
||||
"Simple": "Proste",
|
||||
"Simple File Versioning": "Proste wersjonowanie plików",
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
"Show diff with previous version": "Mostrar diferenças da versão anterior",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Mostrado no lugar do ID do dispositivo no indicador de estado do grupo. Será divulgado aos outros dispositivos como um nome opcional e pré-definido.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Mostrado no lugar do ID do dispositivo no indicador de estado do grupo. Será atualizado para o nome que o dispositivo divulga, caso seja deixado em branco.",
|
||||
"Shutdown": "Desligar",
|
||||
"Shut Down": "Desligar",
|
||||
"Shutdown Complete": "Desligamento completado",
|
||||
"Simple": "Simples",
|
||||
"Simple File Versioning": "Simples",
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
"Show diff with previous version": "Mostrar diferenças em relação à versão anterior",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Apresentado ao invés do ID do dispositivo no indicador de estado do grupo. Será divulgado aos outros dispositivos como um nome predefinido opcional.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Apresentado ao invés do ID do dispositivo no indicador de estado do grupo. Será actualizado para o nome que o dispositivo divulga, se for deixado em branco.",
|
||||
"Shutdown": "Desligar",
|
||||
"Shut Down": "Desligar",
|
||||
"Shutdown Complete": "Encerramento completado",
|
||||
"Simple": "Simples",
|
||||
"Simple File Versioning": "Simples",
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
"Show diff with previous version": "Show diff with previous version",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vizibil în locul ID-ului dispozitivului într-un grup. Va fi sugerat celorlalte dispozitive ca nume opţional. ",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vizibil în locul ID-ului dispozitivului într-un grup. Va fi înlocuit de numele sugerat de dispozitiv daca nu este completat. ",
|
||||
"Shutdown": "Opreşte",
|
||||
"Shut Down": "Opreşte",
|
||||
"Shutdown Complete": "Oprește Complet",
|
||||
"Simple File Versioning": "Versiuni simple ale documentelor",
|
||||
"Single level wildcard (matches within a directory only)": "Asterisc de nivel simplu (corespunde doar unui fişier)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Узнать больше",
|
||||
"Learn more at {%url%}": "Узнать больше на сайте {{url}}",
|
||||
"Limit": "Ограничение",
|
||||
"Limit Bandwidth in LAN": "Ограничить пропускную способность в локальной сети",
|
||||
"Listener Failures": "Ошибки прослушивателя",
|
||||
"Listener Status": "Статус прослушивателя",
|
||||
"Listeners": "Прослушиватель",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Показать различия с предыдущей версией",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Отображается вместо ID устройства в статусе группы. Будет разослан другим устройствам в качестве имени по умолчанию.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Отображается вместо ID устройства в статусе группы. Если поле не заполнено, то будет установлено имя, передаваемое этим устройством.",
|
||||
"Shutdown": "Выключить",
|
||||
"Shut Down": "Выключить",
|
||||
"Shutdown Complete": "Выключение",
|
||||
"Simple": "Просто",
|
||||
"Simple File Versioning": "Простое управление версиями файлов",
|
||||
|
||||
@@ -340,7 +340,7 @@
|
||||
"Show diff with previous version": "පෙර අනුවාදය සමඟ වෙනස පෙන්වන්න",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "පොකුරු තත්ත්වයේ උපාංග හැඳුනුම්පත වෙනුවට පෙන්වා ඇත. විකල්ප පෙරනිමි නාමයක් ලෙස වෙනත් උපාංග වෙත ප්රචාරණය කරනු ඇත.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "පොකුරු තත්ත්වයේ උපාංග හැඳුනුම්පත වෙනුවට පෙන්වා ඇත. හිස්ව තැබුවහොත් උපාංගය ප්රචාරණය කරන නමට යාවත්කාලීන වේ.",
|
||||
"Shutdown": "වසා දමන්න",
|
||||
"Shut Down": "වසා දමන්න",
|
||||
"Shutdown Complete": "වසා දැමීම සම්පූර්ණයි",
|
||||
"Simple": "සරල",
|
||||
"Simple File Versioning": "සරල ගොනු අනුවාදය",
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
"Show diff with previous version": "Ukázať rozdiely s predchádzajúcou verziou",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Zobrazované namiesto ID zariadenia v štatúte klastra. Toto pomenovanie bude oznamovať ostatným zariadeniam ako voliteľné predvolené pomenovanie.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Zobrazované namiesto ID zariadenia v klastri. Ak je ponechané prázdne, bude nahradené pomenovaním, ktoré oznamuje zariadenie.",
|
||||
"Shutdown": "Vypnutie",
|
||||
"Shut Down": "Vypnutie",
|
||||
"Shutdown Complete": "Vypnutie ukončené",
|
||||
"Simple": "Jednoduché",
|
||||
"Simple File Versioning": "Jednoduché verzie súborov",
|
||||
|
||||
@@ -315,7 +315,7 @@
|
||||
"Show diff with previous version": "Pokaži razliko s prejšnjo različico",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Prikazano namesto ID-ja naprave v stanju gruče. Oglašuje se drugim napravam kot neobvezno privzeto ime.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Prikazano namesto ID-ja naprave v stanju gruče. Če ostane prazno, bo posodobljeno na ime, ki ga oglašuje naprava.",
|
||||
"Shutdown": "Izklopi",
|
||||
"Shut Down": "Izklopi",
|
||||
"Shutdown Complete": "Izklop končan",
|
||||
"Simple File Versioning": "Enostvno beleženje različic datotek",
|
||||
"Single level wildcard (matches within a directory only)": "Enostopenjski nadomestni znak (ujema se samo v imeniku)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Läs mer",
|
||||
"Learn more at {%url%}": "Läs mer på {{url}}",
|
||||
"Limit": "Gräns",
|
||||
"Limit Bandwidth in LAN": "Begränsa bandbredd i LAN",
|
||||
"Listener Failures": "Lyssnarfel",
|
||||
"Listener Status": "Lyssnarstatus",
|
||||
"Listeners": "Lyssnare",
|
||||
@@ -315,8 +316,8 @@
|
||||
"Received data is already encrypted": "Mottagna data är redan krypterade",
|
||||
"Recent Changes": "Senaste ändringar",
|
||||
"Reduced by ignore patterns": "Minskas med ignoreringsmönster",
|
||||
"Relay LAN": "Relä LAN",
|
||||
"Relay WAN": "Relä WAN",
|
||||
"Relay LAN": "LAN-relä",
|
||||
"Relay WAN": "WAN-relä",
|
||||
"Release Notes": "Versionsanteckningar",
|
||||
"Release candidates contain the latest features and fixes. They are similar to the traditional bi-weekly Syncthing releases.": "Utgåvskandidater innehåller de senaste funktionerna och korrigeringarna. De liknar de traditionella Syncthing-utgåvorna som kommer ut varannan vecka.",
|
||||
"Remote Devices": "Fjärrenheter",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Visa skillnad med tidigare version",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Visas istället för enhets-ID i klusterstatus. Kommer att annonseras på andra enheter som ett valfritt standardnamn.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Visas istället för enhets-ID i klusterstatusen. Kommer att uppdateras till det namn som enheten annonserar om det lämnas tomt.",
|
||||
"Shutdown": "Stäng av",
|
||||
"Shut Down": "Stäng av",
|
||||
"Shutdown Complete": "Avstängning slutförd",
|
||||
"Simple": "Enkel",
|
||||
"Simple File Versioning": "Enkel filversionshantering",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Daha fazla bilgi edinin",
|
||||
"Learn more at {%url%}": "{{url}} adresinde daha fazla bilgi edinin",
|
||||
"Limit": "Sınır",
|
||||
"Limit Bandwidth in LAN": "LAN'da Bant Genişliğini Sınırla",
|
||||
"Listener Failures": "Dinleyici Hataları",
|
||||
"Listener Status": "Dinleyici Durumu",
|
||||
"Listeners": "Dinleyiciler",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Önceki sürüm ile farklılıkları göster",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Küme durumunda Cihaz Kimliği yerine gösterilir. İsteğe bağlı varsayılan ad olarak diğer cihazlara duyurulacaktır.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Küme durumunda Cihaz Kimliği yerine gösterilir. Boş bırakılırsa duyurulan cihaz adına güncellenecektir.",
|
||||
"Shutdown": "Kapat",
|
||||
"Shut Down": "Kapat",
|
||||
"Shutdown Complete": "Kapatma İşlemi Tamamlandı",
|
||||
"Simple": "Basit",
|
||||
"Simple File Versioning": "Basit Dosya Sürümlendirme",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "Дізнатися більше",
|
||||
"Learn more at {%url%}": "Дізнайтесь більше за посиланням {{url}}",
|
||||
"Limit": "Ліміт",
|
||||
"Limit Bandwidth in LAN": "Обмеження пропускної здатності в локальній мережі",
|
||||
"Listener Failures": "Помилки приймачів",
|
||||
"Listener Status": "Стан приймача",
|
||||
"Listeners": "Приймачі",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "Показати відмінності від попередньої версії",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Показується замість ID пристрою в статусі кластера. Буде розголошено іншим вузлам як опціональне типове ім’я.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Показується замість ID пристрою в статусі кластера. Буде оновлено ім’ям, яке розголошене пристроєм, якщо залишити порожнім.",
|
||||
"Shutdown": "Вимкнути",
|
||||
"Shut Down": "Вимкнути",
|
||||
"Shutdown Complete": "Вимикання завершене",
|
||||
"Simple": "Просте",
|
||||
"Simple File Versioning": "Просте версіювання",
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
"Show QR": "Hiển thị QR",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Hiển thị thay cho ID th.bị trong trạng thái cụm. Sẽ được giới thiệu đến các th.bị khác như tên mặc định tuỳ chọn.",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Hiển thị thay cho ID thiết bị trong trạng thái cụm. Nếu để trống sẽ được cập nhật thành tên mà thiết bị giới thiệu.",
|
||||
"Shutdown": "Tắt",
|
||||
"Shut Down": "Tắt",
|
||||
"Shutdown Complete": "Tắt hoàn tất",
|
||||
"Simple File Versioning": "Kiểu đơn giản",
|
||||
"Single level wildcard (matches within a directory only)": "Ký tự thay thế đơn cấp (phù hợp với chỉ một thư mục)",
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"Learn more": "了解更多",
|
||||
"Learn more at {%url%}": "了解更多请访问 {{url}}",
|
||||
"Limit": "限制",
|
||||
"Limit Bandwidth in LAN": "在局域网内限制带宽",
|
||||
"Listener Failures": "监听程序失败",
|
||||
"Listener Status": "监听程序状态",
|
||||
"Listeners": "监听程序",
|
||||
@@ -370,7 +371,7 @@
|
||||
"Show diff with previous version": "显示与以前版本的差异",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "在集群状态中显示该名称,而不是设备 ID。将作为可选的默认名称向其他设备通告。",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "在集群状态中显示该名称,而不是设备 ID。如果留空,将更新为设备通告的名称。",
|
||||
"Shutdown": "关闭",
|
||||
"Shut Down": "关闭",
|
||||
"Shutdown Complete": "关闭完成",
|
||||
"Simple": "简单",
|
||||
"Simple File Versioning": "简单文件版本控制",
|
||||
|
||||
@@ -340,7 +340,7 @@
|
||||
"Show diff with previous version": "顯示與先前版本的差異",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "在集群狀態中顯示該名稱,而不是設備 ID。將會作為當前設備的可選的默認名稱,報告給所有其他設備。",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "在集群狀態中顯示該名稱,而不是設備 ID。如果設置為空,則會使用目標設備自報的默認名稱。",
|
||||
"Shutdown": "關閉",
|
||||
"Shut Down": "關閉",
|
||||
"Shutdown Complete": "關閉完成",
|
||||
"Simple": "簡易",
|
||||
"Simple File Versioning": "簡易版本控制",
|
||||
|
||||
@@ -368,7 +368,7 @@
|
||||
"Show diff with previous version": "顯示與前一個版本的差異",
|
||||
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "代替裝置識別碼顯示在叢集狀態中。這段文字將會廣播到其他的裝置作為一個可選的預設名稱。",
|
||||
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "代替裝置識別碼顯示在叢集狀態中。本欄若未填寫則將被更新為此裝置所廣播的名稱。",
|
||||
"Shutdown": "關閉",
|
||||
"Shut Down": "關閉",
|
||||
"Shutdown Complete": "關閉完成",
|
||||
"Simple": "簡單",
|
||||
"Simple File Versioning": "簡單檔案版本控制",
|
||||
|
||||
@@ -108,27 +108,23 @@
|
||||
<li><a href="" ng-click="about.show()"><span class="fa fa-fw fa-heart"></span> <span translate>About</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li ng-if="authenticated || config.gui.debugging" class="dropdown action-menu">
|
||||
<li ng-if="authenticated" class="dropdown action-menu">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="fa fa-cog"></span>
|
||||
<span class="hidden-xs" translate>Actions</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-if="authenticated"><a href="" ng-click="showSettings()"><span class="fa fa-fw fa-cog"></span> <span translate>Settings</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="showDeviceIdentification(thisDevice())"><span class="fa fa-fw fa-qrcode"></span> <span translate>Show ID</span></a></li>
|
||||
|
||||
<li ng-if="authenticated" class="divider" aria-hidden="true"></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="advanced()"><span class="fa fa-fw fa-cogs"></span> <span translate>Advanced</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="logging.show()"><span class="fa fa-fw fa-wrench"></span> <span translate>Logs</span></a></li>
|
||||
|
||||
<li class="divider" aria-hidden="true" ng-if="config.gui.debugging"></li>
|
||||
<li><a href="/rest/debug/support" target="_blank" ng-if="config.gui.debugging"><span class="fa fa-fw fa-user-md"></span> <span translate>Support Bundle</span></a></li>
|
||||
|
||||
<li ng-if="authenticated" class="divider" aria-hidden="true"></li>
|
||||
<li ng-if="authenticated && isAuthEnabled()"><a href="" ng-click="logout()"><span class="far fa-fw fa-sign-out"></span> <span translate>Log Out</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="restart()"><span class="fa fa-fw fa-refresh"></span> <span translate>Restart</span></a></li>
|
||||
<li ng-if="authenticated"><a href="" ng-click="shutdown()"><span class="fa fa-fw fa-power-off"></span> <span translate>Shutdown</span></a></li>
|
||||
<li><a href="" ng-click="showSettings()"><span class="fa fa-fw fa-cog"></span> <span translate>Settings</span></a></li>
|
||||
<li><a href="" ng-click="advanced()"><span class="fa fa-fw fa-cogs"></span> <span translate>Advanced</span></a></li>
|
||||
<li class="divider" aria-hidden="true"></li>
|
||||
<li><a href="" ng-click="showDeviceIdentification(thisDevice())"><span class="fa fa-fw fa-qrcode"></span> <span translate>Show ID</span></a></li>
|
||||
<li><a href="" ng-click="logging.show()"><span class="fa fa-fw fa-wrench"></span> <span translate>Logs</span></a></li>
|
||||
<li><a href="/rest/debug/support" target="_blank"><span class="fa fa-fw fa-user-md"></span> <span translate>Support Bundle</span></a></li>
|
||||
<li class="divider" aria-hidden="true"></li>
|
||||
<li ng-if="isAuthEnabled()"><a href="" ng-click="logout()"><span class="far fa-fw fa-sign-out"></span> <span translate>Log Out</span></a></li>
|
||||
<li><a href="" ng-click="restart()"><span class="fa fa-fw fa-refresh"></span> <span translate>Restart</span></a></li>
|
||||
<li><a href="" ng-click="shutdown()"><span class="fa fa-fw fa-power-off"></span> <span translate>Shut Down</span></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -333,7 +329,7 @@
|
||||
</p>
|
||||
<table>
|
||||
<tr ng-repeat="(id, err) in fsWatcherErrorMap()">
|
||||
<td>{{folderLabel(id)}}</td><td>{{err}}</td>
|
||||
<td>{{folderLabel(id)}}: </td><td>{{err}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@@ -619,10 +615,10 @@
|
||||
<button type="button" class="btn btn-sm btn-danger pull-left" ng-click="revertOverrideConfirmationModal('override', folder.id)" ng-if="folderStatus(folder) == 'outofsync' && folder.type == 'sendonly'">
|
||||
<span class="fas fa-arrow-circle-up"></span> <span translate>Override Changes</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-danger pull-left" ng-click="revertOverrideConfirmationModal('revert', folder.id)" ng-if="hasReceiveOnlyChanged(folder)">
|
||||
<button type="button" class="btn btn-sm btn-danger pull-left" ng-click="revertOverrideConfirmationModal('revert', folder.id)" ng-if="hasReceiveOnlyChanged(folder) && ['outofsync', 'faileditems', 'localadditions'].indexOf(folderStatus(folder)) >= 0">
|
||||
<span class="fa fa-arrow-circle-down"></span> <span translate>Revert Local Changes</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-danger pull-left" ng-click="revertOverrideConfirmationModal('deleteEnc', folder.id)" ng-if="hasReceiveEncryptedItems(folder)">
|
||||
<button type="button" class="btn btn-sm btn-danger pull-left" ng-click="revertOverrideConfirmationModal('deleteEnc', folder.id)" ng-if="hasReceiveEncryptedItems(folder) && ['outofsync', 'faileditems', 'localunencrypted'].indexOf(folderStatus(folder)) >= 0">
|
||||
<span class="fa fa-minus-circle"></span> <span translate>Delete Unexpected Items</span>
|
||||
</button>
|
||||
<span class="pull-right">
|
||||
@@ -874,11 +870,11 @@
|
||||
<td ng-if="!connections[deviceCfg.deviceID].connected" class="text-right">
|
||||
<span ng-repeat="addr in deviceCfg.addresses">
|
||||
<span tooltip data-original-title="{{'Configured' | translate}}">{{addr}}</span><br>
|
||||
<small ng-if="system.lastDialStatus[addr].error" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
<small ng-if="system.lastDialStatus[addr].error && !deviceCfg.paused" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
</span>
|
||||
<span ng-repeat="addr in discoveryCache[deviceCfg.deviceID].addresses">
|
||||
<span tooltip data-original-title="{{'Discovered' | translate}}">{{addr}}</span><br>
|
||||
<small ng-if="system.lastDialStatus[addr].error" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
<small ng-if="system.lastDialStatus[addr].error && !deviceCfg.paused" tooltip data-original-title="{{system.lastDialStatus[addr].error}}" class="text-danger">{{abbreviatedError(addr)}}<br></small>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<h4 class="text-center" translate>The Syncthing Authors</h4>
|
||||
<div class="row">
|
||||
<div class="col-md-12" id="contributor-list">
|
||||
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcin Dziadus, Marcus B Spencer, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy van der Vorst, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., 佛跳墙, 落心
|
||||
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, ardevd, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Ashish Bhate, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Daniil Gentili, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcel Meyer, Marcin Dziadus, Marcus B Spencer, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, pullmerge, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tommy van der Vorst, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., yparitcher, 佛跳墙, 落心
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,7 +58,6 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
|
||||
<li><a href="https://github.com/calmh/xdr">calmh/xdr</a>, Copyright © 2014 Jakob Borg.</li>
|
||||
<li><a href="https://github.com/ccding/go-stun">ccding/go-stun</a>, Copyright © 2016 Cong Ding.</li>
|
||||
<li><a href="https://github.com/cespare/xxhash/v2">cespare/xxhash/v2</a>, Copyright © 2016 Caleb Spare.</li>
|
||||
<li><a href="https://github.com/chmduquesne/rollinghash">chmduquesne/rollinghash</a>, Copyright © 2015 Christophe-Marie Duquesne.</li>
|
||||
<li><a href="https://github.com/cpuguy83/go-md2man/v2">cpuguy83/go-md2man/v2</a>, Copyright © 2014 Brian Goff.</li>
|
||||
<li><a href="https://github.com/davecgh/go-spew">davecgh/go-spew</a>, Copyright © 2012-2016 Dave Collins.</li>
|
||||
<li><a href="https://github.com/go-asn1-ber/asn1-ber">go-asn1-ber/asn1-ber</a>, Copyright © 2011-2015 Michael Mitton (mmitton@gmail.com).</li>
|
||||
@@ -70,14 +69,15 @@ Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf,
|
||||
<li><a href="https://github.com/protocolbuffers/protobuf-go">google.golang.org/protobuf</a>, Copyright © 2018 The Go Authors.</li>
|
||||
<li><a href="https://github.com/google/uuid">google/uuid</a>, Copyright © 2009,2014 Google Inc.</li>
|
||||
<li><a href="https://gopkg.in/yaml.v3">gopkg.in/yaml.v3</a>, Copyright © 2025, the gopkg.in/yaml.v3 authors.</li>
|
||||
<li><a href="https://github.com/greatroar/blobloom">greatroar/blobloom</a>, Copyright © 2020-2024 the Blobloom authors.</li>
|
||||
<li><a href="https://github.com/hashicorp/errwrap">hashicorp/errwrap</a>, Copyright © 2014 HashiCorp, Inc.</li>
|
||||
<li><a href="https://github.com/hashicorp/go-multierror">hashicorp/go-multierror</a>, Copyright © 2014 HashiCorp, Inc.</li>
|
||||
<li><a href="https://github.com/hashicorp/golang-lru">hashicorp/golang-lru</a>, Copyright © 2014 HashiCorp, Inc.</li>
|
||||
<li><a href="https://github.com/jackpal/gateway">jackpal/gateway</a>, Copyright © 2010 Jack Palevich.</li>
|
||||
<li><a href="https://github.com/jackpal/go-nat-pmp">jackpal/go-nat-pmp</a>, Copyright 2013 John Howard Palevich.</li>
|
||||
<li><a href="https://github.com/jmoiron/sqlx">jmoiron/sqlx</a>, Copyright © 2013, Jason Moiron.</li>
|
||||
<li><a href="https://github.com/julienschmidt/httprouter">julienschmidt/httprouter</a>, Copyright © 2013, Julien Schmidt.</li>
|
||||
<li><a href="https://github.com/kballard/go-shellquote">kballard/go-shellquote</a>, Copyright © 2014 Kevin Ballard.</li>
|
||||
<li><a href="https://github.com/mattn/go-sqlite3">mattn/go-sqlite3</a>, Copyright © 2014 Yasuhiro Matsumoto.</li>
|
||||
<li><a href="https://github.com/miscreant/miscreant.go">miscreant/miscreant.go</a>, Copyright © 2017-2019 The Miscreant Developers.</li>
|
||||
<li><a href="https://github.com/munnerz/goautoneg">munnerz/goautoneg</a>, Copyright © 2011, Open Knowledge Foundation Ltd.</li>
|
||||
<li><a href="https://github.com/pierrec/lz4">pierrec/lz4</a>, Copyright © 2015 Pierre Curto.</li>
|
||||
|
||||
@@ -34,7 +34,7 @@ angular.module('syncthing.core')
|
||||
middleCol = Math.ceil(size / 2) - 1;
|
||||
|
||||
if (value) {
|
||||
value = value.toString().replace(/[\W_]/i, '');
|
||||
value = value.toString().replace(/[\W_]/g, '');
|
||||
|
||||
for (row = 0; row < size; ++row) {
|
||||
for (col = middleCol; col > -1; --col) {
|
||||
|
||||
@@ -16,11 +16,16 @@
|
||||
<label translate>Available debug logging facilities:</label>
|
||||
<table class="table table-condensed table-striped">
|
||||
<tbody>
|
||||
<tr ng-repeat="(name, data) in logging.facilities">
|
||||
<td>
|
||||
<input type="checkbox" ng-model="data.enabled" ng-change="logging.onFacilityChange(name)" ng-disabled="data.enabled == null"> <span>{{ name }}</span>
|
||||
<tr ng-repeat="(key, level) in logging.facilities.levels">
|
||||
<td>{{ logging.facilities.packages[key] }} (<code>{{ key }}</code>)</td>
|
||||
<td class="form-group">
|
||||
<select class="form-control" ng-model="logging.facilities.levels[key]" ng-change="logging.onFacilityChange()" ng-disabled="logging.facilities.updating">
|
||||
<option value="DEBUG" translate>Debug</option>
|
||||
<option value="INFO" translate>Info</option>
|
||||
<option value="WARN" translate>Warning</option>
|
||||
<option value="ERROR" translate>Error</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>{{ data.description }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -27,7 +27,7 @@ angular.module('syncthing.core')
|
||||
// before modal show animation
|
||||
$(element).on('show.bs.modal', function () {
|
||||
|
||||
// cycle through open modals, acertain modal with highest z-index
|
||||
// cycle through open modals, ascertain modal with highest z-index
|
||||
var largestZ = 1040;
|
||||
$('.modal:visible').each(function (i) {
|
||||
var thisZ = parseInt($(this).css('zIndex'));
|
||||
|
||||
@@ -1568,16 +1568,8 @@ angular.module('syncthing.core')
|
||||
$scope.logging = {
|
||||
facilities: {},
|
||||
refreshFacilities: function () {
|
||||
$http.get(urlbase + '/system/debug').success(function (data) {
|
||||
var facilities = {};
|
||||
data.enabled = data.enabled || [];
|
||||
$.each(data.facilities, function (key, value) {
|
||||
facilities[key] = {
|
||||
description: value,
|
||||
enabled: data.enabled.indexOf(key) > -1
|
||||
}
|
||||
})
|
||||
$scope.logging.facilities = facilities;
|
||||
$http.get(urlbase + '/system/loglevels').success(function (data) {
|
||||
$scope.logging.facilities = data;
|
||||
}).error($scope.emitHTTPError);
|
||||
},
|
||||
show: function () {
|
||||
@@ -1597,13 +1589,10 @@ angular.module('syncthing.core')
|
||||
});
|
||||
showModal('#logViewer');
|
||||
},
|
||||
onFacilityChange: function (facility) {
|
||||
var enabled = $scope.logging.facilities[facility].enabled;
|
||||
// Disable checkboxes while we're in flight.
|
||||
$.each($scope.logging.facilities, function (key) {
|
||||
$scope.logging.facilities[key].enabled = null;
|
||||
})
|
||||
$http.post(urlbase + '/system/debug?' + (enabled ? 'enable=' : 'disable=') + facility)
|
||||
onFacilityChange: function () {
|
||||
// Disable editing while we're in flight.
|
||||
$scope.logging.facilities.updating = true;
|
||||
$http.post(urlbase + '/system/loglevels', $scope.logging.facilities.levels)
|
||||
.success($scope.logging.refreshFacilities)
|
||||
.error($scope.emitHTTPError);
|
||||
},
|
||||
@@ -1626,7 +1615,7 @@ angular.module('syncthing.core')
|
||||
content: function () {
|
||||
var content = "";
|
||||
$.each($scope.logging.entries, function (idx, entry) {
|
||||
content += entry.when.split('.')[0].replace('T', ' ') + ' ' + entry.message + "\n";
|
||||
content += entry.when.split('.')[0].replace('T', ' ') + ' ' + entry.level + ' ' + entry.message + "\n";
|
||||
});
|
||||
return content;
|
||||
},
|
||||
|
||||
@@ -210,6 +210,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input id="LimitBandwidthInLan" type="checkbox" ng-model="tmpOptions.limitBandwidthInLan" /> <span translate>Limit Bandwidth in LAN</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
|
||||
2
gui/default/vendor/fancytree/LICENSE.txt
vendored
2
gui/default/vendor/fancytree/LICENSE.txt
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright 2008-2021 Martin Wendt,
|
||||
Copyright 2008-2023 Martin Wendt,
|
||||
https://wwWendt.de/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,9 @@ type Counts struct {
|
||||
Symlinks int
|
||||
Deleted int
|
||||
Bytes int64
|
||||
Sequence int64 // zero for the global state
|
||||
DeviceID protocol.DeviceID // device ID for remote devices, or special values for local/global
|
||||
LocalFlags uint32 // the local flag for this count bucket
|
||||
Sequence int64 // zero for the global state
|
||||
DeviceID protocol.DeviceID // device ID for remote devices, or special values for local/global
|
||||
LocalFlags protocol.FlagLocal // the local flag for this count bucket
|
||||
}
|
||||
|
||||
func (c Counts) Add(other Counts) Counts {
|
||||
|
||||
@@ -100,10 +100,9 @@ type FileMetadata struct {
|
||||
Sequence int64
|
||||
ModNanos int64
|
||||
Size int64
|
||||
LocalFlags int64
|
||||
LocalFlags protocol.FlagLocal
|
||||
Type protocol.FileInfoType
|
||||
Deleted bool
|
||||
Invalid bool
|
||||
}
|
||||
|
||||
func (f *FileMetadata) ModTime() time.Time {
|
||||
@@ -121,3 +120,7 @@ func (f *FileMetadata) IsDirectory() bool {
|
||||
func (f *FileMetadata) ShouldConflict() bool {
|
||||
return f.LocalFlags&protocol.LocalConflictFlags != 0
|
||||
}
|
||||
|
||||
func (f *FileMetadata) IsInvalid() bool {
|
||||
return f.LocalFlags.IsInvalid()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ var (
|
||||
Namespace: "syncthing",
|
||||
Subsystem: "db",
|
||||
Name: "operations_current",
|
||||
Help: "Number of database operations currently ongoing, per folder and operation",
|
||||
}, []string{"folder", "operation"})
|
||||
metricTotalOperationSeconds = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: "syncthing",
|
||||
|
||||
@@ -9,9 +9,9 @@ package olddb
|
||||
import (
|
||||
"encoding/binary"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/db/olddb/backend"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
)
|
||||
|
||||
// A smallIndex is an in memory bidirectional []byte to uint32 map. It gives
|
||||
@@ -32,7 +32,6 @@ func newSmallIndex(db backend.Backend, prefix []byte) *smallIndex {
|
||||
prefix: prefix,
|
||||
id2val: make(map[uint32]string),
|
||||
val2id: make(map[string]uint32),
|
||||
mut: sync.NewMutex(),
|
||||
}
|
||||
idx.load()
|
||||
return idx
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"database/sql"
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -22,7 +23,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
const currentSchemaVersion = 1
|
||||
const currentSchemaVersion = 3
|
||||
|
||||
//go:embed sql/**
|
||||
var embedded embed.FS
|
||||
@@ -44,7 +45,12 @@ type baseDB struct {
|
||||
func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScripts []string) (*baseDB, error) {
|
||||
// Open the database with options to enable foreign keys and recursive
|
||||
// triggers (needed for the delete+insert triggers on row replace).
|
||||
sqlDB, err := sqlx.Open(dbDriver, "file:"+path+"?"+commonOptions)
|
||||
pathURL := url.URL{
|
||||
Scheme: "file",
|
||||
Path: fileToUriPath(path),
|
||||
RawQuery: commonOptions,
|
||||
}
|
||||
sqlDB, err := sqlx.Open(dbDriver, pathURL.String())
|
||||
if err != nil {
|
||||
return nil, wrap(err)
|
||||
}
|
||||
@@ -62,6 +68,17 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
|
||||
baseName: filepath.Base(path),
|
||||
sql: sqlDB,
|
||||
statements: make(map[string]*sqlx.Stmt),
|
||||
tplInput: map[string]any{
|
||||
"FlagLocalUnsupported": protocol.FlagLocalUnsupported,
|
||||
"FlagLocalIgnored": protocol.FlagLocalIgnored,
|
||||
"FlagLocalMustRescan": protocol.FlagLocalMustRescan,
|
||||
"FlagLocalReceiveOnly": protocol.FlagLocalReceiveOnly,
|
||||
"FlagLocalGlobal": protocol.FlagLocalGlobal,
|
||||
"FlagLocalNeeded": protocol.FlagLocalNeeded,
|
||||
"FlagLocalRemoteInvalid": protocol.FlagLocalRemoteInvalid,
|
||||
"LocalInvalidFlags": protocol.LocalInvalidFlags,
|
||||
"SyncthingVersion": build.LongVersion,
|
||||
},
|
||||
}
|
||||
|
||||
for _, script := range schemaScripts {
|
||||
@@ -96,19 +113,19 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
|
||||
return nil, wrap(err)
|
||||
}
|
||||
|
||||
db.tplInput = map[string]any{
|
||||
"FlagLocalUnsupported": protocol.FlagLocalUnsupported,
|
||||
"FlagLocalIgnored": protocol.FlagLocalIgnored,
|
||||
"FlagLocalMustRescan": protocol.FlagLocalMustRescan,
|
||||
"FlagLocalReceiveOnly": protocol.FlagLocalReceiveOnly,
|
||||
"FlagLocalGlobal": protocol.FlagLocalGlobal,
|
||||
"FlagLocalNeeded": protocol.FlagLocalNeeded,
|
||||
"SyncthingVersion": build.LongVersion,
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func fileToUriPath(path string) string {
|
||||
path = filepath.ToSlash(path)
|
||||
if (build.IsWindows && len(path) >= 2 && path[1] == ':') ||
|
||||
(strings.HasPrefix(path, "//") && !strings.HasPrefix(path, "///")) {
|
||||
// Add an extra leading slash for Windows drive letter or UNC path
|
||||
path = "/" + path
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (s *baseDB) Close() error {
|
||||
s.updateLock.Lock()
|
||||
s.statementsMut.Lock()
|
||||
@@ -151,15 +168,8 @@ func (s *baseDB) stmt(tpl string) stmt {
|
||||
return stmt
|
||||
}
|
||||
|
||||
// Apply template expansions
|
||||
var sb strings.Builder
|
||||
compTpl := template.Must(template.New("tpl").Funcs(tplFuncs).Parse(tpl))
|
||||
if err := compTpl.Execute(&sb, s.tplInput); err != nil {
|
||||
panic("bug: bad template: " + err.Error())
|
||||
}
|
||||
|
||||
// Prepare and cache
|
||||
stmt, err := s.sql.Preparex(sb.String())
|
||||
stmt, err := s.sql.Preparex(s.expandTemplateVars(tpl))
|
||||
if err != nil {
|
||||
return failedStmt{err}
|
||||
}
|
||||
@@ -167,6 +177,17 @@ func (s *baseDB) stmt(tpl string) stmt {
|
||||
return stmt
|
||||
}
|
||||
|
||||
// expandTemplateVars just applies template expansions to the template
|
||||
// string, or dies trying
|
||||
func (s *baseDB) expandTemplateVars(tpl string) string {
|
||||
var sb strings.Builder
|
||||
compTpl := template.Must(template.New("tpl").Funcs(tplFuncs).Parse(tpl))
|
||||
if err := compTpl.Execute(&sb, s.tplInput); err != nil {
|
||||
panic("bug: bad template: " + err.Error())
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
type stmt interface {
|
||||
Exec(args ...any) (sql.Result, error)
|
||||
Get(dest any, args ...any) error
|
||||
@@ -211,7 +232,7 @@ nextScript:
|
||||
// separately. We require it on a separate line because there are
|
||||
// also statement-internal semicolons in the triggers.
|
||||
for _, stmt := range strings.Split(string(bs), "\n;") {
|
||||
if _, err := tx.Exec(stmt); err != nil {
|
||||
if _, err := tx.Exec(s.expandTemplateVars(stmt)); err != nil {
|
||||
return wrap(err, stmt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -77,7 +79,7 @@ func (s *DB) getFolderDB(folder string, create bool) (*folderDB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
l.Debugf("Folder %s in database %s", folder, dbName)
|
||||
slog.Debug("Folder database opened", "folder", folder, "db", dbName)
|
||||
path := dbName
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Join(s.pathBase, dbName)
|
||||
@@ -255,7 +257,7 @@ func (s *DB) ListDevicesForFolder(folder string) ([]protocol.DeviceID, error) {
|
||||
func (s *DB) RemoteSequences(folder string) (map[protocol.DeviceID]int64, error) {
|
||||
fdb, err := s.getFolderDB(folder, false)
|
||||
if errors.Is(err, errNoSuchFolder) {
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -376,6 +378,22 @@ func (s *DB) DropDevice(device protocol.DeviceID) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DB) DebugCounts(out io.Writer, folder string) error {
|
||||
fdb, err := s.getFolderDB(folder, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fdb.DebugCounts(out)
|
||||
}
|
||||
|
||||
func (s *DB) DebugFilePattern(out io.Writer, folder, name string) error {
|
||||
fdb, err := s.getFolderDB(folder, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fdb.DebugFilePattern(out, name)
|
||||
}
|
||||
|
||||
// forEachFolder runs the function for each currently open folderDB,
|
||||
// returning the first error that was encountered.
|
||||
func (s *DB) forEachFolder(fn func(fdb *folderDB) error) error {
|
||||
|
||||
@@ -268,6 +268,57 @@ func TestDontNeedIgnored(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDontNeedRemoteInvalid(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := OpenTemp()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := db.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
// A remote file with the invalid bit set
|
||||
files := []protocol.FileInfo{
|
||||
genFile("test1", 1, 103),
|
||||
}
|
||||
files[0].LocalFlags = protocol.FlagLocalRemoteInvalid
|
||||
err = db.Update(folderID, protocol.DeviceID{42}, files)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// It's not part of the global size
|
||||
s, err := db.CountGlobal(folderID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s.Bytes != 0 || s.Files != 0 {
|
||||
t.Log(s)
|
||||
t.Error("bad global")
|
||||
}
|
||||
|
||||
// We don't need it
|
||||
s, err = db.CountNeed(folderID, protocol.LocalDeviceID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s.Bytes != 0 || s.Files != 0 {
|
||||
t.Log(s)
|
||||
t.Error("bad need")
|
||||
}
|
||||
|
||||
// It shouldn't show up in the need list
|
||||
names := mustCollect[protocol.FileInfo](t)(db.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderAlphabetic, 0, 0))
|
||||
if len(names) != 0 {
|
||||
t.Log(names)
|
||||
t.Error("need no files")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteDontNeedLocalIgnored(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -517,3 +568,59 @@ func TestNeedPagination(t *testing.T) {
|
||||
t.Error("bad need")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletedAfterConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// A delete that comes after a conflict should be applied, not lose the
|
||||
// conflict and suddenly cause an old conflict version to become
|
||||
// promoted.
|
||||
|
||||
// D:\syncthing-windows-amd64-v2.0.0-rc.22.dev.11.gff88430e>syncthing --home=c:\PortableApp\SyncTrayzorPortable-x64\data\syncthing debug database-file tnhbr-gxtuf TreeSizeFreeSetup.exe
|
||||
// DEVICE TYPE NAME SEQUENCE DELETED MODIFIED SIZE FLAGS VERSION BLOCKLIST
|
||||
// -local- FILE TreeSizeFreeSetup.exe 499 del 2025-07-04T11:52:36.2804841Z 0 ------- HZJYWFM:1751507473,OMKHRPB:1751629956 -nil-
|
||||
// J5WNYJ6 FILE TreeSizeFreeSetup.exe 500 del 2025-07-04T11:52:36.2804841Z 0 ------- HZJYWFM:1751507473,OMKHRPB:1751629956 -nil-
|
||||
// 23NHXGS FILE TreeSizeFreeSetup.exe 445 --- 2025-06-23T03:16:10.2804841Z 13832808 -nG---- HZJYWFM:1751507473 7B4kLitF
|
||||
// JKX6ZDN FILE TreeSizeFreeSetup.exe 320 --- 2025-06-23T03:16:10.2804841Z 13832808 ------- JKX6ZDN:1750992570 7B4kLitF
|
||||
|
||||
db, err := OpenTemp()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := db.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
// A file, updated by some remote device. This file is an old, conflicted copy.
|
||||
file := genFile("test1", 1, 101)
|
||||
file.ModifiedS = 1750992570
|
||||
file.Version = protocol.Vector{Counters: []protocol.Counter{{ID: 5 << 60, Value: 1750992570}}}
|
||||
if err := db.Update(folderID, protocol.DeviceID{5}, []protocol.FileInfo{file}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The file, updated by a newer remote device. This file is the newer, conflict-winning copy.
|
||||
file.ModifiedS = 1751507473
|
||||
file.Version = protocol.Vector{Counters: []protocol.Counter{{ID: 2 << 60, Value: 1751507473}}}
|
||||
if err := db.Update(folderID, protocol.DeviceID{2}, []protocol.FileInfo{file}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The file, deleted locally after syncing the file from the remote above..
|
||||
file.SetDeleted(4)
|
||||
if err := db.Update(folderID, protocol.LocalDeviceID, []protocol.FileInfo{file}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// The delete should be the global version
|
||||
f, _, err := db.GetGlobalFile(folderID, "test1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !f.IsDeleted() {
|
||||
t.Log(f)
|
||||
t.Error("should be deleted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,22 +7,27 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/internal/db"
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
)
|
||||
|
||||
const maxDBConns = 16
|
||||
const (
|
||||
maxDBConns = 16
|
||||
minDeleteRetention = 24 * time.Hour
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
*baseDB
|
||||
|
||||
pathBase string
|
||||
deleteRetention time.Duration
|
||||
|
||||
*baseDB
|
||||
|
||||
folderDBsMut sync.RWMutex
|
||||
folderDBs map[string]*folderDB
|
||||
folderDBOpener func(folder, path string, deleteRetention time.Duration) (*folderDB, error)
|
||||
@@ -34,7 +39,11 @@ type Option func(*DB)
|
||||
|
||||
func WithDeleteRetention(d time.Duration) Option {
|
||||
return func(s *DB) {
|
||||
s.deleteRetention = d
|
||||
if d <= 0 {
|
||||
s.deleteRetention = 0
|
||||
} else {
|
||||
s.deleteRetention = max(d, minDeleteRetention)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,10 +59,14 @@ func Open(path string, opts ...Option) (*DB, error) {
|
||||
"sql/schema/common/*",
|
||||
"sql/schema/main/*",
|
||||
}
|
||||
migrations := []string{
|
||||
"sql/migrations/common/*",
|
||||
"sql/migrations/main/*",
|
||||
}
|
||||
|
||||
os.MkdirAll(path, 0o700)
|
||||
_ = os.MkdirAll(path, 0o700)
|
||||
mainPath := filepath.Join(path, "main.db")
|
||||
mainBase, err := openBase(mainPath, maxDBConns, pragmas, schemas, nil)
|
||||
mainBase, err := openBase(mainPath, maxDBConns, pragmas, schemas, migrations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -88,10 +101,14 @@ func OpenForMigration(path string) (*DB, error) {
|
||||
"sql/schema/common/*",
|
||||
"sql/schema/main/*",
|
||||
}
|
||||
migrations := []string{
|
||||
"sql/migrations/common/*",
|
||||
"sql/migrations/main/*",
|
||||
}
|
||||
|
||||
os.MkdirAll(path, 0o700)
|
||||
_ = os.MkdirAll(path, 0o700)
|
||||
mainPath := filepath.Join(path, "main.db")
|
||||
mainBase, err := openBase(mainPath, 1, pragmas, schemas, nil)
|
||||
mainBase, err := openBase(mainPath, 1, pragmas, schemas, migrations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -120,7 +137,7 @@ func OpenTemp() (*DB, error) {
|
||||
return nil, wrap(err)
|
||||
}
|
||||
path := filepath.Join(dir, "db")
|
||||
l.Debugln("Test DB in", path)
|
||||
slog.Debug("Test DB", slogutil.FilePath(path))
|
||||
return Open(path)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,18 +9,18 @@ package sqlite
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/syncthing/syncthing/internal/db"
|
||||
"github.com/syncthing/syncthing/internal/slogutil"
|
||||
"github.com/thejerf/suture/v4"
|
||||
)
|
||||
|
||||
const (
|
||||
internalMetaPrefix = "dbsvc"
|
||||
lastMaintKey = "lastMaint"
|
||||
defaultDeleteRetention = 180 * 24 * time.Hour
|
||||
minDeleteRetention = 24 * time.Hour
|
||||
internalMetaPrefix = "dbsvc"
|
||||
lastMaintKey = "lastMaint"
|
||||
)
|
||||
|
||||
func (s *DB) Service(maintenanceInterval time.Duration) suture.Service {
|
||||
@@ -56,7 +56,7 @@ func (s *Service) Serve(ctx context.Context) error {
|
||||
if wait < 0 {
|
||||
wait = time.Minute
|
||||
}
|
||||
l.Debugln("Next periodic run in", wait)
|
||||
slog.DebugContext(ctx, "Next periodic run due", "after", wait)
|
||||
|
||||
timer := time.NewTimer(wait)
|
||||
for {
|
||||
@@ -71,34 +71,36 @@ func (s *Service) Serve(ctx context.Context) error {
|
||||
}
|
||||
|
||||
timer.Reset(s.maintenanceInterval)
|
||||
l.Debugln("Next periodic run in", s.maintenanceInterval)
|
||||
slog.DebugContext(ctx, "Next periodic run due", "after", s.maintenanceInterval)
|
||||
_ = s.internalMeta.PutTime(lastMaintKey, time.Now())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) periodic(ctx context.Context) error {
|
||||
t0 := time.Now()
|
||||
l.Debugln("Periodic start")
|
||||
slog.DebugContext(ctx, "Periodic start")
|
||||
|
||||
t1 := time.Now()
|
||||
defer func() { l.Debugln("Periodic done in", time.Since(t1), "+", t1.Sub(t0)) }()
|
||||
defer func() { slog.DebugContext(ctx, "Periodic done in", "t1", time.Since(t1), "t0t1", t1.Sub(t0)) }()
|
||||
|
||||
s.sdb.updateLock.Lock()
|
||||
tidy(ctx, s.sdb.sql)
|
||||
err := tidy(ctx, s.sdb.sql)
|
||||
s.sdb.updateLock.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return wrap(s.sdb.forEachFolder(func(fdb *folderDB) error {
|
||||
fdb.updateLock.Lock()
|
||||
defer fdb.updateLock.Unlock()
|
||||
|
||||
if err := garbageCollectOldDeletedLocked(fdb); err != nil {
|
||||
if err := garbageCollectOldDeletedLocked(ctx, fdb); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
if err := garbageCollectBlocklistsAndBlocksLocked(ctx, fdb); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
tidy(ctx, fdb.sql)
|
||||
return nil
|
||||
return tidy(ctx, fdb.sql)
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -116,15 +118,16 @@ func tidy(ctx context.Context, db *sqlx.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func garbageCollectOldDeletedLocked(fdb *folderDB) error {
|
||||
func garbageCollectOldDeletedLocked(ctx context.Context, fdb *folderDB) error {
|
||||
l := slog.With("fdb", fdb.baseDB)
|
||||
if fdb.deleteRetention <= 0 {
|
||||
l.Debugln(fdb.baseName, "delete retention is infinite, skipping cleanup")
|
||||
slog.DebugContext(ctx, "Delete retention is infinite, skipping cleanup")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove deleted files that are marked as not needed (we have processed
|
||||
// them) and they were deleted more than MaxDeletedFileAge ago.
|
||||
l.Debugln(fdb.baseName, "forgetting deleted files older than", fdb.deleteRetention)
|
||||
l.DebugContext(ctx, "Forgetting deleted files", "retention", fdb.deleteRetention)
|
||||
res, err := fdb.stmt(`
|
||||
DELETE FROM files
|
||||
WHERE deleted AND modified < ? AND local_flags & {{.FlagLocalNeeded}} == 0
|
||||
@@ -133,7 +136,7 @@ func garbageCollectOldDeletedLocked(fdb *folderDB) error {
|
||||
return wrap(err)
|
||||
}
|
||||
if aff, err := res.RowsAffected(); err == nil {
|
||||
l.Debugln(fdb.baseName, "removed old deleted file records:", aff)
|
||||
l.DebugContext(ctx, "Removed old deleted file records", "affected", aff)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -174,9 +177,14 @@ func garbageCollectBlocklistsAndBlocksLocked(ctx context.Context, fdb *folderDB)
|
||||
SELECT 1 FROM files WHERE files.blocklist_hash = blocklists.blocklist_hash
|
||||
)`); err != nil {
|
||||
return wrap(err, "delete blocklists")
|
||||
} else if shouldDebug() {
|
||||
rows, err := res.RowsAffected()
|
||||
l.Debugln(fdb.baseName, "blocklist GC:", rows, err)
|
||||
} else {
|
||||
slog.DebugContext(ctx, "Blocklist GC", "fdb", fdb.baseName, "result", slogutil.Expensive(func() any {
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return slogutil.Error(err)
|
||||
}
|
||||
return slog.Int64("rows", rows)
|
||||
}))
|
||||
}
|
||||
|
||||
if res, err := tx.ExecContext(ctx, `
|
||||
@@ -185,9 +193,14 @@ func garbageCollectBlocklistsAndBlocksLocked(ctx context.Context, fdb *folderDB)
|
||||
SELECT 1 FROM blocklists WHERE blocklists.blocklist_hash = blocks.blocklist_hash
|
||||
)`); err != nil {
|
||||
return wrap(err, "delete blocks")
|
||||
} else if shouldDebug() {
|
||||
rows, err := res.RowsAffected()
|
||||
l.Debugln(fdb.baseName, "blocks GC:", rows, err)
|
||||
} else {
|
||||
slog.DebugContext(ctx, "Blocks GC", "fdb", fdb.baseName, "result", slogutil.Expensive(func() any {
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return slogutil.Error(err)
|
||||
}
|
||||
return slog.Int64("rows", rows)
|
||||
}))
|
||||
}
|
||||
|
||||
return wrap(tx.Commit())
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"iter"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -20,6 +22,7 @@ import (
|
||||
"github.com/syncthing/syncthing/internal/db"
|
||||
"github.com/syncthing/syncthing/internal/itererr"
|
||||
"github.com/syncthing/syncthing/internal/timeutil"
|
||||
"github.com/syncthing/syncthing/lib/build"
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
@@ -1157,6 +1160,47 @@ func TestStrangeDeletedGlobalBug(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenSpecialName(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
// Create a "base" dir that is in the way if the path becomes
|
||||
// incorrectly truncated in the next steps.
|
||||
base := path.Join(dir, "test")
|
||||
if err := os.Mkdir(base, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Should be able to open a path with a hash sign in it.
|
||||
p1 := base + "#foo"
|
||||
db, err := Open(p1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(db.path)
|
||||
db.Close()
|
||||
|
||||
if !build.IsWindows {
|
||||
// Should be able to open a path with something that looks like
|
||||
// query params.
|
||||
p2 := base + "?foo=bar"
|
||||
db, err = Open(p2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(db.path)
|
||||
db.Close()
|
||||
}
|
||||
|
||||
// Better not a have problem with a single ampersand either.
|
||||
p2 := base + "&foo"
|
||||
db, err = Open(p2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(db.path)
|
||||
db.Close()
|
||||
}
|
||||
|
||||
func mustCollect[T any](t *testing.T) func(it iter.Seq[T], errFn func() error) []T {
|
||||
t.Helper()
|
||||
return func(it iter.Seq[T], errFn func() error) []T {
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"github.com/syncthing/syncthing/lib/logger"
|
||||
)
|
||||
import "github.com/syncthing/syncthing/internal/slogutil"
|
||||
|
||||
var l = logger.DefaultLogger.NewFacility("sqlite", "SQLite database")
|
||||
|
||||
func shouldDebug() bool { return l.ShouldDebug("sqlite") }
|
||||
func init() { slogutil.RegisterPackage("SQLite database") }
|
||||
|
||||
@@ -16,7 +16,7 @@ type countsRow struct {
|
||||
Count int
|
||||
Size int64
|
||||
Deleted bool
|
||||
LocalFlags int64 `db:"local_flags"`
|
||||
LocalFlags protocol.FlagLocal `db:"local_flags"`
|
||||
}
|
||||
|
||||
func (s *folderDB) CountLocal(device protocol.DeviceID) (db.Counts, error) {
|
||||
@@ -39,13 +39,10 @@ func (s *folderDB) CountNeed(device protocol.DeviceID) (db.Counts, error) {
|
||||
}
|
||||
|
||||
func (s *folderDB) CountGlobal() (db.Counts, error) {
|
||||
// Exclude ignored and receive-only changed files from the global count
|
||||
// (legacy expectation? it's a bit weird since those files can in fact
|
||||
// be global and you can get them with GetGlobal etc.)
|
||||
var res []countsRow
|
||||
err := s.stmt(`
|
||||
SELECT s.type, s.count, s.size, s.local_flags, s.deleted FROM counts s
|
||||
WHERE s.local_flags & {{.FlagLocalGlobal}} != 0 AND s.local_flags & {{or .FlagLocalReceiveOnly .FlagLocalIgnored}} = 0
|
||||
WHERE s.local_flags & {{.FlagLocalGlobal}} != 0 AND s.local_flags & {{.LocalInvalidFlags}} = 0
|
||||
`).Select(&res)
|
||||
if err != nil {
|
||||
return db.Counts{}, wrap(err)
|
||||
@@ -84,7 +81,7 @@ func (s *folderDB) needSizeRemote(device protocol.DeviceID) (db.Counts, error) {
|
||||
// See neededGlobalFilesRemote for commentary as that is the same query without summing
|
||||
if err := s.stmt(`
|
||||
SELECT g.type, count(*) as count, sum(g.size) as size, g.local_flags, g.deleted FROM files g
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND NOT g.invalid AND NOT EXISTS (
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND NOT g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND NOT EXISTS (
|
||||
SELECT 1 FROM FILES f
|
||||
INNER JOIN devices d ON d.idx = f.device_idx
|
||||
WHERE f.name = g.name AND f.version = g.version AND d.device_id = ?
|
||||
@@ -94,10 +91,10 @@ func (s *folderDB) needSizeRemote(device protocol.DeviceID) (db.Counts, error) {
|
||||
UNION ALL
|
||||
|
||||
SELECT g.type, count(*) as count, sum(g.size) as size, g.local_flags, g.deleted FROM files g
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND NOT g.invalid AND EXISTS (
|
||||
WHERE g.local_flags & {{.FlagLocalGlobal}} != 0 AND g.deleted AND g.local_flags & {{.LocalInvalidFlags}} = 0 AND EXISTS (
|
||||
SELECT 1 FROM FILES f
|
||||
INNER JOIN devices d ON d.idx = f.device_idx
|
||||
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND NOT f.invalid
|
||||
WHERE f.name = g.name AND d.device_id = ? AND NOT f.deleted AND f.local_flags & {{.LocalInvalidFlags}} = 0
|
||||
)
|
||||
GROUP BY g.type, g.local_flags, g.deleted
|
||||
`).Select(&res, device.String(),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user