镜像自地址
https://github.com/tuna/tunasync.git
已同步 2025-12-07 15:06:47 +00:00
比较提交
14 次代码提交
| 作者 | SHA1 | 提交日期 | |
|---|---|---|---|
|
|
88b7827e66 | ||
|
|
49b74ae552 | ||
|
|
37255cc827 | ||
|
|
136e01f1cd | ||
|
|
cd73602988 | ||
|
|
2a8fa5636e | ||
|
|
94b9b20626 | ||
|
|
5a9c6b9020 | ||
|
|
75ee481cfa | ||
|
|
2f9e96a75a | ||
|
|
aa36b96828 | ||
|
|
e9ce7fc87a | ||
|
|
3fd71d777b | ||
|
|
984f8a1eb5 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
for i in linux-amd64 linux-arm64; do
|
for i in linux-amd64 linux-arm64; do
|
||||||
make ARCH=$i all
|
make ARCH=$i all
|
||||||
tar -cz --numeric-owner --owner root -f tunasync-$i-bin.tar.gz -C build-$i tunasync tunasynctl
|
tar -cz --numeric-owner --owner root --group root -f tunasync-$i-bin.tar.gz -C build-$i tunasync tunasynctl
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -1,5 +1,4 @@
|
|||||||
tunasync
|
# tunasync
|
||||||
========
|
|
||||||
|
|
||||||

|

