Skip to content

Commit bb66efc

Browse files
committed
fix: bring os_js.go up to date with os.go
Recent changes to os_js.go added WithBoundOS and ChrootOSFS. These changes were not propagated to os_js.go, which results in the following build failures in go-git: % GOOS=js GOARCH=wasm gb ./... github.com/go-git/go-git/v6 ./remote.go:214:32: undefined: osfs.WithBoundOS ./repository.go:348:29: undefined: osfs.WithBoundOS ./repository.go:353:28: undefined: osfs.WithBoundOS ./repository.go:460:28: undefined: osfs.WithBoundOS ./repository.go:468:44: undefined: osfs.WithBoundOS ./repository.go:528:32: undefined: osfs.WithBoundOS ./repository.go:531:46: undefined: osfs.WithBoundOS ./repository.go:551:36: undefined: osfs.WithBoundOS ./repository.go:553:62: undefined: osfs.WithBoundOS This commit brings os_js.go up to date with os.go to fix this. All tests pass with GOOS=js GOARCH=wasm now. Signed-off-by: Christian Stewart <christian@aperture.us>
1 parent 593ae45 commit bb66efc

2 files changed

Lines changed: 186 additions & 8 deletions

File tree

osfs/os_js.go

Lines changed: 177 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,192 @@
33
package osfs
44

55
import (
6+
iofs "io/fs"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
611
"github.com/go-git/go-billy/v6"
712
"github.com/go-git/go-billy/v6/helper/chroot"
813
"github.com/go-git/go-billy/v6/memfs"
14+
"github.com/go-git/go-billy/v6/util"
915
)
1016

11-
// globalMemFs is the global memory fs
17+
// globalMemFs is the global memory fs.
1218
var globalMemFs = memfs.New()
1319

14-
// Default Filesystem representing the root of in-memory filesystem for a
15-
// js/wasm environment.
16-
var Default = memfs.New()
20+
// Default Filesystem representing the root of the os filesystem.
21+
var Default = &ChrootOS{}
1722

