<commit_before>// Copyright 2019 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package memdocstore provides an in-memory implementation of the docstore
// API. It is suitable for local development and testing.
//
// Every document in a memdocstore collection has a unique primary key. The primary
// key values need not be strings; they may be any comparable Go value.
//
// URLs
//
// For docstore.OpenCollection, memdocstore registers for the scheme
// "mem".
// To customize the URL opener, or for more details on the URL format,
// see URLOpener.
// See https://godoc.org/gocloud.dev#hdr-URLs for background information.
package memdocstore // import "gocloud.dev/internal/docstore/memdocstore"

import (
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"

	"gocloud.dev/gcerrors"
	"gocloud.dev/internal/docstore"
	"gocloud.dev/internal/docstore/driver"
	"gocloud.dev/internal/gcerr"
)

func init() {
	docstore.DefaultURLMux().RegisterCollection(Scheme, &URLOpener{})
}

// Scheme is the URL scheme memdocstore registers its URLOpener under on
// docstore.DefaultMux.
const Scheme = "mem"

// URLOpener opens URLs like "mem://_id".
//
// The URL's host is used as the keyField.
// The URL's path is ignored.
//
// No query parameters are supported.
type URLOpener struct{}

// OpenCollectionURL opens a docstore.Collection based on u.
func (*URLOpener) OpenCollectionURL(ctx context.Context, u *url.URL) (*docstore.Collection, error) {
	for param := range u.Query() {
		return nil, fmt.Errorf("open collection %v: invalid query parameter %q", u, param)
	}
	return OpenCollection(u.Host, nil)
}

// Options are optional arguments to the OpenCollection functions.
type Options struct{}

// TODO(jba): make this package thread-safe.

// OpenCollection creates a *docstore.Collection backed by memory. keyField is the
// document field holding the primary key of the collection.
func OpenCollection(keyField string, _ *Options) (*docstore.Collection, error) {
	c, err := newCollection(keyField, nil)
	if err != nil {
		return nil, err
	}
	return docstore.NewCollection(c), nil
}

// OpenCollectionWithKeyFunc creates a *docstore.Collection backed by memory. keyFunc takes
// a document and returns the document's primary key. It should return nil if the
// document is missing the information to construct a key. This will cause all
// actions, even Create, to fail.
func OpenCollectionWithKeyFunc(keyFunc func(docstore.Document) interface{}, _ *Options) (*docstore.Collection, error) {
	c, err := newCollection("", keyFunc)
	if err != nil {
		return nil, err
	}
	return docstore.NewCollection(c), nil
}

func newCollection(keyField string, keyFunc func(docstore.Document) interface{}) (driver.Collection, error) {
	if keyField == "" && keyFunc == nil {
		return nil, gcerr.Newf(gcerr.InvalidArgument, nil, "must provide either keyField or keyFunc")
	}
	return &collection{
		keyField:     keyField,
		keyFunc:      keyFunc,
		docs:         map[interface{}]map[string]interface{}{},
		nextRevision: 1,
	}, nil
}

type collection struct {
	keyField string
	keyFunc  func(docstore.Document) interface{}
	// map from keys to documents. Documents are represented as map[string]interface{},
	// regardless of what their original representation is. Even if the user is using
	// map[string]interface{}, we make our own copy.
	docs         map[interface{}]map[string]interface{}
	nextRevision int64 // incremented on each write
}

// ErrorCode implements driver.ErrorCode.
func (c *collection) ErrorCode(err error) gcerr.ErrorCode {
	return gcerrors.Code(err)
}

// RunActions implements driver.RunActions.
func (c *collection) RunActions(ctx context.Context, actions []*driver.Action, unordered bool) driver.ActionListError {
	if unordered {
		panic("unordered unimplemented")
	}
	// Run each action in order, stopping at the first error.
	for i, a := range actions {
		if err := c.runAction(ctx, a); err != nil {
			return driver.ActionListError{{i, err}}
		}
	}
	return nil
}

// runAction executes a single action.
func (c *collection) runAction(ctx context.Context, a *driver.Action) error {
	// Stop if the context is done.
	if ctx.Err() != nil {
		return ctx.Err()
	}
	// Get the key from the doc so we can look it up in the map.
	key := c.key(a.Doc)
	if key == nil && (a.Kind != driver.Create || c.keyField == "") {
		return gcerr.Newf(gcerr.InvalidArgument, nil, "missing key field")
	}
	// If there is a key, get the current document with that key.
	var (
		current map[string]interface{}
		exists  bool
	)
	if key != nil {
		current, exists = c.docs[key]
	}
	// Check for a NotFound error.
	if !exists && (a.Kind == driver.Replace || a.Kind == driver.Update || a.Kind == driver.Get) {
		return gcerr.Newf(gcerr.NotFound, nil, "document with key %v does not exist", key)
	}
	switch a.Kind {
	case driver.Create:
		// It is an error to attempt to create an existing document.
		if exists {
			return gcerr.Newf(gcerr.AlreadyExists, nil, "Create: document with key %v exists", key)
		}
		// If the user didn't supply a value for the key field, create a new one.
		if key == nil && c.keyField != "" {
			key = driver.UniqueString()
			// Set the new key in the document.
			if err := a.Doc.SetField(c.keyField, key); err != nil {
				return gcerr.Newf(gcerr.InvalidArgument, nil, "cannot set key field %q", c.keyField)
			}
		}
		fallthrough

	case driver.Replace, driver.Put:
		if err := checkRevision(a.Doc, current); err != nil {
			return err
		}
		doc, err := encodeDoc(a.Doc)
		if err != nil {
			return err
		}
		c.changeRevision(doc)
		c.docs[key] = doc

	case driver.Delete:
		if err := checkRevision(a.Doc, current); err != nil {
			return err
		}
		delete(c.docs, key)

	case driver.Update:
		if err := checkRevision(a.Doc, current); err != nil {
			return err
		}
		if err := c.update(current, a.Mods); err != nil {
			return err
		}

	case driver.Get:
		// We've already retrieved the document into current, above.
		// Now we copy its fields into the user-provided document.
		if err := decodeDoc(current, a.Doc, a.FieldPaths); err != nil {
			return err
		}
	default:
		return gcerr.Newf(gcerr.Internal, nil, "unknown kind %v", a.Kind)
	}
	return nil
}

func (c *collection) update(doc map[string]interface{}, mods []driver.Mod) error {
	// Apply each modification. Fail if any mod would fail.
	// Sort mods by first field path element so tests are deterministic.
	sort.Slice(mods, func(i, j int) bool { return mods[i].FieldPath[0] < mods[j].FieldPath[0] })

	// Check first that every field path is valid. That is, whether every component
	// of the path but the last refers to a map, and no component along the way is
	// nil. If that check succeeds, all actions will succeed, making update atomic.
	for _, m := range mods {
		if _, err := getParentMap(doc, m.FieldPath, false); err != nil {
			return err
		}
	}
	for _, m := range mods {
		if m.Value == nil {
			deleteAtFieldPath(doc, m.FieldPath)
		} else {
			// This can't fail because we checked it above.
			_ = setAtFieldPath(doc, m.FieldPath, m.Value)
		}
	}
	if len(mods) > 0 {
		c.changeRevision(doc)
	}
	return nil
}

func (c *collection) key(doc driver.Document) interface{} {
	if c.keyField != "" {
		key, _ := doc.GetField(c.keyField) // ignore error because key will be nil
		return key
	}
	return c.keyFunc(doc.Origin)
}

func (c *collection) changeRevision(doc map[string]interface{}) {
	c.nextRevision++
	doc[docstore.RevisionField] = c.nextRevision
}

func checkRevision(arg driver.Document, current map[string]interface{}) error {
	if current == nil {
		return nil // no existing document
	}
	curRev := current[docstore.RevisionField].(int64)
	r, err := arg.GetField(docstore.RevisionField)
	if err != nil || r == nil {
		return nil // no incoming revision information: nothing to check
	}
	wantRev, ok := r.(int64)
	if !ok {
		return gcerr.Newf(gcerr.InvalidArgument, nil, "revision field %s is not an int64", docstore.RevisionField)
	}
	if wantRev != curRev {
		return gcerr.Newf(gcerr.FailedPrecondition, nil, "mismatched revisions: want %d, current %d", wantRev, curRev)
	}
	return nil
}

// getAtFieldPath gets the value of m at fp. It returns an error if fp is invalid
// (see getParentMap).
func getAtFieldPath(m map[string]interface{}, fp []string) (interface{}, error) {
	m2, err := getParentMap(m, fp, false)
	if err != nil {
		return nil, err
	}
	return m2[fp[len(fp)-1]], nil
}

// setAtFieldPath sets m's value at fp to val. It creates intermediate maps as
// needed. It returns an error if a non-final component of fp does not denote a map.
func setAtFieldPath(m map[string]interface{}, fp []string, val interface{}) error {
	m2, err := getParentMap(m, fp, true)
	if err != nil {
		return err
	}
	m2[fp[len(fp)-1]] = val
	return nil
}

// Delete the value from m at the given field path, if it exists.
func deleteAtFieldPath(m map[string]interface{}, fp []string) {
	m2, _ := getParentMap(m, fp, false) // ignore error
	if m2 != nil {
		delete(m2, fp[len(fp)-1])
	}
}

