func processImportValues(c *chart.Chart) error {
	reqs, err := LoadRequirements(c)
	if err != nil {
		return err
	}
	cvals, err := CoalesceValues(c, &chart.Config{})
	if err != nil {
		return err
	}
	b := cvals.AsMap()
	for _, r := range reqs.Dependencies {
		found := false
		name := r.Name
		for _, v := range c.Dependencies {
			if v.Metadata.Name == r.Name {
				found = true
			}
			if v.Metadata.Name == r.Alias {
				found = true
				name = r.Alias
			}
		}
		if !found {
			continue
		}
		if len(r.ImportValues) > 0 {
			var outiv []interface{}
			for _, riv := range r.ImportValues {
				switch iv := riv.(type) {
				case map[string]interface{}:
					nm := map[string]string{
						"child":  iv["child"].(string),
						"parent": iv["parent"].(string),
					}
					outiv = append(outiv, nm)
					s := name + "." + nm["child"]
					vv, err := cvals.Table(s)
					if err != nil {
						log.Printf("Warning: ImportValues missing table: %v", err)
						continue
					}
					vm := pathToMap(nm["parent"], vv.AsMap())
					b = coalesceTables(b, vm, c.Metadata.Name)
				case string:
					nm := map[string]string{
						"child":  "exports." + iv,
						"parent": ".",
					}
					outiv = append(outiv, nm)
					s := name + "." + nm["child"]
					vm, err := cvals.Table(s)
					if err != nil {
						log.Printf("Warning: ImportValues missing table: %v", err)
						continue
					}
					b = coalesceTables(b, vm.AsMap(), c.Metadata.Name)
				}
			}
			r.ImportValues = outiv
		}
	}
	y, err := yaml.Marshal(b)
	if err != nil {
		return err
	}
	c.Values = &chart.Config{Raw: string(y)}
	return nil
}
processImportValues merges values from child to parent based on the chart's dependencies' ImportValues field.
package chartutil
import (
	"errors"
	"log"
	"strings"
	"time"
	"github.com/ghodss/yaml"
	"k8s.io/helm/pkg/proto/hapi/chart"
	"k8s.io/helm/pkg/version"
)
const (
	requirementsName = "requirements.yaml"
	lockfileName     = "requirements.lock"
)
var (
	ErrRequirementsNotFound = errors.New(requirementsName + " not found")
	ErrLockfileNotFound = errors.New(lockfileName + " not found")
)
type Dependency struct {
	Name string `json:"name"`
	Version string `json:"version,omitempty"`
	Repository string `json:"repository"`
	Condition string `json:"condition,omitempty"`
	Tags []string `json:"tags,omitempty"`
	Enabled bool `json:"enabled,omitempty"`
	ImportValues []interface{} `json:"import-values,omitempty"`
	Alias string `json:"alias,omitempty"`
}
type ErrNoRequirementsFile error
type Requirements struct {
	Dependencies []*Dependency `json:"dependencies"`
}
type RequirementsLock struct {
	Generated time.Time `json:"generated"`
	Digest string `json:"digest"`
	Dependencies []*Dependency `json:"dependencies"`
}
func LoadRequirements(c *chart.Chart) (*Requirements, error) {
	var data []byte
	for _, f := range c.Files {
		if f.TypeUrl == requirementsName {
			data = f.Value
		}
	}
	if len(data) == 0 {
		return nil, ErrRequirementsNotFound
	}
	r := &Requirements{}
	return r, yaml.Unmarshal(data, r)
}
func LoadRequirementsLock(c *chart.Chart) (*RequirementsLock, error) {
	var data []byte
	for _, f := range c.Files {
		if f.TypeUrl == lockfileName {
			data = f.Value
		}
	}
	if len(data) == 0 {
		return nil, ErrLockfileNotFound
	}
	r := &RequirementsLock{}
	return r, yaml.Unmarshal(data, r)
}
func ProcessRequirementsConditions(reqs *Requirements, cvals Values, cpath string) {
	var cond string
	var conds []string
	if reqs == nil || len(reqs.Dependencies) == 0 {
		return
	}
	for _, r := range reqs.Dependencies {
		var hasTrue, hasFalse bool
		cond = string(r.Condition)
		if len(cond) > 0 {
			if strings.Contains(cond, ",") {
				conds = strings.Split(strings.TrimSpace(cond), ",")
			} else {
				conds = []string{strings.TrimSpace(cond)}
			}
			for _, c := range conds {
				if len(c) > 0 {
					vv, err := cvals.PathValue(cpath + c)
					if err == nil {
						if bv, ok := vv.(bool); ok {
							if bv {
								hasTrue = true
							} else {
								hasFalse = true
							}
						} else {
							log.Printf("Warning: Condition path '%s' for chart %s returned non-bool value", c, r.Name)
						}
					} else if _, ok := err.(ErrNoValue); !ok {
						log.Printf("Warning: PathValue returned error %v", err)
					}
					if vv != nil {
						break
					}
				}
			}
			if !hasTrue && hasFalse {
				r.Enabled = false
			} else if hasTrue {
				r.Enabled = true
			}
		}
	}
}
func ProcessRequirementsTags(reqs *Requirements, cvals Values) {
	vt, err := cvals.Table("tags")
	if err != nil {
		return
	}
	if reqs == nil || len(reqs.Dependencies) == 0 {
		return
	}
	for _, r := range reqs.Dependencies {
		if len(r.Tags) > 0 {
			tags := r.Tags
			var hasTrue, hasFalse bool
			for _, k := range tags {
				if b, ok := vt[k]; ok {
					if bv, ok := b.(bool); ok {
						if bv {
							hasTrue = true
						} else {
							hasFalse = true
						}
					} else {
						log.Printf("Warning: Tag '%s' for chart %s returned non-bool value", k, r.Name)
					}
				}
			}
			if !hasTrue && hasFalse {
				r.Enabled = false
			} else if hasTrue || !hasTrue && !hasFalse {
				r.Enabled = true
			}
		}
	}
}
func getAliasDependency(charts []*chart.Chart, aliasChart *Dependency) *chart.Chart {
	var chartFound chart.Chart
	for _, existingChart := range charts {
		if existingChart == nil {
			continue
		}
		if existingChart.Metadata == nil {
			continue
		}
		if existingChart.Metadata.Name != aliasChart.Name {
			continue
		}
		if !version.IsCompatibleRange(aliasChart.Version, existingChart.Metadata.Version) {
			continue
		}
		chartFound = *existingChart
		newMetadata := *existingChart.Metadata
		if aliasChart.Alias != "" {
			newMetadata.Name = aliasChart.Alias
		}
		chartFound.Metadata = &newMetadata
		return &chartFound
	}
	return nil
}
func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error {
	return doProcessRequirementsEnabled(c, v, "")
}
func doProcessRequirementsEnabled(c *chart.Chart, v *chart.Config, path string) error {
	reqs, err := LoadRequirements(c)
	if err != nil {
		if nerr, ok := err.(ErrNoRequirementsFile); !ok {
			return nerr
		}
		return nil
	}
	var chartDependencies []*chart.Chart
	for _, existingDependency := range c.Dependencies {
		var dependencyFound bool
		for _, req := range reqs.Dependencies {
			if existingDependency.Metadata.Name == req.Name && version.IsCompatibleRange(req.Version, existingDependency.Metadata.Version) {
				dependencyFound = true
				break
			}
		}
		if !dependencyFound {
			chartDependencies = append(chartDependencies, existingDependency)
		}
	}
	for _, req := range reqs.Dependencies {
		if chartDependency := getAliasDependency(c.Dependencies, req); chartDependency != nil {
			chartDependencies = append(chartDependencies, chartDependency)
		}
		if req.Alias != "" {
			req.Name = req.Alias
		}
	}
	c.Dependencies = chartDependencies
	for _, lr := range reqs.Dependencies {
		lr.Enabled = true
	}
	cvals, err := CoalesceValues(c, v)
	if err != nil {
		return err
	}
	yvals, err := cvals.YAML()
	if err != nil {
		return err
	}
	cc := chart.Config{Raw: yvals}
	ProcessRequirementsTags(reqs, cvals)
	ProcessRequirementsConditions(reqs, cvals, path)
	rm := map[string]bool{}
	for _, r := range reqs.Dependencies {
		if !r.Enabled {
			rm[r.Name] = true
		}
	}
	cd := []*chart.Chart{}
	copy(cd, c.Dependencies[:0])
	for _, n := range c.Dependencies {
		if _, ok := rm[n.Metadata.Name]; !ok {
			cd = append(cd, n)
		}
	}
	for _, t := range cd {
		subpath := path + t.Metadata.Name + "."
		err := doProcessRequirementsEnabled(t, &cc, subpath)
		if nerr, ok := err.(ErrNoRequirementsFile); !ok && err != nil {
			return nerr
		}
	}
	c.Dependencies = cd
	return nil
}
func pathToMap(path string, data map[string]interface{}) map[string]interface{} {
	if path == "." {
		return data
	}
	ap := strings.Split(path, ".")
	if len(ap) == 0 {
		return nil
	}
	n := []map[string]interface{}{}
	for _, v := range ap {
		nm := make(map[string]interface{})
		nm[v] = make(map[string]interface{})
		n = append(n, nm)
	}
	for i, d := range n {
		for k := range d {
			z := i + 1
			if z == len(n) {
				n[i][k] = data
				break
			}
			n[i][k] = n[z]
		}
	}
	return n[0]
}
func getParents(c *chart.Chart, out []*chart.Chart) []*chart.Chart {
	if len(out) == 0 {
		out = []*chart.Chart{c}
	}
	for _, ch := range c.Dependencies {
		if len(ch.Dependencies) > 0 {
			out = append(out, ch)
			out = getParents(ch, out)
		}
	}
	return out
}