|
||||||
[](https://coveralls.io/github/tuna/tunasync?branch=master)
|
[](https://coveralls.io/github/tuna/tunasync?branch=master)
|
||||||
@@ -12,11 +11,11 @@ tunasync
|
|||||||
|
|
||||||
## Download
|
## Download
|
||||||
|
|
||||||
Pre-built binary for Linux x86_64 is available at [Github releases](https://github.com/tuna/tunasync/releases/latest).
|
Pre-built binary for Linux x86_64 and ARM64 is available at [Github releases](https://github.com/tuna/tunasync/releases/latest).
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
```
|
```text
|
||||||
# Architecture
|
# Architecture
|
||||||
|
|
||||||
- Manager: Central instance for status and job management
|
- Manager: Central instance for status and job management
|
||||||
@@ -50,13 +49,12 @@ PreSyncing Syncing Succe
|
|||||||
+-----------------+
|
+-----------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Go version: 1.13
|
Go version: 1.13
|
||||||
|
|
||||||
```
|
```shell
|
||||||
make all
|
> make all
|
||||||
```
|
```
|
||||||
|
|
||||||
Binaries in the `build/`.
|
Binaries in the `build-linux-amd64/`.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# tunasync 上手指南
|
# tunasync 上手指南
|
||||||
|
|
||||||
date: 2016-10-31 00:50:00
|
date: 2016-10-31 00:50:00
|
||||||
|
|
||||||
[tunasync](https://github.com/tuna/tunasync) 是[清华大学 TUNA 镜像源](https://mirrors.tuna.tsinghua.edu.cn)目前使用的镜像方案。
|
[tunasync](https://github.com/tuna/tunasync) 是[清华大学 TUNA 镜像源](https://mirrors.tuna.tsinghua.edu.cn)目前使用的镜像方案。
|
||||||
@@ -7,32 +8,32 @@ date: 2016-10-31 00:50:00
|
|||||||
|
|
||||||
本例中:
|
本例中:
|
||||||
|
|
||||||
- 只镜像[elvish](https://elvish.io)项目
|
- 只镜像[elvish](https://elvish.io)项目
|
||||||
- 禁用了https
|
- 禁用了https
|
||||||
- 禁用了cgroup支持
|
- 禁用了cgroup支持
|
||||||
|
|
||||||
## 获得tunasync
|
## 获得tunasync
|
||||||
|
|
||||||
### 二进制包
|
### 二进制包
|
||||||
|
|
||||||
到 [Github Releases](https://github.com/tuna/tunasync/releases/latest) 下载 `tunasync-linux-bin.tar.gz` 即可。
|
到 [Github Releases](https://github.com/tuna/tunasync/releases/latest) 下载 `tunasync-linux-amd64-bin.tar.gz` 即可。
|
||||||
|
|
||||||
### 自行编译
|
### 自行编译
|
||||||
|
|
||||||
```
|
```shell
|
||||||
$ make
|
> make
|
||||||
```
|
```
|
||||||
|
|
||||||
## 配置
|
## 配置
|
||||||
|
|
||||||
```
|
```shell
|
||||||
$ mkdir ~/tunasync_demo
|
> mkdir ~/tunasync_demo
|
||||||
$ mkdir /tmp/tunasync
|
> mkdir /tmp/tunasync
|
||||||
```
|
```
|
||||||
|
|
||||||
`~/tunasync_demo/worker.conf`:
|
编辑 `~/tunasync_demo/worker.conf`:
|
||||||
|
|
||||||
```
|
```conf
|
||||||
[global]
|
[global]
|
||||||
name = "test_worker"
|
name = "test_worker"
|
||||||
log_dir = "/tmp/tunasync/log/tunasync/{{.Name}}"
|
log_dir = "/tmp/tunasync/log/tunasync/{{.Name}}"
|
||||||
@@ -64,9 +65,9 @@ upstream = "rsync://rsync.elvish.io/elvish/"
|
|||||||
use_ipv6 = false
|
use_ipv6 = false
|
||||||
```
|
```
|
||||||
|
|
||||||
`~/tunasync_demo/manager.conf`:
|
编辑 `~/tunasync_demo/manager.conf`:
|
||||||
|
|
||||||
```
|
```conf
|
||||||
debug = false
|
debug = false
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
@@ -83,26 +84,26 @@ ca_cert = ""
|
|||||||
|
|
||||||
### 运行
|
### 运行
|
||||||
|
|
||||||
```
|
```shell
|
||||||
$ tunasync manager --config ~/tunasync_demo/manager.conf
|
> tunasync manager --config ~/tunasync_demo/manager.conf
|
||||||
$ tunasync worker --config ~/tunasync_demo/worker.conf
|
> tunasync worker --config ~/tunasync_demo/worker.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
本例中,镜像的数据在`/tmp/tunasync/`
|
本例中,镜像的数据在 `/tmp/tunasync/`。
|
||||||
|
|
||||||
### 控制
|
### 控制
|
||||||
|
|
||||||
查看同步状态
|
查看同步状态
|
||||||
|
|
||||||
```
|
```shell
|
||||||
$ tunasynctl list -p 12345 --all
|
> tunasynctl list -p 12345 --all
|
||||||
```
|
```
|
||||||
|
|
||||||
tunasynctl 也支持配置文件。配置文件可以放在 `/etc/tunasync/ctl.conf` 或者 `~/.config/tunasync/ctl.conf` 两个位置,后者可以覆盖前者的配置值。
|
tunasynctl 也支持配置文件。配置文件可以放在 `/etc/tunasync/ctl.conf` 或者 `~/.config/tunasync/ctl.conf` 两个位置,后者可以覆盖前者的配置值。
|
||||||
|
|
||||||
配置文件内容为:
|
配置文件内容为:
|
||||||
|
|
||||||
```
|
```conf
|
||||||
manager_addr = "127.0.0.1"
|
manager_addr = "127.0.0.1"
|
||||||
manager_port = 12345
|
manager_port = 12345
|
||||||
ca_cert = ""
|
ca_cert = ""
|
||||||
@@ -118,13 +119,13 @@ worker 和 manager 之间用 http(s) 通信,如果你 worker 和 manager 都
|
|||||||
|
|
||||||
可以参看
|
可以参看
|
||||||
|
|
||||||
```
|
```shell
|
||||||
$ tunasync manager --help
|
> tunasync manager --help
|
||||||
$ tunasync worker --help
|
> tunasync worker --help
|
||||||
```
|
```
|
||||||
|
|
||||||
可以看一下 log 目录
|
可以看一下 log 目录
|
||||||
|
|
||||||
一些 worker 配置文件示例 [workers.conf](workers.conf)
|
一些 worker 配置文件示例 [workers.conf](workers.conf)。
|
||||||
|
|
||||||
你可能会用到的操作 [tips.md](tips.md)
|
你可能会用到的操作 [tips.md](tips.md)。
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -60,21 +62,45 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c CmdVerb) String() string {
|
func (c CmdVerb) String() string {
|
||||||
switch c {
|
mapping := map[CmdVerb]string{
|
||||||
case CmdStart:
|
CmdStart: "start",
|
||||||
return "start"
|
CmdStop: "stop",
|
||||||
case CmdStop:
|
CmdDisable: "disable",
|
||||||
return "stop"
|
CmdRestart: "restart",
|
||||||
case CmdDisable:
|
CmdPing: "ping",
|
||||||
return "disable"
|
CmdReload: "reload",
|
||||||
case CmdRestart:
|
|
||||||
return "restart"
|
|
||||||
case CmdPing:
|
|
||||||
return "ping"
|
|
||||||
case CmdReload:
|
|
||||||
return "reload"
|
|
||||||
}
|
}
|
||||||
return "unknown"
|
return mapping[c]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCmdVerbFromString(s string) CmdVerb {
|
||||||
|
mapping := map[string]CmdVerb{
|
||||||
|
"start": CmdStart,
|
||||||
|
"stop": CmdStop,
|
||||||
|
"disable": CmdDisable,
|
||||||
|
"restart": CmdRestart,
|
||||||
|
"ping": CmdPing,
|
||||||
|
"reload": CmdReload,
|
||||||
|
}
|
||||||
|
return mapping[s]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal and Unmarshal for CmdVerb
|
||||||
|
func (s CmdVerb) MarshalJSON() ([]byte, error) {
|
||||||
|
buffer := bytes.NewBufferString(`"`)
|
||||||
|
buffer.WriteString(s.String())
|
||||||
|
buffer.WriteString(`"`)
|
||||||
|
return buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CmdVerb) UnmarshalJSON(b []byte) error {
|
||||||
|
var j string
|
||||||
|
err := json.Unmarshal(b, &j)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*s = NewCmdVerbFromString(j)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A WorkerCmd is the command message send from the
|
// A WorkerCmd is the command message send from the
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
// Version of the program
|
// Version of the program
|
||||||
const Version string = "0.6.7"
|
const Version string = "0.6.9"
|
||||||
|
|||||||
@@ -204,6 +204,8 @@ func (s *Manager) listWorkers(c *gin.Context) {
|
|||||||
workerInfos = append(workerInfos,
|
workerInfos = append(workerInfos,
|
||||||
WorkerStatus{
|
WorkerStatus{
|
||||||
ID: w.ID,
|
ID: w.ID,
|
||||||
|
URL: w.URL,
|
||||||
|
Token: "REDACTED",
|
||||||
LastOnline: w.LastOnline,
|
LastOnline: w.LastOnline,
|
||||||
LastRegister: w.LastRegister,
|
LastRegister: w.LastRegister,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
package worker
|
package worker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package worker
|
||||||
|
|
||||||
|
type btrfsSnapshotHook struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBtrfsSnapshotHook(provider mirrorProvider, snapshotPath string, mirror mirrorConfig) *btrfsSnapshotHook {
|
||||||
|
return &btrfsSnapshotHook{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *btrfsSnapshotHook) postExec() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *btrfsSnapshotHook) postFail() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *btrfsSnapshotHook) postSuccess() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *btrfsSnapshotHook) preExec() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *btrfsSnapshotHook) preJob() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ exit 0
|
|||||||
"Done\n",
|
"Done\n",
|
||||||
targetDir,
|
targetDir,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"-aHvh --no-o --no-g --stats --exclude .~tmp~/ "+
|
"-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ "+
|
||||||
"--delete --delete-after --delay-updates --safe-links "+
|
"--delete --delete-after --delay-updates --safe-links "+
|
||||||
"--timeout=120 -6 %s %s",
|
"--timeout=120 -6 %s %s",
|
||||||
provider.upstreamURL, provider.WorkingDir(),
|
provider.upstreamURL, provider.WorkingDir(),
|
||||||
@@ -190,7 +190,7 @@ exit 0
|
|||||||
"Done\n",
|
"Done\n",
|
||||||
targetDir,
|
targetDir,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"%s %s %s -aHvh --no-o --no-g --stats --exclude .~tmp~/ "+
|
"%s %s %s -aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ "+
|
||||||
"--delete --delete-after --delay-updates --safe-links "+
|
"--delete --delete-after --delay-updates --safe-links "+
|
||||||
"--timeout=30 -4 --delete-excluded %s %s",
|
"--timeout=30 -4 --delete-excluded %s %s",
|
||||||
provider.username, provider.password, proxyAddr,
|
provider.username, provider.password, proxyAddr,
|
||||||
@@ -613,14 +613,14 @@ exit 0
|
|||||||
"Done\n",
|
"Done\n",
|
||||||
targetDir,
|
targetDir,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"-aHvh --no-o --no-g --stats --exclude .~tmp~/ --safe-links "+
|
"-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ --safe-links "+
|
||||||
"--exclude dists/ --timeout=30 -6 "+
|
"--include=*.diff/ --exclude=*.diff/Index --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --include=i18n/by-hash --exclude=i18n/* --exclude=ls-lR* --timeout=30 -6 "+
|
||||||
"--exclude-from %s %s %s",
|
"--exclude-from %s %s %s",
|
||||||
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
||||||
),
|
),
|
||||||
targetDir,
|
targetDir,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"-aHvh --no-o --no-g --stats --exclude .~tmp~/ "+
|
"-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ "+
|
||||||
"--delete --delete-after --delay-updates --safe-links "+
|
"--delete --delete-after --delay-updates --safe-links "+
|
||||||
"--delete-excluded --cache --timeout=30 -6 --exclude-from %s %s %s",
|
"--delete-excluded --cache --timeout=30 -6 --exclude-from %s %s %s",
|
||||||
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
||||||
@@ -655,8 +655,8 @@ exit 0
|
|||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
expectedOutput := fmt.Sprintf(
|
expectedOutput := fmt.Sprintf(
|
||||||
"-aHvh --no-o --no-g --stats --exclude .~tmp~/ --safe-links "+
|
"-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ --safe-links "+
|
||||||
"--exclude dists/ --timeout=30 -6 "+
|
"--include=*.diff/ --exclude=*.diff/Index --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --include=i18n/by-hash --exclude=i18n/* --exclude=ls-lR* --timeout=30 -6 "+
|
||||||
"--exclude-from %s %s %s\n",
|
"--exclude-from %s %s %s\n",
|
||||||
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func newRsyncProvider(c rsyncConfig) (*rsyncProvider, error) {
|
|||||||
|
|
||||||
options := []string{
|
options := []string{
|
||||||
"-aHvh", "--no-o", "--no-g", "--stats",
|
"-aHvh", "--no-o", "--no-g", "--stats",
|
||||||
"--exclude", ".~tmp~/",
|
"--filter" , "risk .~tmp~/", "--exclude", ".~tmp~/",
|
||||||
"--delete", "--delete-after", "--delay-updates",
|
"--delete", "--delete-after", "--delay-updates",
|
||||||
"--safe-links",
|
"--safe-links",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,11 +34,12 @@ type twoStageRsyncProvider struct {
|
|||||||
dataSize string
|
dataSize string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ref: https://salsa.debian.org/mirror-team/archvsync/-/blob/master/bin/ftpsync#L431
|
||||||
var rsyncStage1Profiles = map[string]([]string){
|
var rsyncStage1Profiles = map[string]([]string){
|
||||||
"debian": []string{"dists/"},
|
"debian": []string{"--include=*.diff/", "--exclude=*.diff/Index", "--exclude=Packages*", "--exclude=Sources*", "--exclude=Release*", "--exclude=InRelease", "--include=i18n/by-hash", "--exclude=i18n/*", "--exclude=ls-lR*"},
|
||||||
"debian-oldstyle": []string{
|
"debian-oldstyle": []string{
|
||||||
"Packages*", "Sources*", "Release*",
|
"--exclude=Packages*", "--exclude=Sources*", "--exclude=Release*",
|
||||||
"InRelease", "i18n/*", "ls-lR*", "dep11/*",
|
"--exclude=InRelease", "--exclude=i18n/*", "--exclude=ls-lR*", "--exclude=dep11/*",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,12 +63,12 @@ func newTwoStageRsyncProvider(c twoStageRsyncConfig) (*twoStageRsyncProvider, er
|
|||||||
twoStageRsyncConfig: c,
|
twoStageRsyncConfig: c,
|
||||||
stage1Options: []string{
|
stage1Options: []string{
|
||||||
"-aHvh", "--no-o", "--no-g", "--stats",
|
"-aHvh", "--no-o", "--no-g", "--stats",
|
||||||
"--exclude", ".~tmp~/",
|
"--filter", "risk .~tmp~/", "--exclude", ".~tmp~/",
|
||||||
"--safe-links",
|
"--safe-links",
|
||||||
},
|
},
|
||||||
stage2Options: []string{
|
stage2Options: []string{
|
||||||
"-aHvh", "--no-o", "--no-g", "--stats",
|
"-aHvh", "--no-o", "--no-g", "--stats",
|
||||||
"--exclude", ".~tmp~/",
|
"--filter", "risk .~tmp~/", "--exclude", ".~tmp~/",
|
||||||
"--delete", "--delete-after", "--delay-updates",
|
"--delete", "--delete-after", "--delay-updates",
|
||||||
"--safe-links",
|
"--safe-links",
|
||||||
},
|
},
|
||||||
@@ -109,12 +110,12 @@ func (p *twoStageRsyncProvider) Options(stage int) ([]string, error) {
|
|||||||
var options []string
|
var options []string
|
||||||
if stage == 1 {
|
if stage == 1 {
|
||||||
options = append(options, p.stage1Options...)
|
options = append(options, p.stage1Options...)
|
||||||
stage1Excludes, ok := rsyncStage1Profiles[p.stage1Profile]
|
stage1Profile, ok := rsyncStage1Profiles[p.stage1Profile]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("Invalid Stage 1 Profile")
|
return nil, errors.New("Invalid Stage 1 Profile")
|
||||||
}
|
}
|
||||||
for _, exc := range stage1Excludes {
|
for _, exc := range stage1Profile {
|
||||||
options = append(options, "--exclude", exc)
|
options = append(options, exc)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if stage == 2 {
|
} else if stage == 2 {
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户