// getParentMap returns the map that directly contains the given field path;
// that is, the value of m at the field path that excludes the last component
// of fp. If a non-map is encountered along the way, an InvalidArgument error is
// returned. If nil is encountered, nil is returned unless create is true, in
// which case a map is added at that point.
func getParentMap(m map[string]interface{}, fp []string, create bool) (map[string]interface{}, error) {
	var ok bool
	for _, k := range fp[:len(fp)-1] {
		if m[k] == nil {
			if !create {
				return nil, nil
			}
			m[k] = map[string]interface{}{}
		}
		m, ok = m[k].(map[string]interface{})
		if !ok {
			return nil, gcerr.Newf(gcerr.InvalidArgument, nil, "invalid field path %q at %q", strings.Join(fp, "."), k)
		}
	}
	return m, nil
}
<commit_msg>memdocstore: make thread-safe (#1889)<commit_after>// Copyright 2019 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package memdocstore provides an in-memory implementation of the docstore
// API. It is suitable for local development and testing.
//
// Every document in a memdocstore collection has a unique primary key. The primary
// key values need not be strings; they may be any comparable Go value.
//
// URLs
//
// For docstore.OpenCollection, memdocstore registers for the scheme
// "mem".
// To customize the URL opener, or for more details on the URL format,
// see URLOpener.
// See https://godoc.org/gocloud.dev#hdr-URLs for background information.
package memdocstore // import "gocloud.dev/internal/docstore/memdocstore"

import (
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"sync"

	"gocloud.dev/gcerrors"
	"gocloud.dev/internal/docstore"
	"gocloud.dev/internal/docstore/driver"
	"gocloud.dev/internal/gcerr"
)

func init() {
	docstore.DefaultURLMux().RegisterCollection(Scheme, &URLOpener{})
}

// Scheme is the URL scheme memdocstore registers its URLOpener under on
// docstore.DefaultMux.
const Scheme = "mem"

// URLOpener opens URLs like "mem://_id".
//
// The URL's host is used as the keyField.
// The URL's path is ignored.
//
// No query parameters are supported.
type URLOpener struct{}

// OpenCollectionURL opens a docstore.Collection based on u.
func (*URLOpener) OpenCollectionURL(ctx context.Context, u *url.URL) (*docstore.Collection, error) {
	for param := range u.Query() {
		return nil, fmt.Errorf("open collection %v: invalid query parameter %q", u, param)
	}
	return OpenCollection(u.Host, nil)
}

// Options are optional arguments to the OpenCollection functions.
type Options struct{}

// TODO(jba): make this package thread-safe.

// OpenCollection creates a *docstore.Collection backed by memory. keyField is the
// document field holding the primary key of the collection.
func OpenCollection(keyField string, _ *Options) (*docstore.Collection, error) {
	c, err := newCollection(keyField, nil)
	if err != nil {
		return nil, err
	}
	return docstore.NewCollection(c), nil
}

// OpenCollectionWithKeyFunc creates a *docstore.Collection backed by memory. keyFunc takes
// a document and returns the document's primary key. It should return nil if the
// document is missing the information to construct a key. This will cause all
// actions, even Create, to fail.
func OpenCollectionWithKeyFunc(keyFunc func(docstore.Document) interface{}, _ *Options) (*docstore.Collection, error) {
	c, err := newCollection("", keyFunc)
	if err != nil {
		return nil, err
	}
	return docstore.NewCollection(c), nil
}

func newCollection(keyField string, keyFunc func(docstore.Document) interface{}) (driver.Collection, error) {
	if keyField == "" && keyFunc == nil {
		return nil, gcerr.Newf(gcerr.InvalidArgument, nil, "must provide either keyField or keyFunc")
	}
	return &collection{
		keyField:     keyField,
		keyFunc:      keyFunc,
		docs:         map[interface{}]map[string]interface{}{},
		nextRevision: 1,
	}, nil
}

type collection struct {
	keyField string
	keyFunc  func(docstore.Document) interface{}
	mu       sync.Mutex
	// map from keys to documents. Documents are represented as map[string]interface{},
	// regardless of what their original representation is. Even if the user is using
	// map[string]interface{}, we make our own copy.
	docs         map[interface{}]map[string]interface{}
	nextRevision int64 // incremented on each write
}

// ErrorCode implements driver.ErrorCode.
func (c *collection) ErrorCode(err error) gcerr.ErrorCode {
	return gcerrors.Code(err)
}

// RunActions implements driver.RunActions.
func (c *collection) RunActions(ctx context.Context, actions []*driver.Action, unordered bool) driver.ActionListError {
	if unordered {
		panic("unordered unimplemented")
	}
	// Run each action in order, stopping at the first error.
	for i, a := range actions {
		if err := c.runAction(ctx, a); err != nil {
			return driver.ActionListError{{i, err}}
		}
	}
	return nil
}

// runAction executes a single action.
func (c *collection) runAction(ctx context.Context, a *driver.Action) error {
	// Stop if the context is done.
	if ctx.Err() != nil {
		return ctx.Err()
	}
	// Get the key from the doc so we can look it up in the map.
	key := c.key(a.Doc)
	if key == nil && (a.Kind != driver.Create || c.keyField == "") {
		return gcerr.Newf(gcerr.InvalidArgument, nil, "missing key field")
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	// If there is a key, get the current document with that key.
	var (
		current map[string]interface{}
		exists  bool
	)
	if key != nil {
		current, exists = c.docs[key]
	}
	// Check for a NotFound error.
	if !exists && (a.Kind == driver.Replace || a.Kind == driver.Update || a.Kind == driver.Get) {
		return gcerr.Newf(gcerr.NotFound, nil, "document with key %v does not exist", key)
	}
	switch a.Kind {
	case driver.Create:
		// It is an error to attempt to create an existing document.
		if exists {
			return gcerr.Newf(gcerr.AlreadyExists, nil, "Create: document with key %v exists", key)
		}
		// If the user didn't supply a value for the key field, create a new one.
		if key == nil && c.keyField != "" {
			key = driver.UniqueString()
			// Set the new key in the document.
			if err := a.Doc.SetField(c.keyField, key); err != nil {
				return gcerr.Newf(gcerr.InvalidArgument, nil, "cannot set key field %q", c.keyField)
			}
		}
		fallthrough

	case driver.Replace, driver.Put:
		if err := checkRevision(a.Doc, current); err != nil {
			return err
		}
		doc, err := encodeDoc(a.Doc)
		if err != nil {
			return err
		}
		c.changeRevision(doc)
		c.docs[key] = doc

	case driver.Delete:
		if err := checkRevision(a.Doc, current); err != nil {
			return err
		}
		delete(c.docs, key)

	case driver.Update:
		if err := checkRevision(a.Doc, current); err != nil {
			return err
		}
		if err := c.update(current, a.Mods); err != nil {
			return err
		}

	case driver.Get:
		// We've already retrieved the document into current, above.
		// Now we copy its fields into the user-provided document.
		if err := decodeDoc(current, a.Doc, a.FieldPaths); err != nil {
			return err
		}
	default:
		return gcerr.Newf(gcerr.Internal, nil, "unknown kind %v", a.Kind)
	}
	return nil
}

// Must be called with the lock held.
func (c *collection) update(doc map[string]interface{}, mods []driver.Mod) error {
	// Apply each modification. Fail if any mod would fail.
	// Sort mods by first field path element so tests are deterministic.
	sort.Slice(mods, func(i, j int) bool { return mods[i].FieldPath[0] < mods[j].FieldPath[0] })

	// Check first that every field path is valid. That is, whether every component
	// of the path but the last refers to a map, and no component along the way is
	// nil. If that check succeeds, all actions will succeed, making update atomic.
	for _, m := range mods {
		if _, err := getParentMap(doc, m.FieldPath, false); err != nil {
			return err
		}
	}
	for _, m := range mods {
		if m.Value == nil {
			deleteAtFieldPath(doc, m.FieldPath)
		} else {
			// This can't fail because we checked it above.
			_ = setAtFieldPath(doc, m.FieldPath, m.Value)
		}
	}
	if len(mods) > 0 {
		c.changeRevision(doc)
	}
	return nil
}

func (c *collection) key(doc driver.Document) interface{} {
	if c.keyField != "" {
		key, _ := doc.GetField(c.keyField) // ignore error because key will be nil
		return key
	}
	return c.keyFunc(doc.Origin)
}

// Must be called with the lock held.
func (c *collection) changeRevision(doc map[string]interface{}) {
	c.nextRevision++
	doc[docstore.RevisionField] = c.nextRevision
}

func checkRevision(arg driver.Document, current map[string]interface{}) error {
	if current == nil {
		return nil // no existing document
	}
	curRev := current[docstore.RevisionField].(int64)
	r, err := arg.GetField(docstore.RevisionField)
	if err != nil || r == nil {
		return nil // no incoming revision information: nothing to check
	}
	wantRev, ok := r.(int64)
	if !ok {
		return gcerr.Newf(gcerr.InvalidArgument, nil, "revision field %s is not an int64", docstore.RevisionField)
	}
	if wantRev != curRev {
		return gcerr.Newf(gcerr.FailedPrecondition, nil, "mismatched revisions: want %d, current %d", wantRev, curRev)
	}
	return nil
}

// getAtFieldPath gets the value of m at fp. It returns an error if fp is invalid
// (see getParentMap).
func getAtFieldPath(m map[string]interface{}, fp []string) (interface{}, error) {
	m2, err := getParentMap(m, fp, false)
	if err != nil {
		return nil, err
	}
	return m2[fp[len(fp)-1]], nil
}

// setAtFieldPath sets m's value at fp to val. It creates intermediate maps as
// needed. It returns an error if a non-final component of fp does not denote a map.
func setAtFieldPath(m map[string]interface{}, fp []string, val interface{}) error {
	m2, err := getParentMap(m, fp, true)
	if err != nil {
		return err
	}
	m2[fp[len(fp)-1]] = val
	return nil
}

// Delete the value from m at the given field path, if it exists.
func deleteAtFieldPath(m map[string]interface{}, fp []string) {
	m2, _ := getParentMap(m, fp, false) // ignore error
	if m2 != nil {
		delete(m2, fp[len(fp)-1])
	}
}

// getParentMap returns the map that directly contains the given field path;
// that is, the value of m at the field path that excludes the last component
// of fp. If a non-map is encountered along the way, an InvalidArgument error is
// returned. If nil is encountered, nil is returned unless create is true, in
// which case a map is added at that point.
func getParentMap(m map[string]interface{}, fp []string, create bool) (map[string]interface{}, error) {
	var ok bool
	for _, k := range fp[:len(fp)-1] {
		if m[k] == nil {
			if !create {
				return nil, nil
			}
			m[k] = map[string]interface{}{}
		}
		m, ok = m[k].(map[string]interface{})
		if !ok {
			return nil, gcerr.Newf(gcerr.InvalidArgument, nil, "invalid field path %q at %q", strings.Join(fp, "."), k)
		}
	}
	return m, nil
}
<|endoftext|>


<commit_before>package globalref

import (
	"fmt"

	"github.com/hashicorp/terraform/internal/addrs"
)

// Reference combines an addrs.Reference with the address of the module
// instance or resource instance where it was found.
//
// Because of the design of the Terraform language, our main model of
// references only captures the module-local part of the reference and assumes
// that it's always clear from context which module a reference belongs to.
// That's not true for globalref because our whole purpose is to work across
// module boundaries, and so this package in particular has its own
// representation of references.
type Reference struct {
	// ContainerAddr is always either addrs.ModuleInstance or
	// addrs.AbsResourceInstance. The latter is required if LocalRef's
	// subject is either an addrs.CountAddr or addrs.ForEachAddr, so
	// we can know which resource's repetition expression it's
	// referring to.
	ContainerAddr addrs.Targetable

	// LocalRef is a reference that would be resolved in the context
	// of the module instance or resource instance given in ContainerAddr.
	LocalRef *addrs.Reference
}

func absoluteRef(containerAddr addrs.Targetable, localRef *addrs.Reference) Reference {
	ret := Reference{
		ContainerAddr: containerAddr,
		LocalRef:      localRef,
	}
	// For simplicity's sake, we always reduce the ContainerAddr to be
	// just the module address unless it's a count.index, each.key, or
	// each.value reference, because for anything else it's immaterial
	// which resource it belongs to.
	switch localRef.Subject.(type) {
	case addrs.CountAttr, addrs.ForEachAttr:
		// nothing to do
	default:
		ret.ContainerAddr = ret.ModuleAddr()
	}
	return ret
}

func absoluteRefs(containerAddr addrs.Targetable, refs []*addrs.Reference) []Reference {
	if len(refs) == 0 {
		return nil
	}

	ret := make([]Reference, len(refs))
	for i, ref := range refs {
		ret[i] = absoluteRef(containerAddr, ref)
	}
	return ret
}

// ModuleAddr returns the address of the module where the reference would
// be resolved.
//
// This is either ContainerAddr directly if it's already just a module
// instance, or the module instance part of it if it's a resource instance.
func (r Reference) ModuleAddr() addrs.ModuleInstance {
	switch addr := r.ContainerAddr.(type) {
	case addrs.ModuleInstance:
		return addr
	case addrs.AbsResourceInstance:
		return addr.Module
	default:
		// NOTE: We're intentionally using only a subset of possible
		// addrs.Targetable implementations here, so anything else
		// is invalid.
		panic(fmt.Sprintf("reference has invalid container address type %T", addr))
	}
}

// ResourceAddr returns the address of the resource where the reference
// would be resolved, if there is one.
//
// Because not all references belong to resources, the extra boolean return
// value indicates whether the returned address is valid.
func (r Reference) ResourceAddr() (addrs.AbsResource, bool) {
	switch addr := r.ContainerAddr.(type) {
	case addrs.ModuleInstance:
		return addrs.AbsResource{}, false
	case addrs.AbsResourceInstance:
		return addr.ContainingResource(), true
	default:
		// NOTE: We're intentionally using only a subset of possible
		// addrs.Targetable implementations here, so anything else
		// is invalid.
		panic(fmt.Sprintf("reference has invalid container address type %T", addr))
	}
}

// DebugString returns an internal (but still somewhat Terraform-language-like)
// compact string representation of the reciever, which isn't an address that
// any of our usual address parsers could accept but still captures the
// essence of what the reference represents.
//
// The DebugString result is not suitable for end-user-oriented messages.
//
// DebugString is also not suitable for use as a unique key for a reference,
// because it's ambiguous (between a no-key resource instance and a resource)
// and because it discards the source location information in the LocalRef.
func (r Reference) DebugString() string {
	// As the doc comment insinuates, we don't have any real syntax for
	// "absolute references": references are always local, and targets are
	// always absolute but only include modules and resources.
	return r.ContainerAddr.String() + "::" + r.LocalRef.DisplayString()
}

// addrKey returns the referenceAddrKey value for the item that
// this reference refers to, discarding any source location information.
//
// See the referenceAddrKey doc comment for more information on what this
// is suitable for.
func (r Reference) addrKey() referenceAddrKey {
	// This is a pretty arbitrary bunch of stuff. We include the type here
	// just to differentiate between no-key resource instances and resources.
	return referenceAddrKey(fmt.Sprintf("%s(%T)%s", r.ContainerAddr.String(), r.LocalRef.Subject, r.LocalRef.DisplayString()))
}

// referenceAddrKey is a special string type which conventionally contains
// a unique string representation of the object that a reference refers to,
// although not of the reference itself because it ignores the information
// that would differentiate two different references to the same object.
//
// The actual content of a referenceAddrKey is arbitrary, for internal use
// only. and subject to change in future. We use a named type here only to
// make it easier to see when we're intentionally using strings to uniquely
// identify absolute reference addresses.
type referenceAddrKey string
<commit_msg>ResourceAddr may have resources in LocalRef<commit_after>package globalref

import (
	"fmt"

	"github.com/hashicorp/terraform/internal/addrs"
)

// Reference combines an addrs.Reference with the address of the module
// instance or resource instance where it was found.
//
// Because of the design of the Terraform language, our main model of
// references only captures the module-local part of the reference and assumes
// that it's always clear from context which module a reference belongs to.
// That's not true for globalref because our whole purpose is to work across
// module boundaries, and so this package in particular has its own
// representation of references.
type Reference struct {
	// ContainerAddr is always either addrs.ModuleInstance or
	// addrs.AbsResourceInstance. The latter is required if LocalRef's
	// subject is either an addrs.CountAddr or addrs.ForEachAddr, so
	// we can know which resource's repetition expression it's
	// referring to.
	ContainerAddr addrs.Targetable

	// LocalRef is a reference that would be resolved in the context
	// of the module instance or resource instance given in ContainerAddr.
	LocalRef *addrs.Reference
}

func absoluteRef(containerAddr addrs.Targetable, localRef *addrs.Reference) Reference {
	ret := Reference{
		ContainerAddr: containerAddr,
		LocalRef:      localRef,
	}
	// For simplicity's sake, we always reduce the ContainerAddr to be
	// just the module address unless it's a count.index, each.key, or
	// each.value reference, because for anything else it's immaterial
	// which resource it belongs to.
	switch localRef.Subject.(type) {
	case addrs.CountAttr, addrs.ForEachAttr:
		// nothing to do
	default:
		ret.ContainerAddr = ret.ModuleAddr()
	}
	return ret
}

func absoluteRefs(containerAddr addrs.Targetable, refs []*addrs.Reference) []Reference {
	if len(refs) == 0 {
		return nil
	}

	ret := make([]Reference, len(refs))
	for i, ref := range refs {
		ret[i] = absoluteRef(containerAddr, ref)
	}
	return ret
}

// ModuleAddr returns the address of the module where the reference would
// be resolved.
//
// This is either ContainerAddr directly if it's already just a module
// instance, or the module instance part of it if it's a resource instance.
func (r Reference) ModuleAddr() addrs.ModuleInstance {
	switch addr := r.ContainerAddr.(type) {
	case addrs.ModuleInstance:
		return addr
	case addrs.AbsResourceInstance:
		return addr.Module
	default:
		// NOTE: We're intentionally using only a subset of possible
		// addrs.Targetable implementations here, so anything else
		// is invalid.
		panic(fmt.Sprintf("reference has invalid container address type %T", addr))
	}
}

// ResourceAddr returns the address of the resource where the reference
// would be resolved, if there is one.
//
// Because not all references belong to resources, the extra boolean return
// value indicates whether the returned address is valid.
func (r Reference) ResourceAddr() (addrs.AbsResource, bool) {
	moduleInstance := addrs.RootModuleInstance

	switch container := r.ContainerAddr.(type) {
	case addrs.ModuleInstance:
		moduleInstance = container

		switch ref := r.LocalRef.Subject.(type) {
		case addrs.Resource:
			return ref.Absolute(moduleInstance), true
		case addrs.ResourceInstance:
			return ref.ContainingResource().Absolute(moduleInstance), true
		}

		return addrs.AbsResource{}, false

	case addrs.AbsResourceInstance:
		return container.ContainingResource(), true
	default:
		// NOTE: We're intentionally using only a subset of possible
		// addrs.Targetable implementations here, so anything else
		// is invalid.
		panic(fmt.Sprintf("reference has invalid container address type %T", container))
	}
}

// DebugString returns an internal (but still somewhat Terraform-language-like)
// compact string representation of the reciever, which isn't an address that
// any of our usual address parsers could accept but still captures the
// essence of what the reference represents.
//
// The DebugString result is not suitable for end-user-oriented messages.
//
// DebugString is also not suitable for use as a unique key for a reference,
// because it's ambiguous (between a no-key resource instance and a resource)
// and because it discards the source location information in the LocalRef.
func (r Reference) DebugString() string {
	// As the doc comment insinuates, we don't have any real syntax for
	// "absolute references": references are always local, and targets are
	// always absolute but only include modules and resources.
	return r.ContainerAddr.String() + "::" + r.LocalRef.DisplayString()
}

// addrKey returns the referenceAddrKey value for the item that
// this reference refers to, discarding any source location information.
//
// See the referenceAddrKey doc comment for more information on what this
// is suitable for.
func (r Reference) addrKey() referenceAddrKey {
	// This is a pretty arbitrary bunch of stuff. We include the type here
	// just to differentiate between no-key resource instances and resources.
	return referenceAddrKey(fmt.Sprintf("%s(%T)%s", r.ContainerAddr.String(), r.LocalRef.Subject, r.LocalRef.DisplayString()))
}

// referenceAddrKey is a special string type which conventionally contains
// a unique string representation of the object that a reference refers to,
// although not of the reference itself because it ignores the information
// that would differentiate two different references to the same object.
//
// The actual content of a referenceAddrKey is arbitrary, for internal use
// only. and subject to change in future. We use a named type here only to
// make it easier to see when we're intentionally using strings to uniquely
// identify absolute reference addresses.
type referenceAddrKey string
<|endoftext|>


<commit_before>package printer

import (
	"fmt"
	"strconv"

	"github.com/heptio/developer-dash/internal/view/component"
	"github.com/heptio/developer-dash/internal/view/flexlayout"
	"github.com/pkg/errors"

	batchv1beta1 "k8s.io/api/batch/v1beta1"
)

// CronJobListHandler is a printFunc that lists cronjobs
func CronJobListHandler(list *batchv1beta1.CronJobList, opts Options) (component.ViewComponent, error) {
	if list == nil {
		return nil, errors.New("nil list")
	}

	cols := component.NewTableCols("Name", "Labels", "Schedule", "Age")
	tbl := component.NewTable("CronJobs", cols)

	for _, c := range list.Items {
		row := component.TableRow{}
		cronjobPath := gvkPath(c.Namespace, c.TypeMeta.APIVersion, c.TypeMeta.Kind, c.Name)
		row["Name"] = component.NewLink("", c.Name, cronjobPath)
		row["Labels"] = component.NewLabels(c.Labels)

		row["Schedule"] = component.NewText(c.Spec.Schedule)

		ts := c.CreationTimestamp.Time
		row["Age"] = component.NewTimestamp(ts)

		tbl.Add(row)
	}

	return tbl, nil
}

// CronJobHandler is a printFunc that prints a CronJob
func CronJobHandler(c *batchv1beta1.CronJob, opts Options) (component.ViewComponent, error) {
	fl := flexlayout.New()

	configSection := fl.AddSection()
	cronjobConfigGen := NewCronJobConfiguration(c)
	configView, err := cronjobConfigGen.Create()
	if err != nil {
		return nil, err
	}

	if err := configSection.Add(configView, 14); err != nil {
		return nil, errors.Wrap(err, "add cronjob config to layout")
	}

	jobListSection := fl.AddSection()
	jobListTable, err := createJobListView(c, opts)
	if err != nil {
		return nil, errors.Wrap(err, "create job list for cronjob")
	}
	if err := jobListSection.Add(jobListTable, 24); err != nil {
		return nil, errors.Wrap(err, "add job list to layout")
	}

	podTemplate := NewJobTemplate(c, c.Spec.JobTemplate)
	if err = podTemplate.AddToFlexLayout(fl); err != nil {
		return nil, errors.Wrap(err, "add job template to layout")
	}

	if err := createEventsForObject(fl, c, opts); err != nil {
		return nil, errors.Wrap(err, "add events to layout")
	}

	view := fl.ToComponent("Summary")
	return view, nil
}

// CronJobConfiguration generates cronjob configuration
type CronJobConfiguration struct {
	cronjob *batchv1beta1.CronJob
}

// NewCronJobConfiguration creates an instance of CronJobConfiguration
func NewCronJobConfiguration(c *batchv1beta1.CronJob) *CronJobConfiguration {
	return &CronJobConfiguration{
		cronjob: c,
	}
}

// Create creates a cronjob configuration summary
func (cc *CronJobConfiguration) Create() (*component.Summary, error) {
	if cc == nil || cc.cronjob == nil {
		return nil, errors.New("cronjob is nil")
	}

	sections := component.SummarySections{}

	sections.AddText("Schedule", cc.cronjob.Spec.Schedule)

	if suspend := cc.cronjob.Spec.Suspend; suspend != nil {
		sections.AddText("Suspend", strconv.FormatBool(*suspend))
	}

	sections.AddText("Concurrency Policy", string(cc.cronjob.Spec.ConcurrencyPolicy))

	if lastScheduleTime := cc.cronjob.Status.LastScheduleTime; lastScheduleTime != nil {
		sections = append(sections, component.SummarySection{
			Header:  "Last Schedule Time",
			Content: component.NewTimestamp(lastScheduleTime.Time),
		})
	}

	if sdls := cc.cronjob.Spec.StartingDeadlineSeconds; sdls != nil {
		seconds := fmt.Sprintf("%ds", *sdls)
		sections = append(sections, component.SummarySection{
			Header:  "Starting Deadline Seconds",
			Content: component.NewText(seconds),
		})
	}

	creationTimestamp := cc.cronjob.CreationTimestamp.Time
	sections = append(sections, component.SummarySection{
		Header:  "Age",
		Content: component.NewTimestamp(creationTimestamp),
	})

	sjhl := cc.cronjob.Spec.SuccessfulJobsHistoryLimit
	fjhl := cc.cronjob.Spec.FailedJobsHistoryLimit

	if sjhl != nil {
		sections.AddText("Successful Job History Limit", fmt.Sprintf("%d", *sjhl))
	}

	if fjhl != nil {
		sections.AddText("Failed Job History Limit", fmt.Sprintf("%d", *fjhl))
	}

	summary := component.NewSummary("Configuration", sections...)

	return summary, nil
}
<commit_msg>fixing conflicts #3<commit_after>package printer

import (
	"fmt"
	"strconv"

	"github.com/heptio/developer-dash/internal/overview/link"

	"github.com/heptio/developer-dash/internal/view/component"
	"github.com/heptio/developer-dash/internal/view/flexlayout"
	"github.com/pkg/errors"

	batchv1beta1 "k8s.io/api/batch/v1beta1"
)

// CronJobListHandler is a printFunc that lists cronjobs
func CronJobListHandler(list *batchv1beta1.CronJobList, opts Options) (component.ViewComponent, error) {
	if list == nil {
		return nil, errors.New("nil list")
	}

	cols := component.NewTableCols("Name", "Labels", "Schedule", "Age")
	tbl := component.NewTable("CronJobs", cols)

	for _, c := range list.Items {
		row := component.TableRow{}
		row["Name"] = link.ForObject(&c, c.Name)
		row["Labels"] = component.NewLabels(c.Labels)

		row["Schedule"] = component.NewText(c.Spec.Schedule)

		ts := c.CreationTimestamp.Time
		row["Age"] = component.NewTimestamp(ts)

		tbl.Add(row)
	}

	return tbl, nil
}

// CronJobHandler is a printFunc that prints a CronJob
func CronJobHandler(c *batchv1beta1.CronJob, opts Options) (component.ViewComponent, error) {
	fl := flexlayout.New()

	configSection := fl.AddSection()
	cronjobConfigGen := NewCronJobConfiguration(c)
	configView, err := cronjobConfigGen.Create()
	if err != nil {
		return nil, err
	}

	if err := configSection.Add(configView, 14); err != nil {
		return nil, errors.Wrap(err, "add cronjob config to layout")
	}

	jobListSection := fl.AddSection()
	jobListTable, err := createJobListView(c, opts)
	if err != nil {
		return nil, errors.Wrap(err, "create job list for cronjob")
	}
	if err := jobListSection.Add(jobListTable, 24); err != nil {
		return nil, errors.Wrap(err, "add job list to layout")
	}

	podTemplate := NewJobTemplate(c, c.Spec.JobTemplate)
	if err = podTemplate.AddToFlexLayout(fl); err != nil {
		return nil, errors.Wrap(err, "add job template to layout")
	}

	if err := createEventsForObject(fl, c, opts); err != nil {
		return nil, errors.Wrap(err, "add events to layout")
	}

	view := fl.ToComponent("Summary")
	return view, nil
}

// CronJobConfiguration generates cronjob configuration
type CronJobConfiguration struct {
	cronjob *batchv1beta1.CronJob
}

// NewCronJobConfiguration creates an instance of CronJobConfiguration
func NewCronJobConfiguration(c *batchv1beta1.CronJob) *CronJobConfiguration {
	return &CronJobConfiguration{
		cronjob: c,
	}
}

// Create creates a cronjob configuration summary
func (cc *CronJobConfiguration) Create() (*component.Summary, error) {
	if cc == nil || cc.cronjob == nil {
		return nil, errors.New("cronjob is nil")
	}

	sections := component.SummarySections{}

	sections.AddText("Schedule", cc.cronjob.Spec.Schedule)

	if suspend := cc.cronjob.Spec.Suspend; suspend != nil {
		sections.AddText("Suspend", strconv.FormatBool(*suspend))
	}

	sections.AddText("Concurrency Policy", string(cc.cronjob.Spec.ConcurrencyPolicy))

	if lastScheduleTime := cc.cronjob.Status.LastScheduleTime; lastScheduleTime != nil {
		sections = append(sections, component.SummarySection{
			Header:  "Last Schedule Time",
			Content: component.NewTimestamp(lastScheduleTime.Time),
		})
	}

	if sdls := cc.cronjob.Spec.StartingDeadlineSeconds; sdls != nil {
		seconds := fmt.Sprintf("%ds", *sdls)
		sections = append(sections, component.SummarySection{
			Header:  "Starting Deadline Seconds",
			Content: component.NewText(seconds),
		})
	}

	creationTimestamp := cc.cronjob.CreationTimestamp.Time
	sections = append(sections, component.SummarySection{
		Header:  "Age",
		Content: component.NewTimestamp(creationTimestamp),
	})

	sjhl := cc.cronjob.Spec.SuccessfulJobsHistoryLimit
	fjhl := cc.cronjob.Spec.FailedJobsHistoryLimit

	if sjhl != nil {
		sections.AddText("Successful Job History Limit", fmt.Sprintf("%d", *sjhl))
	}

	if fjhl != nil {
		sections.AddText("Failed Job History Limit", fmt.Sprintf("%d", *fjhl))
	}

	summary := component.NewSummary("Configuration", sections...)

	return summary, nil
}
<|endoftext|>


<commit_before>// Copyright © 2017 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package connection

import (
	"crypto/tls"
	"encoding/binary"
	"fmt"
	"io"
	"time"
)

// buildFrame creates a frame to send to broker.
// recipe:
// bytes 1-6 header
//      2 bytes channel id and command flag
//      4 bytes length of data
// bytes 7-n are data, where 0 < n <= maxPayloadLen.
func buildFrame(channelID uint16, isCommand bool, payload []byte) []byte {
	frame := make([]byte, len(payload)+6)

	var cmdFlag uint16
	if isCommand {
		cmdFlag = 0x8000
	}

	copy(frame[6:], payload)
	binary.BigEndian.PutUint16(frame[0:], channelID&0x7fff|cmdFlag)
	binary.BigEndian.PutUint32(frame[2:], uint32(len(payload)))

	return frame
}

// readFrameFromBroker reads a frame(header + payload) from broker.
func (c *Connection) readFrameFromBroker(r io.Reader) (*noitFrame, error) {
	if conn, ok := r.(*tls.Conn); ok {
		if err := conn.SetDeadline(time.Now().Add(CommTimeoutSeconds * time.Second)); err != nil {
			c.logger.Warn().Err(err).Msg("setting connection deadline")
		}
	}
	hdr, err := readFrameHeader(r)
	if err != nil {
		return nil, err
	}

	if hdr.payloadLen > MaxPayloadLen {
		return nil, fmt.Errorf("received oversized frame (%d len)", hdr.payloadLen) //nolint:goerr113 // restart the connection
	}

	if conn, ok := r.(*tls.Conn); ok {
		if err = conn.SetDeadline(time.Now().Add(CommTimeoutSeconds * time.Second)); err != nil {
			c.logger.Warn().Err(err).Msg("setting connection deadline")
		}
	}
	payload, err := readFramePayload(r, hdr.payloadLen)
	if err != nil {
		return nil, err
	}

	c.logger.Debug().
		Uint16("channel_id", hdr.channelID).
		Bool("is_command", hdr.isCommand).
		Uint32("payload_len", hdr.payloadLen).
		Str("payload", string(payload)).
		Msg("data from broker")

	return &noitFrame{
		header:  hdr,
		payload: payload,
	}, nil
}

// readFrameHeader reads 6 bytes from the broker connection.
func readFrameHeader(r io.Reader) (*noitHeader, error) {
	hdrSize := 6

	data, err := readBytes(r, int64(hdrSize))
	if err != nil {
		return nil, err
	}

	encodedChannelID := binary.BigEndian.Uint16(data)
	hdr := &noitHeader{
		channelID:  encodedChannelID & 0x7fff,
		isCommand:  encodedChannelID&0x8000 > 0,
		payloadLen: binary.BigEndian.Uint32(data[2:]),
	}

	return hdr, nil
}

// readFramePayload consumes n bytes from the broker connection.
func readFramePayload(r io.Reader, size uint32) ([]byte, error) {
	data, err := readBytes(r, int64(size))
	if err != nil {
		return nil, err
	}
	return data, nil
}

// readBytes attempts to reads <size> bytes from broker connection.
func readBytes(r io.Reader, size int64) ([]byte, error) {
	if size == 0 {
		return []byte{}, nil
	}
	buff := make([]byte, 0, size)
	lr := io.LimitReader(r, size)

	n, err := lr.Read(buff[:cap(buff)])
	if n == 0 && err != nil {
		return nil, err //nolint:wrapcheck
	}

	// dealing with expected sizes
	if int64(n) != size {
		sz := 30 // 30 is arbitrary, max amount of a larger buffer wanted in a log message
		if n < sz {
			sz = n
		}
		return nil, fmt.Errorf("invalid read, expected bytes %d got %d (%#v = %s)", size, n, buff[0:sz], string(buff[0:sz])) //nolint:goerr113
	}

	return buff[:n], nil
}
<commit_msg>fix gofmt<commit_after>// Copyright © 2017 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package connection

import (
	"crypto/tls"
	"encoding/binary"
	"fmt"
	"io"
	"time"
)

// buildFrame creates a frame to send to broker.
// recipe:
// bytes 1-6 header
//
//	2 bytes channel id and command flag
//	4 bytes length of data
//
// bytes 7-n are data, where 0 < n <= maxPayloadLen.
func buildFrame(channelID uint16, isCommand bool, payload []byte) []byte {
	frame := make([]byte, len(payload)+6)

	var cmdFlag uint16
	if isCommand {
		cmdFlag = 0x8000
	}

	copy(frame[6:], payload)
	binary.BigEndian.PutUint16(frame[0:], channelID&0x7fff|cmdFlag)
	binary.BigEndian.PutUint32(frame[2:], uint32(len(payload)))

	return frame
}

// readFrameFromBroker reads a frame(header + payload) from broker.
func (c *Connection) readFrameFromBroker(r io.Reader) (*noitFrame, error) {
	if conn, ok := r.(*tls.Conn); ok {
		if err := conn.SetDeadline(time.Now().Add(CommTimeoutSeconds * time.Second)); err != nil {
			c.logger.Warn().Err(err).Msg("setting connection deadline")
		}
	}
	hdr, err := readFrameHeader(r)
	if err != nil {
		return nil, err
	}

	if hdr.payloadLen > MaxPayloadLen {
		return nil, fmt.Errorf("received oversized frame (%d len)", hdr.payloadLen) //nolint:goerr113 // restart the connection
	}

	if conn, ok := r.(*tls.Conn); ok {
		if err = conn.SetDeadline(time.Now().Add(CommTimeoutSeconds * time.Second)); err != nil {
			c.logger.Warn().Err(err).Msg("setting connection deadline")
		}
	}
	payload, err := readFramePayload(r, hdr.payloadLen)
	if err != nil {
		return nil, err
	}

	c.logger.Debug().
		Uint16("channel_id", hdr.channelID).
		Bool("is_command", hdr.isCommand).
		Uint32("payload_len", hdr.payloadLen).
		Str("payload", string(payload)).
		Msg("data from broker")

	return &noitFrame{
		header:  hdr,
		payload: payload,
	}, nil
}

// readFrameHeader reads 6 bytes from the broker connection.
func readFrameHeader(r io.Reader) (*noitHeader, error) {
	hdrSize := 6

	data, err := readBytes(r, int64(hdrSize))
	if err != nil {
		return nil, err
	}

	encodedChannelID := binary.BigEndian.Uint16(data)
	hdr := &noitHeader{
		channelID:  encodedChannelID & 0x7fff,
		isCommand:  encodedChannelID&0x8000 > 0,
		payloadLen: binary.BigEndian.Uint32(data[2:]),
	}

	return hdr, nil
}

// readFramePayload consumes n bytes from the broker connection.
func readFramePayload(r io.Reader, size uint32) ([]byte, error) {
	data, err := readBytes(r, int64(size))
	if err != nil {
		return nil, err
	}
	return data, nil
}

// readBytes attempts to reads <size> bytes from broker connection.
func readBytes(r io.Reader, size int64) ([]byte, error) {
	if size == 0 {
		return []byte{}, nil
	}
	buff := make([]byte, 0, size)
	lr := io.LimitReader(r, size)

	n, err := lr.Read(buff[:cap(buff)])
	if n == 0 && err != nil {
		return nil, err //nolint:wrapcheck
	}

	// dealing with expected sizes
	if int64(n) != size {
		sz := 30 // 30 is arbitrary, max amount of a larger buffer wanted in a log message
		if n < sz {
			sz = n
		}
		return nil, fmt.Errorf("invalid read, expected bytes %d got %d (%#v = %s)", size, n, buff[0:sz], string(buff[0:sz])) //nolint:goerr113
	}

	return buff[:n], nil
}
<|endoftext|>


<commit_before>/*
Copyright 2022 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package feature

import (
	utilfeature "github.com/jetstack/cert-manager/pkg/util/feature"
	"k8s.io/component-base/featuregate"
)

const (
// FeatureName will enable XYZ feature.
// Fill this section out with additional details about the feature.
//
// Owner (responsible for graduating feature through to GA): @username
// Alpha: vX.Y
// Beta: ...
//FeatureName featuregate.Feature = "FeatureName"

// Insert features below this line to maintain the template above.
)

func init() {
	utilfeature.DefaultMutableFeatureGate.Add(webhookFeatureGates)
}

// webhookFeatureGates defines all feature gates for the webhook component.
// To add a new feature, define a key for it above and add it here.
// To check whether a feature is enabled, use:
//   utilfeature.DefaultFeatureGate.Enabled(feature.FeatureName)
// Where utilfeature is github.com/jetstack/cert-manager/pkg/util/feature.
var webhookFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
	//FeatureName: {Default: false, PreRelease: featuregate.Alpha},
}
<commit_msg>Re-order imports<commit_after>/*
Copyright 2022 The cert-manager Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package feature

import (
	"k8s.io/component-base/featuregate"

	utilfeature "github.com/jetstack/cert-manager/pkg/util/feature"
)

const (
// FeatureName will enable XYZ feature.
// Fill this section out with additional details about the feature.
//
// Owner (responsible for graduating feature through to GA): @username
// Alpha: vX.Y
// Beta: ...
//FeatureName featuregate.Feature = "FeatureName"

// Insert features below this line to maintain the template above.
)

func init() {
	utilfeature.DefaultMutableFeatureGate.Add(webhookFeatureGates)
}

// webhookFeatureGates defines all feature gates for the webhook component.
// To add a new feature, define a key for it above and add it here.
// To check whether a feature is enabled, use:
//   utilfeature.DefaultFeatureGate.Enabled(feature.FeatureName)
// Where utilfeature is github.com/jetstack/cert-manager/pkg/util/feature.
var webhookFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
	//FeatureName: {Default: false, PreRelease: featuregate.Alpha},
}
<|endoftext|>


<commit_before>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2018 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * AUTHOR: Bob van Luijt (bob@kub.design)
 * See www.creativesoftwarefdn.org for details
 * Contact: @CreativeSofwFdn / bob@kub.design
 */

package janusgraph

import (
	"context"
	"errors"
	"fmt"
	"reflect"
	"time"

	"github.com/go-openapi/strfmt"

	connutils "github.com/creativesoftwarefdn/weaviate/database/connectors/utils"
	"github.com/creativesoftwarefdn/weaviate/database/schema"
	"github.com/creativesoftwarefdn/weaviate/database/schema/kind"
	"github.com/creativesoftwarefdn/weaviate/models"

	"github.com/creativesoftwarefdn/weaviate/gremlin"

	"encoding/json"
)

func (j *Janusgraph) AddThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID) error {
	k := kind.THING_KIND

	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")

	sanitizedClassName := schema.AssertValidClassName(thing.AtClass)
	vertexLabel := j.state.getMappedClassName(sanitizedClassName)

	q := gremlin.G.AddV(string(vertexLabel)).
		As("newClass").
		StringProperty(PROP_KIND, k.Name()).
		StringProperty(PROP_UUID, UUID.String()).
		StringProperty(PROP_CLASS_ID, string(vertexLabel)).
		StringProperty(PROP_AT_CONTEXT, thing.AtContext).
		Int64Property(PROP_CREATION_TIME_UNIX, thing.CreationTimeUnix).
		Int64Property(PROP_LAST_UPDATE_TIME_UNIX, thing.LastUpdateTimeUnix)

	// map properties in thing.Schema according to the mapping.

	type edgeToAdd struct {
		PropertyName string
		Type         string
		Reference    string
		Location     string
	}

	var edgesToAdd []edgeToAdd

	thingSchema, schema_ok := thing.Schema.(map[string]interface{})
	if schema_ok {
		for propName, value := range thingSchema {
			// TODO relation type
			// if primitive type:
			sanitziedPropertyName := schema.AssertValidPropertyName(propName)
			janusPropertyName := string(j.state.getMappedPropertyName(sanitizedClassName, sanitziedPropertyName))

			switch t := value.(type) {
			case string:
				q = q.StringProperty(janusPropertyName, t)
			case int:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int8:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int16:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int32:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int64:
				q = q.Int64Property(janusPropertyName, t)
			case bool:
				q = q.BoolProperty(janusPropertyName, t)
			case float32:
				q = q.Float64Property(janusPropertyName, float64(t))
			case float64:
				q = q.Float64Property(janusPropertyName, t)
			case time.Time:
				q = q.StringProperty(janusPropertyName, time.Time.String(t))
			case *models.SingleRef:
				panic("not supported yet")
				// Postpone creation of edges
				edgesToAdd = append(edgesToAdd, edgeToAdd{
					PropertyName: janusPropertyName,
					Reference:    t.NrDollarCref.String(),
					Type:         t.Type,
					Location:     *t.LocationURL,
				})
			default:
				j.messaging.ExitError(78, "The type "+reflect.TypeOf(value).String()+" is not supported for Thing properties.")
			}
		}
	}
	//
	//	// Add edges to all referened things.
	//	for _, edge := range edgesToAdd {
	//		q = q.AddE("thingEdge").
	//			FromRef("newClass").
	//			ToQuery(gremlin.G.V().HasLabel(THING_LABEL).HasString("uuid", edge.Reference)).
	//			StringProperty(PROPERTY_EDGE_LABEL, edge.PropertyName).
	//			StringProperty("$cref", edge.Reference).
	//			StringProperty("type", edge.Type).
	//			StringProperty("locationUrl", edge.Location)
	//	}

	// Link to key
	q = q.AddE(KEY_VERTEX_LABEL).
		StringProperty("locationUrl", *thing.Key.LocationURL).
		FromRef("newClass").
		ToQuery(gremlin.G.V().HasLabel(KEY_VERTEX_LABEL).HasString(PROP_UUID, thing.Key.NrDollarCref.String()))

	_, err := j.client.Execute(q)

	return err
}

func (f *Janusgraph) GetThing(ctx context.Context, UUID strfmt.UUID, thingResponse *models.ThingGetResponse) error {
	k := kind.THING_KIND

	// Fetch the thing, it's key, and it's relations.
	q := gremlin.G.V().
		StringProperty(PROP_KIND, k.Name()).
		HasString(PROP_UUID, string(UUID)).
		As("class").
		OutEWithLabel(KEY_VERTEX_LABEL).As("keyEdge").
		InV().Path().FromRef("keyEdge").As("key"). // also get the path, so that we can learn about the location of the key.
		V().
		HasString(PROP_UUID, string(UUID)).
		Raw(`.optional(outE("thingEdge").as("thingEdge").as("ref")).choose(select("ref"), select("class", "key", "ref"), select("class", "key"))`)

	result, err := f.client.Execute(q)

	if err != nil {
		return err
	}

	if len(result.Data) == 0 {
		return errors.New(connutils.StaticThingNotFound)
	}

	// The outputs 'thing' and 'key' will be repeated over all results. Just get them for one for now.
	thingVertex := result.Data[0].AssertKey("class").AssertVertex()
	keyPath := result.Data[0].AssertKey("key").AssertPath()

	// However, we can get multiple refs. In that case, we'll have multiple datums,
	// each with the same thing & key, but a different ref.
	// Let's extract those refs.
	var refEdges []*gremlin.Edge
	for _, datum := range result.Data {
		ref, err := datum.Key("ref")
		if err == nil {
			refEdges = append(refEdges, ref.AssertEdge())
		}
	}

	thingResponse.Key = newKeySingleRefFromKeyPath(keyPath)
	return f.fillThingResponseFromVertexAndEdges(thingVertex, refEdges, thingResponse)
	return nil
}

// TODO check
func (f *Janusgraph) GetThings(ctx context.Context, UUIDs []strfmt.UUID, response *models.ThingsListResponse) error {
	// TODO: Optimize query to perform just _one_ JanusGraph lookup.

	response.TotalResults = 0
	response.Things = make([]*models.ThingGetResponse, 0)

	for _, uuid := range UUIDs {
		var thing_response models.ThingGetResponse
		err := f.GetThing(ctx, uuid, &thing_response)

		if err == nil {
			response.TotalResults += 1
			response.Things = append(response.Things, &thing_response)
		} else {
			return fmt.Errorf("%s: thing with UUID '%v' not found", connutils.StaticThingNotFound, uuid)
		}
	}

	return nil
}

// TODO check
func (f *Janusgraph) ListThings(ctx context.Context, first int, offset int, keyID strfmt.UUID, wheres []*connutils.WhereQuery, response *models.ThingsListResponse) error {
	//
	//	if len(wheres) > 0 {
	//		return errors.New("Wheres are not supported in LisThings")
	//	}
	//
	//	q := gremlin.G.V().
	//		HasLabel(THING_LABEL).
	//		Range(offset, first).
	//		Values([]string{"uuid"})
	//
	//	result, err := f.client.Execute(q)
	//
	//	if err != nil {
	//		return err
	//	}
	//
	//	response.TotalResults = 0
	//	response.Things = make([]*models.ThingGetResponse, 0)
	//
	//	// Get the UUIDs from the first query.
	//	UUIDs := result.AssertStringSlice()
	//
	//	for _, uuid := range UUIDs {
	//		var thing_response models.ThingGetResponse
	//		err := f.GetThing(ctx, strfmt.UUID(uuid), &thing_response)
	//
	//		if err == nil {
	//			response.TotalResults += 1
	//			response.Things = append(response.Things, &thing_response)
	//		} else {
	//			// skip silently; it's probably deleted.
	//		}
	//	}
	//
	return nil
}

func (f *Janusgraph) UpdateThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID) error {
	//	// Base settings
	//	q := gremlin.G.V().HasLabel(THING_LABEL).
	//		HasString("uuid", string(UUID)).
	//		As("thing").
	//		StringProperty("atClass", thing.AtClass).
	//		StringProperty("context", thing.AtContext).
	//		Int64Property("creationTimeUnix", thing.CreationTimeUnix).
	//		Int64Property("lastUpdateTimeUnix", thing.LastUpdateTimeUnix)
	//
	//	type expectedEdge struct {
	//		PropertyName string
	//		Type         string
	//		Reference    string
	//		Location     string
	//	}
	//
	//	var expectedEdges []expectedEdge
	//
	//	schema, schema_ok := thing.Schema.(map[string]interface{})
	//	if schema_ok {
	//		for key, value := range schema {
	//			janusgraphPropertyName := "schema__" + key
	//			switch t := value.(type) {
	//			case string:
	//				q = q.StringProperty(janusgraphPropertyName, t)
	//			case int:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int8:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int16:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int32:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int64:
	//				q = q.Int64Property(janusgraphPropertyName, t)
	//			case bool:
	//				q = q.BoolProperty(janusgraphPropertyName, t)
	//			case float32:
	//				q = q.Float64Property(janusgraphPropertyName, float64(t))
	//			case float64:
	//				q = q.Float64Property(janusgraphPropertyName, t)
	//			case time.Time:
	//				q = q.StringProperty(janusgraphPropertyName, time.Time.String(t))
	//			case *models.SingleRef:
	//				// Postpone creation of edges
	//				expectedEdges = append(expectedEdges, expectedEdge{
	//					PropertyName: janusgraphPropertyName,
	//					Reference:    t.NrDollarCref.String(),
	//					Type:         t.Type,
	//					Location:     *t.LocationURL,
	//				})
	//			default:
	//				f.messaging.ExitError(78, "The type "+reflect.TypeOf(value).String()+" is not supported for Thing properties.")
	//			}
	//		}
	//	}
	//
	//	// Update all edges to all referened things.
	//	// TODO: verify what to if we're not mentioning some reference? how should we remove such a reference?
	//	for _, edge := range expectedEdges {
	//		// First drop the edge
	//		q = q.Optional(gremlin.Current().OutEWithLabel("thingEdge").HasString(PROPERTY_EDGE_LABEL, edge.PropertyName).Drop()).
	//			AddE("thingEdge").
	//			FromRef("thing").
	//			ToQuery(gremlin.G.V().HasLabel(THING_LABEL).HasString("uuid", edge.Reference)).
	//			StringProperty(PROPERTY_EDGE_LABEL, edge.PropertyName).
	//			StringProperty("$cref", edge.Reference).
	//			StringProperty("type", edge.Type).
	//			StringProperty("locationUrl", edge.Location)
	//	}
	//
	//	// Don't update the key.
	//	// TODO verify that indeed this is the desired behaviour.
	//
	//	_, err := f.client.Execute(q)
	//
	//	return err
	return nil
}

