<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 datastore provides a client for Google Cloud Datastore.

Note: This package is in beta.  Some backwards-incompatible changes may occur.

Basic Operations

Entities are the unit of storage and are associated with a key. A key
consists of an optional parent key, a string application ID, a string kind
(also known as an entity type), and either a StringID or an IntID. A
StringID is also known as an entity name or key name.

It is valid to create a key with a zero StringID and a zero IntID; this is
called an incomplete key, and does not refer to any saved entity. Putting an
entity into the datastore under an incomplete key will cause a unique key
to be generated for that entity, with a non-zero IntID.

An entity's contents are a mapping from case-sensitive field names to values.
Valid value types are:
  - signed integers (int, int8, int16, int32 and int64),
  - bool,
  - string,
  - float32 and float64,
  - []byte (up to 1 megabyte in length),
  - any type whose underlying type is one of the above predeclared types,
  - *Key,
  - GeoPoint,
  - time.Time (stored with microsecond precision),
  - structs whose fields are all valid value types,
  - pointers to structs whose fields are all valid value types,
  - slices of any of the above.

Slices of structs are valid, as are structs that contain slices.

The Get and Put functions load and save an entity's contents. An entity's
contents are typically represented by a struct pointer.

Example code:

	type Entity struct {
		Value string
	}

	func main() {
		ctx := context.Background()

		// Create a datastore client. In a typical application, you would create
		// a single client which is reused for every datastore operation.
		dsClient, err := datastore.NewClient(ctx, "my-project")
		if err != nil {
			// Handle error.
		}

		k := datastore.NameKey("Entity", "stringID", nil)
		e := new(Entity)
		if err := dsClient.Get(ctx, k, e); err != nil {
			// Handle error.
		}

		old := e.Value
		e.Value = "Hello World!"

		if _, err := dsClient.Put(ctx, k, e); err != nil {
			// Handle error.
		}

		fmt.Printf("Updated value from %q to %q\n", old, e.Value)
	}

GetMulti, PutMulti and DeleteMulti are batch versions of the Get, Put and
Delete functions. They take a []*Key instead of a *Key, and may return a
datastore.MultiError when encountering partial failure.

Properties

An entity's contents can be represented by a variety of types. These are
typically struct pointers, but can also be any type that implements the
PropertyLoadSaver interface. If using a struct pointer, you do not have to
explicitly implement the PropertyLoadSaver interface; the datastore will
automatically convert via reflection. If a struct pointer does implement that
interface then those methods will be used in preference to the default
behavior for struct pointers. Struct pointers are more strongly typed and are
easier to use; PropertyLoadSavers are more flexible.

The actual types passed do not have to match between Get and Put calls or even
across different calls to datastore. It is valid to put a *PropertyList and
get that same entity as a *myStruct, or put a *myStruct0 and get a *myStruct1.
Conceptually, any entity is saved as a sequence of properties, and is loaded
into the destination value on a property-by-property basis. When loading into
a struct pointer, an entity that cannot be completely represented (such as a
missing field) will result in an ErrFieldMismatch error but it is up to the
caller whether this error is fatal, recoverable or ignorable.

By default, for struct pointers, all properties are potentially indexed, and
the property name is the same as the field name (and hence must start with an
upper case letter).

Fields may have a `datastore:"name,options"` tag. The tag name is the
property name, which must be one or more valid Go identifiers joined by ".",
but may start with a lower case letter. An empty tag name means to just use the
field name. A "-" tag name means that the datastore will ignore that field.

The only valid options are "omitempty", "noindex" and "flatten".

If the options include "omitempty" and the value of the field is empty, then the field will be omitted on Save.
The empty values are false, 0, any nil interface value, and any array, slice, map, or string of length zero.
Struct field values will never be empty.

If options include "noindex" then the field will not be indexed. All fields are indexed
by default. Strings or byte slices longer than 1500 bytes cannot be indexed;
fields used to store long strings and byte slices must be tagged with "noindex"
or they will cause Put operations to fail.

For a nested struct field, the options may also include "flatten". This indicates
that the immediate fields and any nested substruct fields of the nested struct should be
flattened. See below for examples.

To use multiple options together, separate them by a comma.
The order does not matter.

If the options is "" then the comma may be omitted.

Example code:

	// A and B are renamed to a and b.
	// A, C and J are not indexed.
	// D's tag is equivalent to having no tag at all (E).
	// I is ignored entirely by the datastore.
	// J has tag information for both the datastore and json packages.
	type TaggedStruct struct {
		A int `datastore:"a,noindex"`
		B int `datastore:"b"`
		C int `datastore:",noindex"`
		D int `datastore:""`
		E int
		I int `datastore:"-"`
		J int `datastore:",noindex" json:"j"`
	}

Key Field

If the struct contains a *datastore.Key field tagged with the name "__key__",
its value will be ignored on Put. When reading the Entity back into the Go struct,
the field will be populated with the *datastore.Key value used to query for
the Entity.

Example code:

	type MyEntity struct {
		A int
		K *datastore.Key `datastore:"__key__"`
	}

	k := datastore.NameKey("Entity", "stringID", nil)
	e := MyEntity{A: 12}
	k, err = dsClient.Put(ctx, k, e)
	if err != nil {
		// Handle error.
	}

	var entities []Entity
	q := datastore.NewQuery("Entity").Filter("A =", 12).Limit(1)
	_, err := datastore.GetAll(ctx, q, &entities)
	if err != nil {
		// Handle error
	}

	log.Println(entities[0])
	// Prints {12 /Entity,stringID}

Structured Properties

If the struct pointed to contains other structs, then the nested or embedded
structs are themselves saved as Entity values. For example, given these definitions:

	type Inner struct {
		W int32
		X string
	}

	type Outer struct {
		I Inner
	}

then an Outer would have one property, Inner, encoded as an Entity value.

If an outer struct is tagged "noindex" then all of its implicit flattened
fields are effectively "noindex".

If the Inner struct contains a *Key field with the name "__key__", like so:

	type Inner struct {
		W int32
		X string
		K *datastore.Key `datastore:"__key__"`
	}

	type Outer struct {
		I Inner
	}

then the value of K will be used as the Key for Inner, represented
as an Entity value in datastore.

If any nested struct fields should be flattened, instead of encoded as
Entity values, the nested struct field should be tagged with the "flatten"
option. For example, given the following:

	type Inner1 struct {
		W int32
		X string
	}

	type Inner2 struct {
		Y float64
	}

	type Inner3 struct {
		Z bool
	}

	type Inner4 struct {
		WW int
	}

	type Inner5 struct {
		X Inner4
	}

	type Outer struct {
		A int16
		I []Inner1 `datastore:",flatten"`
		J Inner2   `datastore:",flatten"`
		K Inner5   `datastore:",flatten"`
		Inner3     `datastore:",flatten"`
	}

an Outer's properties would be equivalent to those of:

	type OuterEquivalent struct {
		A          int16
		IDotW      []int32  `datastore:"I.W"`
		IDotX      []string `datastore:"I.X"`
		JDotY      float64  `datastore:"J.Y"`
		KDotXDotWW int      `datastore:"K.X.WW"`
		Z          bool
	}

Note that the "flatten" option cannot be used for Entity value fields.
The server will reject any dotted field names for an Entity value.

The PropertyLoadSaver Interface

An entity's contents can also be represented by any type that implements the
PropertyLoadSaver interface. This type may be a struct pointer, but it does
not have to be. The datastore package will call Load when getting the entity's
contents, and Save when putting the entity's contents.
Possible uses include deriving non-stored fields, verifying fields, or indexing
a field only if its value is positive.

Example code:

	type CustomPropsExample struct {
		I, J int
		// Sum is not stored, but should always be equal to I + J.
		Sum int `datastore:"-"`
	}

	func (x *CustomPropsExample) Load(ps []datastore.Property) error {
		// Load I and J as usual.
		if err := datastore.LoadStruct(x, ps); err != nil {
			return err
		}
		// Derive the Sum field.
		x.Sum = x.I + x.J
		return nil
	}

	func (x *CustomPropsExample) Save() ([]datastore.Property, error) {
		// Validate the Sum field.
		if x.Sum != x.I + x.J {
			return errors.New("CustomPropsExample has inconsistent sum")
		}
		// Save I and J as usual. The code below is equivalent to calling
		// "return datastore.SaveStruct(x)", but is done manually for
		// demonstration purposes.
		return []datastore.Property{
			{
				Name:  "I",
				Value: int64(x.I),
			},
			{
				Name:  "J",
				Value: int64(x.J),
			},
		}
	}

The *PropertyList type implements PropertyLoadSaver, and can therefore hold an
arbitrary entity's contents.

Queries

Queries retrieve entities based on their properties or key's ancestry. Running
a query yields an iterator of results: either keys or (key, entity) pairs.
Queries are re-usable and it is safe to call Query.Run from concurrent
goroutines. Iterators are not safe for concurrent use.

Queries are immutable, and are either created by calling NewQuery, or derived
from an existing query by calling a method like Filter or Order that returns a
new query value. A query is typically constructed by calling NewQuery followed
by a chain of zero or more such methods. These methods are:
  - Ancestor and Filter constrain the entities returned by running a query.
  - Order affects the order in which they are returned.
  - Project constrains the fields returned.
  - Distinct de-duplicates projected entities.
  - KeysOnly makes the iterator return only keys, not (key, entity) pairs.
  - Start, End, Offset and Limit define which sub-sequence of matching entities
    to return. Start and End take cursors, Offset and Limit take integers. Start
    and Offset affect the first result, End and Limit affect the last result.
    If both Start and Offset are set, then the offset is relative to Start.
    If both End and Limit are set, then the earliest constraint wins. Limit is
    relative to Start+Offset, not relative to End. As a special case, a
    negative limit means unlimited.

Example code:

	type Widget struct {
		Description string
		Price       int
	}

	func printWidgets(ctx context.Context, client *datastore.Client) {
		q := datastore.NewQuery("Widget").
			Filter("Price <", 1000).
			Order("-Price")
		for t := dsClient.Run(ctx, q); ; {
			var x Widget
			key, err := t.Next(&x)
			if err == iterator.Done {
				break
			}
			if err != nil {
				// Handle error.
			}
			fmt.Printf("Key=%v\nWidget=%#v\n\n", key, x)
		}
	}

Transactions

Client.RunInTransaction runs a function in a transaction.

Example code:

	type Counter struct {
		Count int
	}

	func incCount(ctx context.Context, client *datastore.Client) {
		var count int
		key := datastore.NameKey("Counter", "singleton", nil)
		_, err := dsClient.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
			var x Counter
			if err := tx.Get(key, &x); err != nil && err != datastore.ErrNoSuchEntity {
				return err
			}
			x.Count++
			if _, err := tx.Put(key, &x); err != nil {
				return err
			}
			count = x.Count
			return nil
		})
		if err != nil {
			// Handle error.
		}
		// The value of count is only valid once the transaction is successful
		// (RunInTransaction has returned nil).
		fmt.Printf("Count=%d\n", count)
	}

Google Cloud Datastore Emulator

This package supports the Cloud Datastore emulator, which is useful for testing and
development. Environment variables are used to indicate that datastore traffic should be
directed to the emulator instead of the production Datastore service.

To install and set up the emulator and its environment variables, see the documentation
at https://cloud.google.com/datastore/docs/tools/datastore-emulator.

*/
package datastore // import "cloud.google.com/go/datastore"
<commit_msg>datastore: update broken doc examples<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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 datastore provides a client for Google Cloud Datastore.

Note: This package is in beta.  Some backwards-incompatible changes may occur.

Basic Operations

