From 2597c03d1555e00dec59830b7de75e7090208e05 Mon Sep 17 00:00:00 2001 From: Slack Coder Date: Wed, 2 Oct 2024 16:49:36 -0500 Subject: config: Use TOML TOML is simple for users, and it is used in notably projects like rustlang. It also provides comments! --- internal/github/filesystem.go | 9 ++--- internal/github/github.go | 5 +-- internal/service/config.go | 41 ++++++++++++---------- internal/service/git.go | 7 ++-- internal/service/mirror.go | 27 +++++++++++++++ internal/service/mirror_test.go | 30 ++++++++++++++++ internal/service/rsync.go | 5 +-- internal/service/service.go | 21 ------------ internal/service/service_json.go | 64 ----------------------------------- internal/service/service_json_test.go | 37 -------------------- internal/toml.go | 14 ++++++++ internal/url.go | 21 ++++++++++-- 12 files changed, 129 insertions(+), 152 deletions(-) create mode 100644 internal/service/mirror.go create mode 100644 internal/service/mirror_test.go delete mode 100644 internal/service/service_json.go delete mode 100644 internal/service/service_json_test.go create mode 100644 internal/toml.go (limited to 'internal') diff --git a/internal/github/filesystem.go b/internal/github/filesystem.go index 3f069b4..219ec5d 100644 --- a/internal/github/filesystem.go +++ b/internal/github/filesystem.go @@ -2,13 +2,14 @@ package github import ( "fmt" - "net/url" "os" "path" "strings" + + "git.server.ky/slackcoder/mirror/internal" ) -func listReleasesByTagName(dst *url.URL) ([]string, error) { +func listReleasesByTagName(dst *internal.URL) ([]string, error) { entries, err := os.ReadDir(dst.Path) if err != nil { return nil, err @@ -23,7 +24,7 @@ func listReleasesByTagName(dst *url.URL) ([]string, error) { } // The path which project release assets are saved. -func localReleaseFilePath(dst *url.URL, tagName string) string { +func localReleaseFilePath(dst *internal.URL, tagName string) string { return path.Join(dst.Path, tagName) } @@ -46,7 +47,7 @@ func releaseSourceFileName(project string, tagName string, ext string) string { return fmt.Sprintf("%s-%s.%s", project, releaseName(tagName), ext) } -func removeRelease(dst *url.URL, tagName string) error { +func removeRelease(dst *internal.URL, tagName string) error { fp := localReleaseFilePath(dst, tagName) return os.RemoveAll(fp) } diff --git a/internal/github/github.go b/internal/github/github.go index bf35a6a..b2b1987 100644 --- a/internal/github/github.go +++ b/internal/github/github.go @@ -4,12 +4,13 @@ import ( "fmt" "io" "net/http" - "net/url" "os" "path" "path/filepath" "regexp" "time" + + "git.server.ky/slackcoder/mirror/internal" ) type Client struct { @@ -192,7 +193,7 @@ func (c *Client) download(dst string, src string) error { return nil } -func (c *Client) MirrorAssets(dst *url.URL, src *url.URL) error { +func (c *Client) MirrorAssets(dst *internal.URL, src *internal.URL) error { if src.Hostname() != "github.com" { return fmt.Errorf("host must be github.com") } diff --git a/internal/service/config.go b/internal/service/config.go index bcb9efc..8105cd5 100644 --- a/internal/service/config.go +++ b/internal/service/config.go @@ -1,30 +1,25 @@ package service import ( - "encoding/json" "fmt" "os" "time" "dario.cat/mergo" + "git.server.ky/slackcoder/mirror/internal" + "github.com/BurntSushi/toml" ) type Duration struct { time.Duration } -func (s Duration) MarshalJSON() ([]byte, error) { - return json.Marshal(s.Duration.String()) +func (s Duration) MarshalText() ([]byte, error) { + return []byte(s.Duration.String()), nil } -func (s *Duration) UnmarshalJSON(data []byte) error { - var str string - err := json.Unmarshal(data, &str) - if err != nil { - return err - } - - v, err := time.ParseDuration(str) +func (s *Duration) UnmarshalText(text []byte) error { + v, err := time.ParseDuration(string(text)) if err != nil { return err } @@ -33,15 +28,26 @@ func (s *Duration) UnmarshalJSON(data []byte) error { return nil } +// Global parameters +type GlobalConfig struct { + MaxInterval Duration `toml:"max-interval"` + MinInterval Duration `toml:"min-interval"` +} + type Config struct { - MaxInterval Duration `json:"max-interval,omitempty"` - MinInterval Duration `json:"min-interval,omitempty"` - Mirrors []*Mirror `json:"mirrors,omitempty"` + *GlobalConfig `toml:"global"` + Mirrors []*Mirror `toml:"mirrors,omitempty"` +} + +func (c *Config) String() string { + return internal.MustTOML(c) } var DefaultConfig = Config{ - MaxInterval: Duration{24 * time.Hour}, - MinInterval: Duration{time.Hour}, + GlobalConfig: &GlobalConfig{ + MaxInterval: Duration{24 * time.Hour}, + MinInterval: Duration{time.Hour}, + }, } func (c *Config) Apply(arg Config) { @@ -63,11 +69,12 @@ func ApplyFileConfig(cfg *Config, filePath string) error { } defer f.Close() - err = json.NewDecoder(f).Decode(&ret) + _, err = toml.NewDecoder(f).Decode(&ret) if err != nil { return fmt.Errorf("loading configuration file: %w", err) } cfg.Apply(ret) + return nil } diff --git a/internal/service/git.go b/internal/service/git.go index ad3a653..b61e332 100644 --- a/internal/service/git.go +++ b/internal/service/git.go @@ -3,11 +3,12 @@ package service import ( "errors" "fmt" - "net/url" "os" "os/exec" "path" "strings" + + "git.server.ky/slackcoder/mirror/internal" ) const gitDescriptionFile = "description" @@ -44,7 +45,7 @@ func setDescription(repo string, desc string) error { } // Set the remote origin's URL for the projects repository. -func setRemoteOrigin(repo string, origin *url.URL) error { +func setRemoteOrigin(repo string, origin *internal.URL) error { cmd := exec.Command("git", "remote", "get-url", "origin") cmd.Dir = repo buf, err := cmd.Output() @@ -87,7 +88,7 @@ func getRemoteHeadReference(repo string) (string, error) { return "", errors.New("not found") } -func MirrorGit(dst *url.URL, src *url.URL, description string) error { +func MirrorGit(dst *internal.URL, src *internal.URL, description string) error { if dst.Scheme != "" && dst.Scheme != "file://" { return fmt.Errorf("'%s' scheme not supported", dst.Scheme) } diff --git a/internal/service/mirror.go b/internal/service/mirror.go new file mode 100644 index 0000000..12aaa79 --- /dev/null +++ b/internal/service/mirror.go @@ -0,0 +1,27 @@ +package service + +import ( + "bytes" + + "git.server.ky/slackcoder/mirror/internal" + "github.com/BurntSushi/toml" +) + +type Mirror struct { + Method string `toml:"method,omitempty"` + From *internal.URL `toml:"from,omitempty"` + To *internal.URL `toml:"to,omitempty"` + Description string `toml:"description,omitempty"` +} + +func (m *Mirror) Equal(arg *Mirror) bool { + return m.Method == arg.Method && m.From.String() == arg.From.String() && m.To.String() == arg.To.String() +} + +func (m *Mirror) String() string { + var buf bytes.Buffer + + toml.NewEncoder(&buf).Encode(m) + + return buf.String() +} diff --git a/internal/service/mirror_test.go b/internal/service/mirror_test.go new file mode 100644 index 0000000..f9411e2 --- /dev/null +++ b/internal/service/mirror_test.go @@ -0,0 +1,30 @@ +package service + +import ( + "testing" + + "git.server.ky/slackcoder/mirror/internal" + "github.com/BurntSushi/toml" + "github.com/stretchr/testify/require" +) + +func TestMirrorUnmarshalTOML(t *testing.T) { + str := internal.MustTOML(map[string]interface{}{ + "method": "git", + "from": "https://git.taler.net/merchant.git", + "to": "/mirror/merchant", + }) + + exp := Mirror{ + Method: "git", + From: internal.MustURL("https://git.taler.net/merchant.git"), + To: internal.MustURL("/mirror/merchant"), + } + + var s Mirror + + err := toml.Unmarshal([]byte(str), &s) + + require.NoError(t, err) + require.Equal(t, exp.String(), s.String()) +} diff --git a/internal/service/rsync.go b/internal/service/rsync.go index 8298589..c9c7e92 100644 --- a/internal/service/rsync.go +++ b/internal/service/rsync.go @@ -3,9 +3,10 @@ package service import ( "bytes" "errors" - "net/url" "os/exec" "strings" + + "git.server.ky/slackcoder/mirror/internal" ) var rsyncOpts = []string{ @@ -19,7 +20,7 @@ var rsyncOpts = []string{ "--times", } -func Rsync(dst *url.URL, src *url.URL) error { +func Rsync(dst *internal.URL, src *internal.URL) error { src2 := *src if !strings.HasSuffix(src2.Path, "/.") { src2.Path = src2.Path + "/." diff --git a/internal/service/service.go b/internal/service/service.go index c34bcd3..38cabf8 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -1,11 +1,9 @@ package service import ( - "encoding/json" "errors" "fmt" "math/rand" - "net/url" "os" "strconv" "strings" @@ -15,25 +13,6 @@ import ( "git.server.ky/slackcoder/mirror/internal/github" ) -type Mirror struct { - Method string `json:"method"` - From *url.URL `json:"-"` - To *url.URL `json:"-"` - Description string `json:"description,omitempty"` -} - -func (m *Mirror) Equal(arg *Mirror) bool { - return m.Method == arg.Method && m.From.String() == arg.From.String() && m.To.String() == arg.To.String() -} - -func (m *Mirror) String() string { - buf, err := json.Marshal(m) - if err != nil { - panic(err) - } - return string(buf) -} - type Service struct { cfg *Config diff --git a/internal/service/service_json.go b/internal/service/service_json.go deleted file mode 100644 index 571eb30..0000000 --- a/internal/service/service_json.go +++ /dev/null @@ -1,64 +0,0 @@ -package service - -import ( - "encoding/json" - "net/url" -) - -type JsonURL struct { - *url.URL -} - -func (m JsonURL) MarshalJSON() ([]byte, error) { - str := m.String() - return json.Marshal(str) -} - -func (m *JsonURL) UnmarshalJSON(buf []byte) error { - var str string - - err := json.Unmarshal(buf, &str) - if err != nil { - return err - } - - m.URL, err = url.Parse(str) - return err -} - -func (m Mirror) MarshalJSON() ([]byte, error) { - type Alias Mirror - - m2 := struct { - *Alias - From JsonURL `json:"from"` - To JsonURL `json:"to"` - }{ - Alias: (*Alias)(&m), - From: JsonURL{m.From}, - To: JsonURL{m.To}, - } - - return json.Marshal(m2) -} - -func (m *Mirror) UnmarshalJSON(buf []byte) error { - type Alias Mirror - - var m2 struct { - *Alias - From JsonURL `json:"from"` - To JsonURL `json:"to"` - } - - m2.Alias = (*Alias)(m) - err := json.Unmarshal(buf, &m2) - if err != nil { - return err - } - - m.From = m2.From.URL - m.To = m2.To.URL - - return nil -} diff --git a/internal/service/service_json_test.go b/internal/service/service_json_test.go deleted file mode 100644 index c8e073a..0000000 --- a/internal/service/service_json_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package service - -import ( - "encoding/json" - "testing" - - "git.server.ky/slackcoder/mirror/internal" - "github.com/stretchr/testify/require" -) - -func mustJSON(arg interface{}) string { - buf, err := json.Marshal(arg) - if err != nil { - panic(err) - } - - return string(buf) -} - -func TestMirrorUnmarshalJSON(t *testing.T) { - str := mustJSON(map[string]interface{}{ - "method": "git", - "from": "https://git.taler.net/merchant.git", - "to": "/mirror/merchant", - }) - - exp := Mirror{ - Method: "git", - From: internal.MustURL("https://git.taler.net/merchant.git"), - To: internal.MustURL("/mirror/merchant"), - } - - var s Mirror - err := json.Unmarshal([]byte(str), &s) - require.NoError(t, err) - require.Equal(t, exp.String(), s.String()) -} diff --git a/internal/toml.go b/internal/toml.go new file mode 100644 index 0000000..4222921 --- /dev/null +++ b/internal/toml.go @@ -0,0 +1,14 @@ +package internal + +import ( + "github.com/BurntSushi/toml" +) + +func MustTOML(arg interface{}) string { + buf, err := toml.Marshal(arg) + if err != nil { + panic(err) + } + + return string(buf) +} diff --git a/internal/url.go b/internal/url.go index 3a8d20a..d7a712d 100644 --- a/internal/url.go +++ b/internal/url.go @@ -2,10 +2,27 @@ package internal import "net/url" -func MustURL(arg string) *url.URL { +type URL struct { + *url.URL +} + +func (u *URL) MarshalText() ([]byte, error) { + return []byte(u.URL.String()), nil +} + +func (u *URL) UnmarshalText(buf []byte) error { + var err error + u.URL, err = url.Parse(string(buf)) + if err != nil { + return err + } + return nil +} + +func MustURL(arg string) *URL { u, err := url.Parse(arg) if err != nil { panic(err) } - return u + return &URL{u} } -- cgit v1.2.3