This commit is contained in:
commit
9f416f4b7e
15 changed files with 286 additions and 0 deletions
25
.golangci.yaml
Normal file
25
.golangci.yaml
Normal file
|
@ -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
|
6
.woodpecker/lint.yaml
Normal file
6
.woodpecker/lint.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
steps:
|
||||||
|
lint:
|
||||||
|
image: golang:1.22
|
||||||
|
commands:
|
||||||
|
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||||
|
- golangci-lint run
|
3
README.adoc
Normal file
3
README.adoc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
= A light git repository mirror tools
|
||||||
|
|
||||||
|
Yes, i have no cool name idea for this project
|
13
config.example.toml
Normal file
13
config.example.toml
Normal file
|
@ -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"
|
18
docs/config/README.adoc
Normal file
18
docs/config/README.adoc
Normal file
|
@ -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[]
|
||||||
|
----
|
9
go.mod
Normal file
9
go.mod
Normal file
|
@ -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
|
||||||
|
)
|
26
go.sum
Normal file
26
go.sum
Normal file
|
@ -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=
|
14
internal/config/config.go
Normal file
14
internal/config/config.go
Normal file
|
@ -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)
|
||||||
|
}
|
9
internal/config/errors.go
Normal file
9
internal/config/errors.go
Normal file
|
@ -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")
|
||||||
|
)
|
13
internal/config/test_resources/valid.toml
Normal file
13
internal/config/test_resources/valid.toml
Normal file
|
@ -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"
|
46
internal/config/toml.go
Normal file
46
internal/config/toml.go
Normal file
|
@ -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
|
||||||
|
}
|
48
internal/config/toml_test.go
Normal file
48
internal/config/toml_test.go
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
6
internal/log/config.go
Normal file
6
internal/log/config.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package log
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Level string
|
||||||
|
File string // Output file for log, default stderr
|
||||||
|
}
|
33
internal/log/init.go
Normal file
33
internal/log/init.go
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
17
main.go
Normal file
17
main.go
Normal file
|
@ -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)
|
||||||
|
}
|
Loading…
Reference in a new issue