func softDecrypt(rawData []byte) ([]byte, error) {
	decryptedData, err := decrypt.Data(rawData, "yaml")
	if err == sops.MetadataNotFound {
		return rawData, nil
	} else if err != nil {
		return rawData, errors.Wrap(err, "failed to decrypt file")
	}
	return decryptedData, nil
}
softDecrypt takes data from a file and tries to decrypt it with sops,
if the file has not been encrypted with sops, the original data will be returned
package resource
import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"github.com/pkg/errors"
	"go.mozilla.org/sops/v3"
	"go.mozilla.org/sops/v3/decrypt"
	"gopkg.in/yaml.v2"
)
func Load(base string, paths []string, sopsEnabled bool) (map[string]KubeManifest, error) {
	if _, err := os.Stat(base); os.IsNotExist(err) {
		return nil, fmt.Errorf("git path %q not found", base)
	}
	objs := map[string]KubeManifest{}
	charts, err := newChartTracker(base)
	if err != nil {
		return nil, errors.Wrapf(err, "walking %q for chartdirs", base)
	}
	for _, root := range paths {
		if _, err := os.Stat(root); err != nil {
			return nil, errors.Wrapf(err, "unable to read root path %q", root)
		}
		err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
			if err == nil && info.IsDir() {
				if charts.isDirChart(path) {
					return filepath.SkipDir
				}
				return nil
			}
			if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" {
				return nil
			}
			if charts.isPathInChart(path) {
				return nil
			}
			if err != nil {
				return errors.Wrapf(err, "walking file %q for yaml docs", path)
			}
			bytes, err := loadFile(path, sopsEnabled)
			if err != nil {
				return errors.Wrapf(err, "unable to read file at %q", path)
			}
			source, err := filepath.Rel(base, path)
			if err != nil {
				return errors.Wrapf(err, "path to scan %q is not under base %q", path, base)
			}
			docsInFile, err := ParseMultidoc(bytes, source)
			if err != nil {
				return err
			}
			for id, obj := range docsInFile {
				if alreadyDefined, ok := objs[id]; ok {
					return fmt.Errorf(`duplicate definition of '%s' (in %s and %s)`, id, alreadyDefined.Source(), source)
				}
				objs[id] = obj
			}
			return nil
		})
		if err != nil {
			return objs, err
		}
	}
	return objs, nil
}
type chartTracker map[string]bool
func newChartTracker(root string) (chartTracker, error) {
	chartdirs := make(chartTracker)
	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return nil
		}
		if info.IsDir() && looksLikeChart(path) {
			chartdirs[path] = true
			return filepath.SkipDir
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return chartdirs, nil
}
func (c chartTracker) isDirChart(path string) bool {
	return c[path]
}
func (c chartTracker) isPathInChart(path string) bool {
	p := path
	root := fmt.Sprintf("%c", filepath.Separator)
	for p != root {
		if c[p] {
			return true
		}
		p = filepath.Dir(p)
	}
	return false
}
func looksLikeChart(dir string) bool {
	chartpath := filepath.Join(dir, "Chart.yaml")
	valuespath := filepath.Join(dir, "values.yaml")
	if _, err := os.Stat(chartpath); err != nil && os.IsNotExist(err) {
		return false
	}
	if _, err := os.Stat(valuespath); err != nil && os.IsNotExist(err) {
		return false
	}
	return true
}
func ParseMultidoc(multidoc []byte, source string) (map[string]KubeManifest, error) {
	objs := map[string]KubeManifest{}
	decoder := yaml.NewDecoder(bytes.NewReader(multidoc))
	var obj KubeManifest
	var err error
	for {
		var val interface{}
		if err = decoder.Decode(&val); err != nil {
			break
		}
		bytes, err := yaml.Marshal(val)
		if err != nil {
			return nil, errors.Wrapf(err, "parsing YAML doc from %q", source)
		}
		if obj, err = unmarshalObject(source, bytes); err != nil {
			return nil, errors.Wrapf(err, "parsing YAML doc from %q", source)
		}
		if obj == nil {
			continue
		}
		if list, ok := obj.(*List); ok {
			for _, item := range list.Items {
				id := item.ResourceID().String()
				if _, ok := objs[id]; ok {
					return nil, fmt.Errorf(`duplicate definition of '%s' (in %s)`, id, source)
				}
				objs[id] = item
			}
		} else {
			id := obj.ResourceID().String()
			if _, ok := objs[id]; ok {
				return nil, fmt.Errorf(`duplicate definition of '%s' (in %s)`, id, source)
			}
			objs[id] = obj
		}
	}
	if err != io.EOF {
		return objs, errors.Wrapf(err, "scanning multidoc from %q", source)
	}
	return objs, nil
}
func loadFile(path string, sopsEnabled bool) ([]byte, error) {
	fileBytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	if sopsEnabled && bytes.Contains(fileBytes, []byte("sops:")) {
		return softDecrypt(fileBytes)
	}
	return fileBytes, nil
}