Chromium Code Reviews| Index: server/config/config.go |
| diff --git a/server/config/config.go b/server/config/config.go |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..66e66fc4b7656883597387c31c7dfb0ac14ac4cb |
| --- /dev/null |
| +++ b/server/config/config.go |
| @@ -0,0 +1,188 @@ |
| +// Copyright 2016 The LUCI Authors. All rights reserved. |
| +// Use of this source code is governed under the Apache License, Version 2.0 |
| +// that can be found in the LICENSE file. |
| + |
| +package config |
| + |
| +import ( |
| + "encoding/json" |
| + "net/url" |
| + |
| + "github.com/luci/luci-go/common/config" |
| + "github.com/luci/luci-go/common/errors" |
| + |
| + "golang.org/x/net/context" |
| +) |
| + |
| +// ErrNoConfig is a sentinel error returned by Get when the requested |
| +// configuration is not found. |
|
iannucci
2017/01/07 20:12:16
I would mention that it's an alias of config.ErrNo
dnj
2017/01/10 03:25:57
Done.
|
| +var ErrNoConfig = config.ErrNoConfig |
| + |
| +// GetAllType is the type of configuration to retrieve with GetAll. |
| +// |
| +// GetAllType marshals/unmarshals to/from a compact JSON representation. This is |
| +// used by the caching layer. |
| +type GetAllType string |
| + |
| +const ( |
| + // Project indicates that project configus should be retrieved. |
| + Project = GetAllType("Project") |
| + // Ref indicates that ref configs should be retrieved. |
| + Ref = GetAllType("Ref") |
| +) |
| + |
| +// MarshalJSON implements json.Marshaler. |
| +func (gat GetAllType) MarshalJSON() ([]byte, error) { |
| + switch gat { |
| + case Project: |
| + return json.Marshal("P") |
| + case Ref: |
| + return json.Marshal("R") |
| + default: |
| + return nil, errors.Reason("unknown GetAllType: %(value)v").D("value", gat).Err() |
| + } |
| +} |
| + |
| +// UnmarshalJSON implements json.Unmarshaler. |
| +func (gat *GetAllType) UnmarshalJSON(d []byte) error { |
|
iannucci
2017/01/07 20:12:15
same as other *JSON methods re: constant []byte va
dnj
2017/01/10 03:25:57
Done.
|
| + var v string |
| + if err := json.Unmarshal(d, &v); err != nil { |
| + return errors.Annotate(err).Err() |
| + } |
| + |
| + switch v { |
| + case "P": |
| + *gat = Project |
| + return nil |
| + case "R": |
| + *gat = Ref |
| + return nil |
| + default: |
| + return errors.Reason("unknown GetAllType: %(value)q").D("value", v).Err() |
| + } |
| +} |
| + |
| +// Meta is metadata about a configuration. |
| +type Meta struct { |
| + // ConfigSet is the item's config set. |
| + ConfigSet string |
| + // Path is the item's path within its config set. |
| + Path string |
| + |
| + // ContentHash is the content hash. |
| + ContentHash string |
| + // Revision is the revision string. |
| + Revision string |
| +} |
| + |
| +// ServiceURL returns the URL of the config service. |
| +func ServiceURL(c context.Context) url.URL { return getBackend(c).ServiceURL(c) } |
| + |
| +// Get retrieves a single configuration. |
|
iannucci
2017/01/07 20:12:16
can we call them 'configuration file's? Since from
dnj
2017/01/10 03:25:57
Done.
|
| +// |
| +// r, if supplied, is a MultiResolver that will load the configuration data. |
| +// If nil, the configuration data will be discarded (useful if you only care |
| +// about metas). |
| +// |
| +// meta, if not nil, will have the configuration's Meta loaded into it on |
| +// success. |
| +func Get(c context.Context, a Authority, configSet, path string, r Resolver, meta *Meta) error { |
| + be := getBackend(c) |
| + |
| + params := Params{ |
| + Authority: a, |
| + Content: true, |
| + } |
| + |
| + if fr, ok := r.(FormattingResolver); ok { |
| + params.Format, params.FormatData = fr.Format() |
| + } |
| + |
| + item, err := be.Get(c, configSet, path, params) |
|
iannucci
2017/01/07 20:12:15
maybe the Params thing would be clearer if backend
dnj
2017/01/10 03:25:58
Yeah I was debating doing this. I think I was out
|
| + if err != nil { |
| + return err |
| + } |
| + |
| + if meta != nil { |
| + *meta = item.Meta |
| + } |
| + if r == nil { |
| + return nil |
| + } |
| + return r.Resolve(item) |
| +} |
| + |
| +// GetAll retrieves all configurations of a given type. |
| +// |
| +// r, if supplied, is a MultiResolver that will load the configuration data. |
| +// If nil, the configuration data will be discarded (useful if you only care |
| +// about metas). If the MultiResolver operates on a slice (which it probably |
| +// will), each meta and/or error index will correspond to its slice index. |
| +// |
| +// If meta is not nil, it will be populated with a slice of *Meta entries |
| +// for each loaded configuration, in the same order that r receives them. If |
| +// r resolves to a slice, the indexes for each resolved slice entry and meta |
| +// entry should align unless r is doing something funky. |
| +// |
| +// Two types of failure may happen here. A systemic failure fails to load the |
| +// set of project configurations. This will be returned directly. |
| +// |
| +// A resolver failure happens when the configuratiokns load, but could not be |
| +// resolved. In this case, any successful resolutions and "meta" will be |
| +// populated and an errors.MultiError will be returned containing non-nil |
| +// errors at indices whose configs failed to resolve. |
| +func GetAll(c context.Context, a Authority, t GetAllType, path string, r MultiResolver, meta *[]*Meta) error { |
| + be := getBackend(c) |
| + |
| + params := Params{ |
| + Authority: a, |
| + Content: true, |
| + } |
| + |
| + if fr, ok := r.(FormattingResolver); ok { |
| + params.Format, params.FormatData = fr.Format() |
| + } |
| + |
| + items, err := be.GetAll(c, t, path, params) |
| + if err != nil { |
| + return err |
| + } |
| + |
| + // Load our metas. |
| + if meta != nil { |
| + metaSlice := *meta |
| + if metaSlice == nil { |
| + metaSlice = make([]*Meta, 0, len(items)) |
| + } else { |
| + // Re-use the supplied slice. |
| + metaSlice = metaSlice[:0] |
| + } |
| + |
| + for _, item := range items { |
| + metaSlice = append(metaSlice, &item.Meta) |
| + } |
| + |
| + *meta = metaSlice |
| + } |
| + |
| + if r == nil { |
| + return nil |
| + } |
| + |
| + // Resolve our items. If any individual resolution fails, return that failure |
| + // as a positional error in a MultiError. |
| + lme := errors.NewLazyMultiError(len(items)) |
| + r.PrepareMulti(len(items)) |
| + for i, it := range items { |
| + if err := r.ResolveItemAt(i, it); err != nil { |
| + lme.Assign(i, err) |
| + } |
| + } |
| + return lme.Get() |
| +} |
| + |
| +// GetConfigSetURL returns the URL where the specified ConfigSet is |
| +// configured. If the config set doesn't exist, ErrNoConfig will be returned. |
| +func GetConfigSetURL(c context.Context, a Authority, configSet string) (url.URL, error) { |
| + return getBackend(c).ConfigSetURL(c, a, configSet) |
| +} |