2021-04-09 14:20:26 +08:00
|
|
|
package buildflags
|
2019-03-24 12:30:29 +08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
|
2023-02-09 20:03:58 +08:00
|
|
|
controllerapi "github.com/docker/buildx/controller/pb"
|
2019-03-24 12:30:29 +08:00
|
|
|
"github.com/pkg/errors"
|
2024-06-28 11:31:23 +08:00
|
|
|
"github.com/tonistiigi/go-csvvalue"
|
2019-03-24 12:30:29 +08:00
|
|
|
)
|
|
|
|
|
2024-11-22 02:06:14 +08:00
|
|
|
type Secret struct {
|
|
|
|
ID string `json:"id,omitempty"`
|
|
|
|
FilePath string `json:"src,omitempty"`
|
|
|
|
Env string `json:"env,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Secret) Equal(other *Secret) bool {
|
|
|
|
return s.ID == other.ID && s.FilePath == other.FilePath && s.Env == other.Env
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Secret) String() string {
|
|
|
|
var b csvBuilder
|
|
|
|
if s.ID != "" {
|
|
|
|
b.Write("id", s.ID)
|
2019-03-24 12:30:29 +08:00
|
|
|
}
|
2024-11-22 02:06:14 +08:00
|
|
|
if s.FilePath != "" {
|
|
|
|
b.Write("src", s.FilePath)
|
|
|
|
}
|
|
|
|
if s.Env != "" {
|
|
|
|
b.Write("env", s.Env)
|
|
|
|
}
|
|
|
|
return b.String()
|
2019-03-24 12:30:29 +08:00
|
|
|
}
|
|
|
|
|
2024-11-22 02:06:14 +08:00
|
|
|
func (s *Secret) ToPB() *controllerapi.Secret {
|
|
|
|
return &controllerapi.Secret{
|
|
|
|
ID: s.ID,
|
|
|
|
FilePath: s.FilePath,
|
|
|
|
Env: s.Env,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Secret) UnmarshalText(text []byte) error {
|
|
|
|
value := string(text)
|
2024-06-28 11:31:23 +08:00
|
|
|
fields, err := csvvalue.Fields(value, nil)
|
2019-03-24 12:30:29 +08:00
|
|
|
if err != nil {
|
2024-11-22 02:06:14 +08:00
|
|
|
return errors.Wrap(err, "failed to parse csv secret")
|
2019-03-24 12:30:29 +08:00
|
|
|
}
|
|
|
|
|
2024-11-22 02:06:14 +08:00
|
|
|
*s = Secret{}
|
2019-03-24 12:30:29 +08:00
|
|
|
|
2020-12-19 11:18:51 +08:00
|
|
|
var typ string
|
2019-03-24 12:30:29 +08:00
|
|
|
for _, field := range fields {
|
|
|
|
parts := strings.SplitN(field, "=", 2)
|
|
|
|
key := strings.ToLower(parts[0])
|
|
|
|
|
|
|
|
if len(parts) != 2 {
|
2024-11-22 02:06:14 +08:00
|
|
|
return errors.Errorf("invalid field '%s' must be a key=value pair", field)
|
2019-03-24 12:30:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
value := parts[1]
|
|
|
|
switch key {
|
|
|
|
case "type":
|
2020-12-19 11:18:51 +08:00
|
|
|
if value != "file" && value != "env" {
|
2024-11-22 02:06:14 +08:00
|
|
|
return errors.Errorf("unsupported secret type %q", value)
|
2019-03-24 12:30:29 +08:00
|
|
|
}
|
2020-12-19 11:18:51 +08:00
|
|
|
typ = value
|
2019-03-24 12:30:29 +08:00
|
|
|
case "id":
|
2024-11-22 02:06:14 +08:00
|
|
|
s.ID = value
|
2019-03-24 12:30:29 +08:00
|
|
|
case "source", "src":
|
2024-11-22 02:06:14 +08:00
|
|
|
s.FilePath = value
|
2020-12-19 11:18:51 +08:00
|
|
|
case "env":
|
2024-11-22 02:06:14 +08:00
|
|
|
s.Env = value
|
2019-03-24 12:30:29 +08:00
|
|
|
default:
|
2024-11-22 02:06:14 +08:00
|
|
|
return errors.Errorf("unexpected key '%s' in '%s'", key, field)
|
2019-03-24 12:30:29 +08:00
|
|
|
}
|
|
|
|
}
|
2024-11-22 02:06:14 +08:00
|
|
|
if typ == "env" && s.Env == "" {
|
|
|
|
s.Env = s.FilePath
|
|
|
|
s.FilePath = ""
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ParseSecretSpecs(sl []string) ([]*controllerapi.Secret, error) {
|
|
|
|
fs := make([]*controllerapi.Secret, 0, len(sl))
|
|
|
|
for _, v := range sl {
|
|
|
|
s, err := parseSecret(v)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fs = append(fs, s)
|
|
|
|
}
|
|
|
|
return fs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseSecret(value string) (*controllerapi.Secret, error) {
|
|
|
|
var s Secret
|
|
|
|
if err := s.UnmarshalText([]byte(value)); err != nil {
|
|
|
|
return nil, err
|
2020-12-19 11:18:51 +08:00
|
|
|
}
|
2024-11-22 02:06:14 +08:00
|
|
|
return s.ToPB(), nil
|
2019-03-24 12:30:29 +08:00
|
|
|
}
|