mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-18 09:17:49 +08:00

Removes gogo/protobuf from buildx and updates to a version of moby/buildkit where gogo is removed. This also changes how the proto files are generated. This is because newer versions of protobuf are more strict about name conflicts. If two files have the same name (even if they are relative paths) and are used in different protoc commands, they'll conflict in the registry. Since protobuf file generation doesn't work very well with `paths=source_relative`, this removes the `go:generate` expression and just relies on the dockerfile to perform the generation. Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
227 lines
6.3 KiB
Go
227 lines
6.3 KiB
Go
/*
|
|
*
|
|
* Copyright 2024 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package mem
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
// BufferSlice offers a means to represent data that spans one or more Buffer
|
|
// instances. A BufferSlice is meant to be immutable after creation, and methods
|
|
// like Ref create and return copies of the slice. This is why all methods have
|
|
// value receivers rather than pointer receivers.
|
|
//
|
|
// Note that any of the methods that read the underlying buffers such as Ref,
|
|
// Len or CopyTo etc., will panic if any underlying buffers have already been
|
|
// freed. It is recommended to not directly interact with any of the underlying
|
|
// buffers directly, rather such interactions should be mediated through the
|
|
// various methods on this type.
|
|
//
|
|
// By convention, any APIs that return (mem.BufferSlice, error) should reduce
|
|
// the burden on the caller by never returning a mem.BufferSlice that needs to
|
|
// be freed if the error is non-nil, unless explicitly stated.
|
|
type BufferSlice []Buffer
|
|
|
|
// Len returns the sum of the length of all the Buffers in this slice.
|
|
//
|
|
// # Warning
|
|
//
|
|
// Invoking the built-in len on a BufferSlice will return the number of buffers
|
|
// in the slice, and *not* the value returned by this function.
|
|
func (s BufferSlice) Len() int {
|
|
var length int
|
|
for _, b := range s {
|
|
length += b.Len()
|
|
}
|
|
return length
|
|
}
|
|
|
|
// Ref invokes Ref on each buffer in the slice.
|
|
func (s BufferSlice) Ref() {
|
|
for _, b := range s {
|
|
b.Ref()
|
|
}
|
|
}
|
|
|
|
// Free invokes Buffer.Free() on each Buffer in the slice.
|
|
func (s BufferSlice) Free() {
|
|
for _, b := range s {
|
|
b.Free()
|
|
}
|
|
}
|
|
|
|
// CopyTo copies each of the underlying Buffer's data into the given buffer,
|
|
// returning the number of bytes copied. Has the same semantics as the copy
|
|
// builtin in that it will copy as many bytes as it can, stopping when either dst
|
|
// is full or s runs out of data, returning the minimum of s.Len() and len(dst).
|
|
func (s BufferSlice) CopyTo(dst []byte) int {
|
|
off := 0
|
|
for _, b := range s {
|
|
off += copy(dst[off:], b.ReadOnlyData())
|
|
}
|
|
return off
|
|
}
|
|
|
|
// Materialize concatenates all the underlying Buffer's data into a single
|
|
// contiguous buffer using CopyTo.
|
|
func (s BufferSlice) Materialize() []byte {
|
|
l := s.Len()
|
|
if l == 0 {
|
|
return nil
|
|
}
|
|
out := make([]byte, l)
|
|
s.CopyTo(out)
|
|
return out
|
|
}
|
|
|
|
// MaterializeToBuffer functions like Materialize except that it writes the data
|
|
// to a single Buffer pulled from the given BufferPool.
|
|
//
|
|
// As a special case, if the input BufferSlice only actually has one Buffer, this
|
|
// function simply increases the refcount before returning said Buffer. Freeing this
|
|
// buffer won't release it until the BufferSlice is itself released.
|
|
func (s BufferSlice) MaterializeToBuffer(pool BufferPool) Buffer {
|
|
if len(s) == 1 {
|
|
s[0].Ref()
|
|
return s[0]
|
|
}
|
|
sLen := s.Len()
|
|
if sLen == 0 {
|
|
return emptyBuffer{}
|
|
}
|
|
buf := pool.Get(sLen)
|
|
s.CopyTo(*buf)
|
|
return NewBuffer(buf, pool)
|
|
}
|
|
|
|
// Reader returns a new Reader for the input slice after taking references to
|
|
// each underlying buffer.
|
|
func (s BufferSlice) Reader() Reader {
|
|
s.Ref()
|
|
return &sliceReader{
|
|
data: s,
|
|
len: s.Len(),
|
|
}
|
|
}
|
|
|
|
// Reader exposes a BufferSlice's data as an io.Reader, allowing it to interface
|
|
// with other parts systems. It also provides an additional convenience method
|
|
// Remaining(), which returns the number of unread bytes remaining in the slice.
|
|
// Buffers will be freed as they are read.
|
|
type Reader interface {
|
|
io.Reader
|
|
io.ByteReader
|
|
// Close frees the underlying BufferSlice and never returns an error. Subsequent
|
|
// calls to Read will return (0, io.EOF).
|
|
Close() error
|
|
// Remaining returns the number of unread bytes remaining in the slice.
|
|
Remaining() int
|
|
}
|
|
|
|
type sliceReader struct {
|
|
data BufferSlice
|
|
len int
|
|
// The index into data[0].ReadOnlyData().
|
|
bufferIdx int
|
|
}
|
|
|
|
func (r *sliceReader) Remaining() int {
|
|
return r.len
|
|
}
|
|
|
|
func (r *sliceReader) Close() error {
|
|
r.data.Free()
|
|
r.data = nil
|
|
r.len = 0
|
|
return nil
|
|
}
|
|
|
|
func (r *sliceReader) freeFirstBufferIfEmpty() bool {
|
|
if len(r.data) == 0 || r.bufferIdx != len(r.data[0].ReadOnlyData()) {
|
|
return false
|
|
}
|
|
|
|
r.data[0].Free()
|
|
r.data = r.data[1:]
|
|
r.bufferIdx = 0
|
|
return true
|
|
}
|
|
|
|
func (r *sliceReader) Read(buf []byte) (n int, _ error) {
|
|
if r.len == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
for len(buf) != 0 && r.len != 0 {
|
|
// Copy as much as possible from the first Buffer in the slice into the
|
|
// given byte slice.
|
|
data := r.data[0].ReadOnlyData()
|
|
copied := copy(buf, data[r.bufferIdx:])
|
|
r.len -= copied // Reduce len by the number of bytes copied.
|
|
r.bufferIdx += copied // Increment the buffer index.
|
|
n += copied // Increment the total number of bytes read.
|
|
buf = buf[copied:] // Shrink the given byte slice.
|
|
|
|
// If we have copied all the data from the first Buffer, free it and advance to
|
|
// the next in the slice.
|
|
r.freeFirstBufferIfEmpty()
|
|
}
|
|
|
|
return n, nil
|
|
}
|
|
|
|
func (r *sliceReader) ReadByte() (byte, error) {
|
|
if r.len == 0 {
|
|
return 0, io.EOF
|
|
}
|
|
|
|
// There may be any number of empty buffers in the slice, clear them all until a
|
|
// non-empty buffer is reached. This is guaranteed to exit since r.len is not 0.
|
|
for r.freeFirstBufferIfEmpty() {
|
|
}
|
|
|
|
b := r.data[0].ReadOnlyData()[r.bufferIdx]
|
|
r.len--
|
|
r.bufferIdx++
|
|
// Free the first buffer in the slice if the last byte was read
|
|
r.freeFirstBufferIfEmpty()
|
|
return b, nil
|
|
}
|
|
|
|
var _ io.Writer = (*writer)(nil)
|
|
|
|
type writer struct {
|
|
buffers *BufferSlice
|
|
pool BufferPool
|
|
}
|
|
|
|
func (w *writer) Write(p []byte) (n int, err error) {
|
|
b := Copy(p, w.pool)
|
|
*w.buffers = append(*w.buffers, b)
|
|
return b.Len(), nil
|
|
}
|
|
|
|
// NewWriter wraps the given BufferSlice and BufferPool to implement the
|
|
// io.Writer interface. Every call to Write copies the contents of the given
|
|
// buffer into a new Buffer pulled from the given pool and the Buffer is added to
|
|
// the given BufferSlice.
|
|
func NewWriter(buffers *BufferSlice, pool BufferPool) io.Writer {
|
|
return &writer{buffers: buffers, pool: pool}
|
|
}
|