mirror of https://github.com/kubernetes/kops.git
221 lines
4.0 KiB
Go
221 lines
4.0 KiB
Go
package fi
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"k8s.io/kops/util/pkg/vfs"
|
|
"os"
|
|
)
|
|
|
|
type Resource interface {
|
|
Open() (io.Reader, error)
|
|
}
|
|
|
|
type TemplateResource interface {
|
|
Resource
|
|
Curry(args []string) TemplateResource
|
|
}
|
|
|
|
func ResourcesMatch(a, b Resource) (bool, error) {
|
|
aReader, err := a.Open()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer SafeClose(aReader)
|
|
|
|
bReader, err := b.Open()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer SafeClose(bReader)
|
|
|
|
const size = 8192
|
|
aData := make([]byte, size)
|
|
bData := make([]byte, size)
|
|
|
|
for {
|
|
aN, aErr := io.ReadFull(aReader, aData)
|
|
if aErr != nil && aErr != io.EOF && aErr != io.ErrUnexpectedEOF {
|
|
return false, aErr
|
|
}
|
|
|
|
bN, bErr := io.ReadFull(bReader, bData)
|
|
if bErr != nil && bErr != io.EOF && bErr != io.ErrUnexpectedEOF {
|
|
return false, bErr
|
|
}
|
|
|
|
if aErr == nil && bErr == nil {
|
|
if aN != size || bN != size {
|
|
panic("violation of io.ReadFull contract")
|
|
}
|
|
if !bytes.Equal(aData, bData) {
|
|
return false, nil
|
|
}
|
|
continue
|
|
}
|
|
|
|
if aN != bN {
|
|
return false, nil
|
|
}
|
|
|
|
return bytes.Equal(aData[0:aN], bData[0:bN]), nil
|
|
}
|
|
}
|
|
|
|
func CopyResource(dest io.Writer, r Resource) (int64, error) {
|
|
in, err := r.Open()
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return 0, err
|
|
}
|
|
return 0, fmt.Errorf("error opening resource: %v", err)
|
|
}
|
|
defer SafeClose(in)
|
|
|
|
n, err := io.Copy(dest, in)
|
|
if err != nil {
|
|
return n, fmt.Errorf("error copying resource: %v", err)
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func ResourceAsString(r Resource) (string, error) {
|
|
buf := new(bytes.Buffer)
|
|
_, err := CopyResource(buf, r)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
func ResourceAsBytes(r Resource) ([]byte, error) {
|
|
buf := new(bytes.Buffer)
|
|
_, err := CopyResource(buf, r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
type StringResource struct {
|
|
s string
|
|
}
|
|
|
|
var _ Resource = &StringResource{}
|
|
|
|
func NewStringResource(s string) *StringResource {
|
|
return &StringResource{s: s}
|
|
}
|
|
|
|
func (s *StringResource) Open() (io.Reader, error) {
|
|
r := bytes.NewReader([]byte(s.s))
|
|
return r, nil
|
|
}
|
|
|
|
func (s *StringResource) WriteTo(out io.Writer) error {
|
|
_, err := out.Write([]byte(s.s))
|
|
return err
|
|
}
|
|
|
|
type BytesResource struct {
|
|
data []byte
|
|
}
|
|
|
|
var _ Resource = &BytesResource{}
|
|
|
|
func NewBytesResource(data []byte) *BytesResource {
|
|
return &BytesResource{data: data}
|
|
}
|
|
|
|
func (r *BytesResource) Open() (io.Reader, error) {
|
|
reader := bytes.NewReader([]byte(r.data))
|
|
return reader, nil
|
|
}
|
|
|
|
type FileResource struct {
|
|
Path string
|
|
}
|
|
|
|
var _ Resource = &FileResource{}
|
|
|
|
func NewFileResource(path string) *FileResource {
|
|
return &FileResource{Path: path}
|
|
}
|
|
|
|
func (r *FileResource) Open() (io.Reader, error) {
|
|
in, err := os.Open(r.Path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, err
|
|
}
|
|
return nil, fmt.Errorf("error opening file %q: %v", r.Path, err)
|
|
}
|
|
return in, err
|
|
}
|
|
|
|
type VFSResource struct {
|
|
Path vfs.Path
|
|
}
|
|
|
|
var _ Resource = &VFSResource{}
|
|
|
|
func NewVFSResource(path vfs.Path) *VFSResource {
|
|
return &VFSResource{Path: path}
|
|
}
|
|
|
|
func (r *VFSResource) Open() (io.Reader, error) {
|
|
data, err := r.Path.ReadFile()
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, err
|
|
}
|
|
return nil, fmt.Errorf("error opening file %q: %v", r.Path, err)
|
|
}
|
|
b := bytes.NewBuffer(data)
|
|
return b, err
|
|
}
|
|
|
|
type ResourceHolder struct {
|
|
Name string
|
|
Resource Resource
|
|
}
|
|
|
|
var _ Resource = &ResourceHolder{}
|
|
|
|
func (o *ResourceHolder) Open() (io.Reader, error) {
|
|
if o.Resource == nil {
|
|
return nil, fmt.Errorf("ResourceHolder %q is not bound", o.Name)
|
|
}
|
|
return o.Resource.Open()
|
|
}
|
|
|
|
func (o *ResourceHolder) UnmarshalJSON(data []byte) error {
|
|
var jsonName string
|
|
err := json.Unmarshal(data, &jsonName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
o.Name = jsonName
|
|
return nil
|
|
}
|
|
|
|
func (o *ResourceHolder) Unwrap() Resource {
|
|
return o.Resource
|
|
}
|
|
|
|
func (o *ResourceHolder) AsString() (string, error) {
|
|
return ResourceAsString(o.Unwrap())
|
|
}
|
|
|
|
func (o *ResourceHolder) AsBytes() ([]byte, error) {
|
|
return ResourceAsBytes(o.Unwrap())
|
|
}
|
|
|
|
func WrapResource(r Resource) *ResourceHolder {
|
|
return &ResourceHolder{
|
|
Resource: r,
|
|
}
|
|
}
|