gomodfs

package module
v0.0.0-...-fb052f6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 13, 2025 License: BSD-3-Clause Imports: 52 Imported by: 0

README

gomodfs

gomodfs is a virtual filesystem (supporting FUSE, WebDAV, NFSv3, and WinFsp) that implements a read-only filesystem emulating the GOMODCACHE directory layout that has all Go modules accessible, without making the cmd/go tool ever think it needs to download anything. Instead, gomodfs itself downloads modules on demand to pretend that it was on all disk to begin with.

The motivation of this project is to speed up CI build systems, by sharing the Go module cache between builds (each build in its own ephemeral container or VM) and then sharing the gomodfs filesystem into those containers or VMs (over virtiofs) as a read-only filesystem. The guest builds (potentially running untrusted code from malicious PRs) can usefully share a Go module cache that isn't writable.

Without gomodfs, the alternative is to put GOMODCACHE on a tmpfs and run something like a local Athens server. But then each build ends up downloading tons of zip files at startup and extracting potentially hundreds or gigabytes of dependencies to memory, adding considerable overhead before the build even begins. Alternatively, you make all builds share a writable disk, but then you can't run untrusted code.

Frontends

gomodfs is accessible either via FUSE, WebDAV, or NFS.

FUSE is best for Linux. It's works on macOS too, but it's tedious, especially on EC2 VMs where you need to configure SIP & MDM to get it kernel extensions working.

gomodfs also includes a WebDAV and NFSv3 server.

The WebDAV support came first and was found a little lacking (the macOS kernel forces noexec on those mounts), so we also added NFS support.

Also, sharing either the WebDAV or FUSE mount over virtio-fs into Tart VMs hits bugs and limitations in Apple's virtio-fs implementation. See https://github.com/containers/podman/discussions/23886 and https://github.com/docker/for-mac/issues/7059.

As such, we ended up using NFS. gomodfs runs an NFS server on the host and we mount it in the guest VMs.

Windows includes NFSv3 client support, but it's not very performant. To address that, we also added WinFsp support.

Backends

The gomodfs storage backend is abstract and can be implemented however you'd like.

The primary implementation uses git, as most Go modules change very little between releases, and git does content-addressable de-duping for free. The use of git is somewhat abnormal: there are no commit objects. Only tree and blob objects. And refs to those.

Future implementations of the storage interface might include:

  • traditional GOMODCACHE on-disk layout
  • S3/etc object storage

Status

As of 2025-07-27, this is still all very new. Use with caution. It's starting to work, but it might not. Bug reports welcome.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FS

type FS struct {
	Store store.Store

	Stats  *stats.Stats // or nil if stats are not enabled
	Client *http.Client // or nil to use default client

	// ModuleProxyURL is the URL of the Go module proxy to use.
	// If empty, "https://proxy.golang.org" is used.
	// It should not have a trailing slash.
	ModuleProxyURL string

	Logf func(format string, args ...any) // if non-nil, alternate logger to use

	Verbose bool

	// FileCacheSize specifies the file cache size to use.
	// If zero, a default size is used.
	FileCacheSize int64

	MetricFileContentCacheHit  expvar.Int `type:"counter" name:"file_content_cache_hit" help:"number of file content cache hits"`
	MetricFileContentCacheMiss expvar.Int `type:"counter" name:"file_content_cache_miss" help:"number of file content cache misses"`
	MetricFileContentCacheFill expvar.Int `type:"counter" name:"file_content_cache_fill" help:"number of file content cache fills"`
	MetricFileEntryCount       expvar.Int `type:"gauge" name:"file_content_entry_count" help:"current number of file entries in the file content cache"`
	MetricBlobEntryCount       expvar.Int `type:"gauge" name:"blob_entry_count" help:"current number of blob entries in the blob cache"`
	MetricBlobEntrySize        expvar.Int `type:"gauge" name:"blob_entry_size" help:"current total size of all blob entries in the blob cache"`
	// contains filtered or unexported fields
}

FS is the gomodfs filesystem.

func (*FS) GetFileCacheSize

func (fs *FS) GetFileCacheSize() int64

func (*FS) MountFUSE

func (f *FS) MountFUSE(mntPoint string, opt *MountOpts) (MountRunner, error)

func (*FS) MountNFS

func (fs *FS) MountNFS(mntDir string, nfsAddr net.Addr) error

