<commit_before>// +build ignore

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	verbose    bool
	keepGopath bool
	runTests   bool
)

var config = struct {
	Name      string
	Namespace string
	Main      string
	Tests     []string
}{
	Name:      "restic",                           // name of the program executable and directory
	Namespace: "",                                 // subdir of GOPATH, e.g. "github.com/foo/bar"
	Main:      "cmds/restic",                      // package name for the main package
	Tests:     []string{"restic/...", "cmds/..."}, // tests to run
}

// specialDir returns true if the file begins with a special character ('.' or '_').
func specialDir(name string) bool {
	if name == "." {
		return false
	}

	base := filepath.Base(name)
	if base == "vendor" || base[0] == '_' || base[0] == '.' {
		return true
	}

	return false
}

// excludePath returns true if the file should not be copied to the new GOPATH.
func excludePath(name string) bool {
	ext := path.Ext(name)
	if ext == ".go" || ext == ".s" {
		return false
	}

	parentDir := filepath.Base(filepath.Dir(name))
	if parentDir == "testdata" {
		return false
	}

	return true
}

// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
// to dst/prefix/, so calling
//
//   updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
//
// with "/home/u/restic" containing the file "foo.go" yields the following tree
// at "/tmp/gopath":
//
//   /tmp/gopath
//   └── src
//       └── github.com
//           └── restic
//               └── restic
//                   └── foo.go
func updateGopath(dst, src, prefix string) error {
	return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
		if specialDir(name) {
			if fi.IsDir() {
				return filepath.SkipDir
			}

			return nil
		}

		if fi.IsDir() {
			return nil
		}

		if excludePath(name) {
			return nil
		}

		intermediatePath, err := filepath.Rel(src, name)
		if err != nil {
			return err
		}

		fileSrc := filepath.Join(src, intermediatePath)
		fileDst := filepath.Join(dst, "src", prefix, intermediatePath)

		return copyFile(fileDst, fileSrc)
	})
}

func directoryExists(dirname string) bool {
	stat, err := os.Stat(dirname)
	if err != nil && os.IsNotExist(err) {
		return false
	}

	return stat.IsDir()
}

// copyFile creates dst from src, preserving file attributes and timestamps.
func copyFile(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}

	if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
		return err
	}

	fdst, err := os.Create(dst)
	if err != nil {
		return err
	}

	if _, err = io.Copy(fdst, fsrc); err != nil {
		return err
	}

	if err == nil {
		err = fsrc.Close()
	}

	if err == nil {
		err = fdst.Close()
	}

	if err == nil {
		err = os.Chmod(dst, fi.Mode())
	}

	if err == nil {
		err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
	}

	return nil
}

// die prints the message with fmt.Fprintf() to stderr and exits with an error
// code.
func die(message string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, message, args...)
	os.Exit(1)
}

func showUsage(output io.Writer) {
	fmt.Fprintf(output, "USAGE: go run build.go OPTIONS\n")
	fmt.Fprintf(output, "\n")
	fmt.Fprintf(output, "OPTIONS:\n")
	fmt.Fprintf(output, "  -v     --verbose       output more messages\n")
	fmt.Fprintf(output, "  -t     --tags          specify additional build tags\n")
	fmt.Fprintf(output, "  -k     --keep-gopath   do not remove the GOPATH after build\n")
	fmt.Fprintf(output, "  -T     --test          run tests\n")
	fmt.Fprintf(output, "  -o     --output        set output file name\n")
	fmt.Fprintf(output, "         --goos value    set GOOS for cross-compilation\n")
	fmt.Fprintf(output, "         --goarch value  set GOARCH for cross-compilation\n")
}

func verbosePrintf(message string, args ...interface{}) {
	if !verbose {
		return
	}

	fmt.Printf("build: "+message, args...)
}

// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
// present).
func cleanEnv() (env []string) {
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
			continue
		}

		env = append(env, v)
	}

	return env
}

// build runs "go build args..." with GOPATH set to gopath.
func build(cwd, goos, goarch, gopath string, args ...string) error {
	args = append([]string{"build"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath, "GOARCH="+goarch, "GOOS="+goos, "CGO_ENABLED=0")
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// test runs "go test args..." with GOPATH set to gopath.
func test(cwd, gopath string, args ...string) error {
	args = append([]string{"test"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// getVersion returns the version string from the file VERSION in the current
// directory.
func getVersionFromFile() string {
	buf, err := ioutil.ReadFile("VERSION")
	if err != nil {
		verbosePrintf("error reading file VERSION: %v\n", err)
		return ""
	}

	return strings.TrimSpace(string(buf))
}

// getVersion returns a version string which is a combination of the contents
// of the file VERSION in the current directory and the version from git (if
// available).
func getVersion() string {
	versionFile := getVersionFromFile()
	versionGit := getVersionFromGit()

	verbosePrintf("version from file 'VERSION' is %q, version from git %q\n",
		versionFile, versionGit)

	switch {
	case versionFile == "":
		return versionGit
	case versionGit == "":
		return versionFile
	}

	return fmt.Sprintf("%s (%s)", versionFile, versionGit)
}

// getVersionFromGit returns a version string that identifies the currently
// checked out git commit.
func getVersionFromGit() string {
	cmd := exec.Command("git", "describe",
		"--long", "--tags", "--dirty", "--always")
	out, err := cmd.Output()
	if err != nil {
		verbosePrintf("git describe returned error: %v\n", err)
		return ""
	}

	version := strings.TrimSpace(string(out))
	verbosePrintf("git version is %s\n", version)
	return version
}

// Constants represents a set of constants that are set in the final binary to
// the given value via compiler flags.
type Constants map[string]string

// LDFlags returns the string that can be passed to go build's `-ldflags`.
func (cs Constants) LDFlags() string {
	l := make([]string, 0, len(cs))

	for k, v := range cs {
		l = append(l, fmt.Sprintf(`-X "%s=%s"`, k, v))
	}

	return strings.Join(l, " ")
}

func main() {
	buildTags := []string{}

	skipNext := false
	params := os.Args[1:]

	targetGOOS := runtime.GOOS
	targetGOARCH := runtime.GOARCH

	var outputFilename string

	for i, arg := range params {
		if skipNext {
			skipNext = false
			continue
		}

		switch arg {
		case "-v", "--verbose":
			verbose = true
		case "-k", "--keep-gopath":
			keepGopath = true
		case "-t", "-tags", "--tags":
			if i+1 >= len(params) {
				die("-t given but no tag specified")
			}
			skipNext = true
			buildTags = strings.Split(params[i+1], " ")
		case "-o", "--output":
			skipNext = true
			outputFilename = params[i+1]
		case "-T", "--test":
			runTests = true
		case "--goos":
			skipNext = true
			targetGOOS = params[i+1]
		case "--goarch":
			skipNext = true
			targetGOARCH = params[i+1]
		case "-h":
			showUsage(os.Stdout)
			return
		default:
			fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
			showUsage(os.Stderr)
			os.Exit(1)
		}
	}

	if len(buildTags) == 0 {
		verbosePrintf("adding build-tag release\n")
		buildTags = []string{"release"}
	}

	for i := range buildTags {
		buildTags[i] = strings.TrimSpace(buildTags[i])
	}

	verbosePrintf("build tags: %s\n", buildTags)

	root, err := os.Getwd()
	if err != nil {
		die("Getwd(): %v\n", err)
	}

	gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
	if err != nil {
		die("TempDir(): %v\n", err)
	}

	verbosePrintf("create GOPATH at %v\n", gopath)
	if err = updateGopath(gopath, filepath.Join(root, "src"), config.Namespace); err != nil {
		die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
	}

	vendor := filepath.Join(root, "vendor", "src")
	if directoryExists(vendor) {
		if err = updateGopath(gopath, vendor, ""); err != nil {
			die("copying files from %v to %v failed: %v\n", root, gopath, err)
		}
	}

	defer func() {
		if !keepGopath {
			verbosePrintf("remove %v\n", gopath)
			if err = os.RemoveAll(gopath); err != nil {
				die("remove GOPATH at %s failed: %v\n", err)
			}
		} else {
			verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
		}
	}()

	if outputFilename == "" {
		outputFilename = config.Name
		if targetGOOS == "windows" {
			outputFilename += ".exe"
		}
	}

	cwd, err := os.Getwd()
	if err != nil {
		die("Getwd() returned %v\n", err)
	}
	output := filepath.Join(cwd, outputFilename)

	version := getVersion()
	constants := Constants{}
	if version != "" {
		constants["main.version"] = version
	}
	ldflags := "-s -w " + constants.LDFlags()
	verbosePrintf("ldflags: %s\n", ldflags)

	args := []string{
		"-tags", strings.Join(buildTags, " "),
		"-ldflags", ldflags,
		"-o", output, config.Main,
	}

	err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
	if err != nil {
		die("build failed: %v\n", err)
	}

	if runTests {
		verbosePrintf("running tests\n")

		err = test(cwd, gopath, config.Tests...)
		if err != nil {
			die("running tests failed: %v\n", err)
		}
	}
}
<commit_msg>Check version in build.go<commit_after>// +build ignore

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
)

var (
	verbose    bool
	keepGopath bool
	runTests   bool
)

var config = struct {
	Name      string
	Namespace string
	Main      string
	Tests     []string
}{
	Name:      "restic",                           // name of the program executable and directory
	Namespace: "",                                 // subdir of GOPATH, e.g. "github.com/foo/bar"
	Main:      "cmds/restic",                      // package name for the main package
	Tests:     []string{"restic/...", "cmds/..."}, // tests to run
}

// specialDir returns true if the file begins with a special character ('.' or '_').
func specialDir(name string) bool {
	if name == "." {
		return false
	}

	base := filepath.Base(name)
	if base == "vendor" || base[0] == '_' || base[0] == '.' {
		return true
	}

	return false
}

// excludePath returns true if the file should not be copied to the new GOPATH.
func excludePath(name string) bool {
	ext := path.Ext(name)
	if ext == ".go" || ext == ".s" {
		return false
	}

	parentDir := filepath.Base(filepath.Dir(name))
	if parentDir == "testdata" {
		return false
	}

	return true
}

// updateGopath builds a valid GOPATH at dst, with all Go files in src/ copied
// to dst/prefix/, so calling
//
//   updateGopath("/tmp/gopath", "/home/u/restic", "github.com/restic/restic")
//
// with "/home/u/restic" containing the file "foo.go" yields the following tree
// at "/tmp/gopath":
//
//   /tmp/gopath
//   └── src
//       └── github.com
//           └── restic
//               └── restic
//                   └── foo.go
func updateGopath(dst, src, prefix string) error {
	return filepath.Walk(src, func(name string, fi os.FileInfo, err error) error {
		if specialDir(name) {
			if fi.IsDir() {
				return filepath.SkipDir
			}

			return nil
		}

		if fi.IsDir() {
			return nil
		}

		if excludePath(name) {
			return nil
		}

		intermediatePath, err := filepath.Rel(src, name)
		if err != nil {
			return err
		}

		fileSrc := filepath.Join(src, intermediatePath)
		fileDst := filepath.Join(dst, "src", prefix, intermediatePath)

		return copyFile(fileDst, fileSrc)
	})
}

func directoryExists(dirname string) bool {
	stat, err := os.Stat(dirname)
	if err != nil && os.IsNotExist(err) {
		return false
	}

	return stat.IsDir()
}

// copyFile creates dst from src, preserving file attributes and timestamps.
func copyFile(dst, src string) error {
	fi, err := os.Stat(src)
	if err != nil {
		return err
	}

	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}

	if err = os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		fmt.Printf("MkdirAll(%v)\n", filepath.Dir(dst))
		return err
	}

	fdst, err := os.Create(dst)
	if err != nil {
		return err
	}

	if _, err = io.Copy(fdst, fsrc); err != nil {
		return err
	}

	if err == nil {
		err = fsrc.Close()
	}

	if err == nil {
		err = fdst.Close()
	}

	if err == nil {
		err = os.Chmod(dst, fi.Mode())
	}

	if err == nil {
		err = os.Chtimes(dst, fi.ModTime(), fi.ModTime())
	}

	return nil
}

// die prints the message with fmt.Fprintf() to stderr and exits with an error
// code.
func die(message string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, message, args...)
	os.Exit(1)
}

func showUsage(output io.Writer) {
	fmt.Fprintf(output, "USAGE: go run build.go OPTIONS\n")
	fmt.Fprintf(output, "\n")
	fmt.Fprintf(output, "OPTIONS:\n")
	fmt.Fprintf(output, "  -v     --verbose       output more messages\n")
	fmt.Fprintf(output, "  -t     --tags          specify additional build tags\n")
	fmt.Fprintf(output, "  -k     --keep-gopath   do not remove the GOPATH after build\n")
	fmt.Fprintf(output, "  -T     --test          run tests\n")
	fmt.Fprintf(output, "  -o     --output        set output file name\n")
	fmt.Fprintf(output, "         --goos value    set GOOS for cross-compilation\n")
	fmt.Fprintf(output, "         --goarch value  set GOARCH for cross-compilation\n")
}

func verbosePrintf(message string, args ...interface{}) {
	if !verbose {
		return
	}

	fmt.Printf("build: "+message, args...)
}

// cleanEnv returns a clean environment with GOPATH and GOBIN removed (if
// present).
func cleanEnv() (env []string) {
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOPATH=") || strings.HasPrefix(v, "GOBIN=") {
			continue
		}

		env = append(env, v)
	}

	return env
}

