| 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 |