Compare commits

...

2 Commits

Author SHA1 Message Date
Massaki Archambault 0a50158239 add config tests 2024-06-08 01:02:35 -04:00
Massaki Archambault a4ed751abd move config loader to its own package 2024-06-07 23:42:13 -04:00
5 changed files with 288 additions and 92 deletions

View File

@ -14,6 +14,12 @@ gitlab:
# Default to anonymous (only public projects will be visible). # Default to anonymous (only public projects will be visible).
#token: #token:
# Must be set to either "http" or "ssh".
# The protocol to configure the git remote on.
# "http" may not work on private repos unless a credential manager is configured
# If possible, prefer "ssh" over "http"
pull_method: http
# A list of the group ids to expose their projects in the filesystem. # A list of the group ids to expose their projects in the filesystem.
group_ids: group_ids:
- 9970 # gitlab-org - 9970 # gitlab-org
@ -32,12 +38,6 @@ git:
# The name of the remote in the local clone. # The name of the remote in the local clone.
remote: origin remote: origin
# Must be set to either "http" or "ssh".
# The protocol to configure the git remote on.
# "http" may not work on private repos unless a credential manager is configured
# If possible, prefer "ssh" over "http"
pull_method: http
# Must be set to either "init", or "clone". # Must be set to either "init", or "clone".
# If set to "init", the local copy will be initialized with `git init` and the remote is configured manually. The git server is nerver queried. (fast) # If set to "init", the local copy will be initialized with `git init` and the remote is configured manually. The git server is nerver queried. (fast)
# If set to "clone", the local copy will be initialized with `git clone`. (slow) # If set to "clone", the local copy will be initialized with `git clone`. (slow)

22
config/config.test.yaml Normal file
View File

@ -0,0 +1,22 @@
fs:
mountpoint: /tmp/gitlabfs/test/mnt
mountoptions: nodev
gitlab:
url: https://example.com
token: "12345"
group_ids:
- 123
user_ids:
- 456
include_current_user: true
pull_method: ssh
git:
clone_location: /tmp/gitlabfs/test/clone
remote: origin
on_clone: clone
auto_pull: false
depth: 0
queue_size: 100
worker_count: 1

89
config/loader.go Normal file
View File

@ -0,0 +1,89 @@
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/badjware/gitlabfs/git"
"github.com/badjware/gitlabfs/platforms/gitlab"
"gopkg.in/yaml.v2"
)
type (
Config struct {
FS FSConfig `yaml:"fs,omitempty"`
Gitlab gitlab.GitlabClientConfig `yaml:"gitlab,omitempty"`
Git git.GitClientParam `yaml:"git,omitempty"`
}
FSConfig struct {
Mountpoint string `yaml:"mountpoint,omitempty"`
MountOptions string `yaml:"mountoptions,omitempty"`
}
)
func LoadConfig(configPath string) (*Config, error) {
// defaults
dataHome := os.Getenv("XDG_DATA_HOME")
if dataHome == "" {
dataHome = filepath.Join(os.Getenv("HOME"), ".local/share")
}
defaultCloneLocation := filepath.Join(dataHome, "gitlabfs")
config := &Config{
FS: FSConfig{
Mountpoint: "",
MountOptions: "nodev,nosuid",
},
Gitlab: gitlab.GitlabClientConfig{
URL: "https://gitlab.com",
Token: "",
PullMethod: "http",
GroupIDs: []int{9970},
UserIDs: []int{},
IncludeCurrentUser: true,
},
Git: git.GitClientParam{
CloneLocation: defaultCloneLocation,
Remote: "origin",
OnClone: "init",
AutoPull: false,
Depth: 0,
QueueSize: 200,
QueueWorkerCount: 5,
},
}
if configPath != "" {
f, err := os.Open(configPath)
if err != nil {
return nil, fmt.Errorf("failed to open config file: %v", err)
}
defer f.Close()
d := yaml.NewDecoder(f)
if err := d.Decode(config); err != nil {
return nil, fmt.Errorf("failed to parse config file: %v", err)
}
}
return config, nil
}
func MakeGitConfig(config *Config) (*git.GitClientParam, error) {
// parse on_clone
if config.Git.OnClone != "init" && config.Git.OnClone != "clone" {
return nil, fmt.Errorf("on_clone must be either \"init\" or \"clone\"")
}
return &config.Git, nil
}
func MakeGitlabConfig(config *Config) (*gitlab.GitlabClientConfig, error) {
// parse pull_method
if config.Gitlab.PullMethod != gitlab.PullMethodHTTP && config.Gitlab.PullMethod != gitlab.PullMethodSSH {
return nil, fmt.Errorf("pull_method must be either \"%v\" or \"%v\"", gitlab.PullMethodHTTP, gitlab.PullMethodSSH)
}
return &config.Gitlab, nil
}

