func Symlink(name, target string) TarEntry {
	return tarEntryFunc(func(tw *tar.Writer, buildOpts BuildTarOptions) error {
		return tw.WriteHeader(&tar.Header{
			Typeflag: tar.TypeSymlink,
			Name:     buildOpts.Prefix + name,
			Linkname: target,
			Mode:     0644,
		})
	})
}
Symlink is a symlink entry
package testutil
import (
	"archive/tar"
	"fmt"
	"io"
	"os"
	"strings"
	"time"
)
type TarEntry interface {
	AppendTar(tw *tar.Writer, opts BuildTarOptions) error
}
type BuildTarOptions struct {
	Prefix string
}
type BuildTarOption func(o *BuildTarOptions)
func WithPrefix(prefix string) BuildTarOption {
	return func(o *BuildTarOptions) {
		o.Prefix = prefix
	}
}
func BuildTar(ents []TarEntry, opts ...BuildTarOption) io.Reader {
	var bo BuildTarOptions
	for _, o := range opts {
		o(&bo)
	}
	pr, pw := io.Pipe()
	go func() {
		tw := tar.NewWriter(pw)
		for _, ent := range ents {
			if err := ent.AppendTar(tw, bo); err != nil {
				pw.CloseWithError(err)
				return
			}
		}
		if err := tw.Close(); err != nil {
			pw.CloseWithError(err)
			return
		}
		pw.Close()
	}()
	return pr
}
type tarEntryFunc func(*tar.Writer, BuildTarOptions) error
func (f tarEntryFunc) AppendTar(tw *tar.Writer, opts BuildTarOptions) error { return f(tw, opts) }
type DirectoryBuildTarOption func(o *dirOpts)
type dirOpts struct {
	uid     int
	gid     int
	xattrs  map[string]string
	mode    *os.FileMode
	modTime time.Time
}
func WithDirModTime(modTime time.Time) DirectoryBuildTarOption {
	return func(o *dirOpts) {
		o.modTime = modTime
	}
}
func WithDirOwner(uid, gid int) DirectoryBuildTarOption {
	return func(o *dirOpts) {
		o.uid = uid
		o.gid = gid
	}
}
func WithDirXattrs(xattrs map[string]string) DirectoryBuildTarOption {
	return func(o *dirOpts) {
		o.xattrs = xattrs
	}
}
func WithDirMode(mode os.FileMode) DirectoryBuildTarOption {
	return func(o *dirOpts) {
		o.mode = &mode
	}
}
func Dir(name string, opts ...DirectoryBuildTarOption) TarEntry {
	return tarEntryFunc(func(tw *tar.Writer, buildOpts BuildTarOptions) error {
		var dOpts dirOpts
		for _, o := range opts {
			o(&dOpts)
		}
		if !strings.HasSuffix(name, "/") {
			panic(fmt.Sprintf("missing trailing slash in dir %q ", name))
		}
		var mode int64 = 0755
		if dOpts.mode != nil {
			mode = permAndExtraMode2TarMode(*dOpts.mode)
		}
		return tw.WriteHeader(&tar.Header{
			Typeflag: tar.TypeDir,
			Name:     buildOpts.Prefix + name,
			Mode:     mode,
			ModTime:  dOpts.modTime,
			Xattrs:   dOpts.xattrs,
			Uid:      dOpts.uid,
			Gid:      dOpts.gid,
		})
	})
}
type FileBuildTarOption func(o *fileOpts)
type fileOpts struct {
	uid     int
	gid     int
	xattrs  map[string]string
	mode    *os.FileMode
	modTime time.Time
}
func WithFileOwner(uid, gid int) FileBuildTarOption {
	return func(o *fileOpts) {
		o.uid = uid
		o.gid = gid
	}
}
func WithFileXattrs(xattrs map[string]string) FileBuildTarOption {
	return func(o *fileOpts) {
		o.xattrs = xattrs
	}
}
func WithFileModTime(modTime time.Time) FileBuildTarOption {
	return func(o *fileOpts) {
		o.modTime = modTime
	}
}
func WithFileMode(mode os.FileMode) FileBuildTarOption {
	return func(o *fileOpts) {
		o.mode = &mode
	}
}
func File(name, contents string, opts ...FileBuildTarOption) TarEntry {
	return tarEntryFunc(func(tw *tar.Writer, buildOpts BuildTarOptions) error {
		var fOpts fileOpts
		for _, o := range opts {
			o(&fOpts)
		}
		if strings.HasSuffix(name, "/") {
			return fmt.Errorf("bogus trailing slash in file %q", name)
		}
		var mode int64 = 0644
		if fOpts.mode != nil {
			mode = permAndExtraMode2TarMode(*fOpts.mode)
		}
		if err := tw.WriteHeader(&tar.Header{
			Typeflag: tar.TypeReg,
			Name:     buildOpts.Prefix + name,
			Mode:     mode,
			ModTime:  fOpts.modTime,
			Xattrs:   fOpts.xattrs,
			Size:     int64(len(contents)),
			Uid:      fOpts.uid,
			Gid:      fOpts.gid,
		}); err != nil {
			return err
		}
		_, err := io.WriteString(tw, contents)
		return err
	})
}