add refresh "button"
This commit is contained in:
parent
8d3f49061b
commit
e43d9520f8
30
fs/group.go
30
fs/group.go
|
@ -12,7 +12,9 @@ import (
|
|||
type groupNode struct {
|
||||
fs.Inode
|
||||
param *FSParam
|
||||
group *gitlab.Group
|
||||
|
||||
group *gitlab.Group
|
||||
staticNodes map[string]staticNode
|
||||
}
|
||||
|
||||
// Ensure we are implementing the NodeReaddirer interface
|
||||
|
@ -29,6 +31,9 @@ func newGroupNodeByID(gid int, param *FSParam) (*groupNode, error) {
|
|||
node := &groupNode{
|
||||
param: param,
|
||||
group: group,
|
||||
staticNodes: map[string]staticNode{
|
||||
".refresh": newRefreshNode(group, param),
|
||||
},
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
@ -37,13 +42,16 @@ func newGroupNode(group *gitlab.Group, param *FSParam) (*groupNode, error) {
|
|||
node := &groupNode{
|
||||
param: param,
|
||||
group: group,
|
||||
staticNodes: map[string]staticNode{
|
||||
".refresh": newRefreshNode(group, param),
|
||||
},
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func (n *groupNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
||||
groupContent, _ := n.param.Gitlab.FetchGroupContent(n.group)
|
||||
entries := make([]fuse.DirEntry, 0, len(groupContent.Groups)+len(groupContent.Projects))
|
||||
entries := make([]fuse.DirEntry, 0, len(groupContent.Groups)+len(groupContent.Projects)+len(n.staticNodes))
|
||||
for _, group := range groupContent.Groups {
|
||||
entries = append(entries, fuse.DirEntry{
|
||||
Name: group.Name,
|
||||
|
@ -58,6 +66,13 @@ func (n *groupNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
|||
Mode: fuse.S_IFLNK,
|
||||
})
|
||||
}
|
||||
for name, staticNode := range n.staticNodes {
|
||||
entries = append(entries, fuse.DirEntry{
|
||||
Name: name,
|
||||
Ino: staticNode.Ino(),
|
||||
Mode: staticNode.Mode(),
|
||||
})
|
||||
}
|
||||
return fs.NewListDirStream(entries), 0
|
||||
}
|
||||
|
||||
|
@ -85,5 +100,16 @@ func (n *groupNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut)
|
|||
repositoryNode, _ := newRepositoryNode(project, 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(),
|
||||
}
|
||||
return n.NewInode(ctx, staticNode, attrs), 0
|
||||
}
|
||||
|
||||
return nil, syscall.ENOENT
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall"
|
||||
|
||||
"github.com/badjware/gitlabfs/gitlab"
|
||||
"github.com/hanwen/go-fuse/v2/fs"
|
||||
"github.com/hanwen/go-fuse/v2/fuse"
|
||||
)
|
||||
|
||||
type refreshNode struct {
|
||||
fs.Inode
|
||||
ino uint64
|
||||
refresher gitlab.Refresher
|
||||
}
|
||||
|
||||
// Ensure we are implementing the NodeSetattrer interface
|
||||
var _ = (fs.NodeSetattrer)((*refreshNode)(nil))
|
||||
|
||||
// Ensure we are implementing the NodeOpener interface
|
||||
var _ = (fs.NodeOpener)((*refreshNode)(nil))
|
||||
|
||||
func newRefreshNode(refresher gitlab.Refresher, param *FSParam) *refreshNode {
|
||||
return &refreshNode{
|
||||
ino: <-param.staticInoChan,
|
||||
refresher: refresher,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *refreshNode) Ino() uint64 {
|
||||
return n.ino
|
||||
}
|
||||
|
||||
func (n *refreshNode) Mode() uint32 {
|
||||
return fuse.S_IFREG
|
||||
}
|
||||
|
||||
func (n *refreshNode) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (n *refreshNode) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||
n.refresher.InvalidateCache()
|
||||
return nil, 0, 0
|
||||
}
|
|
@ -18,7 +18,6 @@ type RepositoryNode struct {
|
|||
var _ = (fs.NodeReadlinker)((*RepositoryNode)(nil))
|
||||
|
||||
func newRepositoryNode(project *gitlab.Project, param *FSParam) (*RepositoryNode, error) {
|
||||
|
||||
node := &RepositoryNode{
|
||||
param: param,
|
||||
project: project,
|
||||
|
|
|
@ -15,6 +15,12 @@ const (
|
|||
staticInodeStart = uint64(int(^(uint(0))>>1)) + 1
|
||||
)
|
||||
|
||||
type staticNode interface {
|
||||
fs.InodeEmbedder
|
||||
Ino() uint64
|
||||
Mode() uint32
|
||||
}
|
||||
|
||||
type FSParam struct {
|
||||
Git git.GitClonerPuller
|
||||
Gitlab gitlab.GitlabFetcher
|
||||
|
|
32
fs/users.go
32
fs/users.go
|
@ -71,7 +71,9 @@ func (n *usersNode) OnAdd(ctx context.Context) {
|
|||
type userNode struct {
|
||||
fs.Inode
|
||||
param *FSParam
|
||||
user *gitlab.User
|
||||
|
||||
user *gitlab.User
|
||||
staticNodes map[string]staticNode
|
||||
}
|
||||
|
||||
// Ensure we are implementing the NodeReaddirer interface
|
||||
|
@ -88,6 +90,9 @@ func newUserNodeByID(uid int, param *FSParam) (*userNode, error) {
|
|||
node := &userNode{
|
||||
param: param,
|
||||
user: user,
|
||||
staticNodes: map[string]staticNode{
|
||||
".refresh": newRefreshNode(user, param),
|
||||
},
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
@ -96,13 +101,16 @@ func newUserNode(user *gitlab.User, param *FSParam) (*userNode, error) {
|
|||
node := &userNode{
|
||||
param: param,
|
||||
user: user,
|
||||
staticNodes: map[string]staticNode{
|
||||
".refresh": newRefreshNode(user, param),
|
||||
},
|
||||
}
|
||||
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))
|
||||
entries := make([]fuse.DirEntry, 0, len(userContent.Projects)+len(n.staticNodes))
|
||||
for _, project := range userContent.Projects {
|
||||
entries = append(entries, fuse.DirEntry{
|
||||
Name: project.Name,
|
||||
|
@ -110,11 +118,20 @@ func (n *userNode) Readdir(ctx context.Context) (fs.DirStream, syscall.Errno) {
|
|||
Mode: fuse.S_IFLNK,
|
||||
})
|
||||
}
|
||||
for name, staticNode := range n.staticNodes {
|
||||
entries = append(entries, fuse.DirEntry{
|
||||
Name: name,
|
||||
Ino: staticNode.Ino(),
|
||||
Mode: staticNode.Mode(),
|
||||
})
|
||||
}
|
||||
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)
|
||||
|
||||
// Check if the map of projects contains it
|
||||
project, ok := userContent.Projects[name]
|
||||
if ok {
|
||||
attrs := fs.StableAttr{
|
||||
|
@ -124,5 +141,16 @@ func (n *userNode) Lookup(ctx context.Context, name string, out *fuse.EntryOut)
|
|||
repositoryNode, _ := newRepositoryNode(project, 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(),
|
||||
}
|
||||
return n.NewInode(ctx, staticNode, attrs), 0
|
||||
}
|
||||
|
||||
return nil, syscall.ENOENT
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ type GitlabFetcher interface {
|
|||
UserFetcher
|
||||
}
|
||||
|
||||
type Refresher interface {
|
||||
InvalidateCache()
|
||||
}
|
||||
|
||||
type GitlabClientParam struct {
|
||||
PullMethod string
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package gitlab
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
@ -20,6 +21,7 @@ type Group struct {
|
|||
ID int
|
||||
Name string
|
||||
|
||||
mux sync.Mutex
|
||||
content *GroupContent
|
||||
}
|
||||
|
||||
|
@ -31,6 +33,13 @@ func NewGroupFromGitlabGroup(group *gitlab.Group) Group {
|
|||
}
|
||||
}
|
||||
|
||||
func (g *Group) InvalidateCache() {
|
||||
g.mux.Lock()
|
||||
defer g.mux.Unlock()
|
||||
|
||||
g.content = nil
|
||||
}
|
||||
|
||||
func (c *gitlabClient) FetchGroup(gid int) (*Group, error) {
|
||||
gitlabGroup, _, err := c.client.Groups.GetGroup(gid)
|
||||
if err != nil {
|
||||
|
@ -41,6 +50,10 @@ func (c *gitlabClient) FetchGroup(gid int) (*Group, error) {
|
|||
}
|
||||
|
||||
func (c *gitlabClient) FetchGroupContent(group *Group) (*GroupContent, error) {
|
||||
group.mux.Lock()
|
||||
defer group.mux.Unlock()
|
||||
|
||||
// Get cached data if available
|
||||
if group.content != nil {
|
||||
return group.content, nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package gitlab
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
@ -20,6 +21,7 @@ type User struct {
|
|||
ID int
|
||||
Name string
|
||||
|
||||
mux sync.Mutex
|
||||
content *UserContent
|
||||
}
|
||||
|
||||
|
@ -31,6 +33,13 @@ func NewUserFromGitlabUser(user *gitlab.User) User {
|
|||
}
|
||||
}
|
||||
|
||||
func (u *User) InvalidateCache() {
|
||||
u.mux.Lock()
|
||||
defer u.mux.Unlock()
|
||||
|
||||
u.content = nil
|
||||
}
|
||||
|
||||
func (c *gitlabClient) FetchUser(uid int) (*User, error) {
|
||||
gitlabUser, _, err := c.client.Users.GetUser(uid)
|
||||
if err != nil {
|
||||
|
@ -50,6 +59,10 @@ func (c *gitlabClient) FetchCurrentUser() (*User, error) {
|
|||
}
|
||||
|
||||
func (c *gitlabClient) FetchUserContent(user *User) (*UserContent, error) {
|
||||
user.mux.Lock()
|
||||
defer user.mux.Unlock()
|
||||
|
||||
// Get cached data if available
|
||||
if user.content != nil {
|
||||
return user.content, nil
|
||||
}
|
||||
|
|
2
go.sum
2
go.sum
|
@ -19,6 +19,7 @@ github.com/go-git/go-git v4.7.0+incompatible/go.mod h1:6+421e08gnZWn30y26Vchf7ef
|
|||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI=
|
||||
github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
|
@ -96,6 +97,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqG
|
|||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
Loading…
Reference in New Issue