Entities are the unit of storage and are associated with a key. A key
consists of an optional parent key, a string application ID, a string kind
(also known as an entity type), and either a StringID or an IntID. A
StringID is also known as an entity name or key name.

It is valid to create a key with a zero StringID and a zero IntID; this is
called an incomplete key, and does not refer to any saved entity. Putting an
entity into the datastore under an incomplete key will cause a unique key
to be generated for that entity, with a non-zero IntID.

An entity's contents are a mapping from case-sensitive field names to values.
Valid value types are:
  - signed integers (int, int8, int16, int32 and int64),
  - bool,
  - string,
  - float32 and float64,
  - []byte (up to 1 megabyte in length),
  - any type whose underlying type is one of the above predeclared types,
  - *Key,
  - GeoPoint,
  - time.Time (stored with microsecond precision),
  - structs whose fields are all valid value types,
  - pointers to structs whose fields are all valid value types,
  - slices of any of the above.

Slices of structs are valid, as are structs that contain slices.

The Get and Put functions load and save an entity's contents. An entity's
contents are typically represented by a struct pointer.

Example code:

	type Entity struct {
		Value string
	}

	func main() {
		ctx := context.Background()

		// Create a datastore client. In a typical application, you would create
		// a single client which is reused for every datastore operation.
		dsClient, err := datastore.NewClient(ctx, "my-project")
		if err != nil {
			// Handle error.
		}

		k := datastore.NameKey("Entity", "stringID", nil)
		e := new(Entity)
		if err := dsClient.Get(ctx, k, e); err != nil {
			// Handle error.
		}

		old := e.Value
		e.Value = "Hello World!"

		if _, err := dsClient.Put(ctx, k, e); err != nil {
			// Handle error.
		}

		fmt.Printf("Updated value from %q to %q\n", old, e.Value)
	}

GetMulti, PutMulti and DeleteMulti are batch versions of the Get, Put and
Delete functions. They take a []*Key instead of a *Key, and may return a
datastore.MultiError when encountering partial failure.

Properties

An entity's contents can be represented by a variety of types. These are
typically struct pointers, but can also be any type that implements the
PropertyLoadSaver interface. If using a struct pointer, you do not have to
explicitly implement the PropertyLoadSaver interface; the datastore will
automatically convert via reflection. If a struct pointer does implement that
interface then those methods will be used in preference to the default
behavior for struct pointers. Struct pointers are more strongly typed and are
easier to use; PropertyLoadSavers are more flexible.

The actual types passed do not have to match between Get and Put calls or even
across different calls to datastore. It is valid to put a *PropertyList and
get that same entity as a *myStruct, or put a *myStruct0 and get a *myStruct1.
Conceptually, any entity is saved as a sequence of properties, and is loaded
into the destination value on a property-by-property basis. When loading into
a struct pointer, an entity that cannot be completely represented (such as a
missing field) will result in an ErrFieldMismatch error but it is up to the
caller whether this error is fatal, recoverable or ignorable.

By default, for struct pointers, all properties are potentially indexed, and
the property name is the same as the field name (and hence must start with an
upper case letter).

Fields may have a `datastore:"name,options"` tag. The tag name is the
property name, which must be one or more valid Go identifiers joined by ".",
but may start with a lower case letter. An empty tag name means to just use the
field name. A "-" tag name means that the datastore will ignore that field.

The only valid options are "omitempty", "noindex" and "flatten".

If the options include "omitempty" and the value of the field is empty, then the field will be omitted on Save.
The empty values are false, 0, any nil interface value, and any array, slice, map, or string of length zero.
Struct field values will never be empty.

If options include "noindex" then the field will not be indexed. All fields are indexed
by default. Strings or byte slices longer than 1500 bytes cannot be indexed;
fields used to store long strings and byte slices must be tagged with "noindex"
or they will cause Put operations to fail.

For a nested struct field, the options may also include "flatten". This indicates
that the immediate fields and any nested substruct fields of the nested struct should be
flattened. See below for examples.

To use multiple options together, separate them by a comma.
The order does not matter.

If the options is "" then the comma may be omitted.

Example code:

	// A and B are renamed to a and b.
	// A, C and J are not indexed.
	// D's tag is equivalent to having no tag at all (E).
	// I is ignored entirely by the datastore.
	// J has tag information for both the datastore and json packages.
	type TaggedStruct struct {
		A int `datastore:"a,noindex"`
		B int `datastore:"b"`
		C int `datastore:",noindex"`
		D int `datastore:""`
		E int
		I int `datastore:"-"`
		J int `datastore:",noindex" json:"j"`
	}

Key Field

If the struct contains a *datastore.Key field tagged with the name "__key__",
its value will be ignored on Put. When reading the Entity back into the Go struct,
the field will be populated with the *datastore.Key value used to query for
the Entity.

Example code:

	type MyEntity struct {
		A int
		K *datastore.Key `datastore:"__key__"`
	}

	k := datastore.NameKey("Entity", "stringID", nil)
	e := MyEntity{A: 12}
	k, err = dsClient.Put(ctx, k, e)
	if err != nil {
		// Handle error.
	}

	var entities []MyEntity
	q := datastore.NewQuery("Entity").Filter("A =", 12).Limit(1)
	_, err := dsClient.GetAll(ctx, q, &entities)
	if err != nil {
		// Handle error
	}

	log.Println(entities[0])
	// Prints {12 /Entity,stringID}

Structured Properties

If the struct pointed to contains other structs, then the nested or embedded
structs are themselves saved as Entity values. For example, given these definitions:

	type Inner struct {
		W int32
		X string
	}

	type Outer struct {
		I Inner
	}

then an Outer would have one property, Inner, encoded as an Entity value.

If an outer struct is tagged "noindex" then all of its implicit flattened
fields are effectively "noindex".

If the Inner struct contains a *Key field with the name "__key__", like so:

	type Inner struct {
		W int32
		X string
		K *datastore.Key `datastore:"__key__"`
	}

	type Outer struct {
		I Inner
	}

then the value of K will be used as the Key for Inner, represented
as an Entity value in datastore.

If any nested struct fields should be flattened, instead of encoded as
Entity values, the nested struct field should be tagged with the "flatten"
option. For example, given the following:

	type Inner1 struct {
		W int32
		X string
	}

	type Inner2 struct {
		Y float64
	}

	type Inner3 struct {
		Z bool
	}

	type Inner4 struct {
		WW int
	}

	type Inner5 struct {
		X Inner4
	}

	type Outer struct {
		A int16
		I []Inner1 `datastore:",flatten"`
		J Inner2   `datastore:",flatten"`
		K Inner5   `datastore:",flatten"`
		Inner3     `datastore:",flatten"`
	}

an Outer's properties would be equivalent to those of:

	type OuterEquivalent struct {
		A          int16
		IDotW      []int32  `datastore:"I.W"`
		IDotX      []string `datastore:"I.X"`
		JDotY      float64  `datastore:"J.Y"`
		KDotXDotWW int      `datastore:"K.X.WW"`
		Z          bool
	}

Note that the "flatten" option cannot be used for Entity value fields.
The server will reject any dotted field names for an Entity value.

The PropertyLoadSaver Interface

An entity's contents can also be represented by any type that implements the
PropertyLoadSaver interface. This type may be a struct pointer, but it does
not have to be. The datastore package will call Load when getting the entity's
contents, and Save when putting the entity's contents.
Possible uses include deriving non-stored fields, verifying fields, or indexing
a field only if its value is positive.

Example code:

	type CustomPropsExample struct {
		I, J int
		// Sum is not stored, but should always be equal to I + J.
		Sum int `datastore:"-"`
	}

	func (x *CustomPropsExample) Load(ps []datastore.Property) error {
		// Load I and J as usual.
		if err := datastore.LoadStruct(x, ps); err != nil {
			return err
		}
		// Derive the Sum field.
		x.Sum = x.I + x.J
		return nil
	}

	func (x *CustomPropsExample) Save() ([]datastore.Property, error) {
		// Validate the Sum field.
		if x.Sum != x.I + x.J {
			return nil, errors.New("CustomPropsExample has inconsistent sum")
		}
		// Save I and J as usual. The code below is equivalent to calling
		// "return datastore.SaveStruct(x)", but is done manually for
		// demonstration purposes.
		return []datastore.Property{
			{
				Name:  "I",
				Value: int64(x.I),
			},
			{
				Name:  "J",
				Value: int64(x.J),
			},
		}, nil
	}

The *PropertyList type implements PropertyLoadSaver, and can therefore hold an
arbitrary entity's contents.

Queries

Queries retrieve entities based on their properties or key's ancestry. Running
a query yields an iterator of results: either keys or (key, entity) pairs.
Queries are re-usable and it is safe to call Query.Run from concurrent
goroutines. Iterators are not safe for concurrent use.

Queries are immutable, and are either created by calling NewQuery, or derived
from an existing query by calling a method like Filter or Order that returns a
new query value. A query is typically constructed by calling NewQuery followed
by a chain of zero or more such methods. These methods are:
  - Ancestor and Filter constrain the entities returned by running a query.
  - Order affects the order in which they are returned.
  - Project constrains the fields returned.
  - Distinct de-duplicates projected entities.
  - KeysOnly makes the iterator return only keys, not (key, entity) pairs.
  - Start, End, Offset and Limit define which sub-sequence of matching entities
    to return. Start and End take cursors, Offset and Limit take integers. Start
    and Offset affect the first result, End and Limit affect the last result.
    If both Start and Offset are set, then the offset is relative to Start.
    If both End and Limit are set, then the earliest constraint wins. Limit is
    relative to Start+Offset, not relative to End. As a special case, a
    negative limit means unlimited.

Example code:

	type Widget struct {
		Description string
		Price       int
	}

	func printWidgets(ctx context.Context, client *datastore.Client) {
		q := datastore.NewQuery("Widget").
			Filter("Price <", 1000).
			Order("-Price")
		for t := client.Run(ctx, q); ; {
			var x Widget
			key, err := t.Next(&x)
			if err == iterator.Done {
				break
			}
			if err != nil {
				// Handle error.
			}
			fmt.Printf("Key=%v\nWidget=%#v\n\n", key, x)
		}
	}

Transactions

Client.RunInTransaction runs a function in a transaction.

Example code:

	type Counter struct {
		Count int
	}

	func incCount(ctx context.Context, client *datastore.Client) {
		var count int
		key := datastore.NameKey("Counter", "singleton", nil)
		_, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error {
			var x Counter
			if err := tx.Get(key, &x); err != nil && err != datastore.ErrNoSuchEntity {
				return err
			}
			x.Count++
			if _, err := tx.Put(key, &x); err != nil {
				return err
			}
			count = x.Count
			return nil
		})
		if err != nil {
			// Handle error.
		}
		// The value of count is only valid once the transaction is successful
		// (RunInTransaction has returned nil).
		fmt.Printf("Count=%d\n", count)
	}

Google Cloud Datastore Emulator

This package supports the Cloud Datastore emulator, which is useful for testing and
development. Environment variables are used to indicate that datastore traffic should be
directed to the emulator instead of the production Datastore service.

To install and set up the emulator and its environment variables, see the documentation
at https://cloud.google.com/datastore/docs/tools/datastore-emulator.

*/
package datastore // import "cloud.google.com/go/datastore"
<|endoftext|>


<commit_before>package lib

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	log "github.com/sirupsen/logrus"

	da "github.com/cvmfs/docker-graphdriver/daemon/docker-api"
)

func getAllLayers() []string {
	path := filepath.Join("/", "cvmfs", "*", subDirInsideRepo, "*")
	paths, _ := filepath.Glob(path)
	return paths
}