1823
// New returns a new OS filesystem.
19-
func New(baseDir string, _ ...Option) billy.Filesystem {
24+
// By default paths are deduplicated, but still enforced
25+
// under baseDir. For more info refer to WithDeduplicatePath.
26+
func New(baseDir string, opts ...Option) billy.Filesystem {
27+
o := &options{
28+
deduplicatePath: true,
29+
}
30+
for _, opt := range opts {
31+
opt(o)
32+
}
33+
34+
if o.Type == BoundOSFS {
35+
return newBoundOS(baseDir, o.deduplicatePath)
36+
}
37+
38+
return newChrootOS(baseDir)
39+
}
40+
41+
// ChrootOS is a legacy filesystem based on a "soft chroot" of the js/wasm
42+
// in-memory filesystem.
43+
type ChrootOS struct{}
44+
45+
func newChrootOS(baseDir string) billy.Filesystem {
2046
return chroot.New(Default, Default.Join("/", baseDir))
2147
}
2248

23-
type options struct{}
49+
func (fs *ChrootOS) Create(filename string) (billy.File, error) {
50+
return globalMemFs.Create(filename)
51+
}
52+
53+
func (fs *ChrootOS) OpenFile(filename string, flag int, perm iofs.FileMode) (billy.File, error) {
54+
return globalMemFs.OpenFile(filename, flag, perm)
55+
}
56+
57+
func (fs *ChrootOS) ReadDir(dir string) ([]iofs.DirEntry, error) {
58+
return globalMemFs.ReadDir(dir)
59+
}
60+
61+
func (fs *ChrootOS) Rename(from, to string) error {
62+
return globalMemFs.Rename(from, to)
63+
}
64+
65+
func (fs *ChrootOS) MkdirAll(path string, perm iofs.FileMode) error {
66+
return globalMemFs.MkdirAll(path, perm)
67+
}
68+
69+
func (fs *ChrootOS) Open(filename string) (billy.File, error) {
70+
return globalMemFs.Open(filename)
71+
}
72+
73+
func (fs *ChrootOS) Stat(filename string) (os.FileInfo, error) {
74+
return globalMemFs.Stat(filename)
75+
}
76+
77+
func (fs *ChrootOS) Remove(filename string) error {
78+
return globalMemFs.Remove(filename)
79+
}
80+
81+
func (fs *ChrootOS) Chmod(path string, mode iofs.FileMode) error {
82+
return globalMemFs.(billy.Chmod).Chmod(path, mode)
83+
}
84+
85+
func (fs *ChrootOS) TempFile(dir, prefix string) (billy.File, error) {
86+
return globalMemFs.TempFile(dir, prefix)
87+
}
88+
89+
func (fs *ChrootOS) Join(elem ...string) string {
90+
return globalMemFs.Join(elem...)
91+
}
92+
93+
func (fs *ChrootOS) RemoveAll(path string) error {
94+
return util.RemoveAll(globalMemFs, path)
95+
}
96+
97+
func (fs *ChrootOS) Lstat(filename string) (os.FileInfo, error) {
98+
return globalMemFs.Lstat(filename)
99+
}
100+
101+
func (fs *ChrootOS) Symlink(target, link string) error {
102+
return globalMemFs.Symlink(target, link)
103+
}
104+
105+
func (fs *ChrootOS) Readlink(link string) (string, error) {
106+
return globalMemFs.Readlink(link)
107+
}
108+
109+
// Capabilities implements the Capable interface.
110+
func (fs *ChrootOS) Capabilities() billy.Capability {
111+
return billy.Capabilities(globalMemFs)
112+
}
113+
114+
// BoundOS is a fs implementation based on the js/wasm in-memory filesystem
115+
// which is bound to a base dir.
116+
type BoundOS struct {
117+
billy.Filesystem
118+
baseDir string
119+
deduplicatePath bool
120+
}
121+
122+
func newBoundOS(d string, deduplicatePath bool) billy.Filesystem {
123+
baseDir := globalMemFs.Join("/", d)
124+
return &BoundOS{
125+
Filesystem: chroot.New(globalMemFs, baseDir),
126+
baseDir: baseDir,
127+
deduplicatePath: deduplicatePath,
128+
}
129+
}
130+
131+
// Chroot returns a new BoundOS filesystem, with the base dir set to the
132+
// result of joining the provided path with the underlying base dir.
133+
func (fs *BoundOS) Chroot(path string) (billy.Filesystem, error) {
134+
joined, err := fs.abs(path)
135+
if err != nil {
136+
return nil, err
137+
}
138+
return New(joined, WithBoundOS(), WithDeduplicatePath(fs.deduplicatePath)), nil
139+
}
140+
141+
// Root returns the current base dir of the billy.Filesystem.
142+
func (fs *BoundOS) Root() string {
143+
return fs.baseDir
144+
}
145+
146+
func (fs *BoundOS) abs(filename string) (string, error) {
147+
if filename == "." || filename == "" {
148+
return fs.baseDir, nil
149+
}
150+
151+
filename = filepath.ToSlash(filename)
152+
filename = filepath.Clean(filename)
153+
if strings.HasPrefix(filename, "..") {
154+
return "", billy.ErrCrossedBoundary
155+
}
156+
157+
filename = strings.TrimPrefix(filename, string(filepath.Separator))
158+
return filepath.Clean(filepath.Join(fs.baseDir, filepath.FromSlash(filename))), nil
159+
}
160+
161+
// WithBoundOS returns the option of using a Bound filesystem OS.
162+
func WithBoundOS() Option {
163+
return func(o *options) {
164+
o.Type = BoundOSFS
165+
}
166+
}
167+
168+
// WithChrootOS returns the option of using a Chroot filesystem OS.
169+
func WithChrootOS() Option {
170+
return func(o *options) {
171+
o.Type = ChrootOSFS
172+
}
173+
}
174+
175+
// WithDeduplicatePath toggles the deduplication of the base dir in the path.
176+
// This option is accepted for API parity with non-js builds and has no effect
177+
// on the js/wasm in-memory implementation.
178+
func WithDeduplicatePath(enabled bool) Option {
179+
return func(o *options) {
180+
o.deduplicatePath = enabled
181+
}
182+
}
183+
184+
type options struct {
185+
Type
186+
deduplicatePath bool
187+
}
188+
189+
type Type int
190+
191+
const (
192+
ChrootOSFS Type = iota
193+
BoundOSFS
194+
)

osfs/os_js_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"testing"
1010

1111
"github.com/go-git/go-billy/v6"
12-
"github.com/go-git/go-billy/v6/helper/chroot"
1312
"github.com/stretchr/testify/assert"
1413
)
1514

@@ -33,13 +32,21 @@ func TestCapabilities(t *testing.T) {
3332
}
3433

3534
func TestDefault(t *testing.T) {
36-
want := &chroot.ChrootHelper{} // memfs is wrapped around ChrootHelper.
35+
want := &ChrootOS{}
3736
got := Default
3837

3938
if reflect.TypeOf(got) != reflect.TypeOf(want) {
4039
t.Errorf("wanted Default to be %T got %T", want, got)
4140
}
4241
}
4342

43+
func TestWithBoundOSReturnsBoundOS(t *testing.T) {
44+
got := New(t.TempDir(), WithBoundOS())
45+
assert.IsType(t, &BoundOS{}, got)
46+
}
47+
4448
// API call assertions
4549
var _ = New("/")
50+
var _ = New("/", WithBoundOS())
51+
var _ = New("/", WithChrootOS())
52+
var _ = New("/", WithDeduplicatePath(false))

0 commit comments

Comments
 (0)