164
config/loader_test.go Normal file
View File

@ -0,0 +1,164 @@
package config_test
import (
"reflect"
"testing"
"github.com/badjware/gitlabfs/config"
"github.com/badjware/gitlabfs/git"
"github.com/badjware/gitlabfs/platforms/gitlab"
)
func TestLoadConfig(t *testing.T) {
tests := map[string]struct {
input string
expected *config.Config
}{
"LoadConfig": {
input: "config.test.yaml",
expected: &config.Config{
FS: config.FSConfig{
Mountpoint: "/tmp/gitlabfs/test/mnt",
MountOptions: "nodev",
},
Gitlab: gitlab.GitlabClientConfig{
URL: "https://example.com",
Token: "12345",
PullMethod: "ssh",
GroupIDs: []int{123},
UserIDs: []int{456},
IncludeCurrentUser: true,
},
Git: git.GitClientParam{
CloneLocation: "/tmp/gitlabfs/test/clone",
Remote: "origin",
OnClone: "clone",
AutoPull: false,
Depth: 0,
QueueSize: 100,
QueueWorkerCount: 1,
}},
},
}
for name, test := range tests {
test := test
t.Run(name, func(t *testing.T) {
t.Parallel()
got, err := config.LoadConfig(test.input)
expected := test.expected
if !reflect.DeepEqual(got, expected) {
t.Fatalf("LoadConfig(%v) returned %v; expected %v; error: %v", test.input, got, expected, err)
}
})
}
}
func TestMakeGitConfig(t *testing.T) {
tests := map[string]struct {
input *config.Config
expected *git.GitClientParam
}{
"ValidConfig": {
input: &config.Config{
Git: git.GitClientParam{
CloneLocation: "/tmp",
Remote: "origin",
OnClone: "init",
AutoPull: false,
Depth: 0,
QueueSize: 200,
QueueWorkerCount: 5,
},
},
expected: &git.GitClientParam{
CloneLocation: "/tmp",
Remote: "origin",
OnClone: "init",
AutoPull: false,
Depth: 0,
QueueSize: 200,
QueueWorkerCount: 5,
},
},
"InvalidOnClone": {
input: &config.Config{
Git: git.GitClientParam{
CloneLocation: "/tmp",
Remote: "origin",
OnClone: "invalid",
AutoPull: false,
Depth: 0,
QueueSize: 200,
QueueWorkerCount: 5,
},
},
expected: nil,
},
}
for name, test := range tests {
test := test
t.Run(name, func(t *testing.T) {
t.Parallel()
got, err := config.MakeGitConfig(test.input)
expected := test.expected
if !reflect.DeepEqual(got, expected) {
t.Fatalf("MakeGitConfig(%v) returned %v; expected %v; error %v", test.input, got, expected, err)
}
})
}
}
func TestMakeGitlabConfig(t *testing.T) {
tests := map[string]struct {
input *config.Config
expected *gitlab.GitlabClientConfig
}{
"ValidConfig": {
input: &config.Config{
Gitlab: gitlab.GitlabClientConfig{
URL: "https://gitlab.com",
Token: "",
GroupIDs: []int{9970},
UserIDs: []int{},
IncludeCurrentUser: true,
PullMethod: "http",
},
},
expected: &gitlab.GitlabClientConfig{
URL: "https://gitlab.com",
Token: "",
GroupIDs: []int{9970},
UserIDs: []int{},
IncludeCurrentUser: true,
PullMethod: "http",
},
},
"InvalidPullMethod": {
input: &config.Config{
Gitlab: gitlab.GitlabClientConfig{
URL: "https://gitlab.com",
Token: "",
GroupIDs: []int{9970},
UserIDs: []int{},
IncludeCurrentUser: true,
PullMethod: "invalid",
},
},
expected: nil,
},
}
for name, test := range tests {
test := test
t.Run(name, func(t *testing.T) {
t.Parallel()
got, err := config.MakeGitlabConfig(test.input)
expected := test.expected
if !reflect.DeepEqual(got, expected) {
t.Fatalf("MakeGitlabConfig(%v) returned %v; expected %v; error: %v", test.input, got, expected, err)
}
})
}
}

93
main.go
View File