// this function is based on an "homegrow" implementation of a set intersection, go, since it does not provide generics, does not provides also generic datastructures like sets
func findToRemoveLayers(all_layers, needed_layers []string) (removes []string) {
	all := map[string]bool{}
	needed := map[string]bool{}
	to_remove := map[string]bool{}

	for _, layer := range all_layers {
		all[layer] = true
	}
	for _, layer := range needed_layers {
		needed[layer] = true
	}
	for layer, _ := range all {
		_, isNeeded := needed[layer]
		if !isNeeded {
			to_remove[layer] = true
		}
	}
	for layer := range to_remove {
		removes = append(removes, layer)
	}
	return
}

func findImageToGarbageCollect(CVMFSRepo string) ([]da.Manifest, error) {
	removeSchedulePath := RemoveScheduleLocation(CVMFSRepo)
	llog := func(l *log.Entry) *log.Entry {
		return l.WithFields(log.Fields{
			"action": "find image to garbage collect in schedule file",
			"file":   removeSchedulePath})
	}

	var schedule []da.Manifest

	_, err := os.Stat(removeSchedulePath)
	if os.IsNotExist(err) {
		return schedule, nil
	}
	if err != nil {
		llog(LogE(err)).Error("Error in stating the schedule file")
		return schedule, err
	}
	scheduleFileRO, err := os.Open(removeSchedulePath)
	if err != nil {
		llog(LogE(err)).Error("Error in opening the schedule file")
		return schedule, err
	}

	scheduleBytes, err := ioutil.ReadAll(scheduleFileRO)
	if err != nil {
		llog(LogE(err)).Error("Impossible to read the schedule file")
		return schedule, err
	}

	err = scheduleFileRO.Close()
	if err != nil {
		llog(LogE(err)).Error("Impossible to close the schedule file")
		return schedule, err
	}

	err = json.Unmarshal(scheduleBytes, &schedule)
	if err != nil {
		llog(LogE(err)).Error("Impossible to unmarshal the schedule file")
		return schedule, err
	}

	return schedule, nil
}

// with image and layer we pass the digest of the layer and the digest of the image
func garbabeCollectSingleLayer(CVMFSRepo, image, layer string) error {
	return nil
}

func RemoveUselessLayers() error {
	all_layers := getAllLayers()
	needed_layers, err := GetAllNeededLayers()
	if err != nil {
		return err
	}
	to_remove := findToRemoveLayers(all_layers, needed_layers)
	// to_remove is now a slice of paths that we wish to remove from the
	// repository.
	// However those paths are "complete":
	// `/cvmfs/$repo.name/layers/fffbbbaaa`
	// we need to group them by the repository they belong to, and then
	// extract only the last part of the path we care about:
	// `layers/fffbbbaaa`
	paths := map[string][]string{}
	for _, path := range to_remove {
		pathSplitted := strings.Split(path, "/")
		repoName := pathSplitted[2]
		paths[repoName] = append(paths[repoName], strings.Join(pathSplitted[3:], "/"))
	}
	fmt.Println(paths)
	// possible optimization
	// batch the delete of layers, not all together that it will lock the repo for quite too long
	// but few of them like 10 or 20 together is something very reasonable.
	for repoName, layers := range paths {
		for _, layer := range layers {
			err = ExecCommand("cvmfs_server", "ingest", "--delete", layer, repoName).Start()
			if err != nil {
				LogE(err).Warning("Error in deleting the layer")
			}
		}
	}
	return nil
}
<commit_msg>implement logic to garbage collect a single layer<commit_after>package lib

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	log "github.com/sirupsen/logrus"

	da "github.com/cvmfs/docker-graphdriver/daemon/docker-api"
)

func getAllLayers() []string {
	path := filepath.Join("/", "cvmfs", "*", subDirInsideRepo, "*")
	paths, _ := filepath.Glob(path)
	return paths
}

// this function is based on an "homegrow" implementation of a set intersection, go, since it does not provide generics, does not provides also generic datastructures like sets
func findToRemoveLayers(all_layers, needed_layers []string) (removes []string) {
	all := map[string]bool{}
	needed := map[string]bool{}
	to_remove := map[string]bool{}

	for _, layer := range all_layers {
		all[layer] = true
	}
	for _, layer := range needed_layers {
		needed[layer] = true
	}
	for layer, _ := range all {
		_, isNeeded := needed[layer]
		if !isNeeded {
			to_remove[layer] = true
		}
	}
	for layer := range to_remove {
		removes = append(removes, layer)
	}
	return
}

func findImageToGarbageCollect(CVMFSRepo string) ([]da.Manifest, error) {
	removeSchedulePath := RemoveScheduleLocation(CVMFSRepo)
	llog := func(l *log.Entry) *log.Entry {
		return l.WithFields(log.Fields{
			"action": "find image to garbage collect in schedule file",
			"file":   removeSchedulePath})
	}

	var schedule []da.Manifest

	_, err := os.Stat(removeSchedulePath)
	if os.IsNotExist(err) {
		return schedule, nil
	}
	if err != nil {
		llog(LogE(err)).Error("Error in stating the schedule file")
		return schedule, err
	}
	scheduleFileRO, err := os.Open(removeSchedulePath)
	if err != nil {
		llog(LogE(err)).Error("Error in opening the schedule file")
		return schedule, err
	}

	scheduleBytes, err := ioutil.ReadAll(scheduleFileRO)
	if err != nil {
		llog(LogE(err)).Error("Impossible to read the schedule file")
		return schedule, err
	}

	err = scheduleFileRO.Close()
	if err != nil {
		llog(LogE(err)).Error("Impossible to close the schedule file")
		return schedule, err
	}

	err = json.Unmarshal(scheduleBytes, &schedule)
	if err != nil {
		llog(LogE(err)).Error("Impossible to unmarshal the schedule file")
		return schedule, err
	}

	return schedule, nil
}

// with image and layer we pass the digest of the layer and the digest of the image, both without the sha256: prefix
func garbabeCollectSingleLayer(CVMFSRepo, image, layer string) error {
	backlink, err := getBacklinkFromLayer(CVMFSRepo, layer)
	llog := func(l *log.Entry) *log.Entry {
		return l.WithFields(log.Fields{"action": "garbage collect layer",
			"repo":  CVMFSRepo,
			"image": image,
			"layer": layer})
	}
	if err != nil {
		llog(LogE(err)).Error("Impossible to retrieve the backlink information")
		return err
	}
	var newOrigin []string
	for _, origin := range backlink.Origin {
		withoutPrefix := strings.Split(origin, ":")[1]
		if withoutPrefix != image {
			newOrigin = append(newOrigin, origin)
		}
	}
	if len(newOrigin) > 0 {
		backlink.Origin = newOrigin
		backLinkMarshall, err := json.Marshal(backlink)
		if err != nil {
			llog(LogE(err)).Error("Error in marshaling the new backlink")
			return err
		}

		backlinkPath := getBacklinkPath(CVMFSRepo, layer)

		err = ExecCommand("cvmfs_server", "transaction", CVMFSRepo).Start()
		if err != nil {
			llog(LogE(err)).Error("Error in opening the transaction")
			return err
		}

		dir := filepath.Dir(backlinkPath)
		if _, err := os.Stat(dir); os.IsNotExist(err) {
			err = os.MkdirAll(dir, 0666)
			if err != nil {
				llog(LogE(err)).WithFields(log.Fields{"directory": dir}).Error(
					"Error in creating the directory for the backlinks file, skipping...")
				return err
			}
		}

		err = ioutil.WriteFile(backlinkPath, backLinkMarshall, 0666)
		if err != nil {
			llog(LogE(err)).WithFields(log.Fields{"file": backlinkPath}).Error(
				"Error in writing the backlink file, skipping...")
			return err
		}

		err = ExecCommand("cvmfs_server", "publish", CVMFSRepo).Start()
		if err != nil {
			llog(LogE(err)).Error("Error in publishing after adding the backlinks")
			return err
		}
		// write it to file
		return nil
	} else {
		err = RemoveLayer(CVMFSRepo, layer)
		if err != nil {
			llog(LogE(err)).Error("Error in deleting the layer")
		}
		return err
	}
}

func RemoveUselessLayers() error {
	all_layers := getAllLayers()
	needed_layers, err := GetAllNeededLayers()
	if err != nil {
		return err
	}
	to_remove := findToRemoveLayers(all_layers, needed_layers)
	// to_remove is now a slice of paths that we wish to remove from the
	// repository.
	// However those paths are "complete":
	// `/cvmfs/$repo.name/layers/fffbbbaaa`
	// we need to group them by the repository they belong to, and then
	// extract only the last part of the path we care about:
	// `layers/fffbbbaaa`
	paths := map[string][]string{}
	for _, path := range to_remove {
		pathSplitted := strings.Split(path, "/")
		repoName := pathSplitted[2]
		paths[repoName] = append(paths[repoName], strings.Join(pathSplitted[3:], "/"))
	}
	fmt.Println(paths)
	// possible optimization
	// batch the delete of layers, not all together that it will lock the repo for quite too long
	// but few of them like 10 or 20 together is something very reasonable.
	for repoName, layers := range paths {
		for _, layer := range layers {
			err = ExecCommand("cvmfs_server", "ingest", "--delete", layer, repoName).Start()
			if err != nil {
				LogE(err).Warning("Error in deleting the layer")
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>//  Copyright (c) 2013 Couchbase, Inc.
//
// 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 searcher

import (
	"testing"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
)

func TestPhraseSearch(t *testing.T) {

	twoDocIndexReader, err := twoDocIndex.Reader()
	if err != nil {
		t.Error(err)
	}
	defer func() {
		err := twoDocIndexReader.Close()
		if err != nil {
			t.Fatal(err)
		}
	}()

	angstTermSearcher, err := NewTermSearcher(twoDocIndexReader, "angst", "desc", 1.0, true)
	if err != nil {
		t.Fatal(err)
	}
	beerTermSearcher, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true)
	if err != nil {
		t.Fatal(err)
	}
	mustSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{angstTermSearcher, beerTermSearcher}, true)
	if err != nil {
		t.Fatal(err)
	}
	phraseSearcher, err := NewPhraseSearcher(twoDocIndexReader, mustSearcher, []string{"angst", "beer"})
	if err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		searcher search.Searcher
		results  []*search.DocumentMatch
	}{
		{
			searcher: phraseSearcher,
			results: []*search.DocumentMatch{
				{
					IndexInternalID: index.IndexInternalID("2"),
					Score:           1.0807601687084403,
				},
			},
		},
	}

	for testIndex, test := range tests {
		defer func() {
			err := test.searcher.Close()
			if err != nil {
				t.Fatal(err)
			}
		}()

		ctx := &search.SearchContext{
			DocumentMatchPool: search.NewDocumentMatchPool(test.searcher.DocumentMatchPoolSize(), 0),
		}
		next, err := test.searcher.Next(ctx)
		i := 0
		for err == nil && next != nil {
			if i < len(test.results) {
				if !next.IndexInternalID.Equals(test.results[i].IndexInternalID) {
					t.Errorf("expected result %d to have id %s got %s for test %d", i, test.results[i].IndexInternalID, next.IndexInternalID, testIndex)
				}
				if next.Score != test.results[i].Score {
					t.Errorf("expected result %d to have score %v got  %v for test %d", i, test.results[i].Score, next.Score, testIndex)
					t.Logf("scoring explanation: %s", next.Expl)
				}
			}
			ctx.DocumentMatchPool.Put(next)
			next, err = test.searcher.Next(ctx)
			i++
		}
		if err != nil {
			t.Fatalf("error iterating searcher: %v for test %d", err, testIndex)
		}
		if len(test.results) != i {
			t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex)
		}
	}
}
<commit_msg>Check locations in the phrase searcher as well<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//
// 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 searcher

