This repository was archived by the owner on Jan 24, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathoptions.go
More file actions
241 lines (212 loc) · 7.22 KB
/
options.go
File metadata and controls
241 lines (212 loc) · 7.22 KB
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
package blobber
import (
"log/slog"
"time"
"oras.land/oras-go/v2/registry/remote/credentials"
"github.com/meigma/blobber/core"
"github.com/meigma/blobber/internal/registry"
)
// ClientOption configures a Client.
type ClientOption func(*Client) error
// PushOption configures a Push operation.
type PushOption func(*pushConfig)
// PullOption configures a Pull operation.
type PullOption func(*pullConfig)
// ExtractLimits defines safety limits for extraction.
// Re-exported from core package.
type ExtractLimits = core.ExtractLimits
// pushConfig holds configuration for Push operations.
type pushConfig struct {
annotations map[string]string
mediaType string
compression Compression
progress ProgressCallback
}
// pullConfig holds configuration for Pull operations.
type pullConfig struct {
limits ExtractLimits
progress ProgressCallback
}
// WithAnnotations sets OCI annotations on the pushed image.
func WithAnnotations(annotations map[string]string) PushOption {
return func(c *pushConfig) {
c.annotations = annotations
}
}
// WithCompression sets the compression algorithm (gzip or zstd).
func WithCompression(c Compression) PushOption {
return func(cfg *pushConfig) {
cfg.compression = c
}
}
// WithCredentials sets explicit credentials for a specific registry.
func WithCredentials(registryHost, username, password string) ClientOption {
return func(c *Client) error {
c.credStore = staticCredentials(registryHost, username, password)
return nil
}
}
// WithCredentialStore sets a custom credential store.
func WithCredentialStore(store credentials.Store) ClientOption {
return func(c *Client) error {
c.credStore = store
return nil
}
}
// WithExtractLimits sets safety limits for extraction.
func WithExtractLimits(limits ExtractLimits) PullOption {
return func(c *pullConfig) {
c.limits = limits
}
}
// WithInsecure allows connections to registries without TLS.
func WithInsecure(insecure bool) ClientOption {
return func(c *Client) error {
c.plainHTTP = insecure
return nil
}
}
// WithLogger sets a logger for the client. By default, logging is disabled.
func WithLogger(logger *slog.Logger) ClientOption {
return func(c *Client) error {
c.logger = logger
return nil
}
}
// WithMediaType sets a custom media type for the layer.
func WithMediaType(mt string) PushOption {
return func(c *pushConfig) {
c.mediaType = mt
}
}
// WithPushProgress sets a callback to receive progress updates during push.
// The callback receives cumulative bytes uploaded to the registry.
func WithPushProgress(callback ProgressCallback) PushOption {
return func(c *pushConfig) {
c.progress = callback
}
}
// WithPullProgress sets a callback to receive progress updates during pull.
// The callback receives cumulative bytes downloaded from the registry.
func WithPullProgress(callback ProgressCallback) PullOption {
return func(c *pullConfig) {
c.progress = callback
}
}
// WithUserAgent sets a custom User-Agent header for registry requests.
func WithUserAgent(ua string) ClientOption {
return func(c *Client) error {
c.userAgent = ua
return nil
}
}
// WithDescriptorCache enables in-memory caching for layer descriptor resolution.
// This can return stale results for mutable tags; prefer digest references.
func WithDescriptorCache(enabled bool) ClientOption {
return func(c *Client) error {
c.descCache = enabled
return nil
}
}
// WithCacheDir enables blob caching at the specified directory path.
// When caching is enabled, blobs are stored locally after download and
// served from the cache on subsequent requests.
//
// The cache directory structure is:
//
// <path>/blobs/sha256/<hash> - cached blob files
// <path>/entries/sha256/<hash>.json - cache metadata
//
// If the directory does not exist, it will be created.
// Caching is opt-in; if not specified, no caching is performed.
func WithCacheDir(path string) ClientOption {
return func(c *Client) error {
absPath, err := resolveCachePath(path)
if err != nil {
return err
}
c.cacheDir = absPath
return nil
}
}
// WithBackgroundPrefetch enables background prefetching of complete blobs
// when a partial cache hit occurs. This allows reading from the partial cache
// immediately while the remaining data is downloaded in the background.
//
// This option only has effect when caching is enabled (via WithCacheDir).
// The prefetch runs in a background goroutine and will stop if the context
// is canceled.
func WithBackgroundPrefetch(enabled bool) ClientOption {
return func(c *Client) error {
c.backgroundPrefetch = enabled
return nil
}
}
// WithLazyLoading enables on-demand fetching for OpenImage.
// When enabled, blobs are not downloaded upfront. Instead, byte ranges
// are fetched lazily as they are read (via io.ReaderAt calls).
//
// This is ideal for eStargz archives where only the TOC (table of contents)
// and specific file chunks need to be accessed, avoiding full blob downloads.
//
// The lazy loading workflow:
// 1. OpenImage resolves the layer descriptor (no download yet)
// 2. estargz reads the footer (last ~10KB) to parse the TOC
// 3. Only the requested file chunks are fetched when files are opened
// 4. Downloaded ranges are cached for future access
//
// This option only has effect when caching is enabled (via WithCacheDir).
// If the blob is already complete in cache, it is served directly.
func WithLazyLoading(enabled bool) ClientOption {
return func(c *Client) error {
c.lazyLoading = enabled
return nil
}
}
// WithCacheTTL sets the TTL for cache validation.
// When set, cached entries will be used without re-validating with the
// registry if they were validated within the TTL duration.
//
// A zero or negative TTL means always validate (current behavior).
// This option only has effect when caching is enabled (via WithCacheDir).
//
// WARNING: Using a TTL means you may get stale data if a tag is updated
// on the registry. For immutable references (digests), TTL is always safe.
// For mutable tags, choose a TTL that balances freshness vs. performance.
func WithCacheTTL(ttl time.Duration) ClientOption {
return func(c *Client) error {
c.cacheTTL = ttl
return nil
}
}
// WithCacheVerifyOnRead re-hashes cached blobs on cache hits to detect tampering.
// This is incompatible with lazy loading (WithLazyLoading).
func WithCacheVerifyOnRead(enabled bool) ClientOption {
return func(c *Client) error {
c.cacheVerifyOnRead = enabled
return nil
}
}
// WithSigner configures signing for push operations.
// When set, Push will invoke the signer after successfully pushing the artifact
// and store the signature as an OCI referrer artifact.
func WithSigner(s Signer) ClientOption {
return func(c *Client) error {
c.signer = s
return nil
}
}
// WithVerifier configures verification for pull/open operations.
// When set, OpenImage will fetch and verify signatures before returning.
// Returns ErrNoSignature if no signatures are found.
// Returns ErrSignatureInvalid if verification fails.
func WithVerifier(v Verifier) ClientOption {
return func(c *Client) error {
c.verifier = v
return nil
}
}
// staticCredentials returns a credential store with a single static credential.
func staticCredentials(registryHost, username, password string) credentials.Store {
return registry.StaticCredentials(registryHost, username, password)
}