@ -5,93 +5,14 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/badjware/gitlabfs/config"
"github.com/badjware/gitlabfs/fstree" "github.com/badjware/gitlabfs/fstree"
"github.com/badjware/gitlabfs/git" "github.com/badjware/gitlabfs/git"
"github.com/badjware/gitlabfs/platforms/gitlab" "github.com/badjware/gitlabfs/platforms/gitlab"
"gopkg.in/yaml.v2"
) )
type (
Config struct {
FS FSConfig `yaml:"fs,omitempty"`
Gitlab gitlab.GitlabClientConfig `yaml:"gitlab,omitempty"`
Git git.GitClientParam `yaml:"git,omitempty"`
}
FSConfig struct {
Mountpoint string `yaml:"mountpoint,omitempty"`
MountOptions string `yaml:"mountoptions,omitempty"`
}
)
func loadConfig(configPath string) (*Config, error) {
// defaults
dataHome := os.Getenv("XDG_DATA_HOME")
if dataHome == "" {
dataHome = filepath.Join(os.Getenv("HOME"), ".local/share")
}
defaultCloneLocation := filepath.Join(dataHome, "gitlabfs")
config := &Config{
FS: FSConfig{
Mountpoint: "",
MountOptions: "nodev,nosuid",
},
Gitlab: gitlab.GitlabClientConfig{
URL: "https://gitlab.com",
Token: "",
GroupIDs: []int{9970},
UserIDs: []int{},
IncludeCurrentUser: true,
PullMethod: "http",
},
Git: git.GitClientParam{
CloneLocation: defaultCloneLocation,
Remote: "origin",
OnClone: "init",
AutoPull: false,
Depth: 0,
QueueSize: 200,
QueueWorkerCount: 5,
},
}
if configPath != "" {
f, err := os.Open(configPath)
if err != nil {
return nil, fmt.Errorf("failed to open config file: %v", err)
}
defer f.Close()
d := yaml.NewDecoder(f)
if err := d.Decode(config); err != nil {
return nil, fmt.Errorf("failed to parse config file: %v", err)
}
}
return config, nil
}
func makeGitlabConfig(config *Config) (*gitlab.GitlabClientConfig, error) {
// parse pull_method
if config.Gitlab.PullMethod != gitlab.PullMethodHTTP && config.Gitlab.PullMethod != gitlab.PullMethodSSH {
return nil, fmt.Errorf("pull_method must be either \"%v\" or \"%v\"", gitlab.PullMethodHTTP, gitlab.PullMethodSSH)
}
return &config.Gitlab, nil
}
func makeGitConfig(config *Config) (*git.GitClientParam, error) {
// parse on_clone
if config.Git.OnClone != "init" && config.Git.OnClone != "clone" {
return nil, fmt.Errorf("on_clone must be either \"init\" or \"clone\"")
}
return &config.Git, nil
}
func main() { func main() {
configPath := flag.String("config", "", "The config file") configPath := flag.String("config", "", "The config file")
mountoptionsFlag := flag.String("o", "", "Filesystem mount options. See mount.fuse(8)") mountoptionsFlag := flag.String("o", "", "Filesystem mount options. See mount.fuse(8)")
@ -105,7 +26,7 @@ func main() {
} }
flag.Parse() flag.Parse()
config, err := loadConfig(*configPath) loadedConfig, err := config.LoadConfig(*configPath)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
@ -115,7 +36,7 @@ func main() {
logger := slog.Default() logger := slog.Default()
// Configure mountpoint // Configure mountpoint
mountpoint := config.FS.Mountpoint mountpoint := loadedConfig.FS.Mountpoint
if flag.NArg() == 1 { if flag.NArg() == 1 {
mountpoint = flag.Arg(0) mountpoint = flag.Arg(0)
} }
@ -126,7 +47,7 @@ func main() {
} }
// Configure mountoptions // Configure mountoptions
mountoptions := config.FS.MountOptions mountoptions := loadedConfig.FS.MountOptions
if *mountoptionsFlag != "" { if *mountoptionsFlag != "" {
mountoptions = *mountoptionsFlag mountoptions = *mountoptionsFlag
} }
@ -136,7 +57,7 @@ func main() {
} }
// Create the git client // Create the git client
gitClientParam, err := makeGitConfig(config) gitClientParam, err := config.MakeGitConfig(loadedConfig)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
@ -144,12 +65,12 @@ func main() {
gitClient, _ := git.NewClient(logger, *gitClientParam) gitClient, _ := git.NewClient(logger, *gitClientParam)
// Create the gitlab client // Create the gitlab client
GitlabClientConfig, err := makeGitlabConfig(config) GitlabClientConfig, err := config.MakeGitlabConfig(loadedConfig)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
gitlabClient, _ := gitlab.NewClient(logger, config.Gitlab.URL, config.Gitlab.Token, *GitlabClientConfig) gitlabClient, _ := gitlab.NewClient(logger, loadedConfig.Gitlab.URL, loadedConfig.Gitlab.Token, *GitlabClientConfig)
// Start the filesystem // Start the filesystem
err = fstree.Start( err = fstree.Start(