gitforgefs/fstree/repository.go

83 lines
2.2 KiB
Go

package fstree
import (
"context"
"errors"
"fmt"
"os"
"syscall"
"time"
"github.com/hanwen/go-fuse/v2/fs"
)
const (
repositoryBaseInode = 2_000_000_000
)
type repositorySymlinkNode struct {
fs.Inode
param *FSParam
source RepositorySource
}
type RepositorySource interface {
// GetName() string
GetRepositoryID() uint64
GetCloneURL() string
GetDefaultBranch() string
}
// Ensure we are implementing the NodeReaddirer interface
var _ = (fs.NodeReadlinker)((*repositorySymlinkNode)(nil))
func newRepositoryNodeFromSource(ctx context.Context, source RepositorySource, param *FSParam) (fs.InodeEmbedder, error) {
if param.UseSymlinks {
return &repositorySymlinkNode{
param: param,
source: source,
}, nil
} else {
localRepositoryPath, err := param.GitClient.FetchLocalRepositoryPath(ctx, source)
if err != nil {
return nil, fmt.Errorf("failed to fetch local repository path: %w", err)
}
// The path must exist to successfully create a loopback. We poll the filesystem until its created.
// This of course add latency, maybe we should think of a way of mitigating it in the future.
// We do not care in the case of a symlink. A symlink pointing on nothing is still a valid symlink.
for ctx.Err() == nil {
_, err := os.Stat(localRepositoryPath)
if err == nil {
return fs.NewLoopbackRoot(localRepositoryPath)
} else if errors.Is(err, os.ErrNotExist) {
// wait for the file to be created
// TODO: think of a more efficient way of archiving this
time.Sleep(100 * time.Millisecond)
} else {
// error, filesystem
return nil, fmt.Errorf("error while waiting for the local repository to be created: %w", err)
}
}
// error, context cancelled
return nil, fmt.Errorf("context cancelled while waiting for the local repository to be created: %w", ctx.Err())
}
}
func (n *repositorySymlinkNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
// Create the local copy of the repo
// TODO: cleanup
localRepositoryPath, err := n.param.GitClient.FetchLocalRepositoryPath(ctx, n.source)
if err != nil {
n.param.logger.Error(err.Error())
}
return []byte(localRepositoryPath), 0
}
type repositoryLoopbackNode struct {
fs.LoopbackNode
param *FSParam
source RepositorySource
}