import (
	"reflect"
	"testing"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/search"
)

func TestPhraseSearch(t *testing.T) {

	twoDocIndexReader, err := twoDocIndex.Reader()
	if err != nil {
		t.Error(err)
	}
	defer func() {
		err := twoDocIndexReader.Close()
		if err != nil {
			t.Fatal(err)
		}
	}()

	angstTermSearcher, err := NewTermSearcher(twoDocIndexReader, "angst", "desc", 1.0, true)
	if err != nil {
		t.Fatal(err)
	}
	beerTermSearcher, err := NewTermSearcher(twoDocIndexReader, "beer", "desc", 1.0, true)
	if err != nil {
		t.Fatal(err)
	}
	mustSearcher, err := NewConjunctionSearcher(twoDocIndexReader, []search.Searcher{angstTermSearcher, beerTermSearcher}, true)
	if err != nil {
		t.Fatal(err)
	}
	phraseSearcher, err := NewPhraseSearcher(twoDocIndexReader, mustSearcher, []string{"angst", "beer"})
	if err != nil {
		t.Fatal(err)
	}

	tests := []struct {
		searcher   search.Searcher
		results    []*search.DocumentMatch
		locations  map[string]map[string][]search.Location
		fieldterms [][2]string
	}{
		{
			searcher: phraseSearcher,
			results: []*search.DocumentMatch{
				{
					IndexInternalID: index.IndexInternalID("2"),
					Score:           1.0807601687084403,
				},
			},
			locations:  map[string]map[string][]search.Location{"desc": map[string][]search.Location{"beer": []search.Location{search.Location{Pos: 2, Start: 6, End: 10, ArrayPositions: []float64(nil)}}, "angst": []search.Location{search.Location{Pos: 1, Start: 0, End: 5, ArrayPositions: []float64(nil)}}}},
			fieldterms: [][2]string{[2]string{"desc", "beer"}, [2]string{"desc", "angst"}},
		},
	}

	for testIndex, test := range tests {
		defer func() {
			err := test.searcher.Close()
			if err != nil {
				t.Fatal(err)
			}
		}()

		ctx := &search.SearchContext{
			DocumentMatchPool: search.NewDocumentMatchPool(test.searcher.DocumentMatchPoolSize(), 0),
		}
		next, err := test.searcher.Next(ctx)
		i := 0
		for err == nil && next != nil {
			if i < len(test.results) {
				if !next.IndexInternalID.Equals(test.results[i].IndexInternalID) {
					t.Errorf("expected result %d to have id %s got %s for test %d\n", i, test.results[i].IndexInternalID, next.IndexInternalID, testIndex)
				}
				if next.Score != test.results[i].Score {
					t.Errorf("expected result %d to have score %v got %v for test %d\n", i, test.results[i].Score, next.Score, testIndex)
					t.Logf("scoring explanation: %s\n", next.Expl)
				}
				for _, ft := range test.fieldterms {
					locs := next.Locations[ft[0]][ft[1]]
					explocs := test.locations[ft[0]][ft[1]]
					if len(explocs) != len(locs) {
						t.Fatalf("expected result %d to have %d Locations (%#v) but got %d (%#v) for test %d with field %q and term %q\n", i, len(explocs), explocs, len(locs), locs, testIndex, ft[0], ft[1])
					}
					for ind, exploc := range explocs {
						if !reflect.DeepEqual(*locs[ind], exploc) {
							t.Errorf("expected result %d to have Location %v got %v for test %d\n", i, exploc, locs[ind], testIndex)
						}
					}
				}
			}

			ctx.DocumentMatchPool.Put(next)
			next, err = test.searcher.Next(ctx)
			i++
		}
		if err != nil {
			t.Fatalf("error iterating searcher: %v for test %d", err, testIndex)
		}
		if len(test.results) != i {
			t.Errorf("expected %d results got %d for test %d", len(test.results), i, testIndex)
		}
	}
}
<|endoftext|>


<commit_before>package main

// `biosinfo` represent the computer informations
type biosinfo struct {
	motherboard  string
	productName  string
	serialNumber string //TODO will probably not be available without root
	BIOS         string
	BIOSVersion  string
}

// Get informations about the BIOS (or UEFI)
func getBIOSinfo() biosinfo {
	result := biosinfo{
		motherboard:  "",
		productName:  "",
		serialNumber: "",
		BIOS:         "",
		BIOSVersion:  "",
	}
	return result
}

//TODO read directly from   /sys/devices/virtual/dmi/id/* /sys/class/dmi/id/* on linux to avoid demidecode sudo problem
//or try lshal see http://stackoverflow.com/questions/20206474/extract-the-linux-serial-number-without-sudo
//or dmesg ?
//TODO use `sysctl` and/or kenv interfaces`on BSD
//TODO use `system_profiler` on osx
//TODO use `wmic bios get smbiosbiosversion` on windows
<commit_msg>Update biosinfo stats<commit_after>package main

import (
	"io/ioutil"
	"strings"
)

// `biosinfo` represent the computer motherboard and bios informations
type biosinfo struct {
	boardName   string // name of the motherboard ex. 'C-64'
	boardVendor string // name of the motherboard  vendor ex. 'Commodore'
	biosVendor  string // name of the BIOS editor ex. 'Coreboot'
	biosVersion string // version of the BIOS
	biosDate    string // release date of the BIOS
}

// Get informations about the BIOS (or UEFI)
// we prefer to read directly from `/sys/devices/virtual/dmi/id/` than `demidecode` to avoid `sudo`
func getBIOSinfo() biosinfo {
	boardname, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/board_name")
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}
	boardvendor, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/board_vendor")
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}
	biosvendor, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/bios_vendor")
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}
	biosversion, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/bios_version")
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}
	biosdate, err := ioutil.ReadFile("/sys/devices/virtual/dmi/id/bios_date")
	if err != nil {
		panic(err) //TODO do not panic but manage the error
	}

	result := biosinfo{
		boardName:   strings.TrimRight(string(boardname), "\n"), // Trimright remove the EOF carriage return
		boardVendor: strings.TrimRight(string(boardvendor), "\n"),
		biosVendor:  strings.TrimRight(string(biosvendor), "\n"),
		biosVersion: strings.TrimRight(string(biosversion), "\n"),
		biosDate:    strings.TrimRight(string(biosdate), "\n"),
	}
	return result
}

//TODO use `sysctl` and/or kenv interfaces`on BSD
//TODO use `system_profiler` on osx
//TODO use `wmic bios get smbiosbiosversion` on windows
// We do not ask for the board serial number because it need `sudo` on Linux
// and because it's rarely usefull to look at it on a 'quick' way
<|endoftext|>


<commit_before>package record

import (
	"context"
	"fmt"
	"strings"
	"time"

	"sync"

	"github.com/CyCoreSystems/ari"
	"github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

var (

	// RecordingStartTimeout is the amount of time to wait for a recording to start
	// before declaring the recording to have failed.
	RecordingStartTimeout = 1 * time.Second

	// DefaultMaximumDuration is the default maximum amount of time a recording
	// should be allowed to continue before being terminated.
	DefaultMaximumDuration = 24 * time.Hour

	// DefaultMaximumSilence is the default maximum amount of time silence may be
	// detected before terminating the recording.
	DefaultMaximumSilence = 5 * time.Minute

	// ShutdownGracePeriod is the amount of time to allow a Stop transaction to
	// complete before shutting down the session anyway.
	ShutdownGracePeriod = 3 * time.Second
)

// Options describes a set of recording options for a recording Session
type Options struct {
	// name is the name for the live recording
	name string

	format string

	maxDuration time.Duration

	maxSilence time.Duration

	ifExists string

	beep bool

	terminateOn string
}

func defaultOptions() *Options {
	return &Options{
		beep:        false,
		format:      "wav",
		ifExists:    "fail",
		maxDuration: DefaultMaximumDuration,
		maxSilence:  DefaultMaximumSilence,
		name:        uuid.NewV1().String(),
		terminateOn: "none",
	}
}

func (o *Options) toRecordingOptions() *ari.RecordingOptions {
	return &ari.RecordingOptions{
		Beep:        o.beep,
		Format:      o.format,
		Exists:      o.ifExists,
		MaxDuration: o.maxDuration,
		MaxSilence:  o.maxSilence,
		Terminate:   o.terminateOn,
	}
}

// Apply applies a set of options for the recording Session
func (o *Options) Apply(opts ...OptionFunc) {
	for _, f := range opts {
		f(o)
	}
}

// OptionFunc is a function which applies changes to an Options set
type OptionFunc func(*Options)

// Beep indicates that a beep should be played to signal the start of recording
func Beep() OptionFunc {
	return func(o *Options) {
		o.beep = true
	}
}

// Format configures the file format to be used to store the recording
func Format(format string) OptionFunc {
	return func(o *Options) {
		o.format = format
	}
}

// IfExists configures the behaviour of the recording if the file to be
// recorded already exists.
//
// Valid options are:  "fail" (default), "overwrite", and "append".
func IfExists(action string) OptionFunc {
	return func(o *Options) {
		o.ifExists = action
	}
}

// MaxDuration sets the maximum duration to allow for the recording.  After
// this amount of time, the recording will be automatically Finished.
//
// A setting of 0 disables the limit.
func MaxDuration(max time.Duration) OptionFunc {
	return func(o *Options) {
		o.maxDuration = max
	}
}

// MaxSilence sets the amount of time a block of silence is allowed to become
// before the recording should be declared Finished.
//
// A setting of 0 disables silence detection.
func MaxSilence(max time.Duration) OptionFunc {
	return func(o *Options) {
		o.maxSilence = max
	}
}

// Name configures the recording to use the provided name
func Name(name string) OptionFunc {
	return func(o *Options) {
		o.name = name
	}
}

// TerminateOn configures the DTMF which, if received, will terminate the
// recording.
//
// Valid values are "none" (default), "any", "*", and "#".
func TerminateOn(dtmf string) OptionFunc {
	return func(o *Options) {
		o.terminateOn = dtmf
	}
}

// Session desribes the interface to a generic recording session
type Session interface {
	// Done returns a channel which is closed when the session is complete
	Done() <-chan struct{}

	// Err waits for the session to complete, then returns any error encountered
	// during its execution
	Err() error

	// Result waits for the session to complete, then returns the Result
	Result() (*Result, error)

	// Scrap terminates the recording session and throws away the recording.
	Scrap()

	// Stop stops the recording session
	Stop() *Result
}

// Result represents the result of a recording Session.  It provides an
// interface to disposition the recording.
type Result struct {
	h *ari.StoredRecordingHandle

	// Data holds the final data for the LiveRecording, if it was successful
	Data *ari.LiveRecordingData

	// DTMF holds any DTMF digits which are received during the recording session
	DTMF string

	// Duration indicates the duration of the recording
	Duration time.Duration

	// Error holds any error encountered during the recording session
	Error error

	// Hangup indicates that the Recorder disappeared (due to hangup or
	// destruction) during or after the recording.
	Hangup bool

	overwrite bool
}

// Delete discards the recording
func (r *Result) Delete() error {
	if r.h == nil {
		return errors.New("no stored recording handle available")
	}
	return r.h.Delete()
}

// Save stores the recording to the given name
func (r *Result) Save(name string) error {
	if name == "" {
		// no name indicates the default, which is where it already is
		return nil
	}

	if r.h == nil {
		return errors.New("no stored recording handle available")
	}

	// Copy the recording to the desired name
	destH, err := r.h.Copy(name)
	if err != nil {
		if !strings.Contains(err.Error(), "409 Conflict") || !r.overwrite {
			return errors.Wrapf(err, "failed to copy recording (%s)", r.h.ID())
		}

		// we are set to overwrite, so delete the previous recording
		Logger.Debug("overwriting previous recording")
		err = destH.Delete()
		if err != nil {
			return errors.Wrap(err, "failed to remove previous destination recording")
		}
		_, err = r.h.Copy(name)
		if err != nil {
			return errors.Wrap(err, "failed to copy recording")
		}
	}

	// Delete the original
	err = r.h.Delete()
	if err != nil {
		return errors.Wrap(err, "failed to remove temporary recording after copy")
	}

	return nil
}

// URI returns the AudioURI to play the recording
func (r *Result) URI() string {
	return "recording:" + r.h.ID()
}

// Record starts a new recording Session
func Record(ctx context.Context, r ari.Recorder, opts ...OptionFunc) Session {
	s := newRecordingSession(opts...)

	var wg sync.WaitGroup
	wg.Add(1)
	go s.record(ctx, r, &wg)
	wg.Wait()

	Logger.Debug("returned from internal recording start")
	return s
}

// New creates a new recording Session
func newRecordingSession(opts ...OptionFunc) *recordingSession {
	o := defaultOptions()
	o.Apply(opts...)

	s := &recordingSession{
		cancel:  func() {},
		options: o,
		doneCh:  make(chan struct{}),
		res:     new(Result),
	}

	// If the recording options declare that we should overwrite,
	// carry that over to the copy destination.
	if o.ifExists == "overwrite" {
		s.res.overwrite = true
	}

	return s
}

type recordingSession struct {
	h *ari.LiveRecordingHandle

	cancel context.CancelFunc

	doneCh chan struct{}

	mu sync.Mutex

	options *Options

	res *Result
}

func (s *recordingSession) Done() <-chan struct{} {
	return s.doneCh
}

func (s *recordingSession) Err() error {
	<-s.Done()
	return s.res.Error
}

func (s *recordingSession) Result() (*Result, error) {
	<-s.Done()
	return s.res, s.res.Error
}

func (s *recordingSession) Scrap() {
	s.h.Scrap()
}

func (s *recordingSession) Stop() *Result {
	// Signal stop
	s.res.Error = s.h.Stop()

	// If we successfully signaled a stop, Wait for the stop to complete
	if s.res.Error == nil {
		select {
		case <-s.Done():
		case <-time.After(ShutdownGracePeriod):
		}
	}

	// Shut down the session
	if s.cancel != nil {
		s.cancel()
	}

	// Return the result
	return s.res
}

// nolint: gocyclo
func (s *recordingSession) record(ctx context.Context, r ari.Recorder, wg *sync.WaitGroup) {
	defer close(s.doneCh)

	ctx, cancel := context.WithCancel(ctx)
	s.cancel = cancel
	defer cancel()

	var err error
	s.h, err = r.StageRecord(s.options.name, s.options.toRecordingOptions())
	if err != nil {
		s.res.Error = errors.Wrap(err, "failed to stage recording")
		wg.Done()
		return
	}

	// Store the eventual StoredRecording handle to the Result
	s.res.h = s.h.Stored()

	dtmfSub := r.Subscribe(ari.Events.ChannelDtmfReceived)
	hangupSub := r.Subscribe(ari.Events.ChannelDestroyed, ari.Events.ChannelHangupRequest, ari.Events.BridgeDestroyed)
	startSub := s.h.Subscribe(ari.Events.RecordingStarted)
	failedSub := s.h.Subscribe(ari.Events.RecordingFailed)
	finishedSub := s.h.Subscribe(ari.Events.RecordingFinished)

	defer func() {
		hangupSub.Cancel()
		failedSub.Cancel()
		startSub.Cancel()
		finishedSub.Cancel()
		dtmfSub.Cancel()
	}()

	wg.Done()

	// Record the duration of the recording
	started := time.Now()
	defer func() {
		s.res.Duration = time.Since(started)
		Logger.Debug("recording duration", "duration", s.res.Duration)
	}()

	// Record any DTMF received during the recording
	go s.collectDtmf(ctx, dtmfSub)

	// Record hangup or destruction of our Recorder
	go s.watchHangup(ctx, hangupSub)

	// Start recording
	Logger.Debug("starting recording")
	if err := s.h.Exec(); err != nil {
		s.res.Error = err
		return
	}

	// Time the recording
	startTimer := time.NewTimer(RecordingStartTimeout)

	for {
		select {
		case <-ctx.Done():
			s.Stop()
			return
		case <-startTimer.C:
			Logger.Debug("timeout waiting to start recording")
			s.res.Error = timeoutErr{"Timeout waiting for recording to start"}
			return
		case _, ok := <-startSub.Events():
			if !ok {
				return
			}
			Logger.Debug("recording started")
			startTimer.Stop()
		case e, ok := <-failedSub.Events():
			if !ok {
				return
			}
			Logger.Debug("recording failed")
			r := e.(*ari.RecordingFailed).Recording
			s.res.Data = &r
			s.res.Error = fmt.Errorf("Recording failed: %s", r.Cause)
			return
		case e, ok := <-finishedSub.Events():
			if !ok {
				return
			}
			r := e.(*ari.RecordingFinished).Recording
			Logger.Debug("recording finished")
			s.res.Data = &r
			return
		}
	}
}

func (s *recordingSession) collectDtmf(ctx context.Context, dtmfSub ari.Subscription) {
	for {
		select {
		case e, ok := <-dtmfSub.Events():
			if !ok {
				return
			}
			v := e.(*ari.ChannelDtmfReceived)
			s.res.DTMF += v.Digit
		case <-ctx.Done():
			return
		}
	}
}

func (s *recordingSession) watchHangup(ctx context.Context, hangupSub ari.Subscription) {
	select {
	case <-hangupSub.Events():
		s.res.Hangup = true
	case <-ctx.Done():
	}
}

type timeoutErr struct {
	msg string
}

func (err timeoutErr) Error() string {
	return err.msg
}

func (err timeoutErr) Timeout() bool {
	return true
}
<commit_msg>ext/record: add Pause, Resume<commit_after>package record

import (
	"context"
	"fmt"
	"strings"
	"time"

	"sync"

	"github.com/CyCoreSystems/ari"
	"github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)

var (

	// RecordingStartTimeout is the amount of time to wait for a recording to start
	// before declaring the recording to have failed.
	RecordingStartTimeout = 1 * time.Second

	// DefaultMaximumDuration is the default maximum amount of time a recording
	// should be allowed to continue before being terminated.
	DefaultMaximumDuration = 24 * time.Hour

	// DefaultMaximumSilence is the default maximum amount of time silence may be
	// detected before terminating the recording.
	DefaultMaximumSilence = 5 * time.Minute

	// ShutdownGracePeriod is the amount of time to allow a Stop transaction to
	// complete before shutting down the session anyway.
	ShutdownGracePeriod = 3 * time.Second
)

// Options describes a set of recording options for a recording Session
type Options struct {
	// name is the name for the live recording
	name string

	format string

	maxDuration time.Duration

	maxSilence time.Duration

	ifExists string

	beep bool

	terminateOn string
}

func defaultOptions() *Options {
	return &Options{
		beep:        false,
		format:      "wav",
		ifExists:    "fail",
		maxDuration: DefaultMaximumDuration,
		maxSilence:  DefaultMaximumSilence,
		name:        uuid.NewV1().String(),
		terminateOn: "none",
	}
}

func (o *Options) toRecordingOptions() *ari.RecordingOptions {
	return &ari.RecordingOptions{
		Beep:        o.beep,
		Format:      o.format,
		Exists:      o.ifExists,
		MaxDuration: o.maxDuration,
		MaxSilence:  o.maxSilence,
		Terminate:   o.terminateOn,
	}
}

// Apply applies a set of options for the recording Session
func (o *Options) Apply(opts ...OptionFunc) {
	for _, f := range opts {
		f(o)
	}
}

// OptionFunc is a function which applies changes to an Options set
type OptionFunc func(*Options)

// Beep indicates that a beep should be played to signal the start of recording
func Beep() OptionFunc {
	return func(o *Options) {
		o.beep = true
	}
}

// Format configures the file format to be used to store the recording
func Format(format string) OptionFunc {
	return func(o *Options) {
		o.format = format
	}
}

// IfExists configures the behaviour of the recording if the file to be
// recorded already exists.
//
// Valid options are:  "fail" (default), "overwrite", and "append".
func IfExists(action string) OptionFunc {
	return func(o *Options) {
		o.ifExists = action
	}
}

// MaxDuration sets the maximum duration to allow for the recording.  After
// this amount of time, the recording will be automatically Finished.
//
// A setting of 0 disables the limit.
func MaxDuration(max time.Duration) OptionFunc {
	return func(o *Options) {
		o.maxDuration = max
	}
}

// MaxSilence sets the amount of time a block of silence is allowed to become
// before the recording should be declared Finished.
//
// A setting of 0 disables silence detection.
func MaxSilence(max time.Duration) OptionFunc {
	return func(o *Options) {
		o.maxSilence = max
	}
}

// Name configures the recording to use the provided name
func Name(name string) OptionFunc {
	return func(o *Options) {
		o.name = name
	}
}

// TerminateOn configures the DTMF which, if received, will terminate the
// recording.
//
// Valid values are "none" (default), "any", "*", and "#".
func TerminateOn(dtmf string) OptionFunc {
	return func(o *Options) {
		o.terminateOn = dtmf
	}
}

// Session desribes the interface to a generic recording session
type Session interface {
	// Done returns a channel which is closed when the session is complete
	Done() <-chan struct{}

	// Err waits for the session to complete, then returns any error encountered
	// during its execution
	Err() error

	// Pause temporarily stops the recording session without ending the session
	Pause() error

	// Result waits for the session to complete, then returns the Result
	Result() (*Result, error)

	// Resume restarts a paused recording session
	Resume() error

	// Scrap terminates the recording session and throws away the recording.
	Scrap()

	// Stop stops the recording session
	Stop() *Result
}

// Result represents the result of a recording Session.  It provides an
// interface to disposition the recording.
type Result struct {
	h *ari.StoredRecordingHandle

	// Data holds the final data for the LiveRecording, if it was successful
	Data *ari.LiveRecordingData

	// DTMF holds any DTMF digits which are received during the recording session
	DTMF string

	// Duration indicates the duration of the recording
	Duration time.Duration

	// Error holds any error encountered during the recording session
	Error error

	// Hangup indicates that the Recorder disappeared (due to hangup or
	// destruction) during or after the recording.
	Hangup bool

	overwrite bool
}

// Delete discards the recording
func (r *Result) Delete() error {
	if r.h == nil {
		return errors.New("no stored recording handle available")
	}
	return r.h.Delete()
}

// Save stores the recording to the given name
func (r *Result) Save(name string) error {
	if name == "" {
		// no name indicates the default, which is where it already is
		return nil
	}

	if r.h == nil {
		return errors.New("no stored recording handle available")
	}

	// Copy the recording to the desired name
	destH, err := r.h.Copy(name)
	if err != nil {
		if !strings.Contains(err.Error(), "409 Conflict") || !r.overwrite {
			return errors.Wrapf(err, "failed to copy recording (%s)", r.h.ID())
		}

		// we are set to overwrite, so delete the previous recording
		Logger.Debug("overwriting previous recording")
		err = destH.Delete()
		if err != nil {
			return errors.Wrap(err, "failed to remove previous destination recording")
		}
		_, err = r.h.Copy(name)
		if err != nil {
			return errors.Wrap(err, "failed to copy recording")
		}
	}

	// Delete the original
	err = r.h.Delete()
	if err != nil {
		return errors.Wrap(err, "failed to remove temporary recording after copy")
	}

	return nil
}

// URI returns the AudioURI to play the recording
func (r *Result) URI() string {
	return "recording:" + r.h.ID()
}

// Record starts a new recording Session
func Record(ctx context.Context, r ari.Recorder, opts ...OptionFunc) Session {
	s := newRecordingSession(opts...)

	var wg sync.WaitGroup
	wg.Add(1)
	go s.record(ctx, r, &wg)
	wg.Wait()

	Logger.Debug("returned from internal recording start")
	return s
}

// New creates a new recording Session
func newRecordingSession(opts ...OptionFunc) *recordingSession {
	o := defaultOptions()
	o.Apply(opts...)

	s := &recordingSession{
		cancel:  func() {},
		options: o,
		doneCh:  make(chan struct{}),
		res:     new(Result),
	}

	// If the recording options declare that we should overwrite,
	// carry that over to the copy destination.
	if o.ifExists == "overwrite" {
		s.res.overwrite = true
	}

	return s
}

type recordingSession struct {
	h *ari.LiveRecordingHandle

	cancel context.CancelFunc

	doneCh chan struct{}

	mu sync.Mutex

	options *Options

	res *Result
}

func (s *recordingSession) Done() <-chan struct{} {
	return s.doneCh
}

func (s *recordingSession) Err() error {
	<-s.Done()
	return s.res.Error
}

func (s *recordingSession) Result() (*Result, error) {
	<-s.Done()
	return s.res, s.res.Error
}

func (s *recordingSession) Pause() error {
	return s.h.Pause()
}

func (s *recordingSession) Resume() error {
	return s.h.Resume()
}

func (s *recordingSession) Scrap() {
	s.h.Scrap()
}

func (s *recordingSession) Stop() *Result {
	// Signal stop
	s.res.Error = s.h.Stop()

	// If we successfully signaled a stop, Wait for the stop to complete
	if s.res.Error == nil {
		select {
		case <-s.Done():
		case <-time.After(ShutdownGracePeriod):
		}
	}

	// Shut down the session
	if s.cancel != nil {
		s.cancel()
	}

	// Return the result
	return s.res
}

// nolint: gocyclo
func (s *recordingSession) record(ctx context.Context, r ari.Recorder, wg *sync.WaitGroup) {
	defer close(s.doneCh)

	ctx, cancel := context.WithCancel(ctx)
	s.cancel = cancel
	defer cancel()

	var err error
	s.h, err = r.StageRecord(s.options.name, s.options.toRecordingOptions())
	if err != nil {
		s.res.Error = errors.Wrap(err, "failed to stage recording")
		wg.Done()
		return
	}

	// Store the eventual StoredRecording handle to the Result
	s.res.h = s.h.Stored()

	dtmfSub := r.Subscribe(ari.Events.ChannelDtmfReceived)
	hangupSub := r.Subscribe(ari.Events.ChannelDestroyed, ari.Events.ChannelHangupRequest, ari.Events.BridgeDestroyed)
	startSub := s.h.Subscribe(ari.Events.RecordingStarted)
	failedSub := s.h.Subscribe(ari.Events.RecordingFailed)
	finishedSub := s.h.Subscribe(ari.Events.RecordingFinished)

	defer func() {
		hangupSub.Cancel()
		failedSub.Cancel()
		startSub.Cancel()
		finishedSub.Cancel()
		dtmfSub.Cancel()
	}()

	wg.Done()

	// Record the duration of the recording
	started := time.Now()
	defer func() {
		s.res.Duration = time.Since(started)
		Logger.Debug("recording duration", "duration", s.res.Duration)
	}()

	// Record any DTMF received during the recording
	go s.collectDtmf(ctx, dtmfSub)

	// Record hangup or destruction of our Recorder
	go s.watchHangup(ctx, hangupSub)

	// Start recording
	Logger.Debug("starting recording")
	if err := s.h.Exec(); err != nil {
		s.res.Error = err
		return
	}

	// Time the recording
	startTimer := time.NewTimer(RecordingStartTimeout)

	for {
		select {
		case <-ctx.Done():
			s.Stop()
			return
		case <-startTimer.C:
			Logger.Debug("timeout waiting to start recording")
			s.res.Error = timeoutErr{"Timeout waiting for recording to start"}
			return
		case _, ok := <-startSub.Events():
			if !ok {
				return
			}
			Logger.Debug("recording started")
			startTimer.Stop()
		case e, ok := <-failedSub.Events():
			if !ok {
				return
			}
			Logger.Debug("recording failed")
			r := e.(*ari.RecordingFailed).Recording
			s.res.Data = &r
			s.res.Error = fmt.Errorf("Recording failed: %s", r.Cause)
			return
		case e, ok := <-finishedSub.Events():
			if !ok {
				return
			}
			r := e.(*ari.RecordingFinished).Recording
			Logger.Debug("recording finished")
			s.res.Data = &r
			return
		}
	}
}

func (s *recordingSession) collectDtmf(ctx context.Context, dtmfSub ari.Subscription) {
	for {
		select {
		case e, ok := <-dtmfSub.Events():
			if !ok {
				return
			}
			v := e.(*ari.ChannelDtmfReceived)
			s.res.DTMF += v.Digit
		case <-ctx.Done():
			return
		}
	}
}

func (s *recordingSession) watchHangup(ctx context.Context, hangupSub ari.Subscription) {
	select {
	case <-hangupSub.Events():
		s.res.Hangup = true
	case <-ctx.Done():
	}
}

type timeoutErr struct {
	msg string
}

func (err timeoutErr) Error() string {
	return err.msg
}

func (err timeoutErr) Timeout() bool {
	return true
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// File operations for Darwin

package syscall

import (
	"syscall";
	"unsafe";
)

const nameBufsize = 512

func Open(name string, mode int64, perm int64) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_OPEN, int64(uintptr(unsafe.Pointer(&namebuf[0]))), mode, perm);
	return r1, err;
}

func Creat(name string, perm int64) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_OPEN, int64(uintptr(unsafe.Pointer(&namebuf[0]))), O_CREAT|O_WRONLY|O_TRUNC, perm);
	return r1, err;
}

