-
Notifications
You must be signed in to change notification settings - Fork 63
/
virtual_build_directory.go
162 lines (145 loc) · 5.83 KB
/
virtual_build_directory.go
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package builder
import (
"context"
"os"
"syscall"
"github.com/buildbarn/bb-remote-execution/pkg/cas"
re_filesystem "github.com/buildbarn/bb-remote-execution/pkg/filesystem"
"github.com/buildbarn/bb-remote-execution/pkg/filesystem/access"
"github.com/buildbarn/bb-remote-execution/pkg/filesystem/virtual"
"github.com/buildbarn/bb-storage/pkg/blobstore"
"github.com/buildbarn/bb-storage/pkg/digest"
"github.com/buildbarn/bb-storage/pkg/filesystem"
"github.com/buildbarn/bb-storage/pkg/filesystem/path"
"github.com/buildbarn/bb-storage/pkg/util"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type virtualBuildDirectoryOptions struct {
directoryFetcher cas.DirectoryFetcher
contentAddressableStorage blobstore.BlobAccess
symlinkFactory virtual.SymlinkFactory
characterDeviceFactory virtual.CharacterDeviceFactory
handleAllocator virtual.StatefulHandleAllocator
}
type virtualBuildDirectory struct {
virtual.PrepopulatedDirectory
options *virtualBuildDirectoryOptions
}
// NewVirtualBuildDirectory creates a BuildDirectory that is backed by a
// virtual.PrepopulatedDirectory. Instead of creating all files in the
// input root explicitly, it calls PrepopulatedDirectory.CreateChildren
// to add special file and directory nodes whose contents are read on
// demand.
func NewVirtualBuildDirectory(directory virtual.PrepopulatedDirectory, directoryFetcher cas.DirectoryFetcher, contentAddressableStorage blobstore.BlobAccess, symlinkFactory virtual.SymlinkFactory, characterDeviceFactory virtual.CharacterDeviceFactory, handleAllocator virtual.StatefulHandleAllocator) BuildDirectory {
return &virtualBuildDirectory{
PrepopulatedDirectory: directory,
options: &virtualBuildDirectoryOptions{
directoryFetcher: directoryFetcher,
contentAddressableStorage: contentAddressableStorage,
symlinkFactory: symlinkFactory,
characterDeviceFactory: characterDeviceFactory,
handleAllocator: handleAllocator,
},
}
}
func (d *virtualBuildDirectory) EnterBuildDirectory(name path.Component) (BuildDirectory, error) {
child, err := d.LookupChild(name)
if err != nil {
return nil, err
}
directory, _ := child.GetPair()
if directory == nil {
return nil, syscall.ENOTDIR
}
return &virtualBuildDirectory{
PrepopulatedDirectory: directory,
options: d.options,
}, nil
}
func (d *virtualBuildDirectory) Close() error {
// Virtual directories do not need to be released explicitly.
return nil
}
func (d *virtualBuildDirectory) EnterParentPopulatableDirectory(name path.Component) (ParentPopulatableDirectory, error) {
return d.EnterBuildDirectory(name)
}
func (d *virtualBuildDirectory) EnterUploadableDirectory(name path.Component) (UploadableDirectory, error) {
return d.EnterBuildDirectory(name)
}
func (d *virtualBuildDirectory) InstallHooks(filePool re_filesystem.FilePool, errorLogger util.ErrorLogger) {
d.PrepopulatedDirectory.InstallHooks(
virtual.NewHandleAllocatingFileAllocator(
virtual.NewPoolBackedFileAllocator(filePool, errorLogger),
d.options.handleAllocator),
errorLogger)
}
func (d *virtualBuildDirectory) MergeDirectoryContents(ctx context.Context, errorLogger util.ErrorLogger, digest digest.Digest, monitor access.UnreadDirectoryMonitor) error {
initialContentsFetcher := virtual.NewCASInitialContentsFetcher(
ctx,
cas.NewDecomposedDirectoryWalker(d.options.directoryFetcher, digest),
virtual.NewStatelessHandleAllocatingCASFileFactory(
virtual.NewBlobAccessCASFileFactory(
ctx,
d.options.contentAddressableStorage,
errorLogger),
d.options.handleAllocator.New()),
d.options.symlinkFactory,
digest.GetDigestFunction())
if monitor != nil {
initialContentsFetcher = virtual.NewAccessMonitoringInitialContentsFetcher(initialContentsFetcher, monitor)
}
children, err := initialContentsFetcher.FetchContents(func(name path.Component) virtual.FileReadMonitor { return nil })
if err != nil {
return err
}
return d.CreateChildren(children, false)
}
func (d *virtualBuildDirectory) UploadFile(ctx context.Context, name path.Component, digestFunction digest.Function, writableFileUploadDelay <-chan struct{}) (digest.Digest, error) {
child, err := d.LookupChild(name)
if err != nil {
return digest.BadDigest, err
}
if _, leaf := child.GetPair(); leaf != nil {
return leaf.UploadFile(ctx, d.options.contentAddressableStorage, digestFunction, writableFileUploadDelay)
}
return digest.BadDigest, syscall.EISDIR
}
func (d *virtualBuildDirectory) Lstat(name path.Component) (filesystem.FileInfo, error) {
child, err := d.LookupChild(name)
if err != nil {
return filesystem.FileInfo{}, err
}
if _, leaf := child.GetPair(); leaf != nil {
return virtual.GetFileInfo(name, leaf), nil
}
return filesystem.NewFileInfo(name, filesystem.FileTypeDirectory, false), nil
}
func (d *virtualBuildDirectory) Mkdir(name path.Component, mode os.FileMode) error {
return d.CreateChildren(map[path.Component]virtual.InitialNode{
name: virtual.InitialNode{}.FromDirectory(virtual.EmptyInitialContentsFetcher),
}, false)
}
func (d *virtualBuildDirectory) Mknod(name path.Component, perm os.FileMode, deviceNumber filesystem.DeviceNumber) error {
if perm&os.ModeType != os.ModeDevice|os.ModeCharDevice {
return status.Error(codes.InvalidArgument, "The provided file mode is not for a character device")
}
characterDevice := d.options.characterDeviceFactory.LookupCharacterDevice(deviceNumber)
if err := d.CreateChildren(map[path.Component]virtual.InitialNode{
name: virtual.InitialNode{}.FromLeaf(characterDevice),
}, false); err != nil {
characterDevice.Unlink()
return err
}
return nil
}
func (d *virtualBuildDirectory) Readlink(name path.Component) (path.Parser, error) {
child, err := d.LookupChild(name)
if err != nil {
return nil, err
}
if _, leaf := child.GetPair(); leaf != nil {
return leaf.Readlink()
}
return nil, syscall.EISDIR
}