// build runs "go build args..." with GOPATH set to gopath.
func build(cwd, goos, goarch, gopath string, args ...string) error {
	args = append([]string{"build"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath, "GOARCH="+goarch, "GOOS="+goos, "CGO_ENABLED=0")
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// test runs "go test args..." with GOPATH set to gopath.
func test(cwd, gopath string, args ...string) error {
	args = append([]string{"test"}, args...)
	cmd := exec.Command("go", args...)
	cmd.Env = append(cleanEnv(), "GOPATH="+gopath)
	cmd.Dir = cwd
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	verbosePrintf("go %s\n", args)

	return cmd.Run()
}

// getVersion returns the version string from the file VERSION in the current
// directory.
func getVersionFromFile() string {
	buf, err := ioutil.ReadFile("VERSION")
	if err != nil {
		verbosePrintf("error reading file VERSION: %v\n", err)
		return ""
	}

	return strings.TrimSpace(string(buf))
}

// getVersion returns a version string which is a combination of the contents
// of the file VERSION in the current directory and the version from git (if
// available).
func getVersion() string {
	versionFile := getVersionFromFile()
	versionGit := getVersionFromGit()

	verbosePrintf("version from file 'VERSION' is %q, version from git %q\n",
		versionFile, versionGit)

	switch {
	case versionFile == "":
		return versionGit
	case versionGit == "":
		return versionFile
	}

	return fmt.Sprintf("%s (%s)", versionFile, versionGit)
}

// getVersionFromGit returns a version string that identifies the currently
// checked out git commit.
func getVersionFromGit() string {
	cmd := exec.Command("git", "describe",
		"--long", "--tags", "--dirty", "--always")
	out, err := cmd.Output()
	if err != nil {
		verbosePrintf("git describe returned error: %v\n", err)
		return ""
	}

	version := strings.TrimSpace(string(out))
	verbosePrintf("git version is %s\n", version)
	return version
}

// Constants represents a set of constants that are set in the final binary to
// the given value via compiler flags.
type Constants map[string]string

// LDFlags returns the string that can be passed to go build's `-ldflags`.
func (cs Constants) LDFlags() string {
	l := make([]string, 0, len(cs))

	for k, v := range cs {
		l = append(l, fmt.Sprintf(`-X "%s=%s"`, k, v))
	}

	return strings.Join(l, " ")
}

func main() {
	ver := runtime.Version()
	if strings.HasPrefix(ver, "go1") && ver < "go1.7" {
		fmt.Fprintf(os.Stderr, "Go version %s detected, restic requires at least Go 1.7\n", ver)
		os.Exit(1)
	}

	buildTags := []string{}

	skipNext := false
	params := os.Args[1:]

	targetGOOS := runtime.GOOS
	targetGOARCH := runtime.GOARCH

	var outputFilename string

	for i, arg := range params {
		if skipNext {
			skipNext = false
			continue
		}

		switch arg {
		case "-v", "--verbose":
			verbose = true
		case "-k", "--keep-gopath":
			keepGopath = true
		case "-t", "-tags", "--tags":
			if i+1 >= len(params) {
				die("-t given but no tag specified")
			}
			skipNext = true
			buildTags = strings.Split(params[i+1], " ")
		case "-o", "--output":
			skipNext = true
			outputFilename = params[i+1]
		case "-T", "--test":
			runTests = true
		case "--goos":
			skipNext = true
			targetGOOS = params[i+1]
		case "--goarch":
			skipNext = true
			targetGOARCH = params[i+1]
		case "-h":
			showUsage(os.Stdout)
			return
		default:
			fmt.Fprintf(os.Stderr, "Error: unknown option %q\n\n", arg)
			showUsage(os.Stderr)
			os.Exit(1)
		}
	}

	if len(buildTags) == 0 {
		verbosePrintf("adding build-tag release\n")
		buildTags = []string{"release"}
	}

	for i := range buildTags {
		buildTags[i] = strings.TrimSpace(buildTags[i])
	}

	verbosePrintf("build tags: %s\n", buildTags)

	root, err := os.Getwd()
	if err != nil {
		die("Getwd(): %v\n", err)
	}

	gopath, err := ioutil.TempDir("", fmt.Sprintf("%v-build-", config.Name))
	if err != nil {
		die("TempDir(): %v\n", err)
	}

	verbosePrintf("create GOPATH at %v\n", gopath)
	if err = updateGopath(gopath, filepath.Join(root, "src"), config.Namespace); err != nil {
		die("copying files from %v/src to %v/src failed: %v\n", root, gopath, err)
	}

	vendor := filepath.Join(root, "vendor", "src")
	if directoryExists(vendor) {
		if err = updateGopath(gopath, vendor, ""); err != nil {
			die("copying files from %v to %v failed: %v\n", root, gopath, err)
		}
	}

	defer func() {
		if !keepGopath {
			verbosePrintf("remove %v\n", gopath)
			if err = os.RemoveAll(gopath); err != nil {
				die("remove GOPATH at %s failed: %v\n", err)
			}
		} else {
			verbosePrintf("leaving temporary GOPATH at %v\n", gopath)
		}
	}()

	if outputFilename == "" {
		outputFilename = config.Name
		if targetGOOS == "windows" {
			outputFilename += ".exe"
		}
	}

	cwd, err := os.Getwd()
	if err != nil {
		die("Getwd() returned %v\n", err)
	}
	output := filepath.Join(cwd, outputFilename)

	version := getVersion()
	constants := Constants{}
	if version != "" {
		constants["main.version"] = version
	}
	ldflags := "-s -w " + constants.LDFlags()
	verbosePrintf("ldflags: %s\n", ldflags)

	args := []string{
		"-tags", strings.Join(buildTags, " "),
		"-ldflags", ldflags,
		"-o", output, config.Main,
	}

	err = build(filepath.Join(gopath, "src"), targetGOOS, targetGOARCH, gopath, args...)
	if err != nil {
		die("build failed: %v\n", err)
	}

	if runTests {
		verbosePrintf("running tests\n")

		err = test(cwd, gopath, config.Tests...)
		if err != nil {
			die("running tests failed: %v\n", err)
		}
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"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/errwrap"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpcPeeringConnection() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVPCPeeringCreate,
		Read:   resourceAwsVPCPeeringRead,
		Update: resourceAwsVPCPeeringUpdate,
		Delete: resourceAwsVPCPeeringDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"peer_owner_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},
			"peer_vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"auto_accept": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},
			"accept_status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"accepter":  vpcPeeringConnectionOptionsSchema(),
			"requester": vpcPeeringConnectionOptionsSchema(),
			"tags":      tagsSchema(),
		},
	}
}

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

	// Create the vpc peering connection
	createOpts := &ec2.CreateVpcPeeringConnectionInput{
		PeerVpcId: aws.String(d.Get("peer_vpc_id").(string)),
		VpcId:     aws.String(d.Get("vpc_id").(string)),
	}

	if v, ok := d.GetOk("peer_owner_id"); ok {
		createOpts.PeerOwnerId = aws.String(v.(string))
	}

	log.Printf("[DEBUG] VPC Peering Create options: %#v", createOpts)

	resp, err := conn.CreateVpcPeeringConnection(createOpts)
	if err != nil {
		return errwrap.Wrapf("Error creating VPC Peering Connection: {{err}}", err)
	}

	// Get the ID and store it
	rt := resp.VpcPeeringConnection
	d.SetId(*rt.VpcPeeringConnectionId)
	log.Printf("[INFO] VPC Peering Connection ID: %s", d.Id())

	// Wait for the vpc peering connection to become available
	log.Printf("[DEBUG] Waiting for VPC Peering Connection (%s) to become available.", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  []string{"pending-acceptance"},
		Refresh: resourceAwsVPCPeeringConnectionStateRefreshFunc(conn, d.Id()),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for VPC Peering Connection (%s) to become available: %s",
			d.Id(), err)
	}

	return resourceAwsVPCPeeringUpdate(d, meta)
}

func resourceAwsVPCPeeringRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	pcRaw, _, err := resourceAwsVPCPeeringConnectionStateRefreshFunc(conn, d.Id())()
	if err != nil {
		return err
	}

	if pcRaw == nil {
		d.SetId("")
		return nil
	}

	pc := pcRaw.(*ec2.VpcPeeringConnection)

	// The failed status is a status that we can assume just means the
	// connection is gone. Destruction isn't allowed, and it eventually
	// just "falls off" the console. See GH-2322
	if pc.Status != nil {
		status := map[string]bool{
			"deleted":  true,
			"deleting": true,
			"expired":  true,
			"failed":   true,
			"rejected": true,
		}
		if _, ok := status[*pc.Status.Code]; ok {
			log.Printf("[DEBUG] VPC Peering Connection (%s) in state (%s), removing.",
				d.Id(), *pc.Status.Code)
			d.SetId("")
			return nil
		}
	}
	log.Printf("[DEBUG] VPC Peering Connection response: %#v", pc)

	d.Set("accept_status", pc.Status.Code)
	d.Set("peer_owner_id", pc.AccepterVpcInfo.OwnerId)
	d.Set("peer_vpc_id", pc.AccepterVpcInfo.VpcId)
	d.Set("vpc_id", pc.RequesterVpcInfo.VpcId)

	// When the VPC Peering Connection is pending acceptance,
	// the details about accepter and/or requester peering
	// options would not be included in the response.
	if pc.AccepterVpcInfo != nil && pc.AccepterVpcInfo.PeeringOptions != nil {
		err := d.Set("accepter", flattenPeeringOptions(pc.AccepterVpcInfo.PeeringOptions))
		if err != nil {
			log.Printf("[ERR] Error setting VPC Peering connection accepter information: %s", err)
		}
	}

	if pc.RequesterVpcInfo != nil && pc.RequesterVpcInfo.PeeringOptions != nil {
		err := d.Set("requester", flattenPeeringOptions(pc.RequesterVpcInfo.PeeringOptions))
		if err != nil {
			log.Printf("[ERR] Error setting VPC Peering connection requester information: %s", err)
		}
	}

	err = d.Set("tags", tagsToMap(pc.Tags))
	if err != nil {
		return err
	}

	return nil
}