func Close(fd int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_CLOSE, fd, 0, 0);
	return r1, err;
}

func Read(fd int64, buf *byte, nbytes int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_READ, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes);
	return r1, err;
}

func Write(fd int64, buf *byte, nbytes int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_WRITE, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes);
	return r1, err;
}

func Pipe(fds *[2]int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_PIPE, 0, 0, 0);
	if r1 < 0 {
		return r1, err;
	}
	fds[0] = r1;
	fds[1] = r2;
	return 0, 0;
}

func Stat(name string, buf *Stat_t) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_STAT64, int64(uintptr(unsafe.Pointer(&namebuf[0]))), int64(uintptr(unsafe.Pointer(buf))), 0);
	return r1, err;
}

func Lstat(name *byte, buf *Stat_t) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_LSTAT, int64(uintptr(unsafe.Pointer(name))), int64(uintptr(unsafe.Pointer(buf))), 0);
	return r1, err;
}

func Fstat(fd int64, buf *Stat_t) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_FSTAT, fd, int64(uintptr(unsafe.Pointer(buf))), 0);
	return r1, err;
}

func Unlink(name string) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_UNLINK, int64(uintptr(unsafe.Pointer(&namebuf[0]))), 0, 0);
	return r1, err;
}

func Fcntl(fd, cmd, arg int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_FCNTL, fd, cmd, arg);
	return r1, err
}

func Mkdir(name string, perm int64) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_MKDIR, int64(uintptr(unsafe.Pointer(&namebuf[0]))), perm, 0);
	return r1, err;
}

func Dup2(fd1, fd2 int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_DUP2, fd1, fd2, 0);
	return r1, err;
}

<commit_msg>fstat used wrong system call, lstat used wrong type of name<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// File operations for Darwin

package syscall

import (
	"syscall";
	"unsafe";
)

const nameBufsize = 512

func Open(name string, mode int64, perm int64) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_OPEN, int64(uintptr(unsafe.Pointer(&namebuf[0]))), mode, perm);
	return r1, err;
}

func Creat(name string, perm int64) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_OPEN, int64(uintptr(unsafe.Pointer(&namebuf[0]))), O_CREAT|O_WRONLY|O_TRUNC, perm);
	return r1, err;
}

func Close(fd int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_CLOSE, fd, 0, 0);
	return r1, err;
}

func Read(fd int64, buf *byte, nbytes int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_READ, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes);
	return r1, err;
}

func Write(fd int64, buf *byte, nbytes int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_WRITE, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes);
	return r1, err;
}

func Pipe(fds *[2]int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_PIPE, 0, 0, 0);
	if r1 < 0 {
		return r1, err;
	}
	fds[0] = r1;
	fds[1] = r2;
	return 0, 0;
}

func Stat(name string, buf *Stat_t) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_STAT64, int64(uintptr(unsafe.Pointer(&namebuf[0]))), int64(uintptr(unsafe.Pointer(buf))), 0);
	return r1, err;
}

func Lstat(name string, buf *Stat_t) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_LSTAT64, int64(uintptr(unsafe.Pointer(&namebuf[0]))), int64(uintptr(unsafe.Pointer(buf))), 0);
	return r1, err;
}

func Fstat(fd int64, buf *Stat_t) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_FSTAT64, fd, int64(uintptr(unsafe.Pointer(buf))), 0);
	return r1, err;
}

func Unlink(name string) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_UNLINK, int64(uintptr(unsafe.Pointer(&namebuf[0]))), 0, 0);
	return r1, err;
}

func Fcntl(fd, cmd, arg int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_FCNTL, fd, cmd, arg);
	return r1, err
}

func Mkdir(name string, perm int64) (ret int64, errno int64) {
	var namebuf [nameBufsize]byte;
	if !StringToBytes(namebuf, name) {
		return -1, ENAMETOOLONG
	}
	r1, r2, err := Syscall(SYS_MKDIR, int64(uintptr(unsafe.Pointer(&namebuf[0]))), perm, 0);
	return r1, err;
}

func Dup2(fd1, fd2 int64) (ret int64, errno int64) {
	r1, r2, err := Syscall(SYS_DUP2, fd1, fd2, 0);
	return r1, err;
}

<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"fmt"
	"io"
	"testing"
)

type ErrorOnlyFeed struct {
	name string
}

func (t *ErrorOnlyFeed) Name() string {
	return t.name
}

func (t *ErrorOnlyFeed) Start() error {
	return fmt.Errorf("ErrorOnlyFeed Start() invoked")
}

func (t *ErrorOnlyFeed) Close() error {
	return fmt.Errorf("ErrorOnlyFeed Close() invoked")
}

func (t *ErrorOnlyFeed) Dests() map[string]Dest {
	return nil
}

func (t *ErrorOnlyFeed) Stats(w io.Writer) error {
	return fmt.Errorf("ErrorOnlyFeed Stats() invoked")
}

func TestParsePartitionsToVBucketIds(t *testing.T) {
	v, err := ParsePartitionsToVBucketIds(nil)
	if err != nil || v == nil || len(v) != 0 {
		t.Errorf("expected empty")
	}
	v, err = ParsePartitionsToVBucketIds(map[string]Dest{})
	if err != nil || v == nil || len(v) != 0 {
		t.Errorf("expected empty")
	}
	v, err = ParsePartitionsToVBucketIds(map[string]Dest{"123": nil})
	if err != nil || v == nil || len(v) != 1 {
		t.Errorf("expected one entry")
	}
	if v[0] != uint16(123) {
		t.Errorf("expected 123")
	}
	v, err = ParsePartitionsToVBucketIds(map[string]Dest{"!bad": nil})
	if err == nil || v != nil {
		t.Errorf("expected error")
	}
}

