golang.org/x/build@v0.0.0-20240506185731-218518f32b70/internal/task/task.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package task implements tasks involved in making a Go release. 6 package task 7 8 import ( 9 "bytes" 10 "context" 11 "sync" 12 "time" 13 14 wf "golang.org/x/build/internal/workflow" 15 ) 16 17 // Published holds information for a Go release 18 // that by this time has already been published. 19 // 20 // Published in this context refers to it being 21 // available for download at https://go.dev/dl/. 22 // It doesn't mean it has been announced by now; 23 // that step happens sometime after publication. 24 type Published struct { 25 Version string // Version that's published, in the same format as Go tags. For example, "go1.21rc1". 26 Files []WebsiteFile // Files that are published. 27 } 28 29 // CommunicationTasks combines communication tasks together. 30 type CommunicationTasks struct { 31 AnnounceMailTasks 32 SocialMediaTasks 33 } 34 35 var AwaitDivisor int = 1 36 37 // AwaitCondition calls the condition function every period until it returns 38 // true to indicate success, or an error. If the condition succeeds, 39 // AwaitCondition returns its result. 40 func AwaitCondition[T any](ctx *wf.TaskContext, period time.Duration, condition func() (T, bool, error)) (T, error) { 41 pollTimer := time.NewTicker(period / time.Duration(AwaitDivisor)) 42 defer pollTimer.Stop() 43 for { 44 res, done, err := condition() 45 if done || err != nil { 46 return res, err 47 } 48 select { 49 case <-ctx.Done(): 50 var zero T 51 return zero, ctx.Err() 52 case <-pollTimer.C: 53 ctx.ResetWatchdog() 54 } 55 } 56 } 57 58 // LogWriter is an io.Writer that writes to a workflow task's log, flushing 59 // its buffer periodically to avoid too many writes. 60 type LogWriter struct { 61 Logger wf.Logger 62 63 flushTicker *time.Ticker 64 65 mu sync.Mutex 66 buf []byte 67 } 68 69 func (w *LogWriter) Write(b []byte) (int, error) { 70 w.mu.Lock() 71 defer w.mu.Unlock() 72 73 w.buf = append(w.buf, b...) 74 if len(w.buf) > 1<<20 { 75 w.flushLocked(false) 76 w.flushTicker.Reset(10 * time.Second) 77 } 78 return len(b), nil 79 } 80 81 func (w *LogWriter) flush(force bool) { 82 w.mu.Lock() 83 defer w.mu.Unlock() 84 w.flushLocked(force) 85 } 86 87 func (w *LogWriter) flushLocked(force bool) { 88 if len(w.buf) == 0 { 89 return 90 } 91 log, rest := w.buf, []byte(nil) 92 if !force { 93 nl := bytes.LastIndexByte(w.buf, '\n') 94 if nl == -1 { 95 return 96 } 97 log, rest = w.buf[:nl], w.buf[nl+1:] 98 } 99 w.Logger.Printf("\n%s", string(log)) 100 w.buf = append([]byte(nil), rest...) // don't leak 101 } 102 103 func (w *LogWriter) Run(ctx context.Context) { 104 w.flushTicker = time.NewTicker(10 * time.Second) 105 defer w.flushTicker.Stop() 106 for { 107 select { 108 case <-w.flushTicker.C: 109 w.flush(false) 110 case <-ctx.Done(): 111 w.flush(true) 112 return 113 } 114 } 115 } 116 117 // WebsiteFile represents a file on the go.dev downloads page. 118 // It should be kept in sync with the download code in x/website/internal/dl. 119 type WebsiteFile struct { 120 Filename string `json:"filename"` 121 OS string `json:"os"` 122 Arch string `json:"arch"` 123 Version string `json:"version"` 124 ChecksumSHA256 string `json:"sha256"` 125 Size int64 `json:"size"` 126 Kind string `json:"kind"` // "archive", "installer", "source" 127 } 128 129 func (f WebsiteFile) GOARCH() string { 130 if f.OS == "linux" && f.Arch == "armv6l" { 131 return "arm" 132 } 133 return f.Arch 134 } 135 136 type WebsiteRelease struct { 137 Version string `json:"version"` 138 Stable bool `json:"stable"` 139 Files []WebsiteFile `json:"files"` 140 Visible bool `json:"-"` // show files on page load 141 SplitPortTable bool `json:"-"` // whether files should be split by primary/other ports. 142 }