From 8a2461aa05895cc7828bc9619b50fa5dee5ed1f4 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Sat, 4 May 2024 23:16:38 +0200 Subject: feat: Add config parsing --- .gitignore | 1 + Makefile | 3 ++ README.md | 3 ++ config.example.scfg | 22 +++++++++++++ go.mod | 6 +++- go.sum | 6 ++++ main.go | 32 +++++++++++++++++- pkg/config/config.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++ pkg/config/config_test.go | 56 +++++++++++++++++++++++++++++++ 9 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 config.example.scfg create mode 100644 pkg/config/config.go create mode 100644 pkg/config/config_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/Makefile b/Makefile index 7a0e125..ecf165d 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,6 @@ build: run: go run . + +test: + go test -v --tags=unit ./... diff --git a/README.md b/README.md new file mode 100644 index 0000000..5a723e5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Cerrado + +Read only single user mail based forge for git. diff --git a/config.example.scfg b/config.example.scfg new file mode 100644 index 0000000..eda4f38 --- /dev/null +++ b/config.example.scfg @@ -0,0 +1,22 @@ +scan /srv/git/ { + public true +} + +# TBD +#user admin:iKlvHe1g0UoXE +# +#list main { +# server smtp.example.com +# user admin@admin.com +# password 1234567 +# security tls +# authentication plain +# default false +#} +# +#repository cerrado { +# title Cerrado +# description "Self host single person readonly forge" +# list main +# public true +#} diff --git a/go.mod b/go.mod index cca006e..bfbe03a 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,8 @@ module git.gabrielgio.me/cerrado go 1.22.2 -require golang.org/x/sync v0.7.0 // indirect +require ( + git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082 + github.com/google/go-cmp v0.6.0 + golang.org/x/sync v0.7.0 +) diff --git a/go.sum b/go.sum index e8ef4a3..a982044 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,8 @@ +git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082 h1:9Udx5fm4vRtmgDIBjy2ef5QioHbzpw5oHabbhpAUyEw= +git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082/go.mod h1:ybgvEJTIx5XbaspSviB3KNa6OdPmAZqDoSud7z8fFlw= +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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= diff --git a/main.go b/main.go index 7c80564..ba441fe 100644 --- a/main.go +++ b/main.go @@ -2,16 +2,20 @@ package main import ( "context" + "encoding/json" + "flag" "log/slog" "net/http" "os" "os/signal" "time" + "git.gabrielgio.me/cerrado/pkg/config" "git.gabrielgio.me/cerrado/pkg/worker" ) func main() { + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) defer stop() if err := run(ctx); err != nil { @@ -20,10 +24,36 @@ func main() { } func run(ctx context.Context) error { + var ( + configPath = flag.String("config", "config.example.scfg", "File path for the configuration file") + ) + + flag.Parse() + mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { - if _, err := w.Write([]byte("Hello world!")); err != nil { + + f, err := os.Open(*configPath) + if err != nil { + slog.Error("Error openning config file json", "error", err, "path", *configPath) + return + } + + c, err := config.Parse(f) + if err != nil { + slog.Error("Error parsing config", "error", err, "path", *configPath) + return + } + + b, err := json.MarshalIndent(c, "", " ") + if err != nil { + slog.Error("Error parsing json", "error", err) + return + } + + if _, err := w.Write(b); err != nil { slog.Error("Error handling index", "error", err) + return } }) serverTask := worker.NewServerTask(&http.Server{Handler: mux, Addr: "0.0.0.0:8080"}) diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..ba1614f --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,84 @@ +package config + +import ( + "fmt" + "io" + "strconv" + + "git.sr.ht/~emersion/go-scfg" +) + +type ( + Scan struct { + Path string + Public bool + } + + Configuration struct { + Scan *Scan + } +) + +func Parse(r io.Reader) (*Configuration, error) { + block, err := scfg.Read(r) + if err != nil { + return nil, err + } + + config := defaultConfiguration() + + err = setScan(block, config.Scan) + if err != nil { + return nil, err + } + + return config, nil +} + +func defaultConfiguration() *Configuration { + return &Configuration{ + Scan: &Scan{ + Public: true, + Path: "", + }, + } +} + +func setScan(block scfg.Block, scan *Scan) error { + scanDir := block.Get("scan") + err := setString(scanDir, &scan.Path) + if err != nil { + return err + } + + public := scanDir.Children.Get("public") + return setBool(public, &scan.Public) +} + +func setBool(dir *scfg.Directive, field *bool) error { + + if dir != nil { + p1 := first(dir.Params) + v, err := strconv.ParseBool(p1) + if err != nil { + return fmt.Errorf("Error parsing bool param of %s: %w", dir.Name, err) + } + *field = v + } + return nil +} + +func setString(dir *scfg.Directive, field *string) error { + if dir != nil { + *field = first(dir.Params) + } + return nil +} + +func first[T any](v []T) T { + if len(v) == 0 { + var zero T + return zero + } + return v[0] +} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go new file mode 100644 index 0000000..c8cd887 --- /dev/null +++ b/pkg/config/config_test.go @@ -0,0 +1,56 @@ +// go:build unit +package config + +import ( + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestConfig(t *testing.T) { + testCases := []struct { + name string + config string + expectedConfig *Configuration + }{ + { + name: "minimal scan", + config: `scan "/srv/git"`, + expectedConfig: &Configuration{ + Scan: &Scan{ + Public: true, + Path: "/srv/git", + }, + }, + }, + { + name: "complete scan", + config: `scan "/srv/git" { + public false +}`, + expectedConfig: &Configuration{ + Scan: &Scan{ + Public: false, + Path: "/srv/git", + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + r := strings.NewReader(tc.config) + config, err := Parse(r) + if err != nil { + t.Fatalf("Error parsing config %s", err.Error()) + } + + if diff := cmp.Diff(tc.expectedConfig, config); diff != "" { + t.Errorf("Wrong result given - wanted + got\n %s", diff) + } + + }) + + } +} -- cgit v1.2.3