func (f *Janusgraph) DeleteThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID) error {
	//	q := gremlin.G.V().HasLabel(THING_LABEL).
	//		HasString("uuid", string(UUID)).
	//		Drop()
	//
	//	_, err := f.client.Execute(q)
	//
	//	return err
	return nil
}

func (f *Janusgraph) HistoryThing(ctx context.Context, UUID strfmt.UUID, history *models.ThingHistory) error {
	return nil
}

func (f *Janusgraph) MoveToHistoryThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID, deleted bool) error {
	return nil
}

func debug(result interface{}) {
	j, _ := json.MarshalIndent(result, "", " ")
	fmt.Printf("%v\n", string(j))
}
<commit_msg>enable ListThings<commit_after>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2018 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * AUTHOR: Bob van Luijt (bob@kub.design)
 * See www.creativesoftwarefdn.org for details
 * Contact: @CreativeSofwFdn / bob@kub.design
 */

package janusgraph

import (
	"context"
	"errors"
	"fmt"
	"reflect"
	"time"

	"github.com/go-openapi/strfmt"

	connutils "github.com/creativesoftwarefdn/weaviate/database/connectors/utils"
	"github.com/creativesoftwarefdn/weaviate/database/schema"
	"github.com/creativesoftwarefdn/weaviate/database/schema/kind"
	"github.com/creativesoftwarefdn/weaviate/models"

	"github.com/creativesoftwarefdn/weaviate/gremlin"

	"encoding/json"
)

func (j *Janusgraph) AddThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID) error {
	k := kind.THING_KIND

	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")
	fmt.Printf("########### ADDING THING #######\n")

	sanitizedClassName := schema.AssertValidClassName(thing.AtClass)
	vertexLabel := j.state.getMappedClassName(sanitizedClassName)

	q := gremlin.G.AddV(string(vertexLabel)).
		As("newClass").
		StringProperty(PROP_KIND, k.Name()).
		StringProperty(PROP_UUID, UUID.String()).
		StringProperty(PROP_CLASS_ID, string(vertexLabel)).
		StringProperty(PROP_AT_CONTEXT, thing.AtContext).
		Int64Property(PROP_CREATION_TIME_UNIX, thing.CreationTimeUnix).
		Int64Property(PROP_LAST_UPDATE_TIME_UNIX, thing.LastUpdateTimeUnix)

	// map properties in thing.Schema according to the mapping.

	type edgeToAdd struct {
		PropertyName string
		Type         string
		Reference    string
		Location     string
	}

	var edgesToAdd []edgeToAdd

	thingSchema, schema_ok := thing.Schema.(map[string]interface{})
	if schema_ok {
		for propName, value := range thingSchema {
			// TODO relation type
			// if primitive type:
			sanitziedPropertyName := schema.AssertValidPropertyName(propName)
			janusPropertyName := string(j.state.getMappedPropertyName(sanitizedClassName, sanitziedPropertyName))

			switch t := value.(type) {
			case string:
				q = q.StringProperty(janusPropertyName, t)
			case int:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int8:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int16:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int32:
				q = q.Int64Property(janusPropertyName, int64(t))
			case int64:
				q = q.Int64Property(janusPropertyName, t)
			case bool:
				q = q.BoolProperty(janusPropertyName, t)
			case float32:
				q = q.Float64Property(janusPropertyName, float64(t))
			case float64:
				q = q.Float64Property(janusPropertyName, t)
			case time.Time:
				q = q.StringProperty(janusPropertyName, time.Time.String(t))
			case *models.SingleRef:
				panic("not supported yet")
				// Postpone creation of edges
				edgesToAdd = append(edgesToAdd, edgeToAdd{
					PropertyName: janusPropertyName,
					Reference:    t.NrDollarCref.String(),
					Type:         t.Type,
					Location:     *t.LocationURL,
				})
			default:
				j.messaging.ExitError(78, "The type "+reflect.TypeOf(value).String()+" is not supported for Thing properties.")
			}
		}
	}
	//
	//	// Add edges to all referened things.
	//	for _, edge := range edgesToAdd {
	//		q = q.AddE("thingEdge").
	//			FromRef("newClass").
	//			ToQuery(gremlin.G.V().HasLabel(THING_LABEL).HasString("uuid", edge.Reference)).
	//			StringProperty(PROPERTY_EDGE_LABEL, edge.PropertyName).
	//			StringProperty("$cref", edge.Reference).
	//			StringProperty("type", edge.Type).
	//			StringProperty("locationUrl", edge.Location)
	//	}

	// Link to key
	q = q.AddE(KEY_VERTEX_LABEL).
		StringProperty("locationUrl", *thing.Key.LocationURL).
		FromRef("newClass").
		ToQuery(gremlin.G.V().HasLabel(KEY_VERTEX_LABEL).HasString(PROP_UUID, thing.Key.NrDollarCref.String()))

	_, err := j.client.Execute(q)

	return err
}

