diff --git a/main.go b/main.go
index 76da07bd4f55d968e2d8de6fde919aaca7325301..eedff5eb6a12149528573530facbba8b740bd578 100644
--- a/main.go
+++ b/main.go
@@ -10,7 +10,6 @@ "os/signal"
"time"
"git.gabrielgio.me/cerrado/pkg/config"
- "git.gabrielgio.me/cerrado/pkg/git"
"git.gabrielgio.me/cerrado/pkg/handler"
"git.gabrielgio.me/cerrado/pkg/service"
"git.gabrielgio.me/cerrado/pkg/worker"
@@ -33,38 +32,21 @@ )
flag.Parse()
- mux := http.NewServeMux()
-
- staticHandler, err := handler.NewStaticHander("/static/")
+ // repositorie
+ configRepo, err := config.LoadConfigurationRepository(*configPath)
if err != nil {
return err
}
- f, err := os.Open(*configPath)
- if err != nil {
- return err
- }
+ // services
+ gitService := service.NewGitService(configRepo)
- config, err := config.Parse(f)
+ handler, err := handler.MountHandler(gitService, configRepo)
if err != nil {
return err
}
- // repositories
- gitServer := git.NewGitServerRepository(config.Scan.Path)
-
- // services
- gitService := service.NewGitService(gitServer)
-
- //handlers
- gitHandler := handler.NewGitHandler(gitService)
- aboutHandler := handler.NewAboutHandler(config.RootReadme)
-
- mux.Handle("/static/", staticHandler)
- mux.HandleFunc("/config", handler.ConfigFile(*configPath))
- mux.HandleFunc("/about", aboutHandler.About)
- mux.HandleFunc("/", gitHandler.List)
- serverTask := worker.NewServerTask(&http.Server{Handler: mux, Addr: "0.0.0.0:8080"})
+ serverTask := worker.NewServerTask(&http.Server{Handler: handler, Addr: "0.0.0.0:8080"})
pool := worker.NewTaskPool()
pool.AddTask("http-server", 5*time.Second, serverTask)
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 9b6accea2b385fa1180aec54df7e0a64bb3ee6fe..419d49dac3a06f7357de72162885c2b822be8e07 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -1,27 +1,126 @@
package config
import (
+ "errors"
"fmt"
"io"
+ "os"
+ "path"
"strconv"
"git.gabrielgio.me/cerrado/pkg/u"
"git.sr.ht/~emersion/go-scfg"
+)
+
+var (
+ ScanPathErr = errors.New("Scan path does not exist")
+ RepoPathErr = errors.New("Repository path does not exist")
)
type (
- Scan struct {
+
+ // scan represents piece of the scan from the configuration file.
+ scan struct {
Path string
Public bool
}
- Configuration struct {
- Scan *Scan
+ // configuration represents file configuration.
+ configuration struct {
+ Scan *scan
RootReadme string
}
+
+ // This is a per repository configuration.
+ GitRepositoryConfiguration struct {
+ Name string
+ Path string
+ Public bool
+ }
+
+ // ConfigurationRepository represents the configuration repository (as in
+ // database repositories).
+ // This holds all the function necessary to ask for configuration
+ // information.
+ ConfigurationRepository struct {
+ rootReadme string
+ repositories []*GitRepositoryConfiguration
+ }
)
-func Parse(r io.Reader) (*Configuration, error) {
+func LoadConfigurationRepository(configPath string) (*ConfigurationRepository, error) {
+ f, err := os.Open(configPath)
+ if err != nil {
+ return nil, err
+ }
+
+ config, err := parse(f)
+ if err != nil {
+ return nil, err
+ }
+
+ repo := &ConfigurationRepository{
+ rootReadme: config.RootReadme,
+ }
+
+ err = repo.expandOnScanPath(config.Scan.Path, config.Scan.Public)
+ if err != nil {
+ return nil, err
+ }
+ return repo, nil
+
+}
+
+// GetRootReadme returns root read path
+func (c *ConfigurationRepository) GetRootReadme() string {
+ return c.rootReadme
+}
+
+// GetByName returns configuration of repository for a given name.
+// It returns nil if there is not match for it.
+func (c *ConfigurationRepository) GetByName(name string) *GitRepositoryConfiguration {
+ for _, r := range c.repositories {
+ if r.Name == name {
+ return r
+ }
+ }
+ return nil
+}
+
+// List returns all the configuration for all repositories.
+func (c *ConfigurationRepository) List() []*GitRepositoryConfiguration {
+ return c.repositories
+}
+
+// expandOnScanPath scans the scanPath for folders taking them as repositories
+// and applying them default configuration.
+func (c *ConfigurationRepository) expandOnScanPath(scanPath string, public bool) error {
+ if !u.FileExist(scanPath) {
+ return ScanPathErr
+ }
+
+ entries, err := os.ReadDir(scanPath)
+ if err != nil {
+ return err
+ }
+
+ c.repositories = make([]*GitRepositoryConfiguration, 0)
+ for _, e := range entries {
+ if !e.IsDir() {
+ continue
+ }
+
+ fullPath := path.Join(scanPath, e.Name())
+ c.repositories = append(c.repositories, &GitRepositoryConfiguration{
+ Name: e.Name(),
+ Path: fullPath,
+ Public: public,
+ })
+ }
+ return nil
+}
+
+func parse(r io.Reader) (*configuration, error) {
block, err := scfg.Read(r)
if err != nil {
return nil, err
@@ -42,9 +141,9 @@
return config, nil
}
-func defaultConfiguration() *Configuration {
- return &Configuration{
- Scan: &Scan{
+func defaultConfiguration() *configuration {
+ return &configuration{
+ Scan: &scan{
Public: true,
Path: "",
},
@@ -57,7 +156,7 @@ scanDir := block.Get("root-readme")
return setString(scanDir, readme)
}
-func setScan(block scfg.Block, scan *Scan) error {
+func setScan(block scfg.Block, scan *scan) error {
scanDir := block.Get("scan")
err := setString(scanDir, &scan.Path)
if err != nil {
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index c8cd8876055e2cabe66e1ee574b5c36df358efcb..7afbaef263f86b987b586cc5cb70cc6488a2d994 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -8,17 +8,17 @@
"github.com/google/go-cmp/cmp"
)
-func TestConfig(t *testing.T) {
+func TestFileParsing(t *testing.T) {
testCases := []struct {
name string
config string
- expectedConfig *Configuration
+ expectedConfig *configuration
}{
{
name: "minimal scan",
config: `scan "/srv/git"`,
- expectedConfig: &Configuration{
- Scan: &Scan{
+ expectedConfig: &configuration{
+ Scan: &scan{
Public: true,
Path: "/srv/git",
},
@@ -29,8 +29,8 @@ name: "complete scan",
config: `scan "/srv/git" {
public false
}`,
- expectedConfig: &Configuration{
- Scan: &Scan{
+ expectedConfig: &configuration{
+ Scan: &scan{
Public: false,
Path: "/srv/git",
},
@@ -41,7 +41,7 @@
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := strings.NewReader(tc.config)
- config, err := Parse(r)
+ config, err := parse(r)
if err != nil {
t.Fatalf("Error parsing config %s", err.Error())
}
diff --git a/pkg/git/git.go b/pkg/git/git.go
index 85a3b9560ac63e1915751dc8407365e72539c8fc..b9ab235f7226301c7f57ca245c5b1660fa6230b9 100644
--- a/pkg/git/git.go
+++ b/pkg/git/git.go
@@ -2,63 +2,29 @@ package git
import (
"errors"
- "os"
- "path"
- "git.gabrielgio.me/cerrado/pkg/u"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/object"
)
+var ()
+
var (
- ScanPathErr = errors.New("Scan path does not exist")
- RepoPathErr = errors.New("Repository path does not exist")
- missingHeadErr = errors.New("Head not found")
+ MissingHeadErr = errors.New("Head not found")
)
type (
- GitServerRepository struct {
- scanPath string
- }
-
GitRepository struct {
path string
}
)
-func NewGitServerRepository(scanPath string) *GitServerRepository {
- return &GitServerRepository{scanPath}
-}
-
func NewGitRepository(dir string) *GitRepository {
return &GitRepository{
path: dir,
}
}
-func (g *GitServerRepository) List() ([]*GitRepository, error) {
- if !u.FileExist(g.scanPath) {
- return nil, ScanPathErr
- }
-
- entries, err := os.ReadDir(g.scanPath)
- if err != nil {
- return nil, err
- }
-
- repos := make([]*GitRepository, 0)
- for _, e := range entries {
- if !e.IsDir() {
- continue
- }
-
- fullPath := path.Join(g.scanPath, e.Name())
- repos = append(repos, NewGitRepository(fullPath))
- }
-
- return repos, nil
-}
-
func (g *GitRepository) Path() string {
return g.path
}
@@ -71,7 +37,7 @@ }
ref, err := repo.Head()
if err != nil {
- return nil, errors.Join(missingHeadErr, err)
+ return nil, errors.Join(MissingHeadErr, err)
}
c, err := repo.CommitObject(ref.Hash())
diff --git a/pkg/handler/about.go b/pkg/handler/about/handler.go
rename from pkg/handler/about.go
rename to pkg/handler/about/handler.go
index 3ab2de880549e94be04543d4a0d4698d5d87f2b5..a2caa4eeea02e1e6885069fc90f0d1ef479b4798 100644
--- a/pkg/handler/about.go
+++ b/pkg/handler/about/handler.go
@@ -1,4 +1,4 @@
-package handler
+package about
import (
"io"
@@ -13,12 +13,18 @@
"git.gabrielgio.me/cerrado/templates"
)
-type AboutHandler struct {
- readmePath string
-}
+type (
+ AboutHandler struct {
+ readmePath string
+ }
-func NewAboutHandler(readmePath string) *AboutHandler {
- return &AboutHandler{readmePath}
+ configurationRepository interface {
+ GetRootReadme() string
+ }
+)
+
+func NewAboutHandler(configRepo configurationRepository) *AboutHandler {
+ return &AboutHandler{configRepo.GetRootReadme()}
}
func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) {
diff --git a/pkg/handler/git.go b/pkg/handler/git/handler.go
rename from pkg/handler/git.go
rename to pkg/handler/git/handler.go
index 1ed2c49d357ffbb4b74f2a2331cd84fd6a660794..236ac414a2ce8afb92d6c86bc64781a7f8189904 100644
--- a/pkg/handler/git.go
+++ b/pkg/handler/git/handler.go
@@ -1,4 +1,4 @@
-package handler
+package git
import (
"log/slog"
@@ -8,12 +8,20 @@ "git.gabrielgio.me/cerrado/pkg/service"
"git.gabrielgio.me/cerrado/templates"
)
-type GitHandler struct {
- gitService *service.GitService
-}
+type (
+ GitHandler struct {
+ gitService gitService
+ }
-func NewGitHandler(gitService *service.GitService) *GitHandler {
- return &GitHandler{gitService}
+ gitService interface {
+ ListRepositories() ([]*service.Repository, error)
+ }
+)
+
+func NewGitHandler(gitService gitService) *GitHandler {
+ return &GitHandler{
+ gitService: gitService,
+ }
}
func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) {
diff --git a/pkg/handler/router.go b/pkg/handler/router.go
new file mode 100644
index 0000000000000000000000000000000000000000..a8c9c6f227152e0602af3786f023508c563419d0
--- /dev/null
+++ b/pkg/handler/router.go
@@ -0,0 +1,38 @@
+package handler
+
+import (
+ "net/http"
+
+ serverconfig "git.gabrielgio.me/cerrado/pkg/config"
+ "git.gabrielgio.me/cerrado/pkg/handler/about"
+ "git.gabrielgio.me/cerrado/pkg/handler/config"
+ "git.gabrielgio.me/cerrado/pkg/handler/git"
+ "git.gabrielgio.me/cerrado/pkg/handler/static"
+ "git.gabrielgio.me/cerrado/pkg/service"
+)
+
+// Mount handler gets the requires service and repository to build the handlers
+// This functons wraps the whole handler package and wraps it into one part so
+// its sub package don't leak in other places.
+func MountHandler(
+ gitService *service.GitService,
+ configRepo *serverconfig.ConfigurationRepository,
+) (http.Handler, error) {
+ var (
+ gitHandler = git.NewGitHandler(gitService)
+ aboutHandler = about.NewAboutHandler(configRepo)
+ configHander = config.ConfigFile(configRepo)
+ )
+
+ staticHandler, err := static.NewStaticHander("/static/")
+ if err != nil {
+ return nil, err
+ }
+
+ mux := http.NewServeMux()
+ mux.Handle("/static/", staticHandler)
+ mux.HandleFunc("/config", configHander)
+ mux.HandleFunc("/about", aboutHandler.About)
+ mux.HandleFunc("/", gitHandler.List)
+ return mux, nil
+}
diff --git a/pkg/handler/static.go b/pkg/handler/static/handler.go
rename from pkg/handler/static.go
rename to pkg/handler/static/handler.go
index 9f312f41f09ef14dad4649bfaa0b76d61f8abb5e..6a826cc988aa4d11f5f71417b4a3198a7d611882 100644
--- a/pkg/handler/static.go
+++ b/pkg/handler/static/handler.go
@@ -1,4 +1,4 @@
-package handler
+package static
import (
"io/fs"
diff --git a/pkg/handler/status.go b/pkg/handler/config/handler.go
rename from pkg/handler/status.go
rename to pkg/handler/config/handler.go
index 9baac2c47a3fce61a82cc9451ecc92e8de179c87..c278e35d0e624ac09c1a0065f0f906bd6e88dfe1 100644
--- a/pkg/handler/status.go
+++ b/pkg/handler/config/handler.go
@@ -1,11 +1,10 @@
-package handler
+package config
import (
"bytes"
"encoding/json"
"log/slog"
"net/http"
- "os"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
@@ -15,21 +14,25 @@ "git.gabrielgio.me/cerrado/pkg/config"
"git.gabrielgio.me/cerrado/templates"
)
-func ConfigFile(configPath string) func(http.ResponseWriter, *http.Request) {
+type (
+ configurationRepository interface {
+ GetRootReadme() string
+ List() []*config.GitRepositoryConfiguration
+ }
+)
+
+func ConfigFile(configRepo configurationRepository) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, _ *http.Request) {
- f, err := os.Open(configPath)
- if err != nil {
- slog.Error("Error openning config file", "error", err, "path", configPath)
- return
- }
- c, err := config.Parse(f)
- if err != nil {
- slog.Error("Error parsing config", "error", err, "path", configPath)
- return
+ config := struct {
+ RootReadme string
+ Repositories []*config.GitRepositoryConfiguration
+ }{
+ RootReadme: configRepo.GetRootReadme(),
+ Repositories: configRepo.List(),
}
- b, err := json.MarshalIndent(c, "", " ")
+ b, err := json.MarshalIndent(config, "", " ")
if err != nil {
slog.Error("Error parsing json", "error", err)
return
diff --git a/pkg/service/git.go b/pkg/service/git.go
index 94ca75e454f3af3b40f834ea5f858b37b6e56efd..2b1fe252f8e7785238896329ceca3305c71b817c 100644
--- a/pkg/service/git.go
+++ b/pkg/service/git.go
@@ -3,44 +3,48 @@
import (
"path"
+ "git.gabrielgio.me/cerrado/pkg/config"
"git.gabrielgio.me/cerrado/pkg/git"
)
type (
- GitService struct {
- server *git.GitServerRepository
- }
Repository struct {
Name string
Title string
LastCommitMessage string
LastCommitDate string
}
+
+ GitService struct {
+ configRepo configurationRepository
+ }
+
+ configurationRepository interface {
+ List() []*config.GitRepositoryConfiguration
+ }
)
// TODO: make it configurable
const timeFormat = "2006.01.02 15:04:05"
-func NewGitService(server *git.GitServerRepository) *GitService {
+func NewGitService(configRepo configurationRepository) *GitService {
return &GitService{
- server: server,
+ configRepo: configRepo,
}
}
func (g *GitService) ListRepositories() ([]*Repository, error) {
- rs, err := g.server.List()
- if err != nil {
- return nil, err
- }
+ rs := g.configRepo.List()
repos := make([]*Repository, len(rs))
for i, r := range rs {
- obj, err := r.LastCommit()
+ repo := git.NewGitRepository(r.Path)
+ obj, err := repo.LastCommit()
if err != nil {
return nil, err
}
- baseName := path.Base(r.Path())
+ baseName := path.Base(r.Path)
repos[i] = &Repository{
Name: baseName,
Title: baseName,