Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
473bb86
feat: Add OCI image support and clipctl CLI
cursoragent Oct 26, 2025
e77ad8a
feat: Implement OCI image indexing and lazy loading
cursoragent Oct 26, 2025
8e6093e
Remove clipctl CLI and promote programmatic API
cursoragent Oct 26, 2025
a570112
fix test
luke-beamcloud Oct 26, 2025
3f6619e
Fix: Handle symlink targets and add tests
cursoragent Oct 26, 2025
d062001
Refactor: Stabilize overlayfs mounts and remove test files
cursoragent Oct 26, 2025
519f58b
feat: Add debug script for FUSE mount issues
cursoragent Oct 26, 2025
342897d
Checkpoint before follow-up message
cursoragent Oct 26, 2025
a999780
feat: Add OCI content caching and v2 indexing
cursoragent Oct 27, 2025
3a65f34
Refactor OCI storage to simplify caching and improve testability
cursoragent Oct 27, 2025
df15604
feat: Add comprehensive OCI v2 format verification tests
cursoragent Oct 27, 2025
fd5a487
feat: Optimize OCI indexing and add performance tests
cursoragent Oct 28, 2025
ebda339
Fix: Exclude runtime directories /proc, /sys, /dev from OCI index
cursoragent Oct 28, 2025
e27d53f
Fix: Ensure parent directories exist for all node types
cursoragent Oct 28, 2025
1ea03f8
Refactor: Simplify OCI indexing by removing parent dir creation
cursoragent Oct 28, 2025
5383177
feat: Add FUSE metadata testing strategy and tests
cursoragent Oct 28, 2025
50e7d02
Remove overlayfs and runtime dir filtering
cursoragent Oct 28, 2025
e09efdd
Fix: Set Nlink attribute for directories and files
cursoragent Oct 28, 2025
a961a42
Fix: Add missing FUSE attributes for OCI indexing
cursoragent Oct 28, 2025
d9f939b
Checkpoint before follow-up message
cursoragent Oct 28, 2025
673d18b
Checkpoint before follow-up message
cursoragent Oct 29, 2025
4019e81
feat: Implement disk and remote layer caching
cursoragent Oct 29, 2025
b407724
feat: Implement cross-image disk cache sharing
cursoragent Oct 29, 2025
ebaeb65
feat: Audit OCI indexing and confirm correctness
cursoragent Oct 29, 2025
8a5ea65
feat: Add checkpointing analysis and benchmarks
cursoragent Oct 29, 2025
1446a41
feat: Add content-defined checkpoints for faster reads
cursoragent Oct 29, 2025
b569088
feat: Use content hash for remote cache keys
cursoragent Oct 29, 2025
efd3e55
Fix: Add complete FUSE attributes to root node
cursoragent Oct 29, 2025
dcafbf6
remove some old files
luke-beamcloud Oct 29, 2025
534346a
feat: Implement ContentCache range reads for lazy loading
cursoragent Oct 29, 2025
d4fb318
feat: Implement ContentCache range reads for lazy loading
cursoragent Oct 29, 2025
5d67bcc
feat: Implement ContentCache range reads and CI fixes
cursoragent Oct 29, 2025
9422dd1
Skip FUSE and Docker integration tests in CI
cursoragent Oct 29, 2025
913cb9c
Fix: Skip FUSE and Docker integration tests in CI
cursoragent Oct 29, 2025
c6d9a8e
feat: Implement lazy OCI image FUSE with range reads
cursoragent Oct 29, 2025
1a839ad
remove md files
luke-beamcloud Oct 29, 2025
a198f9b
remove more files
luke-beamcloud Oct 29, 2025
7c5e336
more cleanup
luke-beamcloud Oct 29, 2025
5ae4ee7
remove unused tests
luke-beamcloud Oct 29, 2025
6b2a294
remove comment
luke-beamcloud Oct 29, 2025
0f7f388
move metrics
luke-beamcloud Oct 29, 2025
545721c
wip
luke-beamcloud Oct 29, 2025
76f16ef
add some verbose logs
luke-beamcloud Oct 29, 2025
b81ef15
Consolidate and structure all logging (#31)
luke-lombardi Oct 29, 2025
898214d
Audit and improve oci image caching behavior (#32)
luke-lombardi Oct 29, 2025
324ed54
move tests
luke-beamcloud Oct 29, 2025
9a02452
move some tests around
luke-beamcloud Oct 29, 2025
95b8e23
cleanup
luke-beamcloud Oct 30, 2025
8d052db
Fix OCI indexing cache lookup order (#35)
luke-lombardi Oct 30, 2025
cdecd03
feat: Add minimum gap between OCI checkpoints (#38)
luke-lombardi Oct 30, 2025
bd01be4
clean up logs
luke-beamcloud Oct 30, 2025
ef2ada6
Enable gzip checkpoint seeking for oci layers (#39)
luke-lombardi Oct 30, 2025
06c9283
add content cache available flag
luke-beamcloud Oct 30, 2025
e1187d5
Make registry authentication pluggable (#40)
luke-lombardi Oct 31, 2025
06cef2f
Fix OCI credential provider for beta9 integration (#41)
luke-lombardi Nov 1, 2025
9f938cc
tidy
luke-beamcloud Nov 1, 2025
e0fd643
Embed image metadata into OCI index (#42)
luke-lombardi Nov 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ RUN go mod download

COPY . .

RUN go build -o /workspace/bin/clip /workspace/cmd/main.go
RUN go build -v ./pkg/...

RUN mkdir -p /tmp/test

Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ imageVersion := latest
.PHONY: e2e

build:
okteto build --build-arg BUILD_ENV=okteto -f ./Dockerfile -t localhost:5001/beam-clip:$(imageVersion)
docker build -f ./Dockerfile -t localhost:5001/beam-clip:$(imageVersion) .

start:
cd hack; okteto up --file okteto.yml
Expand All @@ -12,5 +12,4 @@ stop:
cd hack; okteto down --file okteto.yml

e2e:
go build -o ./bin/e2e ./e2e/main.go

go build -o ./bin/e2e ./e2e/main.go
24 changes: 0 additions & 24 deletions README.md

This file was deleted.

13 changes: 0 additions & 13 deletions TODO.md

This file was deleted.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.27.5
github.com/aws/aws-sdk-go-v2/credentials v1.17.5
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.15
github.com/aws/aws-sdk-go-v2/service/ecr v1.27.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.51.2
github.com/gofrs/flock v0.8.1
github.com/google/go-containerregistry v0.19.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.2 h1:en92G0Z7xlksoOylkUhuBSfJgijC7rHVLRdnIlHEs0E=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.2/go.mod h1:HgtQ/wN5G+8QSlK62lbOtNwQ3wTSByJ4wH2rCkPt+AE=
github.com/aws/aws-sdk-go-v2/service/ecr v1.27.0 h1:e9RAM6FgxAN3ca3LKaCr20+YnMqg8vhX/k6WDA8BpT8=
github.com/aws/aws-sdk-go-v2/service/ecr v1.27.0/go.mod h1:Fa36Bp93PNtMtKHoyIvQnJY8EGTR0UQqRo3NfjW0hT0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.3 h1:fpFzBoro/MetYBk+8kxoQGMeKSkXbymnbUh2gy6nVgk=
Expand Down
41 changes: 32 additions & 9 deletions pkg/clip/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"path/filepath"
"strings"
"syscall"
"time"

"github.com/hanwen/go-fuse/v2/fuse"
log "github.com/rs/zerolog/log"
Expand All @@ -31,10 +32,15 @@ func init() {
gob.Register(&common.ClipNode{})
gob.Register(&common.StorageInfoWrapper{})
gob.Register(&common.S3StorageInfo{})
gob.Register(&common.OCIStorageInfo{})
gob.Register(&common.RemoteRef{})
gob.Register(&common.GzipCheckpoint{})
gob.Register(&common.GzipIndex{})
gob.Register(&common.ZstdFrame{})
gob.Register(&common.ZstdIndex{})
}

type ClipArchiverOptions struct {
Verbose bool
Compress bool
ArchivePath string
SourcePath string
Expand Down Expand Up @@ -68,11 +74,27 @@ func (ig *InodeGenerator) Next() uint64 {

// populateIndex creates a representation of the filesystem/folder being archived
func (ca *ClipArchiver) populateIndex(index *btree.BTree, sourcePath string) error {
// Create root directory
now := time.Now()
root := &common.ClipNode{
Path: "/",
NodeType: common.DirNode,
Attr: fuse.Attr{
Mode: uint32(os.ModeDir | 0755),
Ino: 1,
Size: 0,
Blocks: 0,
Atime: uint64(now.Unix()),
Atimensec: uint32(now.Nanosecond()),
Mtime: uint64(now.Unix()),
Mtimensec: uint32(now.Nanosecond()),
Ctime: uint64(now.Unix()),
Ctimensec: uint32(now.Nanosecond()),
Mode: uint32(syscall.S_IFDIR | 0755),
Nlink: 2, // Directories start with link count of 2 (. and ..)
Owner: fuse.Owner{
Uid: 0, // root
Gid: 0, // root
},
},
}
index.Set(root)
Expand Down Expand Up @@ -431,6 +453,12 @@ func (ca *ClipArchiver) ExtractMetadata(archivePath string) (*common.ClipArchive
return nil, fmt.Errorf("error decoding s3 storage info: %v", err)
}
storageInfo = s3Info
case string(common.StorageModeOCI):
var ociInfo common.OCIStorageInfo
if err := gob.NewDecoder(bytes.NewReader(wrapper.Data)).Decode(&ociInfo); err != nil {
return nil, fmt.Errorf("error decoding oci storage info: %v", err)
}
storageInfo = ociInfo
default:
return nil, fmt.Errorf("unsupported storage info type: %s", wrapper.Type)
}
Expand Down Expand Up @@ -496,10 +524,7 @@ func (ca *ClipArchiver) Extract(opts ClipArchiverOptions) error {
// Iterate over the index and extract every node
index.Ascend(index.Min(), func(a interface{}) bool {
node := a.(*common.ClipNode)

if opts.Verbose {
log.Info().Msgf("Extracting... %s", node.Path)
}
log.Debug().Str("path", node.Path).Msg("Extracting")

if node.NodeType == common.FileNode {
// Seek to the position of the file in the archive
Expand Down Expand Up @@ -599,9 +624,7 @@ func (ca *ClipArchiver) writeBlocks(index *btree.BTree, sourcePath string, outFi
}

func (ca *ClipArchiver) processNode(node *common.ClipNode, writer *bufio.Writer, sourcePath string, pos *int64, opts ClipArchiverOptions) bool {
if opts.Verbose {
log.Info().Msgf("Archiving... %s", node.Path)
}
log.Debug().Str("path", node.Path).Msg("Archiving")

f, err := os.Open(path.Join(sourcePath, node.Path))
if err != nil {
Expand Down
3 changes: 0 additions & 3 deletions pkg/clip/archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ func TestCreateArchive(t *testing.T) {
options := CreateOptions{
InputPath: tempDir,
OutputPath: archiveFile.Name(),
Verbose: true,
}

err = CreateArchive(options)
Expand Down Expand Up @@ -107,7 +106,6 @@ func TestCreateArchive(t *testing.T) {
extractOptions := ExtractOptions{
InputFile: archiveFile.Name(),
OutputPath: extractDir,
Verbose: true,
}

err = ExtractArchive(extractOptions)
Expand Down Expand Up @@ -243,7 +241,6 @@ func BenchmarkCreateArchiveFromOCIImage(b *testing.B) {
options := CreateOptions{
InputPath: tmpDir,
OutputPath: archiveFile.Name(),
Verbose: false,
}

start := time.Now()
Expand Down
Loading