1package manifest
2
3import (
4	"regexp"
5	"strings"
6
7	bosherr "github.com/cloudfoundry/bosh-utils/errors"
8	boshlog "github.com/cloudfoundry/bosh-utils/logger"
9)
10
11type Validator interface {
12	Validate(Manifest) error
13}
14
15type validator struct {
16	logger boshlog.Logger
17}
18
19func NewValidator(logger boshlog.Logger) Validator {
20	return &validator{logger: logger}
21}
22
23func (v *validator) Validate(manifest Manifest) error {
24	errs := []error{}
25	releaseNames := map[string]struct{}{}
26	if len(manifest.Releases) < 1 {
27		errs = append(errs, bosherr.Errorf("releases must contain at least 1 release"))
28	}
29
30	for releaseIdx, release := range manifest.Releases {
31		if v.isBlank(release.Name) {
32			errs = append(errs, bosherr.Errorf("releases[%d].name must be provided", releaseIdx))
33		}
34
35		if _, found := releaseNames[release.Name]; found {
36			errs = append(errs, bosherr.Errorf("releases[%d].name '%s' must be unique", releaseIdx, release.Name))
37		}
38		releaseNames[release.Name] = struct{}{}
39
40		if v.isBlank(release.URL) {
41			errs = append(errs, bosherr.Errorf("releases[%d].url must be provided", releaseIdx))
42		}
43
44		matched, err := regexp.MatchString("^(file|http|https)://", release.URL)
45		if err != nil || !matched {
46			errs = append(errs, bosherr.Errorf("releases[%d].url must be a valid URL (file:// or http(s)://)", releaseIdx))
47		}
48
49		if strings.HasPrefix(release.URL, "http") && v.isBlank(release.SHA1) {
50			errs = append(errs, bosherr.Errorf("releases[%d].sha1 must be provided for http URL", releaseIdx))
51		}
52	}
53
54	if len(errs) > 0 {
55		return bosherr.NewMultiError(errs...)
56	}
57
58	return nil
59}
60
61func (v *validator) isBlank(str string) bool {
62	return str == "" || strings.TrimSpace(str) == ""
63}
64