feat: rename project from Fonu to Havline
CI / verify (push) Canceled after 0s

This commit is contained in:
2026-10-01 16:54:35 +08:00
parent c377405696
commit 8fa5d922ac
250 changed files with 6724 additions and 5070 deletions
+5 -5
View File
@@ -12,7 +12,7 @@ import (
"sort"
"time"
"github.com/fonu/fonu/internal/settings"
"github.com/havline/havline/internal/settings"
)
// 保留份数的边界:0/负数按默认值处理,上限防止把磁盘塞满
@@ -23,7 +23,7 @@ const (
// archiveNamePattern 备份命名格式(Export 用 CreateTemp 生成,后缀是随机数字)。
// List / Path 都按它过滤,避免把 backups 目录里任意文件当成备份读写或删除。
var archiveNamePattern = regexp.MustCompile(`^fonu-backup-\d{8}-\d{6}-\d+\.tar\.gz$`)
var archiveNamePattern = regexp.MustCompile(`^havline-backup-\d{8}-\d{6}-\d+\.tar\.gz$`)
// Archive 留在磁盘上的一份备份
type Archive struct {
@@ -104,7 +104,7 @@ func (s *Service) Remove(name string) error {
}
// Verify 回读归档并返回条目数:确认这份备份不是写了一半的残件,
// 同时要求包内必须有 fonu.db(否则多半不是 Fonu 的备份)。
// 同时要求包内必须有 havline.db(否则多半不是 Havline 的备份)。
func (s *Service) Verify(ctx context.Context, path string) (int, error) {
file, err := os.Open(path)
if err != nil {
@@ -133,12 +133,12 @@ func (s *Service) Verify(ctx context.Context, path string) (int, error) {
return count, err
}
count++
if header.Name == "fonu.db" {
if header.Name == "havline.db" {
hasDatabase = true
}
}
if !hasDatabase {
return count, fmt.Errorf("备份里没有 fonu.db,可能不是 Fonu 的备份")
return count, fmt.Errorf("备份里没有 havline.db,可能不是 Havline 的备份")
}
return count, nil
}
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"path/filepath"
"time"
"github.com/fonu/fonu/internal/notify"
"github.com/fonu/fonu/internal/settings"
"github.com/havline/havline/internal/notify"
"github.com/havline/havline/internal/settings"
)
// AutoInterval 自动备份间隔。scheduler 启动时会先跑一轮,靠「最新备份是否还在间隔内」
+8 -8
View File
@@ -31,7 +31,7 @@ func TestDueForBackup(t *testing.T) {
func TestExportVerifyRoundTrip(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "fonu.db"), []byte("db"), 0o600); err != nil {
if err := os.WriteFile(filepath.Join(dir, "havline.db"), []byte("db"), 0o600); err != nil {
t.Fatal(err)
}
svc := New(dir)
@@ -62,7 +62,7 @@ func TestExportVerifyRoundTrip(t *testing.T) {
func TestVerifyRejectsGarbage(t *testing.T) {
svc := New(t.TempDir())
path := filepath.Join(svc.backupsDir(), "fonu-backup-20260925-000000-1.tar.gz")
path := filepath.Join(svc.backupsDir(), "havline-backup-20260925-000000-1.tar.gz")
if err := os.MkdirAll(svc.backupsDir(), 0o755); err != nil {
t.Fatal(err)
}
@@ -80,9 +80,9 @@ func TestListPruneAndPath(t *testing.T) {
t.Fatal(err)
}
for _, name := range []string{
"fonu-backup-20260923-100000-1.tar.gz",
"fonu-backup-20260924-100000-2.tar.gz",
"fonu-backup-20260925-100000-3.tar.gz",
"havline-backup-20260923-100000-1.tar.gz",
"havline-backup-20260924-100000-2.tar.gz",
"havline-backup-20260925-100000-3.tar.gz",
} {
if err := os.WriteFile(filepath.Join(svc.backupsDir(), name), []byte("x"), 0o600); err != nil {
t.Fatal(err)
@@ -100,7 +100,7 @@ func TestListPruneAndPath(t *testing.T) {
if len(archives) != 3 {
t.Fatalf("应只列出 3 份备份,实际 %d", len(archives))
}
if archives[0].Name != "fonu-backup-20260925-100000-3.tar.gz" {
if archives[0].Name != "havline-backup-20260925-100000-3.tar.gz" {
t.Fatalf("应按时间倒序,实际首条 %s", archives[0].Name)
}
@@ -116,12 +116,12 @@ func TestListPruneAndPath(t *testing.T) {
}
// 名称校验:不能让备份名把读写带出备份目录
for _, name := range []string{"../fonu.db", "notes.txt", "", "fonu-backup-x.tar.gz"} {
for _, name := range []string{"../havline.db", "notes.txt", "", "havline-backup-x.tar.gz"} {
if _, err := svc.Path(name); err == nil {
t.Fatalf("非法备份名应拒绝:%q", name)
}
}
if err := svc.Remove("fonu-backup-20260920-100000-9.tar.gz"); err == nil {
if err := svc.Remove("havline-backup-20260920-100000-9.tar.gz"); err == nil {
t.Fatal("删除不存在的备份应报错")
}
if _, err := svc.Prune(0); err != nil {
+2 -2
View File
@@ -35,7 +35,7 @@ func (s *Service) Export(ctx context.Context) (string, error) {
return "", err
}
// CreateTemp 保证同一秒内多次导出不会覆盖已有备份(文件名带随机后缀)
file, err := os.CreateTemp(s.backupsDir(), fmt.Sprintf("fonu-backup-%s-*.tar.gz", time.Now().Format(backupTimeFmt)))
file, err := os.CreateTemp(s.backupsDir(), fmt.Sprintf("havline-backup-%s-*.tar.gz", time.Now().Format(backupTimeFmt)))
if err != nil {
return "", err
}
@@ -59,7 +59,7 @@ func (s *Service) writeArchive(ctx context.Context, file *os.File, outPath strin
gw := gzip.NewWriter(file)
tw := tar.NewWriter(gw)
for _, entry := range []string{"fonu.db", "certs", "nginx", "cloudflared/tunnels"} {
for _, entry := range []string{"havline.db", "certs", "nginx", "cloudflared/tunnels"} {
if err := addToArchive(ctx, tw, s.dataDir, entry); err != nil {
discard()
return err