add support for user repos
This commit is contained in:
parent
4aca123c98
commit
9b09b6aef9
26
fs/group.go
26
fs/group.go
|
@ -21,8 +21,8 @@ var _ = (fs.NodeReaddirer)((*groupNode)(nil))
|
||||||
// Ensure we are implementing the NodeLookuper interface
|
// Ensure we are implementing the NodeLookuper interface
|
||||||
var _ = (fs.NodeLookuper)((*groupNode)(nil))
|
var _ = (fs.NodeLookuper)((*groupNode)(nil))
|
||||||
|
|
||||||
func newRootGroupNode(gid int, param *FSParam) (*groupNode, error) {
|
func newGroupNodeByID(gid int, param *FSParam) (*groupNode, error) {
|
||||||
group, err := param.Gf.FetchGroup(gid)
|
group, err := param.Gitlab.FetchGroup(gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -42,19 +42,19 @@ func newGroupNode(group *gitlab.Group, param *FSParam) (*groupNode, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *groupNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
func (n *groupNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||||
groupContent, _ := n.param.Gf.FetchGroupContent(n.group)
|
groupContent, _ := n.param.Gitlab.FetchGroupContent(n.group)
|
||||||
entries := make([]fuse.DirEntry, 0, len(groupContent.Groups)+len(groupContent.Repositories))
|
entries := make([]fuse.DirEntry, 0, len(groupContent.Groups)+len(groupContent.Projects))
|
||||||
for _, group := range groupContent.Groups {
|
for _, group := range groupContent.Groups {
|
||||||
entries = append(entries, fuse.DirEntry{
|
entries = append(entries, fuse.DirEntry{
|
||||||
Name: group.Path,
|
Name: group.Name,
|
||||||
Ino: uint64(group.ID),
|
Ino: uint64(group.ID),
|
||||||
Mode: fuse.S_IFDIR,
|
Mode: fuse.S_IFDIR,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, repository := range groupContent.Repositories {
|
for _, project := range groupContent.Projects {
|
||||||
entries = append(entries, fuse.DirEntry{
|
entries = append(entries, fuse.DirEntry{
|
||||||
Name: repository.Path,
|
Name: project.Name,
|
||||||
Ino: uint64(repository.ID),
|
Ino: uint64(project.ID),
|
||||||
Mode: fuse.S_IFLNK,
|
Mode: fuse.S_IFLNK,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ 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) {
|
func (n *groupNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
|
||||||
groupContent, _ := n.param.Gf.FetchGroupContent(n.group)
|
groupContent, _ := n.param.Gitlab.FetchGroupContent(n.group)
|
||||||
|
|
||||||
// Check if the map of groups contains it
|
// Check if the map of groups contains it
|
||||||
group, ok := groupContent.Groups[name]
|
group, ok := groupContent.Groups[name]
|
||||||
|
@ -75,14 +75,14 @@ func (n *groupNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut)
|
||||||
return n.NewInode(ctx, groupNode, attrs), 0
|
return n.NewInode(ctx, groupNode, attrs), 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the map of repositories contains it
|
// Check if the map of projects contains it
|
||||||
repository, ok := groupContent.Repositories[name]
|
project, ok := groupContent.Projects[name]
|
||||||
if ok {
|
if ok {
|
||||||
attrs := fs.StableAttr{
|
attrs := fs.StableAttr{
|
||||||
Ino: uint64(repository.ID),
|
Ino: uint64(project.ID),
|
||||||
Mode: fuse.S_IFLNK,
|
Mode: fuse.S_IFLNK,
|
||||||
}
|
}
|
||||||
repositoryNode, _ := newRepositoryNode(repository, n.param)
|
repositoryNode, _ := newRepositoryNode(project, n.param)
|
||||||
return n.NewInode(ctx, repositoryNode, attrs), 0
|
return n.NewInode(ctx, repositoryNode, attrs), 0
|
||||||
}
|
}
|
||||||
return nil, syscall.ENOENT
|
return nil, syscall.ENOENT
|
||||||
|
|
|
@ -18,7 +18,7 @@ type projectsNode struct {
|
||||||
// Ensure we are implementing the NodeOnAdder interface
|
// Ensure we are implementing the NodeOnAdder interface
|
||||||
var _ = (fs.NodeOnAdder)((*projectsNode)(nil))
|
var _ = (fs.NodeOnAdder)((*projectsNode)(nil))
|
||||||
|
|
||||||
func NewProjectsNode(rootGroupIds []int, param *FSParam) *projectsNode {
|
func newProjectsNode(rootGroupIds []int, param *FSParam) *projectsNode {
|
||||||
return &projectsNode{
|
return &projectsNode{
|
||||||
param: param,
|
param: param,
|
||||||
rootGroupIds: rootGroupIds,
|
rootGroupIds: rootGroupIds,
|
||||||
|
@ -27,7 +27,7 @@ func NewProjectsNode(rootGroupIds []int, param *FSParam) *projectsNode {
|
||||||
|
|
||||||
func (n *projectsNode) OnAdd(ctx context.Context) {
|
func (n *projectsNode) OnAdd(ctx context.Context) {
|
||||||
for _, groupID := range n.rootGroupIds {
|
for _, groupID := range n.rootGroupIds {
|
||||||
groupNode, err := newRootGroupNode(groupID, n.param)
|
groupNode, err := newGroupNodeByID(groupID, n.param)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("root group fetch fail: %v\n", err)
|
fmt.Printf("root group fetch fail: %v\n", err)
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,6 @@ func (n *projectsNode) OnAdd(ctx context.Context) {
|
||||||
Mode: fuse.S_IFDIR,
|
Mode: fuse.S_IFDIR,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
n.AddChild(groupNode.group.Path, inode, false)
|
n.AddChild(groupNode.group.Name, inode, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,18 @@ import (
|
||||||
|
|
||||||
type RepositoryNode struct {
|
type RepositoryNode struct {
|
||||||
fs.Inode
|
fs.Inode
|
||||||
param *FSParam
|
param *FSParam
|
||||||
repository *gitlab.Repository
|
project *gitlab.Project
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we are implementing the NodeReaddirer interface
|
// Ensure we are implementing the NodeReaddirer interface
|
||||||
var _ = (fs.NodeReadlinker)((*RepositoryNode)(nil))
|
var _ = (fs.NodeReadlinker)((*RepositoryNode)(nil))
|
||||||
|
|
||||||
func newRepositoryNode(repository *gitlab.Repository, param *FSParam) (*RepositoryNode, error) {
|
func newRepositoryNode(project *gitlab.Project, param *FSParam) (*RepositoryNode, error) {
|
||||||
|
|
||||||
node := &RepositoryNode{
|
node := &RepositoryNode{
|
||||||
param: param,
|
param: param,
|
||||||
repository: repository,
|
project: project,
|
||||||
}
|
}
|
||||||
// Passthrough the error if there is one, nothing to add here
|
// Passthrough the error if there is one, nothing to add here
|
||||||
// Errors on clone/pull are non-fatal
|
// Errors on clone/pull are non-fatal
|
||||||
|
@ -30,7 +30,7 @@ func newRepositoryNode(repository *gitlab.Repository, param *FSParam) (*Reposito
|
||||||
|
|
||||||
func (n *RepositoryNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
|
func (n *RepositoryNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
|
||||||
// Create the local copy of the repo
|
// Create the local copy of the repo
|
||||||
localRepoLoc, _ := n.param.Gcp.CloneOrPull(n.repository.CloneURL, n.repository.ID, "master")
|
localRepoLoc, _ := n.param.Git.CloneOrPull(n.project.CloneURL, n.project.ID, "master")
|
||||||
|
|
||||||
return []byte(localRepoLoc), 0
|
return []byte(localRepoLoc), 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type FSParam struct {
|
type FSParam struct {
|
||||||
Gf gitlab.GroupFetcher
|
Gitlab gitlab.GitlabFetcher
|
||||||
Gcp git.GitClonerPuller
|
Git git.GitClonerPuller
|
||||||
|
|
||||||
staticInoChan chan uint64
|
staticInoChan chan uint64
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ var _ = (fs.NodeOnAdder)((*rootNode)(nil))
|
||||||
func (n *rootNode) OnAdd(ctx context.Context) {
|
func (n *rootNode) OnAdd(ctx context.Context) {
|
||||||
projectsInode := n.NewPersistentInode(
|
projectsInode := n.NewPersistentInode(
|
||||||
ctx,
|
ctx,
|
||||||
NewProjectsNode(
|
newProjectsNode(
|
||||||
n.rootGroupIds,
|
n.rootGroupIds,
|
||||||
n.param,
|
n.param,
|
||||||
),
|
),
|
||||||
|
@ -47,7 +47,7 @@ func (n *rootNode) OnAdd(ctx context.Context) {
|
||||||
|
|
||||||
usersInode := n.NewPersistentInode(
|
usersInode := n.NewPersistentInode(
|
||||||
ctx,
|
ctx,
|
||||||
NewUsersNode(
|
newUsersNode(
|
||||||
n.userIds,
|
n.userIds,
|
||||||
n.param,
|
n.param,
|
||||||
),
|
),
|
||||||
|
|
118
fs/users.go
118
fs/users.go
|
@ -2,8 +2,12 @@ package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/badjware/gitlabfs/gitlab"
|
||||||
"github.com/hanwen/go-fuse/v2/fs"
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
)
|
)
|
||||||
|
|
||||||
type usersNode struct {
|
type usersNode struct {
|
||||||
|
@ -16,7 +20,7 @@ type usersNode struct {
|
||||||
// Ensure we are implementing the NodeOnAdder interface
|
// Ensure we are implementing the NodeOnAdder interface
|
||||||
var _ = (fs.NodeOnAdder)((*usersNode)(nil))
|
var _ = (fs.NodeOnAdder)((*usersNode)(nil))
|
||||||
|
|
||||||
func NewUsersNode(userIds []int, param *FSParam) *usersNode {
|
func newUsersNode(userIds []int, param *FSParam) *usersNode {
|
||||||
return &usersNode{
|
return &usersNode{
|
||||||
param: param,
|
param: param,
|
||||||
userIds: userIds,
|
userIds: userIds,
|
||||||
|
@ -24,19 +28,101 @@ func NewUsersNode(userIds []int, param *FSParam) *usersNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *usersNode) OnAdd(ctx context.Context) {
|
func (n *usersNode) OnAdd(ctx context.Context) {
|
||||||
// for _, userId := range n.userIds {
|
// Fetch the current logged user
|
||||||
// userNode, err := newRootUserNode(userId, n.param)
|
currentUser, err := n.param.Gitlab.FetchCurrentUser()
|
||||||
// if err != nil {
|
// Skip if we are anonymous (or the call fails for some reason...)
|
||||||
// fmt.Printf("user fetch fail: %v\n", err)
|
if err != nil {
|
||||||
// }
|
fmt.Println(err)
|
||||||
// inode := n.NewPersistentInode(
|
} else {
|
||||||
// ctx,
|
currentUserNode, _ := newUserNode(currentUser, n.param)
|
||||||
// userNode,
|
inode := n.NewPersistentInode(
|
||||||
// fs.StableAttr{
|
ctx,
|
||||||
// Ino: <-n.param.staticInoChan,
|
currentUserNode,
|
||||||
// Mode: fuse.S_IFDIR,
|
fs.StableAttr{
|
||||||
// },
|
Ino: <-n.param.staticInoChan,
|
||||||
// )
|
Mode: fuse.S_IFDIR,
|
||||||
// n.AddChild(userNode.user.Path, inode, false)
|
},
|
||||||
// }
|
)
|
||||||
|
n.AddChild(currentUserNode.user.Name, inode, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, userID := range n.userIds {
|
||||||
|
if currentUser != nil && currentUser.ID == userID {
|
||||||
|
// We already added the current user, we can skip it
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userNode, err := newUserNodeByID(userID, n.param)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("user fetch fail: %v\n", err)
|
||||||
|
}
|
||||||
|
inode := n.NewPersistentInode(
|
||||||
|
ctx,
|
||||||
|
userNode,
|
||||||
|
fs.StableAttr{
|
||||||
|
Ino: <-n.param.staticInoChan,
|
||||||
|
Mode: fuse.S_IFDIR,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
n.AddChild(userNode.user.Name, inode, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type userNode struct {
|
||||||
|
fs.Inode
|
||||||
|
param *FSParam
|
||||||
|
user *gitlab.User
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we are implementing the NodeReaddirer interface
|
||||||
|
var _ = (fs.NodeReaddirer)((*userNode)(nil))
|
||||||
|
|
||||||
|
// Ensure we are implementing the NodeLookuper interface
|
||||||
|
var _ = (fs.NodeLookuper)((*userNode)(nil))
|
||||||
|
|
||||||
|
func newUserNodeByID(uid int, param *FSParam) (*userNode, error) {
|
||||||
|
user, err := param.Gitlab.FetchUser(uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
node := &userNode{
|
||||||
|
param: param,
|
||||||
|
user: user,
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUserNode(user *gitlab.User, param *FSParam) (*userNode, error) {
|
||||||
|
node := &userNode{
|
||||||
|
param: param,
|
||||||
|
user: user,
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *userNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||||
|
userContent, _ := n.param.Gitlab.FetchUserContent(n.user)
|
||||||
|
entries := make([]fuse.DirEntry, 0, len(userContent.Projects))
|
||||||
|
for _, project := range userContent.Projects {
|
||||||
|
entries = append(entries, fuse.DirEntry{
|
||||||
|
Name: project.Name,
|
||||||
|
Ino: uint64(project.ID),
|
||||||
|
Mode: fuse.S_IFLNK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return fs.NewListDirStream(entries), 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *userNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*fs.Inode, syscall.Errno) {
|
||||||
|
userContent, _ := n.param.Gitlab.FetchUserContent(n.user)
|
||||||
|
project, ok := userContent.Projects[name]
|
||||||
|
if ok {
|
||||||
|
attrs := fs.StableAttr{
|
||||||
|
Ino: uint64(project.ID),
|
||||||
|
Mode: fuse.S_IFLNK,
|
||||||
|
}
|
||||||
|
repositoryNode, _ := newRepositoryNode(project, n.param)
|
||||||
|
return n.NewInode(ctx, repositoryNode, attrs), 0
|
||||||
|
}
|
||||||
|
return nil, syscall.ENOENT
|
||||||
}
|
}
|
||||||
|
|
112
gitlab/client.go
112
gitlab/client.go
|
@ -6,28 +6,9 @@ import (
|
||||||
"github.com/xanzy/go-gitlab"
|
"github.com/xanzy/go-gitlab"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupFetcher interface {
|
type GitlabFetcher interface {
|
||||||
FetchGroup(gid int) (*Group, error)
|
GroupFetcher
|
||||||
FetchGroupContent(group *Group) (*GroupContent, error)
|
UserFetcher
|
||||||
}
|
|
||||||
|
|
||||||
type GroupContent struct {
|
|
||||||
Groups map[string]*Group
|
|
||||||
Repositories map[string]*Repository
|
|
||||||
}
|
|
||||||
|
|
||||||
type Group struct {
|
|
||||||
ID int
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
Content *GroupContent
|
|
||||||
}
|
|
||||||
|
|
||||||
type Repository struct {
|
|
||||||
ID int
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
CloneURL string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GitlabClientParam struct {
|
type GitlabClientParam struct {
|
||||||
|
@ -52,90 +33,3 @@ func NewClient(gitlabUrl string, gitlabToken string, p GitlabClientParam) (*gitl
|
||||||
}
|
}
|
||||||
return gitlabClient, nil
|
return gitlabClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepositoryFromGitlabProject(project *gitlab.Project) Repository {
|
|
||||||
// https://godoc.org/github.com/xanzy/go-gitlab#Project
|
|
||||||
return Repository{
|
|
||||||
ID: project.ID,
|
|
||||||
Name: project.Name,
|
|
||||||
Path: project.Path,
|
|
||||||
CloneURL: project.HTTPURLToRepo,
|
|
||||||
// CloneUrl: project.SSHURLToRepo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGroupFromGitlabGroup(group *gitlab.Group) Group {
|
|
||||||
// https://godoc.org/github.com/xanzy/go-gitlab#Group
|
|
||||||
return Group{
|
|
||||||
ID: group.ID,
|
|
||||||
Name: group.Name,
|
|
||||||
Path: group.Path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c gitlabClient) FetchGroup(gid int) (*Group, error) {
|
|
||||||
gitlabGroup, _, err := c.client.Groups.GetGroup(gid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to fetch group with id %v: %v\n", gid, err)
|
|
||||||
}
|
|
||||||
group := NewGroupFromGitlabGroup(gitlabGroup)
|
|
||||||
return &group, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c gitlabClient) FetchGroupContent(group *Group) (*GroupContent, error) {
|
|
||||||
if group.Content != nil {
|
|
||||||
return group.Content, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
content := &GroupContent{
|
|
||||||
Groups: map[string]*Group{},
|
|
||||||
Repositories: map[string]*Repository{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// List subgroups in path
|
|
||||||
ListGroupsOpt := &gitlab.ListSubgroupsOptions{
|
|
||||||
ListOptions: gitlab.ListOptions{
|
|
||||||
Page: 1,
|
|
||||||
PerPage: 1000,
|
|
||||||
}}
|
|
||||||
for {
|
|
||||||
gitlabGroups, response, err := c.client.Groups.ListSubgroups(group.ID, ListGroupsOpt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to fetch groups in gitlab: %v", err)
|
|
||||||
}
|
|
||||||
for _, gitlabGroup := range gitlabGroups {
|
|
||||||
group := NewGroupFromGitlabGroup(gitlabGroup)
|
|
||||||
content.Groups[group.Path] = &group
|
|
||||||
}
|
|
||||||
if response.CurrentPage >= response.TotalPages {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Get the next page
|
|
||||||
ListGroupsOpt.Page = response.NextPage
|
|
||||||
}
|
|
||||||
|
|
||||||
// List repositories in path
|
|
||||||
listProjectOpt := &gitlab.ListGroupProjectsOptions{
|
|
||||||
ListOptions: gitlab.ListOptions{
|
|
||||||
Page: 1,
|
|
||||||
PerPage: 1000,
|
|
||||||
}}
|
|
||||||
for {
|
|
||||||
gitlabProjects, response, err := c.client.Groups.ListGroupProjects(group.ID, listProjectOpt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to fetch projects in gitlab: %v", err)
|
|
||||||
}
|
|
||||||
for _, gitlabProject := range gitlabProjects {
|
|
||||||
repository := NewRepositoryFromGitlabProject(gitlabProject)
|
|
||||||
content.Repositories[repository.Path] = &repository
|
|
||||||
}
|
|
||||||
if response.CurrentPage >= response.TotalPages {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Get the next page
|
|
||||||
listProjectOpt.Page = response.NextPage
|
|
||||||
}
|
|
||||||
|
|
||||||
group.Content = content
|
|
||||||
return content, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/xanzy/go-gitlab"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GroupFetcher interface {
|
||||||
|
FetchGroup(gid int) (*Group, error)
|
||||||
|
FetchGroupContent(group *Group) (*GroupContent, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupContent struct {
|
||||||
|
Groups map[string]*Group
|
||||||
|
Projects map[string]*Project
|
||||||
|
}
|
||||||
|
|
||||||
|
type Group struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
|
||||||
|
content *GroupContent
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGroupFromGitlabGroup(group *gitlab.Group) Group {
|
||||||
|
// https://godoc.org/github.com/xanzy/go-gitlab#Group
|
||||||
|
return Group{
|
||||||
|
ID: group.ID,
|
||||||
|
Name: group.Path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gitlabClient) FetchGroup(gid int) (*Group, error) {
|
||||||
|
gitlabGroup, _, err := c.client.Groups.GetGroup(gid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch group with id %v: %v", gid, err)
|
||||||
|
}
|
||||||
|
group := NewGroupFromGitlabGroup(gitlabGroup)
|
||||||
|
return &group, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gitlabClient) FetchGroupContent(group *Group) (*GroupContent, error) {
|
||||||
|
if group.content != nil {
|
||||||
|
return group.content, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
content := &GroupContent{
|
||||||
|
Groups: map[string]*Group{},
|
||||||
|
Projects: map[string]*Project{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// List subgroups in path
|
||||||
|
ListGroupsOpt := &gitlab.ListSubgroupsOptions{
|
||||||
|
ListOptions: gitlab.ListOptions{
|
||||||
|
Page: 1,
|
||||||
|
PerPage: 1000,
|
||||||
|
}}
|
||||||
|
for {
|
||||||
|
gitlabGroups, response, err := c.client.Groups.ListSubgroups(group.ID, ListGroupsOpt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch groups in gitlab: %v", err)
|
||||||
|
}
|
||||||
|
for _, gitlabGroup := range gitlabGroups {
|
||||||
|
group := NewGroupFromGitlabGroup(gitlabGroup)
|
||||||
|
content.Groups[group.Name] = &group
|
||||||
|
}
|
||||||
|
if response.CurrentPage >= response.TotalPages {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Get the next page
|
||||||
|
ListGroupsOpt.Page = response.NextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
// List projects in path
|
||||||
|
listProjectOpt := &gitlab.ListGroupProjectsOptions{
|
||||||
|
ListOptions: gitlab.ListOptions{
|
||||||
|
Page: 1,
|
||||||
|
PerPage: 1000,
|
||||||
|
}}
|
||||||
|
for {
|
||||||
|
gitlabProjects, response, err := c.client.Groups.ListGroupProjects(group.ID, listProjectOpt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch projects in gitlab: %v", err)
|
||||||
|
}
|
||||||
|
for _, gitlabProject := range gitlabProjects {
|
||||||
|
project := NewProjectFromGitlabProject(gitlabProject)
|
||||||
|
content.Projects[project.Name] = &project
|
||||||
|
}
|
||||||
|
if response.CurrentPage >= response.TotalPages {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Get the next page
|
||||||
|
listProjectOpt.Page = response.NextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
group.content = content
|
||||||
|
return content, nil
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import "github.com/xanzy/go-gitlab"
|
||||||
|
|
||||||
|
type Project struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
CloneURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProjectFromGitlabProject(project *gitlab.Project) Project {
|
||||||
|
// https://godoc.org/github.com/xanzy/go-gitlab#Project
|
||||||
|
return Project{
|
||||||
|
ID: project.ID,
|
||||||
|
Name: project.Path,
|
||||||
|
// CloneURL: project.HTTPURLToRepo,
|
||||||
|
CloneURL: project.SSHURLToRepo,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package gitlab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/xanzy/go-gitlab"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserFetcher interface {
|
||||||
|
FetchUser(uid int) (*User, error)
|
||||||
|
FetchCurrentUser() (*User, error)
|
||||||
|
FetchUserContent(user *User) (*UserContent, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserContent struct {
|
||||||
|
Projects map[string]*Project
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
|
||||||
|
content *UserContent
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserFromGitlabUser(user *gitlab.User) User {
|
||||||
|
// https://godoc.org/github.com/xanzy/go-gitlab#User
|
||||||
|
return User{
|
||||||
|
ID: user.ID,
|
||||||
|
Name: user.Username,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gitlabClient) FetchUser(uid int) (*User, error) {
|
||||||
|
gitlabUser, _, err := c.client.Users.GetUser(uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch user with id %v: %v", uid, err)
|
||||||
|
}
|
||||||
|
user := NewUserFromGitlabUser(gitlabUser)
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gitlabClient) FetchCurrentUser() (*User, error) {
|
||||||
|
gitlabUser, _, err := c.client.Users.CurrentUser()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch current user: %v", err)
|
||||||
|
}
|
||||||
|
user := NewUserFromGitlabUser(gitlabUser)
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gitlabClient) FetchUserContent(user *User) (*UserContent, error) {
|
||||||
|
if user.content != nil {
|
||||||
|
return user.content, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
content := &UserContent{
|
||||||
|
Projects: map[string]*Project{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the user repositories
|
||||||
|
listProjectOpt := &gitlab.ListProjectsOptions{
|
||||||
|
ListOptions: gitlab.ListOptions{
|
||||||
|
Page: 1,
|
||||||
|
PerPage: 1000,
|
||||||
|
}}
|
||||||
|
for {
|
||||||
|
gitlabProjects, response, err := c.client.Projects.ListUserProjects(user.ID, listProjectOpt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch projects in gitlab: %v", err)
|
||||||
|
}
|
||||||
|
for _, gitlabProject := range gitlabProjects {
|
||||||
|
project := NewProjectFromGitlabProject(gitlabProject)
|
||||||
|
content.Projects[project.Name] = &project
|
||||||
|
}
|
||||||
|
if response.CurrentPage >= response.TotalPages {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Get the next page
|
||||||
|
listProjectOpt.Page = response.NextPage
|
||||||
|
}
|
||||||
|
|
||||||
|
user.content = content
|
||||||
|
return content, nil
|
||||||
|
}
|
2
main.go
2
main.go
|
@ -45,5 +45,5 @@ func main() {
|
||||||
gitClient, _ := git.NewClient(gitClientParam)
|
gitClient, _ := git.NewClient(gitClientParam)
|
||||||
|
|
||||||
// Start the filesystem
|
// Start the filesystem
|
||||||
fs.Start(mountpoint, []int{*gitlabRootGroupID}, []int{}, &fs.FSParam{Gf: gitlabClient, Gcp: gitClient})
|
fs.Start(mountpoint, []int{*gitlabRootGroupID}, []int{}, &fs.FSParam{Gitlab: gitlabClient, Git: gitClient})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue