github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/util/buildflags/export.go (about)

     1  package buildflags
     2  
     3  import (
     4  	"encoding/csv"
     5  	"regexp"
     6  	"strings"
     7  
     8  	"github.com/containerd/containerd/platforms"
     9  	controllerapi "github.com/docker/buildx/controller/pb"
    10  	"github.com/moby/buildkit/client"
    11  	"github.com/moby/buildkit/exporter/containerimage/exptypes"
    12  	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  func ParseExports(inp []string) ([]*controllerapi.ExportEntry, error) {
    17  	var outs []*controllerapi.ExportEntry
    18  	if len(inp) == 0 {
    19  		return nil, nil
    20  	}
    21  	for _, s := range inp {
    22  		csvReader := csv.NewReader(strings.NewReader(s))
    23  		fields, err := csvReader.Read()
    24  		if err != nil {
    25  			return nil, err
    26  		}
    27  
    28  		out := controllerapi.ExportEntry{
    29  			Attrs: map[string]string{},
    30  		}
    31  		if len(fields) == 1 && fields[0] == s && !strings.HasPrefix(s, "type=") {
    32  			if s != "-" {
    33  				outs = append(outs, &controllerapi.ExportEntry{
    34  					Type:        client.ExporterLocal,
    35  					Destination: s,
    36  				})
    37  				continue
    38  			}
    39  			out = controllerapi.ExportEntry{
    40  				Type:        client.ExporterTar,
    41  				Destination: s,
    42  			}
    43  		}
    44  
    45  		if out.Type == "" {
    46  			for _, field := range fields {
    47  				parts := strings.SplitN(field, "=", 2)
    48  				if len(parts) != 2 {
    49  					return nil, errors.Errorf("invalid value %s", field)
    50  				}
    51  				key := strings.TrimSpace(strings.ToLower(parts[0]))
    52  				value := parts[1]
    53  				switch key {
    54  				case "type":
    55  					out.Type = value
    56  				default:
    57  					out.Attrs[key] = value
    58  				}
    59  			}
    60  		}
    61  		if out.Type == "" {
    62  			return nil, errors.Errorf("type is required for output")
    63  		}
    64  
    65  		if out.Type == "registry" {
    66  			out.Type = client.ExporterImage
    67  			if _, ok := out.Attrs["push"]; !ok {
    68  				out.Attrs["push"] = "true"
    69  			}
    70  		}
    71  
    72  		if dest, ok := out.Attrs["dest"]; ok {
    73  			out.Destination = dest
    74  			delete(out.Attrs, "dest")
    75  		}
    76  
    77  		outs = append(outs, &out)
    78  	}
    79  	return outs, nil
    80  }
    81  
    82  func ParseAnnotations(inp []string) (map[exptypes.AnnotationKey]string, error) {
    83  	// TODO: use buildkit's annotation parser once it supports setting custom prefix and ":" separator
    84  	annotationRegexp := regexp.MustCompile(`^(?:([a-z-]+)(?:\[([A-Za-z0-9_/-]+)\])?:)?(\S+)$`)
    85  	annotations := make(map[exptypes.AnnotationKey]string)
    86  	for _, inp := range inp {
    87  		k, v, ok := strings.Cut(inp, "=")
    88  		if !ok {
    89  			return nil, errors.Errorf("invalid annotation %q, expected key=value", inp)
    90  		}
    91  
    92  		groups := annotationRegexp.FindStringSubmatch(k)
    93  		if groups == nil {
    94  			return nil, errors.Errorf("invalid annotation format, expected <type>:<key>=<value>, got %q", inp)
    95  		}
    96  
    97  		typ, platform, key := groups[1], groups[2], groups[3]
    98  		switch typ {
    99  		case "":
   100  		case exptypes.AnnotationIndex, exptypes.AnnotationIndexDescriptor, exptypes.AnnotationManifest, exptypes.AnnotationManifestDescriptor:
   101  		default:
   102  			return nil, errors.Errorf("unknown annotation type %q", typ)
   103  		}
   104  
   105  		var ociPlatform *ocispecs.Platform
   106  		if platform != "" {
   107  			p, err := platforms.Parse(platform)
   108  			if err != nil {
   109  				return nil, errors.Wrapf(err, "invalid platform %q", platform)
   110  			}
   111  			ociPlatform = &p
   112  		}
   113  
   114  		ak := exptypes.AnnotationKey{
   115  			Type:     typ,
   116  			Platform: ociPlatform,
   117  			Key:      key,
   118  		}
   119  		annotations[ak] = v
   120  	}
   121  	return annotations, nil
   122  }