func resourceVPCPeeringConnectionAccept(conn *ec2.EC2, id string) (string, error) {
	log.Printf("[INFO] Accept VPC Peering Connection with ID: %s", id)

	req := &ec2.AcceptVpcPeeringConnectionInput{
		VpcPeeringConnectionId: aws.String(id),
	}

	resp, err := conn.AcceptVpcPeeringConnection(req)
	if err != nil {
		return "", err
	}
	pc := resp.VpcPeeringConnection

	return *pc.Status.Code, nil
}

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

	modifyOpts := &ec2.ModifyVpcPeeringConnectionOptionsInput{
		VpcPeeringConnectionId: aws.String(d.Id()),
	}

	if v, ok := d.GetOk("accepter"); ok {
		if s := v.(*schema.Set); len(s.List()) > 0 {
			co := s.List()[0].(map[string]interface{})
			modifyOpts.AccepterPeeringConnectionOptions = expandPeeringOptions(co)
		}
	}

	if v, ok := d.GetOk("requester"); ok {
		if s := v.(*schema.Set); len(s.List()) > 0 {
			co := s.List()[0].(map[string]interface{})
			modifyOpts.RequesterPeeringConnectionOptions = expandPeeringOptions(co)
		}
	}

	log.Printf("[DEBUG] VPC Peering Connection modify options: %#v", modifyOpts)
	if _, err := conn.ModifyVpcPeeringConnectionOptions(modifyOpts); err != nil {
		return err
	}

	return nil
}

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

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

	pcRaw, _, err := resourceAwsVPCPeeringConnectionStateRefreshFunc(conn, d.Id())()
	if err != nil {
		return err
	}
	if pcRaw == nil {
		d.SetId("")
		return nil
	}
	pc := pcRaw.(*ec2.VpcPeeringConnection)

	if _, ok := d.GetOk("auto_accept"); ok {
		if pc.Status != nil && *pc.Status.Code == "pending-acceptance" {
			status, err := resourceVPCPeeringConnectionAccept(conn, d.Id())
			if err != nil {
				return err
			}
			log.Printf("[DEBUG] VPC Peering Connection accept status: %s", status)
		}
	}

	if d.HasChange("accepter") || d.HasChange("requester") {
		_, ok := d.GetOk("auto_accept")
		if !ok && pc.Status != nil && *pc.Status.Code != "active" {
			return fmt.Errorf("Unable to modify peering options. The VPC Peering Connection "+
				"%q is not active. Please set `auto_accept` attribute to `true`, "+
				"or activate VPC Peering Connection manually.", d.Id())
		}

		if err := resourceVPCPeeringConnectionOptionsModify(d, meta); err != nil {
			return errwrap.Wrapf("Error modifying VPC Peering Connection options: {{err}}", err)
		}
	}

	return resourceAwsVPCPeeringRead(d, meta)
}

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

	_, err := conn.DeleteVpcPeeringConnection(
		&ec2.DeleteVpcPeeringConnectionInput{
			VpcPeeringConnectionId: aws.String(d.Id()),
		})

	return err
}

// resourceAwsVPCPeeringConnectionStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VPCPeeringConnection.
func resourceAwsVPCPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {

		resp, err := conn.DescribeVpcPeeringConnections(&ec2.DescribeVpcPeeringConnectionsInput{
			VpcPeeringConnectionIds: []*string{aws.String(id)},
		})
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcPeeringConnectionID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error reading VPC Peering Connection details: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		pc := resp.VpcPeeringConnections[0]

		return pc, *pc.Status.Code, nil
	}
}

func vpcPeeringConnectionOptionsSchema() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeSet,
		Optional: true,
		Computed: true,
		MaxItems: 1,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"allow_remote_vpc_dns_resolution": &schema.Schema{
					Type:     schema.TypeBool,
					Optional: true,
					Default:  false,
				},
				"allow_classic_link_to_remote_vpc": &schema.Schema{
					Type:     schema.TypeBool,
					Optional: true,
					Default:  false,
				},
				"allow_vpc_to_remote_classic_link": &schema.Schema{
					Type:     schema.TypeBool,
					Optional: true,
					Default:  false,
				},
			},
		},
	}
}

func flattenPeeringOptions(options *ec2.VpcPeeringConnectionOptionsDescription) (results []map[string]interface{}) {
	m := make(map[string]interface{})

	if options.AllowDnsResolutionFromRemoteVpc != nil {
		m["allow_remote_vpc_dns_resolution"] = *options.AllowDnsResolutionFromRemoteVpc
	}

	if options.AllowEgressFromLocalClassicLinkToRemoteVpc != nil {
		m["allow_classic_link_to_remote_vpc"] = *options.AllowEgressFromLocalClassicLinkToRemoteVpc
	}

	if options.AllowEgressFromLocalVpcToRemoteClassicLink != nil {
		m["allow_vpc_to_remote_classic_link"] = *options.AllowEgressFromLocalVpcToRemoteClassicLink
	}

	results = append(results, m)
	return
}

func expandPeeringOptions(m map[string]interface{}) *ec2.PeeringConnectionOptionsRequest {
	r := &ec2.PeeringConnectionOptionsRequest{}

	if v, ok := m["allow_remote_vpc_dns_resolution"]; ok {
		r.AllowDnsResolutionFromRemoteVpc = aws.Bool(v.(bool))
	}

	if v, ok := m["allow_classic_link_to_remote_vpc"]; ok {
		r.AllowEgressFromLocalClassicLinkToRemoteVpc = aws.Bool(v.(bool))
	}

	if v, ok := m["allow_vpc_to_remote_classic_link"]; ok {
		r.AllowEgressFromLocalVpcToRemoteClassicLink = aws.Bool(v.(bool))
	}

	return r
}
<commit_msg>Make sure that VPC Peering Connection in a failed state returns an error.<commit_after>package aws

import (
	"errors"
	"fmt"
	"log"
	"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/errwrap"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpcPeeringConnection() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVPCPeeringCreate,
		Read:   resourceAwsVPCPeeringRead,
		Update: resourceAwsVPCPeeringUpdate,
		Delete: resourceAwsVPCPeeringDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"peer_owner_id": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},
			"peer_vpc_id": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"vpc_id": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"auto_accept": {
				Type:     schema.TypeBool,
				Optional: true,
			},
			"accept_status": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"accepter":  vpcPeeringConnectionOptionsSchema(),
			"requester": vpcPeeringConnectionOptionsSchema(),
			"tags":      tagsSchema(),
		},
	}
}

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

	// Create the vpc peering connection
	createOpts := &ec2.CreateVpcPeeringConnectionInput{
		PeerVpcId: aws.String(d.Get("peer_vpc_id").(string)),
		VpcId:     aws.String(d.Get("vpc_id").(string)),
	}

	if v, ok := d.GetOk("peer_owner_id"); ok {
		createOpts.PeerOwnerId = aws.String(v.(string))
	}

	log.Printf("[DEBUG] VPC Peering Create options: %#v", createOpts)

	resp, err := conn.CreateVpcPeeringConnection(createOpts)
	if err != nil {
		return errwrap.Wrapf("Error creating VPC Peering Connection: {{err}}", err)
	}

	// Get the ID and store it
	rt := resp.VpcPeeringConnection
	d.SetId(*rt.VpcPeeringConnectionId)
	log.Printf("[INFO] VPC Peering Connection ID: %s", d.Id())

	// Wait for the vpc peering connection to become available
	log.Printf("[DEBUG] Waiting for VPC Peering Connection (%s) to become available.", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  []string{"pending-acceptance"},
		Refresh: resourceAwsVPCPeeringConnectionStateRefreshFunc(conn, d.Id()),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return errwrap.Wrapf(fmt.Sprintf(
			"Error waiting for VPC Peering Connection (%s) to become available: {{err}}",
			d.Id()), err)
	}

	return resourceAwsVPCPeeringUpdate(d, meta)
}

func resourceAwsVPCPeeringRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	pcRaw, status, err := resourceAwsVPCPeeringConnectionStateRefreshFunc(conn, d.Id())()
	// Allow a failed VPC Peering Connection to fallthrough,
	// to allow rest of the logic below to do its work.
	if err != nil && status != "failed" {
		return err
	}

	if pcRaw == nil {
		d.SetId("")
		return nil
	}

	pc := pcRaw.(*ec2.VpcPeeringConnection)

	// The failed status is a status that we can assume just means the
	// connection is gone. Destruction isn't allowed, and it eventually
	// just "falls off" the console. See GH-2322
	if pc.Status != nil {
		status := map[string]bool{
			"deleted":  true,
			"deleting": true,
			"expired":  true,
			"failed":   true,
			"rejected": true,
		}
		if _, ok := status[*pc.Status.Code]; ok {
			log.Printf("[DEBUG] VPC Peering Connection (%s) in state (%s), removing.",
				d.Id(), *pc.Status.Code)
			d.SetId("")
			return nil
		}
	}
	log.Printf("[DEBUG] VPC Peering Connection response: %#v", pc)

	d.Set("accept_status", pc.Status.Code)
	d.Set("peer_owner_id", pc.AccepterVpcInfo.OwnerId)
	d.Set("peer_vpc_id", pc.AccepterVpcInfo.VpcId)
	d.Set("vpc_id", pc.RequesterVpcInfo.VpcId)

	// When the VPC Peering Connection is pending acceptance,
	// the details about accepter and/or requester peering
	// options would not be included in the response.
	if pc.AccepterVpcInfo.PeeringOptions != nil {
		err := d.Set("accepter", flattenPeeringOptions(pc.AccepterVpcInfo.PeeringOptions))
		if err != nil {
			return errwrap.Wrapf("Error setting VPC Peering Connection accepter information: {{err}}", err)
		}
	}

	if pc.RequesterVpcInfo.PeeringOptions != nil {
		err := d.Set("requester", flattenPeeringOptions(pc.RequesterVpcInfo.PeeringOptions))
		if err != nil {
			return errwrap.Wrapf("Error setting VPC Peering Connection requester information: {{err}}", err)
		}
	}

	err = d.Set("tags", tagsToMap(pc.Tags))
	if err != nil {
		return errwrap.Wrapf("Error setting VPC Peering Connection tags: {{err}}", err)
	}

	return nil
}

func resourceVPCPeeringConnectionAccept(conn *ec2.EC2, id string) (string, error) {
	log.Printf("[INFO] Accept VPC Peering Connection with ID: %s", id)

	req := &ec2.AcceptVpcPeeringConnectionInput{
		VpcPeeringConnectionId: aws.String(id),
	}

	resp, err := conn.AcceptVpcPeeringConnection(req)
	if err != nil {
		return "", err
	}
	pc := resp.VpcPeeringConnection

	return *pc.Status.Code, nil
}

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

	modifyOpts := &ec2.ModifyVpcPeeringConnectionOptionsInput{
		VpcPeeringConnectionId: aws.String(d.Id()),
	}

	if v, ok := d.GetOk("accepter"); ok {
		if s := v.(*schema.Set); len(s.List()) > 0 {
			co := s.List()[0].(map[string]interface{})
			modifyOpts.AccepterPeeringConnectionOptions = expandPeeringOptions(co)
		}
	}

	if v, ok := d.GetOk("requester"); ok {
		if s := v.(*schema.Set); len(s.List()) > 0 {
			co := s.List()[0].(map[string]interface{})
			modifyOpts.RequesterPeeringConnectionOptions = expandPeeringOptions(co)
		}
	}

	log.Printf("[DEBUG] VPC Peering Connection modify options: %#v", modifyOpts)
	if _, err := conn.ModifyVpcPeeringConnectionOptions(modifyOpts); err != nil {
		return err
	}

	return nil
}

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

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

	pcRaw, _, err := resourceAwsVPCPeeringConnectionStateRefreshFunc(conn, d.Id())()
	if err != nil {
		return err
	}

	if pcRaw == nil {
		d.SetId("")
		return nil
	}
	pc := pcRaw.(*ec2.VpcPeeringConnection)

	if _, ok := d.GetOk("auto_accept"); ok {
		if pc.Status != nil && *pc.Status.Code == "pending-acceptance" {
			status, err := resourceVPCPeeringConnectionAccept(conn, d.Id())
			if err != nil {
				return errwrap.Wrapf("Unable to accept VPC Peering Connection: {{err}}", err)
			}
			log.Printf("[DEBUG] VPC Peering Connection accept status: %s", status)
		}
	}

	if d.HasChange("accepter") || d.HasChange("requester") {
		_, ok := d.GetOk("auto_accept")
		if !ok && pc.Status != nil && *pc.Status.Code != "active" {
			return fmt.Errorf("Unable to modify peering options. The VPC Peering Connection "+
				"%q is not active. Please set `auto_accept` attribute to `true`, "+
				"or activate VPC Peering Connection manually.", d.Id())
		}

		if err := resourceVPCPeeringConnectionOptionsModify(d, meta); err != nil {
			return errwrap.Wrapf("Error modifying VPC Peering Connection options: {{err}}", err)
		}
	}

	return resourceAwsVPCPeeringRead(d, meta)
}

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

	_, err := conn.DeleteVpcPeeringConnection(
		&ec2.DeleteVpcPeeringConnectionInput{
			VpcPeeringConnectionId: aws.String(d.Id()),
		})

	return err
}

// resourceAwsVPCPeeringConnectionStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// a VPCPeeringConnection.
func resourceAwsVPCPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeVpcPeeringConnections(&ec2.DescribeVpcPeeringConnectionsInput{
			VpcPeeringConnectionIds: []*string{aws.String(id)},
		})
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcPeeringConnectionID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error reading VPC Peering Connection details: %s", err)
				return nil, "error", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		pc := resp.VpcPeeringConnections[0]

		// A VPC Peering Connection can exist in a failed state due to
		// incorrect VPC ID, account ID, or overlapping IP address range,
		// thus we short circuit before the time out would occur.
		if pc != nil && *pc.Status.Code == "failed" {
			return nil, "failed", errors.New(*pc.Status.Message)
		}

		return pc, *pc.Status.Code, nil
	}
}

func vpcPeeringConnectionOptionsSchema() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeSet,
		Optional: true,
		Computed: true,
		MaxItems: 1,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"allow_remote_vpc_dns_resolution": {
					Type:     schema.TypeBool,
					Optional: true,
					Default:  false,
				},
				"allow_classic_link_to_remote_vpc": {
					Type:     schema.TypeBool,
					Optional: true,
					Default:  false,
				},
				"allow_vpc_to_remote_classic_link": {
					Type:     schema.TypeBool,
					Optional: true,
					Default:  false,
				},
			},
		},
	}
}

func flattenPeeringOptions(options *ec2.VpcPeeringConnectionOptionsDescription) (results []map[string]interface{}) {
	m := make(map[string]interface{})

	if options.AllowDnsResolutionFromRemoteVpc != nil {
		m["allow_remote_vpc_dns_resolution"] = *options.AllowDnsResolutionFromRemoteVpc
	}

	if options.AllowEgressFromLocalClassicLinkToRemoteVpc != nil {
		m["allow_classic_link_to_remote_vpc"] = *options.AllowEgressFromLocalClassicLinkToRemoteVpc
	}

	if options.AllowEgressFromLocalVpcToRemoteClassicLink != nil {
		m["allow_vpc_to_remote_classic_link"] = *options.AllowEgressFromLocalVpcToRemoteClassicLink
	}

	results = append(results, m)
	return
}

func expandPeeringOptions(m map[string]interface{}) *ec2.PeeringConnectionOptionsRequest {
	r := &ec2.PeeringConnectionOptionsRequest{}

	if v, ok := m["allow_remote_vpc_dns_resolution"]; ok {
		r.AllowDnsResolutionFromRemoteVpc = aws.Bool(v.(bool))
	}

	if v, ok := m["allow_classic_link_to_remote_vpc"]; ok {
		r.AllowEgressFromLocalClassicLinkToRemoteVpc = aws.Bool(v.(bool))
	}

	if v, ok := m["allow_vpc_to_remote_classic_link"]; ok {
		r.AllowEgressFromLocalVpcToRemoteClassicLink = aws.Bool(v.(bool))
	}

	return r
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/dynport/gocli"
	"github.com/dynport/gocloud/aws/ec2"
	"sort"
	"strings"
	"time"
)

const (
	CLI_INSTANCE_TYPE  = "--instance-type"
	CLI_SSH_KEY        = "--ssh-key"
	CLI_SECURITY_GROUP = "--security-group"
	CLI_CANONICAL      = "--canonical"
	CLI_SELF           = "--self"
	CLI_UBUNTU         = "--ubuntu"
	CLI_UBUNTU_RARING  = "--raring"
	CLI_UBUNTU_SAUCY   = "--saucy"

	USAGE_IMAGE_ID            = "IMAGE"
	USAGE_KEY_NAME            = "KEY_NAME"
	USAGE_IMAGE_TYPE          = "IMAGE_TYPE"
	USAGE_TERMINATE_INSTANCES = "INSTANCE [INSTANCE [...]]"
	USAGE_CREATE_TAGS         = "RESOURCE KEY VALUE"

	USAGE_RUN_INSTANCE = "IMAGE"
)

var ec2Client = ec2.NewFromEnv()

func init() {
	router.Register("aws/ec2/instances/describe", &gocli.Action{
		Handler: ec2DescribeInstances, Description: "Describe ec2 instances",
	})

	args := gocli.NewArgs(nil)
	args.RegisterString(CLI_INSTANCE_TYPE, "instance_type", false, "c1.medium", "Instance Type")
	args.RegisterString(CLI_SSH_KEY, "ssh_key", true, "", "SSH Key")
	args.RegisterString(CLI_SECURITY_GROUP, "security_group", true, "", "Security Group")

	router.Register("aws/ec2/instances/run", &gocli.Action{
		Handler: ec2RunInstances, Description: "Run ec2 instances", Args: args,
	})

	router.Register("aws/ec2/images/create", &gocli.Action{
		Handler: ec2CreateImage, Description: "Create image from instance",
	})

	router.Register("aws/ec2/instances/terminate", &gocli.Action{
		Handler: ec2TerminateInstances, Description: "Terminate ec2 instances", Usage: USAGE_TERMINATE_INSTANCES,
	})

	router.Register("aws/ec2/tags/create", &gocli.Action{
		Handler: ec2CreateTags, Description: "Create Tags", Usage: USAGE_CREATE_TAGS,
	})

	router.Register("aws/ec2/tags/describe", &gocli.Action{Handler: ec2DescribeTags, Description: "Describe Tags"})

	args = gocli.NewArgs(nil)
	args.RegisterBool(CLI_CANONICAL, "canonical", false, false, "Filter canonical images")
	args.RegisterBool(CLI_SELF, "self", false, false, "Filter own images")
	args.RegisterBool(CLI_UBUNTU, "ubuntu", false, false, "Filter ubuntu images")
	args.RegisterBool(CLI_UBUNTU_RARING, "raring", false, false, "Filter ubuntu raring images")
	args.RegisterBool(CLI_UBUNTU_SAUCY, "saucy", false, false, "Filter ubuntu saucy images")

	router.Register("aws/ec2/images/describe", &gocli.Action{
		Handler: ec2DescribeImages, Description: "Describe ec2 images", Args: args,
	})

	router.Register("aws/ec2/key-pairs/describe", &gocli.Action{
		Handler: ec2DescribeKeyPairs, Description: "Describe key pairs",
	})

	router.Register("aws/ec2/addresses/describe", &gocli.Action{
		Handler: ec2DescribeAddresses, Description: "Describe Addresses",
	})

	router.Register("aws/ec2/security-groups/describe", &gocli.Action{
		Handler: ec2DescribeSecurityGroups, Description: "Describe Security Groups",
	})

	router.Register("aws/ec2/spot-price-history/describe", &gocli.Action{
		Handler: ec2DescribeSpotPriceHistory, Description: "Describe Spot Price History",
	})
}

func ec2DescribeSpotPriceHistory(args *gocli.Args) error {
	filter := &ec2.SpotPriceFilter{
		InstanceTypes:       []string{"c1.medium"},
		ProductDescriptions: []string{ec2.DESC_LINUX_UNIX},
		StartTime:           time.Now().Add(-7 * 24 * time.Hour),
	}
	prices, e := ec2Client.DescribeSpotPriceHistory(filter)
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, price := range prices {
		table.Add(price.InstanceType, price.ProductDescription, price.SpotPrice, price.Timestamp, price.AvailabilityZone)
	}
	fmt.Println(table)

	return nil
}

func ec2DescribeSecurityGroups(args *gocli.Args) error {
	groups, e := ec2Client.DescribeSecurityGroups()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, group := range groups {
		table.Add(group.GroupId, "", "", group.GroupName)
		for _, perm := range group.IpPermissions {
			ports := ""
			if perm.FromPort > 0 {
				if perm.FromPort == perm.ToPort {
					ports += fmt.Sprintf("%d", perm.FromPort)
				} else {
					ports += fmt.Sprintf("%d-%d", perm.FromPort, perm.ToPort)
				}
			}
			groups := []string{}
			for _, group := range perm.Groups {
				groups = append(groups, group.GroupId)
			}
			if len(groups) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(groups, ","))
			}

			if len(perm.IpRanges) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(perm.IpRanges, ","))
			}
		}
	}
	fmt.Print(table)
	return nil

}

func ec2DescribeAddresses(args *gocli.Args) error {
	addresses, e := ec2Client.DescribeAddresses()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, address := range addresses {
		table.Add(address.PublicIp, address.PrivateIpAddress, address.Domain, address.InstanceId)
	}
	fmt.Print(table)
	return nil
}

func ec2DescribeKeyPairs(args *gocli.Args) error {
	pairs, e := ec2Client.DescribeKeyPairs()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, pair := range pairs {
		table.Add(pair.KeyName, pair.KeyFingerprint)
	}
	fmt.Print(table)
	return nil
}

const USAGE_CREATE_IMAGE = "INSTANCE"

func ec2CreateImage(args *gocli.Args) error {
	if len(args.Args) != 0 {
		return fmt.Errorf(USAGE_CREATE_IMAGE)
	}
	instanceId := args.Args[0]
	logger.Infof("creating image of instance %s", instanceId)
	return nil
}

func ec2RunInstances(args *gocli.Args) error {
	if len(args.Args) == 0 {
		return fmt.Errorf(USAGE_IMAGE_ID)
	}
	imageId := args.Args[0]
	imageType := args.MustGetString(CLI_INSTANCE_TYPE)
	keyName := args.MustGetString(CLI_SSH_KEY)
	securityGroup := args.MustGetString(CLI_SECURITY_GROUP)

	config := &ec2.RunInstancesConfig{
		ImageId:        imageId,
		KeyName:        keyName,
		InstanceType:   imageType,
		SecurityGroups: []string{securityGroup},
	}
	_, e := ec2Client.RunInstances(config)
	return e
}

func ec2TerminateInstances(args *gocli.Args) error {
	if len(args.Args) < 1 {
		return fmt.Errorf(USAGE_TERMINATE_INSTANCES)
	}
	return ec2Client.TerminateInstances(args.Args)
}

func ec2CreateTags(args *gocli.Args) error {
	if len(args.Args) != 3 {
		return fmt.Errorf(USAGE_CREATE_TAGS)
	}
	resourceId := args.Args[0]
	tags := map[string]string{
		args.Args[1]: args.Args[2],
	}
	return ec2Client.CreateTags([]string{resourceId}, tags)
}