func TestDataSourcePartitions(t *testing.T) {
	a, err := DataSourcePartitions("a fake source type",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected fake data source type to error")
	}

	a, err = DataSourcePartitions("couchbase",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected couchbase source type to error on bad server url")
	}

	a, err = DataSourcePartitions("couchbase-dcp",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected couchbase source type to error on bad server url")
	}

	a, err = DataSourcePartitions("couchbase-tap",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected couchbase source type to error on bad server url")
	}

	a, err = DataSourcePartitions("nil",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err != nil || a != nil {
		t.Errorf("expected nil source type to work, but have no partitions")
	}

	a, err = DataSourcePartitions("dest",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected dest source type to error on non-json server params")
	}

	a, err = DataSourcePartitions("dest",
		"sourceName", "sourceUUID", "", "serverURL")
	if err != nil || a == nil {
		t.Errorf("expected dest source type to ok on empty server params")
	}

	a, err = DataSourcePartitions("dest",
		"sourceName", "sourceUUID", "{}", "serverURL")
	if err != nil || a == nil {
		t.Errorf("expected dest source type to ok on empty JSON server params")
	}
}
<commit_msg>TestNilFeedStart()<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"fmt"
	"io"
	"testing"
)

type ErrorOnlyFeed struct {
	name string
}

func (t *ErrorOnlyFeed) Name() string {
	return t.name
}

func (t *ErrorOnlyFeed) Start() error {
	return fmt.Errorf("ErrorOnlyFeed Start() invoked")
}

func (t *ErrorOnlyFeed) Close() error {
	return fmt.Errorf("ErrorOnlyFeed Close() invoked")
}

func (t *ErrorOnlyFeed) Dests() map[string]Dest {
	return nil
}

func (t *ErrorOnlyFeed) Stats(w io.Writer) error {
	return fmt.Errorf("ErrorOnlyFeed Stats() invoked")
}

func TestParsePartitionsToVBucketIds(t *testing.T) {
	v, err := ParsePartitionsToVBucketIds(nil)
	if err != nil || v == nil || len(v) != 0 {
		t.Errorf("expected empty")
	}
	v, err = ParsePartitionsToVBucketIds(map[string]Dest{})
	if err != nil || v == nil || len(v) != 0 {
		t.Errorf("expected empty")
	}
	v, err = ParsePartitionsToVBucketIds(map[string]Dest{"123": nil})
	if err != nil || v == nil || len(v) != 1 {
		t.Errorf("expected one entry")
	}
	if v[0] != uint16(123) {
		t.Errorf("expected 123")
	}
	v, err = ParsePartitionsToVBucketIds(map[string]Dest{"!bad": nil})
	if err == nil || v != nil {
		t.Errorf("expected error")
	}
}

