| Index: go/src/infra/gae/libs/wrapper/memory/key.go
|
| diff --git a/go/src/infra/gae/libs/wrapper/memory/key.go b/go/src/infra/gae/libs/wrapper/memory/key.go
|
| deleted file mode 100644
|
| index c6dd56fba8fb195207b06ff454cdd9d4fa576a8f..0000000000000000000000000000000000000000
|
| --- a/go/src/infra/gae/libs/wrapper/memory/key.go
|
| +++ /dev/null
|
| @@ -1,236 +0,0 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package memory
|
| -
|
| -import (
|
| - "bytes"
|
| - "errors"
|
| - "fmt"
|
| -
|
| - "github.com/golang/protobuf/proto"
|
| - "github.com/luci/luci-go/common/cmpbin"
|
| - "github.com/mjibson/goon"
|
| -
|
| - "appengine"
|
| - "appengine/datastore"
|
| - "appengine_internal"
|
| - basepb "appengine_internal/base"
|
| -)
|
| -
|
| -const keyNumToksReasonableLimit = 50
|
| -
|
| -///////////////////////////// fakeGAECtxForNewKey //////////////////////////////
|
| -
|
| -type fakeGAECtxForNewKey string
|
| -
|
| -var _ = appengine.Context((fakeGAECtxForNewKey)(""))
|
| -
|
| -func (fakeGAECtxForNewKey) Debugf(format string, args ...interface{}) {}
|
| -func (fakeGAECtxForNewKey) Infof(format string, args ...interface{}) {}
|
| -func (fakeGAECtxForNewKey) Warningf(format string, args ...interface{}) {}
|
| -func (fakeGAECtxForNewKey) Errorf(format string, args ...interface{}) {}
|
| -func (fakeGAECtxForNewKey) Criticalf(format string, args ...interface{}) {}
|
| -func (fakeGAECtxForNewKey) Request() interface{} { return nil }
|
| -func (f fakeGAECtxForNewKey) Call(service, method string, in, out appengine_internal.ProtoMessage, opts *appengine_internal.CallOptions) error {
|
| - if service != "__go__" || method != "GetNamespace" {
|
| - panic(fmt.Errorf("fakeGAECtxForNewKey: cannot facilitate Call(%q, %q, ...)", service, method))
|
| - }
|
| - out.(*basepb.StringProto).Value = proto.String(string(f))
|
| - return nil
|
| -}
|
| -func (fakeGAECtxForNewKey) FullyQualifiedAppID() string { return "dev~my~app" }
|
| -
|
| -/////////////////////////////// Key construction ///////////////////////////////
|
| -
|
| -func newKey(ns, kind, stringID string, intID int64, parent *datastore.Key) *datastore.Key {
|
| - return datastore.NewKey(fakeGAECtxForNewKey(ns), kind, stringID, intID, parent)
|
| -}
|
| -func newKeyObjError(ns string, knr goon.KindNameResolver, src interface{}) (*datastore.Key, error) {
|
| - return (&goon.Goon{
|
| - Context: fakeGAECtxForNewKey(ns),
|
| - KindNameResolver: knr}).KeyError(src)
|
| -}
|
| -func newKeyObj(ns string, knr goon.KindNameResolver, obj interface{}) *datastore.Key {
|
| - k, err := newKeyObjError(ns, knr, obj)
|
| - if err != nil {
|
| - panic(err)
|
| - }
|
| - return k
|
| -}
|
| -func kind(ns string, knr goon.KindNameResolver, src interface{}) string {
|
| - return newKeyObj(ns, knr, src).Kind()
|
| -}
|
| -
|
| -/////////////////////////////// Binary Encoding ////////////////////////////////
|
| -
|
| -type keyTok struct {
|
| - kind string
|
| - intID uint64
|
| - stringID string
|
| -}
|
| -
|
| -func keyToToks(key *datastore.Key) (namespace string, ret []*keyTok) {
|
| - var inner func(*datastore.Key)
|
| - inner = func(k *datastore.Key) {
|
| - if k.Parent() != nil {
|
| - inner(k.Parent())
|
| - }
|
| - ret = append(ret, &keyTok{k.Kind(), uint64(k.IntID()), k.StringID()})
|
| - }
|
| - inner(key)
|
| - namespace = key.Namespace()
|
| - return
|
| -}
|
| -
|
| -func toksToKey(ns string, toks []*keyTok) (ret *datastore.Key) {
|
| - for _, t := range toks {
|
| - ret = newKey(ns, t.kind, t.stringID, int64(t.intID), ret)
|
| - }
|
| - return
|
| -}
|
| -
|
| -type nsOption bool
|
| -
|
| -const (
|
| - withNS nsOption = true
|
| - noNS = false
|
| -)
|
| -
|
| -func keyBytes(nso nsOption, k *datastore.Key) []byte {
|
| - buf := &bytes.Buffer{}
|
| - writeKey(buf, nso, k)
|
| - return buf.Bytes()
|
| -}
|
| -
|
| -func keyFromByteString(nso nsOption, d string, ns string) (*datastore.Key, error) {
|
| - return readKey(bytes.NewBufferString(d), nso, ns)
|
| -}
|
| -
|
| -func writeKey(buf *bytes.Buffer, nso nsOption, k *datastore.Key) {
|
| - // namespace ++ #tokens ++ [tok.kind ++ tok.stringID ++ tok.intID?]*
|
| - namespace, toks := keyToToks(k)
|
| - if nso == withNS {
|
| - writeString(buf, namespace)
|
| - }
|
| - cmpbin.WriteUint(buf, uint64(len(toks)))
|
| - for _, tok := range toks {
|
| - writeString(buf, tok.kind)
|
| - writeString(buf, tok.stringID)
|
| - if tok.stringID == "" {
|
| - cmpbin.WriteUint(buf, tok.intID)
|
| - }
|
| - }
|
| -}
|
| -
|
| -func readKey(buf *bytes.Buffer, nso nsOption, ns string) (*datastore.Key, error) {
|
| - namespace := ns
|
| - if nso == withNS {
|
| - err := error(nil)
|
| - if namespace, err = readString(buf); err != nil {
|
| - return nil, err
|
| - }
|
| - }
|
| -
|
| - numToks, _, err := cmpbin.ReadUint(buf)
|
| - if err != nil {
|
| - return nil, err
|
| - }
|
| - if numToks > keyNumToksReasonableLimit {
|
| - return nil, fmt.Errorf("readKey: tried to decode huge key of length %d", numToks)
|
| - }
|
| -
|
| - toks := make([]*keyTok, numToks)
|
| - for i := uint64(0); i < numToks; i++ {
|
| - tok := &keyTok{}
|
| - if tok.kind, err = readString(buf); err != nil {
|
| - return nil, err
|
| - }
|
| - if tok.stringID, err = readString(buf); err != nil {
|
| - return nil, err
|
| - }
|
| - if tok.stringID == "" {
|
| - if tok.intID, _, err = cmpbin.ReadUint(buf); err != nil {
|
| - return nil, err
|
| - }
|
| - if tok.intID == 0 {
|
| - return nil, errors.New("readKey: decoded key with empty stringID and empty intID")
|
| - }
|
| - }
|
| - toks[i] = tok
|
| - }
|
| -
|
| - return toksToKey(namespace, toks), nil
|
| -}
|
| -
|
| -//////////////////////////////// Key utilities /////////////////////////////////
|
| -
|
| -func rootKey(key *datastore.Key) *datastore.Key {
|
| - for key.Parent() != nil {
|
| - key = key.Parent()
|
| - }
|
| - return key
|
| -}
|
| -
|
| -type keyValidOption bool
|
| -
|
| -const (
|
| - // userKeyOnly is used with keyValid, and ensures that the key is only one
|
| - // that's valid for a user program to write to.
|
| - userKeyOnly keyValidOption = false
|
| -
|
| - // allowSpecialKeys is used with keyValid, and allows keys for special
|
| - // metadata objects (like "__entity_group__").
|
| - allowSpecialKeys = true
|
| -)
|
| -
|
| -// keyValid checks to see if a key is valid by applying a bunch of constraint
|
| -// rules to it (e.g. can't have StringID and IntID set at the same time, can't
|
| -// have a parent key which is Incomplete(), etc.)
|
| -//
|
| -// It verifies that the key is also in the provided namespace. It can also
|
| -// reject keys which are 'special' e.g. have a Kind starting with "__". This
|
| -// behavior is controllable with opt.
|
| -func keyValid(ns string, k *datastore.Key, opt keyValidOption) bool {
|
| - // copied from the appengine SDK because why would any user program need to
|
| - // see if a key is valid? /s
|
| - if k == nil {
|
| - return false
|
| - }
|
| - // since we do "client-side" validation of namespaces, check this here.
|
| - if k.Namespace() != ns {
|
| - return false
|
| - }
|
| - for ; k != nil; k = k.Parent() {
|
| - if opt == userKeyOnly && len(k.Kind()) >= 2 && k.Kind()[:2] == "__" { // reserve all Kinds starting with __
|
| - return false
|
| - }
|
| - if k.Kind() == "" || k.AppID() == "" {
|
| - return false
|
| - }
|
| - if k.StringID() != "" && k.IntID() != 0 {
|
| - return false
|
| - }
|
| - if k.Parent() != nil {
|
| - if k.Parent().Incomplete() {
|
| - return false
|
| - }
|
| - if k.Parent().AppID() != k.AppID() || k.Parent().Namespace() != k.Namespace() {
|
| - return false
|
| - }
|
| - }
|
| - }
|
| - return true
|
| -}
|
| -
|
| -// keyCouldBeValid is like keyValid, but it allows for the possibility that the
|
| -// last token of the key is Incomplete(). It returns true if the Key will become
|
| -// valid once it recieves an automatically-assigned ID.
|
| -func keyCouldBeValid(ns string, k *datastore.Key, opt keyValidOption) bool {
|
| - // adds an id to k if it's incomplete.
|
| - if k.Incomplete() {
|
| - k = newKey(ns, k.Kind(), "", 1, k.Parent())
|
| - }
|
| - return keyValid(ns, k, opt)
|
| -}
|
|
|