func ec2DescribeTags(args *gocli.Args) error {
	if len(args.Args) < 0 {
		return fmt.Errorf("instance...")
	}
	tags, e := ec2Client.DescribeTags()
	if e != nil {
		return e
	}
	sort.Sort(tags)
	table := gocli.NewTable()
	for _, tag := range tags {
		table.Add(tag.ResourceType, tag.ResourceId, tag.Key, tag.Value)
	}
	fmt.Println(table)
	return nil
}

func ec2DescribeInstances(args *gocli.Args) error {
	logger.Info("describing ec2 instances")
	instances, e := ec2Client.DescribeInstances()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	table.Add("id", "image", "name", "key", "state", "type", "private_ip", "ip", "launched", "groups")
	for _, i := range instances {
		sgs := []string{}
		for _, g := range i.SecurityGroups {
			sgs = append(sgs, g.GroupId)
		}
		table.Add(
			i.InstanceId,
			i.ImageId,
			i.Name(),
			i.KeyName,
			i.InstanceStateName,
			i.InstanceType,
			i.PrivateIpAddress,
			i.IpAddress,
			i.LaunchTime.Format("2006-01-02T15:04:05"),
			strings.Join(sgs, ","),
		)
	}
	fmt.Println(table)

	return nil
}

func ec2DescribeImages(args *gocli.Args) error {
	logger.Info("describing images")
	filter := &ec2.ImageFilter{}
	if args.GetBool(CLI_CANONICAL) {
		filter.Owner = ec2.CANONICAL_OWNER_ID
	} else if args.GetBool(CLI_SELF) {
		filter.Owner = ec2.SELF_OWNER_ID
	}

	if args.GetBool(CLI_UBUNTU) {
		filter.Name = ec2.UBUNTU_PREFIX
	} else if args.GetBool(CLI_UBUNTU_RARING) {
		filter.Name = ec2.UBUNTU_RARING_PREFIX
	} else if args.GetBool(CLI_UBUNTU_SAUCY) {
		filter.Name = ec2.UBUNTU_SAUCY_PREFIX
	}

	images, e := ec2Client.DescribeImagesWithFilter(filter)
	if e != nil {
		return e
	}
	sort.Sort(images)
	table := gocli.NewTable()
	for _, image := range images {
		table.Add(image.ImageId, image.Name, image.ImageState)
	}
	fmt.Println(table)
	return nil
}
<commit_msg>no longer required AWS credentials set for all actions<commit_after>package main

import (
	"fmt"
	"github.com/dynport/gocli"
	"github.com/dynport/gocloud/aws/ec2"
	"sort"
	"strings"
	"time"
)

const (
	CLI_INSTANCE_TYPE  = "--instance-type"
	CLI_SSH_KEY        = "--ssh-key"
	CLI_SECURITY_GROUP = "--security-group"
	CLI_CANONICAL      = "--canonical"
	CLI_SELF           = "--self"
	CLI_UBUNTU         = "--ubuntu"
	CLI_UBUNTU_RARING  = "--raring"
	CLI_UBUNTU_SAUCY   = "--saucy"

	USAGE_IMAGE_ID            = "IMAGE"
	USAGE_KEY_NAME            = "KEY_NAME"
	USAGE_IMAGE_TYPE          = "IMAGE_TYPE"
	USAGE_TERMINATE_INSTANCES = "INSTANCE [INSTANCE [...]]"
	USAGE_CREATE_TAGS         = "RESOURCE KEY VALUE"

	USAGE_RUN_INSTANCE = "IMAGE"
)

func ec2Client() *ec2.Client {
	return ec2.NewFromEnv()
}

func init() {
	router.Register("aws/ec2/instances/describe", &gocli.Action{
		Handler: ec2DescribeInstances, Description: "Describe ec2 instances",
	})

	args := gocli.NewArgs(nil)
	args.RegisterString(CLI_INSTANCE_TYPE, "instance_type", false, "c1.medium", "Instance Type")
	args.RegisterString(CLI_SSH_KEY, "ssh_key", true, "", "SSH Key")
	args.RegisterString(CLI_SECURITY_GROUP, "security_group", true, "", "Security Group")

	router.Register("aws/ec2/instances/run", &gocli.Action{
		Handler: ec2RunInstances, Description: "Run ec2 instances", Args: args,
	})

	router.Register("aws/ec2/images/create", &gocli.Action{
		Handler: ec2CreateImage, Description: "Create image from instance",
	})

	router.Register("aws/ec2/instances/terminate", &gocli.Action{
		Handler: ec2TerminateInstances, Description: "Terminate ec2 instances", Usage: USAGE_TERMINATE_INSTANCES,
	})

	router.Register("aws/ec2/tags/create", &gocli.Action{
		Handler: ec2CreateTags, Description: "Create Tags", Usage: USAGE_CREATE_TAGS,
	})

	router.Register("aws/ec2/tags/describe", &gocli.Action{Handler: ec2DescribeTags, Description: "Describe Tags"})

	args = gocli.NewArgs(nil)
	args.RegisterBool(CLI_CANONICAL, "canonical", false, false, "Filter canonical images")
	args.RegisterBool(CLI_SELF, "self", false, false, "Filter own images")
	args.RegisterBool(CLI_UBUNTU, "ubuntu", false, false, "Filter ubuntu images")
	args.RegisterBool(CLI_UBUNTU_RARING, "raring", false, false, "Filter ubuntu raring images")
	args.RegisterBool(CLI_UBUNTU_SAUCY, "saucy", false, false, "Filter ubuntu saucy images")

	router.Register("aws/ec2/images/describe", &gocli.Action{
		Handler: ec2DescribeImages, Description: "Describe ec2 images", Args: args,
	})

	router.Register("aws/ec2/key-pairs/describe", &gocli.Action{
		Handler: ec2DescribeKeyPairs, Description: "Describe key pairs",
	})

	router.Register("aws/ec2/addresses/describe", &gocli.Action{
		Handler: ec2DescribeAddresses, Description: "Describe Addresses",
	})

	router.Register("aws/ec2/security-groups/describe", &gocli.Action{
		Handler: ec2DescribeSecurityGroups, Description: "Describe Security Groups",
	})

	router.Register("aws/ec2/spot-price-history/describe", &gocli.Action{
		Handler: ec2DescribeSpotPriceHistory, Description: "Describe Spot Price History",
	})
}

func ec2DescribeSpotPriceHistory(args *gocli.Args) error {
	filter := &ec2.SpotPriceFilter{
		InstanceTypes:       []string{"c1.medium"},
		ProductDescriptions: []string{ec2.DESC_LINUX_UNIX},
		StartTime:           time.Now().Add(-7 * 24 * time.Hour),
	}
	prices, e := ec2Client().DescribeSpotPriceHistory(filter)
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, price := range prices {
		table.Add(price.InstanceType, price.ProductDescription, price.SpotPrice, price.Timestamp, price.AvailabilityZone)
	}
	fmt.Println(table)

	return nil
}

func ec2DescribeSecurityGroups(args *gocli.Args) error {
	groups, e := ec2Client().DescribeSecurityGroups()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, group := range groups {
		table.Add(group.GroupId, "", "", group.GroupName)
		for _, perm := range group.IpPermissions {
			ports := ""
			if perm.FromPort > 0 {
				if perm.FromPort == perm.ToPort {
					ports += fmt.Sprintf("%d", perm.FromPort)
				} else {
					ports += fmt.Sprintf("%d-%d", perm.FromPort, perm.ToPort)
				}
			}
			groups := []string{}
			for _, group := range perm.Groups {
				groups = append(groups, group.GroupId)
			}
			if len(groups) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(groups, ","))
			}

			if len(perm.IpRanges) > 0 {
				table.Add("", perm.IpProtocol, ports, strings.Join(perm.IpRanges, ","))
			}
		}
	}
	fmt.Print(table)
	return nil

}

func ec2DescribeAddresses(args *gocli.Args) error {
	addresses, e := ec2Client().DescribeAddresses()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, address := range addresses {
		table.Add(address.PublicIp, address.PrivateIpAddress, address.Domain, address.InstanceId)
	}
	fmt.Print(table)
	return nil
}

func ec2DescribeKeyPairs(args *gocli.Args) error {
	pairs, e := ec2Client().DescribeKeyPairs()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	for _, pair := range pairs {
		table.Add(pair.KeyName, pair.KeyFingerprint)
	}
	fmt.Print(table)
	return nil
}

const USAGE_CREATE_IMAGE = "INSTANCE"

func ec2CreateImage(args *gocli.Args) error {
	if len(args.Args) != 0 {
		return fmt.Errorf(USAGE_CREATE_IMAGE)
	}
	instanceId := args.Args[0]
	logger.Infof("creating image of instance %s", instanceId)
	return nil
}

func ec2RunInstances(args *gocli.Args) error {
	if len(args.Args) == 0 {
		return fmt.Errorf(USAGE_IMAGE_ID)
	}
	imageId := args.Args[0]
	imageType := args.MustGetString(CLI_INSTANCE_TYPE)
	keyName := args.MustGetString(CLI_SSH_KEY)
	securityGroup := args.MustGetString(CLI_SECURITY_GROUP)

	config := &ec2.RunInstancesConfig{
		ImageId:        imageId,
		KeyName:        keyName,
		InstanceType:   imageType,
		SecurityGroups: []string{securityGroup},
	}
	_, e := ec2Client().RunInstances(config)
	return e
}

func ec2TerminateInstances(args *gocli.Args) error {
	if len(args.Args) < 1 {
		return fmt.Errorf(USAGE_TERMINATE_INSTANCES)
	}
	return ec2Client().TerminateInstances(args.Args)
}

func ec2CreateTags(args *gocli.Args) error {
	if len(args.Args) != 3 {
		return fmt.Errorf(USAGE_CREATE_TAGS)
	}
	resourceId := args.Args[0]
	tags := map[string]string{
		args.Args[1]: args.Args[2],
	}
	return ec2Client().CreateTags([]string{resourceId}, tags)
}

func ec2DescribeTags(args *gocli.Args) error {
	if len(args.Args) < 0 {
		return fmt.Errorf("instance...")
	}
	tags, e := ec2Client().DescribeTags()
	if e != nil {
		return e
	}
	sort.Sort(tags)
	table := gocli.NewTable()
	for _, tag := range tags {
		table.Add(tag.ResourceType, tag.ResourceId, tag.Key, tag.Value)
	}
	fmt.Println(table)
	return nil
}

func ec2DescribeInstances(args *gocli.Args) error {
	logger.Info("describing ec2 instances")
	instances, e := ec2Client().DescribeInstances()
	if e != nil {
		return e
	}
	table := gocli.NewTable()
	table.Add("id", "image", "name", "key", "state", "type", "private_ip", "ip", "launched", "groups")
	for _, i := range instances {
		sgs := []string{}
		for _, g := range i.SecurityGroups {
			sgs = append(sgs, g.GroupId)
		}
		table.Add(
			i.InstanceId,
			i.ImageId,
			i.Name(),
			i.KeyName,
			i.InstanceStateName,
			i.InstanceType,
			i.PrivateIpAddress,
			i.IpAddress,
			i.LaunchTime.Format("2006-01-02T15:04:05"),
			strings.Join(sgs, ","),
		)
	}
	fmt.Println(table)

	return nil
}

