files.go (136 lines of code) (raw):
package dalec
import (
goerrors "errors"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/moby/buildkit/client/llb"
"github.com/pkg/errors"
)
const (
defaultFilePerms = 0o644
defaultDirPerms = 0o755
)
func (d *SourceInlineDir) PopulateAt(p string) llb.StateOption {
return func(st llb.State) llb.State {
perms := d.Permissions.Perm()
if perms == 0 {
perms = defaultDirPerms
}
st = st.File(llb.Mkdir(p, perms, llb.WithUIDGID(int(d.UID), int(d.GID))))
sorted := SortMapKeys(d.Files)
for _, k := range sorted {
f := d.Files[k]
st = st.With(f.PopulateAt(filepath.Join(p, k)))
}
return st
}
}
func (f *SourceInlineFile) PopulateAt(p string) llb.StateOption {
return func(st llb.State) llb.State {
perms := f.Permissions.Perm()
if perms == 0 {
perms = defaultFilePerms
}
return st.File(
llb.Mkfile(p, perms, []byte(f.Contents), llb.WithUIDGID(int(f.UID), int(f.GID))),
)
}
}
func (s *SourceInline) validate(subpath string) (retErr error) {
var errs []error
if s.File == nil && s.Dir == nil {
errs = append(errs, errors.New("inline source is missing contents to inline"))
}
if s.File != nil && s.Dir != nil {
errs = append(errs, errors.New("inline source variant cannot have both a file and dir set"))
}
if s.Dir != nil {
if err := s.Dir.validate(); err != nil {
errs = append(errs, err)
}
}
if s.File != nil {
if subpath != "" {
errs = append(errs, errors.New("inline file source cannot have a path set"))
}
if err := s.File.validate(); err != nil {
errs = append(errs, err)
}
}
return goerrors.Join(errs...)
}
func (s *SourceInlineDir) validate() error {
var errs []error
if s.UID < 0 {
errs = append(errs, errors.Errorf("uid %d must be non-negative", s.UID))
}
if s.GID < 0 {
errs = append(errs, errors.Errorf("gid %d must be non-negative", s.GID))
}
for k, f := range s.Files {
if strings.ContainsRune(k, os.PathSeparator) {
errs = append(errs, errors.Wrapf(sourceNamePathSeparatorError, "file %q", k))
}
if err := f.validate(); err != nil {
errs = append(errs, errors.Wrapf(err, "file %q", k))
}
}
return goerrors.Join(errs...)
}
func (s *SourceInlineFile) validate() error {
var errs []error
if s.UID < 0 {
errs = append(errs, errors.Errorf("uid %d must be non-negative", s.UID))
}
if s.GID < 0 {
errs = append(errs, errors.Errorf("gid %d must be non-negative", s.GID))
}
return goerrors.Join(errs...)
}
func (s *SourceInline) Doc(w io.Writer, name string) {
if s.File != nil {
s.File.Doc(w, name)
}
if s.Dir != nil {
s.Dir.Doc(w, name)
}
}
func (s *SourceInlineFile) Doc(w io.Writer, name string) {
fmt.Fprintln(w, ` cat << EOF > `+name+`
`+s.Contents+`
EOF`)
if s.UID != 0 {
fmt.Fprintln(w, ` chown `+strconv.Itoa(s.UID)+" "+name)
}
if s.GID != 0 {
fmt.Fprintln(w, ` chgrp `+strconv.Itoa(s.GID)+" "+name)
}
perms := s.Permissions.Perm()
if perms == 0 {
perms = 0o644
}
fmt.Fprintf(w, " chmod %o %s\n", perms.Perm(), name)
}
func (s *SourceInlineDir) Doc(w io.Writer, name string) {
fmt.Fprintln(w, ` mkdir -p `+name)
if s.UID != 0 {
fmt.Fprintln(w, ` chown `+strconv.Itoa(s.UID)+" "+name)
}
if s.GID != 0 {
fmt.Fprintln(w, ` chgrp `+strconv.Itoa(s.GID)+" "+name)
}
perms := s.Permissions.Perm()
if perms == 0 {
perms = 0o644
}
sorted := SortMapKeys(s.Files)
for _, k := range sorted {
v := s.Files[k]
v.Doc(w, filepath.Join(name, k))
}
fmt.Fprintf(w, " chmod %o %s\n", perms.Perm(), name)
}