1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
package dotgit
import (
"os"
"path/filepath"
"strings"
"github.com/go-git/go-billy/v5"
)
// RepositoryFilesystem is a billy.Filesystem compatible object wrapper
// which handles dot-git filesystem operations and supports commondir according to git scm layout:
// https://github.com/git/git/blob/master/Documentation/gitrepository-layout.txt
type RepositoryFilesystem struct {
dotGitFs billy.Filesystem
commonDotGitFs billy.Filesystem
}
func NewRepositoryFilesystem(dotGitFs, commonDotGitFs billy.Filesystem) *RepositoryFilesystem {
return &RepositoryFilesystem{
dotGitFs: dotGitFs,
commonDotGitFs: commonDotGitFs,
}
}
func (fs *RepositoryFilesystem) mapToRepositoryFsByPath(path string) billy.Filesystem {
// Nothing to decide if commondir not defined
if fs.commonDotGitFs == nil {
return fs.dotGitFs
}
cleanPath := filepath.Clean(path)
// Check exceptions for commondir (https://git-scm.com/docs/gitrepository-layout#Documentation/gitrepository-layout.txt)
switch cleanPath {
case fs.dotGitFs.Join(logsPath, "HEAD"):
return fs.dotGitFs
case fs.dotGitFs.Join(refsPath, "bisect"), fs.dotGitFs.Join(refsPath, "rewritten"), fs.dotGitFs.Join(refsPath, "worktree"):
return fs.dotGitFs
}
// Determine dot-git root by first path element.
// There are some elements which should always use commondir when commondir defined.
// Usual dot-git root will be used for the rest of files.
switch strings.Split(cleanPath, string(filepath.Separator))[0] {
case objectsPath, refsPath, packedRefsPath, configPath, branchesPath, hooksPath, infoPath, remotesPath, logsPath, shallowPath, worktreesPath:
return fs.commonDotGitFs
default:
return fs.dotGitFs
}
}
func (fs *RepositoryFilesystem) Create(filename string) (billy.File, error) {
return fs.mapToRepositoryFsByPath(filename).Create(filename)
}
func (fs *RepositoryFilesystem) Open(filename string) (billy.File, error) {
return fs.mapToRepositoryFsByPath(filename).Open(filename)
}
func (fs *RepositoryFilesystem) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
return fs.mapToRepositoryFsByPath(filename).OpenFile(filename, flag, perm)
}
func (fs *RepositoryFilesystem) Stat(filename string) (os.FileInfo, error) {
return fs.mapToRepositoryFsByPath(filename).Stat(filename)
}
func (fs *RepositoryFilesystem) Rename(oldpath, newpath string) error {
return fs.mapToRepositoryFsByPath(oldpath).Rename(oldpath, newpath)
}
func (fs *RepositoryFilesystem) Remove(filename string) error {
return fs.mapToRepositoryFsByPath(filename).Remove(filename)
}
func (fs *RepositoryFilesystem) Join(elem ...string) string {
return fs.dotGitFs.Join(elem...)
}
func (fs *RepositoryFilesystem) TempFile(dir, prefix string) (billy.File, error) {
return fs.mapToRepositoryFsByPath(dir).TempFile(dir, prefix)
}
func (fs *RepositoryFilesystem) ReadDir(path string) ([]os.FileInfo, error) {
return fs.mapToRepositoryFsByPath(path).ReadDir(path)
}
func (fs *RepositoryFilesystem) MkdirAll(filename string, perm os.FileMode) error {
return fs.mapToRepositoryFsByPath(filename).MkdirAll(filename, perm)
}
func (fs *RepositoryFilesystem) Lstat(filename string) (os.FileInfo, error) {
return fs.mapToRepositoryFsByPath(filename).Lstat(filename)
}
func (fs *RepositoryFilesystem) Symlink(target, link string) error {
return fs.mapToRepositoryFsByPath(target).Symlink(target, link)
}
func (fs *RepositoryFilesystem) Readlink(link string) (string, error) {
return fs.mapToRepositoryFsByPath(link).Readlink(link)
}
func (fs *RepositoryFilesystem) Chroot(path string) (billy.Filesystem, error) {
return fs.mapToRepositoryFsByPath(path).Chroot(path)
}
func (fs *RepositoryFilesystem) Root() string {
return fs.dotGitFs.Root()
}
|