func (f *Janusgraph) GetThing(ctx context.Context, UUID strfmt.UUID, thingResponse *models.ThingGetResponse) error {
	k := kind.THING_KIND

	// Fetch the thing, it's key, and it's relations.
	q := gremlin.G.V().
		StringProperty(PROP_KIND, k.Name()).
		HasString(PROP_UUID, string(UUID)).
		As("class").
		OutEWithLabel(KEY_VERTEX_LABEL).As("keyEdge").
		InV().Path().FromRef("keyEdge").As("key"). // also get the path, so that we can learn about the location of the key.
		V().
		HasString(PROP_UUID, string(UUID)).
		Raw(`.optional(outE("thingEdge").as("thingEdge").as("ref")).choose(select("ref"), select("class", "key", "ref"), select("class", "key"))`)

	result, err := f.client.Execute(q)

	if err != nil {
		return err
	}

	if len(result.Data) == 0 {
		return errors.New(connutils.StaticThingNotFound)
	}

	// The outputs 'thing' and 'key' will be repeated over all results. Just get them for one for now.
	thingVertex := result.Data[0].AssertKey("class").AssertVertex()
	keyPath := result.Data[0].AssertKey("key").AssertPath()

	// However, we can get multiple refs. In that case, we'll have multiple datums,
	// each with the same thing & key, but a different ref.
	// Let's extract those refs.
	var refEdges []*gremlin.Edge
	for _, datum := range result.Data {
		ref, err := datum.Key("ref")
		if err == nil {
			refEdges = append(refEdges, ref.AssertEdge())
		}
	}

	thingResponse.Key = newKeySingleRefFromKeyPath(keyPath)
	return f.fillThingResponseFromVertexAndEdges(thingVertex, refEdges, thingResponse)
	return nil
}

// TODO check
func (f *Janusgraph) GetThings(ctx context.Context, UUIDs []strfmt.UUID, response *models.ThingsListResponse) error {
	// TODO: Optimize query to perform just _one_ JanusGraph lookup.

	response.TotalResults = 0
	response.Things = make([]*models.ThingGetResponse, 0)

	for _, uuid := range UUIDs {
		var thing_response models.ThingGetResponse
		err := f.GetThing(ctx, uuid, &thing_response)

		if err == nil {
			response.TotalResults += 1
			response.Things = append(response.Things, &thing_response)
		} else {
			return fmt.Errorf("%s: thing with UUID '%v' not found", connutils.StaticThingNotFound, uuid)
		}
	}

	return nil
}

// TODO check
func (f *Janusgraph) ListThings(ctx context.Context, first int, offset int, keyID strfmt.UUID, wheres []*connutils.WhereQuery, response *models.ThingsListResponse) error {
	k := kind.THING_KIND

	if len(wheres) > 0 {
		return errors.New("Wheres are not supported in LisThings")
	}

	q := gremlin.G.V().
		HasString(PROP_KIND, k.Name()).
		Range(offset, first).
		Values([]string{PROP_UUID})

	result, err := f.client.Execute(q)

	if err != nil {
		return err
	}

	response.TotalResults = 0
	response.Things = make([]*models.ThingGetResponse, 0)

	// Get the UUIDs from the first query.
	UUIDs := result.AssertStringSlice()

	for _, uuid := range UUIDs {
		var thing_response models.ThingGetResponse
		err := f.GetThing(ctx, strfmt.UUID(uuid), &thing_response)

		if err == nil {
			response.TotalResults += 1
			response.Things = append(response.Things, &thing_response)
		} else {
			// skip silently; it's probably deleted.
		}
	}

	return nil
}

func (f *Janusgraph) UpdateThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID) error {
	//	// Base settings
	//	q := gremlin.G.V().HasLabel(THING_LABEL).
	//		HasString("uuid", string(UUID)).
	//		As("thing").
	//		StringProperty("atClass", thing.AtClass).
	//		StringProperty("context", thing.AtContext).
	//		Int64Property("creationTimeUnix", thing.CreationTimeUnix).
	//		Int64Property("lastUpdateTimeUnix", thing.LastUpdateTimeUnix)
	//
	//	type expectedEdge struct {
	//		PropertyName string
	//		Type         string
	//		Reference    string
	//		Location     string
	//	}
	//
	//	var expectedEdges []expectedEdge
	//
	//	schema, schema_ok := thing.Schema.(map[string]interface{})
	//	if schema_ok {
	//		for key, value := range schema {
	//			janusgraphPropertyName := "schema__" + key
	//			switch t := value.(type) {
	//			case string:
	//				q = q.StringProperty(janusgraphPropertyName, t)
	//			case int:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int8:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int16:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int32:
	//				q = q.Int64Property(janusgraphPropertyName, int64(t))
	//			case int64:
	//				q = q.Int64Property(janusgraphPropertyName, t)
	//			case bool:
	//				q = q.BoolProperty(janusgraphPropertyName, t)
	//			case float32:
	//				q = q.Float64Property(janusgraphPropertyName, float64(t))
	//			case float64:
	//				q = q.Float64Property(janusgraphPropertyName, t)
	//			case time.Time:
	//				q = q.StringProperty(janusgraphPropertyName, time.Time.String(t))
	//			case *models.SingleRef:
	//				// Postpone creation of edges
	//				expectedEdges = append(expectedEdges, expectedEdge{
	//					PropertyName: janusgraphPropertyName,
	//					Reference:    t.NrDollarCref.String(),
	//					Type:         t.Type,
	//					Location:     *t.LocationURL,
	//				})
	//			default:
	//				f.messaging.ExitError(78, "The type "+reflect.TypeOf(value).String()+" is not supported for Thing properties.")
	//			}
	//		}
	//	}
	//
	//	// Update all edges to all referened things.
	//	// TODO: verify what to if we're not mentioning some reference? how should we remove such a reference?
	//	for _, edge := range expectedEdges {
	//		// First drop the edge
	//		q = q.Optional(gremlin.Current().OutEWithLabel("thingEdge").HasString(PROPERTY_EDGE_LABEL, edge.PropertyName).Drop()).
	//			AddE("thingEdge").
	//			FromRef("thing").
	//			ToQuery(gremlin.G.V().HasLabel(THING_LABEL).HasString("uuid", edge.Reference)).
	//			StringProperty(PROPERTY_EDGE_LABEL, edge.PropertyName).
	//			StringProperty("$cref", edge.Reference).
	//			StringProperty("type", edge.Type).
	//			StringProperty("locationUrl", edge.Location)
	//	}
	//
	//	// Don't update the key.
	//	// TODO verify that indeed this is the desired behaviour.
	//
	//	_, err := f.client.Execute(q)
	//
	//	return err
	return nil
}

func (f *Janusgraph) DeleteThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID) error {
	//	q := gremlin.G.V().HasLabel(THING_LABEL).
	//		HasString("uuid", string(UUID)).
	//		Drop()
	//
	//	_, err := f.client.Execute(q)
	//
	//	return err
	return nil
}

func (f *Janusgraph) HistoryThing(ctx context.Context, UUID strfmt.UUID, history *models.ThingHistory) error {
	return nil
}

func (f *Janusgraph) MoveToHistoryThing(ctx context.Context, thing *models.Thing, UUID strfmt.UUID, deleted bool) error {
	return nil
}

func debug(result interface{}) {
	j, _ := json.MarshalIndent(result, "", " ")
	fmt.Printf("%v\n", string(j))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/bwmarrin/discordgo"
)

func init() {
	newCommand("avatar", 0, false, false, msgAvatar).setHelp("Args: [@user]\n\nReturns the given users avatar.\nIf no user ID is given, your own avatar is sent.\n\nExample:\n`!owo avatar @Strum355#2298`").add()
}

func msgAvatar(s *discordgo.Session, m *discordgo.MessageCreate, msglist []string) {
	if len(msglist) == 1 {
		getAvatar(m.Author.ID, m, s)
		return
	}

	if len(m.Mentions) != 0 {
		getAvatar(m.Mentions[0].ID, m, s)
		return
	}

	s.ChannelMessageSend(m.ChannelID, "User not found :(")
}

func getAvatar(userID string, m *discordgo.MessageCreate, s *discordgo.Session) {
	guild, err := guildDetails(m.ChannelID, "", s)
	if err != nil {
		s.ChannelMessageSend(m.ChannelID, "There was an error finding the user :( Please try again")
		return
	}

	// slow warmup or fast but limited to guild :( shame
	user, err := memberDetails(guild.ID, userID, s)
	if err != nil {
		s.ChannelMessageSend(m.ChannelID, "There was an error finding the user :( Please try again")
		return
	}

	s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{
		Description: user.User.Username + "'s Avatar",

		Color: 0x000000,

		Image: &discordgo.MessageEmbedImage{
			URL: user.User.AvatarURL("2048"),
		},
	})
}
<commit_msg>This didnt go through the first time?? (#14)<commit_after>package main

import (
	"github.com/bwmarrin/discordgo"
)

func init() {
	newCommand("avatar", 0, false, false, msgAvatar).setHelp("Args: [@user]\n\nReturns the given users avatar.\nIf no user ID is given, your own avatar is sent.\n\nExample:\n`!owo avatar @Strum355#2298`").add()
}

func msgAvatar(s *discordgo.Session, m *discordgo.MessageCreate, msglist []string) {
	if len(msglist) == 1 {
		getAvatar(m.Author.ID, m, s)
		return
	}

	if len(m.Mentions) != 0 {
		getAvatar(m.Mentions[0].ID, m, s)
		return
	}

	s.ChannelMessageSend(m.ChannelID, "User not found :(")
}

func getAvatar(userID string, m *discordgo.MessageCreate, s *discordgo.Session) {
/* 	guild, err := guildDetails(m.ChannelID, "", s)
	if err != nil {
		s.ChannelMessageSend(m.ChannelID, "There was an error finding the user :( Please try again")
		return
	} */

	// slow warmup or fast but limited to guild :( shame
	// or maybe not??? will monitor
	user, err := userDetails(userID, s)
	if err != nil {
		s.ChannelMessageSend(m.ChannelID, "There was an error finding the user :( Please try again")
		return
	}

	s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{
		Description: user.Username + "'s Avatar",

		Color: 0x000000,

		Image: &discordgo.MessageEmbedImage{
			URL: user.AvatarURL("2048"),
		},
	})
}
<|endoftext|>


<commit_before>package logbuddy

type MsgRouter struct {
}
<commit_msg>register msg sender<commit_after>package logbuddy

type MsgRouter struct {
	Handlers map[int]*MsgHandler
}

type MsgHandler struct {
	Sender    chan interface{}
	Receivers []chan interface{}
}

//Register
func (mr *MsgRouter) RegisterSender(s chan interface{}, id int) {
	mh := &MsgHandler{Sender: s}
	mr.Handlers[id] = mh
}

//Unregister
func (mr *MsgRouter) UnregisterSender(id int) {
	//Remove Sender
}

