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  }