| Index: go/src/infra/gae/libs/gae/upstream_errors.go
 | 
| diff --git a/go/src/infra/gae/libs/gae/upstream_errors.go b/go/src/infra/gae/libs/gae/upstream_errors.go
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..f6ebad5538ae2b3dd14ae34b0f3f6766cb8a9cf5
 | 
| --- /dev/null
 | 
| +++ b/go/src/infra/gae/libs/gae/upstream_errors.go
 | 
| @@ -0,0 +1,109 @@
 | 
| +// 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.
 | 
| +
 | 
| +// This file contains types and values which are mirrors/duplicates of the
 | 
| +// upstream SDK errors. This exists so that users can depend solely on this
 | 
| +// wrapper library without also needing to import the SDK.
 | 
| +//
 | 
| +// Format of the errors is Err<sub>Name, where <sub> is one of the 2/3-letter
 | 
| +// All Caps subpackage codes (e.g. DS, TQ, MC, etc.). Name is the same as the
 | 
| +// original SDK error.
 | 
| +//
 | 
| +// Note that this only replicates the 'named' errors (which a user might compare
 | 
| +// for equality or observe by-type in their code like ErrDSNoSuchEntity). The
 | 
| +// underlying implementations can (and do) return many more sorts of non-named
 | 
| +// and custom errors.
 | 
| +
 | 
| +package gae
 | 
| +
 | 
| +import (
 | 
| +	"fmt"
 | 
| +	"reflect"
 | 
| +
 | 
| +	"google.golang.org/appengine/datastore"
 | 
| +	"google.golang.org/appengine/memcache"
 | 
| +	"google.golang.org/appengine/taskqueue"
 | 
| +)
 | 
| +
 | 
| +// These are pass-through versions from the managed-VM SDK. All implementations
 | 
| +// must return these (exact) errors (not just an error with the same text).
 | 
| +var (
 | 
| +	ErrDSInvalidEntityType     = datastore.ErrInvalidEntityType
 | 
| +	ErrDSInvalidKey            = datastore.ErrInvalidKey
 | 
| +	ErrDSNoSuchEntity          = datastore.ErrNoSuchEntity
 | 
| +	ErrDSConcurrentTransaction = datastore.ErrConcurrentTransaction
 | 
| +	ErrDSQueryDone             = datastore.Done
 | 
| +
 | 
| +	ErrMCCacheMiss   = memcache.ErrCacheMiss
 | 
| +	ErrMCCASConflict = memcache.ErrCASConflict
 | 
| +	ErrMCNoStats     = memcache.ErrNoStats
 | 
| +	ErrMCNotStored   = memcache.ErrNotStored
 | 
| +	ErrMCServerError = memcache.ErrServerError
 | 
| +
 | 
| +	ErrTQTaskAlreadyAdded = taskqueue.ErrTaskAlreadyAdded
 | 
| +)
 | 
| +
 | 
| +/////////////////////////////// Supporting code ////////////////////////////////
 | 
| +
 | 
| +// MultiError is returned by batch operations when there are errors with
 | 
| +// particular elements. Errors will be in a one-to-one correspondence with
 | 
| +// the input elements; successful elements will have a nil entry.
 | 
| +type MultiError []error
 | 
| +
 | 
| +func (m MultiError) Error() string {
 | 
| +	s, n := "", 0
 | 
| +	for _, e := range m {
 | 
| +		if e != nil {
 | 
| +			if n == 0 {
 | 
| +				s = e.Error()
 | 
| +			}
 | 
| +			n++
 | 
| +		}
 | 
| +	}
 | 
| +	switch n {
 | 
| +	case 0:
 | 
| +		return "(0 errors)"
 | 
| +	case 1:
 | 
| +		return s
 | 
| +	case 2:
 | 
| +		return s + " (and 1 other error)"
 | 
| +	}
 | 
| +	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
 | 
| +}
 | 
| +
 | 
| +// SingleError provides a simple way to uwrap a MultiError if you know that it
 | 
| +// could only ever contain one element.
 | 
| +//
 | 
| +// If err is a MultiError, return its first element. Otherwise, return err.
 | 
| +func SingleError(err error) error {
 | 
| +	if me, ok := err.(MultiError); ok {
 | 
| +		if len(me) == 0 {
 | 
| +			return nil
 | 
| +		}
 | 
| +		return me[0]
 | 
| +	}
 | 
| +	return err
 | 
| +}
 | 
| +
 | 
| +var (
 | 
| +	multiErrorType = reflect.TypeOf(MultiError(nil))
 | 
| +)
 | 
| +
 | 
| +// FixError will convert a backend-specific non-plain error type to the
 | 
| +// corresponding gae wrapper type. This is intended to be used solely by
 | 
| +// implementations (not user code). A correct implementation of the gae wrapper
 | 
| +// should never return an SDK-specific error type if an alternate type appears
 | 
| +// in this file.
 | 
| +func FixError(err error) error {
 | 
| +	if err != nil {
 | 
| +		// we know that err already conforms to the error interface (or the caller's
 | 
| +		// method wouldn't compile), so check to see if the error's underlying type
 | 
| +		// looks like one of the special error types we implement.
 | 
| +		v := reflect.ValueOf(err)
 | 
| +		if v.Type().ConvertibleTo(multiErrorType) {
 | 
| +			err = v.Convert(multiErrorType).Interface().(error)
 | 
| +		}
 | 
| +	}
 | 
| +	return err
 | 
| +}
 | 
| 
 |