forked from buildpacks/pack
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config_reader.go
137 lines (112 loc) · 3.51 KB
/
config_reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package builder
import (
"fmt"
"io"
"os"
"path/filepath"
"github.com/BurntSushi/toml"
"github.com/pkg/errors"
"github.com/buildpacks/pack/internal/config"
"github.com/buildpacks/pack/internal/dist"
"github.com/buildpacks/pack/internal/paths"
"github.com/buildpacks/pack/internal/style"
)
// Config is a builder configuration file
type Config struct {
Description string `toml:"description"`
Buildpacks BuildpackCollection `toml:"buildpacks"`
Order dist.Order `toml:"order"`
Stack StackConfig `toml:"stack"`
Lifecycle LifecycleConfig `toml:"lifecycle"`
}
// BuildpackCollection is a list of BuildpackConfigs
type BuildpackCollection []BuildpackConfig
// BuildpackConfig details the configuration of a Buildpack
type BuildpackConfig struct {
dist.BuildpackInfo
dist.ImageOrURI
}
// StackConfig details the configuration of a Stack
type StackConfig struct {
ID string `toml:"id"`
BuildImage string `toml:"build-image"`
RunImage string `toml:"run-image"`
RunImageMirrors []string `toml:"run-image-mirrors,omitempty"`
}
// LifecycleConfig details the configuration of the Lifecycle
type LifecycleConfig struct {
URI string `toml:"uri"`
Version string `toml:"version"`
}
// ReadConfig reads a builder configuration from the file path provided and returns the
// configuration along with any warnings encountered while parsing
func ReadConfig(path string) (config Config, warnings []string, err error) {
builderDir, err := filepath.Abs(filepath.Dir(path))
if err != nil {
return Config{}, nil, err
}
file, err := os.Open(path)
if err != nil {
return Config{}, nil, errors.Wrap(err, "opening config file")
}
defer file.Close()
config, err = parseConfig(file, builderDir, path)
if err != nil {
return Config{}, nil, errors.Wrapf(err, "parse contents of '%s'", path)
}
if len(config.Order) == 0 {
warnings = append(warnings, fmt.Sprintf("empty %s definition", style.Symbol("order")))
}
return config, warnings, nil
}
// Validate a Config
func (c Config) Validate() error {
return c.Stack.Validate()
}
// Validate a StackConfig
func (s StackConfig) Validate() error {
if s.ID == "" {
return errors.New("stack.id is required")
}
if s.BuildImage == "" {
return errors.New("stack.build-image is required")
}
if s.RunImage == "" {
return errors.New("stack.run-image is required")
}
return nil
}
// parseConfig reads a builder configuration from reader and resolves relative buildpack paths using `relativeToDir`
func parseConfig(reader io.Reader, relativeToDir, path string) (Config, error) {
builderConfig := Config{}
tomlMetadata, err := toml.DecodeReader(reader, &builderConfig)
if err != nil {
return Config{}, errors.Wrap(err, "decoding toml contents")
}
undecodedKeys := tomlMetadata.Undecoded()
if len(undecodedKeys) > 0 {
unknownElementsMsg := config.FormatUndecodedKeys(undecodedKeys)
return Config{}, errors.Errorf("%s in %s",
unknownElementsMsg,
style.Symbol(path),
)
}
for i, bp := range builderConfig.Buildpacks {
if bp.URI == "" {
continue
}
uri, err := paths.ToAbsolute(bp.URI, relativeToDir)
if err != nil {
return Config{}, errors.Wrap(err, "transforming buildpack URI")
}
builderConfig.Buildpacks[i].URI = uri
}
if builderConfig.Lifecycle.URI != "" {
uri, err := paths.ToAbsolute(builderConfig.Lifecycle.URI, relativeToDir)
if err != nil {
return Config{}, errors.Wrap(err, "transforming lifecycle URI")
}
builderConfig.Lifecycle.URI = uri
}
return builderConfig, nil
}