func TestDataSourcePartitions(t *testing.T) {
	a, err := DataSourcePartitions("a fake source type",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected fake data source type to error")
	}

	a, err = DataSourcePartitions("couchbase",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected couchbase source type to error on bad server url")
	}

	a, err = DataSourcePartitions("couchbase-dcp",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected couchbase source type to error on bad server url")
	}

	a, err = DataSourcePartitions("couchbase-tap",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected couchbase source type to error on bad server url")
	}

	a, err = DataSourcePartitions("nil",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err != nil || a != nil {
		t.Errorf("expected nil source type to work, but have no partitions")
	}

	a, err = DataSourcePartitions("dest",
		"sourceName", "sourceUUID", "sourceParams", "serverURL")
	if err == nil || a != nil {
		t.Errorf("expected dest source type to error on non-json server params")
	}

	a, err = DataSourcePartitions("dest",
		"sourceName", "sourceUUID", "", "serverURL")
	if err != nil || a == nil {
		t.Errorf("expected dest source type to ok on empty server params")
	}

	a, err = DataSourcePartitions("dest",
		"sourceName", "sourceUUID", "{}", "serverURL")
	if err != nil || a == nil {
		t.Errorf("expected dest source type to ok on empty JSON server params")
	}
}

func TestNilFeedStart(t *testing.T) {
	if NewNILFeed("", nil).Start() != nil {
		t.Errorf("expected NILFeed.Start() to work")
	}
}
<|endoftext|>


<commit_before>// Package deep provides function deep.Equal which is like reflect.DeepEqual but
// returns a list of differences. This is helpful when comparing complex types
// like structures and maps.
package deep

import (
	"errors"
	"fmt"
	"log"
	"reflect"
	"strings"
)

var (
	// FloatPrecision is the number of decimal places to round float values
	// to when comparing.
	FloatPrecision = 10

	// MaxDiff specifies the maximum number of differences to return.
	MaxDiff = 10

	// MaxDepth specifies the maximum levels of a struct to recurse into.
	MaxDepth = 10

	// LogErrors causes errors to be logged to STDERR when true.
	LogErrors = false

	// CompareUnexportedFields causes unexported struct fields, like s in
	// T{s int}, to be comparsed when true.
	CompareUnexportedFields = false
)

var (
	// ErrMaxRecursion is logged when MaxDepth is reached.
	ErrMaxRecursion = errors.New("recursed to MaxDepth")

	// ErrTypeMismatch is logged when Equal passed two different types of values.
	ErrTypeMismatch = errors.New("variables are different reflect.Type")

	// ErrNotHandled is logged when a primitive Go kind is not handled.
	ErrNotHandled = errors.New("cannot compare the reflect.Kind")
)

type cmp struct {
	diff        []string
	buff        []string
	floatFormat string
}

var errorType = reflect.TypeOf((*error)(nil)).Elem()

// Equal compares variables a and b, recursing into their structure up to
// MaxDepth levels deep, and returns a list of differences, or nil if there are
// none. Some differences may not be found if an error is also returned.
//
// If a type has an Equal method, like time.Equal, it is called to check for
// equality.
func Equal(a, b interface{}) []string {
	aVal := reflect.ValueOf(a)
	bVal := reflect.ValueOf(b)
	c := &cmp{
		diff:        []string{},
		buff:        []string{},
		floatFormat: fmt.Sprintf("%%.%df", FloatPrecision),
	}
	if a == nil && b == nil {
		return nil
	} else if a == nil && b != nil {
		c.saveDiff(b, "<nil pointer>")
	} else if a != nil && b == nil {
		c.saveDiff(a, "<nil pointer>")
	}
	if len(c.diff) > 0 {
		return c.diff
	}

	c.equals(aVal, bVal, 0)
	if len(c.diff) > 0 {
		return c.diff // diffs
	}
	return nil // no diffs
}

func (c *cmp) equals(a, b reflect.Value, level int) {
	if level > MaxDepth {
		logError(ErrMaxRecursion)
		return
	}

	// Check if one value is nil, e.g. T{x: *X} and T.x is nil
	if !a.IsValid() || !b.IsValid() {
		if a.IsValid() && !b.IsValid() {
			c.saveDiff(a.Type(), "<nil pointer>")
		} else if !a.IsValid() && b.IsValid() {
			c.saveDiff("<nil pointer>", b.Type())
		}
		return
	}

	// If differenet types, they can't be equal
	aType := a.Type()
	bType := b.Type()
	if aType != bType {
		c.saveDiff(aType, bType)
		logError(ErrTypeMismatch)
		return
	}

	// Primitive https://golang.org/pkg/reflect/#Kind
	aKind := a.Kind()
	bKind := b.Kind()

	// If both types implement the error interface, compare the error strings.
	// This must be done before dereferencing because the interface is on a
	// pointer receiver.
	if aType.Implements(errorType) && bType.Implements(errorType) {
		if a.Elem().IsValid() && b.Elem().IsValid() { // both err != nil
			aString := a.MethodByName("Error").Call(nil)[0].String()
			bString := b.MethodByName("Error").Call(nil)[0].String()
			if aString != bString {
				c.saveDiff(aString, bString)
			}
			return
		}
	}

	// Dereference pointers and interface{}
	if aElem, bElem := (aKind == reflect.Ptr || aKind == reflect.Interface),
		(bKind == reflect.Ptr || bKind == reflect.Interface); aElem || bElem {

		if aElem {
			a = a.Elem()
		}

		if bElem {
			b = b.Elem()
		}

		c.equals(a, b, level+1)
		return
	}

	// Types with an Equal(), like time.Time.
	eqFunc := a.MethodByName("Equal")
	if eqFunc.IsValid() {
		retVals := eqFunc.Call([]reflect.Value{b})
		if !retVals[0].Bool() {
			c.saveDiff(a, b)
		}
		return
	}

	switch aKind {

	/////////////////////////////////////////////////////////////////////
	// Iterable kinds
	/////////////////////////////////////////////////////////////////////

	case reflect.Struct:
		/*
			The variables are structs like:
				type T struct {
					FirstName string
					LastName  string
				}
			Type = <pkg>.T, Kind = reflect.Struct

			Iterate through the fields (FirstName, LastName), recurse into their values.
		*/
		for i := 0; i < a.NumField(); i++ {
			if aType.Field(i).PkgPath != "" && !CompareUnexportedFields {
				continue // skip unexported field, e.g. s in type T struct {s string}
			}

			c.push(aType.Field(i).Name) // push field name to buff

			// Get the Value for each field, e.g. FirstName has Type = string,
			// Kind = reflect.String.
			af := a.Field(i)
			bf := b.Field(i)

			// Recurse to compare the field values
			c.equals(af, bf, level+1)

			c.pop() // pop field name from buff

			if len(c.diff) >= MaxDiff {
				break
			}
		}
	case reflect.Map:
		/*
			The variables are maps like:
				map[string]int{
					"foo": 1,
					"bar": 2,
				}
			Type = map[string]int, Kind = reflect.Map

			Or:
				type T map[string]int{}
			Type = <pkg>.T, Kind = reflect.Map

			Iterate through the map keys (foo, bar), recurse into their values.
		*/

		if a.IsNil() || b.IsNil() {
			if a.IsNil() && !b.IsNil() {
				c.saveDiff("<nil map>", b)
			} else if !a.IsNil() && b.IsNil() {
				c.saveDiff(a, "<nil map>")
			}
			return
		}

		if a.Pointer() == b.Pointer() {
			return
		}

		for _, key := range a.MapKeys() {
			c.push(fmt.Sprintf("map[%s]", key))

			aVal := a.MapIndex(key)
			bVal := b.MapIndex(key)
			if bVal.IsValid() {
				c.equals(aVal, bVal, level+1)
			} else {
				c.saveDiff(aVal, "<does not have key>")
			}

			c.pop()

			if len(c.diff) >= MaxDiff {
				return
			}
		}

		for _, key := range b.MapKeys() {
			if aVal := a.MapIndex(key); aVal.IsValid() {
				continue
			}

			c.push(fmt.Sprintf("map[%s]", key))
			c.saveDiff("<does not have key>", b.MapIndex(key))
			c.pop()
			if len(c.diff) >= MaxDiff {
				return
			}
		}
	case reflect.Slice:
		if a.IsNil() || b.IsNil() {
			if a.IsNil() && !b.IsNil() {
				c.saveDiff("<nil slice>", b)
			} else if !a.IsNil() && b.IsNil() {
				c.saveDiff(a, "<nil slice>")
			}
			return
		}

		if a.Pointer() == b.Pointer() {
			return
		}

		aLen := a.Len()
		bLen := b.Len()
		n := aLen
		if bLen > aLen {
			n = bLen
		}
		for i := 0; i < n; i++ {
			c.push(fmt.Sprintf("slice[%d]", i))
			if i < aLen && i < bLen {
				c.equals(a.Index(i), b.Index(i), level+1)
			} else if i < aLen {
				c.saveDiff(a.Index(i), "<no value>")
			} else {
				c.saveDiff("<no value>", b.Index(i))
			}
			c.pop()
			if len(c.diff) >= MaxDiff {
				break
			}
		}

	/////////////////////////////////////////////////////////////////////
	// Primitive kinds
	/////////////////////////////////////////////////////////////////////

	case reflect.Float32, reflect.Float64:
		// Avoid 0.04147685731961082 != 0.041476857319611
		// 6 decimal places is close enough
		aval := fmt.Sprintf(c.floatFormat, a.Float())
		bval := fmt.Sprintf(c.floatFormat, b.Float())
		if aval != bval {
			c.saveDiff(a.Float(), b.Float())
		}
	case reflect.Bool:
		if a.Bool() != b.Bool() {
			c.saveDiff(a.Bool(), b.Bool())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if a.Int() != b.Int() {
			c.saveDiff(a.Int(), b.Int())
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if a.Uint() != b.Uint() {
			c.saveDiff(a.Uint(), b.Uint())
		}
	case reflect.String:
		if a.String() != b.String() {
			c.saveDiff(a.String(), b.String())
		}

	default:
		logError(ErrNotHandled)
	}
}

func (c *cmp) push(name string) {
	c.buff = append(c.buff, name)
}

func (c *cmp) pop() {
	if len(c.buff) > 0 {
		c.buff = c.buff[0 : len(c.buff)-1]
	}
}

func (c *cmp) saveDiff(aval, bval interface{}) {
	if len(c.buff) > 0 {
		varName := strings.Join(c.buff, ".")
		c.diff = append(c.diff, fmt.Sprintf("%s: %v != %v", varName, aval, bval))
	} else {
		c.diff = append(c.diff, fmt.Sprintf("%v != %v", aval, bval))
	}
}

func logError(err error) {
	if LogErrors {
		log.Println(err)
	}
}
<commit_msg>Add comparison for arrays<commit_after>// Package deep provides function deep.Equal which is like reflect.DeepEqual but
// returns a list of differences. This is helpful when comparing complex types
// like structures and maps.
package deep

import (
	"errors"
	"fmt"
	"log"
	"reflect"
	"strings"
)

var (
	// FloatPrecision is the number of decimal places to round float values
	// to when comparing.
	FloatPrecision = 10

	// MaxDiff specifies the maximum number of differences to return.
	MaxDiff = 10

	// MaxDepth specifies the maximum levels of a struct to recurse into.
	MaxDepth = 10

	// LogErrors causes errors to be logged to STDERR when true.
	LogErrors = false

	// CompareUnexportedFields causes unexported struct fields, like s in
	// T{s int}, to be comparsed when true.
	CompareUnexportedFields = false
)

var (
	// ErrMaxRecursion is logged when MaxDepth is reached.
	ErrMaxRecursion = errors.New("recursed to MaxDepth")

	// ErrTypeMismatch is logged when Equal passed two different types of values.
	ErrTypeMismatch = errors.New("variables are different reflect.Type")

	// ErrNotHandled is logged when a primitive Go kind is not handled.
	ErrNotHandled = errors.New("cannot compare the reflect.Kind")
)

type cmp struct {
	diff        []string
	buff        []string
	floatFormat string
}

var errorType = reflect.TypeOf((*error)(nil)).Elem()

// Equal compares variables a and b, recursing into their structure up to
// MaxDepth levels deep, and returns a list of differences, or nil if there are
// none. Some differences may not be found if an error is also returned.
//
// If a type has an Equal method, like time.Equal, it is called to check for
// equality.
func Equal(a, b interface{}) []string {
	aVal := reflect.ValueOf(a)
	bVal := reflect.ValueOf(b)
	c := &cmp{
		diff:        []string{},
		buff:        []string{},
		floatFormat: fmt.Sprintf("%%.%df", FloatPrecision),
	}
	if a == nil && b == nil {
		return nil
	} else if a == nil && b != nil {
		c.saveDiff(b, "<nil pointer>")
	} else if a != nil && b == nil {
		c.saveDiff(a, "<nil pointer>")
	}
	if len(c.diff) > 0 {
		return c.diff
	}

	c.equals(aVal, bVal, 0)
	if len(c.diff) > 0 {
		return c.diff // diffs
	}
	return nil // no diffs
}

func (c *cmp) equals(a, b reflect.Value, level int) {
	if level > MaxDepth {
		logError(ErrMaxRecursion)
		return
	}

	// Check if one value is nil, e.g. T{x: *X} and T.x is nil
	if !a.IsValid() || !b.IsValid() {
		if a.IsValid() && !b.IsValid() {
			c.saveDiff(a.Type(), "<nil pointer>")
		} else if !a.IsValid() && b.IsValid() {
			c.saveDiff("<nil pointer>", b.Type())
		}
		return
	}

	// If differenet types, they can't be equal
	aType := a.Type()
	bType := b.Type()
	if aType != bType {
		c.saveDiff(aType, bType)
		logError(ErrTypeMismatch)
		return
	}

	// Primitive https://golang.org/pkg/reflect/#Kind
	aKind := a.Kind()
	bKind := b.Kind()

	// If both types implement the error interface, compare the error strings.
	// This must be done before dereferencing because the interface is on a
	// pointer receiver.
	if aType.Implements(errorType) && bType.Implements(errorType) {
		if a.Elem().IsValid() && b.Elem().IsValid() { // both err != nil
			aString := a.MethodByName("Error").Call(nil)[0].String()
			bString := b.MethodByName("Error").Call(nil)[0].String()
			if aString != bString {
				c.saveDiff(aString, bString)
			}
			return
		}
	}

	// Dereference pointers and interface{}
	if aElem, bElem := (aKind == reflect.Ptr || aKind == reflect.Interface),
		(bKind == reflect.Ptr || bKind == reflect.Interface); aElem || bElem {

		if aElem {
			a = a.Elem()
		}

		if bElem {
			b = b.Elem()
		}

		c.equals(a, b, level+1)
		return
	}

	// Types with an Equal(), like time.Time.
	eqFunc := a.MethodByName("Equal")
	if eqFunc.IsValid() {
		retVals := eqFunc.Call([]reflect.Value{b})
		if !retVals[0].Bool() {
			c.saveDiff(a, b)
		}
		return
	}

	switch aKind {

	/////////////////////////////////////////////////////////////////////
	// Iterable kinds
	/////////////////////////////////////////////////////////////////////

	case reflect.Struct:
		/*
			The variables are structs like:
				type T struct {
					FirstName string
					LastName  string
				}
			Type = <pkg>.T, Kind = reflect.Struct

			Iterate through the fields (FirstName, LastName), recurse into their values.
		*/
		for i := 0; i < a.NumField(); i++ {
			if aType.Field(i).PkgPath != "" && !CompareUnexportedFields {
				continue // skip unexported field, e.g. s in type T struct {s string}
			}

			c.push(aType.Field(i).Name) // push field name to buff

			// Get the Value for each field, e.g. FirstName has Type = string,
			// Kind = reflect.String.
			af := a.Field(i)
			bf := b.Field(i)

			// Recurse to compare the field values
			c.equals(af, bf, level+1)

			c.pop() // pop field name from buff

			if len(c.diff) >= MaxDiff {
				break
			}
		}
	case reflect.Map:
		/*
			The variables are maps like:
				map[string]int{
					"foo": 1,
					"bar": 2,
				}
			Type = map[string]int, Kind = reflect.Map

			Or:
				type T map[string]int{}
			Type = <pkg>.T, Kind = reflect.Map

			Iterate through the map keys (foo, bar), recurse into their values.
		*/

		if a.IsNil() || b.IsNil() {
			if a.IsNil() && !b.IsNil() {
				c.saveDiff("<nil map>", b)
			} else if !a.IsNil() && b.IsNil() {
				c.saveDiff(a, "<nil map>")
			}
			return
		}

		if a.Pointer() == b.Pointer() {
			return
		}

		for _, key := range a.MapKeys() {
			c.push(fmt.Sprintf("map[%s]", key))

			aVal := a.MapIndex(key)
			bVal := b.MapIndex(key)
			if bVal.IsValid() {
				c.equals(aVal, bVal, level+1)
			} else {
				c.saveDiff(aVal, "<does not have key>")
			}

			c.pop()

			if len(c.diff) >= MaxDiff {
				return
			}
		}

		for _, key := range b.MapKeys() {
			if aVal := a.MapIndex(key); aVal.IsValid() {
				continue
			}

			c.push(fmt.Sprintf("map[%s]", key))
			c.saveDiff("<does not have key>", b.MapIndex(key))
			c.pop()
			if len(c.diff) >= MaxDiff {
				return
			}
		}
	case reflect.Array:
		aLen := a.Len()
		bLen := b.Len()
		n := aLen
		if bLen > aLen {
			n = bLen
		}
		for i := 0; i < n; i++ {
			c.push(fmt.Sprintf("array[%d]", i))
			if i < aLen && i < bLen {
				c.equals(a.Index(i), b.Index(i), level+1)
			} else if i < aLen {
				c.saveDiff(a.Index(i), "<no value>")
			} else {
				c.saveDiff("<no value>", b.Index(i))
			}
			c.pop()
			if len(c.diff) >= MaxDiff {
				break
			}
		}
	case reflect.Slice:
		if a.IsNil() || b.IsNil() {
			if a.IsNil() && !b.IsNil() {
				c.saveDiff("<nil slice>", b)
			} else if !a.IsNil() && b.IsNil() {
				c.saveDiff(a, "<nil slice>")
			}
			return
		}

		if a.Pointer() == b.Pointer() {
			return
		}

		aLen := a.Len()
		bLen := b.Len()
		n := aLen
		if bLen > aLen {
			n = bLen
		}
		for i := 0; i < n; i++ {
			c.push(fmt.Sprintf("slice[%d]", i))
			if i < aLen && i < bLen {
				c.equals(a.Index(i), b.Index(i), level+1)
			} else if i < aLen {
				c.saveDiff(a.Index(i), "<no value>")
			} else {
				c.saveDiff("<no value>", b.Index(i))
			}
			c.pop()
			if len(c.diff) >= MaxDiff {
				break
			}
		}

	/////////////////////////////////////////////////////////////////////
	// Primitive kinds
	/////////////////////////////////////////////////////////////////////

	case reflect.Float32, reflect.Float64:
		// Avoid 0.04147685731961082 != 0.041476857319611
		// 6 decimal places is close enough
		aval := fmt.Sprintf(c.floatFormat, a.Float())
		bval := fmt.Sprintf(c.floatFormat, b.Float())
		if aval != bval {
			c.saveDiff(a.Float(), b.Float())
		}
	case reflect.Bool:
		if a.Bool() != b.Bool() {
			c.saveDiff(a.Bool(), b.Bool())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if a.Int() != b.Int() {
			c.saveDiff(a.Int(), b.Int())
		}
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if a.Uint() != b.Uint() {
			c.saveDiff(a.Uint(), b.Uint())
		}
	case reflect.String:
		if a.String() != b.String() {
			c.saveDiff(a.String(), b.String())
		}

	default:
		logError(ErrNotHandled)
	}
}

func (c *cmp) push(name string) {
	c.buff = append(c.buff, name)
}

func (c *cmp) pop() {
	if len(c.buff) > 0 {
		c.buff = c.buff[0 : len(c.buff)-1]
	}
}

func (c *cmp) saveDiff(aval, bval interface{}) {
	if len(c.buff) > 0 {
		varName := strings.Join(c.buff, ".")
		c.diff = append(c.diff, fmt.Sprintf("%s: %v != %v", varName, aval, bval))
	} else {
		c.diff = append(c.diff, fmt.Sprintf("%v != %v", aval, bval))
	}
}

func logError(err error) {
	if LogErrors {
		log.Println(err)
	}
}
<|endoftext|>