From 8f4486698a44693b5a061dc21fed574a1375189d Mon Sep 17 00:00:00 2001 From: Ada Date: Thu, 4 Apr 2024 01:12:42 +0200 Subject: [PATCH] :tada: First commit --- .golangci.yaml | 25 ++++++++++++ .woodpecker/test.yaml | 9 +++++ README.adoc | 3 ++ config.example.toml | 13 ++++++ docs/config/README.adoc | 18 +++++++++ go.mod | 9 +++++ go.sum | 26 ++++++++++++ internal/config/config.go | 14 +++++++ internal/config/errors.go | 9 +++++ internal/config/test_resources/valid.toml | 13 ++++++ internal/config/toml.go | 46 ++++++++++++++++++++++ internal/config/toml_test.go | 48 +++++++++++++++++++++++ internal/log/config.go | 6 +++ internal/log/init.go | 33 ++++++++++++++++ main.go | 17 ++++++++ 15 files changed, 289 insertions(+) create mode 100644 .golangci.yaml create mode 100644 .woodpecker/test.yaml create mode 100644 README.adoc create mode 100644 config.example.toml create mode 100644 docs/config/README.adoc create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/config/config.go create mode 100644 internal/config/errors.go create mode 100644 internal/config/test_resources/valid.toml create mode 100644 internal/config/toml.go create mode 100644 internal/config/toml_test.go create mode 100644 internal/log/config.go create mode 100644 internal/log/init.go create mode 100644 main.go diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..99c947d --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,25 @@ +linters: + enable-all: true + disable: + # Deprecated + - varcheck + - ifshort + - interfacer + - maligned + - deadcode + - scopelint + - golint + - structcheck + - exhaustivestruct + - nosnakecase + # To extremist/unusable + - depguard + - varnamelen + - exhaustruct + - wsl + - contextcheck + - wrapcheck +linters-settings: + lll: + # Too short by default + line-length: 160 \ No newline at end of file diff --git a/.woodpecker/test.yaml b/.woodpecker/test.yaml new file mode 100644 index 0000000..e3e7317 --- /dev/null +++ b/.woodpecker/test.yaml @@ -0,0 +1,9 @@ +steps: + lint: + image: golangci/golangci-lint:latest + commands: + - golangci-lint run + test: + image: golang:1.22 + commands: + - go test ./... diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..c4d2253 --- /dev/null +++ b/README.adoc @@ -0,0 +1,3 @@ += A light git repository mirror tools + +Yes, i have no cool name idea for this project \ No newline at end of file diff --git a/config.example.toml b/config.example.toml new file mode 100644 index 0000000..436d4a3 --- /dev/null +++ b/config.example.toml @@ -0,0 +1,13 @@ +clonedirectory = "archive/" + +[log] +level = "DEBUG" +file = "" # Default in stderr + +[[RepoList]] +URL = "https://github.com/torvalds/linux/" +name = "linux" + +[[RepoList]] +URL = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" +name = "linuxtwo" \ No newline at end of file diff --git a/docs/config/README.adoc b/docs/config/README.adoc new file mode 100644 index 0000000..0ed3e4d --- /dev/null +++ b/docs/config/README.adoc @@ -0,0 +1,18 @@ += Configuration + +File format used is https://toml.io/en/[toml] + +== Options: +* `clonedirectory`: Directory where mirror is clone +* `log`: Log config section +** `level`: Log level, allowed value is: "DEBUG", "INFO", "WARN", "ERROR", "FATAL" +** `file`: Log file, default (empty) is in stderr +** `RepoList`: List of mirrored git repository +*** `URL`: Source URL +*** `name`: directory name of clone + +== Example: +[source,toml] +---- +include::../../config.example.toml[] +---- diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0015a86 --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module git.gnous.eu/ada/git-mirror + +go 1.22 + +require ( + github.com/pelletier/go-toml/v2 v2.2.0 + github.com/sirupsen/logrus v1.9.3 + golang.org/x/sys v0.18.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d82dacc --- /dev/null +++ b/go.sum @@ -0,0 +1,26 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= +github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..911b5a8 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,14 @@ +package config + +import "git.gnous.eu/ada/git-mirror/internal/log" + +type Config struct { + CloneDirectory string // Repository where gir-mirror keep repository + Log log.Config + RepoList []repoConfig +} + +type repoConfig struct { + URL string // Source url + Name string // Name of clone (directory name) +} diff --git a/internal/config/errors.go b/internal/config/errors.go new file mode 100644 index 0000000..6289e9f --- /dev/null +++ b/internal/config/errors.go @@ -0,0 +1,9 @@ +package config + +import "errors" + +var ( + errLogLevel = errors.New("log level is invalid, valid list is : \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"FATAL\"") + errCloneDirectoryUnwritable = errors.New("clone directory is not writable") + errConfigFileNotReadable = errors.New("config file is not loadable") +) diff --git a/internal/config/test_resources/valid.toml b/internal/config/test_resources/valid.toml new file mode 100644 index 0000000..4cdabab --- /dev/null +++ b/internal/config/test_resources/valid.toml @@ -0,0 +1,13 @@ +clonedirectory = "archive/" + +[log] +level = "WARN" +file = "log.txt" + +[[RepoList]] +URL = "https://github.com/torvalds/linux/" +name = "linux" + +[[RepoList]] +URL = "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" +name = "linuxtwo" diff --git a/internal/config/toml.go b/internal/config/toml.go new file mode 100644 index 0000000..4c69493 --- /dev/null +++ b/internal/config/toml.go @@ -0,0 +1,46 @@ +package config + +import ( + "os" + + "github.com/pelletier/go-toml/v2" + "golang.org/x/sys/unix" +) + +func LoadToml(file string) (Config, error) { + var config Config + + source, err := os.ReadFile(file) + if err != nil { + return config, errConfigFileNotReadable + } + + err = toml.Unmarshal(source, &config) + if err != nil { + panic(err) + } + + return config, nil +} + +func VerifyConfig(config Config) error { + allowedValue := []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"} + found := false + for _, v := range allowedValue { + if v == config.Log.Level { + found = true + } + } + + if !found { + return errLogLevel + } + + if unix.Access(config.CloneDirectory, unix.W_OK) != nil { + return errCloneDirectoryUnwritable + } + + // TODO: verify RepoList not redundant + + return nil +} diff --git a/internal/config/toml_test.go b/internal/config/toml_test.go new file mode 100644 index 0000000..caa6c89 --- /dev/null +++ b/internal/config/toml_test.go @@ -0,0 +1,48 @@ +package config_test + +import ( + "testing" + + "git.gnous.eu/ada/git-mirror/internal/config" +) + +func TestToml(t *testing.T) { + t.Parallel() + testLoadTomlValid(t) +} + +func testLoadTomlValid(t *testing.T) { + t.Helper() + got, err := config.LoadToml("test_resources/valid.toml") + if err != nil { + t.Fatal("Cannot load config: ", err) + } + // {aa {WARN } [{aa yy} {bb yy}]} + if got.CloneDirectory != "archive/" { + t.Fatal("Invalid CloneDirectory: ", got.CloneDirectory) + } + + if got.Log.Level != "WARN" { + t.Fatal("Invalid log level: ", got.Log.Level) + } + + if got.Log.File != "log.txt" { + t.Fatal("Invalid log file: ", got.Log.File) + } + + if got.RepoList[0].Name != "linux" { + t.Fatal("Invalid first repo name: ", got.RepoList[0].Name) + } + + if got.RepoList[0].URL != "https://github.com/torvalds/linux/" { + t.Fatal("Invalid first repo url: ", got.RepoList[0].URL) + } + + if got.RepoList[1].Name != "linuxtwo" { + t.Fatal("Invalid second repo name: ", got.RepoList[1].Name) + } + + if got.RepoList[1].URL != "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" { + t.Fatal("Invalid second repo URL: ", got.RepoList[1].URL) + } +} diff --git a/internal/log/config.go b/internal/log/config.go new file mode 100644 index 0000000..0f09914 --- /dev/null +++ b/internal/log/config.go @@ -0,0 +1,6 @@ +package log + +type Config struct { + Level string + File string // Output file for log, default stderr +} diff --git a/internal/log/init.go b/internal/log/init.go new file mode 100644 index 0000000..a8b123a --- /dev/null +++ b/internal/log/init.go @@ -0,0 +1,33 @@ +package log + +import ( + "os" + + "github.com/sirupsen/logrus" +) + +func (config Config) Init() { + if config.File != "" { + file, err := os.OpenFile(config.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o640) //nolint:gomnd + if err != nil { + logrus.Fatal("Cannot open log file: ", err) + } + logrus.SetOutput(file) + } + + if config.Level == "DEBUG" { + logrus.SetLevel(logrus.DebugLevel) + } + if config.Level == "INFO" { + logrus.SetLevel(logrus.InfoLevel) + } + if config.Level == "WARN" { + logrus.SetLevel(logrus.WarnLevel) + } + if config.Level == "ERROR" { + logrus.SetLevel(logrus.ErrorLevel) + } + if config.Level == "FATAL" { + logrus.SetLevel(logrus.ErrorLevel) + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..19dba9d --- /dev/null +++ b/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "git.gnous.eu/ada/git-mirror/internal/config" + "github.com/sirupsen/logrus" +) + +func main() { + initConfig, err := config.LoadToml("config.example.toml") + if err != nil { + logrus.Fatal(err) + } + + initConfig.Log.Init() + logrus.Info("Config loaded") + logrus.Debug("Config: ", initConfig) +}