Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(513)

Side by Side Diff: server/config/config.go

Issue 2580713002: Implement a server-side config service interface. (Closed)
Patch Set: Update MultiResolver interface, add test for MultiError. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package config
6
7 import (
8 "encoding/json"
9 "net/url"
10
11 "github.com/luci/luci-go/common/config"
12 "github.com/luci/luci-go/common/errors"
13
14 "golang.org/x/net/context"
15 )
16
17 // ErrNoConfig is a sentinel error returned by Get when the requested
18 // 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.
19 var ErrNoConfig = config.ErrNoConfig
20
21 // GetAllType is the type of configuration to retrieve with GetAll.
22 //
23 // GetAllType marshals/unmarshals to/from a compact JSON representation. This is
24 // used by the caching layer.
25 type GetAllType string
26
27 const (
28 // Project indicates that project configus should be retrieved.
29 Project = GetAllType("Project")
30 // Ref indicates that ref configs should be retrieved.
31 Ref = GetAllType("Ref")
32 )
33
34 // MarshalJSON implements json.Marshaler.
35 func (gat GetAllType) MarshalJSON() ([]byte, error) {
36 switch gat {
37 case Project:
38 return json.Marshal("P")
39 case Ref:
40 return json.Marshal("R")
41 default:
42 return nil, errors.Reason("unknown GetAllType: %(value)v").D("va lue", gat).Err()
43 }
44 }
45
46 // UnmarshalJSON implements json.Unmarshaler.
47 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.
48 var v string
49 if err := json.Unmarshal(d, &v); err != nil {
50 return errors.Annotate(err).Err()
51 }
52
53 switch v {
54 case "P":
55 *gat = Project
56 return nil
57 case "R":
58 *gat = Ref
59 return nil
60 default:
61 return errors.Reason("unknown GetAllType: %(value)q").D("value", v).Err()
62 }
63 }
64
65 // Meta is metadata about a configuration.
66 type Meta struct {
67 // ConfigSet is the item's config set.
68 ConfigSet string
69 // Path is the item's path within its config set.
70 Path string
71
72 // ContentHash is the content hash.
73 ContentHash string
74 // Revision is the revision string.
75 Revision string
76 }
77
78 // ServiceURL returns the URL of the config service.
79 func ServiceURL(c context.Context) url.URL { return getBackend(c).ServiceURL(c) }
80
81 // 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.
82 //
83 // r, if supplied, is a MultiResolver that will load the configuration data.
84 // If nil, the configuration data will be discarded (useful if you only care
85 // about metas).
86 //
87 // meta, if not nil, will have the configuration's Meta loaded into it on
88 // success.
89 func Get(c context.Context, a Authority, configSet, path string, r Resolver, met a *Meta) error {
90 be := getBackend(c)
91
92 params := Params{
93 Authority: a,
94 Content: true,
95 }
96
97 if fr, ok := r.(FormattingResolver); ok {
98 params.Format, params.FormatData = fr.Format()
99 }
100
101 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
102 if err != nil {
103 return err
104 }
105
106 if meta != nil {
107 *meta = item.Meta
108 }
109 if r == nil {
110 return nil
111 }
112 return r.Resolve(item)
113 }
114
115 // GetAll retrieves all configurations of a given type.
116 //
117 // r, if supplied, is a MultiResolver that will load the configuration data.
118 // If nil, the configuration data will be discarded (useful if you only care
119 // about metas). If the MultiResolver operates on a slice (which it probably
120 // will), each meta and/or error index will correspond to its slice index.
121 //
122 // If meta is not nil, it will be populated with a slice of *Meta entries
123 // for each loaded configuration, in the same order that r receives them. If
124 // r resolves to a slice, the indexes for each resolved slice entry and meta
125 // entry should align unless r is doing something funky.
126 //
127 // Two types of failure may happen here. A systemic failure fails to load the
128 // set of project configurations. This will be returned directly.
129 //
130 // A resolver failure happens when the configuratiokns load, but could not be
131 // resolved. In this case, any successful resolutions and "meta" will be
132 // populated and an errors.MultiError will be returned containing non-nil
133 // errors at indices whose configs failed to resolve.
134 func GetAll(c context.Context, a Authority, t GetAllType, path string, r MultiRe solver, meta *[]*Meta) error {
135 be := getBackend(c)
136
137 params := Params{
138 Authority: a,
139 Content: true,
140 }
141
142 if fr, ok := r.(FormattingResolver); ok {
143 params.Format, params.FormatData = fr.Format()
144 }
145
146 items, err := be.GetAll(c, t, path, params)
147 if err != nil {
148 return err
149 }
150
151 // Load our metas.
152 if meta != nil {
153 metaSlice := *meta
154 if metaSlice == nil {
155 metaSlice = make([]*Meta, 0, len(items))
156 } else {
157 // Re-use the supplied slice.
158 metaSlice = metaSlice[:0]
159 }
160
161 for _, item := range items {
162 metaSlice = append(metaSlice, &item.Meta)
163 }
164
165 *meta = metaSlice
166 }
167
168 if r == nil {
169 return nil
170 }
171
172 // Resolve our items. If any individual resolution fails, return that fa ilure
173 // as a positional error in a MultiError.
174 lme := errors.NewLazyMultiError(len(items))
175 r.PrepareMulti(len(items))
176 for i, it := range items {
177 if err := r.ResolveItemAt(i, it); err != nil {
178 lme.Assign(i, err)
179 }
180 }
181 return lme.Get()
182 }
183
184 // GetConfigSetURL returns the URL where the specified ConfigSet is
185 // configured. If the config set doesn't exist, ErrNoConfig will be returned.
186 func GetConfigSetURL(c context.Context, a Authority, configSet string) (url.URL, error) {
187 return getBackend(c).ConfigSetURL(c, a, configSet)
188 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698