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

Side by Side Diff: server/config/format.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 "fmt"
9 "sync"
10
11 "github.com/luci/luci-go/common/errors"
12
13 "golang.org/x/net/context"
14 )
15
16 // Formatter applies a transformation to the data's cached representation.
17 //
18 // The Formatter is supplied with the content to format, and any additional
19 // formatter data
iannucci 2017/01/07 20:12:16 This is the format data that comes with the Params
dnj 2017/01/10 03:25:58 It's the data in Item's Content, implemented by th
20 type Formatter interface {
21 FormatItem(c, fd string) (string, error)
22 }
23
24 // FormatterRegistry is a registry of Resolver key mapped to the Formatter to
25 // use to format that key.
26 type FormatterRegistry struct {
27 registryMu sync.RWMutex
28 registry map[string]Formatter
29 }
30
31 // Register registers a Formatter with the FormatBackend.
32 //
33 // If the supplied key is already registered, Register will panic.
34 func (r *FormatterRegistry) Register(rk string, f Formatter) {
35 if rk == "" {
36 panic("cannot register empty key")
37 }
38
39 r.registryMu.Lock()
40 defer r.registryMu.Unlock()
41
42 if _, ok := r.registry[rk]; ok {
43 panic(fmt.Errorf("key %q is already registered", rk))
44 }
45 if r.registry == nil {
46 r.registry = make(map[string]Formatter)
iannucci 2017/01/07 20:12:16 nit: `map[string]Formatter{}` is shorter
dnj 2017/01/10 03:25:58 Done.
47 }
48 r.registry[rk] = f
49 }
50
51 // Get returns the Formatter associated with the provided Format.
52 func (r *FormatterRegistry) Get(f string) Formatter {
53 r.registryMu.RLock()
54 defer r.registryMu.RUnlock()
55 return r.registry[f]
56 }
57
58 // FormatBackend is a Backend implementation that applies Formatter
59 // transformations to the various Items that pass through it.
60 //
61 // Formatter transformations are registered explicitly to the Resolver
62 // descriptions of the types that they operate on. If an Item is already
63 // formatted, no further transformations will be applied.
64 type FormatBackend struct {
65 // Backend is the underlying Backend that this FormatBackend will pull d ata
66 // from.
67 Backend
68
69 // GetRegistry returns the FormatterRegistry to use. If it returns nil,
70 // no formatting will be done.
71 GetRegistry func(context.Context) *FormatterRegistry
72 }
73
74 // Get implements Backend.
75 func (b *FormatBackend) Get(c context.Context, configSet, path string, p Params) (*Item, error) {
76 item, err := b.Backend.Get(c, configSet, path, p)
77 if err != nil {
78 return nil, err
79 }
80
81 if p.Format != "" {
82 formatter, err := b.getFormatter(c, p.Format)
83 if err != nil {
84 return nil, errors.Annotate(err).Reason("failed to get f ormatter for %(format)q, data %(data)q").
85 D("format", p.Format).D("data", p.FormatData).Er r()
86 }
87
88 if err := b.formatItem(item, formatter, p.Format, p.FormatData); err != nil {
89 return nil, errors.Annotate(err).Reason("failed to forma t item to %(format)q, data %(data)q").
90 D("format", p.Format).D("data", p.FormatData).Er r()
91 }
92 }
93 return item, nil
94 }
95
96 // GetAll implements Backend.
97 func (b *FormatBackend) GetAll(c context.Context, t GetAllType, path string, p P arams) ([]*Item, error) {
98 items, err := b.Backend.GetAll(c, t, path, p)
99 if err != nil {
100 return nil, err
101 }
102
103 if p.Format != "" {
104 formatter, err := b.getFormatter(c, p.Format)
105 if err != nil {
106 return nil, errors.Annotate(err).Reason("failed to get f ormatter for %(format)q, data %(data)q").
107 D("format", p.Format).D("data", p.FormatData).Er r()
108 }
109
110 lme := errors.NewLazyMultiError(len(items))
111 for i, item := range items {
112 if err := b.formatItem(item, formatter, p.Format, p.Form atData); err != nil {
113 lme.Assign(i, err)
114 }
115 }
116
117 if err := lme.Get(); err != nil {
118 return nil, errors.Annotate(err).Reason("failed to forma t items to %(format)q, data %(data)q").
119 D("format", p.Format).D("data", p.FormatData).Er r()
120 }
121 }
122 return items, nil
123 }
124
125 func (b *FormatBackend) getFormatter(c context.Context, f string) (Formatter, er ror) {
126 if b.GetRegistry == nil {
127 return nil, errors.New("no formatter registry function installed ")
128 }
129
130 reg := b.GetRegistry(c)
131 if reg == nil {
132 return nil, errors.New("formatter registry function returned nil registry")
133 }
134 formatter := reg.Get(f)
135 if formatter == nil {
136 return nil, errors.Reason("unknown formatter: %(formatter)q").D( "formatter", f).Err()
137 }
138 return formatter, nil
139 }
140
141 func (b *FormatBackend) formatItem(it *Item, formatter Formatter, f, fd string) error {
142 if it.Format != "" {
143 // Item is already formatted.
144 return nil
145 }
146
147 // Item is not formatted, so format it.
148 content, err := formatter.FormatItem(it.Content, fd)
149 if err != nil {
150 return errors.Annotate(err).Reason("failed to format item").Err( )
151 }
152 it.Content = content
153 it.Format = f
154 it.FormatData = fd
155 return nil
156 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698