func (*FS) MountWebDAV

func (f *FS) MountWebDAV(mntPoint string, opt *MountOpts) (MountRunner, error)

func (*FS) MountWinFSP

func (mfs *FS) MountWinFSP(mntDir string) (MountRunner, error)

func (*FS) NFSHandler

func (fs *FS) NFSHandler() nfs.Handler

func (*FS) RegisterMetrics

func (fs *FS) RegisterMetrics(reg *prometheus.Registry)

RegisterMetrics registers the FS's expvar.Int fields and other stats as Prometheus metrics in the provided registry.

func (*FS) ServeHTTP

func (s *FS) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*FS) StatusJSON

func (f *FS) StatusJSON() []byte

StatusJSON returns the JSON-encoded status of the <root>/.gomodfs-status file and the debug HTTP handler's /status.json endpoint.

type MountOpts

type MountOpts struct {
	Debug bool // if true, enables debug logging
}

MountOpts are options for mounting the gomodfs filesystem.

A nil value is equivalent to the zero value.

type MountRunner

type MountRunner interface {
	Unmount() error
	Wait()
}

type NFSHandler

type NFSHandler struct {
	nfs.Handler // temporary embedding during dev to watch what panics
	// contains filtered or unexported fields
}

func (*NFSHandler) Change

func (h *NFSHandler) Change(billy.Filesystem) billy.Change

func (*NFSHandler) FSStat

func (h *NFSHandler) FSStat(ctx context.Context, fs billy.Filesystem, stat *nfs.FSStat) error

func (*NFSHandler) FromHandle

func (h *NFSHandler) FromHandle(handleb []byte) (_ billy.Filesystem, segs []string, err error)

func (*NFSHandler) HandleLimit

func (h *NFSHandler) HandleLimit() int

func (*NFSHandler) InvalidateHandle

func (h *NFSHandler) InvalidateHandle(fs billy.Filesystem, fh []byte) error

func (*NFSHandler) Mount

func (*NFSHandler) OnNFSRead

func (n *NFSHandler) OnNFSRead(ctx context.Context, handleb []byte, offset uint64, count uint32) (*nfs.NFSReadResult, error)

func (*NFSHandler) ToHandle

func (h *NFSHandler) ToHandle(_ billy.Filesystem, path []string) []byte

type StatusJSON

type StatusJSON struct {
	Filesystem string                   `json:"filesystem"`
	Uptime     float64                  `json:"uptime"` // seconds since process start
	Ops        map[string]*stats.OpStat `json:"ops,omitzero"`
}

StatusJSON is the JSON type of the <root>/.gomodfs-status file and the debug HTTP handler's /status.json endpoint.

Directories

Path Synopsis
cmd
dumppack command
The dumppack command is used to dump the contents of a pack file to a specified path for debugging purposes.
The dumppack command is used to dump the contents of a pack file to a specified path for debugging purposes.
gomodfs command
The gomodfs server is a virtual file system (FUSE or WebDAV) that implements a read-only GOMODCACHE filesystem that pretends that all modules are accessible, downloading them on demand as needed.
The gomodfs server is a virtual file system (FUSE or WebDAV) that implements a read-only GOMODCACHE filesystem that pretends that all modules are accessible, downloading them on demand as needed.
internal
lru
Package lru contains a typed Least-Recently-Used cache.
Package lru contains a typed Least-Recently-Used cache.
Package stats tracks staticics for the gomodfs file system.
Package stats tracks staticics for the gomodfs file system.
gitstore
Package gitstore stores gomodfs modules in a git repository.
Package gitstore stores gomodfs modules in a git repository.
temp-dev-fork
testing
nfsmount command
The startgomodfs binary is used in CI tests to start a gomodfs server on Windows, because Powershell-in-YAML-in-Github-Actions with shell quoting is hard.
The startgomodfs binary is used in CI tests to start a gomodfs server on Windows, because Powershell-in-YAML-in-Github-Actions with shell quoting is hard.
startgomodfs command
The startgomodfs binary is used in CI tests to start a gomodfs server on Windows, because Powershell-in-YAML-in-Github-Actions with shell quoting is hard.
The startgomodfs binary is used in CI tests to start a gomodfs server on Windows, because Powershell-in-YAML-in-Github-Actions with shell quoting is hard.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL