123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- package config
- import (
- "fmt"
- "path"
- "github.com/Sirupsen/logrus"
- yaml "github.com/cloudfoundry-incubator/candiedyaml"
- "github.com/docker/libcompose/utils"
- )
- // MergeServicesV2 merges a v2 compose file into an existing set of service configs
- func MergeServicesV2(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, bytes []byte, options *ParseOptions) (map[string]*ServiceConfig, error) {
- var config Config
- if err := yaml.Unmarshal(bytes, &config); err != nil {
- return nil, err
- }
- datas := config.Services
- if options.Interpolate {
- if err := Interpolate(environmentLookup, &datas); err != nil {
- return nil, err
- }
- }
- if options.Preprocess != nil {
- var err error
- datas, err = options.Preprocess(datas)
- if err != nil {
- return nil, err
- }
- }
- for name, data := range datas {
- data, err := parseV2(resourceLookup, environmentLookup, file, data, datas, options)
- if err != nil {
- logrus.Errorf("Failed to parse service %s: %v", name, err)
- return nil, err
- }
- if serviceConfig, ok := existingServices.Get(name); ok {
- var rawExistingService RawService
- if err := utils.Convert(serviceConfig, &rawExistingService); err != nil {
- return nil, err
- }
- data = mergeConfig(rawExistingService, data)
- }
- datas[name] = data
- }
- serviceConfigs := make(map[string]*ServiceConfig)
- if err := utils.Convert(datas, &serviceConfigs); err != nil {
- return nil, err
- }
- return serviceConfigs, nil
- }
- // ParseVolumes parses volumes in a compose file
- func ParseVolumes(bytes []byte) (map[string]*VolumeConfig, error) {
- volumeConfigs := make(map[string]*VolumeConfig)
- var config Config
- if err := yaml.Unmarshal(bytes, &config); err != nil {
- return nil, err
- }
- if err := utils.Convert(config.Volumes, &volumeConfigs); err != nil {
- return nil, err
- }
- return volumeConfigs, nil
- }
- // ParseNetworks parses networks in a compose file
- func ParseNetworks(bytes []byte) (map[string]*NetworkConfig, error) {
- networkConfigs := make(map[string]*NetworkConfig)
- var config Config
- if err := yaml.Unmarshal(bytes, &config); err != nil {
- return nil, err
- }
- if err := utils.Convert(config.Networks, &networkConfigs); err != nil {
- return nil, err
- }
- return networkConfigs, nil
- }
- func parseV2(resourceLookup ResourceLookup, environmentLookup EnvironmentLookup, inFile string, serviceData RawService, datas RawServiceMap, options *ParseOptions) (RawService, error) {
- serviceData, err := readEnvFile(resourceLookup, inFile, serviceData)
- if err != nil {
- return nil, err
- }
- serviceData = resolveContextV2(inFile, serviceData)
- value, ok := serviceData["extends"]
- if !ok {
- return serviceData, nil
- }
- mapValue, ok := value.(map[interface{}]interface{})
- if !ok {
- return serviceData, nil
- }
- if resourceLookup == nil {
- return nil, fmt.Errorf("Can not use extends in file %s no mechanism provided to files", inFile)
- }
- file := asString(mapValue["file"])
- service := asString(mapValue["service"])
- if service == "" {
- return serviceData, nil
- }
- var baseService RawService
- if file == "" {
- if serviceData, ok := datas[service]; ok {
- baseService, err = parseV2(resourceLookup, environmentLookup, inFile, serviceData, datas, options)
- } else {
- return nil, fmt.Errorf("Failed to find service %s to extend", service)
- }
- } else {
- bytes, resolved, err := resourceLookup.Lookup(file, inFile)
- if err != nil {
- logrus.Errorf("Failed to lookup file %s: %v", file, err)
- return nil, err
- }
- var config Config
- if err := yaml.Unmarshal(bytes, &config); err != nil {
- return nil, err
- }
- baseRawServices := config.Services
- if options.Interpolate {
- err = Interpolate(environmentLookup, &baseRawServices)
- if err != nil {
- return nil, err
- }
- }
- baseService, ok = baseRawServices[service]
- if !ok {
- return nil, fmt.Errorf("Failed to find service %s in file %s", service, file)
- }
- baseService, err = parseV2(resourceLookup, environmentLookup, resolved, baseService, baseRawServices, options)
- }
- if err != nil {
- return nil, err
- }
- baseService = clone(baseService)
- logrus.Debugf("Merging %#v, %#v", baseService, serviceData)
- for _, k := range noMerge {
- if _, ok := baseService[k]; ok {
- source := file
- if source == "" {
- source = inFile
- }
- return nil, fmt.Errorf("Cannot extend service '%s' in %s: services with '%s' cannot be extended", service, source, k)
- }
- }
- baseService = mergeConfig(baseService, serviceData)
- logrus.Debugf("Merged result %#v", baseService)
- return baseService, nil
- }
- func resolveContextV2(inFile string, serviceData RawService) RawService {
- if _, ok := serviceData["build"]; !ok {
- return serviceData
- }
- build := serviceData["build"].(map[interface{}]interface{})
- context := asString(build["context"])
- if context == "" {
- return serviceData
- }
- if IsValidRemote(context) {
- return serviceData
- }
- current := path.Dir(inFile)
- if context == "." {
- context = current
- } else {
- current = path.Join(current, context)
- }
- build["context"] = current
- return serviceData
- }
|