Skip to content

Commit 5c97696

Browse files
committed
dap: improve determination of the proper parent for certain ops
Improves the determination of the proper parent for exec and file ops. With file ops, it will only consider inputs and ignore secondary inputs. This prevents the following case: ``` FROM busybox AS build1 RUN echo foo > /hello FROM scratch COPY --from=build1 /hello . ``` Previously, `build1` would be considered the parent of the copy instruction. Now, copy properly does not have a parent. If there are multiple file ops and the operations disagree on the canonical "parent", we give up on trying to find a canonical parent and assume there is none. For exec operations, whichever input is associated with the root mount is considered the primary parent. For all other operations, the first parent is considered the primary parent if it exists. Signed-off-by: Jonathan A. Sternberg <[email protected]>
1 parent 10605b8 commit 5c97696

File tree

1 file changed

+44
-3
lines changed

1 file changed

+44
-3
lines changed

dap/thread.go

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,12 @@ func (t *thread) createBranch(last *step) (first *step) {
163163

164164
op := t.ops[first.dgst]
165165
if len(op.Inputs) > 0 {
166-
for i := len(op.Inputs) - 1; i > 0; i-- {
166+
parent := t.determineParent(op)
167+
for i := len(op.Inputs) - 1; i >= 0; i-- {
168+
if i == parent {
169+
// Skip the direct parent.
170+
continue
171+
}
167172
inp := op.Inputs[i]
168173

169174
// Create a pseudo-step that acts as an exit point for this
@@ -188,8 +193,10 @@ func (t *thread) createBranch(last *step) (first *step) {
188193
}
189194

190195
// Set the digest of the parent input on the first step associated
191-
// with this step.
192-
prev.dgst = digest.Digest(op.Inputs[0].Digest)
196+
// with this step if it exists.
197+
if parent >= 0 {
198+
prev.dgst = digest.Digest(op.Inputs[parent].Digest)
199+
}
193200
}
194201

195202
// New first is the step we just created.
@@ -217,6 +224,40 @@ func (t *thread) getStackFrame(dgst digest.Digest) *frame {
217224
return f
218225
}
219226

227+
func (t *thread) determineParent(op *pb.Op) int {
228+
// Another section should have already checked this but
229+
// double check here just in case we forget somewhere else.
230+
// The rest of this method assumes there's at least one parent
231+
// at index zero.
232+
n := len(op.Inputs)
233+
if n == 0 {
234+
return -1
235+
}
236+
237+
switch op := op.Op.(type) {
238+
case *pb.Op_Exec:
239+
for _, m := range op.Exec.Mounts {
240+
if m.Dest == "/" {
241+
return int(m.Input)
242+
}
243+
}
244+
return -1
245+
case *pb.Op_File:
246+
// Use the first input where the index is from one of the inputs.
247+
for _, action := range op.File.Actions {
248+
if input := int(action.Input); input >= 0 && input < n {
249+
return input
250+
}
251+
}
252+
253+
// Default to having no parent.
254+
return -1
255+
default:
256+
// Default to index zero.
257+
return 0
258+
}
259+
}
260+
220261
func (t *thread) reset() {
221262
t.c = nil
222263
t.ref = nil

0 commit comments

Comments
 (0)