func ec2DescribeImages(args *gocli.Args) error {
	logger.Info("describing images")
	filter := &ec2.ImageFilter{}
	if args.GetBool(CLI_CANONICAL) {
		filter.Owner = ec2.CANONICAL_OWNER_ID
	} else if args.GetBool(CLI_SELF) {
		filter.Owner = ec2.SELF_OWNER_ID
	}

	if args.GetBool(CLI_UBUNTU) {
		filter.Name = ec2.UBUNTU_PREFIX
	} else if args.GetBool(CLI_UBUNTU_RARING) {
		filter.Name = ec2.UBUNTU_RARING_PREFIX
	} else if args.GetBool(CLI_UBUNTU_SAUCY) {
		filter.Name = ec2.UBUNTU_SAUCY_PREFIX
	}

	images, e := ec2Client().DescribeImagesWithFilter(filter)
	if e != nil {
		return e
	}
	sort.Sort(images)
	table := gocli.NewTable()
	for _, image := range images {
		table.Add(image.ImageId, image.Name, image.ImageState)
	}
	fmt.Println(table)
	return nil
}
<|endoftext|>


<commit_before>package gohasha

import (
	"testing"
)

const (
	MD5LENGTH   = 32
	CRC64LENGTH = 16
)

func TestDataMd5(t *testing.T) {
	result, err := GoHasha(&GohashaOptions{Data: "foobar"})
	if err != nil {
		t.Errorf("Found error")
	}

	if len(result) != MD5LENGTH {
		t.Errorf("%d not match %d", len(result), MD5LENGTH)
	}
}

func TestDataCrc64(t *testing.T) {
	result, err := GoHasha(&GohashaOptions{Data: "foobar", Algorithm: "crc64"})
	if err != nil {
		t.Errorf("found error")
	}

	if len(result) != CRC64LENGTH {
		t.Errorf("%d not match %d", len(result), CRC64LENGTH)
	}
}

func TestUserFunction(t *testing.T) {
	result, err := GoHasha(&GohashaOptions{Data: "foobar", HashingFunc: func(str string) string{
		return str
	}})
	if err != nil {
		t.Errorf("found error")
	}

	if result != "foobar" {
		t.Errorf("%s not match %s", result, "foobar")
	}

}

func TestReadFromFileMd5(t *testing.T) {
	result, _ := GoHasha(&GohashaOptions{Filepath: "gohasha.go"})
	if len(result) != MD5LENGTH {
		t.Errorf("%d not match %d", len(result), MD5LENGTH)
	}
}

func TestReadFromFileCrc64(t *testing.T) {
	result, _ := GoHasha(&GohashaOptions{Filepath: "gohasha.go", Algorithm: "crc64"})
	if len(result) != CRC64LENGTH {
		t.Errorf("%d not match %d", len(result), CRC64LENGTH)
	}
}

func TestReadFromWebPage(t *testing.T) {
	result, _ := GoHasha(&GohashaOptions{Webpage: "https://golang.org"})
	if len(result) != MD5LENGTH {
		t.Errorf("%d not match %d", len(result), CRC64LENGTH)
	}
}
<commit_msg>Add tests for hashing interface{} data<commit_after>package gohasha

import (
	"testing"
)

const (
	MD5LENGTH   = 32
	CRC64LENGTH = 16
)

func TestDataMd5(t *testing.T) {
	result, err := GoHasha(&GohashaOptions{Data: "foobar"})
	if err != nil {
		t.Errorf("Found error")
	}

	if len(result) != MD5LENGTH {
		t.Errorf("%d not match %d", len(result), MD5LENGTH)
	}
}

func TestDataCrc64(t *testing.T) {
	result, err := GoHasha(&GohashaOptions{Data: "foobar", Algorithm: "crc64"})
	if err != nil {
		t.Errorf("found error")
	}

	if len(result) != CRC64LENGTH {
		t.Errorf("%d not match %d", len(result), CRC64LENGTH)
	}
}

func TestDataObject(t *testing.T) {
	value := map[string]string{"Seven": "days"}
	result, err := GoHasha(&GohashaOptions{Object:value, Algorithm: "crc64"})
	if err != nil {
		t.Errorf("found error")
	}

	if len(result) != CRC64LENGTH {
		t.Errorf("%d not match %d", len(result), CRC64LENGTH)
	}
}

func TestUserFunction(t *testing.T) {
	result, err := GoHasha(&GohashaOptions{Data: "foobar", HashingFunc: func(str string) string{
		return str
	}})
	if err != nil {
		t.Errorf("found error")
	}

	if result != "foobar" {
		t.Errorf("%s not match %s", result, "foobar")
	}

}

func TestReadFromFileMd5(t *testing.T) {
	result, _ := GoHasha(&GohashaOptions{Filepath: "gohasha.go"})
	if len(result) != MD5LENGTH {
		t.Errorf("%d not match %d", len(result), MD5LENGTH)
	}
}

func TestReadFromFileCrc64(t *testing.T) {
	result, _ := GoHasha(&GohashaOptions{Filepath: "gohasha.go", Algorithm: "crc64"})
	if len(result) != CRC64LENGTH {
		t.Errorf("%d not match %d", len(result), CRC64LENGTH)
	}
}

func TestReadFromWebPage(t *testing.T) {
	result, _ := GoHasha(&GohashaOptions{Webpage: "https://golang.org"})
	if len(result) != MD5LENGTH {
		t.Errorf("%d not match %d", len(result), CRC64LENGTH)
	}
}
<|endoftext|>


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

package apps

import (
	"net/url"
	"path"
	"strings"

	"github.com/srinandan/apigeecli/apiclient"
)

//CreateKey
func CreateKey(developerEmail string, appID string, consumerKey string, consumerSecret string, apiProducts []string, scopes []string, attrs map[string]string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)

	key := []string{}

	key = append(key, "\"apiProducts\":[\""+getArrayStr(apiProducts)+"\"]")
	key = append(key, "\"scopes\":[\""+getArrayStr(scopes)+"\"]")

	if len(attrs) != 0 {
		attributes := []string{}
		for keyattr, value := range attrs {
			attributes = append(attributes, "{\"name\":\""+keyattr+"\",\"value\":\""+value+"\"}")
		}
		attributesStr := "\"attributes\":[" + strings.Join(attributes, ",") + "]"
		key = append(key, attributesStr)
	}

	key = append(key, "\"consumerKey\":\""+consumerKey+"\"")
	key = append(key, "\"consumerSecret\":\""+consumerSecret+"\"")

	payload := "{" + strings.Join(key, ",") + "}"

	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys")
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), payload)
	return respBody, err
}

//DeleteKey
func DeleteKey(developerEmail string, appID string, key string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys", key)
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), "", "DELETE")
	return respBody, err
}

//GetKey
func GetKey(developerEmail string, appID string, key string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys", key)
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}
<commit_msg>support creating keys with api products<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apps

import (
	"net/url"
	"path"
	"strings"

	"github.com/srinandan/apigeecli/apiclient"
)

//CreateKey
func CreateKey(developerEmail string, appID string, consumerKey string, consumerSecret string, apiProducts []string, scopes []string, attrs map[string]string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)

	key := []string{}

	key = append(key, "\"scopes\":[\""+getArrayStr(scopes)+"\"]")

	if len(attrs) != 0 {
		attributes := []string{}
		for keyattr, value := range attrs {
			attributes = append(attributes, "{\"name\":\""+keyattr+"\",\"value\":\""+value+"\"}")
		}
		attributesStr := "\"attributes\":[" + strings.Join(attributes, ",") + "]"
		key = append(key, attributesStr)
	}

	key = append(key, "\"consumerKey\":\""+consumerKey+"\"")
	key = append(key, "\"consumerSecret\":\""+consumerSecret+"\"")

	payload := "{" + strings.Join(key, ",") + "}"

	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys")

	if len(apiProducts) > 0 {
		apiclient.SetPrintOutput(false)
	}
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), payload)

	if err != nil {
		return respBody, err
	}

	//since the API does not support adding products when creating a key, use a second API call to add products
	if len(apiProducts) > 0 {
		apiclient.SetPrintOutput(true)
		respBody, err = UpdateKeyProducts(developerEmail, appID, consumerKey, apiProducts)
	}

	return respBody, err
}

//DeleteKey
func DeleteKey(developerEmail string, appID string, key string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys", key)
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), "", "DELETE")
	return respBody, err
}

//GetKey
func GetKey(developerEmail string, appID string, key string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)
	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys", key)
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String())
	return respBody, err
}

//UpdateKey
func UpdateKey(developerEmail string, appID string, consumerKey string, consumerSecret string, apiProducts []string, scopes []string, attrs map[string]string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)

	key := []string{}

	if len(apiProducts) > 0 {
		key = append(key, "\"apiProducts\":[\""+getArrayStr(apiProducts)+"\"]")
	}

	if len(scopes) > 0 {
		key = append(key, "\"scopes\":[\""+getArrayStr(scopes)+"\"]")
	}

	if len(attrs) > 0 {
		attributes := []string{}
		for keyattr, value := range attrs {
			attributes = append(attributes, "{\"name\":\""+keyattr+"\",\"value\":\""+value+"\"}")
		}
		attributesStr := "\"attributes\":[" + strings.Join(attributes, ",") + "]"
		key = append(key, attributesStr)
	}

	key = append(key, "\"consumerKey\":\""+consumerKey+"\"")

	if consumerSecret != "" {
		key = append(key, "\"consumerSecret\":\""+consumerSecret+"\"")
	}

	payload := "{" + strings.Join(key, ",") + "}"

	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys", consumerKey)
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), payload)

	return respBody, err
}

func UpdateKeyProducts(developerEmail string, appID string, consumerKey string, apiProducts []string) (respBody []byte, err error) {
	u, _ := url.Parse(apiclient.BaseURL)

	key := []string{}
	key = append(key, "\"apiProducts\":[\""+getArrayStr(apiProducts)+"\"]")

	payload := "{" + strings.Join(key, ",") + "}"

	u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "developers", developerEmail, "apps", appID, "keys", consumerKey)
	respBody, err = apiclient.HttpClient(apiclient.GetPrintOutput(), u.String(), payload)

	return respBody, err
}
<|endoftext|>


<commit_before>// Package tmpl implements a protobuf template-based generator.
package tmpl // import "sourcegraph.com/sourcegraph/prototools/tmpl"

import (
	"bytes"
	"encoding/xml"
	"errors"
	"fmt"
	"html/template"
	"io/ioutil"
	"path"

	gateway "github.com/gengo/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
	"github.com/golang/protobuf/proto"
	descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
)

// Generator is the type whose methods generate the output, stored in the associated response structure.
type Generator struct {
	// FileMap is the map of template files to use for the generation process.
	FileMap FileMap

	// RootDir is the root directory path prefix to place onto URLs for generated
	// types.
	RootDir string

	// APIHost is the base URL to use for rendering grpc-gateway routes, e.g.:
	//
	//  http://api.mysite.com/
	//
	APIHost string

	// ReadFile if non-nil is used to read template files, otherwise
	// ioutil.ReadFile is used.
	ReadFile func(path string) ([]byte, error)

	// request from protoc compiler, which should be set by the user of this
	// package via the SetRequest method.
	request *plugin.CodeGeneratorRequest

	// Response to protoc compiler.
	response *plugin.CodeGeneratorResponse

	// grpc-gateway registry used to determine HTTP routes.
	registry *gateway.Registry
}

// ParseFileMap parses and executes a filemap template.
func (g *Generator) ParseFileMap(dir, data string) error {
	// Parse the template data.
	t, err := template.New("").Funcs(Preload).Parse(data)
	if err != nil {
		return err
	}

	// Execute the template.
	buf := bytes.NewBuffer(nil)
	err = t.Execute(buf, g.request)
	if err != nil {
		return err
	}

	// Parse the filemap.
	g.FileMap.Dir = dir
	err = xml.Unmarshal(buf.Bytes(), &g.FileMap)
	if err != nil {
		return err
	}
	if len(g.FileMap.Generate) == 0 {
		return errors.New("no generate elements found in file map")
	}
	return nil
}

// Generate generates a response for g.Request (which you should unmarshal data
// into using protobuf).
//
// If any error is encountered during generation, it is returned and should be
// considered fatal to the generation process (the response will be nil).
func (g *Generator) Generate() (response *plugin.CodeGeneratorResponse, err error) {
	// Reset the response to its initial state.
	g.response.Reset()

	// Execute each generator.
	errs := bytes.NewBuffer(nil)
	for _, gen := range g.FileMap.Generate {
		f, err := g.GenerateOutput(gen.Output, nil)
		if err != nil {
			fmt.Fprintf(errs, "%s\n", err)
			continue
		}
		g.response.File = append(g.response.File, f)
	}

	if errs.Len() > 0 {
		g.response.File = nil
		errsStr := errs.String()
		g.response.Error = &errsStr
	}
	return g.response, nil
}

// GenerateOutput generates a CodeGeneratorResponse_File for the output file
// name.
//
// The ctx parameter specifies an arbitrary context for which to execute the
// template with, it is exposed to the executed template file as "Ctx".
func (g *Generator) GenerateOutput(name string, ctx interface{}) (*plugin.CodeGeneratorResponse_File, error) {
	// Find the generator with that output filename.
	for _, gen := range g.FileMap.Generate {
		if gen.Output != name {
			continue
		}

		// Execute in whichever mode is correct.
		if gen.Target != "" {
			return g.genTarget(gen, ctx)
		} else {
			return g.genNoTarget(gen, ctx)
		}
	}

	var outputs []string
	for _, gen := range g.FileMap.Generate {
		outputs = append(outputs, gen.Output)
	}
	return nil, fmt.Errorf("no such generator with output file %q\nvalid outputs are: %q", name, outputs)
}

// SetRequest sets the request the generator is generating a response for. If an
// error is returned generation is not safe (the request is bad) until a
// different request object is set successfully through this method.
func (g *Generator) SetRequest(r *plugin.CodeGeneratorRequest) error {
	g.request = r

	// Load into the grpc-gateway registry.
	return g.registry.Load(g.request)
}

// New returns a new generator for the given template.
func New() *Generator {
	return &Generator{
		request:  &plugin.CodeGeneratorRequest{},
		response: &plugin.CodeGeneratorResponse{},
		registry: gateway.NewRegistry(),
	}
}

// genTarget a filemap generator with a specific target (e.g. for individual doc
// pages).
func (g *Generator) genTarget(gen *FileMapGenerate, userCtx interface{}) (*plugin.CodeGeneratorResponse_File, error) {
	var (
		buf       = bytes.NewBuffer(nil)
		protoFile = g.request.GetProtoFile()
		f         *descriptor.FileDescriptorProto
	)

	// Find the target proto file.
	for _, v := range protoFile {
		if gen.Target == v.GetName() {
			f = v
			break
		}
	}
	if f == nil {
		return nil, fmt.Errorf("no input proto file for generator target %q", gen.Target)
	}

	// Prepare the generators template.
	tmpl, err := g.prepare(gen)
	if err != nil {
		return nil, err
	}

	// Execute the template with this context and generate a response
	// for the input file.
	ctx := &tmplFuncs{
		f:          f,
		outputFile: gen.Output,
		rootDir:    g.RootDir,
		protoFile:  protoFile,
		registry:   g.registry,
		apiHost:    g.APIHost,
	}
	err = tmpl.Funcs(ctx.funcMap()).Execute(buf, struct {
		*descriptor.FileDescriptorProto
		Generate *FileMapGenerate
		Data     map[string]string
		Request  *plugin.CodeGeneratorRequest
		Ctx      interface{}
	}{
		f,
		gen,
		gen.DataMap(),
		g.request,
		userCtx,
	})
	if err != nil {
		return nil, err
	}

	// Generate the response file with the rendered template.
	return &plugin.CodeGeneratorResponse_File{
		Name:    proto.String(gen.Output),
		Content: proto.String(buf.String()),
	}, nil
}

// genNoTarget executes a target-less filemap generator (e.g. for index pages
// rather than individual doc pages). It panics if gen.Target != "".
func (g *Generator) genNoTarget(gen *FileMapGenerate, userCtx interface{}) (*plugin.CodeGeneratorResponse_File, error) {
	buf := bytes.NewBuffer(nil)

	// Only running generators not on proto files (i.e. generators without
	// targets).
	if gen.Target != "" {
		panic("expected a generator without a target")
	}

	// Prepare the generators template.
	tmpl, err := g.prepare(gen)
	if err != nil {
		return nil, err
	}

	// Execute the template with this context and generate a response file.
	ctx := &tmplFuncs{
		outputFile: gen.Output,
		rootDir:    g.RootDir,
		registry:   g.registry,
		apiHost:    g.APIHost,
	}
	err = tmpl.Funcs(ctx.funcMap()).Execute(buf, struct {
		*plugin.CodeGeneratorRequest
		Generate *FileMapGenerate
		Data     map[string]string
		Ctx      interface{}
	}{
		g.request,
		gen,
		gen.DataMap(),
		userCtx,
	})
	if err != nil {
		return nil, err
	}

	// Generate the response file with the rendered template.
	return &plugin.CodeGeneratorResponse_File{
		Name:    proto.String(gen.Output),
		Content: proto.String(buf.String()),
	}, nil
}

// loadTemplate is responsible for loading a single template and associating it
// with t. It reads the template file from g.ReadFile as appropriate.
func (g *Generator) loadTemplate(t *template.Template, tmplPath string) (*template.Template, error) {
	// Make the filepath relative to the filemap.
	tmplPath = g.FileMap.relative(tmplPath)[0]

	// Determine the open function.
	readFile := g.ReadFile
	if readFile == nil {
		readFile = ioutil.ReadFile
	}

	// Read the file.
	data, err := readFile(tmplPath)
	if err != nil {
		return nil, err
	}

	// Create a new template and parse.
	_, name := path.Split(tmplPath)
	return t.New(name).Parse(string(data))
}

// prepare prepares the given filemap generators template for execution,
// handling parsing of both the relative-path templates and their includes.
func (g *Generator) prepare(gen *FileMapGenerate) (*template.Template, error) {
	// Preload the function map (or else the functions will fail when
	// called due to a lack of valid context).
	var (
		t   = template.New("").Funcs(Preload)
		err error
	)

	// Parse the included template files.
	for _, inc := range gen.Include {
		_, err := g.loadTemplate(t, inc)
		if err != nil {
			return nil, err
		}
	}

	// Parse the template file to execute.
	tmpl, err := g.loadTemplate(t, gen.Template)
	if err != nil {
		return nil, err
	}
	_, name := path.Split(gen.Template)
	tmpl = tmpl.Lookup(name)
	return tmpl, nil
}
<commit_msg>tmpl: Remove unneeded init.<commit_after>// Package tmpl implements a protobuf template-based generator.
package tmpl // import "sourcegraph.com/sourcegraph/prototools/tmpl"

import (
	"bytes"
	"encoding/xml"
	"errors"
	"fmt"
	"html/template"
	"io/ioutil"
	"path"

	gateway "github.com/gengo/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
	"github.com/golang/protobuf/proto"
	descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
)

// Generator is the type whose methods generate the output, stored in the associated response structure.
type Generator struct {
	// FileMap is the map of template files to use for the generation process.
	FileMap FileMap

	// RootDir is the root directory path prefix to place onto URLs for generated
	// types.
	RootDir string

	// APIHost is the base URL to use for rendering grpc-gateway routes, e.g.:
	//
	//  http://api.mysite.com/
	//
	APIHost string

	// ReadFile if non-nil is used to read template files, otherwise
	// ioutil.ReadFile is used.
	ReadFile func(path string) ([]byte, error)

	// request from protoc compiler, which should be set by the user of this
	// package via the SetRequest method.
	request *plugin.CodeGeneratorRequest

	// Response to protoc compiler.
	response *plugin.CodeGeneratorResponse

	// grpc-gateway registry used to determine HTTP routes.
	registry *gateway.Registry
}

// ParseFileMap parses and executes a filemap template.
func (g *Generator) ParseFileMap(dir, data string) error {
	// Parse the template data.
	t, err := template.New("").Funcs(Preload).Parse(data)
	if err != nil {
		return err
	}

	// Execute the template.
	buf := bytes.NewBuffer(nil)
	err = t.Execute(buf, g.request)
	if err != nil {
		return err
	}

	// Parse the filemap.
	g.FileMap.Dir = dir
	err = xml.Unmarshal(buf.Bytes(), &g.FileMap)
	if err != nil {
		return err
	}
	if len(g.FileMap.Generate) == 0 {
		return errors.New("no generate elements found in file map")
	}
	return nil
}

// Generate generates a response for g.Request (which you should unmarshal data
// into using protobuf).
//
// If any error is encountered during generation, it is returned and should be
// considered fatal to the generation process (the response will be nil).
func (g *Generator) Generate() (response *plugin.CodeGeneratorResponse, err error) {
	// Reset the response to its initial state.
	g.response.Reset()

	// Execute each generator.
	errs := bytes.NewBuffer(nil)
	for _, gen := range g.FileMap.Generate {
		f, err := g.GenerateOutput(gen.Output, nil)
		if err != nil {
			fmt.Fprintf(errs, "%s\n", err)
			continue
		}
		g.response.File = append(g.response.File, f)
	}

	if errs.Len() > 0 {
		g.response.File = nil
		errsStr := errs.String()
		g.response.Error = &errsStr
	}
	return g.response, nil
}

// GenerateOutput generates a CodeGeneratorResponse_File for the output file
// name.
//
// The ctx parameter specifies an arbitrary context for which to execute the
// template with, it is exposed to the executed template file as "Ctx".
func (g *Generator) GenerateOutput(name string, ctx interface{}) (*plugin.CodeGeneratorResponse_File, error) {
	// Find the generator with that output filename.
	for _, gen := range g.FileMap.Generate {
		if gen.Output != name {
			continue
		}

		// Execute in whichever mode is correct.
		if gen.Target != "" {
			return g.genTarget(gen, ctx)
		} else {
			return g.genNoTarget(gen, ctx)
		}
	}

	var outputs []string
	for _, gen := range g.FileMap.Generate {
		outputs = append(outputs, gen.Output)
	}
	return nil, fmt.Errorf("no such generator with output file %q\nvalid outputs are: %q", name, outputs)
}

// SetRequest sets the request the generator is generating a response for. If an
// error is returned generation is not safe (the request is bad) until a
// different request object is set successfully through this method.
func (g *Generator) SetRequest(r *plugin.CodeGeneratorRequest) error {
	g.request = r

	// Load into the grpc-gateway registry.
	return g.registry.Load(g.request)
}

// New returns a new generator for the given template.
func New() *Generator {
	return &Generator{
		response: &plugin.CodeGeneratorResponse{},
		registry: gateway.NewRegistry(),
	}
}

// genTarget a filemap generator with a specific target (e.g. for individual doc
// pages).
func (g *Generator) genTarget(gen *FileMapGenerate, userCtx interface{}) (*plugin.CodeGeneratorResponse_File, error) {
	var (
		buf       = bytes.NewBuffer(nil)
		protoFile = g.request.GetProtoFile()
		f         *descriptor.FileDescriptorProto
	)

	// Find the target proto file.
	for _, v := range protoFile {
		if gen.Target == v.GetName() {
			f = v
			break
		}
	}
	if f == nil {
		return nil, fmt.Errorf("no input proto file for generator target %q", gen.Target)
	}

	// Prepare the generators template.
	tmpl, err := g.prepare(gen)
	if err != nil {
		return nil, err
	}

	// Execute the template with this context and generate a response
	// for the input file.
	ctx := &tmplFuncs{
		f:          f,
		outputFile: gen.Output,
		rootDir:    g.RootDir,
		protoFile:  protoFile,
		registry:   g.registry,
		apiHost:    g.APIHost,
	}
	err = tmpl.Funcs(ctx.funcMap()).Execute(buf, struct {
		*descriptor.FileDescriptorProto
		Generate *FileMapGenerate
		Data     map[string]string
		Request  *plugin.CodeGeneratorRequest
		Ctx      interface{}
	}{
		f,
		gen,
		gen.DataMap(),
		g.request,
		userCtx,
	})
	if err != nil {
		return nil, err
	}

	// Generate the response file with the rendered template.
	return &plugin.CodeGeneratorResponse_File{
		Name:    proto.String(gen.Output),
		Content: proto.String(buf.String()),
	}, nil
}

// genNoTarget executes a target-less filemap generator (e.g. for index pages
// rather than individual doc pages). It panics if gen.Target != "".
func (g *Generator) genNoTarget(gen *FileMapGenerate, userCtx interface{}) (*plugin.CodeGeneratorResponse_File, error) {
	buf := bytes.NewBuffer(nil)

	// Only running generators not on proto files (i.e. generators without
	// targets).
	if gen.Target != "" {
		panic("expected a generator without a target")
	}

	// Prepare the generators template.
	tmpl, err := g.prepare(gen)
	if err != nil {
		return nil, err
	}

	// Execute the template with this context and generate a response file.
	ctx := &tmplFuncs{
		outputFile: gen.Output,
		rootDir:    g.RootDir,
		registry:   g.registry,
		apiHost:    g.APIHost,
	}
	err = tmpl.Funcs(ctx.funcMap()).Execute(buf, struct {
		*plugin.CodeGeneratorRequest
		Generate *FileMapGenerate
		Data     map[string]string
		Ctx      interface{}
	}{
		g.request,
		gen,
		gen.DataMap(),
		userCtx,
	})
	if err != nil {
		return nil, err
	}

	// Generate the response file with the rendered template.
	return &plugin.CodeGeneratorResponse_File{
		Name:    proto.String(gen.Output),
		Content: proto.String(buf.String()),
	}, nil
}

// loadTemplate is responsible for loading a single template and associating it
// with t. It reads the template file from g.ReadFile as appropriate.
func (g *Generator) loadTemplate(t *template.Template, tmplPath string) (*template.Template, error) {
	// Make the filepath relative to the filemap.
	tmplPath = g.FileMap.relative(tmplPath)[0]

	// Determine the open function.
	readFile := g.ReadFile
	if readFile == nil {
		readFile = ioutil.ReadFile
	}

	// Read the file.
	data, err := readFile(tmplPath)
	if err != nil {
		return nil, err
	}

	// Create a new template and parse.
	_, name := path.Split(tmplPath)
	return t.New(name).Parse(string(data))
}

// prepare prepares the given filemap generators template for execution,
// handling parsing of both the relative-path templates and their includes.
func (g *Generator) prepare(gen *FileMapGenerate) (*template.Template, error) {
	// Preload the function map (or else the functions will fail when
	// called due to a lack of valid context).
	var (
		t   = template.New("").Funcs(Preload)
		err error
	)

	// Parse the included template files.
	for _, inc := range gen.Include {
		_, err := g.loadTemplate(t, inc)
		if err != nil {
			return nil, err
		}
	}

	// Parse the template file to execute.
	tmpl, err := g.loadTemplate(t, gen.Template)
	if err != nil {
		return nil, err
	}
	_, name := path.Split(gen.Template)
	tmpl = tmpl.Lookup(name)
	return tmpl, nil
}
<|endoftext|>


<commit_before>package todoist

import (
	"fmt"
	"github.com/seanrees/tripist/tasks"
	"log"
	"math/rand"
	"strconv"
	"time"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

// Verify runs a series of compatability tests on Todoist, returning error if incompatible.
//
// This code verifies that Todoist and this are compatible. It is done in lieu of
// a unit test or mock, as any local implementation would diverge from the ultimate
// source of truth.
//
// This code fails fast and should not be expected to return all compatibility errors in
// one call.
//
// This could be rewritten with Go's testing package but would require a TestMain to setup
// the API and user keys.
func Verify(api *SyncV7API) error {
	step := 0

	var err error
	var p *Project
	var tp *tasks.Project
	var items []Item

	name := randomProjectName()
	if _, err = verifyProjectPresence(name, &step, false, api); err != nil {
		return err
	}

	l(&step, "Creating project %q", name)
	err = api.CreateProject(tasks.Project{Name: name})
	if err != nil {
		return err
	}

	l(&step, "Verifying %q created successfully", name)
	p, err = verifyProjectPresence(name, &step, true, api)
	if err != nil {
		return err
	}

	l(&step, "Adding items to project %q", name)
	due := time.Date(2016, 07, 15, 12, 00, 00, 00, time.UTC)
	testTasks := []tasks.Task{
		{Content: "one", Position: 1, DueDate: due},
		{Content: "two", Position: 2, DueDate: due},
	}
	cmds := Commands{}
	id := strconv.Itoa(*p.Id)
	for _, t := range testTasks {
		cmds = append(cmds, api.createItem(id, t))
	}
	if _, err := api.Write(cmds); err != nil {
		return err
	}

	tp, err = verifyTasksInProject(name, &step, testTasks, api)

	l(&step, "Updating an item in project %q", name)
	testTasks[0].Position = 3
	testTasks[0].DueDate.Add(24 * time.Hour)
	d := tasks.Diff{tasks.Changed, testTasks[0]}
	err = api.UpdateProject(*tp, []tasks.Diff{d})
	if err != nil {
		return err
	}

	_, err = verifyTasksInProject(name, &step, testTasks, api)

	l(&step, "Deleting an item")
	items, err = api.listItems(p)
	del := items[0]
	if err != nil {
		return err
	}
	if _, err = api.Write(Commands{api.deleteItem(del)}); err != nil {
		return err
	}
	items, err = api.listItems(p)
	for _, i := range items {
		if *i.Content == *del.Content {
			return fmt.Errorf("delete item failed on item %q", *i.Content)
		}
	}

	l(&step, "Deleting project %q", name)
	if _, err = api.Write(Commands{api.deleteProject(p)}); err != nil {
		return err
	}

	if _, err = verifyProjectPresence(name, &step, false, api); err != nil {
		return err
	}

	return nil
}

func l(step *int, s string, v ...interface{}) {
	msg := fmt.Sprintf("[step %02d] %s", *step, s)
	log.Printf(msg, v...)
	*step++
}

func randomProjectName() string {
	chars := []rune("abcdefABCDEF0123456789")
	name := make([]rune, 5)
	for i := range name {
		name[i] = chars[rand.Intn(len(chars))]
	}
	return fmt.Sprintf("Todoist Verification %s", string(name))
}

func verifyProjectPresence(name string, step *int, expected bool, api *SyncV7API) (*Project, error) {
	str := ""
	if !expected {
		str = "not "
	}

	l(step, "Verifying %q %spresent", name, str)

	p, err := api.findProject(name)
	if err != nil {
		return nil, err
	}
	found := p != nil
	if found != expected {
		return nil, fmt.Errorf("found %q which should %sexist", name, str)
	}

	return p, nil
}

func verifyTasksInProject(name string, step *int, expected []tasks.Task, api *SyncV7API) (*tasks.Project, error) {
	l(step, "Verifying items in project %q", name)
	tp, found, err := api.LoadProject(name)
	if err != nil {
		return nil, err
	}
	if !found {
		return nil, fmt.Errorf("unable to find project %q with LoadProject", name)
	}
	if d := tp.DiffTasks(tasks.Project{Tasks: expected}); len(d) > 0 {
		return nil, fmt.Errorf("unexpected diffs in write / read cycle: %v", d)
	}

	return &tp, nil
}
<commit_msg>Fix issue detected by go vet<commit_after>package todoist

import (
	"fmt"
	"github.com/seanrees/tripist/tasks"
	"log"
	"math/rand"
	"strconv"
	"time"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

// Verify runs a series of compatability tests on Todoist, returning error if incompatible.
//
// This code verifies that Todoist and this are compatible. It is done in lieu of
// a unit test or mock, as any local implementation would diverge from the ultimate
// source of truth.
//
// This code fails fast and should not be expected to return all compatibility errors in
// one call.
//
// This could be rewritten with Go's testing package but would require a TestMain to setup
// the API and user keys.
func Verify(api *SyncV7API) error {
	step := 0

	var err error
	var p *Project
	var tp *tasks.Project
	var items []Item

	name := randomProjectName()
	if _, err = verifyProjectPresence(name, &step, false, api); err != nil {
		return err
	}

	l(&step, "Creating project %q", name)
	err = api.CreateProject(tasks.Project{Name: name})
	if err != nil {
		return err
	}

	l(&step, "Verifying %q created successfully", name)
	p, err = verifyProjectPresence(name, &step, true, api)
	if err != nil {
		return err
	}

	l(&step, "Adding items to project %q", name)
	due := time.Date(2016, 07, 15, 12, 00, 00, 00, time.UTC)
	testTasks := []tasks.Task{
		{Content: "one", Position: 1, DueDate: due},
		{Content: "two", Position: 2, DueDate: due},
	}
	cmds := Commands{}
	id := strconv.Itoa(*p.Id)
	for _, t := range testTasks {
		cmds = append(cmds, api.createItem(id, t))
	}
	if _, err := api.Write(cmds); err != nil {
		return err
	}

	tp, err = verifyTasksInProject(name, &step, testTasks, api)

	l(&step, "Updating an item in project %q", name)
	testTasks[0].Position = 3
	testTasks[0].DueDate.Add(24 * time.Hour)
	d := tasks.Diff{Type: tasks.Changed, Task: testTasks[0]}
	err = api.UpdateProject(*tp, []tasks.Diff{d})
	if err != nil {
		return err
	}

	_, err = verifyTasksInProject(name, &step, testTasks, api)

	l(&step, "Deleting an item")
	items, err = api.listItems(p)
	del := items[0]
	if err != nil {
		return err
	}
	if _, err = api.Write(Commands{api.deleteItem(del)}); err != nil {
		return err
	}
	items, err = api.listItems(p)
	for _, i := range items {
		if *i.Content == *del.Content {
			return fmt.Errorf("delete item failed on item %q", *i.Content)
		}
	}

	l(&step, "Deleting project %q", name)
	if _, err = api.Write(Commands{api.deleteProject(p)}); err != nil {
		return err
	}

	if _, err = verifyProjectPresence(name, &step, false, api); err != nil {
		return err
	}

	return nil
}

func l(step *int, s string, v ...interface{}) {
	msg := fmt.Sprintf("[step %02d] %s", *step, s)
	log.Printf(msg, v...)
	*step++
}

func randomProjectName() string {
	chars := []rune("abcdefABCDEF0123456789")
	name := make([]rune, 5)
	for i := range name {
		name[i] = chars[rand.Intn(len(chars))]
	}
	return fmt.Sprintf("Todoist Verification %s", string(name))
}

func verifyProjectPresence(name string, step *int, expected bool, api *SyncV7API) (*Project, error) {
	str := ""
	if !expected {
		str = "not "
	}

	l(step, "Verifying %q %spresent", name, str)

	p, err := api.findProject(name)
	if err != nil {
		return nil, err
	}
	found := p != nil
	if found != expected {
		return nil, fmt.Errorf("found %q which should %sexist", name, str)
	}

	return p, nil
}

func verifyTasksInProject(name string, step *int, expected []tasks.Task, api *SyncV7API) (*tasks.Project, error) {
	l(step, "Verifying items in project %q", name)
	tp, found, err := api.LoadProject(name)
	if err != nil {
		return nil, err
	}
	if !found {
		return nil, fmt.Errorf("unable to find project %q with LoadProject", name)
	}
	if d := tp.DiffTasks(tasks.Project{Tasks: expected}); len(d) > 0 {
		return nil, fmt.Errorf("unexpected diffs in write / read cycle: %v", d)
	}

	return &tp, nil
}
<|endoftext|>