func ReadAndMergeBundleData(sources ...BundleDataSource) (*BundleData, error) {
	var allParts []*BundleDataPart
	var partSrcIndex []int
	for srcIndex, src := range sources {
		if src == nil {
			continue
		}

		for _, part := range src.Parts() {
			allParts = append(allParts, part)
			partSrcIndex = append(partSrcIndex, srcIndex)
		}
	}

	if len(allParts) == 0 {
		return nil, errors.NotValidf("malformed bundle: bundle is empty")
	}

	// Treat the first part as the base bundle
	base := allParts[0]
	if err := VerifyNoOverlayFieldsPresent(base.Data); err != nil {
		return nil, errors.Trace(err)
	}

	// Merge parts and resolve include directives
	for index, part := range allParts {
		// Resolve any re-writing of normalisation that could cause the presence
		// field to be out of sync with the actual bundle representation.
		resolveOverlayPresenceFields(part)

		if index != 0 {
			if err := applyOverlay(base, part); err != nil {
				return nil, errors.Trace(err)
			}
		}

		// Relative include directives are resolved using the base path
		// of the datasource that yielded this part
		srcIndex := partSrcIndex[index]
		incResolver := sources[srcIndex].ResolveInclude
		basePath := sources[srcIndex].BasePath()
		for app, appData := range base.Data.Applications {
			if appData == nil {
				return nil, errors.Errorf("base application %q has no body", app)
			}
			resolvedCharm, err := resolveRelativeCharmPath(basePath, appData.Charm)
			if err != nil {
				return nil, errors.Annotatef(err, "resolving relative charm path %q for application %q", appData.Charm, app)
			}
			appData.Charm = resolvedCharm

			for k, v := range appData.Options {
				newV, changed, err := resolveIncludes(incResolver, v)
				if err != nil {
					return nil, errors.Annotatef(err, "processing option %q for application %q", k, app)
				}
				if changed {
					appData.Options[k] = newV
				}
			}

			for k, v := range appData.Annotations {
				newV, changed, err := resolveIncludes(incResolver, v)
				if err != nil {
					return nil, errors.Annotatef(err, "processing annotation %q for application %q", k, app)
				}
				if changed {
					appData.Annotations[k] = newV
				}
			}
		}

		for machine, machineData := range base.Data.Machines {
			if machineData == nil {
				continue
			}

			for k, v := range machineData.Annotations {
				newV, changed, err := resolveIncludes(incResolver, v)
				if err != nil {
					return nil, errors.Annotatef(err, "processing annotation %q for machine %q", k, machine)
				}
				if changed {
					machineData.Annotations[k] = newV
				}
			}
		}
	}

	return base.Data, nil
}
// ReadAndMergeBundleData reads N bundle data sources, composes their contents
// together and returns the result. The first bundle data source is treated as
// a base bundle while subsequent bundle data sources are treated as overlays
// which are sequentially merged onto the base bundle.
//
// Before returning the merged bundle, ReadAndMergeBundleData will also attempt
// to resolve any include directives present in the machine annotations,
// application options and annotations.
//
// When merging an overlay into a base bundle the following rules apply for the
// BundleData struct fields:
// - if an overlay specifies a bundle-level series, it overrides the base bundle
//   series.
// - overlay-defined relations are appended to the base bundle relations
// - overlay-defined machines overwrite the base bundle machines.
// - if an overlay defines an application that is not present in the base bundle,
//   it will get appended to the application list.
// - if an overlay defines an empty application or saas value, it will be removed
//   from the base bundle together with any associated relations. For example, to
//   remove an application named "mysql" the following overlay snippet can be
//   provided:
//     applications:
//       mysql:
//
// - if an overlay defines an application that is also present in the base bundle
//   the two application specs are merged together (see following rules)
//
// ApplicationSpec merge rules:
// - if the overlay defines a value for a scalar or slice field, it will overwrite
//   the value from the base spec (e.g. trust, series etc).
// - if the overlay specifies a nil/empty value for a map field, then the map
//   field of the base spec will be cleared.
// - if the overlay specifies a non-empty value for a map field, its key/value
//   tuples are iterated and:
//   - if the value is nil/zero and the value is non-scalar, it is deleted from
//     the base spec.
//   - otherwise, the key/value is inserted into the base spec overwriting any
//     existing entries.
ReadAndMergeBundleData reads N bundle data sources, composes their contents
together and returns the result. The first bundle data source is treated as
a base bundle while subsequent bundle data sources are treated as overlays
which are sequentially merged onto the base bundle.

Before returning the merged bundle, ReadAndMergeBundleData will also attempt
to resolve any include directives present in the machine annotations,
application options and annotations.

When merging an overlay into a base bundle the following rules apply for the
BundleData struct fields:
- if an overlay specifies a bundle-level series, it overrides the base bundle
series.
- overlay-defined relations are appended to the base bundle relations
- overlay-defined machines overwrite the base bundle machines.
- if an overlay defines an application that is not present in the base bundle,
it will get appended to the application list.
- if an overlay defines an empty application or saas value, it will be removed
from the base bundle together with any associated relations. For example, to
remove an application named "mysql" the following overlay snippet can be
provided:
applications:
mysql.

- if an overlay defines an application that is also present in the base bundle
the two application specs are merged together

ApplicationSpec merge rules:
- if the overlay defines a value for a scalar or slice field, it will overwrite
the value from the base spec .
- if the overlay specifies a nil/empty value for a map field, then the map
field of the base spec will be cleared.
- if the overlay specifies a non-empty value for a map field, its key/value
tuples are iterated and:
- if the value is nil/zero and the value is non-scalar, it is deleted from
the base spec.
- otherwise, the key/value is inserted into the base spec overwriting any
existing entries.
// ReadAndMergeBundleData reads N bundle data sources composes their contents // together and returns the result . The first bundle data source is treated as // a base bundle while subsequent bundle data sources are treated as overlays // which are sequentially merged onto the base bundle . // // Before returning the merged bundle ReadAndMergeBundleData will also attempt // to resolve any include directives present in the machine annotations // application options and annotations . // // When merging an overlay into a base bundle the following rules apply for the // BundleData struct fields : // - if an overlay specifies a bundle - level series it overrides the base bundle // series . // - overlay - defined relations are appended to the base bundle relations // - overlay - defined machines overwrite the base bundle machines . // - if an overlay defines an application that is not present in the base bundle // it will get appended to the application list . // - if an overlay defines an empty application or saas value it will be removed // from the base bundle together with any associated relations . For example to // remove an application named " mysql " the following overlay snippet can be // provided : // applications : // mysql : // // - if an overlay defines an application that is also present in the base bundle // the two application specs are merged together ( see following rules ) // // ApplicationSpec merge rules : // - if the overlay defines a value for a scalar or slice field it will overwrite // the value from the base spec ( e . g . trust series etc ) . // - if the overlay specifies a nil / empty value for a map field then the map // field of the base spec will be cleared . // - if the overlay specifies a non - empty value for a map field its key / value // tuples are iterated and : // - if the value is nil / zero and the value is non - scalar it is deleted from // the base spec . // - otherwise the key / value is inserted into the base spec overwriting any // existing entries .
func ReadAndMergeBundleData(sources ...BundleDataSource) (*BundleData, error) {
	var allParts []*BundleDataPart
	var partSrcIndex []int
	for srcIndex, src := range sources {
		if src == nil {
			continue
		}
		for _, part := range src.Parts() {
			allParts = append(allParts, part)
			partSrcIndex = append(partSrcIndex, srcIndex)
		}
	}
	if len(allParts) == 0 {
		return nil, errors.NotValidf("malformed bundle: bundle is empty")
	}
	base := allParts[0]
	if err := VerifyNoOverlayFieldsPresent(base.Data); err != nil {
		return nil, errors.Trace(err)
	}
	for index, part := range allParts {
		resolveOverlayPresenceFields(part)
		if index != 0 {
			if err := applyOverlay(base, part); err != nil {
				return nil, errors.Trace(err)
			}
		}
		srcIndex := partSrcIndex[index]
		incResolver := sources[srcIndex].ResolveInclude
		basePath := sources[srcIndex].BasePath()
		for app, appData := range base.Data.Applications {
			if appData == nil {
				return nil, errors.Errorf("base application %q has no body", app)
			}
			resolvedCharm, err := resolveRelativeCharmPath(basePath, appData.Charm)
			if err != nil {
				return nil, errors.Annotatef(err, "resolving relative charm path %q for application %q", appData.Charm, app)
			}
			appData.Charm = resolvedCharm
			for k, v := range appData.Options {
				newV, changed, err := resolveIncludes(incResolver, v)
				if err != nil {
					return nil, errors.Annotatef(err, "processing option %q for application %q", k, app)
				}
				if changed {
					appData.Options[k] = newV
				}
			}
			for k, v := range appData.Annotations {
				newV, changed, err := resolveIncludes(incResolver, v)
				if err != nil {
					return nil, errors.Annotatef(err, "processing annotation %q for application %q", k, app)
				}
				if changed {
					appData.Annotations[k] = newV
				}
			}
		}
		for machine, machineData := range base.Data.Machines {
			if machineData == nil {
				continue
			}
			for k, v := range machineData.Annotations {
				newV, changed, err := resolveIncludes(incResolver, v)
				if err != nil {
					return nil, errors.Annotatef(err, "processing annotation %q for machine %q", k, machine)
				}
				if changed {
					machineData.Annotations[k] = newV
				}
			}
		}
	}
	return base.Data, nil
}
func ReadAndMergeBundleData ( sources ... BundleDataSource ) ( * BundleData , error ) { var allParts [ ] * BundleDataPart var partSrcIndex [ ] int for srcIndex , src := range sources { if src == nil { continue } for _ , part := range src . Parts ( ) { allParts = append ( allParts , part ) partSrcIndex = append ( partSrcIndex , srcIndex ) } } if len ( allParts ) == 0 { return nil , errors . NotValidf ( " " ) } base := allParts [ 0 ] if err := VerifyNoOverlayFieldsPresent ( base . Data ) ; err != nil { return nil , errors . Trace ( err ) } for index , part := range allParts { resolveOverlayPresenceFields ( part ) if index != 0 { if err := applyOverlay ( base , part ) ; err != nil { return nil , errors . Trace ( err ) } } srcIndex := partSrcIndex [ index ] incResolver := sources [ srcIndex ] . ResolveInclude basePath := sources [ srcIndex ] . BasePath ( ) for app , appData := range base . Data . Applications { if appData == nil { return nil , errors . Errorf ( " " , app ) } resolvedCharm , err := resolveRelativeCharmPath ( basePath , appData . Charm ) if err != nil { return nil , errors . Annotatef ( err , " " , appData . Charm , app ) } appData . Charm = resolvedCharm for k , v := range appData . Options { newV , changed , err := resolveIncludes ( incResolver , v ) if err != nil { return nil , errors . Annotatef ( err , " " , k , app ) } if changed { appData . Options [ k ] = newV } } for k , v := range appData . Annotations { newV , changed , err := resolveIncludes ( incResolver , v ) if err != nil { return nil , errors . Annotatef ( err , " " , k , app ) } if changed { appData . Annotations [ k ] = newV } } } for machine , machineData := range base . Data . Machines { if machineData == nil { continue } for k , v := range machineData . Annotations { newV , changed , err := resolveIncludes ( incResolver , v ) if err != nil { return nil , errors . Annotatef ( err , " " , k , machine ) } if changed { machineData . Annotations [ k ] = newV } } } } return base . Data , nil }
ReadAndMergeBundleData reads N bundle data sources, composes their contents
together and returns the result.
ReadAndMergeBundleData reads N bundle data sources composes their contents together and returns the result .
// Treat the first part as the base bundle // Merge parts and resolve include directives // Resolve any re-writing of normalisation that could cause the presence // field to be out of sync with the actual bundle representation. // Relative include directives are resolved using the base path // of the datasource that yielded this part