func (mr *MsgRouter) RegisterReceivers(r chan interface{}, id int) int {
	mr.Handlers[id].Receivers = append(mr.Handlers[id].Receivers, r)
	return len(mr.Handlers[id].Receivers) - 1

}

//FanOut

//FanIn
<|endoftext|>


<commit_before>package main

import (
	"github.com/gopherjs/gopherjs/js"
)

func main() {

}<commit_msg>Added test output<commit_after>package main

import (
	"github.com/gopherjs/gopherjs/js"
)

func main() {
	//Add a title
	js.Global.Get("document").Set("title", "GopherJS Canvas Test")
	//See if it works
	js.Global.Call("alert", "Success...")
}<|endoftext|>


<commit_before>package resty

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"testing"
)

var (
	LogRequests = false
)

type TestRequest struct {
	Method string
	Path   string
	Data   interface{}

	ExpectedStatus int
	ExpectedData   interface{}
}

func (tr *TestRequest) String() string {
	return tr.Method + " " + tr.Path
}

func (tr *TestRequest) Run(t *testing.T, c *Client) {
	r := c.Do(tr.Method, tr.Path, tr.Data, nil)
	if LogRequests {
		t.Logf("%s: %s", tr.String(), r.Value)
	}

	switch {
	case r.Err != nil:
		t.Fatalf("%s: error: %v, status: %d, resp: %s", tr.String(), r.Err, r.Status, r.Value)
	case tr.ExpectedStatus == 0 && r.Status != 200, r.Status != tr.ExpectedStatus:
		t.Fatalf("%s: wanted %d, got %d: %s", tr.String(), tr.ExpectedStatus, r.Status, r.Value)
	case tr.ExpectedData != nil:
		if err := compareRes(r.Value, getVal(tr.ExpectedData)); err != nil {
			t.Fatalf("%s: %v", tr.String(), err)
		}
	}
}

// a == result, b == expected
func compareRes(a, b []byte) error {
	var am, bm interface{}
	if err := json.Unmarshal(a, &am); err != nil {
		return fmt.Errorf("%s: %v", a, err)
	}
	if err := json.Unmarshal(b, &bm); err != nil {
		return fmt.Errorf("%s: %v", b, err)
	}

	return cmp(am, bm)
}

func cmp(a, b interface{}) error {
	switch a := a.(type) {
	case []interface{}:
		amap := make([]map[string]interface{}, len(a))
		for i, v := range a {
			amap[i], _ = v.(map[string]interface{})
		}

		switch b := b.(type) {
		case []interface{}:
			bmap := make([]map[string]interface{}, len(b))
			for i, v := range b {
				bmap[i], _ = v.(map[string]interface{})
			}
			var okcount int
			for _, av := range amap {
				for _, bv := range bmap {
					if cmpMap(av, bv) == nil {
						okcount++
						break
					}
				}
			}
			if okcount == len(b) {
				return nil
			}
			return fmt.Errorf("not all expected values were found: a = %v, b = %v", a, b)

		case map[string]interface{}:
			var err error
			for _, av := range amap {
				if err = cmpMap(av, b); err == nil {
					break
				}
			}
			return err
		}

	case map[string]interface{}:
		if b, ok := b.(map[string]interface{}); ok {
			return cmpMap(a, b)
		}
	}
	return fmt.Errorf("type mismatch, a = %T, b = %T", a, b)
}

func cmpMap(am, bm map[string]interface{}) error {
	for k, v := range bm {
		ov := am[k]
		switch ov := ov.(type) {
		case map[string]interface{}:
			if v, ok := v.(map[string]interface{}); ok {
				if err := cmpMap(ov, v); err != nil {
					return fmt.Errorf("%s: %v", k, err)
				}
			} else {
				return fmt.Errorf("%s: type mismatch %T vs %T", k, am[k], bm[k])
			}
		case []interface{}:
			if err := cmp(ov, v); err != nil {
				return err
			}
		default:
			if !reflect.DeepEqual(v, ov) {
				return fmt.Errorf("%s wanted %v, got %v", k, v, ov)
			}
		}
	}
	return nil
}

func getVal(v interface{}) []byte {
	switch v := v.(type) {
	case []byte:
		return v
	case string:
		return []byte(v)
	case io.Reader:
		b, _ := ioutil.ReadAll(v)
		return b
	case nil:
		return nil
	}
	j, _ := json.Marshal(v)
	return j
}
<commit_msg>add partial matches<commit_after>package resty

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"reflect"
	"testing"
)

var (
	LogRequests = false
)

type PartialMatch []byte

type TestRequest struct {
	Method string
	Path   string
	Data   interface{}

	ExpectedStatus int
	ExpectedData   interface{}
}

func (tr *TestRequest) String() string {
	return tr.Method + " " + tr.Path
}

func (tr *TestRequest) Run(t *testing.T, c *Client) {
	r := c.Do(tr.Method, tr.Path, tr.Data, nil)
	if LogRequests {
		t.Logf("%s: %s", tr.String(), r.Value)
	}

	switch {
	case r.Err != nil:
		t.Fatalf("%s: error: %v, status: %d, resp: %s", tr.String(), r.Err, r.Status, r.Value)
	case tr.ExpectedStatus == 0 && r.Status != 200, r.Status != tr.ExpectedStatus:
		t.Fatalf("%s: wanted %d, got %d: %s", tr.String(), tr.ExpectedStatus, r.Status, r.Value)
	case tr.ExpectedData != nil:
		if ev, ok := tr.ExpectedData.(PartialMatch); ok {
			if bytes.Index(r.Value, []byte(ev)) == -1 {
				t.Fatalf("%s: partial mismatched, wanted %s, got: %s", tr.String(), ev, r.Value)
			}
			return
		}
		if err := compareRes(r.Value, getVal(tr.ExpectedData)); err != nil {
			t.Fatalf("%s: %v", tr.String(), err)
		}
	}
}

// a == result, b == expected
func compareRes(a, b []byte) error {
	var am, bm interface{}
	if err := json.Unmarshal(a, &am); err != nil {
		return fmt.Errorf("%s: %v", a, err)
	}
	if err := json.Unmarshal(b, &bm); err != nil {
		return fmt.Errorf("%s: %v", b, err)
	}

	return cmp(am, bm)
}

func cmp(a, b interface{}) error {
	switch a := a.(type) {
	case []interface{}:
		amap := make([]map[string]interface{}, len(a))
		for i, v := range a {
			amap[i], _ = v.(map[string]interface{})
		}

		switch b := b.(type) {
		case []interface{}:
			bmap := make([]map[string]interface{}, len(b))
			for i, v := range b {
				bmap[i], _ = v.(map[string]interface{})
			}
			var okcount int
			for _, av := range amap {
				for _, bv := range bmap {
					if cmpMap(av, bv) == nil {
						okcount++
						break
					}
				}
			}
			if okcount == len(b) {
				return nil
			}
			return fmt.Errorf("not all expected values were found: a = %v, b = %v", a, b)

		case map[string]interface{}:
			var err error
			for _, av := range amap {
				if err = cmpMap(av, b); err == nil {
					break
				}
			}
			return err
		}

	case map[string]interface{}:
		if b, ok := b.(map[string]interface{}); ok {
			return cmpMap(a, b)
		}
	}
	return fmt.Errorf("type mismatch, a = %T, b = %T", a, b)
}

func cmpMap(am, bm map[string]interface{}) error {
	for k, v := range bm {
		ov := am[k]
		switch ov := ov.(type) {
		case map[string]interface{}:
			if v, ok := v.(map[string]interface{}); ok {
				if err := cmpMap(ov, v); err != nil {
					return fmt.Errorf("%s: %v", k, err)
				}
			} else {
				return fmt.Errorf("%s: type mismatch %T vs %T", k, am[k], bm[k])
			}
		case []interface{}:
			if err := cmp(ov, v); err != nil {
				return err
			}
		default:
			if !reflect.DeepEqual(v, ov) {
				return fmt.Errorf("%s wanted %v, got %v", k, v, ov)
			}
		}
	}
	return nil
}

func getVal(v interface{}) []byte {
	switch v := v.(type) {
	case []byte:
		return v
	case string:
		return []byte(v)
	case io.Reader:
		b, _ := ioutil.ReadAll(v)
		return b
	case nil:
		return nil
	}
	j, _ := json.Marshal(v)
	return j
}
<|endoftext|>


<commit_before>package multi

import (
	"github.com/bcurren/go-hue"
	"time"
)

type rGetLights struct {
	lights []hue.Light
	err error
}

type rGetNewLights struct {
	lights []hue.Light
	lastScan time.Time
	err error
}

type rSearchForNewLights struct {
	err error
}

// GetLights() is same as hue.User.GetLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLights() ([]hue.Light, error) {
	c := make(chan rGetLights)
	for _, api := range m.apis {
		go gGetLights(c, api)
	}
	return lGetLights(c, len(m.apis))
}

func gGetLights(c chan rGetLights, api hue.API) {
	lights, err := api.GetLights()
	c <- rGetLights{mapLightIds(lights), err}
}

func lGetLights(c chan rGetLights, nResponses int) ([]hue.Light, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <- c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		} else {
			lLights = append(lLights, result.lights)
		}
	}

	return mergeLights(lLights), mergeErrors(lErrors)
}

// GetNewLights() is same as hue.User.GetNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetNewLights() ([]hue.Light, time.Time, error) {
	c := make(chan rGetNewLights)
	for _, api := range m.apis {
		go gGetNewLights(c, api)
	}
	return lGetNewLights(c, len(m.apis))
}

func gGetNewLights(c chan rGetNewLights, api hue.API) {
	lights, lastScan, err := api.GetNewLights()
	c <- rGetNewLights{mapLightIds(lights), lastScan, err}
}

func lGetNewLights(c chan rGetNewLights, nResponses int) ([]hue.Light, time.Time, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)
	lLastScan := make([]time.Time, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <- c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
		if result.lights != nil {
			lLights = append(lLights, result.lights)
		}
		lLastScan = append(lLastScan, result.lastScan)
	}

	return mergeLights(lLights), mergeTime(lLastScan), mergeErrors(lErrors)
}

// SearchForNewLights() is same as hue.User.SearchForNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SearchForNewLights() error {
	c := make(chan rSearchForNewLights)
	for _, api := range m.apis {
		go gSearchForNewLights(c, api)
	}
	return lSearchForNewLights(c, len(m.apis))
}

func gSearchForNewLights(c chan rSearchForNewLights, api hue.API) {
	err := api.SearchForNewLights()
	c <- rSearchForNewLights{err}
}

func lSearchForNewLights(c chan rSearchForNewLights, nResponses int) error {
	lErrors := make([]error, 0, 1)

	for i := 0; i < nResponses; i++ {
		result := <- c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
	}

	return mergeErrors(lErrors)
}

// GetLightAttributes() is same as hue.User.GetLightAttributes() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLightAttributes(socketId string) (*hue.LightAttributes, error) {
	return nil, nil
}

// SetLightName() is same as hue.User.SetLightName() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightName(socketId string, name string) error {
	return nil
}

// SetLightState() is same as hue.User.SetLightState() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightState(socketId string, state *hue.LightState) error {
	return nil
}

func mergeLights(lLights [][]hue.Light) []hue.Light {
	countOfLights := 0
	for _, lights := range lLights {
		countOfLights += len(lights)
	}

	mLights := make([]hue.Light, countOfLights)
	copyTo := 0
	for _, lights := range lLights {
		copy(mLights[copyTo:], lights)
		copyTo += len(lights)
	}

	return mLights
}

func mergeErrors(lErrors []error) error {
	return nil
}

func mergeTime(lTime []time.Time) time.Time {
	return lTime[0]
}

func mapLightIds(lLights []hue.Light) []hue.Light {
	return lLights
}<commit_msg>added SetLightState<commit_after>package multi

import (
	"github.com/bcurren/go-hue"
	"time"
)

type rGetLights struct {
	lights []hue.Light
	err error
}

type rGetNewLights struct {
	lights []hue.Light
	lastScan time.Time
	err error
}

type rSearchForNewLights struct {
	err error
}

// GetLights() is same as hue.User.GetLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLights() ([]hue.Light, error) {
	c := make(chan rGetLights)
	for _, api := range m.apis {
		go gGetLights(c, api)
	}
	return lGetLights(c, len(m.apis))
}

func gGetLights(c chan rGetLights, api hue.API) {
	lights, err := api.GetLights()
	c <- rGetLights{mapLightIds(lights), err}
}

func lGetLights(c chan rGetLights, nResponses int) ([]hue.Light, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <- c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		} else {
			lLights = append(lLights, result.lights)
		}
	}

	return mergeLights(lLights), mergeErrors(lErrors)
}

