mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
vendor: update buildkit with typed errors support
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
77
vendor/github.com/moby/buildkit/util/progress/multireader.go
generated
vendored
Normal file
77
vendor/github.com/moby/buildkit/util/progress/multireader.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
package progress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type MultiReader struct {
|
||||
mu sync.Mutex
|
||||
main Reader
|
||||
initialized bool
|
||||
done chan struct{}
|
||||
writers map[*progressWriter]func()
|
||||
}
|
||||
|
||||
func NewMultiReader(pr Reader) *MultiReader {
|
||||
mr := &MultiReader{
|
||||
main: pr,
|
||||
writers: make(map[*progressWriter]func()),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
return mr
|
||||
}
|
||||
|
||||
func (mr *MultiReader) Reader(ctx context.Context) Reader {
|
||||
mr.mu.Lock()
|
||||
defer mr.mu.Unlock()
|
||||
|
||||
pr, ctx, closeWriter := NewContext(ctx)
|
||||
pw, _, ctx := FromContext(ctx)
|
||||
|
||||
w := pw.(*progressWriter)
|
||||
mr.writers[w] = closeWriter
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-mr.done:
|
||||
}
|
||||
mr.mu.Lock()
|
||||
defer mr.mu.Unlock()
|
||||
delete(mr.writers, w)
|
||||
}()
|
||||
|
||||
if !mr.initialized {
|
||||
go mr.handle()
|
||||
mr.initialized = true
|
||||
}
|
||||
|
||||
return pr
|
||||
}
|
||||
|
||||
func (mr *MultiReader) handle() error {
|
||||
for {
|
||||
p, err := mr.main.Read(context.TODO())
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
mr.mu.Lock()
|
||||
for w, c := range mr.writers {
|
||||
w.Close()
|
||||
c()
|
||||
}
|
||||
mr.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
mr.mu.Lock()
|
||||
for _, p := range p {
|
||||
for w := range mr.writers {
|
||||
w.writeRawProgress(p)
|
||||
}
|
||||
}
|
||||
mr.mu.Unlock()
|
||||
}
|
||||
}
|
104
vendor/github.com/moby/buildkit/util/progress/multiwriter.go
generated
vendored
Normal file
104
vendor/github.com/moby/buildkit/util/progress/multiwriter.go
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
package progress
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type rawProgressWriter interface {
|
||||
WriteRawProgress(*Progress) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
type MultiWriter struct {
|
||||
mu sync.Mutex
|
||||
items []*Progress
|
||||
writers map[rawProgressWriter]struct{}
|
||||
meta map[string]interface{}
|
||||
}
|
||||
|
||||
func NewMultiWriter(opts ...WriterOption) *MultiWriter {
|
||||
mw := &MultiWriter{
|
||||
writers: map[rawProgressWriter]struct{}{},
|
||||
meta: map[string]interface{}{},
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(mw)
|
||||
}
|
||||
return mw
|
||||
}
|
||||
|
||||
func (ps *MultiWriter) Add(pw Writer) {
|
||||
rw, ok := pw.(rawProgressWriter)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
ps.mu.Lock()
|
||||
plist := make([]*Progress, 0, len(ps.items))
|
||||
for _, p := range ps.items {
|
||||
plist = append(plist, p)
|
||||
}
|
||||
sort.Slice(plist, func(i, j int) bool {
|
||||
return plist[i].Timestamp.Before(plist[j].Timestamp)
|
||||
})
|
||||
for _, p := range plist {
|
||||
rw.WriteRawProgress(p)
|
||||
}
|
||||
ps.writers[rw] = struct{}{}
|
||||
ps.mu.Unlock()
|
||||
}
|
||||
|
||||
func (ps *MultiWriter) Delete(pw Writer) {
|
||||
rw, ok := pw.(rawProgressWriter)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ps.mu.Lock()
|
||||
delete(ps.writers, rw)
|
||||
ps.mu.Unlock()
|
||||
}
|
||||
|
||||
func (ps *MultiWriter) Write(id string, v interface{}) error {
|
||||
p := &Progress{
|
||||
ID: id,
|
||||
Timestamp: time.Now(),
|
||||
Sys: v,
|
||||
meta: ps.meta,
|
||||
}
|
||||
return ps.WriteRawProgress(p)
|
||||
}
|
||||
|
||||
func (ps *MultiWriter) WriteRawProgress(p *Progress) error {
|
||||
meta := p.meta
|
||||
if len(ps.meta) > 0 {
|
||||
meta = map[string]interface{}{}
|
||||
for k, v := range p.meta {
|
||||
meta[k] = v
|
||||
}
|
||||
for k, v := range ps.meta {
|
||||
if _, ok := meta[k]; !ok {
|
||||
meta[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
p.meta = meta
|
||||
return ps.writeRawProgress(p)
|
||||
}
|
||||
|
||||
func (ps *MultiWriter) writeRawProgress(p *Progress) error {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
ps.items = append(ps.items, p)
|
||||
for w := range ps.writers {
|
||||
if err := w.WriteRawProgress(p); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *MultiWriter) Close() error {
|
||||
return nil
|
||||
}
|
261
vendor/github.com/moby/buildkit/util/progress/progress.go
generated
vendored
Normal file
261
vendor/github.com/moby/buildkit/util/progress/progress.go
generated
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
package progress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Progress package provides utility functions for using the context to capture
|
||||
// progress of a running function. All progress items written contain an ID
|
||||
// that is used to collapse unread messages.
|
||||
|
||||
type contextKeyT string
|
||||
|
||||
var contextKey = contextKeyT("buildkit/util/progress")
|
||||
|
||||
// FromContext returns a progress writer from a context.
|
||||
func FromContext(ctx context.Context, opts ...WriterOption) (Writer, bool, context.Context) {
|
||||
v := ctx.Value(contextKey)
|
||||
pw, ok := v.(*progressWriter)
|
||||
if !ok {
|
||||
if pw, ok := v.(*MultiWriter); ok {
|
||||
return pw, true, ctx
|
||||
}
|
||||
return &noOpWriter{}, false, ctx
|
||||
}
|
||||
pw = newWriter(pw)
|
||||
for _, o := range opts {
|
||||
o(pw)
|
||||
}
|
||||
ctx = context.WithValue(ctx, contextKey, pw)
|
||||
return pw, true, ctx
|
||||
}
|
||||
|
||||
type WriterOption func(Writer)
|
||||
|
||||
// NewContext returns a new context and a progress reader that captures all
|
||||
// progress items writtern to this context. Last returned parameter is a closer
|
||||
// function to signal that no new writes will happen to this context.
|
||||
func NewContext(ctx context.Context) (Reader, context.Context, func()) {
|
||||
pr, pw, cancel := pipe()
|
||||
ctx = WithProgress(ctx, pw)
|
||||
return pr, ctx, cancel
|
||||
}
|
||||
|
||||
func WithProgress(ctx context.Context, pw Writer) context.Context {
|
||||
return context.WithValue(ctx, contextKey, pw)
|
||||
}
|
||||
|
||||
func WithMetadata(key string, val interface{}) WriterOption {
|
||||
return func(w Writer) {
|
||||
if pw, ok := w.(*progressWriter); ok {
|
||||
pw.meta[key] = val
|
||||
}
|
||||
if pw, ok := w.(*MultiWriter); ok {
|
||||
pw.meta[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Controller interface {
|
||||
Start(context.Context) (context.Context, func(error))
|
||||
Status(id string, action string) func()
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Write(id string, value interface{}) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
type Reader interface {
|
||||
Read(context.Context) ([]*Progress, error)
|
||||
}
|
||||
|
||||
type Progress struct {
|
||||
ID string
|
||||
Timestamp time.Time
|
||||
Sys interface{}
|
||||
meta map[string]interface{}
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Action string
|
||||
Current int
|
||||
Total int
|
||||
Started *time.Time
|
||||
Completed *time.Time
|
||||
}
|
||||
|
||||
type progressReader struct {
|
||||
ctx context.Context
|
||||
cond *sync.Cond
|
||||
mu sync.Mutex
|
||||
writers map[*progressWriter]struct{}
|
||||
dirty map[string]*Progress
|
||||
}
|
||||
|
||||
func (pr *progressReader) Read(ctx context.Context) ([]*Progress, error) {
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func() {
|
||||
select {
|
||||
case <-done:
|
||||
case <-ctx.Done():
|
||||
pr.mu.Lock()
|
||||
pr.cond.Broadcast()
|
||||
pr.mu.Unlock()
|
||||
}
|
||||
}()
|
||||
pr.mu.Lock()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
pr.mu.Unlock()
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
dmap := pr.dirty
|
||||
if len(dmap) == 0 {
|
||||
select {
|
||||
case <-pr.ctx.Done():
|
||||
if len(pr.writers) == 0 {
|
||||
pr.mu.Unlock()
|
||||
return nil, io.EOF
|
||||
}
|
||||
default:
|
||||
}
|
||||
pr.cond.Wait()
|
||||
continue
|
||||
}
|
||||
pr.dirty = make(map[string]*Progress)
|
||||
pr.mu.Unlock()
|
||||
|
||||
out := make([]*Progress, 0, len(dmap))
|
||||
for _, p := range dmap {
|
||||
out = append(out, p)
|
||||
}
|
||||
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
return out[i].Timestamp.Before(out[j].Timestamp)
|
||||
})
|
||||
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *progressReader) append(pw *progressWriter) {
|
||||
pr.mu.Lock()
|
||||
defer pr.mu.Unlock()
|
||||
|
||||
select {
|
||||
case <-pr.ctx.Done():
|
||||
return
|
||||
default:
|
||||
pr.writers[pw] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func pipe() (*progressReader, *progressWriter, func()) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
pr := &progressReader{
|
||||
ctx: ctx,
|
||||
writers: make(map[*progressWriter]struct{}),
|
||||
dirty: make(map[string]*Progress),
|
||||
}
|
||||
pr.cond = sync.NewCond(&pr.mu)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
pr.mu.Lock()
|
||||
pr.cond.Broadcast()
|
||||
pr.mu.Unlock()
|
||||
}()
|
||||
pw := &progressWriter{
|
||||
reader: pr,
|
||||
}
|
||||
return pr, pw, cancel
|
||||
}
|
||||
|
||||
func newWriter(pw *progressWriter) *progressWriter {
|
||||
meta := make(map[string]interface{})
|
||||
for k, v := range pw.meta {
|
||||
meta[k] = v
|
||||
}
|
||||
pw = &progressWriter{
|
||||
reader: pw.reader,
|
||||
meta: meta,
|
||||
}
|
||||
pw.reader.append(pw)
|
||||
return pw
|
||||
}
|
||||
|
||||
type progressWriter struct {
|
||||
done bool
|
||||
reader *progressReader
|
||||
meta map[string]interface{}
|
||||
}
|
||||
|
||||
func (pw *progressWriter) Write(id string, v interface{}) error {
|
||||
if pw.done {
|
||||
return errors.Errorf("writing %s to closed progress writer", id)
|
||||
}
|
||||
return pw.writeRawProgress(&Progress{
|
||||
ID: id,
|
||||
Timestamp: time.Now(),
|
||||
Sys: v,
|
||||
meta: pw.meta,
|
||||
})
|
||||
}
|
||||
|
||||
func (pw *progressWriter) WriteRawProgress(p *Progress) error {
|
||||
meta := p.meta
|
||||
if len(pw.meta) > 0 {
|
||||
meta = map[string]interface{}{}
|
||||
for k, v := range p.meta {
|
||||
meta[k] = v
|
||||
}
|
||||
for k, v := range pw.meta {
|
||||
if _, ok := meta[k]; !ok {
|
||||
meta[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
p.meta = meta
|
||||
return pw.writeRawProgress(p)
|
||||
}
|
||||
|
||||
func (pw *progressWriter) writeRawProgress(p *Progress) error {
|
||||
pw.reader.mu.Lock()
|
||||
pw.reader.dirty[p.ID] = p
|
||||
pw.reader.cond.Broadcast()
|
||||
pw.reader.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pw *progressWriter) Close() error {
|
||||
pw.reader.mu.Lock()
|
||||
delete(pw.reader.writers, pw)
|
||||
pw.reader.mu.Unlock()
|
||||
pw.reader.cond.Broadcast()
|
||||
pw.done = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Progress) Meta(key string) (interface{}, bool) {
|
||||
v, ok := p.meta[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
type noOpWriter struct{}
|
||||
|
||||
func (pw *noOpWriter) Write(_ string, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pw *noOpWriter) Close() error {
|
||||
return nil
|
||||
}
|
12
vendor/github.com/moby/buildkit/util/progress/progressui/display.go
generated
vendored
12
vendor/github.com/moby/buildkit/util/progress/progressui/display.go
generated
vendored
@ -273,7 +273,14 @@ func (t *trace) update(s *client.SolveStatus, termWidth int) {
|
||||
if v.Started != nil {
|
||||
ts = l.Timestamp.Sub(*v.Started)
|
||||
}
|
||||
v.logs = append(v.logs, []byte(fmt.Sprintf("#%d %s %s", v.index, fmt.Sprintf("%#.4g", ts.Seconds())[:5], dt)))
|
||||
prec := 1
|
||||
sec := ts.Seconds()
|
||||
if sec < 10 {
|
||||
prec = 3
|
||||
} else if sec < 100 {
|
||||
prec = 2
|
||||
}
|
||||
v.logs = append(v.logs, []byte(fmt.Sprintf("#%d %s %s", v.index, fmt.Sprintf("%.[2]*[1]f", sec, prec), dt)))
|
||||
}
|
||||
i++
|
||||
})
|
||||
@ -548,6 +555,9 @@ func align(l, r string, w int) string {
|
||||
}
|
||||
|
||||
func wrapHeight(j []*job, limit int) []*job {
|
||||
if limit < 0 {
|
||||
return nil
|
||||
}
|
||||
var wrapped []*job
|
||||
wrapped = append(wrapped, j...)
|
||||
if len(j) > limit {
|
||||
|
6
vendor/github.com/moby/buildkit/util/progress/progressui/printer.go
generated
vendored
6
vendor/github.com/moby/buildkit/util/progress/progressui/printer.go
generated
vendored
@ -57,11 +57,11 @@ func (p *textMux) printVtx(t *trace, dgst digest.Digest) {
|
||||
p.notFirst = true
|
||||
}
|
||||
|
||||
if os.Getenv("PROGRESS_NO_TRUNC") == "1" {
|
||||
if os.Getenv("PROGRESS_NO_TRUNC") == "0" {
|
||||
fmt.Fprintf(p.w, "#%d %s\n", v.index, limitString(v.Name, 72))
|
||||
} else {
|
||||
fmt.Fprintf(p.w, "#%d %s\n", v.index, v.Name)
|
||||
fmt.Fprintf(p.w, "#%d %s\n", v.index, v.Digest)
|
||||
} else {
|
||||
fmt.Fprintf(p.w, "#%d %s\n", v.index, limitString(v.Name, 72))
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user