Skip to content

Commit edfba12

Browse files
authored
Merge pull request #6045 from jedevc/solveopt-exporter-store
client: allow configuring exporter content store
2 parents 870aae6 + dce5cac commit edfba12

File tree

2 files changed

+78
-43
lines changed

2 files changed

+78
-43
lines changed

client/client_test.go

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3703,6 +3703,38 @@ func testOCIExporterContentStore(t *testing.T, sb integration.Sandbox) {
37033703
}, nil)
37043704
require.NoError(t, err)
37053705

3706+
dt, err := os.ReadFile(outTar)
3707+
require.NoError(t, err)
3708+
m, err := testutil.ReadTarToMap(dt, false)
3709+
require.NoError(t, err)
3710+
3711+
checkStore := func(dir string) {
3712+
err = filepath.Walk(dir, func(filename string, fi os.FileInfo, err error) error {
3713+
filename = strings.TrimPrefix(filename, dir)
3714+
filename = strings.Trim(filename, "/")
3715+
if filename == "" || filename == "ingest" {
3716+
return nil
3717+
}
3718+
3719+
if fi.IsDir() {
3720+
require.Contains(t, m, filename+"/")
3721+
} else {
3722+
require.Contains(t, m, filename)
3723+
if filename == ocispecs.ImageIndexFile {
3724+
// this file has a timestamp in it, so we can't compare
3725+
return nil
3726+
}
3727+
f, err := os.Open(path.Join(dir, filename))
3728+
require.NoError(t, err)
3729+
data, err := io.ReadAll(f)
3730+
require.NoError(t, err)
3731+
require.Equal(t, m[filename].Data, data)
3732+
}
3733+
return nil
3734+
})
3735+
require.NoError(t, err)
3736+
}
3737+
37063738
outDir := filepath.Join(destDir, "out.d")
37073739
attrs = map[string]string{
37083740
"tar": "false",
@@ -3720,35 +3752,28 @@ func testOCIExporterContentStore(t *testing.T, sb integration.Sandbox) {
37203752
},
37213753
}, nil)
37223754
require.NoError(t, err)
3755+
checkStore(outDir)
37233756

3724-
dt, err := os.ReadFile(outTar)
3757+
outStoreDir := filepath.Join(destDir, "store.d")
3758+
store, err := local.NewStore(outStoreDir)
37253759
require.NoError(t, err)
3726-
m, err := testutil.ReadTarToMap(dt, false)
3760+
attrs = map[string]string{
3761+
"tar": "false",
3762+
}
3763+
if exp == ExporterDocker {
3764+
attrs["name"] = target
3765+
}
3766+
_, err = c.Solve(sb.Context(), def, SolveOpt{
3767+
Exports: []ExportEntry{
3768+
{
3769+
Type: exp,
3770+
Attrs: attrs,
3771+
OutputStore: store,
3772+
},
3773+
},
3774+
}, nil)
37273775
require.NoError(t, err)
3728-
3729-
filepath.Walk(outDir, func(filename string, fi os.FileInfo, err error) error {
3730-
filename = strings.TrimPrefix(filename, outDir)
3731-
filename = strings.Trim(filename, "/")
3732-
if filename == "" || filename == "ingest" {
3733-
return nil
3734-
}
3735-
3736-
if fi.IsDir() {
3737-
require.Contains(t, m, filename+"/")
3738-
} else {
3739-
require.Contains(t, m, filename)
3740-
if filename == ocispecs.ImageIndexFile {
3741-
// this file has a timestamp in it, so we can't compare
3742-
return nil
3743-
}
3744-
f, err := os.Open(path.Join(outDir, filename))
3745-
require.NoError(t, err)
3746-
data, err := io.ReadAll(f)
3747-
require.NoError(t, err)
3748-
require.Equal(t, m[filename].Data, data)
3749-
}
3750-
return nil
3751-
})
3776+
checkStore(outDir)
37523777
}
37533778

37543779
checkAllReleasable(t, c, sb, true)

client/solve.go

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@ type SolveOpt struct {
5555
}
5656

5757
type ExportEntry struct {
58-
Type string
59-
Attrs map[string]string
60-
Output filesync.FileOutputFunc // for ExporterOCI and ExporterDocker
61-
OutputDir string // for ExporterLocal
58+
Type string
59+
Attrs map[string]string
60+
Output filesync.FileOutputFunc // for ExporterOCI and ExporterDocker
61+
OutputDir string // for ExporterLocal
62+
OutputStore content.Store
6263
}
6364

6465
type CacheOptionsEntry struct {
@@ -154,26 +155,28 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
154155

155156
var syncTargets []filesync.FSSyncTarget
156157
for exID, ex := range opt.Exports {
157-
var supportFile bool
158-
var supportDir bool
158+
var supportFile, supportDir, supportStore bool
159159
switch ex.Type {
160160
case ExporterLocal:
161161
supportDir = true
162162
case ExporterTar:
163163
supportFile = true
164164
case ExporterOCI, ExporterDocker:
165-
supportDir = ex.OutputDir != ""
166165
supportFile = ex.Output != nil
167-
}
168-
if supportFile && supportDir {
169-
return nil, errors.Errorf("both file and directory output is not supported by %s exporter", ex.Type)
166+
supportStore = ex.OutputStore != nil || ex.OutputDir != ""
167+
if supportFile && supportStore {
168+
return nil, errors.Errorf("both file and store output is not supported by %s exporter", ex.Type)
169+
}
170170
}
171171
if !supportFile && ex.Output != nil {
172172
return nil, errors.Errorf("output file writer is not supported by %s exporter", ex.Type)
173173
}
174-
if !supportDir && ex.OutputDir != "" {
174+
if !supportDir && !supportStore && ex.OutputDir != "" {
175175
return nil, errors.Errorf("output directory is not supported by %s exporter", ex.Type)
176176
}
177+
if !supportStore && ex.OutputStore != nil {
178+
return nil, errors.Errorf("output store is not supported by %s exporter", ex.Type)
179+
}
177180
if supportFile {
178181
if ex.Output == nil {
179182
return nil, errors.Errorf("output file writer is required for %s exporter", ex.Type)
@@ -184,20 +187,27 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
184187
if ex.OutputDir == "" {
185188
return nil, errors.Errorf("output directory is required for %s exporter", ex.Type)
186189
}
187-
switch ex.Type {
188-
case ExporterOCI, ExporterDocker:
190+
syncTargets = append(syncTargets, filesync.WithFSSyncDir(exID, ex.OutputDir))
191+
}
192+
if supportStore {
193+
store := ex.OutputStore
194+
if store == nil {
189195
if err := os.MkdirAll(ex.OutputDir, 0755); err != nil {
190196
return nil, err
191197
}
192-
cs, err := contentlocal.NewStore(ex.OutputDir)
198+
store, err = contentlocal.NewStore(ex.OutputDir)
193199
if err != nil {
194200
return nil, err
195201
}
196-
contentStores["export"] = cs
197202
storesToUpdate = append(storesToUpdate, ex.OutputDir)
198-
default:
199-
syncTargets = append(syncTargets, filesync.WithFSSyncDir(exID, ex.OutputDir))
200203
}
204+
205+
// TODO: this should be dependent on the exporter id (to allow multiple oci exporters)
206+
storeName := "export"
207+
if _, ok := contentStores[storeName]; ok {
208+
return nil, errors.Errorf("oci store key %q already exists", storeName)
209+
}
210+
contentStores[storeName] = store
201211
}
202212
}
203213

0 commit comments

Comments
 (0)