You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.6 KiB
Go
121 lines
3.6 KiB
Go
/*
|
|
Copyright 2020 The Compose Specification Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package loader
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/compose-spec/compose-go/dotenv"
|
|
"github.com/compose-spec/compose-go/types"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// LoadIncludeConfig parse the require config from raw yaml
|
|
func LoadIncludeConfig(source []interface{}) ([]types.IncludeConfig, error) {
|
|
var requires []types.IncludeConfig
|
|
err := Transform(source, &requires)
|
|
return requires, err
|
|
}
|
|
|
|
var transformIncludeConfig TransformerFunc = func(data interface{}) (interface{}, error) {
|
|
switch value := data.(type) {
|
|
case string:
|
|
return map[string]interface{}{"path": value}, nil
|
|
case map[string]interface{}:
|
|
return value, nil
|
|
default:
|
|
return data, errors.Errorf("invalid type %T for `include` configuration", value)
|
|
}
|
|
}
|
|
|
|
func loadInclude(configDetails types.ConfigDetails, model *types.Config, options *Options, loaded []string) (*types.Config, error) {
|
|
for _, r := range model.Include {
|
|
for i, p := range r.Path {
|
|
if !filepath.IsAbs(p) {
|
|
r.Path[i] = filepath.Join(configDetails.WorkingDir, p)
|
|
}
|
|
}
|
|
if r.ProjectDirectory == "" {
|
|
r.ProjectDirectory = filepath.Dir(r.Path[0])
|
|
}
|
|
|
|
loadOptions := options.clone()
|
|
loadOptions.SetProjectName(model.Name, true)
|
|
loadOptions.ResolvePaths = true
|
|
loadOptions.SkipNormalization = true
|
|
loadOptions.SkipConsistencyCheck = true
|
|
|
|
env, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
imported, err := load(types.ConfigDetails{
|
|
WorkingDir: r.ProjectDirectory,
|
|
ConfigFiles: types.ToConfigFiles(r.Path),
|
|
Environment: env,
|
|
}, loadOptions, loaded)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = importResources(model, imported, r.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
model.Include = nil
|
|
return model, nil
|
|
}
|
|
|
|
// importResources import into model all resources defined by imported, and report error on conflict
|
|
func importResources(model *types.Config, imported *types.Project, path []string) error {
|
|
services := mapByName(model.Services)
|
|
for _, service := range imported.Services {
|
|
if _, ok := services[service.Name]; ok {
|
|
return fmt.Errorf("imported compose file %s defines conflicting service %s", path, service.Name)
|
|
}
|
|
model.Services = append(model.Services, service)
|
|
}
|
|
for n, network := range imported.Networks {
|
|
if _, ok := model.Networks[n]; ok {
|
|
return fmt.Errorf("imported compose file %s defines conflicting network %s", path, n)
|
|
}
|
|
model.Networks[n] = network
|
|
}
|
|
for n, volume := range imported.Volumes {
|
|
if _, ok := model.Volumes[n]; ok {
|
|
return fmt.Errorf("imported compose file %s defines conflicting volume %s", path, n)
|
|
}
|
|
model.Volumes[n] = volume
|
|
}
|
|
for n, secret := range imported.Secrets {
|
|
if _, ok := model.Secrets[n]; ok {
|
|
return fmt.Errorf("imported compose file %s defines conflicting secret %s", path, n)
|
|
}
|
|
model.Secrets[n] = secret
|
|
}
|
|
for n, config := range imported.Configs {
|
|
if _, ok := model.Configs[n]; ok {
|
|
return fmt.Errorf("imported compose file %s defines conflicting config %s", path, n)
|
|
}
|
|
model.Configs[n] = config
|
|
}
|
|
return nil
|
|
}
|