Compare commits
6 Commits
36b3963ac3
...
1a01c9ecea
Author | SHA1 | Date |
---|---|---|
Massaki Archambault | 1a01c9ecea | |
Massaki Archambault | 0e5fed0bbd | |
Massaki Archambault | 382a0f6d8d | |
Massaki Archambault | 937e5c341d | |
Massaki Archambault | a0aaa4491b | |
Massaki Archambault | 4e2b631a0c |
|
@ -6,6 +6,10 @@ fs:
|
|||
# See mount.fuse(8) for the full list of options.
|
||||
#mountoptions: nodev,nosuid
|
||||
|
||||
# The git forge to use as the backend.
|
||||
# Must be one of "gitlab" or "github"
|
||||
forge: gitlab
|
||||
|
||||
gitlab:
|
||||
# The gitlab url.
|
||||
url: https://gitlab.com
|
||||
|
@ -16,7 +20,7 @@ gitlab:
|
|||
|
||||
# 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
|
||||
# "http" may not work on private projects unless a credential manager is configured
|
||||
# If possible, prefer "ssh" over "http"
|
||||
pull_method: http
|
||||
|
||||
|
@ -28,7 +32,7 @@ gitlab:
|
|||
user_ids: []
|
||||
|
||||
# Set how archived projects are handled.
|
||||
# If set to "show", it will add them to the filesystem and treat them like any other repository
|
||||
# If set to "show", it will add them to the filesystem and treat them like any other project
|
||||
# If set to "hide", it will add them to the filesystem, but prefix the symlink with a "."
|
||||
# If set to "ignore", it will make them absent from the filesystem
|
||||
# Default to "hide"
|
||||
|
@ -37,6 +41,35 @@ gitlab:
|
|||
# If set to true, the user the api token belongs to will automatically be added to the list of users exposed by the filesystem.
|
||||
include_current_user: true
|
||||
|
||||
github:
|
||||
# The github api token
|
||||
# Default to anonymous (only public repositories will be visible)
|
||||
#token:
|
||||
|
||||
# Must be set to either "http" or "ssh".
|
||||
# The protocol to configure the git remote on.
|
||||
# "http" may not work on private repositories unless a credential manager is configured
|
||||
# If possible, prefer "ssh" over "http"
|
||||
pull_method: http
|
||||
|
||||
# A list of the name of the organizations to expose in the filesystem
|
||||
org_names: []
|
||||
|
||||
# A list of the name of the user to expose their repositories un the filesystem
|
||||
user_names: []
|
||||
|
||||
# Set how archived repositories are handled.
|
||||
# If set to "show", it will add them to the filesystem and treat them like any other repository
|
||||
# If set to "hide", it will add them to the filesystem, but prefix the symlink with a "."
|
||||
# If set to "ignore", it will make them absent from the filesystem
|
||||
# Default to "hide"
|
||||
archived_repo_handling: hide
|
||||
|
||||
# If set to true, the personal repositories and the repositories of the organizations the user the api token belongs to
|
||||
# will be automatically be added to the list of users exposed by the filesystem.
|
||||
include_current_user: true
|
||||
|
||||
|
||||
git:
|
||||
# Path to the local repository cache. Repositories in the filesystem will symlink to a folder in this path.
|
||||
# Default to $XDG_DATA_HOME/gitlabfs, or $HOME/.local/share/gitlabfs if the environment variable $XDG_DATA_HOME is unset.
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
fs:
|
||||
mountpoint: /tmp/gitlabfs/test/mnt
|
||||
mountpoint: /tmp/gitlabfs/test/mnt/gitlab
|
||||
mountoptions: nodev
|
||||
forge: gitlab
|
||||
|
||||
gitlab:
|
||||
url: https://example.com
|
||||
token: "12345"
|
||||
pull_method: ssh
|
||||
group_ids:
|
||||
- 123
|
||||
user_ids:
|
||||
- 456
|
||||
archived_project_handling: hide
|
||||
include_current_user: true
|
||||
|
||||
github:
|
||||
token: "12345"
|
||||
pull_method: http
|
||||
org_names:
|
||||
- test-org
|
||||
user_names:
|
||||
- test-user
|
||||
archived_repo_handling: hide
|
||||
include_current_user: true
|
||||
pull_method: ssh
|
||||
|
||||
git:
|
||||
clone_location: /tmp/gitlabfs/test/clone
|
||||
clone_location: /tmp/gitlabfs/test/cache/gitlab
|
||||
remote: origin
|
||||
on_clone: clone
|
||||
auto_pull: false
|
||||
|
|
112
config/loader.go
112
config/loader.go
|
@ -5,20 +5,62 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/badjware/gitlabfs/git"
|
||||
"github.com/badjware/gitlabfs/platforms/gitlab"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
ForgeGitlab = "gitlab"
|
||||
ForgeGithub = "github"
|
||||
|
||||
PullMethodHTTP = "http"
|
||||
PullMethodSSH = "ssh"
|
||||
|
||||
ArchivedProjectShow = "show"
|
||||
ArchivedProjectHide = "hide"
|
||||
ArchivedProjectIgnore = "ignore"
|
||||
)
|
||||
|
||||
type (
|
||||
Config struct {
|
||||
FS FSConfig `yaml:"fs,omitempty"`
|
||||
Gitlab gitlab.GitlabClientConfig `yaml:"gitlab,omitempty"`
|
||||
Git git.GitClientParam `yaml:"git,omitempty"`
|
||||
FS FSConfig `yaml:"fs,omitempty"`
|
||||
Gitlab GitlabClientConfig `yaml:"gitlab,omitempty"`
|
||||
Github GithubClientConfig `yaml:"github,omitempty"`
|
||||
Git GitClientConfig `yaml:"git,omitempty"`
|
||||
}
|
||||
FSConfig struct {
|
||||
Mountpoint string `yaml:"mountpoint,omitempty"`
|
||||
MountOptions string `yaml:"mountoptions,omitempty"`
|
||||
Forge string `yaml:"forge,omitempty"`
|
||||
}
|
||||
GitlabClientConfig struct {
|
||||
URL string `yaml:"url,omitempty"`
|
||||
Token string `yaml:"token,omitempty"`
|
||||
|
||||
GroupIDs []int `yaml:"group_ids,omitempty"`
|
||||
UserIDs []int `yaml:"user_ids,omitempty"`
|
||||
|
||||
ArchivedProjectHandling string `yaml:"archived_project_handling,omitempty"`
|
||||
IncludeCurrentUser bool `yaml:"include_current_user,omitempty"`
|
||||
PullMethod string `yaml:"pull_method,omitempty"`
|
||||
}
|
||||
GithubClientConfig struct {
|
||||
Token string `yaml:"token,omitempty"`
|
||||
|
||||
OrgNames []string `yaml:"org_names,omitempty"`
|
||||
UserNames []string `yaml:"user_names,omitempty"`
|
||||
|
||||
ArchivedRepoHandling string `yaml:"archived_repo_handling,omitempty"`
|
||||
IncludeCurrentUser bool `yaml:"include_current_user,omitempty"`
|
||||
PullMethod string `yaml:"pull_method,omitempty"`
|
||||
}
|
||||
GitClientConfig struct {
|
||||
CloneLocation string `yaml:"clone_location,omitempty"`
|
||||
Remote string `yaml:"remote,omitempty"`
|
||||
OnClone string `yaml:"on_clone,omitempty"`
|
||||
AutoPull bool `yaml:"auto_pull,omitempty"`
|
||||
Depth int `yaml:"depth,omitempty"`
|
||||
QueueSize int `yaml:"queue_size,omitempty"`
|
||||
QueueWorkerCount int `yaml:"worker_count,omitempty"`
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -34,8 +76,9 @@ func LoadConfig(configPath string) (*Config, error) {
|
|||
FS: FSConfig{
|
||||
Mountpoint: "",
|
||||
MountOptions: "nodev,nosuid",
|
||||
Forge: "",
|
||||
},
|
||||
Gitlab: gitlab.GitlabClientConfig{
|
||||
Gitlab: GitlabClientConfig{
|
||||
URL: "https://gitlab.com",
|
||||
Token: "",
|
||||
PullMethod: "http",
|
||||
|
@ -44,7 +87,15 @@ func LoadConfig(configPath string) (*Config, error) {
|
|||
ArchivedProjectHandling: "hide",
|
||||
IncludeCurrentUser: true,
|
||||
},
|
||||
Git: git.GitClientParam{
|
||||
Github: GithubClientConfig{
|
||||
Token: "",
|
||||
PullMethod: "http",
|
||||
OrgNames: []string{},
|
||||
UserNames: []string{},
|
||||
ArchivedRepoHandling: "hide",
|
||||
IncludeCurrentUser: true,
|
||||
},
|
||||
Git: GitClientConfig{
|
||||
CloneLocation: defaultCloneLocation,
|
||||
Remote: "origin",
|
||||
OnClone: "init",
|
||||
|
@ -68,28 +119,47 @@ func LoadConfig(configPath string) (*Config, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// validate forge is set
|
||||
if config.FS.Forge != ForgeGithub && config.FS.Forge != ForgeGitlab {
|
||||
return nil, fmt.Errorf("fs.forge must be either \"%v\", or \"%v\"", ForgeGitlab, ForgeGithub)
|
||||
}
|
||||
|
||||
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) {
|
||||
func MakeGitlabConfig(config *Config) (*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)
|
||||
if config.Gitlab.PullMethod != PullMethodHTTP && config.Gitlab.PullMethod != PullMethodSSH {
|
||||
return nil, fmt.Errorf("gitlab.pull_method must be either \"%v\" or \"%v\"", PullMethodHTTP, PullMethodSSH)
|
||||
}
|
||||
|
||||
// parse archive_handing
|
||||
if config.Gitlab.ArchivedProjectHandling != gitlab.ArchivedProjectShow && config.Gitlab.ArchivedProjectHandling != gitlab.ArchivedProjectHide && config.Gitlab.ArchivedProjectHandling != gitlab.ArchivedProjectIgnore {
|
||||
return nil, fmt.Errorf("pull_method must be either \"%v\", \"%v\" or \"%v\"", gitlab.ArchivedProjectShow, gitlab.ArchivedProjectHide, gitlab.ArchivedProjectIgnore)
|
||||
if config.Gitlab.ArchivedProjectHandling != ArchivedProjectShow && config.Gitlab.ArchivedProjectHandling != ArchivedProjectHide && config.Gitlab.ArchivedProjectHandling != ArchivedProjectIgnore {
|
||||
return nil, fmt.Errorf("gitlab.archived_project_handling must be either \"%v\", \"%v\" or \"%v\"", ArchivedProjectShow, ArchivedProjectHide, ArchivedProjectIgnore)
|
||||
}
|
||||
|
||||
return &config.Gitlab, nil
|
||||
}
|
||||
|
||||
func MakeGithubConfig(config *Config) (*GithubClientConfig, error) {
|
||||
// parse pull_method
|
||||
if config.Gitlab.PullMethod != PullMethodHTTP && config.Gitlab.PullMethod != PullMethodSSH {
|
||||
return nil, fmt.Errorf("github.pull_method must be either \"%v\" or \"%v\"", PullMethodHTTP, PullMethodSSH)
|
||||
}
|
||||
|
||||
// parse archive_handing
|
||||
if config.Gitlab.ArchivedProjectHandling != ArchivedProjectShow && config.Gitlab.ArchivedProjectHandling != ArchivedProjectHide && config.Gitlab.ArchivedProjectHandling != ArchivedProjectIgnore {
|
||||
return nil, fmt.Errorf("github.archived_repo_handling must be either \"%v\", \"%v\" or \"%v\"", ArchivedProjectShow, ArchivedProjectHide, ArchivedProjectIgnore)
|
||||
}
|
||||
|
||||
return &config.Github, nil
|
||||
}
|
||||
|
||||
func MakeGitConfig(config *Config) (*GitClientConfig, error) {
|
||||
// parse on_clone
|
||||
if config.Git.OnClone != "init" && config.Git.OnClone != "clone" {
|
||||
return nil, fmt.Errorf("git.on_clone must be either \"init\" or \"clone\"")
|
||||
}
|
||||
|
||||
return &config.Git, nil
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/badjware/gitlabfs/config"
|
||||
"github.com/badjware/gitlabfs/git"
|
||||
"github.com/badjware/gitlabfs/platforms/gitlab"
|
||||
)
|
||||
|
||||
func TestLoadConfig(t *testing.T) {
|
||||
|
@ -18,10 +16,11 @@ func TestLoadConfig(t *testing.T) {
|
|||
input: "config.test.yaml",
|
||||
expected: &config.Config{
|
||||
FS: config.FSConfig{
|
||||
Mountpoint: "/tmp/gitlabfs/test/mnt",
|
||||
Mountpoint: "/tmp/gitlabfs/test/mnt/gitlab",
|
||||
MountOptions: "nodev",
|
||||
Forge: "gitlab",
|
||||
},
|
||||
Gitlab: gitlab.GitlabClientConfig{
|
||||
Gitlab: config.GitlabClientConfig{
|
||||
URL: "https://example.com",
|
||||
Token: "12345",
|
||||
PullMethod: "ssh",
|
||||
|
@ -30,8 +29,16 @@ func TestLoadConfig(t *testing.T) {
|
|||
ArchivedProjectHandling: "hide",
|
||||
IncludeCurrentUser: true,
|
||||
},
|
||||
Git: git.GitClientParam{
|
||||
CloneLocation: "/tmp/gitlabfs/test/clone",
|
||||
Github: config.GithubClientConfig{
|
||||
Token: "12345",
|
||||
PullMethod: "http",
|
||||
OrgNames: []string{"test-org"},
|
||||
UserNames: []string{"test-user"},
|
||||
ArchivedRepoHandling: "hide",
|
||||
IncludeCurrentUser: true,
|
||||
},
|
||||
Git: config.GitClientConfig{
|
||||
CloneLocation: "/tmp/gitlabfs/test/cache/gitlab",
|
||||
Remote: "origin",
|
||||
OnClone: "clone",
|
||||
AutoPull: false,
|
||||
|
@ -58,11 +65,14 @@ func TestLoadConfig(t *testing.T) {
|
|||
func TestMakeGitConfig(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
input *config.Config
|
||||
expected *git.GitClientParam
|
||||
expected *config.GitClientConfig
|
||||
}{
|
||||
"ValidConfig": {
|
||||
input: &config.Config{
|
||||
Git: git.GitClientParam{
|
||||
FS: config.FSConfig{
|
||||
Forge: "gitlab",
|
||||
},
|
||||
Git: config.GitClientConfig{
|
||||
CloneLocation: "/tmp",
|
||||
Remote: "origin",
|
||||
OnClone: "init",
|
||||
|
@ -72,7 +82,7 @@ func TestMakeGitConfig(t *testing.T) {
|
|||
QueueWorkerCount: 5,
|
||||
},
|
||||
},
|
||||
expected: &git.GitClientParam{
|
||||
expected: &config.GitClientConfig{
|
||||
CloneLocation: "/tmp",
|
||||
Remote: "origin",
|
||||
OnClone: "init",
|
||||
|
@ -84,7 +94,10 @@ func TestMakeGitConfig(t *testing.T) {
|
|||
},
|
||||
"InvalidOnClone": {
|
||||
input: &config.Config{
|
||||
Git: git.GitClientParam{
|
||||
FS: config.FSConfig{
|
||||
Forge: "gitlab",
|
||||
},
|
||||
Git: config.GitClientConfig{
|
||||
CloneLocation: "/tmp",
|
||||
Remote: "origin",
|
||||
OnClone: "invalid",
|
||||
|
@ -114,11 +127,14 @@ func TestMakeGitConfig(t *testing.T) {
|
|||
func TestMakeGitlabConfig(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
input *config.Config
|
||||
expected *gitlab.GitlabClientConfig
|
||||
expected *config.GitlabClientConfig
|
||||
}{
|
||||
"ValidConfig": {
|
||||
input: &config.Config{
|
||||
Gitlab: gitlab.GitlabClientConfig{
|
||||
FS: config.FSConfig{
|
||||
Forge: "gitlab",
|
||||
},
|
||||
Gitlab: config.GitlabClientConfig{
|
||||
URL: "https://gitlab.com",
|
||||
PullMethod: "http",
|
||||
Token: "",
|
||||
|
@ -128,7 +144,7 @@ func TestMakeGitlabConfig(t *testing.T) {
|
|||
IncludeCurrentUser: true,
|
||||
},
|
||||
},
|
||||
expected: &gitlab.GitlabClientConfig{
|
||||
expected: &config.GitlabClientConfig{
|
||||
URL: "https://gitlab.com",
|
||||
PullMethod: "http",
|
||||
Token: "",
|
||||
|
@ -140,7 +156,10 @@ func TestMakeGitlabConfig(t *testing.T) {
|
|||
},
|
||||
"InvalidPullMethod": {
|
||||
input: &config.Config{
|
||||
Gitlab: gitlab.GitlabClientConfig{
|
||||
FS: config.FSConfig{
|
||||
Forge: "gitlab",
|
||||
},
|
||||
Gitlab: config.GitlabClientConfig{
|
||||
URL: "https://gitlab.com",
|
||||
PullMethod: "invalid",
|
||||
Token: "",
|
||||
|
@ -154,7 +173,7 @@ func TestMakeGitlabConfig(t *testing.T) {
|
|||
},
|
||||
"InvalidArchiveHandling": {
|
||||
input: &config.Config{
|
||||
Gitlab: gitlab.GitlabClientConfig{
|
||||
Gitlab: config.GitlabClientConfig{
|
||||
URL: "https://gitlab.com",
|
||||
PullMethod: "http",
|
||||
Token: "",
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
"github.com/badjware/gitlabfs/config"
|
||||
"github.com/badjware/gitlabfs/fstree"
|
||||
"github.com/google/go-github/v63/github"
|
||||
)
|
||||
|
||||
type githubClient struct {
|
||||
config.GithubClientConfig
|
||||
client *github.Client
|
||||
|
||||
logger *slog.Logger
|
||||
|
||||
rootContent map[string]fstree.GroupSource
|
||||
|
||||
// API response cache
|
||||
organizationCacheMux sync.RWMutex
|
||||
organizationNameToIDMap map[string]int64
|
||||
organizationCache map[int64]*Organization
|
||||
userCacheMux sync.RWMutex
|
||||
userNameToIDMap map[string]int64
|
||||
userCache map[int64]*User
|
||||
}
|
||||
|
||||
func NewClient(logger *slog.Logger, config config.GithubClientConfig) (*githubClient, error) {
|
||||
client := github.NewClient(nil)
|
||||
if config.Token != "" {
|
||||
client = client.WithAuthToken(config.Token)
|
||||
}
|
||||
|
||||
gitHubClient := &githubClient{
|
||||
GithubClientConfig: config,
|
||||
client: client,
|
||||
|
||||
logger: logger,
|
||||
|
||||
rootContent: nil,
|
||||
|
||||
organizationNameToIDMap: map[string]int64{},
|
||||
organizationCache: map[int64]*Organization{},
|
||||
userNameToIDMap: map[string]int64{},
|
||||
userCache: map[int64]*User{},
|
||||
}
|
||||
|
||||
// Fetch current user and add it to the list
|
||||
currentUser, _, err := client.Users.Get(context.Background(), "")
|
||||
if err != nil {
|
||||
logger.Warn("failed to fetch the current user:", "error", err.Error())
|
||||
} else {
|
||||
gitHubClient.UserNames = append(gitHubClient.UserNames, *currentUser.Login)
|
||||
}
|
||||
|
||||
return gitHubClient, nil
|
||||
}
|
||||
|
||||
func (c *githubClient) FetchRootGroupContent() (map[string]fstree.GroupSource, error) {
|
||||
if c.rootContent == nil {
|
||||
rootContent := make(map[string]fstree.GroupSource)
|
||||
|
||||
for _, org_name := range c.GithubClientConfig.OrgNames {
|
||||
org, err := c.fetchOrganization(org_name)
|
||||
if err != nil {
|
||||
c.logger.Warn(err.Error())
|
||||
} else {
|
||||
rootContent[org.Name] = org
|
||||
}
|
||||
}
|
||||
|
||||
for _, user_name := range c.GithubClientConfig.UserNames {
|
||||
user, err := c.fetchUser(user_name)
|
||||
if err != nil {
|
||||
c.logger.Warn(err.Error())
|
||||
} else {
|
||||
rootContent[user.Name] = user
|
||||
}
|
||||
}
|
||||
|
||||
c.rootContent = rootContent
|
||||
}
|
||||
return c.rootContent, nil
|
||||
}
|
||||
|
||||
func (c *githubClient) FetchGroupContent(gid uint64) (map[string]fstree.GroupSource, map[string]fstree.RepositorySource, error) {
|
||||
if org, found := c.organizationCache[int64(gid)]; found {
|
||||
return c.fetchOrganizationContent(org)
|
||||
}
|
||||
if user, found := c.userCache[int64(gid)]; found {
|
||||
return c.fetchUserContent(user)
|
||||
}
|
||||
return nil, nil, fmt.Errorf("invalid gid: %v", gid)
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/badjware/gitlabfs/fstree"
|
||||
"github.com/google/go-github/v63/github"
|
||||
)
|
||||
|
||||
type Organization struct {
|
||||
ID int64
|
||||
Name string
|
||||
|
||||
mux sync.Mutex
|
||||
|
||||
// hold org content
|
||||
childRepositories map[string]fstree.RepositorySource
|
||||
}
|
||||
|
||||
func (o *Organization) GetGroupID() uint64 {
|
||||
return uint64(o.ID)
|
||||
}
|
||||
|
||||
func (o *Organization) InvalidateContentCache() {
|
||||
o.mux.Lock()
|
||||
defer o.mux.Unlock()
|
||||
|
||||
// clear child repositories from cache
|
||||
o.childRepositories = nil
|
||||
}
|
||||
|
||||
func (c *githubClient) fetchOrganization(org_name string) (*Organization, error) {
|
||||
c.organizationCacheMux.RLock()
|
||||
cachedId, found := c.organizationNameToIDMap[org_name]
|
||||
if found {
|
||||
cachedOrg := c.organizationCache[cachedId]
|
||||
c.organizationCacheMux.RUnlock()
|
||||
|
||||
// if found in cache, return the cached reference
|
||||
c.logger.Debug("Organization cache hit", "org_name", org_name)
|
||||
return cachedOrg, nil
|
||||
} else {
|
||||
c.organizationCacheMux.RUnlock()
|
||||
|
||||
c.logger.Debug("Organization cache miss", "org_name", org_name)
|
||||
}
|
||||
|
||||
// If not found in cache, fetch organization infos from API
|
||||
githubOrg, _, err := c.client.Organizations.Get(context.Background(), org_name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch organization with name %v: %v", org_name, err)
|
||||
}
|
||||
newOrg := Organization{
|
||||
ID: *githubOrg.ID,
|
||||
Name: *githubOrg.Login,
|
||||
|
||||
childRepositories: nil,
|
||||
}
|
||||
|
||||
// save in cache
|
||||
c.organizationCacheMux.Lock()
|
||||
c.organizationCache[newOrg.ID] = &newOrg
|
||||
c.organizationNameToIDMap[newOrg.Name] = newOrg.ID
|
||||
c.organizationCacheMux.Unlock()
|
||||
|
||||
return &newOrg, nil
|
||||
}
|
||||
|
||||
func (c *githubClient) fetchOrganizationContent(org *Organization) (map[string]fstree.GroupSource, map[string]fstree.RepositorySource, error) {
|
||||
org.mux.Lock()
|
||||
defer org.mux.Unlock()
|
||||
|
||||
// Get cached data if available
|
||||
// TODO: cache cache invalidation?
|
||||
if org.childRepositories == nil {
|
||||
childRepositories := make(map[string]fstree.RepositorySource)
|
||||
|
||||
// Fetch the organization repositories
|
||||
repositoryListOpt := &github.RepositoryListByOrgOptions{
|
||||
ListOptions: github.ListOptions{PerPage: 100},
|
||||
}
|
||||
for {
|
||||
githubRepositories, response, err := c.client.Repositories.ListByOrg(context.Background(), org.Name, repositoryListOpt)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch repository in github: %v", err)
|
||||
}
|
||||
for _, githubRepository := range githubRepositories {
|
||||
repository := c.newRepositoryFromGithubRepository(githubRepository)
|
||||
if repository != nil {
|
||||
childRepositories[repository.Path] = repository
|
||||
}
|
||||
}
|
||||
if response.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
// Get the next page
|
||||
repositoryListOpt.Page = response.NextPage
|
||||
}
|
||||
|
||||
org.childRepositories = childRepositories
|
||||
}
|
||||
return make(map[string]fstree.GroupSource), org.childRepositories, nil
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package github
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/badjware/gitlabfs/config"
|
||||
"github.com/google/go-github/v63/github"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
ID int64
|
||||
Path string
|
||||
CloneURL string
|
||||
DefaultBranch string
|
||||
}
|
||||
|
||||
func (r *Repository) GetRepositoryID() uint64 {
|
||||
return uint64(r.ID)
|
||||
}
|
||||
|
||||
func (r *Repository) GetCloneURL() string {
|
||||
return r.CloneURL
|
||||
}
|
||||
|
||||
func (r *Repository) GetDefaultBranch() string {
|
||||
return r.DefaultBranch
|
||||
}
|
||||
|
||||
func (c *githubClient) newRepositoryFromGithubRepository(repository *github.Repository) *Repository {
|
||||
if c.ArchivedRepoHandling == config.ArchivedProjectIgnore && *repository.Archived {
|
||||
return nil
|
||||
}
|
||||
r := Repository{
|
||||
ID: *repository.ID,
|
||||
Path: *repository.Name,
|
||||
DefaultBranch: *repository.DefaultBranch,
|
||||
}
|
||||
if r.DefaultBranch == "" {
|
||||
r.DefaultBranch = "master"
|
||||
}
|
||||
if c.PullMethod == config.PullMethodSSH {
|
||||
r.CloneURL = *repository.SSHURL
|
||||
} else {
|
||||
r.CloneURL = *repository.CloneURL
|
||||
}
|
||||
if c.ArchivedRepoHandling == config.ArchivedProjectHide && *repository.Archived {
|
||||
r.Path = path.Join(path.Dir(r.Path), "."+path.Base(r.Path))
|
||||
}
|
||||
return &r
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/badjware/gitlabfs/fstree"
|
||||
"github.com/google/go-github/v63/github"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int64
|
||||
Name string
|
||||
|
||||
mux sync.Mutex
|
||||
|
||||
// hold user content
|
||||
childRepositories map[string]fstree.RepositorySource
|
||||
}
|
||||
|
||||
func (u *User) GetGroupID() uint64 {
|
||||
return uint64(u.ID)
|
||||
}
|
||||
|
||||
func (u *User) InvalidateContentCache() {
|
||||
u.mux.Lock()
|
||||
defer u.mux.Unlock()
|
||||
|
||||
// clear child repositories from cache
|
||||
u.childRepositories = nil
|
||||
}
|
||||
|
||||
func (c *githubClient) fetchUser(user_name string) (*User, error) {
|
||||
c.userCacheMux.RLock()
|
||||
cachedId, found := c.userNameToIDMap[user_name]
|
||||
if found {
|
||||
cachedUser := c.userCache[cachedId]
|
||||
c.userCacheMux.RUnlock()
|
||||
|
||||
// if found in cache, return the cached reference
|
||||
c.logger.Debug("User cache hit", "user_name", user_name)
|
||||
return cachedUser, nil
|
||||
} else {
|
||||
c.userCacheMux.RUnlock()
|
||||
|
||||
c.logger.Debug("User cache miss", "user_name", user_name)
|
||||
}
|
||||
|
||||
// If not found in cache, fetch user infos from API
|
||||
githubUser, _, err := c.client.Users.Get(context.Background(), user_name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch user with name %v: %v", user_name, err)
|
||||
}
|
||||
newUser := User{
|
||||
ID: *githubUser.ID,
|
||||
Name: *githubUser.Login,
|
||||
|
||||
childRepositories: nil,
|
||||
}
|
||||
|
||||
// save in cache
|
||||
c.userCacheMux.Lock()
|
||||
c.userCache[newUser.ID] = &newUser
|
||||
c.userNameToIDMap[newUser.Name] = newUser.ID
|
||||
c.userCacheMux.Unlock()
|
||||
|
||||
return &newUser, nil
|
||||
}
|
||||
|
||||
func (c *githubClient) fetchUserContent(user *User) (map[string]fstree.GroupSource, map[string]fstree.RepositorySource, error) {
|
||||
user.mux.Lock()
|
||||
defer user.mux.Unlock()
|
||||
|
||||
// Get cached data if available
|
||||
// TODO: cache cache invalidation?
|
||||
if user.childRepositories == nil {
|
||||
childRepositories := make(map[string]fstree.RepositorySource)
|
||||
|
||||
// Fetch the user repositories
|
||||
repositoryListOpt := &github.RepositoryListByUserOptions{
|
||||
ListOptions: github.ListOptions{PerPage: 100},
|
||||
}
|
||||
for {
|
||||
githubRepositories, response, err := c.client.Repositories.ListByUser(context.Background(), user.Name, repositoryListOpt)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch repository in github: %v", err)
|
||||
}
|
||||
for _, githubRepository := range githubRepositories {
|
||||
repository := c.newRepositoryFromGithubRepository(githubRepository)
|
||||
if repository != nil {
|
||||
childRepositories[repository.Path] = repository
|
||||
}
|
||||
}
|
||||
if response.NextPage == 0 {
|
||||
break
|
||||
}
|
||||
// Get the next page
|
||||
repositoryListOpt.Page = response.NextPage
|
||||
}
|
||||
|
||||
user.childRepositories = childRepositories
|
||||
}
|
||||
return make(map[string]fstree.GroupSource), user.childRepositories, nil
|
||||
}
|
|
@ -6,38 +6,18 @@ import (
|
|||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/badjware/gitlabfs/config"
|
||||
"github.com/badjware/gitlabfs/fstree"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
const (
|
||||
PullMethodHTTP = "http"
|
||||
PullMethodSSH = "ssh"
|
||||
|
||||
ArchivedProjectShow = "show"
|
||||
ArchivedProjectHide = "hide"
|
||||
ArchivedProjectIgnore = "ignore"
|
||||
)
|
||||
|
||||
type GitlabClientConfig struct {
|
||||
URL string `yaml:"url,omitempty"`
|
||||
Token string `yaml:"token,omitempty"`
|
||||
GroupIDs []int `yaml:"group_ids,omitempty"`
|
||||
UserIDs []int `yaml:"user_ids,omitempty"`
|
||||
ArchivedProjectHandling string `yaml:"archived_project_handling,omitempty"`
|
||||
IncludeCurrentUser bool `yaml:"include_current_user,omitempty"`
|
||||
PullMethod string `yaml:"pull_method,omitempty"`
|
||||
}
|
||||
|
||||
type gitlabClient struct {
|
||||
GitlabClientConfig
|
||||
config.GitlabClientConfig
|
||||
client *gitlab.Client
|
||||
|
||||
logger *slog.Logger
|
||||
|
||||
// root group cache
|
||||
rootGroupCache map[string]fstree.GroupSource
|
||||
currentUserCache *User
|
||||
rootContent map[string]fstree.GroupSource
|
||||
|
||||
// API response cache
|
||||
groupCacheMux sync.RWMutex
|
||||
|
@ -46,33 +26,41 @@ type gitlabClient struct {
|
|||
userCache map[int]*User
|
||||
}
|
||||
|
||||
func NewClient(logger *slog.Logger, gitlabUrl string, gitlabToken string, p GitlabClientConfig) (*gitlabClient, error) {
|
||||
func NewClient(logger *slog.Logger, config config.GitlabClientConfig) (*gitlabClient, error) {
|
||||
client, err := gitlab.NewClient(
|
||||
gitlabToken,
|
||||
gitlab.WithBaseURL(gitlabUrl),
|
||||
config.Token,
|
||||
gitlab.WithBaseURL(config.URL),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create gitlab client: %v", err)
|
||||
}
|
||||
|
||||
gitlabClient := &gitlabClient{
|
||||
GitlabClientConfig: p,
|
||||
GitlabClientConfig: config,
|
||||
client: client,
|
||||
|
||||
logger: logger,
|
||||
|
||||
rootGroupCache: nil,
|
||||
currentUserCache: nil,
|
||||
rootContent: nil,
|
||||
|
||||
groupCache: map[int]*Group{},
|
||||
userCache: map[int]*User{},
|
||||
}
|
||||
|
||||
// Fetch current user and add it to the list
|
||||
currentUser, _, err := client.Users.CurrentUser()
|
||||
if err != nil {
|
||||
logger.Warn("failed to fetch the current user:", "error", err.Error())
|
||||
} else {
|
||||
gitlabClient.UserIDs = append(gitlabClient.UserIDs, currentUser.ID)
|
||||
}
|
||||
|
||||
return gitlabClient, nil
|
||||
}
|
||||
|
||||
func (c *gitlabClient) FetchRootGroupContent() (map[string]fstree.GroupSource, error) {
|
||||
// use cached values if available
|
||||
if c.rootGroupCache == nil {
|
||||
if c.rootContent == nil {
|
||||
rootGroupCache := make(map[string]fstree.GroupSource)
|
||||
|
||||
// fetch root groups
|
||||
|
@ -91,23 +79,14 @@ func (c *gitlabClient) FetchRootGroupContent() (map[string]fstree.GroupSource, e
|
|||
}
|
||||
rootGroupCache[user.Name] = user
|
||||
}
|
||||
// fetch current user if configured
|
||||
if c.IncludeCurrentUser {
|
||||
currentUser, err := c.fetchCurrentUser()
|
||||
if err != nil {
|
||||
c.logger.Warn(err.Error())
|
||||
} else {
|
||||
rootGroupCache[currentUser.Name] = currentUser
|
||||
}
|
||||
}
|
||||
|
||||
c.rootGroupCache = rootGroupCache
|
||||
c.rootContent = rootGroupCache
|
||||
}
|
||||
return c.rootGroupCache, nil
|
||||
return c.rootContent, nil
|
||||
}
|
||||
|
||||
func (c *gitlabClient) FetchGroupContent(gid uint64) (map[string]fstree.GroupSource, map[string]fstree.RepositorySource, error) {
|
||||
if slices.Contains[[]int, int](c.UserIDs, int(gid)) || (c.currentUserCache != nil && c.currentUserCache.ID == int(gid)) {
|
||||
if slices.Contains[[]int, int](c.UserIDs, int(gid)) {
|
||||
// gid is a user
|
||||
user, err := c.fetchUser(int(gid))
|
||||
if err != nil {
|
|
@ -3,6 +3,7 @@ package gitlab
|
|||
import (
|
||||
"path"
|
||||
|
||||
"github.com/badjware/gitlabfs/config"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
|
@ -27,7 +28,7 @@ func (p *Project) GetDefaultBranch() string {
|
|||
|
||||
func (c *gitlabClient) newProjectFromGitlabProject(project *gitlab.Project) *Project {
|
||||
// https://godoc.org/github.com/xanzy/go-gitlab#Project
|
||||
if c.ArchivedProjectHandling == ArchivedProjectIgnore && project.Archived {
|
||||
if c.ArchivedProjectHandling == config.ArchivedProjectIgnore && project.Archived {
|
||||
return nil
|
||||
}
|
||||
p := Project{
|
||||
|
@ -38,12 +39,12 @@ func (c *gitlabClient) newProjectFromGitlabProject(project *gitlab.Project) *Pro
|
|||
if p.DefaultBranch == "" {
|
||||
p.DefaultBranch = "master"
|
||||
}
|
||||
if c.PullMethod == PullMethodSSH {
|
||||
if c.PullMethod == config.PullMethodSSH {
|
||||
p.CloneURL = project.SSHURLToRepo
|
||||
} else {
|
||||
p.CloneURL = project.HTTPURLToRepo
|
||||
}
|
||||
if c.ArchivedProjectHandling == ArchivedProjectHide && project.Archived {
|
||||
if c.ArchivedProjectHandling == config.ArchivedProjectHide && project.Archived {
|
||||
p.Path = path.Join(path.Dir(p.Path), "."+path.Base(p.Path))
|
||||
}
|
||||
return &p
|
|
@ -64,23 +64,6 @@ func (c *gitlabClient) fetchUser(uid int) (*User, error) {
|
|||
return &newUser, nil
|
||||
}
|
||||
|
||||
func (c *gitlabClient) fetchCurrentUser() (*User, error) {
|
||||
if c.currentUserCache == nil {
|
||||
gitlabUser, _, err := c.client.Users.CurrentUser()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch current user: %v", err)
|
||||
}
|
||||
newUser := User{
|
||||
ID: gitlabUser.ID,
|
||||
Name: gitlabUser.Username,
|
||||
|
||||
childProjects: nil,
|
||||
}
|
||||
c.currentUserCache = &newUser
|
||||
}
|
||||
return c.currentUserCache, nil
|
||||
}
|
||||
|
||||
func (c *gitlabClient) fetchUserContent(user *User) (map[string]fstree.GroupSource, map[string]fstree.RepositorySource, error) {
|
||||
// Only a single routine can fetch the user content at the time.
|
||||
// We lock for the whole duration of the function to avoid fetching the same data from the API
|
|
@ -39,7 +39,7 @@ func newGroupNodeFromSource(source GroupSource, param *FSParam) (*groupNode, err
|
|||
}
|
||||
|
||||
func (n *groupNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
groups, repositories, err := n.param.GitPlatform.FetchGroupContent(n.source.GetGroupID())
|
||||
groups, repositories, err := n.param.GitForge.FetchGroupContent(n.source.GetGroupID())
|
||||
if err != nil {
|
||||
n.param.logger.Error(err.Error())
|
||||
}
|
||||
|
@ -70,38 +70,41 @@ func (n *groupNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
|||
}
|
||||
|
||||
func (n *groupNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
|
||||
groups, repositories, _ := n.param.GitPlatform.FetchGroupContent(n.source.GetGroupID())
|
||||
|
||||
// Check if the map of groups contains it
|
||||
group, found := groups[name]
|
||||
if found {
|
||||
attrs := fs.StableAttr{
|
||||
Ino: group.GetGroupID(),
|
||||
Mode: fuse.S_IFDIR,
|
||||
groups, repositories, err := n.param.GitForge.FetchGroupContent(n.source.GetGroupID())
|
||||
if err != nil {
|
||||
n.param.logger.Error(err.Error())
|
||||
} else {
|
||||
// Check if the map of groups contains it
|
||||
group, found := groups[name]
|
||||
if found {
|
||||
attrs := fs.StableAttr{
|
||||
Ino: group.GetGroupID(),
|
||||
Mode: fuse.S_IFDIR,
|
||||
}
|
||||
groupNode, _ := newGroupNodeFromSource(group, n.param)
|
||||
return n.NewInode(ctx, groupNode, attrs), 0
|
||||
}
|
||||
groupNode, _ := newGroupNodeFromSource(group, n.param)
|
||||
return n.NewInode(ctx, groupNode, attrs), 0
|
||||
}
|
||||
|
||||
// Check if the map of projects contains it
|
||||
repository, found := repositories[name]
|
||||
if found {
|
||||
attrs := fs.StableAttr{
|
||||
Ino: repository.GetRepositoryID(),
|
||||
Mode: fuse.S_IFLNK,
|
||||
// Check if the map of projects contains it
|
||||
repository, found := repositories[name]
|
||||
if found {
|
||||
attrs := fs.StableAttr{
|
||||
Ino: repository.GetRepositoryID(),
|
||||
Mode: fuse.S_IFLNK,
|
||||
}
|
||||
repositoryNode, _ := newRepositoryNodeFromSource(repository, n.param)
|
||||
return n.NewInode(ctx, repositoryNode, attrs), 0
|
||||
}
|
||||
repositoryNode, _ := newRepositoryNodeFromSource(repository, n.param)
|
||||
return n.NewInode(ctx, repositoryNode, attrs), 0
|
||||
}
|
||||
|
||||
// Check if the map of static nodes contains it
|
||||
staticNode, ok := n.staticNodes[name]
|
||||
if ok {
|
||||
attrs := fs.StableAttr{
|
||||
Ino: staticNode.Ino(),
|
||||
Mode: staticNode.Mode(),
|
||||
// Check if the map of static nodes contains it
|
||||
staticNode, ok := n.staticNodes[name]
|
||||
if ok {
|
||||
attrs := fs.StableAttr{
|
||||
Ino: staticNode.Ino(),
|
||||
Mode: staticNode.Mode(),
|
||||
}
|
||||
return n.NewInode(ctx, staticNode, attrs), 0
|
||||
}
|
||||
return n.NewInode(ctx, staticNode, attrs), 0
|
||||
}
|
||||
|
||||
return nil, syscall.ENOENT
|
||||
|
|
|
@ -26,14 +26,14 @@ type GitClient interface {
|
|||
FetchLocalRepositoryPath(source RepositorySource) (string, error)
|
||||
}
|
||||
|
||||
type GitPlatform interface {
|
||||
type GitForge interface {
|
||||
FetchRootGroupContent() (map[string]GroupSource, error)
|
||||
FetchGroupContent(gid uint64) (map[string]GroupSource, map[string]RepositorySource, error)
|
||||
}
|
||||
|
||||
type FSParam struct {
|
||||
GitClient GitClient
|
||||
GitPlatform GitPlatform
|
||||
GitClient GitClient
|
||||
GitForge GitForge
|
||||
|
||||
logger *slog.Logger
|
||||
staticInoChan chan uint64
|
||||
|
@ -77,7 +77,7 @@ func Start(logger *slog.Logger, mountpoint string, mountoptions []string, param
|
|||
}
|
||||
|
||||
func (n *rootNode) OnAdd(ctx context.Context) {
|
||||
rootGroups, err := n.param.GitPlatform.FetchRootGroupContent()
|
||||
rootGroups, err := n.param.GitForge.FetchRootGroupContent()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -10,24 +10,15 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/badjware/gitlabfs/config"
|
||||
"github.com/badjware/gitlabfs/fstree"
|
||||
"github.com/badjware/gitlabfs/utils"
|
||||
"github.com/vmihailenco/taskq/v3"
|
||||
"github.com/vmihailenco/taskq/v3/memqueue"
|
||||
)
|
||||
|
||||
type GitClientParam struct {
|
||||
CloneLocation string `yaml:"clone_location,omitempty"`
|
||||
Remote string `yaml:"remote,omitempty"`
|
||||
OnClone string `yaml:"on_clone,omitempty"`
|
||||
AutoPull bool `yaml:"auto_pull,omitempty"`
|
||||
Depth int `yaml:"depth,omitempty"`
|
||||
QueueSize int `yaml:"queue_size,omitempty"`
|
||||
QueueWorkerCount int `yaml:"worker_count,omitempty"`
|
||||
}
|
||||
|
||||
type gitClient struct {
|
||||
GitClientParam
|
||||
config.GitClientConfig
|
||||
|
||||
logger *slog.Logger
|
||||
|
||||
|
@ -42,11 +33,11 @@ type gitClient struct {
|
|||
pullTask *taskq.Task
|
||||
}
|
||||
|
||||
func NewClient(logger *slog.Logger, p GitClientParam) (*gitClient, error) {
|
||||
func NewClient(logger *slog.Logger, p config.GitClientConfig) (*gitClient, error) {
|
||||
queueFactory := memqueue.NewFactory()
|
||||
// Create the client
|
||||
c := &gitClient{
|
||||
GitClientParam: p,
|
||||
GitClientConfig: p,
|
||||
|
||||
logger: logger,
|
||||
|
||||
|
|
14
git/clone.go
14
git/clone.go
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
func (c *gitClient) clone(url string, defaultBranch string, dst string) error {
|
||||
if c.GitClientParam.OnClone == "init" {
|
||||
if c.GitClientConfig.OnClone == "init" {
|
||||
// "Fake" cloning the repo by never actually talking to the git server
|
||||
// This skip a fetch operation that we would do if we where to do a proper clone
|
||||
// We can save a lot of time and network i/o doing it this way, at the cost of
|
||||
|
@ -40,8 +40,8 @@ func (c *gitClient) clone(url string, defaultBranch string, dst string) error {
|
|||
"git", "remote", "add",
|
||||
"-m", defaultBranch,
|
||||
"--",
|
||||
c.GitClientParam.Remote, // name
|
||||
url, // url
|
||||
c.GitClientConfig.Remote, // name
|
||||
url, // url
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to setup remote %v in git repo %v: %v", url, dst, err)
|
||||
|
@ -54,7 +54,7 @@ func (c *gitClient) clone(url string, defaultBranch string, dst string) error {
|
|||
"git", "config", "--local",
|
||||
"--",
|
||||
fmt.Sprintf("branch.%s.remote", defaultBranch), // key
|
||||
c.GitClientParam.Remote, // value
|
||||
c.GitClientConfig.Remote, // value
|
||||
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -77,10 +77,10 @@ func (c *gitClient) clone(url string, defaultBranch string, dst string) error {
|
|||
c.logger.Info("Cloning git repository", "directory", dst, "repository", url)
|
||||
args := []string{
|
||||
"clone",
|
||||
"--origin", c.GitClientParam.Remote,
|
||||
"--origin", c.GitClientConfig.Remote,
|
||||
}
|
||||
if c.GitClientParam.Depth != 0 {
|
||||
args = append(args, "--depth", strconv.Itoa(c.GitClientParam.Depth))
|
||||
if c.GitClientConfig.Depth != 0 {
|
||||
args = append(args, "--depth", strconv.Itoa(c.GitClientConfig.Depth))
|
||||
}
|
||||
args = append(args,
|
||||
"--",
|
||||
|
|
|
@ -24,13 +24,13 @@ func (c *gitClient) pull(repoPath string, defaultBranch string) error {
|
|||
args := []string{
|
||||
"pull",
|
||||
}
|
||||
if c.GitClientParam.Depth != 0 {
|
||||
args = append(args, "--depth", strconv.Itoa(c.GitClientParam.Depth))
|
||||
if c.GitClientConfig.Depth != 0 {
|
||||
args = append(args, "--depth", strconv.Itoa(c.GitClientConfig.Depth))
|
||||
}
|
||||
args = append(args,
|
||||
"--",
|
||||
c.GitClientParam.Remote, // repository
|
||||
defaultBranch, // refspec
|
||||
c.GitClientConfig.Remote, // repository
|
||||
defaultBranch, // refspec
|
||||
)
|
||||
|
||||
_, err = utils.ExecProcessInDir(c.logger, repoPath, "git", args...)
|
||||
|
|
1
go.mod
1
go.mod
|
@ -18,6 +18,7 @@ require (
|
|||
github.com/go-redis/redis/v8 v8.11.4 // indirect
|
||||
github.com/go-redis/redis_rate/v9 v9.1.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-github/v63 v63.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -114,6 +114,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v63 v63.0.0 h1:13xwK/wk9alSokujB9lJkuzdmQuVn2QCPeck76wR3nE=
|
||||
github.com/google/go-github/v63 v63.0.0/go.mod h1:IqbcrgUmIcEaioWrGYei/09o+ge5vhffGOcxrO0AfmA=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
|
|
28
main.go
28
main.go
|
@ -8,9 +8,10 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/badjware/gitlabfs/config"
|
||||
"github.com/badjware/gitlabfs/forges/github"
|
||||
"github.com/badjware/gitlabfs/forges/gitlab"
|
||||
"github.com/badjware/gitlabfs/fstree"
|
||||
"github.com/badjware/gitlabfs/git"
|
||||
"github.com/badjware/gitlabfs/platforms/gitlab"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -64,20 +65,31 @@ func main() {
|
|||
}
|
||||
gitClient, _ := git.NewClient(logger, *gitClientParam)
|
||||
|
||||
// Create the gitlab client
|
||||
GitlabClientConfig, err := config.MakeGitlabConfig(loadedConfig)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
var gitForgeClient fstree.GitForge
|
||||
if loadedConfig.FS.Forge == config.ForgeGitlab {
|
||||
// Create the gitlab client
|
||||
GitlabClientConfig, err := config.MakeGitlabConfig(loadedConfig)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
gitForgeClient, _ = gitlab.NewClient(logger, *GitlabClientConfig)
|
||||
} else if loadedConfig.FS.Forge == config.ForgeGithub {
|
||||
// Create the github client
|
||||
GithubClientConfig, err := config.MakeGithubConfig(loadedConfig)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
gitForgeClient, _ = github.NewClient(logger, *GithubClientConfig)
|
||||
}
|
||||
gitlabClient, _ := gitlab.NewClient(logger, loadedConfig.Gitlab.URL, loadedConfig.Gitlab.Token, *GitlabClientConfig)
|
||||
|
||||
// Start the filesystem
|
||||
err = fstree.Start(
|
||||
logger,
|
||||
mountpoint,
|
||||
parsedMountoptions,
|
||||
&fstree.FSParam{GitClient: gitClient, GitPlatform: gitlabClient},
|
||||
&fstree.FSParam{GitClient: gitClient, GitForge: gitForgeClient},
|
||||
*debug,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue