<commit_before>package localexec

import (
	"context"
	"fmt"
	"io"
	"os/exec"
	"runtime"

	"github.com/armon/circbuf"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/go-linereader"
)

const (
	// maxBufSize limits how much output we collect from a local
	// invocation. This is to prevent TF memory usage from growing
	// to an enormous amount due to a faulty process.
	maxBufSize = 8 * 1024
)

func Provisioner() terraform.ResourceProvisioner {
	return &schema.Provisioner{
		Schema: map[string]*schema.Schema{
			"command": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
		},

		ApplyFunc: applyFn,
	}
}

func applyFn(ctx context.Context) error {
	data := ctx.Value(schema.ProvConfigDataKey).(*schema.ResourceData)
	o := ctx.Value(schema.ProvOutputKey).(terraform.UIOutput)

	command := data.Get("command").(string)
	if command == "" {
		return fmt.Errorf("local-exec provisioner command must be a non-empty string")
	}

	// Execute the command using a shell
	var shell, flag string
	if runtime.GOOS == "windows" {
		shell = "cmd"
		flag = "/C"
	} else {
		shell = "/bin/sh"
		flag = "-c"
	}

	// Setup the reader that will read the lines from the command
	pr, pw := io.Pipe()
	copyDoneCh := make(chan struct{})
	go copyOutput(o, pr, copyDoneCh)

	// Setup the command
	cmd := exec.Command(shell, flag, command)
	output, _ := circbuf.NewBuffer(maxBufSize)
	cmd.Stderr = io.MultiWriter(output, pw)
	cmd.Stdout = io.MultiWriter(output, pw)

	// Output what we're about to run
	o.Output(fmt.Sprintf(
		"Executing: %s %s \"%s\"",
		shell, flag, command))

	// Start the command
	err := cmd.Start()
	if err == nil {
		// Wait for the command to complete in a goroutine
		doneCh := make(chan struct{})
		go func() {
			defer close(doneCh)
			err = cmd.Wait()
		}()

		// Wait for the command to finish or for us to be interrupted
		select {
		case <-doneCh:
		case <-ctx.Done():
			cmd.Process.Kill()
			err = cmd.Wait()
		}
	}

	// Close the write-end of the pipe so that the goroutine mirroring output
	// ends properly.
	pw.Close()
	<-copyDoneCh

	if err != nil {
		return fmt.Errorf("Error running command '%s': %v. Output: %s",
			command, err, output.Bytes())
	}

	return nil
}

func copyOutput(o terraform.UIOutput, r io.Reader, doneCh chan<- struct{}) {
	defer close(doneCh)
	lr := linereader.New(r)
	for line := range lr.Ch {
		o.Output(line)
	}
}
<commit_msg>provisioners/local-exec: remove data race by setting err only once<commit_after>package localexec

import (
	"context"
	"fmt"
	"io"
	"os/exec"
	"runtime"

	"github.com/armon/circbuf"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/go-linereader"
)

const (
	// maxBufSize limits how much output we collect from a local
	// invocation. This is to prevent TF memory usage from growing
	// to an enormous amount due to a faulty process.
	maxBufSize = 8 * 1024
)

func Provisioner() terraform.ResourceProvisioner {
	return &schema.Provisioner{
		Schema: map[string]*schema.Schema{
			"command": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
		},

		ApplyFunc: applyFn,
	}
}

func applyFn(ctx context.Context) error {
	data := ctx.Value(schema.ProvConfigDataKey).(*schema.ResourceData)
	o := ctx.Value(schema.ProvOutputKey).(terraform.UIOutput)

	command := data.Get("command").(string)
	if command == "" {
		return fmt.Errorf("local-exec provisioner command must be a non-empty string")
	}

	// Execute the command using a shell
	var shell, flag string
	if runtime.GOOS == "windows" {
		shell = "cmd"
		flag = "/C"
	} else {
		shell = "/bin/sh"
		flag = "-c"
	}

	// Setup the reader that will read the lines from the command
	pr, pw := io.Pipe()
	copyDoneCh := make(chan struct{})
	go copyOutput(o, pr, copyDoneCh)

	// Setup the command
	cmd := exec.Command(shell, flag, command)
	output, _ := circbuf.NewBuffer(maxBufSize)
	cmd.Stderr = io.MultiWriter(output, pw)
	cmd.Stdout = io.MultiWriter(output, pw)

	// Output what we're about to run
	o.Output(fmt.Sprintf(
		"Executing: %s %s \"%s\"",
		shell, flag, command))

	// Start the command
	err := cmd.Start()
	if err == nil {
		// Wait for the command to complete in a goroutine
		doneCh := make(chan error, 1)
		go func() {
			doneCh <- cmd.Wait()
		}()

		// Wait for the command to finish or for us to be interrupted
		select {
		case err = <-doneCh:
		case <-ctx.Done():
			cmd.Process.Kill()
			err = cmd.Wait()
		}
	}

	// Close the write-end of the pipe so that the goroutine mirroring output
	// ends properly.
	pw.Close()
	<-copyDoneCh

	if err != nil {
		return fmt.Errorf("Error running command '%s': %v. Output: %s",
			command, err, output.Bytes())
	}

	return nil
}

func copyOutput(o terraform.UIOutput, r io.Reader, doneCh chan<- struct{}) {
	defer close(doneCh)
	lr := linereader.New(r)
	for line := range lr.Ch {
		o.Output(line)
	}
}
<|endoftext|>


<commit_before>package goapns_test

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/tantalum73/Go-APNS"
)

func TestMessageSetter(t *testing.T) {
	m := goapns.NewMessage()

	m.Badge(42)
	assert.Equal(t, 42, m.Payload.Badge, "Badge not set correctly")

	//Testing default priority
	assert.Equal(t, 10, m.Header.Priority)

	m.NoBadgeChange()
	assert.Equal(t, -1, m.Payload.Badge, "Badge not re-set correctly")

	m.ContentAvailable()
	assert.Equal(t, 1, m.Payload.ContentAvailable, "ContentAvailable not set correctly")
	assert.Equal(t, 5, m.Header.Priority, "ContentAvailable not set correctly")

	m.ContentUnavailable()
	assert.Equal(t, 0, m.Payload.ContentAvailable, "ContentUnavailable not set correctly")
	assert.Equal(t, 10, m.Header.Priority, "ContentUnavailable not set correctly")

	// message := goapns.NewMessage().Title("Title").Body("A Test notification :)").Sound("Default").Badge(42)
	// message.Custom("key", "val")

}
<commit_msg>More tests<commit_after>package goapns_test

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/tantalum73/Go-APNS"
)

func TestMessageSetter(t *testing.T) {
	m := goapns.NewMessage()

	m.Badge(42)
	assert.Equal(t, 42, m.Payload.Badge, "Badge not set correctly")

	//Testing default priority
	assert.Equal(t, 10, m.Header.Priority)

	m.NoBadgeChange()
	assert.Equal(t, -1, m.Payload.Badge, "Badge not re-set correctly")

	m.ContentAvailable()
	assert.Equal(t, 1, m.Payload.ContentAvailable, "ContentAvailable not set correctly")
	assert.Equal(t, 5, m.Header.Priority, "ContentAvailable not set correctly")

	m.ContentUnavailable()
	assert.Equal(t, 0, m.Payload.ContentAvailable, "ContentUnavailable not set correctly")
	assert.Equal(t, 10, m.Header.Priority, "ContentUnavailable not set correctly")

	m.Body("body")
	assert.Equal(t, "body", m.Alert.Body)
	// message := goapns.NewMessage().Title("Title").Body("A Test notification :)").Sound("Default").Badge(42)
	// message.Custom("key", "val")

}
<|endoftext|>


<commit_before>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package flags provides an extensive command line option parser.
// The flags package is similar in functionality to the go builtin flag package
// but provides more options and uses reflection to provide a convenient and
// succinct way of specifying command line options.
//
// Supported features:
//     Options with short names (-v)
//     Options with long names (--verbose)
//     Options with and without arguments (bool v.s. other type)
//     Options with optional arguments and default values
//     Multiple option groups each containing a set of options
//     Generate and print well-formatted help message
//     Passing remaining command line arguments after -- (optional)
//     Ignoring unknown command line options (optional)
//     Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
//     Supports multiple short options -aux
//     Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
//     Supports same option multiple times (can store in slice or last option counts)
//     Supports maps
//     Supports function callbacks
//
// Additional features specific to Windows:
//     Options with short names (/v)
//     Options with long names (/verbose)
//     Windows-style options with arguments use a colon as the delimiter
//     Modify generated help message with Windows-style / options
//
// The flags package uses structs, reflection and struct field tags
// to allow users to specify command line options. This results in very simple
// and consise specification of your application options. For example:
//
//     type Options struct {
//         Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
//     }
//
// This specifies one option with a short name -v and a long name --verbose.
// When either -v or --verbose is found on the command line, a 'true' value
// will be appended to the Verbose field. e.g. when specifying -vvv, the
// resulting value of Verbose will be {[true, true, true]}.
//
// Slice options work exactly the same as primitive type options, except that
// whenever the option is encountered, a value is appended to the slice.
//
// Map options from string to primitive type are also supported. On the command
// line, you specify the value for such an option as key:value. For example
//
//     type Options struct {
//         AuthorInfo string[string] `short:"a"`
//     }
//
// Then, the AuthorInfo map can be filled with something like
// -a name:Jesse -a "surname:van den Kieboom".
//
// Finally, for full control over the conversion between command line argument
// values and options, user defined types can choose to implement the Marshaler
// and Unmarshaler interfaces.
//
// Available field tags:
//     short:       the short name of the option (single character)
//     long:        the long name of the option
//     required:    whether an option is required to appear on the command line.
//                  If a required option is not present, the parser will return
//                  ErrRequired.
//     description: the description of the option (optional)
//
//     optional:       whether an argument of the option is optional (optional)
//     optional-value: the value of an optional option when the option occurs
//                     without an argument. This tag can be specified multiple
//                     times in the case of maps or slices (optional)
//     default:        the default value of an option. This tag can be specified
//                     multiple times in the case of slices or maps (optional).
//     default-mask:   when specified, this value will be displayed in the help
//                     instead of the actual default value. This is useful
//                     mostly for hiding otherwise sensitive information from
//                     showing up in the help. If default-mask takes the special
//                     value "-", then no default value will be shown at all
//                     (optional)
//     value-name:     the name of the argument value (to be shown in the help,
//                     (optional)
//
//     base: a base (radix) used to convert strings to integer values, the default
//           base is 10 (i.e. decimal) (optional)
//
//     group:                when specified on a struct field, makes the struct
//                           field a separate group with the given name (optional).
//     command:              when specified on a struct field, makes the struct
//                           field a (sub)command with the given name (optional).
//     subcommands-optional: when specified on a command struct field, makes
//                           any subcommands of that command optional.
//
// Either short: or long: must be specified to make the field eligible as an
// option.
//
//
// Option groups:
//
// Option groups are a simple way to semantically separate your options. The
// only real difference is in how your options will appear in the builtin
// generated help. All options in a particular group are shown together in the
// help under the name of the group.
//
// There are currently three ways to specify option groups.
//
//     1. Use NewNamedParser specifying the various option groups.
//     2. Use AddGroup to add a group to an existing parser.
//     3. Add a struct field to the toplevel options annotated with the
//        group:"group-name" tag.
//
//
//
// Commands:
//
// The flags package also has basic support for commands. Commands are often
// used in monolithic applications that support various commands or actions.
// Take git for example, all of the add, commit, checkout, etc. are called
// commands. Using commands you can easily separate multiple functions of your
// application.
//
// There are currently two ways to specifiy a command.
//
//     1. Use AddCommand on an existing parser.
//     2. Add a struct field to your options struct annotated with the
//        command:"command-name" tag.
//
// The most common, idiomatic way to implement commands is to define a global
// parser instance and implement each command in a separate file. These
// command files should define a go init function which calls AddCommand on
// the global parser.
//
// When parsing ends and there is an active command and that command implements
// the Commander interface, then its Execute method will be run with the
// remaining command line arguments.
//
// Command structs can have options which become valid to parse after the
// command has been specified on the command line. It is currently not valid
// to specify options from the parent level of the command after the command
// name has occurred. Thus, given a toplevel option "-v" and a command "add":
//
//     Valid:   ./app -v add
//     Invalid: ./app add -v
//
package flags
<commit_msg>the required tag is actually optional<commit_after>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package flags provides an extensive command line option parser.
// The flags package is similar in functionality to the go builtin flag package
// but provides more options and uses reflection to provide a convenient and
// succinct way of specifying command line options.
//
// Supported features:
//     Options with short names (-v)
//     Options with long names (--verbose)
//     Options with and without arguments (bool v.s. other type)
//     Options with optional arguments and default values
//     Multiple option groups each containing a set of options
//     Generate and print well-formatted help message
//     Passing remaining command line arguments after -- (optional)
//     Ignoring unknown command line options (optional)
//     Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
//     Supports multiple short options -aux
//     Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
//     Supports same option multiple times (can store in slice or last option counts)
//     Supports maps
//     Supports function callbacks
//
// Additional features specific to Windows:
//     Options with short names (/v)
//     Options with long names (/verbose)
//     Windows-style options with arguments use a colon as the delimiter
//     Modify generated help message with Windows-style / options
//
// The flags package uses structs, reflection and struct field tags
// to allow users to specify command line options. This results in very simple
// and consise specification of your application options. For example:
//
//     type Options struct {
//         Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
//     }
//
// This specifies one option with a short name -v and a long name --verbose.
// When either -v or --verbose is found on the command line, a 'true' value
// will be appended to the Verbose field. e.g. when specifying -vvv, the
// resulting value of Verbose will be {[true, true, true]}.
//
// Slice options work exactly the same as primitive type options, except that
// whenever the option is encountered, a value is appended to the slice.
//
// Map options from string to primitive type are also supported. On the command
// line, you specify the value for such an option as key:value. For example
//
//     type Options struct {
//         AuthorInfo string[string] `short:"a"`
//     }
//
// Then, the AuthorInfo map can be filled with something like
// -a name:Jesse -a "surname:van den Kieboom".
//
// Finally, for full control over the conversion between command line argument
// values and options, user defined types can choose to implement the Marshaler
// and Unmarshaler interfaces.
//
// Available field tags:
//     short:       the short name of the option (single character)
//     long:        the long name of the option
//     required:    whether an option is required to appear on the command line.
//                  If a required option is not present, the parser will return
//                  ErrRequired. (optional)
//     description: the description of the option (optional)
//
//     optional:       whether an argument of the option is optional (optional)
//     optional-value: the value of an optional option when the option occurs
//                     without an argument. This tag can be specified multiple
//                     times in the case of maps or slices (optional)
//     default:        the default value of an option. This tag can be specified
//                     multiple times in the case of slices or maps (optional).
//     default-mask:   when specified, this value will be displayed in the help
//                     instead of the actual default value. This is useful
//                     mostly for hiding otherwise sensitive information from
//                     showing up in the help. If default-mask takes the special
//                     value "-", then no default value will be shown at all
//                     (optional)
//     value-name:     the name of the argument value (to be shown in the help,
//                     (optional)
//
//     base: a base (radix) used to convert strings to integer values, the default
//           base is 10 (i.e. decimal) (optional)
//
//     group:                when specified on a struct field, makes the struct
//                           field a separate group with the given name (optional).
//     command:              when specified on a struct field, makes the struct
//                           field a (sub)command with the given name (optional).
//     subcommands-optional: when specified on a command struct field, makes
//                           any subcommands of that command optional.
//
// Either short: or long: must be specified to make the field eligible as an
// option.
//
//
// Option groups:
//
// Option groups are a simple way to semantically separate your options. The
// only real difference is in how your options will appear in the builtin
// generated help. All options in a particular group are shown together in the
// help under the name of the group.
//
// There are currently three ways to specify option groups.
//
//     1. Use NewNamedParser specifying the various option groups.
//     2. Use AddGroup to add a group to an existing parser.
//     3. Add a struct field to the toplevel options annotated with the
//        group:"group-name" tag.
//
//
//
// Commands:
//
// The flags package also has basic support for commands. Commands are often
// used in monolithic applications that support various commands or actions.
// Take git for example, all of the add, commit, checkout, etc. are called
// commands. Using commands you can easily separate multiple functions of your
// application.
//
// There are currently two ways to specifiy a command.
//
//     1. Use AddCommand on an existing parser.
//     2. Add a struct field to your options struct annotated with the
//        command:"command-name" tag.
//
// The most common, idiomatic way to implement commands is to define a global
// parser instance and implement each command in a separate file. These
// command files should define a go init function which calls AddCommand on
// the global parser.
//
// When parsing ends and there is an active command and that command implements
// the Commander interface, then its Execute method will be run with the
// remaining command line arguments.
//
// Command structs can have options which become valid to parse after the
// command has been specified on the command line. It is currently not valid
// to specify options from the parent level of the command after the command
// name has occurred. Thus, given a toplevel option "-v" and a command "add":
//
//     Valid:   ./app -v add
//     Invalid: ./app add -v
//
package flags
<|endoftext|>


<commit_before>package docker

import (
	"testing"

	"github.com/stretchr/testify/require"
)

func TestValidateCgroupPermission(t *testing.T) {
	positiveCases := []string{
		"r",
		"rw",
		"rwm",
		"mr",
		"mrw",
		"",
	}

	for _, c := range positiveCases {
		t.Run("positive case: "+c, func(t *testing.T) {
			require.True(t, validateCgroupPermission(c))
		})
	}

	negativeCases := []string{
		"q",
		"asdf",
		"rq",
	}

	for _, c := range negativeCases {
		t.Run("negative case: "+c, func(t *testing.T) {
			require.False(t, validateCgroupPermission(c))
		})
	}

}

func TestExpandPath(t *testing.T) {
	cases := []struct {
		base     string
		target   string
		expected string
	}{
		{"/tmp/alloc/task", "/home/user", "/home/user"},
		{"/tmp/alloc/task", "/home/user/..", "/home"},

		{"/tmp/alloc/task", ".", "/tmp/alloc/task"},
		{"/tmp/alloc/task", "..", "/tmp/alloc"},

		{"/tmp/alloc/task", "d1/d2", "/tmp/alloc/task/d1/d2"},
		{"/tmp/alloc/task", "../d1/d2", "/tmp/alloc/d1/d2"},
		{"/tmp/alloc/task", "../../d1/d2", "/tmp/d1/d2"},
	}

	for _, c := range cases {
		t.Run(c.expected, func(t *testing.T) {
			require.Equal(t, c.expected, expandPath(c.base, c.target))
		})
	}
}

func TestIsParentPath(t *testing.T) {
	require.True(t, isParentPath("/a/b/c", "/a/b/c"))
	require.True(t, isParentPath("/a/b/c", "/a/b/c/d"))
	require.True(t, isParentPath("/a/b/c", "/a/b/c/d/e"))

	require.False(t, isParentPath("/a/b/c", "/a/b/d"))
	require.False(t, isParentPath("/a/b/c", "/a/b/cd"))
	require.False(t, isParentPath("/a/b/c", "/a/d/c"))
	require.False(t, isParentPath("/a/b/c", "/d/e/c"))
}
<commit_msg>docker: ExpandPath tests validate slashpath<commit_after>package docker

import (
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestValidateCgroupPermission(t *testing.T) {
	positiveCases := []string{
		"r",
		"rw",
		"rwm",
		"mr",
		"mrw",
		"",
	}

	for _, c := range positiveCases {
		t.Run("positive case: "+c, func(t *testing.T) {
			require.True(t, validateCgroupPermission(c))
		})
	}

	negativeCases := []string{
		"q",
		"asdf",
		"rq",
	}

	for _, c := range negativeCases {
		t.Run("negative case: "+c, func(t *testing.T) {
			require.False(t, validateCgroupPermission(c))
		})
	}

}

func TestExpandPath(t *testing.T) {
	cases := []struct {
		base     string
		target   string
		expected string
	}{
		{"/tmp/alloc/task", "/home/user", "/home/user"},
		{"/tmp/alloc/task", "/home/user/..", "/home"},

		{"/tmp/alloc/task", ".", "/tmp/alloc/task"},
		{"/tmp/alloc/task", "..", "/tmp/alloc"},

		{"/tmp/alloc/task", "d1/d2", "/tmp/alloc/task/d1/d2"},
		{"/tmp/alloc/task", "../d1/d2", "/tmp/alloc/d1/d2"},
		{"/tmp/alloc/task", "../../d1/d2", "/tmp/d1/d2"},
	}

	for _, c := range cases {
		t.Run(c.expected, func(t *testing.T) {
			require.Equal(t, c.expected, filepath.ToSlash(expandPath(c.base, c.target)))
		})
	}
}

func TestIsParentPath(t *testing.T) {
	require.True(t, isParentPath("/a/b/c", "/a/b/c"))
	require.True(t, isParentPath("/a/b/c", "/a/b/c/d"))
	require.True(t, isParentPath("/a/b/c", "/a/b/c/d/e"))

	require.False(t, isParentPath("/a/b/c", "/a/b/d"))
	require.False(t, isParentPath("/a/b/c", "/a/b/cd"))
	require.False(t, isParentPath("/a/b/c", "/a/d/c"))
	require.False(t, isParentPath("/a/b/c", "/d/e/c"))
}
<|endoftext|>


<commit_before>package aws

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsNetworkInterface() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsNetworkInterfaceCreate,
		Read:   resourceAwsNetworkInterfaceRead,
		Update: resourceAwsNetworkInterfaceUpdate,
		Delete: resourceAwsNetworkInterfaceDelete,

		Schema: map[string]*schema.Schema{

			"subnet_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"private_ips": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"security_groups": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"source_dest_check": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},

			"attachment": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"instance": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"device_index": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"attachment_id": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
					},
				},
				Set: resourceAwsEniAttachmentHash,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) error {

	conn := meta.(*AWSClient).ec2conn

	request := &ec2.CreateNetworkInterfaceInput{
		SubnetId: aws.String(d.Get("subnet_id").(string)),
	}

	security_groups := d.Get("security_groups").(*schema.Set).List()
	if len(security_groups) != 0 {
		request.Groups = expandStringList(security_groups)
	}

	private_ips := d.Get("private_ips").(*schema.Set).List()
	if len(private_ips) != 0 {
		request.PrivateIpAddresses = expandPrivateIPAddresses(private_ips)
	}

	log.Printf("[DEBUG] Creating network interface")
	resp, err := conn.CreateNetworkInterface(request)
	if err != nil {
		return fmt.Errorf("Error creating ENI: %s", err)
	}

	d.SetId(*resp.NetworkInterface.NetworkInterfaceId)
	log.Printf("[INFO] ENI ID: %s", d.Id())
	return resourceAwsNetworkInterfaceUpdate(d, meta)
}

func resourceAwsNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error {

	conn := meta.(*AWSClient).ec2conn
	describe_network_interfaces_request := &ec2.DescribeNetworkInterfacesInput{
		NetworkInterfaceIds: []*string{aws.String(d.Id())},
	}
	describeResp, err := conn.DescribeNetworkInterfaces(describe_network_interfaces_request)

	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidNetworkInterfaceID.NotFound" {
			// The ENI is gone now, so just remove it from the state
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving ENI: %s", err)
	}
	if len(describeResp.NetworkInterfaces) != 1 {
		return fmt.Errorf("Unable to find ENI: %#v", describeResp.NetworkInterfaces)
	}

	eni := describeResp.NetworkInterfaces[0]
	d.Set("subnet_id", eni.SubnetId)
	d.Set("private_ips", flattenNetworkInterfacesPrivateIPAddresses(eni.PrivateIpAddresses))
	d.Set("security_groups", flattenGroupIdentifiers(eni.Groups))
	d.Set("source_dest_check", eni.SourceDestCheck)

	// Tags
	d.Set("tags", tagsToMap(eni.TagSet))

	if eni.Attachment != nil {
		attachment := []map[string]interface{}{flattenAttachment(eni.Attachment)}
		d.Set("attachment", attachment)
	} else {
		d.Set("attachment", nil)
	}

	return nil
}

func networkInterfaceAttachmentRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {

		describe_network_interfaces_request := &ec2.DescribeNetworkInterfacesInput{
			NetworkInterfaceIds: []*string{aws.String(id)},
		}
		describeResp, err := conn.DescribeNetworkInterfaces(describe_network_interfaces_request)

		if err != nil {
			log.Printf("[ERROR] Could not find network interface %s. %s", id, err)
			return nil, "", err
		}

		eni := describeResp.NetworkInterfaces[0]
		hasAttachment := strconv.FormatBool(eni.Attachment != nil)
		log.Printf("[DEBUG] ENI %s has attachment state %s", id, hasAttachment)
		return eni, hasAttachment, nil
	}
}

func resourceAwsNetworkInterfaceDetach(oa *schema.Set, meta interface{}, eniId string) error {
	// if there was an old attachment, remove it
	if oa != nil && len(oa.List()) > 0 {
		old_attachment := oa.List()[0].(map[string]interface{})
		detach_request := &ec2.DetachNetworkInterfaceInput{
			AttachmentId: aws.String(old_attachment["attachment_id"].(string)),
			Force:        aws.Bool(true),
		}
		conn := meta.(*AWSClient).ec2conn
		_, detach_err := conn.DetachNetworkInterface(detach_request)
		if detach_err != nil {
			return fmt.Errorf("Error detaching ENI: %s", detach_err)
		}

		log.Printf("[DEBUG] Waiting for ENI (%s) to become dettached", eniId)
		stateConf := &resource.StateChangeConf{
			Pending: []string{"true"},
			Target:  "false",
			Refresh: networkInterfaceAttachmentRefreshFunc(conn, eniId),
			Timeout: 10 * time.Minute,
		}
		if _, err := stateConf.WaitForState(); err != nil {
			return fmt.Errorf(
				"Error waiting for ENI (%s) to become dettached: %s", eniId, err)
		}
	}

	return nil
}

func convertToAwsStringSlice(s []interface{}) []*string {
	var b []*string
	for _, i := range s {
		b = append(b, aws.String(i.(string)))
	}
	return b
}

func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	d.Partial(true)

	if d.HasChange("attachment") {
		oa, na := d.GetChange("attachment")

		detach_err := resourceAwsNetworkInterfaceDetach(oa.(*schema.Set), meta, d.Id())
		if detach_err != nil {
			return detach_err
		}

		// if there is a new attachment, attach it
		if na != nil && len(na.(*schema.Set).List()) > 0 {
			new_attachment := na.(*schema.Set).List()[0].(map[string]interface{})
			di := new_attachment["device_index"].(int)
			attach_request := &ec2.AttachNetworkInterfaceInput{
				DeviceIndex:        aws.Int64(int64(di)),
				InstanceId:         aws.String(new_attachment["instance"].(string)),
				NetworkInterfaceId: aws.String(d.Id()),
			}
			_, attach_err := conn.AttachNetworkInterface(attach_request)
			if attach_err != nil {
				return fmt.Errorf("Error attaching ENI: %s", attach_err)
			}
		}

		d.SetPartial("attachment")
	}

	if d.HasChange("private_ips") {
		o, n := d.GetChange("private_ips")
		if o == nil {
			o = new(schema.Set)
		}
		if n == nil {
			n = new(schema.Set)
		}

		os := o.(*schema.Set)
		ns := n.(*schema.Set)

		// Unassign old IP addresses
		unassignIps := os.Difference(ns)
		if unassignIps.Len() != 0 {
			input := &ec2.UnassignPrivateIpAddressesInput{
				NetworkInterfaceId: aws.String(d.Id()),
				PrivateIpAddresses: convertToAwsStringSlice(unassignIps.List()),
			}
			_, err := conn.UnassignPrivateIpAddresses(input)
			if err != nil {
				return fmt.Errorf("Failure to unassign Private IPs: %s", err)
			}
		}

		// Assign new IP addresses
		assignIps := ns.Difference(os)
		if assignIps.Len() != 0 {
			input := &ec2.AssignPrivateIpAddressesInput{
				NetworkInterfaceId: aws.String(d.Id()),
				PrivateIpAddresses: convertToAwsStringSlice(assignIps.List()),
			}
			_, err := conn.AssignPrivateIpAddresses(input)
			if err != nil {
				return fmt.Errorf("Failure to assign Private IPs: %s", err)
			}
		}

		d.SetPartial("private_ips")
	}

	request := &ec2.ModifyNetworkInterfaceAttributeInput{
		NetworkInterfaceId: aws.String(d.Id()),
		SourceDestCheck:    &ec2.AttributeBooleanValue{Value: aws.Bool(d.Get("source_dest_check").(bool))},
	}

	_, err := conn.ModifyNetworkInterfaceAttribute(request)
	if err != nil {
		return fmt.Errorf("Failure updating ENI: %s", err)
	}

	d.SetPartial("source_dest_check")

	if d.HasChange("security_groups") {
		request := &ec2.ModifyNetworkInterfaceAttributeInput{
			NetworkInterfaceId: aws.String(d.Id()),
			Groups:             expandStringList(d.Get("security_groups").(*schema.Set).List()),
		}

		_, err := conn.ModifyNetworkInterfaceAttribute(request)
		if err != nil {
			return fmt.Errorf("Failure updating ENI: %s", err)
		}

		d.SetPartial("security_groups")
	}

	if err := setTags(conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	d.Partial(false)

	return resourceAwsNetworkInterfaceRead(d, meta)
}

func resourceAwsNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	log.Printf("[INFO] Deleting ENI: %s", d.Id())

	detach_err := resourceAwsNetworkInterfaceDetach(d.Get("attachment").(*schema.Set), meta, d.Id())
	if detach_err != nil {
		return detach_err
	}

	deleteEniOpts := ec2.DeleteNetworkInterfaceInput{
		NetworkInterfaceId: aws.String(d.Id()),
	}
	if _, err := conn.DeleteNetworkInterface(&deleteEniOpts); err != nil {
		return fmt.Errorf("Error deleting ENI: %s", err)
	}

	return nil
}

func resourceAwsEniAttachmentHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["instance"].(string)))
	buf.WriteString(fmt.Sprintf("%d-", m["device_index"].(int)))
	return hashcode.String(buf.String())
}
<commit_msg>Reuse structure method for network interface ips<commit_after>package aws

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsNetworkInterface() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsNetworkInterfaceCreate,
		Read:   resourceAwsNetworkInterfaceRead,
		Update: resourceAwsNetworkInterfaceUpdate,
		Delete: resourceAwsNetworkInterfaceDelete,

		Schema: map[string]*schema.Schema{

			"subnet_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"private_ips": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"security_groups": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"source_dest_check": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},

			"attachment": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"instance": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"device_index": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"attachment_id": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
					},
				},
				Set: resourceAwsEniAttachmentHash,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceAwsNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) error {

	conn := meta.(*AWSClient).ec2conn

	request := &ec2.CreateNetworkInterfaceInput{
		SubnetId: aws.String(d.Get("subnet_id").(string)),
	}

	security_groups := d.Get("security_groups").(*schema.Set).List()
	if len(security_groups) != 0 {
		request.Groups = expandStringList(security_groups)
	}

	private_ips := d.Get("private_ips").(*schema.Set).List()
	if len(private_ips) != 0 {
		request.PrivateIpAddresses = expandPrivateIPAddresses(private_ips)
	}

	log.Printf("[DEBUG] Creating network interface")
	resp, err := conn.CreateNetworkInterface(request)
	if err != nil {
		return fmt.Errorf("Error creating ENI: %s", err)
	}

	d.SetId(*resp.NetworkInterface.NetworkInterfaceId)
	log.Printf("[INFO] ENI ID: %s", d.Id())
	return resourceAwsNetworkInterfaceUpdate(d, meta)
}

func resourceAwsNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error {

	conn := meta.(*AWSClient).ec2conn
	describe_network_interfaces_request := &ec2.DescribeNetworkInterfacesInput{
		NetworkInterfaceIds: []*string{aws.String(d.Id())},
	}
	describeResp, err := conn.DescribeNetworkInterfaces(describe_network_interfaces_request)

	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidNetworkInterfaceID.NotFound" {
			// The ENI is gone now, so just remove it from the state
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving ENI: %s", err)
	}
	if len(describeResp.NetworkInterfaces) != 1 {
		return fmt.Errorf("Unable to find ENI: %#v", describeResp.NetworkInterfaces)
	}

	eni := describeResp.NetworkInterfaces[0]
	d.Set("subnet_id", eni.SubnetId)
	d.Set("private_ips", flattenNetworkInterfacesPrivateIPAddresses(eni.PrivateIpAddresses))
	d.Set("security_groups", flattenGroupIdentifiers(eni.Groups))
	d.Set("source_dest_check", eni.SourceDestCheck)

	// Tags
	d.Set("tags", tagsToMap(eni.TagSet))

	if eni.Attachment != nil {
		attachment := []map[string]interface{}{flattenAttachment(eni.Attachment)}
		d.Set("attachment", attachment)
	} else {
		d.Set("attachment", nil)
	}

	return nil
}

func networkInterfaceAttachmentRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {

		describe_network_interfaces_request := &ec2.DescribeNetworkInterfacesInput{
			NetworkInterfaceIds: []*string{aws.String(id)},
		}
		describeResp, err := conn.DescribeNetworkInterfaces(describe_network_interfaces_request)

		if err != nil {
			log.Printf("[ERROR] Could not find network interface %s. %s", id, err)
			return nil, "", err
		}

		eni := describeResp.NetworkInterfaces[0]
		hasAttachment := strconv.FormatBool(eni.Attachment != nil)
		log.Printf("[DEBUG] ENI %s has attachment state %s", id, hasAttachment)
		return eni, hasAttachment, nil
	}
}

func resourceAwsNetworkInterfaceDetach(oa *schema.Set, meta interface{}, eniId string) error {
	// if there was an old attachment, remove it
	if oa != nil && len(oa.List()) > 0 {
		old_attachment := oa.List()[0].(map[string]interface{})
		detach_request := &ec2.DetachNetworkInterfaceInput{
			AttachmentId: aws.String(old_attachment["attachment_id"].(string)),
			Force:        aws.Bool(true),
		}
		conn := meta.(*AWSClient).ec2conn
		_, detach_err := conn.DetachNetworkInterface(detach_request)
		if detach_err != nil {
			return fmt.Errorf("Error detaching ENI: %s", detach_err)
		}

		log.Printf("[DEBUG] Waiting for ENI (%s) to become dettached", eniId)
		stateConf := &resource.StateChangeConf{
			Pending: []string{"true"},
			Target:  "false",
			Refresh: networkInterfaceAttachmentRefreshFunc(conn, eniId),
			Timeout: 10 * time.Minute,
		}
		if _, err := stateConf.WaitForState(); err != nil {
			return fmt.Errorf(
				"Error waiting for ENI (%s) to become dettached: %s", eniId, err)
		}
	}

	return nil
}

func resourceAwsNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	d.Partial(true)

	if d.HasChange("attachment") {
		oa, na := d.GetChange("attachment")

		detach_err := resourceAwsNetworkInterfaceDetach(oa.(*schema.Set), meta, d.Id())
		if detach_err != nil {
			return detach_err
		}

		// if there is a new attachment, attach it
		if na != nil && len(na.(*schema.Set).List()) > 0 {
			new_attachment := na.(*schema.Set).List()[0].(map[string]interface{})
			di := new_attachment["device_index"].(int)
			attach_request := &ec2.AttachNetworkInterfaceInput{
				DeviceIndex:        aws.Int64(int64(di)),
				InstanceId:         aws.String(new_attachment["instance"].(string)),
				NetworkInterfaceId: aws.String(d.Id()),
			}
			_, attach_err := conn.AttachNetworkInterface(attach_request)
			if attach_err != nil {
				return fmt.Errorf("Error attaching ENI: %s", attach_err)
			}
		}

		d.SetPartial("attachment")
	}

	if d.HasChange("private_ips") {
		o, n := d.GetChange("private_ips")
		if o == nil {
			o = new(schema.Set)
		}
		if n == nil {
			n = new(schema.Set)
		}

		os := o.(*schema.Set)
		ns := n.(*schema.Set)

		// Unassign old IP addresses
		unassignIps := os.Difference(ns)
		if unassignIps.Len() != 0 {
			input := &ec2.UnassignPrivateIpAddressesInput{
				NetworkInterfaceId: aws.String(d.Id()),
				PrivateIpAddresses: expandStringList(unassignIps.List()),
			}
			_, err := conn.UnassignPrivateIpAddresses(input)
			if err != nil {
				return fmt.Errorf("Failure to unassign Private IPs: %s", err)
			}
		}

		// Assign new IP addresses
		assignIps := ns.Difference(os)
		if assignIps.Len() != 0 {
			input := &ec2.AssignPrivateIpAddressesInput{
				NetworkInterfaceId: aws.String(d.Id()),
				PrivateIpAddresses: expandStringList(assignIps.List()),
			}
			_, err := conn.AssignPrivateIpAddresses(input)
			if err != nil {
				return fmt.Errorf("Failure to assign Private IPs: %s", err)
			}
		}

		d.SetPartial("private_ips")
	}

	request := &ec2.ModifyNetworkInterfaceAttributeInput{
		NetworkInterfaceId: aws.String(d.Id()),
		SourceDestCheck:    &ec2.AttributeBooleanValue{Value: aws.Bool(d.Get("source_dest_check").(bool))},
	}

	_, err := conn.ModifyNetworkInterfaceAttribute(request)
	if err != nil {
		return fmt.Errorf("Failure updating ENI: %s", err)
	}

	d.SetPartial("source_dest_check")

	if d.HasChange("security_groups") {
		request := &ec2.ModifyNetworkInterfaceAttributeInput{
			NetworkInterfaceId: aws.String(d.Id()),
			Groups:             expandStringList(d.Get("security_groups").(*schema.Set).List()),
		}

		_, err := conn.ModifyNetworkInterfaceAttribute(request)
		if err != nil {
			return fmt.Errorf("Failure updating ENI: %s", err)
		}

		d.SetPartial("security_groups")
	}

	if err := setTags(conn, d); err != nil {
		return err
	} else {
		d.SetPartial("tags")
	}

	d.Partial(false)

	return resourceAwsNetworkInterfaceRead(d, meta)
}

func resourceAwsNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	log.Printf("[INFO] Deleting ENI: %s", d.Id())

	detach_err := resourceAwsNetworkInterfaceDetach(d.Get("attachment").(*schema.Set), meta, d.Id())
	if detach_err != nil {
		return detach_err
	}

	deleteEniOpts := ec2.DeleteNetworkInterfaceInput{
		NetworkInterfaceId: aws.String(d.Id()),
	}
	if _, err := conn.DeleteNetworkInterface(&deleteEniOpts); err != nil {
		return fmt.Errorf("Error deleting ENI: %s", err)
	}

	return nil
}

func resourceAwsEniAttachmentHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["instance"].(string)))
	buf.WriteString(fmt.Sprintf("%d-", m["device_index"].(int)))
	return hashcode.String(buf.String())
}
<|endoftext|>


<commit_before>package golog

import . "github.com/mndrix/golog/term"

import "github.com/mndrix/ps"

// Frame represents a single frame in a Golog machine's call stack
type Frame interface {
    // Env returns this stack frame's current bindings
    Env() Bindings

    // Goal returns this stack frame's current goal
    Goal() Term

    // HasChoicePoint returns true if this stack frame has unexplored
    // choicepoints
    HasChoicePoint() bool

    // NewChild creates a child stack frame similar to this one with
    // this one as the child's parent
    NewChild(Term, Bindings, *ps.List, *ps.List) Frame

    // Parent returns this stack frame's parent stack frame
    Parent() Frame

    // TakeChoicePoint returns the next choice point in line
    // (nil if there isn't one) and a new frame with the remaining
    // choice points intact
    TakeChoicePoint() (ChoicePoint, Frame)
}

var frameBottom frame
func init() {
    frameBottom.parent = &frameBottom  // infinite parental loop
    frameBottom.env = NewBindings()
    frameBottom.disjs = ps.NewList()
    frameBottom.conjs = ps.NewList()
}

// NewFrame returns a new, empty stack from
func NewFrame() Frame {
    return &frameBottom
}

type frame struct {
    env     Bindings
    parent  *frame
    goal    Term
    disjs   *ps.List     // of ChoicePoint
    conjs   *ps.List     // of Continuation
}

func (f *frame) clone() *frame {
    var f1 frame
    f1.env = f.env
    f1.parent = f.parent
    f1.goal = f.goal
    f1.disjs = f.disjs
    f1.conjs = f1.conjs
    return &f1
}

func (parent *frame) NewChild(goal Term, env Bindings, conjs, disjs *ps.List) Frame {
    child := parent.clone()
    child.parent = parent
    child.goal = goal
    if env != nil {
        child.env = env
    }
    if conjs != nil {
        child.conjs = conjs
    }
    if disjs != nil {
        child.disjs = disjs
    }

    return child
}

func (f *frame) TakeChoicePoint() (ChoicePoint, Frame) {
    if f.disjs == nil || f.disjs.IsNil() {
        return nil, nil
    }

    f1 := f.clone()
    f1.disjs = f.disjs.Tail()
    return f.disjs.Head().(ChoicePoint), f1
}

func (f *frame) Env() Bindings {
    return f.env
}

func (f *frame) Goal() Term {
    return f.goal
}

func (f *frame) Parent() Frame {
    return f.parent
}

func (f *frame) HasChoicePoint() bool {
    return f.disjs != nil && !f.disjs.IsNil()
}

// is this the bottom-most stack frame?
func IsBottom(f Frame) bool {
    switch fr := f.(type) {
        case *frame:
            return fr == &frameBottom
    }
    panic("Unexpected frame implementation")
}
<commit_msg>Refactor frame.NewChild<commit_after>package golog

import . "github.com/mndrix/golog/term"

import "github.com/mndrix/ps"

// Frame represents a single frame in a Golog machine's call stack
type Frame interface {
    // Env returns this stack frame's current bindings
    Env() Bindings

    // Goal returns this stack frame's current goal
    Goal() Term

    // HasChoicePoint returns true if this stack frame has unexplored
    // choicepoints
    HasChoicePoint() bool

    // NewChild creates a child stack frame similar to this one with
    // this one as the child's parent
    NewChild(Term, Bindings, *ps.List, *ps.List) Frame

    // Parent returns this stack frame's parent stack frame
    Parent() Frame

    // TakeChoicePoint returns the next choice point in line
    // (nil if there isn't one) and a new frame with the remaining
    // choice points intact
    TakeChoicePoint() (ChoicePoint, Frame)
}

var frameBottom frame
func init() {
    frameBottom.parent = &frameBottom  // infinite parental loop
    frameBottom.env = NewBindings()
    frameBottom.disjs = ps.NewList()
    frameBottom.conjs = ps.NewList()
}

// NewFrame returns a new, empty stack from
func NewFrame() Frame {
    return &frameBottom
}

type frame struct {
    env     Bindings
    parent  *frame
    goal    Term
    disjs   *ps.List     // of ChoicePoint
    conjs   *ps.List     // of Continuation
}

func (f *frame) clone() *frame {
    var f1 frame
    f1.env = f.env
    f1.parent = f.parent
    f1.goal = f.goal
    f1.disjs = f.disjs
    f1.conjs = f1.conjs
    return &f1
}

func (f *frame) update(goal Term, env Bindings, conjs, disjs *ps.List) *frame {
    newb := f.clone()
    newb.goal = goal
    if env != nil {
        newb.env = env
    }
    if conjs != nil {
        newb.conjs = conjs
    }
    if disjs != nil {
        newb.disjs = disjs
    }
    return newb
}
func (f *frame) NewChild(goal Term, env Bindings, conjs, disjs *ps.List) Frame {
    child := f.update(goal, env, conjs, disjs)
    child.parent = f
    return child
}

func (f *frame) TakeChoicePoint() (ChoicePoint, Frame) {
    if f.disjs == nil || f.disjs.IsNil() {
        return nil, nil
    }

    f1 := f.clone()
    f1.disjs = f.disjs.Tail()
    return f.disjs.Head().(ChoicePoint), f1
}

func (f *frame) Env() Bindings {
    return f.env
}

func (f *frame) Goal() Term {
    return f.goal
}

func (f *frame) Parent() Frame {
    return f.parent
}

func (f *frame) HasChoicePoint() bool {
    return f.disjs != nil && !f.disjs.IsNil()
}

// is this the bottom-most stack frame?
func IsBottom(f Frame) bool {
    switch fr := f.(type) {
        case *frame:
            return fr == &frameBottom
    }
    panic("Unexpected frame implementation")
}
<|endoftext|>


<commit_before>package gorma

import (
	"fmt"
	"os"
	"path/filepath"

	"text/template"

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
	"gopkg.in/alecthomas/kingpin.v2"
)

// Generator is the application code generator.
type Generator struct {
	genfiles []string
}

// ModelWriter generate code for a goa application media types.
// Media types are data structures used to render the response bodies.
type ModelWriter struct {
	*codegen.GoGenerator
	ModelTmpl *template.Template
}

// NewModelWriter returns a contexts code writer.
// Media types contain the data used to render response bodies.
func NewModelWriter(filename string) (*ModelWriter, error) {
	cw := codegen.NewGoGenerator(filename)
	funcMap := cw.FuncMap
	funcMap["gotypedef"] = codegen.GoTypeDef
	funcMap["gotyperef"] = codegen.GoTypeRef
	funcMap["goify"] = codegen.Goify
	funcMap["gotypename"] = codegen.GoTypeName
	funcMap["gonative"] = codegen.GoNativeType
	funcMap["typeUnmarshaler"] = codegen.TypeUnmarshaler
	funcMap["typeMarshaler"] = codegen.MediaTypeMarshaler
	funcMap["recursiveValidate"] = codegen.RecursiveChecker
	funcMap["tempvar"] = codegen.Tempvar

	modelTmpl, err := template.New("models").Funcs(funcMap).Parse(modelTmpl)
	if err != nil {
		return nil, err
	}
	w := ModelWriter{
		GoGenerator: cw,
		ModelTmpl:   modelTmpl,
	}
	return &w, nil
}

// Execute writes the code for the context types to the writer.
func (w *ModelWriter) Execute(mt *design.MediaTypeDefinition) error {
	return w.ModelTmpl.Execute(w, mt)
}

// Generate is the generator entry point called by the meta generator.
func Generate(api *design.APIDefinition) ([]string, error) {
	g, err := NewGenerator()
	if err != nil {
		return nil, err
	}
	return g.Generate(api)
}

// NewGenerator returns the application code generator.
func NewGenerator() (*Generator, error) {
	return new(Generator), nil
}

// JSONSchemaDir is the path to the directory where the schema controller is generated.
func ModelDir() string {
	return filepath.Join(codegen.OutputDir, "models")
}

// Generate produces the skeleton main.
func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) {
	os.RemoveAll(ModelDir())
	os.MkdirAll(ModelDir(), 0755)
	app := kingpin.New("Model generator", "model generator")
	codegen.RegisterFlags(app)
	_, err := app.Parse(os.Args[1:])
	if err != nil {
		panic(err)
	}
	fmt.Println(codegen.OutputDir)
	imp, err := filepath.Rel(filepath.Join(os.Getenv("GOPATH"), "src"), codegen.OutputDir)
	if err != nil {
		return nil, err
	}
	imp = filepath.Join(imp, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(imp),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
	}

	title := fmt.Sprintf("%s: Models", api.Name)
	filename := filepath.Join(ModelDir(), "models.go")
	mtw, err := NewModelWriter(filename)
	if err != nil {
		panic(err)
	}
	mtw.WriteHeader(title, "models", imports)

	err = api.IterateMediaTypes(func(res *design.MediaTypeDefinition) error {
		if res.Type.IsObject() {
			fmt.Println(res.UserTypeDefinition.TypeName)

			fmt.Printf("%v\n", res)
			err = mtw.Execute(res)
			if err != nil {
				panic(err)
				//	g.Cleanup()
				return err
			}

		} else {
			fmt.Println("skipping")
		}

		return nil

	})
	if err := mtw.FormatCode(); err != nil {
		g.Cleanup()
		return nil, err
	}
	if err != nil {
		g.genfiles = append(g.genfiles, filename)
	}
	return g.genfiles, err
}

// Cleanup removes all the files generated by this generator during the last invokation of Generate.
func (g *Generator) Cleanup() {
	for _, f := range g.genfiles {
		os.Remove(f)
	}
	g.genfiles = nil
}

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}{{gotypename . 0}} media type{{end}}
// Identifier: {{.Identifier}}{{$typeName := gotypename . 0}}
type {{$typeName}} {{gotypedef . 0 true false}}

func {{$typeName}}FromCreatePayload(ctx *app.Create{{$typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{$typeName}} {
	target := app.{{$typeName}}{}
	copier.Copy(&target, &m)
	return &target
}

type {{$typeName}}Storage interface {
	List(ctx *app.List{{$typeName}}Context) []{{$typeName}}
	Get(ctx *app.Show{{$typeName}}Context) ({{$typeName}}, error)
	Add(ctx *app.Create{{$typeName}}Context) ({{$typeName}}, error)
	Update(ctx *app.Update{{$typeName}}Context, m {{$typeName}}) ({{$typeName}}, error)
	Delete(ctx *app.Delete{{$typeName}}Context, id int) (bool, error)
}

type {{$typeName}}DB struct {
	DB gorm.DB
}

func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx *app.List{{$typeName}}Context) []{{$typeName}} {

	var objs []{{$typeName}}
	m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx *app.Show{{$typeName}}Context) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, ctx.{{$typeName}}ID).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx *app.Create{{$typeName}}Context) ({{$typeName}}, error) {
	model := {{$typeName}}FromCreatePayload(ctx)
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx *app.Update{{$typeName}}Context, model {{$typeName}}) ({{$typeName}}, error) {
	getCtx, err := app.NewShow{{$typeName}}Context(ctx.Context)
	if err != nil {
		return {{$typeName}}{}, err
	}
	obj, err := m.Get(getCtx)
	if err != nil {
		return model, err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}
func (m *{{$typeName}}DB) Delete(ctx *app.Delete{{$typeName}}Context, id int) (bool, error) {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return false, err
	}
	return true, nil
}

type Mock{{$typeName}}Storage struct {
	{{$typeName}}List  map[int]{{$typeName}}
	nextID int
	mut sync.Mutex
}

func NewMock{{$typeName}}Storage() *Mock{{$typeName}}Storage {
	ml := make(map[int]{{$typeName}}, 0)
	return &Mock{{$typeName}}Storage{ {{$typeName}}List: ml}
}

func (db *Mock{{$typeName}}Storage) List(ctx *app.List{{$typeName}}Context) []{{$typeName}} {
	var list []{{$typeName}} = make([]{{$typeName}}, 0)
	for _, v := range db.{{$typeName}}List {
		list = append(list, v)
	}
	return list
}

func (db *Mock{{$typeName}}Storage) Get(ctx *app.Show{{$typeName}}Context) ({{$typeName}}, error) {

	var obj {{$typeName}}

	obj, ok := db.{{$typeName}}List[ctx.{{$typeName}}ID]
	if ok {
		return obj, nil
	} else {
		return obj, errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Add(ctx *app.Create{{$typeName}}Context)  ({{$typeName}}, error) {
	u := {{$typeName}}FromCreatePayload(ctx)
	db.mut.Lock()
	db.nextID = db.nextID + 1
	u.ID = db.nextID
	db.mut.Unlock()

	db.{{$typeName}}List[u.ID] = u
	return u, nil
}

func (db *Mock{{$typeName}}Storage) Update(ctx *app.Update{{$typeName}}Context, u {{$typeName}}) ({{$typeName}}, error) {
	id := u.ID
	_, ok := db.{{$typeName}}List[id]
	if ok {
		db.{{$typeName}}List[id] = u
		return db.{{$typeName}}List[id], nil
	} else {
		return u, errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Delete(ctx *app.Delete{{$typeName}}Context, id int) (bool, error) {
	_, ok := db.{{$typeName}}List[id]
	if ok {
		delete(db.{{$typeName}}List, id)
		return true, nil
	} else {
		return false, errors.New("Could not delete this user")
	}
}
`
<commit_msg>cleanup a little'<commit_after>package gorma

import (
	"fmt"
	"os"
	"path/filepath"

	"text/template"

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
	"gopkg.in/alecthomas/kingpin.v2"
)

// Generator is the application code generator.
type Generator struct {
	genfiles []string
}

// ModelWriter generate code for a goa application media types.
// Media types are data structures used to render the response bodies.
type ModelWriter struct {
	*codegen.GoGenerator
	ModelTmpl *template.Template
}

// NewModelWriter returns a contexts code writer.
// Media types contain the data used to render response bodies.
func NewModelWriter(filename string) (*ModelWriter, error) {
	cw := codegen.NewGoGenerator(filename)
	funcMap := cw.FuncMap
	funcMap["gotypedef"] = codegen.GoTypeDef
	funcMap["gotyperef"] = codegen.GoTypeRef
	funcMap["goify"] = codegen.Goify
	funcMap["gotypename"] = codegen.GoTypeName
	funcMap["gonative"] = codegen.GoNativeType
	funcMap["typeUnmarshaler"] = codegen.TypeUnmarshaler
	funcMap["typeMarshaler"] = codegen.MediaTypeMarshaler
	funcMap["recursiveValidate"] = codegen.RecursiveChecker
	funcMap["tempvar"] = codegen.Tempvar

	modelTmpl, err := template.New("models").Funcs(funcMap).Parse(modelTmpl)
	if err != nil {
		return nil, err
	}
	w := ModelWriter{
		GoGenerator: cw,
		ModelTmpl:   modelTmpl,
	}
	return &w, nil
}

// Execute writes the code for the context types to the writer.
func (w *ModelWriter) Execute(mt *design.MediaTypeDefinition) error {
	return w.ModelTmpl.Execute(w, mt)
}

// Generate is the generator entry point called by the meta generator.
func Generate(api *design.APIDefinition) ([]string, error) {
	g, err := NewGenerator()
	if err != nil {
		return nil, err
	}
	return g.Generate(api)
}

// NewGenerator returns the application code generator.
func NewGenerator() (*Generator, error) {
	return new(Generator), nil
}

// JSONSchemaDir is the path to the directory where the schema controller is generated.
func ModelDir() string {
	return filepath.Join(codegen.OutputDir, "models")
}

// Generate produces the skeleton main.
func (g *Generator) Generate(api *design.APIDefinition) ([]string, error) {
	os.RemoveAll(ModelDir())
	os.MkdirAll(ModelDir(), 0755)
	app := kingpin.New("Model generator", "model generator")
	codegen.RegisterFlags(app)
	_, err := app.Parse(os.Args[1:])
	if err != nil {
		panic(err)
	}
	fmt.Println(codegen.OutputDir)
	imp, err := filepath.Rel(filepath.Join(os.Getenv("GOPATH"), "src"), codegen.OutputDir)
	if err != nil {
		return nil, err
	}
	imp = filepath.Join(imp, "app")
	imports := []*codegen.ImportSpec{
		codegen.SimpleImport(imp),
		codegen.SimpleImport("github.com/jinzhu/gorm"),
		codegen.SimpleImport("github.com/jinzhu/copier"),
	}

	title := fmt.Sprintf("%s: Models", api.Name)
	filename := filepath.Join(ModelDir(), "models.go")
	mtw, err := NewModelWriter(filename)
	if err != nil {
		panic(err)
	}
	mtw.WriteHeader(title, "models", imports)
	err = api.IterateMediaTypes(func(res *design.MediaTypeDefinition) error {
		if res.Type.IsObject() {

			err = mtw.Execute(res)
			if err != nil {
				g.Cleanup()
				return err
			}
		}
		return nil
	})
	if err := mtw.FormatCode(); err != nil {
		g.Cleanup()
		return nil, err
	}
	if err != nil {
		g.genfiles = append(g.genfiles, filename)
	}
	return g.genfiles, err
}

// Cleanup removes all the files generated by this generator during the last invokation of Generate.
func (g *Generator) Cleanup() {
	for _, f := range g.genfiles {
		os.Remove(f)
	}
	g.genfiles = nil
}

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}{{gotypename . 0}} media type{{end}}
// Identifier: {{.Identifier}}{{$typeName := gotypename . 0}}
type {{$typeName}} {{gotypedef . 0 true false}}

func {{$typeName}}FromCreatePayload(ctx *app.Create{{$typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}
func (m {{$typeName}}) ToApp() *app.{{$typeName}} {
	target := app.{{$typeName}}{}
	copier.Copy(&target, &m)
	return &target
}

type {{$typeName}}Storage interface {
	List(ctx *app.List{{$typeName}}Context) []{{$typeName}}
	Get(ctx *app.Show{{$typeName}}Context) ({{$typeName}}, error)
	Add(ctx *app.Create{{$typeName}}Context) ({{$typeName}}, error)
	Update(ctx *app.Update{{$typeName}}Context, m {{$typeName}}) ({{$typeName}}, error)
	Delete(ctx *app.Delete{{$typeName}}Context, id int) (bool, error)
}

type {{$typeName}}DB struct {
	DB gorm.DB
}

func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	return &{{$typeName}}DB{DB: db}
}

func (m *{{$typeName}}DB) List(ctx *app.List{{$typeName}}Context) []{{$typeName}} {

	var objs []{{$typeName}}
	m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) Get(ctx *app.Show{{$typeName}}Context) ({{$typeName}}, error) {

	var obj {{$typeName}}

	err := m.DB.Find(&obj, ctx.{{$typeName}}ID).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx *app.Create{{$typeName}}Context) ({{$typeName}}, error) {
	model := {{$typeName}}FromCreatePayload(ctx)
	err := m.DB.Create(&model).Error
	return model, err
}
func (m *{{$typeName}}DB) Update(ctx *app.Update{{$typeName}}Context, model {{$typeName}}) ({{$typeName}}, error) {
	getCtx, err := app.NewShow{{$typeName}}Context(ctx.Context)
	if err != nil {
		return {{$typeName}}{}, err
	}
	obj, err := m.Get(getCtx)
	if err != nil {
		return model, err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	if err != nil {
		ctx.Error(err.Error())
	}
	return obj, err
}
func (m *{{$typeName}}DB) Delete(ctx *app.Delete{{$typeName}}Context, id int) (bool, error) {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		ctx.Logger.Error(err.Error())
		return false, err
	}
	return true, nil
}

type Mock{{$typeName}}Storage struct {
	{{$typeName}}List  map[int]{{$typeName}}
	nextID int
	mut sync.Mutex
}

func NewMock{{$typeName}}Storage() *Mock{{$typeName}}Storage {
	ml := make(map[int]{{$typeName}}, 0)
	return &Mock{{$typeName}}Storage{ {{$typeName}}List: ml}
}

func (db *Mock{{$typeName}}Storage) List(ctx *app.List{{$typeName}}Context) []{{$typeName}} {
	var list []{{$typeName}} = make([]{{$typeName}}, 0)
	for _, v := range db.{{$typeName}}List {
		list = append(list, v)
	}
	return list
}

func (db *Mock{{$typeName}}Storage) Get(ctx *app.Show{{$typeName}}Context) ({{$typeName}}, error) {

	var obj {{$typeName}}

	obj, ok := db.{{$typeName}}List[ctx.{{$typeName}}ID]
	if ok {
		return obj, nil
	} else {
		return obj, errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Add(ctx *app.Create{{$typeName}}Context)  ({{$typeName}}, error) {
	u := {{$typeName}}FromCreatePayload(ctx)
	db.mut.Lock()
	db.nextID = db.nextID + 1
	u.ID = db.nextID
	db.mut.Unlock()

	db.{{$typeName}}List[u.ID] = u
	return u, nil
}

func (db *Mock{{$typeName}}Storage) Update(ctx *app.Update{{$typeName}}Context, u {{$typeName}}) ({{$typeName}}, error) {
	id := u.ID
	_, ok := db.{{$typeName}}List[id]
	if ok {
		db.{{$typeName}}List[id] = u
		return db.{{$typeName}}List[id], nil
	} else {
		return u, errors.New("{{$typeName}} does not exist")
	}
}

func (db *Mock{{$typeName}}Storage) Delete(ctx *app.Delete{{$typeName}}Context, id int) (bool, error) {
	_, ok := db.{{$typeName}}List[id]
	if ok {
		delete(db.{{$typeName}}List, id)
		return true, nil
	} else {
		return false, errors.New("Could not delete this user")
	}
}
`
<|endoftext|>


<commit_before>package null_test

import (
	"testing"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	"github.com/philharnish/forge/spec/matchers"
	"github.com/philharnish/forge/src/data/graph/bloom/node"
	"github.com/philharnish/forge/src/data/graph/bloom/null"
)

func Test(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Tests")
}

var _ = Describe("Node interfaces", func() {
	It("includes Root func", func() {
		Expect(null.Null.Root()).NotTo(BeNil())
	})

	It("includes Items func", func() {
		items := null.Null.Items(node.NodeAcceptAll)
		Expect(items).NotTo(BeNil())
		Expect(items.HasNext()).To(BeFalse())
		Expect(func() { items.Next() }).To(Panic())
	})

	It("includes String func", func() {
		Expect(null.Null.String()).To(Equal("Null()"))
	})
})

type TestIterator struct{}

func (iterator *TestIterator) Root() *node.Node {
	return &node.Node{}
}

func (iterator *TestIterator) Items(acceptor node.NodeAcceptor) node.NodeItems {
	return &TestItems{"a", "b"}
}

func (iterator *TestIterator) String() string {
	return node.Format("TestIterator", iterator.Root())
}

type TestItems []string

func (items *TestItems) HasNext() bool {
	return len(*items) > 0
}

func (items *TestItems) Next() (string, node.NodeIterator) {
	if !items.HasNext() {
		return "", nil
	}
	item := (*items)[0]
	*items = (*items)[1:]
	return item, &TestIterator{}
}

func getFirstItem(i node.NodeIterator) (string, node.NodeIterator) {
	items := i.Items(node.NodeAcceptAll)
	return items.Next()
}

var _ = Describe("TestIterator", func() {
	var iterator *TestIterator

	BeforeEach(func() {
		iterator = &TestIterator{}
	})

	It("Conforms with interface and compiles", func() {
		_, value := getFirstItem(iterator)
		Expect(value).NotTo(BeNil())
	})

	It("Produces string results", func() {
		Expect(iterator.String()).To(Equal("TestIterator('', '', 0)"))
	})

	It("Produces shallow string results", func() {
		Expect(node.StringChildren(iterator)).To(matchers.LookLike(`
				TestIterator('', '', 0)
				├─a = TestIterator('', '', 0)
				└─b = TestIterator('', '', 0)
		`))
	})

	It("Produces deeper string results", func() {
		Expect(node.StringChildren(iterator, 2)).To(matchers.LookLike(`
				TestIterator('', '', 0)
				├─a = TestIterator('', '', 0)
				│ ├─a = TestIterator('', '', 0)
				│ └─b = TestIterator('', '', 0)
				└─b = TestIterator('', '', 0)
				• ├─a = TestIterator('', '', 0)
				• └─b = TestIterator('', '', 0)
		`))
	})
})
<commit_msg>Delete dead code.<commit_after>package null_test

import (
	"testing"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	"github.com/philharnish/forge/src/data/graph/bloom/node"
	"github.com/philharnish/forge/src/data/graph/bloom/null"
)

func Test(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Tests")
}

var _ = Describe("Node interfaces", func() {
	It("includes Root func", func() {
		Expect(null.Null.Root()).NotTo(BeNil())
	})

	It("includes Items func", func() {
		items := null.Null.Items(node.NodeAcceptAll)
		Expect(items).NotTo(BeNil())
		Expect(items.HasNext()).To(BeFalse())
		Expect(func() { items.Next() }).To(Panic())
	})

	It("includes String func", func() {
		Expect(null.Null.String()).To(Equal("Null()"))
	})
})
<|endoftext|>


<commit_before>package unionfind

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestNew(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	assert.NotNil(uf.nodes)
	assert.NotNil(uf.ufSets)
	assert.Len(uf.nodes, 0)
	assert.Len(uf.ufSets, 0)
}

func TestUnion(t *testing.T) {
	assert := assert.New(t)
	uf := New()

	// set A
	uf.Union(1, 1)
	uf.Union(1, 2)
	uf.Union(1, 2)
	assert.Len(uf.nodes, 2)
	assert.Len(uf.ufSets, 1)

	node1, node2 := uf.nodes[interface{}(1)], uf.nodes[interface{}(2)]
	assert.Contains(uf.ufSets, node1)
	assert.Equal(node1.value, 1)
	assert.Equal(node1.ancestor, node1)
	assert.Contains(node1.childs, node2)
	assert.NotContains(uf.ufSets, node2)
	assert.Equal(node2.value, 2)
	assert.Equal(node2.ancestor, node1)
	assert.Empty(node2.childs)

	uf.Union(1, 3)
	node3 := uf.nodes[interface{}(3)]
	assert.Len(node1.childs, 2)
	assert.Empty(node2.childs)
	assert.Len(uf.nodes, 3)
	assert.Len(uf.ufSets, 1)
	assert.Equal(node3.ancestor, node1)
	assert.Contains(node1.childs, node3)

	// set B
	//    10
	//   /  \
	// 11    12
	//      /
	//     13
	uf.Union(10, 11)
	uf.Union(10, 12)
	uf.Union(12, 13)

	assert.Len(uf.nodes, 3+4)
	node10, node11, node12, node13 := uf.nodes[interface{}(10)], uf.nodes[interface{}(11)], uf.nodes[interface{}(12)], uf.nodes[interface{}(13)]
	assert.Contains(uf.ufSets, node10)
	assert.Contains(node10.childs, node11)
	assert.Contains(node10.childs, node12)
	assert.Empty(node11.childs)
	assert.Contains(node12.childs, node13)
	assert.Empty(node13.childs)
	assert.Len(uf.ufSets, 2)
	assert.Equal(uf.ufSets[node10], 4)

	// SET C
	//        20
	//      /
	//     21
	//    /  \
	//   22   23
	//    \
	//     24
	uf.Union(20, 21)
	uf.Union(21, 22)
	uf.Union(21, 23)
	uf.Union(22, 24)

	assert.Len(uf.nodes, 3+4+5)
	node20, node21, node22, node23, node24 := uf.nodes[interface{}(20)], uf.nodes[interface{}(21)], uf.nodes[interface{}(22)], uf.nodes[interface{}(23)], uf.nodes[interface{}(24)]
	assert.Contains(uf.ufSets, node20)
	assert.Contains(node20.childs, node21)
	assert.Len(node20.childs, 1)
	assert.Contains(node21.childs, node22)
	assert.Contains(node21.childs, node23)
	assert.Len(node21.childs, 2)
	assert.Contains(node22.childs, node24)
	assert.Len(node22.childs, 1)
	assert.Empty(node23.childs)
	assert.Empty(node24.childs)
	assert.Len(uf.ufSets, 3)
	assert.Equal(uf.ufSets[node20], 5)

	// Union set B and C
	uf.Union(12, 21)
	assert.Len(uf.nodes, 3+4+5)
	assert.Len(uf.ufSets, 2)
	assert.Equal(uf.ufSets[node20], 4+5)
	assert.Len(node21.childs, 3)
	assert.Contains(node21.childs, node12)
	assert.Len(node12.childs, 2)
	assert.Contains(node12.childs, node10)
	assert.Len(node10.childs, 1)
	assert.NotContains(node10.childs, node12)
}

func TestUnion2(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	// set A
	//    10
	//   /  \
	// 11    12
	//      /
	//     13
	//    /
	//   14
	uf.Union(10, 11)
	uf.Union(10, 12)
	uf.Union(12, 13)
	uf.Union(13, 14)
	node10, node11, node12, node13, node14 := uf.nodes[interface{}(10)], uf.nodes[interface{}(11)], uf.nodes[interface{}(12)], uf.nodes[interface{}(13)], uf.nodes[interface{}(14)]

	// SET B
	//        20
	//      /
	//     21
	//    /  \
	//   22   23
	//    \
	//     24
	uf.Union(20, 21)
	uf.Union(21, 22)
	uf.Union(21, 23)
	uf.Union(22, 24)
	node20, node21, node22, node23, node24 := uf.nodes[interface{}(20)], uf.nodes[interface{}(21)], uf.nodes[interface{}(22)], uf.nodes[interface{}(23)], uf.nodes[interface{}(24)]

	// Union set A and B
	//        10
	//       /  \
	//     11   12
	//         /  \
	//        13   22
	//       /    /  \
	//      14   24  21
	//              /  \
	//             20  23
	uf.Union(12, 22)
	assert.Len(uf.nodes, 5+5)
	assert.Len(uf.ufSets, 1)

	assert.Len(node10.childs, 2)
	assert.Equal(node10.ancestor, node10)
	assert.Equal(node10.parent, node10)
	assert.Contains(node10.childs, node11)
	assert.Contains(node10.childs, node12)

	assert.Empty(node11.childs)
	assert.Equal(node11.ancestor, node10)
	assert.Equal(node11.parent, node10)

	assert.Len(node12.childs, 2)
	assert.Equal(node12.ancestor, node10)
	assert.Equal(node12.parent, node10)
	assert.Contains(node12.childs, node13)
	assert.Contains(node12.childs, node22)

	assert.Len(node13.childs, 1)
	assert.Equal(node13.ancestor, node10)
	assert.Equal(node13.parent, node12)
	assert.Contains(node13.childs, node14)

	assert.Empty(node14.childs)
	assert.Equal(node14.ancestor, node10)
	assert.Equal(node14.parent, node13)

	assert.Len(node22.childs, 2)
	assert.Equal(node22.ancestor, node10)
	assert.Equal(node22.parent, node12)
	assert.Contains(node22.childs, node24)
	assert.Contains(node22.childs, node21)

	assert.Empty(node24.childs)
	assert.Equal(node24.ancestor, node10)
	assert.Equal(node24.parent, node22)

	assert.Len(node21.childs, 2)
	assert.Equal(node21.ancestor, node10)
	assert.Equal(node21.parent, node22)
	assert.Contains(node21.childs, node20)
	assert.Contains(node21.childs, node23)

	assert.Empty(node20.childs)
	assert.Equal(node20.ancestor, node10)
	assert.Equal(node20.parent, node21)

	assert.Empty(node23.childs)
	assert.Equal(node23.ancestor, node10)
	assert.Equal(node23.parent, node21)
}

func TestFind(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	uf.Union(1, 2)
	assert.Equal(uf.Find(1), 1)
	assert.Equal(uf.Find(2), 1)
	assert.Nil(uf.Find(3))
}

func TestConnected(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	uf.Union(1, 2)
	uf.Union(3, 4)
	assert.True(uf.Connected(1, 2))
	assert.True(uf.Connected(3, 4))
	assert.False(uf.Connected(1, 3))
	assert.False(uf.Connected(1, 4))
	assert.False(uf.Connected(2, 3))
	assert.False(uf.Connected(2, 4))
}

func TestCount(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	assert.Equal(uf.Count(), 0)
	uf.Union(1, 2)
	assert.Equal(uf.Count(), 1)
	uf.Union(3, 4)
	assert.Equal(uf.Count(), 2)
	uf.Union(1, 4)
	assert.Equal(uf.Count(), 1)
	uf.Union(2, 3)
	assert.Equal(uf.Count(), 1)
}
<commit_msg>fix typo: sync fix test<commit_after>package unionfind

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestNew(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	assert.NotNil(uf.nodes)
	assert.NotNil(uf.ufSets)
	assert.Len(uf.nodes, 0)
	assert.Len(uf.ufSets, 0)
}

func TestUnion(t *testing.T) {
	assert := assert.New(t)
	uf := New()

	// set A
	uf.Union(1, 1)
	uf.Union(1, 2)
	uf.Union(1, 2)
	assert.Len(uf.nodes, 2)
	assert.Len(uf.ufSets, 1)

	node1, node2 := uf.nodes[interface{}(1)], uf.nodes[interface{}(2)]
	assert.Contains(uf.ufSets, node1)
	assert.Equal(node1.value, 1)
	assert.Equal(node1.ancestor, node1)
	assert.Contains(node1.children, node2)
	assert.NotContains(uf.ufSets, node2)
	assert.Equal(node2.value, 2)
	assert.Equal(node2.ancestor, node1)
	assert.Empty(node2.children)

	uf.Union(1, 3)
	node3 := uf.nodes[interface{}(3)]
	assert.Len(node1.children, 2)
	assert.Empty(node2.children)
	assert.Len(uf.nodes, 3)
	assert.Len(uf.ufSets, 1)
	assert.Equal(node3.ancestor, node1)
	assert.Contains(node1.children, node3)

	// set B
	//    10
	//   /  \
	// 11    12
	//      /
	//     13
	uf.Union(10, 11)
	uf.Union(10, 12)
	uf.Union(12, 13)

	assert.Len(uf.nodes, 3+4)
	node10, node11, node12, node13 := uf.nodes[interface{}(10)], uf.nodes[interface{}(11)], uf.nodes[interface{}(12)], uf.nodes[interface{}(13)]
	assert.Contains(uf.ufSets, node10)
	assert.Contains(node10.children, node11)
	assert.Contains(node10.children, node12)
	assert.Empty(node11.children)
	assert.Contains(node12.children, node13)
	assert.Empty(node13.children)
	assert.Len(uf.ufSets, 2)
	assert.Equal(uf.ufSets[node10], 4)

	// SET C
	//        20
	//      /
	//     21
	//    /  \
	//   22   23
	//    \
	//     24
	uf.Union(20, 21)
	uf.Union(21, 22)
	uf.Union(21, 23)
	uf.Union(22, 24)

	assert.Len(uf.nodes, 3+4+5)
	node20, node21, node22, node23, node24 := uf.nodes[interface{}(20)], uf.nodes[interface{}(21)], uf.nodes[interface{}(22)], uf.nodes[interface{}(23)], uf.nodes[interface{}(24)]
	assert.Contains(uf.ufSets, node20)
	assert.Contains(node20.children, node21)
	assert.Len(node20.children, 1)
	assert.Contains(node21.children, node22)
	assert.Contains(node21.children, node23)
	assert.Len(node21.children, 2)
	assert.Contains(node22.children, node24)
	assert.Len(node22.children, 1)
	assert.Empty(node23.children)
	assert.Empty(node24.children)
	assert.Len(uf.ufSets, 3)
	assert.Equal(uf.ufSets[node20], 5)

	// Union set B and C
	uf.Union(12, 21)
	assert.Len(uf.nodes, 3+4+5)
	assert.Len(uf.ufSets, 2)
	assert.Equal(uf.ufSets[node20], 4+5)
	assert.Len(node21.children, 3)
	assert.Contains(node21.children, node12)
	assert.Len(node12.children, 2)
	assert.Contains(node12.children, node10)
	assert.Len(node10.children, 1)
	assert.NotContains(node10.children, node12)
}

func TestUnion2(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	// set A
	//    10
	//   /  \
	// 11    12
	//      /
	//     13
	//    /
	//   14
	uf.Union(10, 11)
	uf.Union(10, 12)
	uf.Union(12, 13)
	uf.Union(13, 14)
	node10, node11, node12, node13, node14 := uf.nodes[interface{}(10)], uf.nodes[interface{}(11)], uf.nodes[interface{}(12)], uf.nodes[interface{}(13)], uf.nodes[interface{}(14)]

	// SET B
	//        20
	//      /
	//     21
	//    /  \
	//   22   23
	//    \
	//     24
	uf.Union(20, 21)
	uf.Union(21, 22)
	uf.Union(21, 23)
	uf.Union(22, 24)
	node20, node21, node22, node23, node24 := uf.nodes[interface{}(20)], uf.nodes[interface{}(21)], uf.nodes[interface{}(22)], uf.nodes[interface{}(23)], uf.nodes[interface{}(24)]

	// Union set A and B
	//        10
	//       /  \
	//     11   12
	//         /  \
	//        13   22
	//       /    /  \
	//      14   24  21
	//              /  \
	//             20  23
	uf.Union(12, 22)
	assert.Len(uf.nodes, 5+5)
	assert.Len(uf.ufSets, 1)

	assert.Len(node10.children, 2)
	assert.Equal(node10.ancestor, node10)
	assert.Equal(node10.parent, node10)
	assert.Contains(node10.children, node11)
	assert.Contains(node10.children, node12)

	assert.Empty(node11.children)
	assert.Equal(node11.ancestor, node10)
	assert.Equal(node11.parent, node10)

	assert.Len(node12.children, 2)
	assert.Equal(node12.ancestor, node10)
	assert.Equal(node12.parent, node10)
	assert.Contains(node12.children, node13)
	assert.Contains(node12.children, node22)

	assert.Len(node13.children, 1)
	assert.Equal(node13.ancestor, node10)
	assert.Equal(node13.parent, node12)
	assert.Contains(node13.children, node14)

	assert.Empty(node14.children)
	assert.Equal(node14.ancestor, node10)
	assert.Equal(node14.parent, node13)

	assert.Len(node22.children, 2)
	assert.Equal(node22.ancestor, node10)
	assert.Equal(node22.parent, node12)
	assert.Contains(node22.children, node24)
	assert.Contains(node22.children, node21)

	assert.Empty(node24.children)
	assert.Equal(node24.ancestor, node10)
	assert.Equal(node24.parent, node22)

	assert.Len(node21.children, 2)
	assert.Equal(node21.ancestor, node10)
	assert.Equal(node21.parent, node22)
	assert.Contains(node21.children, node20)
	assert.Contains(node21.children, node23)

	assert.Empty(node20.children)
	assert.Equal(node20.ancestor, node10)
	assert.Equal(node20.parent, node21)

	assert.Empty(node23.children)
	assert.Equal(node23.ancestor, node10)
	assert.Equal(node23.parent, node21)
}

func TestFind(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	uf.Union(1, 2)
	assert.Equal(uf.Find(1), 1)
	assert.Equal(uf.Find(2), 1)
	assert.Nil(uf.Find(3))
}

func TestConnected(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	uf.Union(1, 2)
	uf.Union(3, 4)
	assert.True(uf.Connected(1, 2))
	assert.True(uf.Connected(3, 4))
	assert.False(uf.Connected(1, 3))
	assert.False(uf.Connected(1, 4))
	assert.False(uf.Connected(2, 3))
	assert.False(uf.Connected(2, 4))
}

func TestCount(t *testing.T) {
	assert := assert.New(t)

	uf := New()
	assert.Equal(uf.Count(), 0)
	uf.Union(1, 2)
	assert.Equal(uf.Count(), 1)
	uf.Union(3, 4)
	assert.Equal(uf.Count(), 2)
	uf.Union(1, 4)
	assert.Equal(uf.Count(), 1)
	uf.Union(2, 3)
	assert.Equal(uf.Count(), 1)
}
<|endoftext|>


<commit_before>package state

import (
	"fmt"

	"github.com/hashicorp/consul/agent/consul/stream"
	"github.com/hashicorp/go-memdb"
)

// ReadTxn is implemented by memdb.Txn to perform read operations.
type ReadTxn interface {
	Get(table, index string, args ...interface{}) (memdb.ResultIterator, error)
	First(table, index string, args ...interface{}) (interface{}, error)
	FirstWatch(table, index string, args ...interface{}) (<-chan struct{}, interface{}, error)
	Abort()
}

// WriteTxn is implemented by memdb.Txn to perform write operations.
type WriteTxn interface {
	ReadTxn
	Insert(table string, obj interface{}) error
	Commit() error
}

// Changes wraps a memdb.Changes to include the index at which these changes
// were made.
type Changes struct {
	// Index is the latest index at the time these changes were committed.
	Index   uint64
	Changes memdb.Changes
}

// changeTrackerDB is a thin wrapper around memdb.DB which enables TrackChanges on
// all write transactions. When the transaction is committed the changes are
// sent to the eventPublisher which will create and emit change events.
type changeTrackerDB struct {
	db             *memdb.MemDB
	publisher      eventPublisher
	processChanges func(ReadTxn, Changes) ([]stream.Event, error)
}

type eventPublisher interface {
	Publish(events []stream.Event)
}

// Txn exists to maintain backwards compatibility with memdb.DB.Txn. Preexisting
// code may use it to create a read-only transaction, but it will panic if called
// with write=true.
//
// Deprecated: use either ReadTxn, or WriteTxn.
func (c *changeTrackerDB) Txn(write bool) *txn {
	if write {
		panic("don't use db.Txn(true), use db.WriteTxn(idx uin64)")
	}
	return c.ReadTxn()
}

// ReadTxn returns a read-only transaction which behaves exactly the same as
// memdb.Txn
//
// TODO: this could return a regular memdb.Txn if all the state functions accepted
// the ReadTxn interface
func (c *changeTrackerDB) ReadTxn() *txn {
	return &txn{Txn: c.db.Txn(false)}
}

// WriteTxn returns a wrapped memdb.Txn suitable for writes to the state store.
// It will track changes and publish events for the changes when Commit
// is called.
//
// The idx argument must be the index of the current Raft operation. Almost
// all mutations to state should happen as part of a raft apply so the index of
// the log being applied can be passed to WriteTxn.
// The exceptional cases are transactions that are executed on an empty
// memdb.DB as part of Restore, and those executed by tests where we insert
// data directly into the DB. These cases may use WriteTxnRestore.
func (c *changeTrackerDB) WriteTxn(idx uint64) *txn {
	t := &txn{
		Txn:     c.db.Txn(true),
		Index:   idx,
		publish: c.publish,
	}
	t.Txn.TrackChanges()
	return t
}

func (c *changeTrackerDB) publish(changes Changes) error {
	readOnlyTx := c.db.Txn(false)
	defer readOnlyTx.Abort()

	events, err := c.processChanges(readOnlyTx, changes)
	if err != nil {
		return fmt.Errorf("failed generating events from changes: %v", err)
	}
	c.publisher.Publish(events)
	return nil
}

// WriteTxnRestore returns a wrapped RW transaction that should only be used in
// Restore where we need to replace the entire contents of the Store.
// WriteTxnRestore uses a zero index since the whole restore doesn't really
// occur at one index - the effect is to write many values that were previously
// written across many indexes.
func (c *changeTrackerDB) WriteTxnRestore() *txn {
	t := &txn{
		Txn:   c.db.Txn(true),
		Index: 0,
	}

	// We enable change tracking so that usage data is correctly populated.
	t.Txn.TrackChanges()
	return t
}

// txn wraps a memdb.Txn to capture changes and send them to the EventPublisher.
//
// This can not be done with txn.Defer because the callback passed to Defer is
// invoked after commit completes, and because the callback can not return an
// error. Any errors from the callback would be lost,  which would result in a
// missing change event, even though the state store had changed.
type txn struct {
	*memdb.Txn
	// Index in raft where the write is occurring. The value is zero for a
	// read-only, or WriteTxnRestore transaction.
	// Index is stored so that it may be passed along to any subscribers as part
	// of a change event.
	Index   uint64
	publish func(changes Changes) error
}

// Commit first pushes changes to EventPublisher, then calls Commit on the
// underlying transaction.
//
// Note that this function, unlike memdb.Txn, returns an error which must be checked
// by the caller. A non-nil error indicates that a commit failed and was not
// applied.
func (tx *txn) Commit() error {
	changes := Changes{
		Index:   tx.Index,
		Changes: tx.Txn.Changes(),
	}

	if len(changes.Changes) > 0 {
		if err := updateUsage(tx, changes); err != nil {
			return err
		}
	}

	// publish may be nil if this is a read-only or WriteTxnRestore transaction.
	// In those cases changes should also be empty, and there will be nothing
	// to publish.
	if tx.publish != nil {
		if err := tx.publish(changes); err != nil {
			return err
		}
	}

	tx.Txn.Commit()
	return nil
}

// TODO: may be replaced by a gRPC type.
type topic string

func (t topic) String() string {
	return string(t)
}

func processDBChanges(tx ReadTxn, changes Changes) ([]stream.Event, error) {
	// TODO: add other table handlers here.
	return aclChangeUnsubscribeEvent(tx, changes)
}

func newSnapshotHandlers() stream.SnapshotHandlers {
	return stream.SnapshotHandlers{}
}
<commit_msg>Update godoc string for memdb wrapper functions/structs<commit_after>package state

import (
	"fmt"

	"github.com/hashicorp/consul/agent/consul/stream"
	"github.com/hashicorp/go-memdb"
)

// ReadTxn is implemented by memdb.Txn to perform read operations.
type ReadTxn interface {
	Get(table, index string, args ...interface{}) (memdb.ResultIterator, error)
	First(table, index string, args ...interface{}) (interface{}, error)
	FirstWatch(table, index string, args ...interface{}) (<-chan struct{}, interface{}, error)
	Abort()
}

// WriteTxn is implemented by memdb.Txn to perform write operations.
type WriteTxn interface {
	ReadTxn
	Insert(table string, obj interface{}) error
	Commit() error
}

// Changes wraps a memdb.Changes to include the index at which these changes
// were made.
type Changes struct {
	// Index is the latest index at the time these changes were committed.
	Index   uint64
	Changes memdb.Changes
}

// changeTrackerDB is a thin wrapper around memdb.DB which enables TrackChanges on
// all write transactions. When the transaction is committed the changes are:
// 1. Used to update our internal usage tracking
// 2. Sent to the eventPublisher which will create and emit change events
type changeTrackerDB struct {
	db             *memdb.MemDB
	publisher      eventPublisher
	processChanges func(ReadTxn, Changes) ([]stream.Event, error)
}

type eventPublisher interface {
	Publish(events []stream.Event)
}

// Txn exists to maintain backwards compatibility with memdb.DB.Txn. Preexisting
// code may use it to create a read-only transaction, but it will panic if called
// with write=true.
//
// Deprecated: use either ReadTxn, or WriteTxn.
func (c *changeTrackerDB) Txn(write bool) *txn {
	if write {
		panic("don't use db.Txn(true), use db.WriteTxn(idx uin64)")
	}
	return c.ReadTxn()
}

// ReadTxn returns a read-only transaction which behaves exactly the same as
// memdb.Txn
//
// TODO: this could return a regular memdb.Txn if all the state functions accepted
// the ReadTxn interface
func (c *changeTrackerDB) ReadTxn() *txn {
	return &txn{Txn: c.db.Txn(false)}
}

// WriteTxn returns a wrapped memdb.Txn suitable for writes to the state store.
// It will track changes and publish events for the changes when Commit
// is called.
//
// The idx argument must be the index of the current Raft operation. Almost
// all mutations to state should happen as part of a raft apply so the index of
// the log being applied can be passed to WriteTxn.
// The exceptional cases are transactions that are executed on an empty
// memdb.DB as part of Restore, and those executed by tests where we insert
// data directly into the DB. These cases may use WriteTxnRestore.
func (c *changeTrackerDB) WriteTxn(idx uint64) *txn {
	t := &txn{
		Txn:     c.db.Txn(true),
		Index:   idx,
		publish: c.publish,
	}
	t.Txn.TrackChanges()
	return t
}

func (c *changeTrackerDB) publish(changes Changes) error {
	readOnlyTx := c.db.Txn(false)
	defer readOnlyTx.Abort()

	events, err := c.processChanges(readOnlyTx, changes)
	if err != nil {
		return fmt.Errorf("failed generating events from changes: %v", err)
	}
	c.publisher.Publish(events)
	return nil
}

// WriteTxnRestore returns a wrapped RW transaction that should only be used in
// Restore where we need to replace the entire contents of the Store.
// WriteTxnRestore uses a zero index since the whole restore doesn't really
// occur at one index - the effect is to write many values that were previously
// written across many indexes. WriteTxnRestore also does not publish any
// change events to subscribers.
func (c *changeTrackerDB) WriteTxnRestore() *txn {
	t := &txn{
		Txn:   c.db.Txn(true),
		Index: 0,
	}

	// We enable change tracking so that usage data is correctly populated.
	t.Txn.TrackChanges()
	return t
}

// txn wraps a memdb.Txn to capture changes and send them to the EventPublisher.
//
// This can not be done with txn.Defer because the callback passed to Defer is
// invoked after commit completes, and because the callback can not return an
// error. Any errors from the callback would be lost,  which would result in a
// missing change event, even though the state store had changed.
type txn struct {
	*memdb.Txn
	// Index in raft where the write is occurring. The value is zero for a
	// read-only, or WriteTxnRestore transaction.
	// Index is stored so that it may be passed along to any subscribers as part
	// of a change event.
	Index   uint64
	publish func(changes Changes) error
}

// Commit first pushes changes to EventPublisher, then calls Commit on the
// underlying transaction.
//
// Note that this function, unlike memdb.Txn, returns an error which must be checked
// by the caller. A non-nil error indicates that a commit failed and was not
// applied.
func (tx *txn) Commit() error {
	changes := Changes{
		Index:   tx.Index,
		Changes: tx.Txn.Changes(),
	}

	if len(changes.Changes) > 0 {
		if err := updateUsage(tx, changes); err != nil {
			return err
		}
	}

	// publish may be nil if this is a read-only or WriteTxnRestore transaction.
	// In those cases changes should also be empty, and there will be nothing
	// to publish.
	if tx.publish != nil {
		if err := tx.publish(changes); err != nil {
			return err
		}
	}

	tx.Txn.Commit()
	return nil
}

// TODO: may be replaced by a gRPC type.
type topic string

func (t topic) String() string {
	return string(t)
}

func processDBChanges(tx ReadTxn, changes Changes) ([]stream.Event, error) {
	// TODO: add other table handlers here.
	return aclChangeUnsubscribeEvent(tx, changes)
}

func newSnapshotHandlers() stream.SnapshotHandlers {
	return stream.SnapshotHandlers{}
}
<|endoftext|>


<commit_before>// Copyright 2014-2016 Amazon.com, Inc. or its affiliates. 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. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 image

import (
	"fmt"
	"sync"
	"time"

	"github.com/aws/amazon-ecs-agent/agent/api"
	"github.com/cihub/seelog"
)

type Image struct {
	ImageID string
	Names   []string
	Size    int64
}

// ImageState represents a docker image
// and its state information such as containers associated with it
type ImageState struct {
	Image      *Image
	Containers []*api.Container `json:"-"`
	PulledAt   time.Time
	LastUsedAt time.Time
	updateLock sync.RWMutex
}

func (imageState *ImageState) UpdateContainerReference(container *api.Container) {
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	seelog.Infof("Updating container reference %v in Image State - %v", container.Name, imageState.Image.ImageID)
	imageState.Containers = append(imageState.Containers, container)
}

func (imageState *ImageState) AddImageName(imageName string) {
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	if !imageState.HasImageName(imageName) {
		seelog.Infof("Adding image name- %v to Image state- %v", imageName, imageState.Image.ImageID)
		imageState.Image.Names = append(imageState.Image.Names, imageName)
	}
}

func (imageState *ImageState) HasNoAssociatedContainers() bool {
	return len(imageState.Containers) == 0
}

func (imageState *ImageState) UpdateImageState(container *api.Container) {
	imageState.AddImageName(container.Image)
	imageState.UpdateContainerReference(container)
}

func (imageState *ImageState) RemoveImageName(containerImageName string) {
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	for i, imageName := range imageState.Image.Names {
		if imageName == containerImageName {
			imageState.Image.Names = append(imageState.Image.Names[:i], imageState.Image.Names[i+1:]...)
		}
	}
}

func (imageState *ImageState) HasImageName(containerImageName string) bool {
	for _, imageName := range imageState.Image.Names {
		if imageName == containerImageName {
			return true
		}
	}
	return false
}

func (imageState *ImageState) RemoveContainerReference(container *api.Container) error {
	// Get the image state write lock for updating container reference
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	for i, _ := range imageState.Containers {
		if imageState.Containers[i].Name == container.Name {
			// Container reference found; hence remove it
			seelog.Infof("Removing Container Reference: %v from Image State- %v", container.Name, imageState.Image.ImageID)
			imageState.Containers = append(imageState.Containers[:i], imageState.Containers[i+1:]...)
			// Update the last used time for the image
			imageState.LastUsedAt = time.Now()
			return nil
		}
	}
	return fmt.Errorf("Container reference is not found in the image state container: %s", container.String())
}
<commit_msg>Fixed a race condition that can cause agent panici<commit_after>// Copyright 2014-2016 Amazon.com, Inc. or its affiliates. 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. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 image

import (
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"github.com/aws/amazon-ecs-agent/agent/api"
	"github.com/cihub/seelog"
)

type Image struct {
	ImageID string
	Names   []string
	Size    int64
}

// ImageState represents a docker image
// and its state information such as containers associated with it
type ImageState struct {
	Image      *Image
	Containers []*api.Container `json:"-"`
	PulledAt   time.Time
	LastUsedAt time.Time
	updateLock sync.RWMutex
}

func (imageState *ImageState) UpdateContainerReference(container *api.Container) {
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	seelog.Infof("Updating container reference %v in Image State - %v", container.Name, imageState.Image.ImageID)
	imageState.Containers = append(imageState.Containers, container)
}

func (imageState *ImageState) AddImageName(imageName string) {
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	if !imageState.HasImageName(imageName) {
		seelog.Infof("Adding image name- %v to Image state- %v", imageName, imageState.Image.ImageID)
		imageState.Image.Names = append(imageState.Image.Names, imageName)
	}
}

func (imageState *ImageState) HasNoAssociatedContainers() bool {
	return len(imageState.Containers) == 0
}

func (imageState *ImageState) UpdateImageState(container *api.Container) {
	imageState.AddImageName(container.Image)
	imageState.UpdateContainerReference(container)
}

func (imageState *ImageState) RemoveImageName(containerImageName string) {
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	for i, imageName := range imageState.Image.Names {
		if imageName == containerImageName {
			imageState.Image.Names = append(imageState.Image.Names[:i], imageState.Image.Names[i+1:]...)
		}
	}
}

func (imageState *ImageState) HasImageName(containerImageName string) bool {
	for _, imageName := range imageState.Image.Names {
		if imageName == containerImageName {
			return true
		}
	}
	return false
}

func (imageState *ImageState) RemoveContainerReference(container *api.Container) error {
	// Get the image state write lock for updating container reference
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()
	for i, _ := range imageState.Containers {
		if imageState.Containers[i].Name == container.Name {
			// Container reference found; hence remove it
			seelog.Infof("Removing Container Reference: %v from Image State- %v", container.Name, imageState.Image.ImageID)
			imageState.Containers = append(imageState.Containers[:i], imageState.Containers[i+1:]...)
			// Update the last used time for the image
			imageState.LastUsedAt = time.Now()
			return nil
		}
	}
	return fmt.Errorf("Container reference is not found in the image state container: %s", container.String())
}

func (imageState *ImageState) MarshalJSON() ([]byte, error) {
	imageState.updateLock.Lock()
	defer imageState.updateLock.Unlock()

	return json.Marshal(&struct {
		Image      *Image
		PulledAt   time.Time
		LastUsedAt time.Time
	}{
		Image:      imageState.Image,
		PulledAt:   imageState.PulledAt,
		LastUsedAt: imageState.LastUsedAt,
	})
}
<|endoftext|>