OLD | NEW |
1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 // Package dumper implements a very VERY dumb datastore-dumping debugging aid. | 5 // Package dumper implements a very VERY dumb datastore-dumping debugging aid. |
6 // You shouldn't plan on having this work with the production datastore with any | 6 // You shouldn't plan on having this work with the production datastore with any |
7 // appreciable amount of data. | 7 // appreciable amount of data. |
8 // | 8 // |
9 // This will take an arbitrary query (or even a query for every entity in the | 9 // This will take an arbitrary query (or even a query for every entity in the |
10 // entire datastore), and print every entity to some output stream. | 10 // entire datastore), and print every entity to some output stream. |
11 package dumper | 11 package dumper |
12 | 12 |
13 import ( | 13 import ( |
14 "fmt" | 14 "fmt" |
15 "io" | 15 "io" |
16 "os" | 16 "os" |
17 "sort" | 17 "sort" |
18 "strings" | 18 "strings" |
19 | 19 |
20 » "github.com/luci/gae/service/datastore" | 20 » ds "github.com/luci/gae/service/datastore" |
| 21 |
21 "golang.org/x/net/context" | 22 "golang.org/x/net/context" |
22 ) | 23 ) |
23 | 24 |
24 // Key is a key into a PropFilterMap | 25 // Key is a key into a PropFilterMap |
25 type Key struct { | 26 type Key struct { |
26 Kind string | 27 Kind string |
27 PropName string | 28 PropName string |
28 } | 29 } |
29 | 30 |
30 // A PropFilterMap maps from Kind+PropertyName tuples to a formatting function.
You | 31 // A PropFilterMap maps from Kind+PropertyName tuples to a formatting function.
You |
31 // may use this to specially format particular properties. | 32 // may use this to specially format particular properties. |
32 type PropFilterMap map[Key]func(datastore.Property) string | 33 type PropFilterMap map[Key]func(ds.Property) string |
33 | 34 |
34 // KindFilterMap maps from a Kind to a formatting function. You may use this to | 35 // KindFilterMap maps from a Kind to a formatting function. You may use this to |
35 // specially format particular Kinds. If this function returns an empty string, | 36 // specially format particular Kinds. If this function returns an empty string, |
36 // the default formatting function (including any PropFilterMap entries) will be | 37 // the default formatting function (including any PropFilterMap entries) will be |
37 // used. | 38 // used. |
38 type KindFilterMap map[string]func(*datastore.Key, datastore.PropertyMap) string | 39 type KindFilterMap map[string]func(*ds.Key, ds.PropertyMap) string |
39 | 40 |
40 // Config is a configured dumper. | 41 // Config is a configured dumper. |
41 type Config struct { | 42 type Config struct { |
42 // OutStream is the output stream to use. If this is nil, os.Stdout will
be | 43 // OutStream is the output stream to use. If this is nil, os.Stdout will
be |
43 // used. | 44 // used. |
44 OutStream io.Writer | 45 OutStream io.Writer |
45 | 46 |
46 // WithSpecial, if true, includes entities which have kinds that begin a
nd | 47 // WithSpecial, if true, includes entities which have kinds that begin a
nd |
47 // end with "__". By default, these entities are skipped. | 48 // end with "__". By default, these entities are skipped. |
48 WithSpecial bool | 49 WithSpecial bool |
49 | 50 |
50 // PropFilters is an optional property filter map for controlling the | 51 // PropFilters is an optional property filter map for controlling the |
51 // rendering of certain Kind/Property values. | 52 // rendering of certain Kind/Property values. |
52 PropFilters PropFilterMap | 53 PropFilters PropFilterMap |
53 | 54 |
54 // KindFilters is an optional kind filter for controlling the rendering
of | 55 // KindFilters is an optional kind filter for controlling the rendering
of |
55 // certain Kind values. | 56 // certain Kind values. |
56 KindFilters KindFilterMap | 57 KindFilters KindFilterMap |
57 } | 58 } |
58 | 59 |
59 // Query will dump everything matching the provided query. | 60 // Query will dump everything matching the provided query. |
60 // | 61 // |
61 // If the provided query is nil, a kindless query without any filters will be | 62 // If the provided query is nil, a kindless query without any filters will be |
62 // used. | 63 // used. |
63 func (cfg Config) Query(c context.Context, q *datastore.Query) (n int, err error
) { | 64 func (cfg Config) Query(c context.Context, q *ds.Query) (n int, err error) { |
64 » ds := datastore.Get(c) | |
65 | |
66 if q == nil { | 65 if q == nil { |
67 » » q = datastore.NewQuery("") | 66 » » q = ds.NewQuery("") |
68 } | 67 } |
69 | 68 |
70 out := cfg.OutStream | 69 out := cfg.OutStream |
71 if out == nil { | 70 if out == nil { |
72 out = os.Stdout | 71 out = os.Stdout |
73 } | 72 } |
74 | 73 |
75 » fmtVal := func(kind, name string, prop datastore.Property) string { | 74 » fmtVal := func(kind, name string, prop ds.Property) string { |
76 if fn := cfg.PropFilters[Key{kind, name}]; fn != nil { | 75 if fn := cfg.PropFilters[Key{kind, name}]; fn != nil { |
77 return fn(prop) | 76 return fn(prop) |
78 } | 77 } |
79 return prop.String() | 78 return prop.String() |
80 } | 79 } |
81 | 80 |
82 prnt := func(format string, args ...interface{}) (err error) { | 81 prnt := func(format string, args ...interface{}) (err error) { |
83 var amt int | 82 var amt int |
84 amt, err = fmt.Fprintf(out, format, args...) | 83 amt, err = fmt.Fprintf(out, format, args...) |
85 n += amt | 84 n += amt |
86 return | 85 return |
87 } | 86 } |
88 | 87 |
89 » prop := func(kind, name string, pdata datastore.PropertyData) (err error
) { | 88 » prop := func(kind, name string, pdata ds.PropertyData) (err error) { |
90 switch t := pdata.(type) { | 89 switch t := pdata.(type) { |
91 » » case datastore.Property: | 90 » » case ds.Property: |
92 return prnt(" %q: %s\n", name, fmtVal(kind, name, t)) | 91 return prnt(" %q: %s\n", name, fmtVal(kind, name, t)) |
93 | 92 |
94 » » case datastore.PropertySlice: | 93 » » case ds.PropertySlice: |
95 if len(t) <= 1 { | 94 if len(t) <= 1 { |
96 return prnt(" %q: [%s]\n", name, fmtVal(kind, n
ame, t[0])) | 95 return prnt(" %q: [%s]\n", name, fmtVal(kind, n
ame, t[0])) |
97 } | 96 } |
98 if err = prnt(" %q: [\n %s", name, fmtVal(kind, name
, t[0])); err != nil { | 97 if err = prnt(" %q: [\n %s", name, fmtVal(kind, name
, t[0])); err != nil { |
99 return | 98 return |
100 } | 99 } |
101 for _, v := range t[1:] { | 100 for _, v := range t[1:] { |
102 if err = prnt(",\n %s", fmtVal(kind, name, v)
); err != nil { | 101 if err = prnt(",\n %s", fmtVal(kind, name, v)
); err != nil { |
103 return | 102 return |
104 } | 103 } |
105 } | 104 } |
106 | 105 |
107 default: | 106 default: |
108 return fmt.Errorf("unknown PropertyData %T", t) | 107 return fmt.Errorf("unknown PropertyData %T", t) |
109 } | 108 } |
110 return prnt("\n ]\n") | 109 return prnt("\n ]\n") |
111 } | 110 } |
112 | 111 |
113 » err = ds.Run(q, func(pm datastore.PropertyMap) error { | 112 » err = ds.Run(c, q, func(pm ds.PropertyMap) error { |
114 » » key := datastore.GetMetaDefault(pm, "key", nil).(*datastore.Key) | 113 » » key := ds.GetMetaDefault(pm, "key", nil).(*ds.Key) |
115 if !cfg.WithSpecial && strings.HasPrefix(key.Kind(), "__") && st
rings.HasSuffix(key.Kind(), "__") { | 114 if !cfg.WithSpecial && strings.HasPrefix(key.Kind(), "__") && st
rings.HasSuffix(key.Kind(), "__") { |
116 return nil | 115 return nil |
117 } | 116 } |
118 if err := prnt("\n%s:\n", key); err != nil { | 117 if err := prnt("\n%s:\n", key); err != nil { |
119 return err | 118 return err |
120 } | 119 } |
121 pm, _ = pm.Save(false) | 120 pm, _ = pm.Save(false) |
122 | 121 |
123 // See if we have a KindFilter for this | 122 // See if we have a KindFilter for this |
124 if flt, ok := cfg.KindFilters[key.Kind()]; ok { | 123 if flt, ok := cfg.KindFilters[key.Kind()]; ok { |
(...skipping 17 matching lines...) Expand all Loading... |
142 return err | 141 return err |
143 } | 142 } |
144 } | 143 } |
145 return nil | 144 return nil |
146 }) | 145 }) |
147 return | 146 return |
148 } | 147 } |
149 | 148 |
150 // Query dumps the provided query to stdout without special entities and with | 149 // Query dumps the provided query to stdout without special entities and with |
151 // default rendering. | 150 // default rendering. |
152 func Query(c context.Context, q *datastore.Query) { | 151 func Query(c context.Context, q *ds.Query) { |
153 Config{}.Query(c, q) | 152 Config{}.Query(c, q) |
154 } | 153 } |
155 | 154 |
156 // All dumps all entities to stdout without special entities and with default | 155 // All dumps all entities to stdout without special entities and with default |
157 // rendering. | 156 // rendering. |
158 func All(c context.Context) { | 157 func All(c context.Context) { |
159 Config{}.Query(c, nil) | 158 Config{}.Query(c, nil) |
160 } | 159 } |
OLD | NEW |