github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/util/progress/writer.go (about) 1 package progress 2 3 import ( 4 "time" 5 6 "github.com/moby/buildkit/client" 7 "github.com/moby/buildkit/identity" 8 "github.com/opencontainers/go-digest" 9 ) 10 11 type Writer interface { 12 Write(*client.SolveStatus) 13 WriteBuildRef(string, string) 14 ValidateLogSource(digest.Digest, interface{}) bool 15 ClearLogSource(interface{}) 16 } 17 18 func Write(w Writer, name string, f func() error) error { 19 dgst := digest.FromBytes([]byte(identity.NewID())) 20 tm := time.Now() 21 22 vtx := client.Vertex{ 23 Digest: dgst, 24 Name: name, 25 Started: &tm, 26 } 27 28 w.Write(&client.SolveStatus{ 29 Vertexes: []*client.Vertex{&vtx}, 30 }) 31 32 err := f() 33 34 tm2 := time.Now() 35 vtx2 := vtx 36 vtx2.Completed = &tm2 37 if err != nil { 38 vtx2.Error = err.Error() 39 } 40 w.Write(&client.SolveStatus{ 41 Vertexes: []*client.Vertex{&vtx2}, 42 }) 43 44 return err 45 } 46 47 func WriteBuildRef(w Writer, target string, ref string) { 48 w.WriteBuildRef(target, ref) 49 } 50 51 func NewChannel(w Writer) (chan *client.SolveStatus, chan struct{}) { 52 ch := make(chan *client.SolveStatus) 53 done := make(chan struct{}) 54 go func() { 55 for { 56 v, ok := <-ch 57 if !ok { 58 close(done) 59 w.ClearLogSource(done) 60 return 61 } 62 63 if len(v.Logs) > 0 { 64 logs := make([]*client.VertexLog, 0, len(v.Logs)) 65 for _, l := range v.Logs { 66 if w.ValidateLogSource(l.Vertex, done) { 67 logs = append(logs, l) 68 } 69 } 70 v.Logs = logs 71 } 72 73 w.Write(v) 74 } 75 }() 76 return ch, done 77 } 78 79 type tee struct { 80 Writer 81 ch chan *client.SolveStatus 82 } 83 84 func (t *tee) Write(v *client.SolveStatus) { 85 v2 := *v 86 t.ch <- &v2 87 t.Writer.Write(v) 88 } 89 90 func Tee(w Writer, ch chan *client.SolveStatus) Writer { 91 if ch == nil { 92 return w 93 } 94 return &tee{ 95 Writer: w, 96 ch: ch, 97 } 98 }