Federated via graft
2.0 kB
90 lines
1// Command sync runs the Forgejo <-> Radicle sync daemon: on an interval, it
2// mirrors git content, issues and patches for every repo pair listed in the
3// config file, then sleeps until the next pass.
4package main
5
6import (
7 "flag"
8 "log/slog"
9 "net/http"
10 "os"
11 "time"
12
13 "graft/internal/config"
14 "graft/internal/state"
15 "graft/internal/status"
16 "graft/internal/sync"
17)
18
19func main() {
20 configPath := flag.String("config", "/etc/graft/config.yaml", "path to config.yaml")
21 once := flag.Bool("once", false, "run a single pass and exit, instead of looping")
22 listen := flag.String("listen", ":8090", "address to serve /healthz and / (status) on; empty disables it")
23 flag.Parse()
24
25 log := slog.New(slog.NewJSONHandler(os.Stdout, nil))
26
27 cfg, err := config.Load(*configPath)
28 if err != nil {
29 log.Error("load config", "err", err)
30 os.Exit(1)
31 }
32
33 st, err := state.Open(cfg.StateDB)
34 if err != nil {
35 log.Error("open state db", "err", err)
36 os.Exit(1)
37 }
38 defer st.Close()
39
40 stateDir := cfg.StateDB
41 if idx := lastSlash(stateDir); idx >= 0 {
42 stateDir = stateDir[:idx]
43 }
44
45 syncers := make([]*sync.RepoSyncer, 0, len(cfg.Repos))
46 for _, pair := range cfg.Repos {
47 rs, err := sync.New(pair, st, sync.WorkDirFor(stateDir, pair.Name))
48 if err != nil {
49 log.Error("set up repo pair", "pair", pair.Name, "err", err)
50 os.Exit(1)
51 }
52 syncers = append(syncers, rs)
53 }
54
55 tracker := status.NewTracker(st)
56 runAll := func() {
57 for _, rs := range syncers {
58 gitErr, issuesErr, patchErr := rs.Run(log)
59 tracker.Record(rs.Name(), gitErr, issuesErr, patchErr)
60 }
61 }
62
63 if *listen != "" {
64 go func() {
65 if err := http.ListenAndServe(*listen, tracker.Handler()); err != nil {
66 log.Error("status server stopped", "err", err)
67 }
68 }()
69 }
70
71 runAll()
72 if *once {
73 return
74 }
75
76 ticker := time.NewTicker(cfg.SyncInterval)
77 defer ticker.Stop()
78 for range ticker.C {
79 runAll()
80 }
81}
82
83func lastSlash(s string) int {
84 for i := len(s) - 1; i >= 0; i-- {
85 if s[i] == '/' {
86 return i
87 }
88 }
89 return -1
90}