@@ -3,28 +3,18 @@ package local
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
- "io"
7
- "io/fs"
8
6
"os"
9
- "path"
10
7
"strings"
11
8
"time"
12
9
13
- "github.com/docker/docker/pkg/idtools"
14
- intoto "github.com/in-toto/in-toto-golang/in_toto"
15
10
"github.com/moby/buildkit/cache"
16
11
"github.com/moby/buildkit/exporter"
17
- "github.com/moby/buildkit/exporter/attestation"
18
12
"github.com/moby/buildkit/exporter/containerimage/exptypes"
19
13
"github.com/moby/buildkit/exporter/util/epoch"
20
14
"github.com/moby/buildkit/session"
21
15
"github.com/moby/buildkit/session/filesync"
22
- "github.com/moby/buildkit/snapshot"
23
16
"github.com/moby/buildkit/solver/result"
24
17
"github.com/moby/buildkit/util/progress"
25
- "github.com/moby/buildkit/util/staticfs"
26
- digest "github.com/opencontainers/go-digest"
27
- ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
28
18
"github.com/pkg/errors"
29
19
"github.com/tonistiigi/fsutil"
30
20
fstypes "github.com/tonistiigi/fsutil/types"
@@ -56,12 +46,17 @@ func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exp
56
46
return nil , err
57
47
}
58
48
59
- i := & localExporterInstance {localExporter : e , epoch : tm }
49
+ i := & localExporterInstance {
50
+ localExporter : e ,
51
+ opts : CreateFSOpts {
52
+ Epoch : tm ,
53
+ },
54
+ }
60
55
61
56
for k , v := range opt {
62
57
switch k {
63
58
case keyAttestationPrefix :
64
- i .attestationPrefix = v
59
+ i .opts . AttestationPrefix = v
65
60
}
66
61
}
67
62
@@ -70,8 +65,7 @@ func (e *localExporter) Resolve(ctx context.Context, opt map[string]string) (exp
70
65
71
66
type localExporterInstance struct {
72
67
* localExporter
73
- epoch * time.Time
74
- attestationPrefix string
68
+ opts CreateFSOpts
75
69
}
76
70
77
71
func (e * localExporterInstance ) Name () string {
@@ -86,11 +80,11 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
86
80
timeoutCtx , cancel := context .WithTimeout (ctx , 5 * time .Second )
87
81
defer cancel ()
88
82
89
- if e .epoch == nil {
83
+ if e .opts . Epoch == nil {
90
84
if tm , ok , err := epoch .ParseSource (inp ); err != nil {
91
85
return nil , err
92
86
} else if ok {
93
- e .epoch = tm
87
+ e .opts . Epoch = tm
94
88
}
95
89
}
96
90
@@ -114,127 +108,14 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
114
108
115
109
now := time .Now ().Truncate (time .Second )
116
110
117
- export := func (ctx context.Context , k string , p * ocispecs. Platform , ref cache.ImmutableRef , attestations []result.Attestation ) func () error {
111
+ export := func (ctx context.Context , k string , ref cache.ImmutableRef , attestations []result.Attestation ) func () error {
118
112
return func () error {
119
- var src string
120
- var err error
121
- var idmap * idtools.IdentityMapping
122
- if ref == nil {
123
- src , err = os .MkdirTemp ("" , "buildkit" )
124
- if err != nil {
125
- return err
126
- }
127
- defer os .RemoveAll (src )
128
- } else {
129
- mount , err := ref .Mount (ctx , true , session .NewGroup (sessionID ))
130
- if err != nil {
131
- return err
132
- }
133
-
134
- lm := snapshot .LocalMounter (mount )
135
-
136
- src , err = lm .Mount ()
137
- if err != nil {
138
- return err
139
- }
140
-
141
- idmap = mount .IdentityMapping ()
142
-
143
- defer lm .Unmount ()
144
- }
145
-
146
- walkOpt := & fsutil.WalkOpt {}
147
- var idMapFunc func (p string , st * fstypes.Stat ) fsutil.MapResult
148
- if idmap != nil {
149
- idMapFunc = func (p string , st * fstypes.Stat ) fsutil.MapResult {
150
- uid , gid , err := idmap .ToContainer (idtools.Identity {
151
- UID : int (st .Uid ),
152
- GID : int (st .Gid ),
153
- })
154
- if err != nil {
155
- return fsutil .MapResultExclude
156
- }
157
- st .Uid = uint32 (uid )
158
- st .Gid = uint32 (gid )
159
- return fsutil .MapResultKeep
160
- }
161
- }
162
- walkOpt .Map = func (p string , st * fstypes.Stat ) fsutil.MapResult {
163
- res := fsutil .MapResultKeep
164
- if idMapFunc != nil {
165
- res = idMapFunc (p , st )
166
- }
167
- if e .epoch != nil {
168
- st .ModTime = e .epoch .UnixNano ()
169
- }
170
- return res
171
- }
172
-
173
- outputFS := fsutil .NewFS (src , walkOpt )
174
-
175
- attestations , err = attestation .Unbundle (ctx , session .NewGroup (sessionID ), inp .Refs , attestations )
113
+ outputFS , cleanup , err := CreateFS (ctx , sessionID , k , ref , inp .Refs , attestations , now , e .opts )
176
114
if err != nil {
177
115
return err
178
116
}
179
- if len (attestations ) > 0 {
180
- subjects := []intoto.Subject {}
181
- err = outputFS .Walk (ctx , func (path string , info fs.FileInfo , err error ) error {
182
- if err != nil {
183
- return err
184
- }
185
- if ! info .Mode ().IsRegular () {
186
- return nil
187
- }
188
- f , err := outputFS .Open (path )
189
- if err != nil {
190
- return err
191
- }
192
- defer f .Close ()
193
- d := digest .Canonical .Digester ()
194
- if _ , err := io .Copy (d .Hash (), f ); err != nil {
195
- return err
196
- }
197
- subjects = append (subjects , intoto.Subject {
198
- Name : path ,
199
- Digest : result .ToDigestMap (d .Digest ()),
200
- })
201
- return nil
202
- })
203
- if err != nil {
204
- return err
205
- }
206
-
207
- stmts , err := attestation .MakeInTotoStatements (ctx , session .NewGroup (sessionID ), inp .Refs , attestations , subjects )
208
- if err != nil {
209
- return err
210
- }
211
- stmtFS := staticfs .NewFS ()
212
-
213
- names := map [string ]struct {}{}
214
- for i , stmt := range stmts {
215
- dt , err := json .Marshal (stmt )
216
- if err != nil {
217
- return errors .Wrap (err , "failed to marshal attestation" )
218
- }
219
-
220
- if attestations [i ].Path == "" {
221
- return errors .New ("attestation does not have set path" )
222
- }
223
- name := e .attestationPrefix + path .Base (attestations [i ].Path )
224
- if _ , ok := names [name ]; ok {
225
- return errors .Errorf ("duplicate attestation path name %s" , name )
226
- }
227
- names [name ] = struct {}{}
228
-
229
- st := fstypes.Stat {
230
- Mode : 0600 ,
231
- Path : name ,
232
- ModTime : now .UnixNano (),
233
- }
234
- stmtFS .Add (name , st , dt )
235
- }
236
-
237
- outputFS = staticfs .NewMergeFS (outputFS , stmtFS )
117
+ if cleanup != nil {
118
+ defer cleanup ()
238
119
}
239
120
240
121
lbl := "copying files"
@@ -244,8 +125,8 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
244
125
Mode : uint32 (os .ModeDir | 0755 ),
245
126
Path : strings .Replace (k , "/" , "_" , - 1 ),
246
127
}
247
- if e .epoch != nil {
248
- st .ModTime = e .epoch .UnixNano ()
128
+ if e .opts . Epoch != nil {
129
+ st .ModTime = e .opts . Epoch .UnixNano ()
249
130
}
250
131
251
132
outputFS , err = fsutil .SubDirFS ([]fsutil.Dir {{FS : outputFS , Stat : st }})
@@ -270,13 +151,13 @@ func (e *localExporterInstance) Export(ctx context.Context, inp *exporter.Source
270
151
if ! ok {
271
152
return nil , errors .Errorf ("failed to find ref for ID %s" , p .ID )
272
153
}
273
- eg .Go (export (ctx , p .ID , & p . Platform , r , inp .Attestations [p .ID ]))
154
+ eg .Go (export (ctx , p .ID , r , inp .Attestations [p .ID ]))
274
155
if ! isMap {
275
156
break
276
157
}
277
158
}
278
159
} else {
279
- eg .Go (export (ctx , "" , nil , inp .Ref , nil ))
160
+ eg .Go (export (ctx , "" , inp .Ref , nil ))
280
161
}
281
162
282
163
if err := eg .Wait (); err != nil {
0 commit comments