diff options
| author | Gabriel A. Giovanini <mail@gabrielgio.me> | 2024-05-04 23:16:38 +0200 | 
|---|---|---|
| committer | Gabriel A. Giovanini <mail@gabrielgio.me> | 2024-05-04 23:17:02 +0200 | 
| commit | 8a2461aa05895cc7828bc9619b50fa5dee5ed1f4 (patch) | |
| tree | 86c6848d9c9a7d7b2d272fa43af66350d2cd1d0e | |
| parent | 3fb9c66ffa0bf87cbd7cc1b5f4129f3447e94c13 (diff) | |
| download | cerrado-8a2461aa05895cc7828bc9619b50fa5dee5ed1f4.tar.gz cerrado-8a2461aa05895cc7828bc9619b50fa5dee5ed1f4.tar.bz2 cerrado-8a2461aa05895cc7828bc9619b50fa5dee5ed1f4.zip | |
feat: Add config parsing
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | config.example.scfg | 22 | ||||
| -rw-r--r-- | go.mod | 6 | ||||
| -rw-r--r-- | go.sum | 6 | ||||
| -rw-r--r-- | main.go | 32 | ||||
| -rw-r--r-- | pkg/config/config.go | 84 | ||||
| -rw-r--r-- | pkg/config/config_test.go | 56 | 
9 files changed, 211 insertions, 2 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ @@ -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 +#} @@ -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 +) @@ -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= @@ -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) +			} + +		}) + +	} +} | 
