2018-01-02 18:06:50 +00:00
|
|
|
package solver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/moby/buildkit/client"
|
|
|
|
"github.com/moby/buildkit/util/progress"
|
|
|
|
digest "github.com/opencontainers/go-digest"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (j *Job) Status(ctx context.Context, ch chan *client.SolveStatus) error {
|
2020-07-05 05:25:45 +00:00
|
|
|
vs := &vertexStream{cache: map[digest.Digest]*client.Vertex{}, wasCached: make(map[digest.Digest]struct{})}
|
2018-01-02 18:06:50 +00:00
|
|
|
pr := j.pr.Reader(ctx)
|
|
|
|
defer func() {
|
|
|
|
if enc := vs.encore(); len(enc) > 0 {
|
|
|
|
ch <- &client.SolveStatus{Vertexes: enc}
|
|
|
|
}
|
2018-04-13 21:00:15 +00:00
|
|
|
close(ch)
|
2018-01-02 18:06:50 +00:00
|
|
|
}()
|
2018-04-13 21:00:15 +00:00
|
|
|
|
2018-01-02 18:06:50 +00:00
|
|
|
for {
|
|
|
|
p, err := pr.Read(ctx)
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ss := &client.SolveStatus{}
|
|
|
|
for _, p := range p {
|
|
|
|
switch v := p.Sys.(type) {
|
|
|
|
case client.Vertex:
|
|
|
|
ss.Vertexes = append(ss.Vertexes, vs.append(v)...)
|
|
|
|
|
|
|
|
case progress.Status:
|
|
|
|
vtx, ok := p.Meta("vertex")
|
|
|
|
if !ok {
|
|
|
|
logrus.Warnf("progress %s status without vertex info", p.ID)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
vs := &client.VertexStatus{
|
|
|
|
ID: p.ID,
|
|
|
|
Vertex: vtx.(digest.Digest),
|
|
|
|
Name: v.Action,
|
|
|
|
Total: int64(v.Total),
|
|
|
|
Current: int64(v.Current),
|
|
|
|
Timestamp: p.Timestamp,
|
|
|
|
Started: v.Started,
|
|
|
|
Completed: v.Completed,
|
|
|
|
}
|
|
|
|
ss.Statuses = append(ss.Statuses, vs)
|
|
|
|
case client.VertexLog:
|
|
|
|
vtx, ok := p.Meta("vertex")
|
|
|
|
if !ok {
|
|
|
|
logrus.Warnf("progress %s log without vertex info", p.ID)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
v.Vertex = vtx.(digest.Digest)
|
|
|
|
v.Timestamp = p.Timestamp
|
|
|
|
ss.Logs = append(ss.Logs, &v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
case ch <- ss:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type vertexStream struct {
|
2020-07-05 05:25:45 +00:00
|
|
|
cache map[digest.Digest]*client.Vertex
|
|
|
|
wasCached map[digest.Digest]struct{}
|
2018-01-02 18:06:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (vs *vertexStream) append(v client.Vertex) []*client.Vertex {
|
|
|
|
var out []*client.Vertex
|
|
|
|
vs.cache[v.Digest] = &v
|
2018-04-13 21:00:15 +00:00
|
|
|
if v.Started != nil {
|
2018-01-02 18:06:50 +00:00
|
|
|
for _, inp := range v.Inputs {
|
|
|
|
if inpv, ok := vs.cache[inp]; ok {
|
|
|
|
if !inpv.Cached && inpv.Completed == nil {
|
|
|
|
inpv.Cached = true
|
2018-04-13 21:00:15 +00:00
|
|
|
inpv.Started = v.Started
|
|
|
|
inpv.Completed = v.Started
|
|
|
|
out = append(out, vs.append(*inpv)...)
|
|
|
|
delete(vs.cache, inp)
|
2018-01-02 18:06:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-05 05:25:45 +00:00
|
|
|
if v.Cached {
|
|
|
|
vs.markCached(v.Digest)
|
|
|
|
}
|
|
|
|
|
2018-01-02 18:06:50 +00:00
|
|
|
vcopy := v
|
|
|
|
return append(out, &vcopy)
|
|
|
|
}
|
|
|
|
|
2020-07-05 05:25:45 +00:00
|
|
|
func (vs *vertexStream) markCached(dgst digest.Digest) {
|
|
|
|
if v, ok := vs.cache[dgst]; ok {
|
|
|
|
if _, ok := vs.wasCached[dgst]; !ok {
|
|
|
|
for _, inp := range v.Inputs {
|
|
|
|
vs.markCached(inp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vs.wasCached[dgst] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-02 18:06:50 +00:00
|
|
|
func (vs *vertexStream) encore() []*client.Vertex {
|
|
|
|
var out []*client.Vertex
|
|
|
|
for _, v := range vs.cache {
|
|
|
|
if v.Started != nil && v.Completed == nil {
|
|
|
|
now := time.Now()
|
|
|
|
v.Completed = &now
|
2020-07-05 05:25:45 +00:00
|
|
|
if _, ok := vs.wasCached[v.Digest]; !ok && v.Error == "" {
|
|
|
|
v.Error = context.Canceled.Error()
|
|
|
|
}
|
2018-01-02 18:06:50 +00:00
|
|
|
out = append(out, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|