// GetNewLights() is same as hue.User.GetNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetNewLights() ([]hue.Light, time.Time, error) {
	c := make(chan rGetNewLights)
	for _, api := range m.apis {
		go gGetNewLights(c, api)
	}
	return lGetNewLights(c, len(m.apis))
}

func gGetNewLights(c chan rGetNewLights, api hue.API) {
	lights, lastScan, err := api.GetNewLights()
	c <- rGetNewLights{mapLightIds(lights), lastScan, err}
}

func lGetNewLights(c chan rGetNewLights, nResponses int) ([]hue.Light, time.Time, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)
	lLastScan := make([]time.Time, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <- c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
		if result.lights != nil {
			lLights = append(lLights, result.lights)
		}
		lLastScan = append(lLastScan, result.lastScan)
	}

	return mergeLights(lLights), mergeTime(lLastScan), mergeErrors(lErrors)
}

// SearchForNewLights() is same as hue.User.SearchForNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SearchForNewLights() error {
	c := make(chan rSearchForNewLights)
	for _, api := range m.apis {
		go gSearchForNewLights(c, api)
	}
	return lSearchForNewLights(c, len(m.apis))
}

func gSearchForNewLights(c chan rSearchForNewLights, api hue.API) {
	err := api.SearchForNewLights()
	c <- rSearchForNewLights{err}
}

func lSearchForNewLights(c chan rSearchForNewLights, nResponses int) error {
	lErrors := make([]error, 0, 1)

	for i := 0; i < nResponses; i++ {
		result := <- c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
	}

	return mergeErrors(lErrors)
}

// GetLightAttributes() is same as hue.User.GetLightAttributes() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLightAttributes(lightId string) (*hue.LightAttributes, error) {
	api, newLightId, err := m.findAPIAndLightId(lightId)
	if err != nil {
		return nil, err
	}
	return api.GetLightAttributes(newLightId)
}

// SetLightName() is same as hue.User.SetLightName() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightName(lightId string, name string) error {
	api, newLightId, err := m.findAPIAndLightId(lightId)
	if err != nil {
		return err
	}
	return api.SetLightName(newLightId, name)
}

// SetLightState() is same as hue.User.SetLightState() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightState(lightId string, state *hue.LightState) error {
	api, newLightId, err := m.findAPIAndLightId(lightId)
	if err != nil {
		return err
	}
	return api.SetLightState(newLightId, state)
}

func mergeLights(lLights [][]hue.Light) []hue.Light {
	countOfLights := 0
	for _, lights := range lLights {
		countOfLights += len(lights)
	}

	mLights := make([]hue.Light, countOfLights)
	copyTo := 0
	for _, lights := range lLights {
		copy(mLights[copyTo:], lights)
		copyTo += len(lights)
	}

	return mLights
}

func mergeErrors(lErrors []error) error {
	return nil
}

func mergeTime(lTime []time.Time) time.Time {
	return lTime[0]
}

func mapLightIds(lLights []hue.Light) []hue.Light {
	return lLights
}

func (m *MultiAPI) findAPIAndLightId(lightId string) (hue.API, string, error) {
	return m.apis[0], lightId, nil
}
<|endoftext|>


<commit_before>package curr

import (
	"os"
	"testing"

	. "github.com/otiai10/mint"
)

var pkgpath string

func init() {
	gopath := os.Getenv("GOPATH")
	pkgpath = gopath + "/src/github.com/otiai10/curr"
}

func TestLine(t *testing.T) {
	Because(t, "Line() should provide current line", func(t *testing.T) {
		Expect(t, Line()).ToBe(19)
		// <- line 20
		Expect(t, Line()).ToBe(21)
	})
}

func TestFunc(t *testing.T) {
	Because(t, "Func() should provide current function name", func(t *testing.T) {
		Expect(t, Foobaa()).ToBe("Foobaa")
	})
	Expect(t, Func()).ToBe("TestFunc")
}

func TestFile(t *testing.T) {
	Because(t, "File() should provide current file name", func(t *testing.T) {
		Expect(t, File()).ToBe(pkgpath + "/all_test.go")
	})
}

func TestBasename(t *testing.T) {
	Because(t, "Basename() should provide current file basename", func(t *testing.T) {
		Expect(t, Basename()).ToBe("all_test.go")
	})
}

func TestDir(t *testing.T) {
	Because(t, "Dir() should provide current directory", func(t *testing.T) {
		Expect(t, Dir()).ToBe(pkgpath)
	})
}

func Foobaa() string {
	return Func()
}
<commit_msg>Fix test<commit_after>package curr

import (
	"os"
	"testing"

	. "github.com/otiai10/mint"
)

var pkgpath string

func init() {
	pkgpath = os.Getenv("GITHUB_WORKSPACE")
	if pkgpath == "" {
		pkgpath = os.Getenv("GOPATH") + "/src/github.com/otiai10/curr"
	}
}

func TestLine(t *testing.T) {
	Because(t, "Line() should provide current line", func(t *testing.T) {
		Expect(t, Line()).ToBe(21)
		// <- line 22
		Expect(t, Line()).ToBe(23)
	})
}

func TestFunc(t *testing.T) {
	Because(t, "Func() should provide current function name", func(t *testing.T) {
		Expect(t, Foobaa()).ToBe("Foobaa")
	})
	Expect(t, Func()).ToBe("TestFunc")
}

func TestFile(t *testing.T) {
	Because(t, "File() should provide current file name", func(t *testing.T) {
		Expect(t, File()).ToBe(pkgpath + "/all_test.go")
	})
}

func TestBasename(t *testing.T) {
	Because(t, "Basename() should provide current file basename", func(t *testing.T) {
		Expect(t, Basename()).ToBe("all_test.go")
	})
}

func TestDir(t *testing.T) {
	Because(t, "Dir() should provide current directory", func(t *testing.T) {
		Expect(t, Dir()).ToBe(pkgpath)
	})
}

func Foobaa() string {
	return Func()
}
<|endoftext|>


<commit_before>// Package textual provides some simple functions for manipulating text.
package textual

import (
	"bytes"
	"strings"
)

// Truncate the given string to length using … as ellipsis.
func Truncate(s string, length int) string {
	return TruncateWithEllipsis(s,length,"…")
}

// Truncate the given string to length using provided ellipsis.
func TruncateWithEllipsis(s string, length int, ellipsis string) string {

	l := len(s)
	el := len(ellipsis)
	if l+el > length {
		s = string(s[0:length-el]) + ellipsis
	}
	return s
}

// Provide the plural version of an English word using some simple rules and a table of exceptions.
func ToPlural(text string) (plural string) {

	// We only deal with lowercase
	word := strings.ToLower(text)

	// Check translations first, and return a direct translation if there is one
	if translations[word] != "" {
		return translations[word]
	}

	// If we have no translation, just follow some basic rules - avoid new rules if possible
	if strings.HasSuffix(word, "s") || strings.HasSuffix(word, "z") || strings.HasSuffix(word, "h") {
		plural = word + "es"
	} else if strings.HasSuffix(word, "y") {
		plural = strings.TrimRight(word, "y") + "ies"
	} else if strings.HasSuffix(word, "um") {
		plural = strings.TrimRight(word, "um") + "a"
	} else {
		plural = word + "s"
	}

	return plural
}

// Which irregulars are important or correct depends on your usage of English
// Some of those below are now considered old-fashioned and many more could be added
// As this is used for database models, it only needs a limited subset of all irregulars
// NB you should not attempt to reverse and singularize, but just use the singular provided
var translations = map[string]string{
	"hero":        "heroes",
	"supernova":   "supernovae",
	"day":         "days",
	"monkey":      "monkeys",
	"money":       "monies",
	"chassis":     "chassis",
	"sheep":       "sheep",
	"aircraft":    "aircraft",
	"fish":        "fish",
	"nucleus":     "nuclei",
	"mouse":       "mice",
	"buffalo":     "buffalo",
	"species":     "species",
	"information": "information",
	"wife":        "wives",
	"shelf":       "shelves",
	"index":       "indices",
	"matrix":      "matrices",
	"formula":     "formulae",
	"millennium":  "millennia",
	"ganglion":    "ganglia",
	"octopus":     "octopodes",
	"man":         "men",
	"woman":       "women",
	"person":      "people",
	"axis":        "axes",
	"die":         "dice",
	// ..etc
}

// Convert string from struct field names to corresponding database column names (e.g. FieldName to field_name)
func ToSnake(text string) string {
	b := bytes.NewBufferString("")
	for i, c := range text {
		if i > 0 && c >= 'A' && c <= 'Z' {
			b.WriteRune('_')
		}
		b.WriteRune(c)
	}
	return strings.ToLower(b.String())
}

// Convert string from database column names to corresponding struct field names (e.g. field_name to FieldName)
func ToCamel(text string, private ...bool) string {
	lowerCamel := false
	if private != nil {
		lowerCamel = private[0]
	}
	b := bytes.NewBufferString("")
	s := strings.Split(text, "_")
	for i, v := range s {
		if len(v) > 0 {
			s := v[:1]
			if i > 0 || lowerCamel == false {
				s = strings.ToUpper(s)
			}
			b.WriteString(s)
			b.WriteString(v[1:])
		}
	}
	return b.String()
}
<commit_msg>Updated truncate ellipsis<commit_after>// Package textual provides some simple functions for manipulating text.
package textual

import (
	"bytes"
	"strings"
)

// Truncate the given string to length using … as ellipsis.
func Truncate(s string, length int) string {
	return TruncateWithEllipsis(s, length, "…")
}

// Truncate the given string to length using provided ellipsis.
func TruncateWithEllipsis(s string, length int, ellipsis string) string {

	l := len(s)
	el := len(ellipsis)
	if l+el > length {
		s = string(s[0:length-el]) + ellipsis
	}
	return s
}

// Provide the plural version of an English word using some simple rules and a table of exceptions.
func ToPlural(text string) (plural string) {

	// We only deal with lowercase
	word := strings.ToLower(text)

	// Check translations first, and return a direct translation if there is one
	if translations[word] != "" {
		return translations[word]
	}

	// If we have no translation, just follow some basic rules - avoid new rules if possible
	if strings.HasSuffix(word, "s") || strings.HasSuffix(word, "z") || strings.HasSuffix(word, "h") {
		plural = word + "es"
	} else if strings.HasSuffix(word, "y") {
		plural = strings.TrimRight(word, "y") + "ies"
	} else if strings.HasSuffix(word, "um") {
		plural = strings.TrimRight(word, "um") + "a"
	} else {
		plural = word + "s"
	}

	return plural
}

// Which irregulars are important or correct depends on your usage of English
// Some of those below are now considered old-fashioned and many more could be added
// As this is used for database models, it only needs a limited subset of all irregulars
// NB you should not attempt to reverse and singularize, but just use the singular provided
var translations = map[string]string{
	"hero":        "heroes",
	"supernova":   "supernovae",
	"day":         "days",
	"monkey":      "monkeys",
	"money":       "monies",
	"chassis":     "chassis",
	"sheep":       "sheep",
	"aircraft":    "aircraft",
	"fish":        "fish",
	"nucleus":     "nuclei",
	"mouse":       "mice",
	"buffalo":     "buffalo",
	"species":     "species",
	"information": "information",
	"wife":        "wives",
	"shelf":       "shelves",
	"index":       "indices",
	"matrix":      "matrices",
	"formula":     "formulae",
	"millennium":  "millennia",
	"ganglion":    "ganglia",
	"octopus":     "octopodes",
	"man":         "men",
	"woman":       "women",
	"person":      "people",
	"axis":        "axes",
	"die":         "dice",
	// ..etc
}

// Convert string from struct field names to corresponding database column names (e.g. FieldName to field_name)
func ToSnake(text string) string {
	b := bytes.NewBufferString("")
	for i, c := range text {
		if i > 0 && c >= 'A' && c <= 'Z' {
			b.WriteRune('_')
		}
		b.WriteRune(c)
	}
	return strings.ToLower(b.String())
}

// Convert string from database column names to corresponding struct field names (e.g. field_name to FieldName)
func ToCamel(text string, private ...bool) string {
	lowerCamel := false
	if private != nil {
		lowerCamel = private[0]
	}
	b := bytes.NewBufferString("")
	s := strings.Split(text, "_")
	for i, v := range s {
		if len(v) > 0 {
			s := v[:1]
			if i > 0 || lowerCamel == false {
				s = strings.ToUpper(s)
			}
			b.WriteString(s)
			b.WriteString(v[1:])
		}
	}
	return b.String()
}
<|endoftext|>