<commit_before>package s3

import (
	"context"

	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/helper/schema"

	terraformAWS "github.com/hashicorp/terraform/builtin/providers/aws"
)

// New creates a new backend for S3 remote state.
func New() backend.Backend {
	s := &schema.Backend{
		Schema: map[string]*schema.Schema{
			"bucket": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The name of the S3 bucket",
			},

			"key": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The path to the state file inside the bucket",
			},

			"region": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The region of the S3 bucket.",
				DefaultFunc: schema.EnvDefaultFunc("AWS_DEFAULT_REGION", nil),
			},

			"endpoint": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "A custom endpoint for the S3 API",
				DefaultFunc: schema.EnvDefaultFunc("AWS_S3_ENDPOINT", ""),
			},

			"encrypt": {
				Type:        schema.TypeBool,
				Optional:    true,
				Description: "Whether to enable server side encryption of the state file",
				Default:     false,
			},

			"acl": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Canned ACL to be applied to the state file",
				Default:     "",
			},

			"access_key": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "AWS access key",
				Default:     "",
			},

			"secret_key": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "AWS secret key",
				Default:     "",
			},

			"kms_key_id": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The ARN of a KMS Key to use for encrypting the state",
				Default:     "",
			},

			"lock_table": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "DynamoDB table for state locking",
				Default:     "",
				Deprecated:  "please use the dynamodb_table attribute",
			},

			"dynamodb_table": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "DynamoDB table for state locking and consistency",
				Default:     "",
			},

			"profile": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "AWS profile name",
				Default:     "",
			},

			"shared_credentials_file": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Path to a shared credentials file",
				Default:     "",
			},

			"token": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "MFA token",
				Default:     "",
			},

			"role_arn": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The role to be assumed",
				Default:     "",
			},

			"session_name": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The session name to use when assuming the role.",
				Default:     "",
			},

			"external_id": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The external ID to use when assuming the role",
				Default:     "",
			},

			"assume_role_policy": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The permissions applied when assuming a role.",
				Default:     "",
			},
		},
	}

	result := &Backend{Backend: s}
	result.Backend.ConfigureFunc = result.configure
	return result
}

type Backend struct {
	*schema.Backend

	// The fields below are set from configure
	s3Client  *s3.S3
	dynClient *dynamodb.DynamoDB

	bucketName           string
	keyName              string
	serverSideEncryption bool
	acl                  string
	kmsKeyID             string
	ddbTable             string
}

func (b *Backend) configure(ctx context.Context) error {
	if b.s3Client != nil {
		return nil
	}

	// Grab the resource data
	data := schema.FromContextBackendConfig(ctx)

	b.bucketName = data.Get("bucket").(string)
	b.keyName = data.Get("key").(string)
	b.serverSideEncryption = data.Get("encrypt").(bool)
	b.acl = data.Get("acl").(string)
	b.kmsKeyID = data.Get("kms_key_id").(string)

	b.ddbTable = data.Get("dynamodb_table").(string)
	if b.ddbTable == "" {
		// try the depracted field
		b.ddbTable = data.Get("lock_table").(string)
	}

	cfg := &terraformAWS.Config{
		AccessKey:             data.Get("access_key").(string),
		AssumeRoleARN:         data.Get("role_arn").(string),
		AssumeRoleExternalID:  data.Get("external_id").(string),
		AssumeRolePolicy:      data.Get("assume_role_policy").(string),
		AssumeRoleSessionName: data.Get("session_name").(string),
		CredsFilename:         data.Get("shared_credentials_file").(string),
		Profile:               data.Get("profile").(string),
		Region:                data.Get("region").(string),
		S3Endpoint:            data.Get("endpoint").(string),
		SecretKey:             data.Get("secret_key").(string),
		Token:                 data.Get("token").(string),
	}

	client, err := cfg.Client()
	if err != nil {
		return err
	}

	b.s3Client = client.(*terraformAWS.AWSClient).S3()
	b.dynClient = client.(*terraformAWS.AWSClient).DynamoDB()

	return nil
}
<commit_msg>rename aws provider import in s3 backend<commit_after>package s3

import (
	"context"

	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/helper/schema"

	terraformAWS "github.com/terraform-providers/terraform-provider-aws/aws"
)

// New creates a new backend for S3 remote state.
func New() backend.Backend {
	s := &schema.Backend{
		Schema: map[string]*schema.Schema{
			"bucket": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The name of the S3 bucket",
			},

			"key": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The path to the state file inside the bucket",
			},

			"region": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The region of the S3 bucket.",
				DefaultFunc: schema.EnvDefaultFunc("AWS_DEFAULT_REGION", nil),
			},

			"endpoint": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "A custom endpoint for the S3 API",
				DefaultFunc: schema.EnvDefaultFunc("AWS_S3_ENDPOINT", ""),
			},

			"encrypt": {
				Type:        schema.TypeBool,
				Optional:    true,
				Description: "Whether to enable server side encryption of the state file",
				Default:     false,
			},

			"acl": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Canned ACL to be applied to the state file",
				Default:     "",
			},

			"access_key": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "AWS access key",
				Default:     "",
			},

			"secret_key": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "AWS secret key",
				Default:     "",
			},

			"kms_key_id": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The ARN of a KMS Key to use for encrypting the state",
				Default:     "",
			},

			"lock_table": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "DynamoDB table for state locking",
				Default:     "",
				Deprecated:  "please use the dynamodb_table attribute",
			},

			"dynamodb_table": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "DynamoDB table for state locking and consistency",
				Default:     "",
			},

			"profile": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "AWS profile name",
				Default:     "",
			},

			"shared_credentials_file": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Path to a shared credentials file",
				Default:     "",
			},

			"token": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "MFA token",
				Default:     "",
			},

			"role_arn": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The role to be assumed",
				Default:     "",
			},

			"session_name": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The session name to use when assuming the role.",
				Default:     "",
			},

			"external_id": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The external ID to use when assuming the role",
				Default:     "",
			},

			"assume_role_policy": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The permissions applied when assuming a role.",
				Default:     "",
			},
		},
	}

	result := &Backend{Backend: s}
	result.Backend.ConfigureFunc = result.configure
	return result
}

type Backend struct {
	*schema.Backend

	// The fields below are set from configure
	s3Client  *s3.S3
	dynClient *dynamodb.DynamoDB

	bucketName           string
	keyName              string
	serverSideEncryption bool
	acl                  string
	kmsKeyID             string
	ddbTable             string
}

func (b *Backend) configure(ctx context.Context) error {
	if b.s3Client != nil {
		return nil
	}

	// Grab the resource data
	data := schema.FromContextBackendConfig(ctx)

	b.bucketName = data.Get("bucket").(string)
	b.keyName = data.Get("key").(string)
	b.serverSideEncryption = data.Get("encrypt").(bool)
	b.acl = data.Get("acl").(string)
	b.kmsKeyID = data.Get("kms_key_id").(string)

	b.ddbTable = data.Get("dynamodb_table").(string)
	if b.ddbTable == "" {
		// try the depracted field
		b.ddbTable = data.Get("lock_table").(string)
	}

	cfg := &terraformAWS.Config{
		AccessKey:             data.Get("access_key").(string),
		AssumeRoleARN:         data.Get("role_arn").(string),
		AssumeRoleExternalID:  data.Get("external_id").(string),
		AssumeRolePolicy:      data.Get("assume_role_policy").(string),
		AssumeRoleSessionName: data.Get("session_name").(string),
		CredsFilename:         data.Get("shared_credentials_file").(string),
		Profile:               data.Get("profile").(string),
		Region:                data.Get("region").(string),
		S3Endpoint:            data.Get("endpoint").(string),
		SecretKey:             data.Get("secret_key").(string),
		Token:                 data.Get("token").(string),
	}

	client, err := cfg.Client()
	if err != nil {
		return err
	}

	b.s3Client = client.(*terraformAWS.AWSClient).S3()
	b.dynClient = client.(*terraformAWS.AWSClient).DynamoDB()

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

type Mutator interface {
	Mutate(ast.Node) (func(), bool)
	Name() string
}

type AST struct {
	mtx  sync.Mutex
	fset *token.FileSet
	pkgs map[string]*ast.Package
}

func newAST(filename string) (*AST, error) {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, filename, nil, 0)
	if err != nil {
		return nil, err
	}

	return &AST{
		fset: fset,
		pkgs: pkgs,
	}, nil
}

func (a *AST) ApplyMutation(m Mutator) {
	visitor := newNodeVisitor(a, m)
	a.forEachFile(func(name string, file *ast.File) error {
		ast.Walk(visitor, file)
		return nil
	})
}

func (a *AST) forEachFile(fn func(string, *ast.File) error) error {
	for _, pkg := range a.pkgs {
		for fname, ast := range pkg.Files {
			if err := fn(fname, ast); err != nil {
				return err
			}
		}
	}
	return nil
}

func (a *AST) write(basepath string) error {
	return a.forEachFile(func(name string, ast *ast.File) error {
		name = strings.TrimPrefix(name, wd)
		filename := filepath.Join(basepath, name)
		if err := os.MkdirAll(filepath.Dir(filename), 0777); err != nil {
			return err
		}

		file, err := os.Create(filename)
		if err != nil {
			return err
		}
		defer file.Close()

		err = printer.Fprint(file, a.fset, ast)
		if err != nil {
			return err
		}

		return nil
	})
}
<commit_msg>parsing the fileset when creating the ast so that we have access to the individual file when creating a mutant<commit_after>package main

import (
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"
	"path/filepath"
	"sync"
)

type Mutator interface {
	Mutate(ast.Node) (func(), bool)
	Name() string
}

type AST struct {
	mtx   sync.Mutex
	fset  *token.FileSet
	pkgs  map[string]*ast.Package
	files map[string]*token.File
}

func newAST(filename string) (*AST, error) {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, filename, nil, 0)
	if err != nil {
		return nil, err
	}

	a := &AST{
		fset:  fset,
		pkgs:  pkgs,
		files: map[string]*token.File{},
	}
	fset.Iterate(func(f *token.File) bool {
		a.files[trimWD(f.Name())] = f
		return true
	})

	return a, nil
}

func (a *AST) ApplyMutation(m Mutator) {
	a.forEachFile(func(name string, file *ast.File) error {
		visitor := newNodeVisitor(a, a.files[name], m)
		ast.Walk(visitor, file)
		return nil
	})
}

func (a *AST) forEachFile(fn func(string, *ast.File) error) error {
	for _, pkg := range a.pkgs {
		for fname, ast := range pkg.Files {
			fname = trimWD(fname)
			if err := fn(fname, ast); err != nil {
				return err
			}
		}
	}
	return nil
}

func (a *AST) write(basepath string) error {
	return a.forEachFile(func(name string, ast *ast.File) error {
		filename := filepath.Join(basepath, name)
		if err := os.MkdirAll(filepath.Dir(filename), 0777); err != nil {
			return err
		}

		file, err := os.Create(filename)
		if err != nil {
			return err
		}
		defer file.Close()

		err = printer.Fprint(file, a.fset, ast)
		if err != nil {
			return err
		}

		return nil
	})
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"unicode"
)

func ParseCmdLine() string {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "bambam needs exactly one golang source file to process.\n")
		os.Exit(1)
	}
	fn := os.Args[1]
	if !strings.HasSuffix(fn, ".go") {
		fmt.Fprintf(os.Stderr, "error: bambam input file '%s' did not end in '.go'.\n")
		os.Exit(1)
	}
	return fn
}

func main() {
	readMe := ParseCmdLine()

	x := NewExtractor()
	x.Init()

	by := x.AssembleCapnpFile(ExtractStructs(readMe, nil))
	os.Stdout.Write(by.Bytes())
	fmt.Printf("\n")
	fmt.Printf("##compile with:\n\n##   capnp compile -ogo yourfile.capnp\n\n")
}

type Extractor struct {
	fieldCount int
	out        bytes.Buffer
	pkgName    string
	importDecl string

	// for testing purposes
	myCounts []int
	myNames  []string
}

func NewExtractor() *Extractor {
	return &Extractor{
		pkgName:    "testpkg",
		importDecl: "testpkg",
	}
}

func ExtractFromString(src string) []byte {
	return ExtractStructs("", "package main; "+src)
}

func ExtractString2String(src string) string {
	return string(ExtractStructs("", "package main; "+src))
}

// ExtractStructs pulls out the struct definitions from a golang source file.
//
// src has to be string, []byte, or io.Reader, as in parser.ParseFile(). src
// can be nil if fname is provided. See http://golang.org/pkg/go/parser/#ParseFile
//
func ExtractStructs(fname string, src interface{}) []byte {

	x := NewExtractor()
	x.Init()

	fset := token.NewFileSet() // positions are relative to fset

	f, err := parser.ParseFile(fset, fname, src, parser.ParseComments)
	if err != nil {
		panic(err)
	}

	//	fmt.Printf("parsed output f.Decls is:\n")
	//	goon.Dump(f.Decls)

	//fmt.Printf("len(f.Decls) = %d\n", len(f.Decls))

	for _, v := range f.Decls {
		switch v.(type) {
		case *ast.GenDecl:
			d := v.(*ast.GenDecl)
			//fmt.Printf("dump of d, an %#v = \n", ty)
			//goon.Dump(d)

			//fmt.Printf("\n\n\n  detail dump of d.Specs\n")
			for _, spe := range d.Specs {
				switch spe.(type) {
				case (*ast.TypeSpec):

					// go back and print the comments
					if d.Doc != nil && d.Doc.List != nil && len(d.Doc.List) > 0 {
						for _, com := range d.Doc.List {
							x.GenerateComment(com.Text)
						}
					}

					typeSpec := spe.(*ast.TypeSpec)
					//fmt.Printf("\n\n *ast.TypeSpec spe = \n")

					if typeSpec.Name.Obj.Kind == ast.Typ {

						switch typeSpec.Name.Obj.Decl.(type) {
						case (*ast.TypeSpec):
							//curStructName := typeSpec.Name.String()
							curStructName := typeSpec.Name.Name
							ts2 := typeSpec.Name.Obj.Decl.(*ast.TypeSpec)

							//fmt.Printf("\n\n  in ts2 = %#v\n", ts2)
							//goon.Dump(ts2)

							switch ts2.Type.(type) {
							default:
								// *ast.InterfaceType and *ast.Ident end up here.
								//fmt.Printf("\n\n unrecog type ty = %#v\n", ty)
							case (*ast.StructType):
								stru := ts2.Type.(*ast.StructType)

								x.StartStruct(curStructName)
								//fmt.Printf("\n\n stru = %#v\n", stru)
								//goon.Dump(stru)

								if stru.Fields != nil {
									for _, fld := range stru.Fields.List {
										if fld != nil {
											//fmt.Printf("\n\n    fld.Names = %#v\n", fld.Names) // looking for
											//goon.Dump(fld.Names)

											if len(fld.Names) == 0 {
												// field without name: embedded/anonymous struct
												x.GenerateEmbedded(fld.Type.(*ast.Ident).Name)

											} else {
												// field with name
												for _, ident := range fld.Names {

													switch ident.Obj.Decl.(type) {
													case (*ast.Field):
														// named field
														fld2 := ident.Obj.Decl.(*ast.Field)

														//fmt.Printf("\n\n    fld2 = %#v\n", fld2)
														//goon.Dump(fld2)

														switch fld2.Type.(type) {
														case (*ast.Ident):
															ident2 := fld2.Type.(*ast.Ident)
															x.GenerateStructField(ident.Name, ident2.Name, fld2, NotList)
														case (*ast.ArrayType):
															// slice or array
															ident2 := fld2.Type.(*ast.ArrayType)
															switch ident2.Elt.(type) {
															case (*ast.Ident):
																x.GenerateStructField(ident.Name, ident2.Elt.(*ast.Ident).Name, fld2, YesIsList)
															case (*ast.StarExpr):
																x.GenerateStructField(ident.Name, ident2.Elt.(*ast.StarExpr).X.(*ast.Ident).Name, fld2, YesIsList)
															}
														}
													}
												}
											}

										}
									}
								}

								//fmt.Printf("} // end of %s \n\n", typeSpec.Name) // prod
								x.EndStruct()

								//goon.Dump(stru)
								//fmt.Printf("\n =========== end stru =======\n\n\n")
							}
						}

						//fmt.Printf("spe.Name.Obj.Kind = %s\n", typeSpec.Name.Obj.Kind)

						//fmt.Printf("spe.Name.Obj = %#v\n", typeSpec.Name.Obj)
						//goon.Dump(typeSpec.Name.Obj)

						//fmt.Printf("spe.Name.Obj.Decl = %#v\n", typeSpec.Name.Obj.Decl)
						//goon.Dump(typeSpec.Name.Obj.Decl)
					}

				}
			}
		}
	}

	return x.out.Bytes()
}

func (x *Extractor) Init() {
	//fmt.Fprintf(&x.out, "package main; func main(){println(`extractor output ran fine.`)}\n")
}
func (x *Extractor) StartStruct(name string) {
	x.fieldCount = 0
	cname := UppercaseCapnpTypeName(name)
	fmt.Fprintf(&x.out, "struct %s { ", cname)
}
func (x *Extractor) EndStruct() {
	fmt.Fprintf(&x.out, "} ")
}

func (x *Extractor) GenerateComment(c string) {
	skipCommentsForNow := false
	if !skipCommentsForNow {
		fmt.Fprintf(&x.out, "%s\n", c) // prod
	}
}

func UppercaseCapnpTypeName(name string) string {
	if len(name) == 0 {
		return name
	}

	// gotta upercase the first letter of type (struct) names
	runes := []rune(name)
	runes[0] = unicode.ToUpper(runes[0])
	return string(runes)

}

func LowercaseCapnpFieldName(name string) string {
	if len(name) == 0 {
		return name
	}

	// gotta lowercase the first letter of field names
	runes := []rune(name)
	runes[0] = unicode.ToLower(runes[0])
	return string(runes)
}

const YesIsList = true
const NotList = false

func (x *Extractor) GenerateStructField(name string, typeName string, fld *ast.Field, isList bool) {

	loweredName := LowercaseCapnpFieldName(name)
	typeDisplayed := UppercaseCapnpTypeName(typeName)

	switch typeName {
	case "string":
		typeDisplayed = "Text"
	case "int":
		typeDisplayed = "Int64"
	case "bool":
		typeDisplayed = "Bool"
	case "int8":
		typeDisplayed = "Int8"
	case "int16":
		typeDisplayed = "Int16"
	case "int32":
		typeDisplayed = "Int32"
	case "int64":
		typeDisplayed = "Int64"
	case "uint8":
		typeDisplayed = "UInt8"
	case "uint16":
		typeDisplayed = "UInt16"
	case "uint32":
		typeDisplayed = "UInt32"
	case "uint64":
		typeDisplayed = "UInt64"
	case "float32":
		typeDisplayed = "Float32"
	case "float64":
		typeDisplayed = "Float64"
	case "byte":
		if isList {
			typeDisplayed = "Data"
			isList = false
		} else {
			typeDisplayed = "Uint8"
		}
	}

	if isList {
		fmt.Fprintf(&x.out, "%s @%d: List(%s); ", loweredName, x.fieldCount, typeDisplayed)
	} else {
		fmt.Fprintf(&x.out, "%s @%d: %s; ", loweredName, x.fieldCount, typeDisplayed)
	}
	x.fieldCount++
}

func (x *Extractor) GenerateEmbedded(typeName string) {
	fmt.Fprintf(&x.out, "%s; ", typeName) // prod
}

func getNewCapnpId() string {
	id, err := exec.Command("capnp", "id").CombinedOutput()
	if err != nil {
		panic(err)
	}
	n := len(id)
	if n > 0 {
		id = id[:n-1]
	}

	return string(id)
}

func (x *Extractor) AssembleCapnpFile(in []byte) *bytes.Buffer {
	var by bytes.Buffer

	id := getNewCapnpId()

	fmt.Fprintf(&by, `%s;
using Go = import "go.capnp";
$Go.package("%s");
$Go.import("%s");
`, id, x.pkgName, x.importDecl)
	by.Write(in)
	fmt.Fprintf(&by, "\n")

	return &by
}

func CapnpCompileFragment(in []byte) []byte {
	x := NewExtractor()
	return x.CapnpCompileFragment(in)
}

func (x *Extractor) CapnpCompileFragment(in []byte) []byte {

	f, err := ioutil.TempFile(".", "capnp.test.")
	if err != nil {
		panic(err)
	}
	defer os.Remove(f.Name())

	by := x.AssembleCapnpFile(in)
	debug := string(by.Bytes())

	f.Write(by.Bytes())
	f.Close()

	compiled, err := CapnpCompilePath(f.Name())
	if err != nil {
		return []byte(fmt.Sprintf("error compiling the generated capnp code: '%s'; error: '%s'\n", debug, err) + string(compiled))
	}

	return compiled
}

func CapnpCompilePath(fname string) ([]byte, error) {
	defer os.Remove(fname + ".go")

	by, err := exec.Command("capnp", "compile", "-ogo", fname).CombinedOutput()
	if err != nil {
		return by, err
	}
	return by, nil
}
<commit_msg>atg. prettier output.<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"unicode"
)

func ParseCmdLine() string {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "bambam needs exactly one golang source file to process.\n")
		os.Exit(1)
	}
	fn := os.Args[1]
	if !strings.HasSuffix(fn, ".go") {
		fmt.Fprintf(os.Stderr, "error: bambam input file '%s' did not end in '.go'.\n")
		os.Exit(1)
	}
	return fn
}

func main() {
	readMe := ParseCmdLine()

	x := NewExtractor()
	x.fieldPrefix = "   "
	x.fieldSuffix = "\n"

	by := x.AssembleCapnpFile(ExtractStructs(readMe, nil, x))
	os.Stdout.Write(by.Bytes())
	fmt.Printf("\n")
	fmt.Printf("##compile with:\n\n##   capnp compile -ogo yourfile.capnp\n\n")
}

type Extractor struct {
	fieldCount  int
	out         bytes.Buffer
	pkgName     string
	importDecl  string
	fieldPrefix string
	fieldSuffix string

	// for testing purposes
	myCounts *Extractor
	myNames  []string
}

func NewExtractor() *Extractor {
	return &Extractor{
		pkgName:    "testpkg",
		importDecl: "testpkg",
	}
}

func ExtractFromString(src string) []byte {
	return ExtractStructs("", "package main; "+src, nil)
}

func ExtractString2String(src string) string {
	return string(ExtractStructs("", "package main; "+src, nil))
}

// ExtractStructs pulls out the struct definitions from a golang source file.
//
// src has to be string, []byte, or io.Reader, as in parser.ParseFile(). src
// can be nil if fname is provided. See http://golang.org/pkg/go/parser/#ParseFile
//
func ExtractStructs(fname string, src interface{}, x *Extractor) []byte {

	if x == nil {
		x = NewExtractor()
	}

	fset := token.NewFileSet() // positions are relative to fset

	f, err := parser.ParseFile(fset, fname, src, parser.ParseComments)
	if err != nil {
		panic(err)
	}

	//	fmt.Printf("parsed output f.Decls is:\n")
	//	goon.Dump(f.Decls)

	//fmt.Printf("len(f.Decls) = %d\n", len(f.Decls))

	for _, v := range f.Decls {
		switch v.(type) {
		case *ast.GenDecl:
			d := v.(*ast.GenDecl)
			//fmt.Printf("dump of d, an %#v = \n", ty)
			//goon.Dump(d)

			//fmt.Printf("\n\n\n  detail dump of d.Specs\n")
			for _, spe := range d.Specs {
				switch spe.(type) {
				case (*ast.TypeSpec):

					// go back and print the comments
					if d.Doc != nil && d.Doc.List != nil && len(d.Doc.List) > 0 {
						for _, com := range d.Doc.List {
							x.GenerateComment(com.Text)
						}
					}

					typeSpec := spe.(*ast.TypeSpec)
					//fmt.Printf("\n\n *ast.TypeSpec spe = \n")

					if typeSpec.Name.Obj.Kind == ast.Typ {

						switch typeSpec.Name.Obj.Decl.(type) {
						case (*ast.TypeSpec):
							//curStructName := typeSpec.Name.String()
							curStructName := typeSpec.Name.Name
							ts2 := typeSpec.Name.Obj.Decl.(*ast.TypeSpec)

							//fmt.Printf("\n\n  in ts2 = %#v\n", ts2)
							//goon.Dump(ts2)

							switch ts2.Type.(type) {
							default:
								// *ast.InterfaceType and *ast.Ident end up here.
								//fmt.Printf("\n\n unrecog type ty = %#v\n", ty)
							case (*ast.StructType):
								stru := ts2.Type.(*ast.StructType)

								x.StartStruct(curStructName)
								//fmt.Printf("\n\n stru = %#v\n", stru)
								//goon.Dump(stru)

								if stru.Fields != nil {
									for _, fld := range stru.Fields.List {
										if fld != nil {
											//fmt.Printf("\n\n    fld.Names = %#v\n", fld.Names) // looking for
											//goon.Dump(fld.Names)

											if len(fld.Names) == 0 {
												// field without name: embedded/anonymous struct
												x.GenerateEmbedded(fld.Type.(*ast.Ident).Name)

											} else {
												// field with name
												for _, ident := range fld.Names {

													switch ident.Obj.Decl.(type) {
													case (*ast.Field):
														// named field
														fld2 := ident.Obj.Decl.(*ast.Field)

														//fmt.Printf("\n\n    fld2 = %#v\n", fld2)
														//goon.Dump(fld2)

														switch fld2.Type.(type) {

														case (*ast.StarExpr):
															star2 := fld2.Type.(*ast.StarExpr)
															x.GenerateStructField(ident.Name, star2.X.(*ast.Ident).Name, fld2, NotList)

														case (*ast.Ident):
															ident2 := fld2.Type.(*ast.Ident)
															x.GenerateStructField(ident.Name, ident2.Name, fld2, NotList)
														case (*ast.ArrayType):
															// slice or array
															array2 := fld2.Type.(*ast.ArrayType)
															switch array2.Elt.(type) {
															case (*ast.Ident):
																x.GenerateStructField(ident.Name, array2.Elt.(*ast.Ident).Name, fld2, YesIsList)
															case (*ast.StarExpr):
																x.GenerateStructField(ident.Name, array2.Elt.(*ast.StarExpr).X.(*ast.Ident).Name, fld2, YesIsList)
															}
														}
													}
												}
											}

										}
									}
								}

								//fmt.Printf("} // end of %s \n\n", typeSpec.Name) // prod
								x.EndStruct()

								//goon.Dump(stru)
								//fmt.Printf("\n =========== end stru =======\n\n\n")
							}
						}

						//fmt.Printf("spe.Name.Obj.Kind = %s\n", typeSpec.Name.Obj.Kind)

						//fmt.Printf("spe.Name.Obj = %#v\n", typeSpec.Name.Obj)
						//goon.Dump(typeSpec.Name.Obj)

						//fmt.Printf("spe.Name.Obj.Decl = %#v\n", typeSpec.Name.Obj.Decl)
						//goon.Dump(typeSpec.Name.Obj.Decl)
					}

				}
			}
		}
	}

	return x.out.Bytes()
}

func (x *Extractor) StartStruct(name string) {
	x.fieldCount = 0
	cname := UppercaseCapnpTypeName(name)
	fmt.Fprintf(&x.out, "struct %s { %s", cname, x.fieldSuffix)
}
func (x *Extractor) EndStruct() {
	fmt.Fprintf(&x.out, "} %s", x.fieldSuffix)
}

func (x *Extractor) GenerateComment(c string) {
	skipCommentsForNow := false
	if !skipCommentsForNow {
		fmt.Fprintf(&x.out, "%s\n", c) // prod
	}
}

func UppercaseCapnpTypeName(name string) string {
	if len(name) == 0 {
		return name
	}

	// gotta upercase the first letter of type (struct) names
	runes := []rune(name)
	runes[0] = unicode.ToUpper(runes[0])
	return string(runes)

}

func LowercaseCapnpFieldName(name string) string {
	if len(name) == 0 {
		return name
	}

	// gotta lowercase the first letter of field names
	runes := []rune(name)
	runes[0] = unicode.ToLower(runes[0])
	return string(runes)
}

const YesIsList = true
const NotList = false

func (x *Extractor) GenerateStructField(name string, typeName string, fld *ast.Field, isList bool) {

	loweredName := LowercaseCapnpFieldName(name)
	typeDisplayed := UppercaseCapnpTypeName(typeName)

	switch typeName {
	case "string":
		typeDisplayed = "Text"
	case "int":
		typeDisplayed = "Int64"
	case "bool":
		typeDisplayed = "Bool"
	case "int8":
		typeDisplayed = "Int8"
	case "int16":
		typeDisplayed = "Int16"
	case "int32":
		typeDisplayed = "Int32"
	case "int64":
		typeDisplayed = "Int64"
	case "uint8":
		typeDisplayed = "UInt8"
	case "uint16":
		typeDisplayed = "UInt16"
	case "uint32":
		typeDisplayed = "UInt32"
	case "uint64":
		typeDisplayed = "UInt64"
	case "float32":
		typeDisplayed = "Float32"
	case "float64":
		typeDisplayed = "Float64"
	case "byte":
		if isList {
			typeDisplayed = "Data"
			isList = false
		} else {
			typeDisplayed = "Uint8"
		}
	}

	if isList {
		fmt.Fprintf(&x.out, "%s%s @%d: List(%s); %s", x.fieldPrefix, loweredName, x.fieldCount, typeDisplayed, x.fieldSuffix)
	} else {
		fmt.Fprintf(&x.out, "%s%s @%d: %s; %s", x.fieldPrefix, loweredName, x.fieldCount, typeDisplayed, x.fieldSuffix)
	}
	x.fieldCount++
}

func (x *Extractor) GenerateEmbedded(typeName string) {
	fmt.Fprintf(&x.out, "%s; ", typeName) // prod
}

func getNewCapnpId() string {
	id, err := exec.Command("capnp", "id").CombinedOutput()
	if err != nil {
		panic(err)
	}
	n := len(id)
	if n > 0 {
		id = id[:n-1]
	}

	return string(id)
}

func (x *Extractor) AssembleCapnpFile(in []byte) *bytes.Buffer {
	var by bytes.Buffer

	id := getNewCapnpId()

	fmt.Fprintf(&by, `%s;
using Go = import "go.capnp";
$Go.package("%s");
$Go.import("%s");
%s`, id, x.pkgName, x.importDecl, x.fieldSuffix)
	by.Write(in)
	fmt.Fprintf(&by, "\n")

	return &by
}

func CapnpCompileFragment(in []byte) []byte {
	x := NewExtractor()
	return x.CapnpCompileFragment(in)
}

func (x *Extractor) CapnpCompileFragment(in []byte) []byte {

	f, err := ioutil.TempFile(".", "capnp.test.")
	if err != nil {
		panic(err)
	}
	defer os.Remove(f.Name())

	by := x.AssembleCapnpFile(in)
	debug := string(by.Bytes())

	f.Write(by.Bytes())
	f.Close()

	compiled, err := CapnpCompilePath(f.Name())
	if err != nil {
		return []byte(fmt.Sprintf("error compiling the generated capnp code: '%s'; error: '%s'\n", debug, err) + string(compiled))
	}

	return compiled
}

func CapnpCompilePath(fname string) ([]byte, error) {
	defer os.Remove(fname + ".go")

	by, err := exec.Command("capnp", "compile", "-ogo", fname).CombinedOutput()
	if err != nil {
		return by, err
	}
	return by, nil
}
<|endoftext|>


<commit_before>package admin_test

import (
	"testing"

	_ "github.com/mattn/go-sqlite3"
	"github.com/qor/qor"
	"github.com/qor/qor/admin"
	"github.com/qor/qor/resource"
)

func TestTextInput(t *testing.T) {
	user := Admin.AddResource(&User{})
	meta := &admin.Meta{Name: "Name"}
	user.Meta(meta)

	if meta.Label != "Name" {
		t.Error("default label not set")
	}

	if meta.Alias != "Name" {
		t.Error("default Alias is not same as field Name")
	}

	if meta.Type != "string" {
		t.Error("default Type is not string")
	}

	oldUserName := "old name"
	newUserName := "new name"

	// Valuer
	userRecord := &User{Name: oldUserName}
	db.Create(&userRecord)
	value := meta.Valuer(userRecord, &qor.Context{Config: &qor.Config{DB: &db}})

	if *value.(*string) != oldUserName {
		t.Error("resource's value doesn't get")
	}

	// Setter
	metaValue := &resource.MetaValue{
		Name:  "User.Name",
		Value: newUserName,
		Meta:  meta,
	}

	meta.Setter(userRecord, metaValue, &qor.Context{Config: &qor.Config{DB: &db}})
	if userRecord.Name != newUserName {
		t.Error("resource's value doesn't set")
	}
}

// TODO: there maybe a bug of file Type meta generation meta.go#L142
func TestDefaultMetaType(t *testing.T) {
	user := Admin.AddResource(&User{})
	booleanMeta := &admin.Meta{Name: "Active"}
	timeMeta := &admin.Meta{Name: "RegisteredAt"}
	numberMeta := &admin.Meta{Name: "CreditCardId"}
	// fileMeta := &admin.Meta{Name: "Avatar"}
	user.Meta(booleanMeta)
	user.Meta(timeMeta)
	user.Meta(numberMeta)
	// user.Meta(fileMeta)

	if booleanMeta.Type != "checkbox" {
		t.Error("boolean field doesn't set as checkbox")
	}

	if timeMeta.Type != "datetime" {
		t.Error("time field doesn't set as datetime")
	}

	if numberMeta.Type != "number" {
		t.Error("number field doesn't set as number")
	}

	// if fileMeta.Type != "file" {
	// 	t.Error("file field doesn't set as file")
	// }
}

func TestMeta(t *testing.T) {
	profileModel := Profile{
		Name:  "Qor",
		Sex:   "Female",
		Phone: Phone{Num: "1024"},
	}
	userModel := &User{Profile: profileModel}
	db.Create(userModel)

	user := Admin.AddResource(&User{})
	profileNameMeta := &admin.Meta{Name: "Profile.Name"}
	user.Meta(profileNameMeta)
	profileSexMeta := &admin.Meta{Name: "Profile.Sex"}
	user.Meta(profileSexMeta)
	phoneNumMeta := &admin.Meta{Name: "Profile.Phone.Num"}
	user.Meta(phoneNumMeta)

	userModel.Profile = Profile{}
	valx := phoneNumMeta.Valuer(userModel, &qor.Context{Config: &qor.Config{DB: &db}})
	if val, ok := valx.(*string); !ok || *val != profileModel.Phone.Num {
		t.Errorf("Profile.Phone.Num: got %q; expect %q", *val, profileModel.Phone.Num)
	}
	if userModel.Profile.Name != profileModel.Name {
		t.Errorf("Profile.Name: got %q; expect %q", userModel.Profile.Name, profileModel.Name)
	}
	if userModel.Profile.Sex != profileModel.Sex {
		t.Errorf("Profile.Sex: got %q; expect %q", userModel.Profile.Sex, profileModel.Sex)
	}
	if userModel.Profile.Phone.Num != profileModel.Phone.Num {
		t.Errorf("Profile.Phone.Num: got %q; expect %q", userModel.Profile.Phone.Num, profileModel.Phone.Num)
	}

	mvs := &resource.MetaValues{
		Values: []*resource.MetaValue{
			&resource.MetaValue{
				Name:  "Profile.Name",
				Value: "Qor III",
				Meta:  profileNameMeta,
			},
			&resource.MetaValue{
				Name:  "Profile.Sex",
				Value: "Male",
				Meta:  profileSexMeta,
			},
			&resource.MetaValue{
				Name:  "Profile.Phone.Num",
				Value: "2048",
				Meta:  phoneNumMeta,
			},
		},
	}
	profileNameMeta.Setter(userModel, mvs.Values[0], &qor.Context{Config: &qor.Config{DB: &db}})
	if userModel.Profile.Name != mvs.Values[0].Value {
		t.Errorf("Profile.Name: got %q; expect %q", userModel.Profile.Name, mvs.Values[0].Value)
	}
	profileSexMeta.Setter(userModel, mvs.Values[1], &qor.Context{Config: &qor.Config{DB: &db}})
	if userModel.Profile.Sex != mvs.Values[1].Value {
		t.Errorf("Profile.Sex: got %q; expect %q", userModel.Profile.Sex, mvs.Values[1].Value)
	}
	phoneNumMeta.Setter(userModel, mvs.Values[2], &qor.Context{Config: &qor.Config{DB: &db}})
	if userModel.Profile.Phone.Num != mvs.Values[2].Value {
		t.Errorf("Profile.Phone.Num: got %q; expect %q", userModel.Profile.Phone.Num, mvs.Values[2].Value)
	}
}
<commit_msg>Relational field meta type test.<commit_after>package admin_test

import (
	"testing"

	_ "github.com/mattn/go-sqlite3"
	"github.com/qor/qor"
	"github.com/qor/qor/admin"
	"github.com/qor/qor/resource"
)

func TestTextInput(t *testing.T) {
	user := Admin.AddResource(&User{})
	meta := &admin.Meta{Name: "Name"}
	user.Meta(meta)

	if meta.Label != "Name" {
		t.Error("default label not set")
	}

	if meta.Alias != "Name" {
		t.Error("default Alias is not same as field Name")
	}

	if meta.Type != "string" {
		t.Error("default Type is not string")
	}

	oldUserName := "old name"
	newUserName := "new name"

	// Valuer
	userRecord := &User{Name: oldUserName}
	db.Create(&userRecord)
	value := meta.Valuer(userRecord, &qor.Context{Config: &qor.Config{DB: &db}})

	if *value.(*string) != oldUserName {
		t.Error("resource's value doesn't get")
	}

	// Setter
	metaValue := &resource.MetaValue{
		Name:  "User.Name",
		Value: newUserName,
		Meta:  meta,
	}

	meta.Setter(userRecord, metaValue, &qor.Context{Config: &qor.Config{DB: &db}})
	if userRecord.Name != newUserName {
		t.Error("resource's value doesn't set")
	}
}

// TODO: there maybe a bug of file Type meta generation meta.go#L142
func TestDefaultMetaType(t *testing.T) {
	user := Admin.AddResource(&User{})
	booleanMeta := &admin.Meta{Name: "Active"}
	timeMeta := &admin.Meta{Name: "RegisteredAt"}
	numberMeta := &admin.Meta{Name: "CreditCardId"}
	// fileMeta := &admin.Meta{Name: "Avatar"}
	user.Meta(booleanMeta)
	user.Meta(timeMeta)
	user.Meta(numberMeta)
	// user.Meta(fileMeta)

	if booleanMeta.Type != "checkbox" {
		t.Error("boolean field doesn't set as checkbox")
	}

	if timeMeta.Type != "datetime" {
		t.Error("time field doesn't set as datetime")
	}

	if numberMeta.Type != "number" {
		t.Error("number field doesn't set as number")
	}

	// if fileMeta.Type != "file" {
	// 	t.Error("file field doesn't set as file")
	// }
}

func TestRelationFieldMetaType(t *testing.T) {
	userRecord := &User{}
	db.Create(userRecord)

	user := Admin.AddResource(&User{})

	userProfileMeta := &admin.Meta{Name: "Profile"}
	user.Meta(userProfileMeta)

	if userProfileMeta.Type != "single_edit" {
		t.Error("has_one relation doesn't generate single_edit type meta")
	}

	userAddressesMeta := &admin.Meta{Name: "Addresses"}
	user.Meta(userAddressesMeta)

	if userAddressesMeta.Type != "collection_edit" {
		t.Error("has_many relation doesn't generate collection_edit type meta")
	}

	userLanguagesMeta := &admin.Meta{Name: "Languages", Collection: []string{"Fake language"}}
	user.Meta(userLanguagesMeta)

	if userLanguagesMeta.Type != "select_many" {
		t.Error("many_to_many relation doesn't generate select_many type meta")
	}
}

func TestSetMetaValue(t *testing.T) {
}

func TestSetMetaCollection(t *testing.T) {
}

func TestMetaSetter(t *testing.T) {
}

func TestNestedField(t *testing.T) {
}

func TestMeta(t *testing.T) {
	profileModel := Profile{
		Name:  "Qor",
		Sex:   "Female",
		Phone: Phone{Num: "1024"},
	}
	userModel := &User{Profile: profileModel}
	db.Create(userModel)

	user := Admin.AddResource(&User{})
	profileNameMeta := &admin.Meta{Name: "Profile.Name"}
	user.Meta(profileNameMeta)
	profileSexMeta := &admin.Meta{Name: "Profile.Sex"}
	user.Meta(profileSexMeta)
	phoneNumMeta := &admin.Meta{Name: "Profile.Phone.Num"}
	user.Meta(phoneNumMeta)

	userModel.Profile = Profile{}
	valx := phoneNumMeta.Valuer(userModel, &qor.Context{Config: &qor.Config{DB: &db}})
	if val, ok := valx.(*string); !ok || *val != profileModel.Phone.Num {
		t.Errorf("Profile.Phone.Num: got %q; expect %q", *val, profileModel.Phone.Num)
	}
	if userModel.Profile.Name != profileModel.Name {
		t.Errorf("Profile.Name: got %q; expect %q", userModel.Profile.Name, profileModel.Name)
	}
	if userModel.Profile.Sex != profileModel.Sex {
		t.Errorf("Profile.Sex: got %q; expect %q", userModel.Profile.Sex, profileModel.Sex)
	}
	if userModel.Profile.Phone.Num != profileModel.Phone.Num {
		t.Errorf("Profile.Phone.Num: got %q; expect %q", userModel.Profile.Phone.Num, profileModel.Phone.Num)
	}

	mvs := &resource.MetaValues{
		Values: []*resource.MetaValue{
			&resource.MetaValue{
				Name:  "Profile.Name",
				Value: "Qor III",
				Meta:  profileNameMeta,
			},
			&resource.MetaValue{
				Name:  "Profile.Sex",
				Value: "Male",
				Meta:  profileSexMeta,
			},
			&resource.MetaValue{
				Name:  "Profile.Phone.Num",
				Value: "2048",
				Meta:  phoneNumMeta,
			},
		},
	}
	profileNameMeta.Setter(userModel, mvs.Values[0], &qor.Context{Config: &qor.Config{DB: &db}})
	if userModel.Profile.Name != mvs.Values[0].Value {
		t.Errorf("Profile.Name: got %q; expect %q", userModel.Profile.Name, mvs.Values[0].Value)
	}
	profileSexMeta.Setter(userModel, mvs.Values[1], &qor.Context{Config: &qor.Config{DB: &db}})
	if userModel.Profile.Sex != mvs.Values[1].Value {
		t.Errorf("Profile.Sex: got %q; expect %q", userModel.Profile.Sex, mvs.Values[1].Value)
	}
	phoneNumMeta.Setter(userModel, mvs.Values[2], &qor.Context{Config: &qor.Config{DB: &db}})
	if userModel.Profile.Phone.Num != mvs.Values[2].Value {
		t.Errorf("Profile.Phone.Num: got %q; expect %q", userModel.Profile.Phone.Num, mvs.Values[2].Value)
	}
}
<|endoftext|>


<commit_before>/*
fixityworker.go receives GenericFile records from the fixity queue.
It downloads the generic files from S3 preservation storage,
calculates the files' SHA256 checksums and writes the results back
to Fluctus. None of the data downloaded from S3 is saved to disk;
it's simply streamed through the SHA256 hash writer and then discarded.
*/
package workers

import (
	"encoding/json"
	"fmt"
	"github.com/APTrust/bagman/bagman"
	"github.com/nsqio/go-nsq"
	"strings"
	"time"
)

type FixityChecker struct {
	FixityChannel  chan *bagman.FixityResult
	ResultsChannel chan *bagman.FixityResult
	ProcUtil       *bagman.ProcessUtil
}

func NewFixityChecker(procUtil *bagman.ProcessUtil) (*FixityChecker) {
	fixityChecker := &FixityChecker{
		ProcUtil: procUtil,
	}
	workerBufferSize := procUtil.Config.BagDeleteWorker.Workers * 10
	fixityChecker.FixityChannel = make(chan *bagman.FixityResult, workerBufferSize)
	fixityChecker.ResultsChannel = make(chan *bagman.FixityResult, workerBufferSize)
	for i := 0; i < procUtil.Config.BagDeleteWorker.Workers; i++ {
		go fixityChecker.logResult()
		go fixityChecker.checkFile()
	}
	return fixityChecker
}

// MessageHandler handles messages from the queue, putting each
// item into the pipleline.
func (fixityChecker *FixityChecker) HandleMessage(message *nsq.Message) error {
	message.DisableAutoResponse()
	var genericFile bagman.GenericFile
	err := json.Unmarshal(message.Body, &genericFile)
	if err != nil {
		detailedError := fmt.Errorf(
			"Could not unmarshal JSON data from nsq: %v. JSON: %s",
			err, string(message.Body))
		fixityChecker.ProcUtil.MessageLog.Error(detailedError.Error())
		message.Finish()
		return detailedError
	}

	if genericFile.GetChecksum("sha256") == nil {
		detailedError := fmt.Errorf(
			"Cannot check GenericFile %s: it has no SHA256 checksum!",
			genericFile.Identifier)
		fixityChecker.ProcUtil.MessageLog.Error(detailedError.Error())
		message.Finish()
		return detailedError
	}

	result := bagman.NewFixityResult(&genericFile)
	result.NsqMessage = message
	fixityChecker.FixityChannel <- result
	fixityChecker.ProcUtil.MessageLog.Info("Put %s into fixity channel", genericFile.Identifier)
	return nil
}

func (fixityChecker *FixityChecker) logResult() {
	for result := range fixityChecker.ResultsChannel {
		fixityChecker.ProcUtil.MessageLog.Debug("Fedora digest = '%s' ... S3 digest = '%s'",
			result.FedoraSha256(), result.Sha256)
		if result.S3FileExists == false {
			fixityChecker.ProcUtil.MessageLog.Error("GenericFile '%s' with URL '%s' does not exist in S3",
				result.GenericFile.Identifier, result.GenericFile.URI)
			result.NsqMessage.Finish()
			fixityChecker.ProcUtil.IncrementFailed()
			fixityChecker.logStats()
			continue
		}
		// Check failure cases...
		if result.GotDigestFromPreservationFile() == false && result.Retry == true {
			if result.NsqMessage.Attempts >= uint16(fixityChecker.ProcUtil.Config.FixityWorker.MaxAttempts) {
				fixityChecker.ProcUtil.MessageLog.Error(
					"Attempt to calculate checksum for file %s at S3 URL %s has failed too many times. " +
						"This item will not be requeued.",
					result.GenericFile.Identifier,
					result.GenericFile.URI)
				// Too many failures. Send to trouble queue.
				err := bagman.Enqueue(fixityChecker.ProcUtil.Config.NsqdHttpAddress,
					fixityChecker.ProcUtil.Config.FailedFixityWorker.NsqTopic, result)
				if err != nil {
					fixityChecker.ProcUtil.MessageLog.Error("Could not send '%s' to trouble queue: %v",
						result.GenericFile.Identifier, err)
				}
				result.NsqMessage.Finish()
				fixityChecker.ProcUtil.IncrementFailed()
				fixityChecker.logStats()
			} else {
				fixityChecker.ProcUtil.MessageLog.Error(
					"Requeueing %s because fetch from S3 failed, or read from S3 " +
						"datastream failed while calculating checksum. This item is being requeued.",
					result.GenericFile.Identifier)
				result.NsqMessage.Requeue(1 * time.Minute)
				fixityChecker.ProcUtil.IncrementFailed()
				fixityChecker.logStats()
			}
			continue
		}

		// If we got this far, we have enough info to compare checksums.
		eventSaved := fixityChecker.savePremisEvent(result)
		if eventSaved == false {
			fixityChecker.ProcUtil.MessageLog.Error(
				"Requeueing %s because attempt to save event to Fluctus failed",
				result.GenericFile.Identifier)
			result.NsqMessage.Requeue(1 * time.Minute)
			fixityChecker.ProcUtil.IncrementFailed()
		} else {
			fixityChecker.ProcUtil.MessageLog.Info("Finished with %s", result.GenericFile.Identifier)
			fixityChecker.ProcUtil.IncrementSucceeded()
			result.NsqMessage.Finish()
		}
		fixityChecker.logStats()
	}
}

func (fixityChecker *FixityChecker) savePremisEvent(fixityResult *bagman.FixityResult) (bool) {
	premisEvent, err := fixityResult.BuildPremisEvent()
	if err != nil {
		fixityChecker.ProcUtil.MessageLog.Error("Error building PremisEvent for %s: %v",
			fixityResult.GenericFile.Identifier, err)
		return false
	} else {
		_, err := fixityChecker.ProcUtil.FluctusClient.PremisEventSave(
			fixityResult.GenericFile.Identifier,
			"GenericFile",
			premisEvent)
		if err != nil {
			fixityChecker.ProcUtil.MessageLog.Error(
				"Error saving PremisEvent for %s to Fluctus: %v",
				fixityResult.GenericFile.Identifier, err)
			return false
		} else {
			fixityChecker.ProcUtil.MessageLog.Info("Saved PremisEvent for %s",
				fixityResult.GenericFile.Identifier)
		}
	}
	return true
}

func (fixityChecker *FixityChecker) logStats() {
	fixityChecker.ProcUtil.MessageLog.Info("**STATS** Succeeded: %d, Failed: %d",
		fixityChecker.ProcUtil.Succeeded(), fixityChecker.ProcUtil.Failed())
}

// Fetch the file and calculate its SHA256 digest. This may take hours if the
// file is 250GB. Touch the NSQ message on both sides of the operation to
// prevent it from timing out.
func (fixityChecker *FixityChecker) checkFile() {
	for result := range fixityChecker.FixityChannel {
		fixityChecker.ProcUtil.MessageLog.Info("Checking %s", result.GenericFile.Identifier)
		result.NsqMessage.Touch()
		err := fixityChecker.ProcUtil.S3Client.FetchAndCalculateSha256(result, "")
		// Log usage errors. These shouldn't happen.
		if err != nil && strings.Index(err.Error(), "cannot by nil") > 0 {
			fixityChecker.ProcUtil.MessageLog.Error(err.Error())
		}
		result.NsqMessage.Touch()
		fixityChecker.ResultsChannel <- result
	}
}
<commit_msg>Fixed config problem<commit_after>/*
fixityworker.go receives GenericFile records from the fixity queue.
It downloads the generic files from S3 preservation storage,
calculates the files' SHA256 checksums and writes the results back
to Fluctus. None of the data downloaded from S3 is saved to disk;
it's simply streamed through the SHA256 hash writer and then discarded.
*/
package workers

import (
	"encoding/json"
	"fmt"
	"github.com/APTrust/bagman/bagman"
	"github.com/nsqio/go-nsq"
	"strings"
	"time"
)

type FixityChecker struct {
	FixityChannel  chan *bagman.FixityResult
	ResultsChannel chan *bagman.FixityResult
	ProcUtil       *bagman.ProcessUtil
}

func NewFixityChecker(procUtil *bagman.ProcessUtil) (*FixityChecker) {
	fixityChecker := &FixityChecker{
		ProcUtil: procUtil,
	}
	workerBufferSize := procUtil.Config.FixityWorker.Workers * 10
	fixityChecker.FixityChannel = make(chan *bagman.FixityResult, workerBufferSize)
	fixityChecker.ResultsChannel = make(chan *bagman.FixityResult, workerBufferSize)
	fixityChecker.ProcUtil.MessageLog.Info("Starting %d workers with a buffer size of %d",
		procUtil.Config.FixityWorker.Workers, workerBufferSize)
	for i := 0; i < procUtil.Config.FixityWorker.Workers; i++ {
		go fixityChecker.logResult()
		go fixityChecker.checkFile()
	}
	return fixityChecker
}

// MessageHandler handles messages from the queue, putting each
// item into the pipleline.
func (fixityChecker *FixityChecker) HandleMessage(message *nsq.Message) error {
	message.DisableAutoResponse()
	var genericFile bagman.GenericFile
	err := json.Unmarshal(message.Body, &genericFile)
	if err != nil {
		detailedError := fmt.Errorf(
			"Could not unmarshal JSON data from nsq: %v. JSON: %s",
			err, string(message.Body))
		fixityChecker.ProcUtil.MessageLog.Error(detailedError.Error())
		message.Finish()
		return detailedError
	}

	if genericFile.GetChecksum("sha256") == nil {
		detailedError := fmt.Errorf(
			"Cannot check GenericFile %s: it has no SHA256 checksum!",
			genericFile.Identifier)
		fixityChecker.ProcUtil.MessageLog.Error(detailedError.Error())
		message.Finish()
		return detailedError
	}

	result := bagman.NewFixityResult(&genericFile)
	result.NsqMessage = message
	fixityChecker.FixityChannel <- result
	fixityChecker.ProcUtil.MessageLog.Info("Put %s into fixity channel", genericFile.Identifier)
	return nil
}

// Fetch the file and calculate its SHA256 digest. This may take hours if the
// file is 250GB. Touch the NSQ message on both sides of the operation to
// prevent it from timing out.
func (fixityChecker *FixityChecker) checkFile() {
	for result := range fixityChecker.FixityChannel {
		fixityChecker.ProcUtil.MessageLog.Info("Checking %s", result.GenericFile.Identifier)
		result.NsqMessage.Touch()
		err := fixityChecker.ProcUtil.S3Client.FetchAndCalculateSha256(result, "")
		// Log usage errors. These shouldn't happen.
		if err != nil && strings.Index(err.Error(), "cannot be nil") > 0 {
			fixityChecker.ProcUtil.MessageLog.Error(err.Error())
		}
		result.NsqMessage.Touch()
		fixityChecker.ResultsChannel <- result
	}
}

func (fixityChecker *FixityChecker) logResult() {
	for result := range fixityChecker.ResultsChannel {
		fixityChecker.ProcUtil.MessageLog.Debug("Fedora digest = '%s' ... S3 digest = '%s'",
			result.FedoraSha256(), result.Sha256)
		if result.S3FileExists == false {
			fixityChecker.ProcUtil.MessageLog.Error("GenericFile '%s' with URL '%s' does not exist in S3",
				result.GenericFile.Identifier, result.GenericFile.URI)
			result.NsqMessage.Finish()
			fixityChecker.ProcUtil.IncrementFailed()
			fixityChecker.logStats()
			continue
		}
		// Check failure cases...
		if result.GotDigestFromPreservationFile() == false && result.Retry == true {
			if result.NsqMessage.Attempts >= uint16(fixityChecker.ProcUtil.Config.FixityWorker.MaxAttempts) {
				fixityChecker.ProcUtil.MessageLog.Error(
					"Attempt to calculate checksum for file %s at S3 URL %s has failed too many times. " +
						"This item will not be requeued.",
					result.GenericFile.Identifier,
					result.GenericFile.URI)
				// Too many failures. Send to trouble queue.
				err := bagman.Enqueue(fixityChecker.ProcUtil.Config.NsqdHttpAddress,
					fixityChecker.ProcUtil.Config.FailedFixityWorker.NsqTopic, result)
				if err != nil {
					fixityChecker.ProcUtil.MessageLog.Error("Could not send '%s' to trouble queue: %v",
						result.GenericFile.Identifier, err)
				}
				result.NsqMessage.Finish()
				fixityChecker.ProcUtil.IncrementFailed()
				fixityChecker.logStats()
			} else {
				fixityChecker.ProcUtil.MessageLog.Error(
					"Requeueing %s because fetch from S3 failed, or read from S3 " +
						"datastream failed while calculating checksum. This item is being requeued.",
					result.GenericFile.Identifier)
				result.NsqMessage.Requeue(1 * time.Minute)
				fixityChecker.ProcUtil.IncrementFailed()
				fixityChecker.logStats()
			}
			continue
		}

		// If we got this far, we have enough info to compare checksums.
		eventSaved := fixityChecker.savePremisEvent(result)
		if eventSaved == false {
			fixityChecker.ProcUtil.MessageLog.Error(
				"Requeueing %s because attempt to save event to Fluctus failed",
				result.GenericFile.Identifier)
			result.NsqMessage.Requeue(1 * time.Minute)
			fixityChecker.ProcUtil.IncrementFailed()
		} else {
			fixityChecker.ProcUtil.MessageLog.Info("Finished with %s", result.GenericFile.Identifier)
			fixityChecker.ProcUtil.IncrementSucceeded()
			result.NsqMessage.Finish()
		}
		fixityChecker.logStats()
	}
}

func (fixityChecker *FixityChecker) savePremisEvent(fixityResult *bagman.FixityResult) (bool) {
	premisEvent, err := fixityResult.BuildPremisEvent()
	if err != nil {
		fixityChecker.ProcUtil.MessageLog.Error("Error building PremisEvent for %s: %v",
			fixityResult.GenericFile.Identifier, err)
		return false
	}
	if premisEvent.Outcome == "failure" {
		fixityChecker.ProcUtil.MessageLog.Error("SHA256 CHECKSUM DOES NOT MATCH FOR GENERIC FILE %s",
			fixityResult.GenericFile.Identifier)
	}
	_, err = fixityChecker.ProcUtil.FluctusClient.PremisEventSave(
		fixityResult.GenericFile.Identifier,
		"GenericFile",
		premisEvent)
	if err != nil {
		fixityChecker.ProcUtil.MessageLog.Error(
			"Error saving PremisEvent for %s to Fluctus: %v",
			fixityResult.GenericFile.Identifier, err)
		return false
	} else {
		fixityChecker.ProcUtil.MessageLog.Info("Saved PremisEvent for %s",
			fixityResult.GenericFile.Identifier)
	}
	return true
}

func (fixityChecker *FixityChecker) logStats() {
	fixityChecker.ProcUtil.MessageLog.Info("**STATS** Succeeded: %d, Failed: %d",
		fixityChecker.ProcUtil.Succeeded(), fixityChecker.ProcUtil.Failed())
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    Logger "github.com/sn0w/Karen/logger"
    "github.com/bwmarrin/discordgo"
    "math/rand"
    "time"
    "strings"
    "regexp"
    "github.com/getsentry/raven-go"
    "github.com/sn0w/Karen/plugins"
    "github.com/sn0w/Karen/utils"
    "github.com/sn0w/Karen/helpers"
)

// Called after the gateway connected
func BotOnReady(session *discordgo.Session, event *discordgo.Ready) {
    Logger.INF("Connected to discord!")
    fmt.Printf(
        "\n To add me to your discord server visit https://discordapp.com/oauth2/authorize?client_id=%s&scope=bot&permissions=%s\n\n",
        utils.GetConfig().Path("discord.id").Data().(string),
        utils.GetConfig().Path("discord.perms").Data().(string),
    )

    discordSession = session

    // Init plugins
    tmpl := "[PLUG] %s reacts to [ %s]"

    for _, plugin := range plugins.GetPlugins() {
        cmds := ""

        for _, cmd := range plugin.Commands() {
            cmds += cmd + " "
        }

        Logger.INF(fmt.Sprintf(
            tmpl,
            helpers.Typeof(plugin),
            cmds,
        ))

        plugin.Init(session)
    }

    // Async stats
    go func() {
        time.Sleep(3 * time.Second)

        configName := utils.GetConfig().Path("bot.name").Data().(string)
        configAvatar := utils.GetConfig().Path("bot.avatar").Data().(string)

        // Change avatar if desired
        if configAvatar != "" && configAvatar != session.State.User.Avatar {
            session.UserUpdate(
                "",
                "",
                session.State.User.Username,
                configAvatar,
                "",
            )
        }

        // Change name if desired
        if configName != "" && configName != session.State.User.Username {
            session.UserUpdate(
                "",
                "",
                configName,
                session.State.User.Avatar,
                "",
            )
        }
    }()

    // Run async game-changer
    go changeGameInterval(session)
}

// Called after a new message was sent
// This will be called after *every* message on *every* server so it should die as soon as possible.
func BotOnMessageCreate(session *discordgo.Session, message *discordgo.MessageCreate) {
    // Ignore other bots and @everyone/@here
    if (!message.Author.Bot && !message.MentionEveryone) {
        // Get the channel
        // Ignore the event if we cannot resolve the cannel
        channel, err := session.Channel(message.ChannelID)
        if err != nil {
            go raven.CaptureError(err, map[string]string{})
            return
        }

        // We only do things in guilds.
        // Get a friend already and stop chatting with bots
        if (!channel.IsPrivate) {
            // Check if the message contains @mentions
            if (len(message.Mentions) >= 1) {
                // Check if someone is mentioning us
                if (message.Mentions[0].ID == session.State.User.ID) {
                    // Prepare content for editing
                    msg := message.Content

                    /// Remove our @mention
                    msg = strings.Replace(msg, "<@" + session.State.User.ID + ">", "", -1)

                    // Trim message
                    msg = strings.Trim(msg, " ")

                    switch {
                    case regexp.MustCompile("^REFRESH CHAT SESSION$").Match([]byte(msg)):
                        utils.RequireAdmin(session, message.Message, func() {
                            // Refresh cleverbot session
                            utils.CleverbotRefreshSession(channel.ID)
                            discordSession.ChannelMessageSend(channel.ID, ":cyclone: Refreshed!")
                        })
                        return

                    case regexp.MustCompile("^SET PREFIX (.){0,10}$").Match([]byte(msg)):
                        utils.RequireAdmin(session, message.Message, func() {
                            // Set new prefix
                            err := utils.SetPrefixForServer(channel.GuildID, strings.Replace(msg, "SET PREFIX ", "", 1))

                            if err != nil {
                                utils.SendError(session, message.Message, err)
                            } else {
                                discordSession.ChannelMessageSend(channel.ID, ":white_check_mark: Saved!")
                            }
                        })
                        return

                    default:
                        // Send to cleverbot
                        session.ChannelTyping(message.ChannelID)
                        // Resolve other @mentions before sending the message
                        for _, user := range message.Mentions {
                            msg = strings.Replace(msg, "<@" + user.ID + ">", user.Username, -1)
                        }

                        // Remove smileys
                        msg = regexp.MustCompile(`:\w+:`).ReplaceAllString(msg, "")

                        // Send to cleverbot
                        utils.CleverbotSend(session, channel.ID, msg)
                        return
                    }
                }
            }

            // Only continue if a prefix is set
            prefix, err := utils.GetPrefixForServer(channel.GuildID)
            if err != nil {
                go raven.CaptureError(err, map[string]string{})
                return
            }

            // Split the message into parts
            parts := strings.Split(message.Content, " ")

            // Save a sanitized version of the command (no prefix)
            cmd := strings.Replace(parts[0], prefix, "", 1)

            // Check if the message is prefixed for us
            if (strings.HasPrefix(message.Content, prefix)) {
                // Check if the user calls for help
                if cmd == "h" || cmd == "help" {
                    discordSession.ChannelMessageSend(
                        message.ChannelID,
                        fmt.Sprintf("<@%s> Check out <http://meetkaren.xyz/#commandlist>", message.Author.ID),
                    )
                } else {
                    // Check if a module matches said command
                    // Do nothing otherwise
                    plugins.CallBotPlugin(
                        cmd,
                        strings.Replace(message.Content, prefix + cmd, "", -1),
                        message.Message,
                        discordSession,
                    )
                }
            }
        }
    }
}

// Changes the game interval every 10 seconds after called
func changeGameInterval(session *discordgo.Session) {
    for {
        err := session.UpdateStatus(0, games[rand.Intn(len(games))])
        if err != nil {
            raven.CaptureError(err, map[string]string{})
        }

        time.Sleep(10 * time.Second)
    }
}

// List of games to randomly show
var games = []string{
    // Random stuff
    "async is the future!",
    "down with OOP!",
    "spoopy stuff",
    "Planking",

    // Kaomoji
    "ʕ•ᴥ•ʔ",
    "༼ つ ◕_◕ ༽つ",
    "(ﾉ◕ヮ◕)ﾉ*:･ﾟ✧",
    "( ͡° ͜ʖ ͡°)",
    "¯\\_(ツ)_/¯",
    "(ง ͠° ͟ل͜ ͡°)ง",
    "ಠ_ಠ",
    "(╯°□°)╯︵ ʞooqǝɔɐɟ",
    "♪~ ᕕ(ᐛ)ᕗ",
    "\\ (•◡•) /",
    "｡◕‿◕｡",

    // actual games
    "Hearthstone",
    "Overwatch",
    "HuniePop",
    "Candy Crush",
    "Hyperdimension Neptunia",
    "Final Fantasy MCMX",
    "CIV V",
    "Pokemon Go",
    "Simulation Simulator 2016",
    "Half Life 3",
    "Nekopara",

    // software
    "with FFMPEG",
    "with libav",
    "with gophers",
    "with python",
    "with reflections",

    // names
    "with Shinobu-Chan",
    "with Ako-Chan",
    "with Nadeko",
    "with Miku",
    "with you O_o",
    "with cats",
    "with JOHN CENA",
    "with senpai",
    "with Serraniel#8978",
    "with 0xFADED#3237",
    "with C0untLizzi",
    "with moot",
    "with your waifu",
    "with Trump",
}
<commit_msg>Fix bugs, Make @mention case-less and improve prefixes<commit_after>package main

import (
    "fmt"
    Logger "github.com/sn0w/Karen/logger"
    "github.com/bwmarrin/discordgo"
    "math/rand"
    "time"
    "strings"
    "regexp"
    "github.com/getsentry/raven-go"
    "github.com/sn0w/Karen/plugins"
    "github.com/sn0w/Karen/utils"
    "github.com/sn0w/Karen/helpers"
)

// Called after the gateway connected
func BotOnReady(session *discordgo.Session, event *discordgo.Ready) {
    Logger.INF("Connected to discord!")
    fmt.Printf(
        "\n To add me to your discord server visit https://discordapp.com/oauth2/authorize?client_id=%s&scope=bot&permissions=%s\n\n",
        utils.GetConfig().Path("discord.id").Data().(string),
        utils.GetConfig().Path("discord.perms").Data().(string),
    )

    discordSession = session

    // Init plugins
    tmpl := "[PLUG] %s reacts to [ %s]"

    for _, plugin := range plugins.GetPlugins() {
        cmds := ""

        for _, cmd := range plugin.Commands() {
            cmds += cmd + " "
        }

        Logger.INF(fmt.Sprintf(
            tmpl,
            helpers.Typeof(plugin),
            cmds,
        ))

        plugin.Init(session)
    }

    // Async stats
    go func() {
        time.Sleep(3 * time.Second)

        configName := utils.GetConfig().Path("bot.name").Data().(string)
        configAvatar := utils.GetConfig().Path("bot.avatar").Data().(string)

        // Change avatar if desired
        if configAvatar != "" && configAvatar != session.State.User.Avatar {
            session.UserUpdate(
                "",
                "",
                session.State.User.Username,
                configAvatar,
                "",
            )
        }

        // Change name if desired
        if configName != "" && configName != session.State.User.Username {
            session.UserUpdate(
                "",
                "",
                configName,
                session.State.User.Avatar,
                "",
            )
        }
    }()

    // Run async game-changer
    go changeGameInterval(session)
}

// Called after a new message was sent
// This will be called after *every* message on *every* server so it should die as soon as possible.
func BotOnMessageCreate(session *discordgo.Session, message *discordgo.MessageCreate) {
    // Ignore other bots and @everyone/@here
    if (!message.Author.Bot && !message.MentionEveryone) {
        // Get the channel
        // Ignore the event if we cannot resolve the channel
        channel, err := session.Channel(message.ChannelID)
        if err != nil {
            go raven.CaptureError(err, map[string]string{})
            return
        }

        // We only do things in guilds.
        // Get a friend already and stop chatting with bots
        if (!channel.IsPrivate) {
            // Check if the message contains @mentions
            if (len(message.Mentions) >= 1) {
                // Check if someone is mentioning us
                if (message.Mentions[0].ID == session.State.User.ID) {
                    // Prepare content for editing
                    msg := message.Content

                    /// Remove our @mention
                    msg = strings.Replace(msg, "<@" + session.State.User.ID + ">", "", -1)

                    // Trim message
                    msg = strings.Trim(msg, " ")

                    // Convert to []byte before matching
                    bmsg := []byte(msg)

                    // Match against common task patterns
                    // Send to cleverbot if nothing matches
                    switch {
                    case regexp.MustCompile("(?i)^HELP.*").Match(bmsg):
                        sendHelp(message)
                        return

                    case regexp.MustCompile("(?i)^PREFIX.*").Match(bmsg):
                        prefix, _ := utils.GetPrefixForServer(channel.GuildID)
                        if prefix == "" {
                            discordSession.ChannelMessageSend(
                                channel.ID,
                                "Seems like there is no prefix yet :thinking:\n" +
                                    "Admins can set one by typing for example `@Karen set prefix ?`",
                            )
                        }

                        discordSession.ChannelMessageSend(
                            channel.ID,
                            "The prefix is `" + prefix + "` :smiley:",
                        )
                        return

                    case regexp.MustCompile("(?i)^REFRESH CHAT SESSION$").Match(bmsg):
                        utils.RequireAdmin(session, message.Message, func() {
                            // Refresh cleverbot session
                            utils.CleverbotRefreshSession(channel.ID)
                            discordSession.ChannelMessageSend(channel.ID, ":cyclone: Refreshed!")
                        })
                        return

                    case regexp.MustCompile("(?i)^SET PREFIX (.){1,25}$").Match(bmsg):
                        utils.RequireAdmin(session, message.Message, func() {
                            // Extract prefix
                            prefix := strings.Split(
                                regexp.MustCompile("(?i)^SET PREFIX\\s").ReplaceAllString(msg, ""),
                                " ",
                            )[0]

                            // Set new prefix
                            err := utils.SetPrefixForServer(
                                channel.GuildID,
                                prefix,
                            )

                            if err != nil {
                                utils.SendError(session, message.Message, err)
                            } else {
                                discordSession.ChannelMessageSend(channel.ID, ":white_check_mark: Saved! \n The prefix is now `" + prefix + "`")
                            }
                        })
                        return

                    default:
                        // Send to cleverbot
                        session.ChannelTyping(message.ChannelID)

                        // Resolve other @mentions before sending the message
                        for _, user := range message.Mentions {
                            msg = strings.Replace(msg, "<@" + user.ID + ">", user.Username, -1)
                        }

                        // Remove smileys
                        msg = regexp.MustCompile(`:\w+:`).ReplaceAllString(msg, "")

                        // Send to cleverbot
                        utils.CleverbotSend(session, channel.ID, msg)
                        return
                    }
                }
            }

            // Only continue if a prefix is set
            prefix, _ := utils.GetPrefixForServer(channel.GuildID)
            if prefix == "" {
                return
            }

            // Check if the message is prefixed for us
            if (strings.HasPrefix(message.Content, prefix)) {
                // Split the message into parts
                parts := strings.Split(message.Content, " ")

                // Save a sanitized version of the command (no prefix)
                cmd := strings.Replace(parts[0], prefix, "", 1)

                // Check if the user calls for help
                if cmd == "h" || cmd == "help" {
                    sendHelp(message)
                    return
                } else {
                    // Check if a module matches said command
                    // Do nothing otherwise
                    plugins.CallBotPlugin(
                        cmd,
                        strings.Replace(message.Content, prefix + cmd, "", -1),
                        message.Message,
                        discordSession,
                    )
                }
            }
        }
    }
}

func sendHelp(message *discordgo.MessageCreate) {
    discordSession.ChannelMessageSend(
        message.ChannelID,
        fmt.Sprintf("<@%s> Check out <http://meetkaren.xyz/#commandlist>", message.Author.ID),
    )
}

// Changes the game interval every 10 seconds after called
func changeGameInterval(session *discordgo.Session) {
    for {
        err := session.UpdateStatus(0, games[rand.Intn(len(games))])
        if err != nil {
            raven.CaptureError(err, map[string]string{})
        }

        time.Sleep(10 * time.Second)
    }
}

// List of games to randomly show
var games = []string{
    // Random stuff
    "async is the future!",
    "down with OOP!",
    "spoopy stuff",
    "Planking",

    // Kaomoji
    "ʕ•ᴥ•ʔ",
    "༼ つ ◕_◕ ༽つ",
    "(ﾉ◕ヮ◕)ﾉ*:･ﾟ✧",
    "( ͡° ͜ʖ ͡°)",
    "¯\\_(ツ)_/¯",
    "(ง ͠° ͟ل͜ ͡°)ง",
    "ಠ_ಠ",
    "(╯°□°)╯︵ ʞooqǝɔɐɟ",
    "♪~ ᕕ(ᐛ)ᕗ",
    "\\ (•◡•) /",
    "｡◕‿◕｡",

    // actual games
    "Hearthstone",
    "Overwatch",
    "HuniePop",
    "Candy Crush",
    "Hyperdimension Neptunia",
    "Final Fantasy MCMX",
    "CIV V",
    "Pokemon Go",
    "Simulation Simulator 2016",
    "Half Life 3",
    "Nekopara",

    // software
    "with FFMPEG",
    "with libav",
    "with gophers",
    "with python",
    "with reflections",

    // names
    "with Shinobu-Chan",
    "with Ako-Chan",
    "with Nadeko",
    "with Miku",
    "with you O_o",
    "with cats",
    "with JOHN CENA",
    "with senpai",
    "with Serraniel#8978",
    "with 0xFADED#3237",
    "with C0untLizzi",
    "with moot",
    "with your waifu",
    "with Trump",
}
<|endoftext|>


<commit_before><commit_msg>Print correct replica value on scaling<commit_after><|endoftext|>


<commit_before>package config

import (
	log "github.com/Sirupsen/logrus"
	"github.com/spf13/viper"
	"reflect"
)

type BgpConfigSet struct {
	Bgp    Bgp
	Policy RoutingPolicy
}

func ReadConfigfileServe(path, format string, configCh chan BgpConfigSet, reloadCh chan bool) {
	cnt := 0
	for {
		<-reloadCh

		b := Bgp{}
		p := RoutingPolicy{}
		v := viper.New()
		v.SetConfigFile(path)
		v.SetConfigType(format)
		err := v.ReadInConfig()
		if err != nil {
			goto ERROR
		}
		err = v.Unmarshal(&b)
		if err != nil {
			goto ERROR
		}
		err = SetDefaultConfigValues(v, &b)
		if err != nil {
			goto ERROR
		}
		err = v.Unmarshal(&p)
		if err != nil {
			goto ERROR
		}

		if cnt == 0 {
			log.Info("finished reading the config file")
		}
		cnt++
		configCh <- BgpConfigSet{Bgp: b, Policy: p}
		continue

	ERROR:
		if cnt == 0 {
			log.Fatal("can't read config file ", path, ", ", err)
		} else {
			log.Warning("can't read config file ", path, ", ", err)
			continue
		}

	}
}

func inSlice(n Neighbor, b []Neighbor) int {
	for i, nb := range b {
		if nb.Config.NeighborAddress == n.Config.NeighborAddress {
			return i
		}
	}
	return -1
}

func UpdateConfig(curC *Bgp, newC *Bgp) (*Bgp, []Neighbor, []Neighbor, []Neighbor) {
	bgpConfig := Bgp{}
	if curC == nil {
		bgpConfig.Global = newC.Global
		curC = &bgpConfig
	} else {
		// can't update the global config
		bgpConfig.Global = curC.Global
	}
	added := []Neighbor{}
	deleted := []Neighbor{}
	updated := []Neighbor{}

	for _, n := range newC.Neighbors {
		if idx := inSlice(n, curC.Neighbors); idx < 0 {
			added = append(added, n)
		} else {
			if !reflect.DeepEqual(n.ApplyPolicy, curC.Neighbors[idx].ApplyPolicy) {
				updated = append(updated, n)
			}
		}
	}

	for _, n := range curC.Neighbors {
		if inSlice(n, newC.Neighbors) < 0 {
			deleted = append(deleted, n)
		}
	}

	bgpConfig.Neighbors = newC.Neighbors
	return &bgpConfig, added, deleted, updated
}

func CheckPolicyDifference(currentPolicy *RoutingPolicy, newPolicy *RoutingPolicy) bool {

	log.Debug("current policy : ", currentPolicy)
	log.Debug("newPolicy policy : ", newPolicy)

	var result bool = false
	if currentPolicy == nil && newPolicy == nil {

		result = false
	} else {
		if currentPolicy != nil && newPolicy != nil {
			// TODO: reconsider the way of policy object comparison
			result = !reflect.DeepEqual(*currentPolicy, *newPolicy)
		} else {
			result = true
		}
	}
	return result
}
<commit_msg>config: validate when unmarshalling configuration<commit_after>package config

import (
	log "github.com/Sirupsen/logrus"
	"github.com/spf13/viper"
	"reflect"
)

type BgpConfigSet struct {
	Bgp    Bgp
	Policy RoutingPolicy
}

func ReadConfigfileServe(path, format string, configCh chan BgpConfigSet, reloadCh chan bool) {
	cnt := 0
	for {
		<-reloadCh

		b := Bgp{}
		v := viper.New()
		v.SetConfigFile(path)
		v.SetConfigType(format)
		err := v.ReadInConfig()
		c := struct {
			Global            Global             `mapstructure:"global"`
			Neighbors         []Neighbor         `mapstructure:"neighbors"`
			RpkiServers       []RpkiServer       `mapstructure:"rpki-servers"`
			DefinedSets       DefinedSets        `mapstructure:"defined-sets"`
			PolicyDefinitions []PolicyDefinition `mapstructure:"policy-definitions"`
		}{}
		if err != nil {
			goto ERROR
		}
		err = v.UnmarshalExact(&c)
		if err != nil {
			goto ERROR
		}
		b.Global = c.Global
		b.Neighbors = c.Neighbors
		b.RpkiServers = c.RpkiServers
		err = SetDefaultConfigValues(v, &b)
		if err != nil {
			goto ERROR
		}
		if cnt == 0 {
			log.Info("finished reading the config file")
		}
		cnt++
		configCh <- BgpConfigSet{
			Bgp: b,
			Policy: RoutingPolicy{
				DefinedSets:       c.DefinedSets,
				PolicyDefinitions: c.PolicyDefinitions,
			},
		}
		continue

	ERROR:
		if cnt == 0 {
			log.Fatal("can't read config file ", path, ", ", err)
		} else {
			log.Warning("can't read config file ", path, ", ", err)
			continue
		}

	}
}

func inSlice(n Neighbor, b []Neighbor) int {
	for i, nb := range b {
		if nb.Config.NeighborAddress == n.Config.NeighborAddress {
			return i
		}
	}
	return -1
}

func UpdateConfig(curC *Bgp, newC *Bgp) (*Bgp, []Neighbor, []Neighbor, []Neighbor) {
	bgpConfig := Bgp{}
	if curC == nil {
		bgpConfig.Global = newC.Global
		curC = &bgpConfig
	} else {
		// can't update the global config
		bgpConfig.Global = curC.Global
	}
	added := []Neighbor{}
	deleted := []Neighbor{}
	updated := []Neighbor{}

	for _, n := range newC.Neighbors {
		if idx := inSlice(n, curC.Neighbors); idx < 0 {
			added = append(added, n)
		} else {
			if !reflect.DeepEqual(n.ApplyPolicy, curC.Neighbors[idx].ApplyPolicy) {
				updated = append(updated, n)
			}
		}
	}

	for _, n := range curC.Neighbors {
		if inSlice(n, newC.Neighbors) < 0 {
			deleted = append(deleted, n)
		}
	}

	bgpConfig.Neighbors = newC.Neighbors
	return &bgpConfig, added, deleted, updated
}

func CheckPolicyDifference(currentPolicy *RoutingPolicy, newPolicy *RoutingPolicy) bool {

	log.Debug("current policy : ", currentPolicy)
	log.Debug("newPolicy policy : ", newPolicy)

	var result bool = false
	if currentPolicy == nil && newPolicy == nil {

		result = false
	} else {
		if currentPolicy != nil && newPolicy != nil {
			// TODO: reconsider the way of policy object comparison
			result = !reflect.DeepEqual(*currentPolicy, *newPolicy)
		} else {
			result = true
		}
	}
	return result
}
<|endoftext|>


<commit_before><commit_msg>Basic display functionality<commit_after><|endoftext|>


<commit_before><commit_msg>try to add the size of chunk setting<commit_after><|endoftext|>


<commit_before>package virtualbox

import (
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"os"
	"reflect"
	"testing"
)

func testConfig() map[string]interface{} {
	return map[string]interface{}{
		"iso_md5":      "foo",
		"iso_url":      "http://www.google.com/",
		"ssh_username": "foo",

		packer.BuildNameConfigKey: "foo",
	}
}

func TestBuilder_ImplementsBuilder(t *testing.T) {
	var raw interface{}
	raw = &Builder{}
	if _, ok := raw.(packer.Builder); !ok {
		t.Error("Builder must implement builder.")
	}
}

func TestBuilderPrepare_Defaults(t *testing.T) {
	var b Builder
	config := testConfig()
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestOSType != "Other" {
		t.Errorf("bad guest OS type: %s", b.config.GuestOSType)
	}

	if b.config.OutputDir != "output-foo" {
		t.Errorf("bad output dir: %s", b.config.OutputDir)
	}

	if b.config.SSHHostPortMin != 2222 {
		t.Errorf("bad min ssh host port: %d", b.config.SSHHostPortMin)
	}

	if b.config.SSHHostPortMax != 4444 {
		t.Errorf("bad max ssh host port: %d", b.config.SSHHostPortMax)
	}

	if b.config.SSHPort != 22 {
		t.Errorf("bad ssh port: %d", b.config.SSHPort)
	}

	if b.config.VMName != "packer-foo" {
		t.Errorf("bad vm name: %s", b.config.VMName)
	}
}

func TestBuilderPrepare_BootWait(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "boot_wait")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawBootWait != "10s" {
		t.Fatalf("bad value: %s", b.config.RawBootWait)
	}

	// Test with a bad boot_wait
	config["boot_wait"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["boot_wait"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_DiskSize(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "disk_size")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.DiskSize != 40000 {
		t.Fatalf("bad size: %d", b.config.DiskSize)
	}

	config["disk_size"] = 60000
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.DiskSize != 60000 {
		t.Fatalf("bad size: %s", b.config.DiskSize)
	}
}

func TestBuilderPrepare_GuestAdditionsPath(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "guest_additions_path")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.GuestAdditionsPath != "VBoxGuestAdditions.iso" {
		t.Fatalf("bad: %s", b.config.GuestAdditionsPath)
	}

	config["guest_additions_path"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestAdditionsPath != "foo" {
		t.Fatalf("bad size: %s", b.config.GuestAdditionsPath)
	}
}

func TestBuilderPrepare_HTTPPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["http_port_min"] = 1000
	config["http_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["http_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["http_port_min"] = 500
	config["http_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ISOMD5(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test bad
	config["iso_md5"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test good
	config["iso_md5"] = "FOo"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOMD5 != "foo" {
		t.Fatalf("should've lowercased: %s", b.config.ISOMD5)
	}
}

func TestBuilderPrepare_ISOUrl(t *testing.T) {
	var b Builder
	config := testConfig()

	config["iso_url"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["iso_url"] = "i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "file:i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "http://www.packer.io"
	err = b.Prepare(config)
	if err != nil {
		t.Errorf("should not have error: %s", err)
	}

	tf, err := ioutil.TempFile("", "packer")
	if err != nil {
		t.Fatalf("error tempfile: %s", err)
	}
	defer os.Remove(tf.Name())

	config["iso_url"] = tf.Name()
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOUrl != "file://"+tf.Name() {
		t.Fatalf("iso_url should be modified: %s", b.config.ISOUrl)
	}
}

func TestBuilderPrepare_OutputDir(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with existing dir
	dir, err := ioutil.TempDir("", "packer")
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.RemoveAll(dir)

	config["output_directory"] = dir
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["output_directory"] = "i-hope-i-dont-exist"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with a bad value
	config["shutdown_timeout"] = "this is not good"
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["shutdown_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHHostPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["ssh_host_port_min"] = 1000
	config["ssh_host_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["ssh_host_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["ssh_host_port_min"] = 500
	config["ssh_host_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHUser(t *testing.T) {
	var b Builder
	config := testConfig()

	config["ssh_username"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["ssh_username"] = "exists"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "ssh_wait_timeout")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawSSHWaitTimeout != "20m" {
		t.Fatalf("bad value: %s", b.config.RawSSHWaitTimeout)
	}

	// Test with a bad value
	config["ssh_wait_timeout"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["ssh_wait_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_VBoxManage(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with empty
	delete(config, "vboxmanage")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if !reflect.DeepEqual(b.config.VBoxManage, [][]string{}) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}

	// Test with a good one
	config["vboxmanage"] = [][]interface{}{
		[]interface{}{"foo", "bar", "baz"},
	}

	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	expected := [][]string{
		[]string{"foo", "bar", "baz"},
	}

	if !reflect.DeepEqual(b.config.VBoxManage, expected) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}
}

func TestBuilderPrepare_VBoxVersionFile(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test empty
	delete(config, "virtualbox_version_file")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.VBoxVersionFile != ".vbox_version" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}

	// Test with a good one
	config["virtualbox_version_file"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.VBoxVersionFile != "foo" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}
}
<commit_msg>builder/virtualbox: test the configuration<commit_after>package virtualbox

import (
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"os"
	"reflect"
	"testing"
)

func testConfig() map[string]interface{} {
	return map[string]interface{}{
		"iso_md5":      "foo",
		"iso_url":      "http://www.google.com/",
		"ssh_username": "foo",

		packer.BuildNameConfigKey: "foo",
	}
}

func TestBuilder_ImplementsBuilder(t *testing.T) {
	var raw interface{}
	raw = &Builder{}
	if _, ok := raw.(packer.Builder); !ok {
		t.Error("Builder must implement builder.")
	}
}

func TestBuilderPrepare_Defaults(t *testing.T) {
	var b Builder
	config := testConfig()
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestOSType != "Other" {
		t.Errorf("bad guest OS type: %s", b.config.GuestOSType)
	}

	if b.config.OutputDir != "output-foo" {
		t.Errorf("bad output dir: %s", b.config.OutputDir)
	}

	if b.config.SSHHostPortMin != 2222 {
		t.Errorf("bad min ssh host port: %d", b.config.SSHHostPortMin)
	}

	if b.config.SSHHostPortMax != 4444 {
		t.Errorf("bad max ssh host port: %d", b.config.SSHHostPortMax)
	}

	if b.config.SSHPort != 22 {
		t.Errorf("bad ssh port: %d", b.config.SSHPort)
	}

	if b.config.VMName != "packer-foo" {
		t.Errorf("bad vm name: %s", b.config.VMName)
	}
}

func TestBuilderPrepare_BootWait(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "boot_wait")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawBootWait != "10s" {
		t.Fatalf("bad value: %s", b.config.RawBootWait)
	}

	// Test with a bad boot_wait
	config["boot_wait"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["boot_wait"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_DiskSize(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "disk_size")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.DiskSize != 40000 {
		t.Fatalf("bad size: %d", b.config.DiskSize)
	}

	config["disk_size"] = 60000
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.DiskSize != 60000 {
		t.Fatalf("bad size: %s", b.config.DiskSize)
	}
}

func TestBuilderPrepare_GuestAdditionsPath(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "guest_additions_path")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.GuestAdditionsPath != "VBoxGuestAdditions.iso" {
		t.Fatalf("bad: %s", b.config.GuestAdditionsPath)
	}

	config["guest_additions_path"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestAdditionsPath != "foo" {
		t.Fatalf("bad size: %s", b.config.GuestAdditionsPath)
	}
}

func TestBuilderPrepare_GuestAdditionsSHA256(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "guest_additions_sha256")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.GuestAdditionsSHA256 != "" {
		t.Fatalf("bad: %s", b.config.GuestAdditionsSHA256)
	}

	config["guest_additions_sha256"] = "FOO"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestAdditionsSHA256 != "foo" {
		t.Fatalf("bad size: %s", b.config.GuestAdditionsSHA256)
	}
}

func TestBuilderPrepare_GuestAdditionsURL(t *testing.T) {
	var b Builder
	config := testConfig()

	config["guest_additions_url"] = ""
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.GuestAdditionsURL != "" {
		t.Fatalf("should be empty: %s", b.config.GuestAdditionsURL)
	}

	config["guest_additions_url"] = "i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["guest_additions_url"] = "file:i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["guest_additions_url"] = "http://www.packer.io"
	err = b.Prepare(config)
	if err != nil {
		t.Errorf("should not have error: %s", err)
	}

	tf, err := ioutil.TempFile("", "packer")
	if err != nil {
		t.Fatalf("error tempfile: %s", err)
	}
	defer os.Remove(tf.Name())

	config["guest_additions_url"] = tf.Name()
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestAdditionsURL != "file://"+tf.Name() {
		t.Fatalf("guest_additions_url should be modified: %s", b.config.GuestAdditionsURL)
	}
}

func TestBuilderPrepare_HTTPPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["http_port_min"] = 1000
	config["http_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["http_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["http_port_min"] = 500
	config["http_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ISOMD5(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test bad
	config["iso_md5"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test good
	config["iso_md5"] = "FOo"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOMD5 != "foo" {
		t.Fatalf("should've lowercased: %s", b.config.ISOMD5)
	}
}

func TestBuilderPrepare_ISOUrl(t *testing.T) {
	var b Builder
	config := testConfig()

	config["iso_url"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["iso_url"] = "i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "file:i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "http://www.packer.io"
	err = b.Prepare(config)
	if err != nil {
		t.Errorf("should not have error: %s", err)
	}

	tf, err := ioutil.TempFile("", "packer")
	if err != nil {
		t.Fatalf("error tempfile: %s", err)
	}
	defer os.Remove(tf.Name())

	config["iso_url"] = tf.Name()
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOUrl != "file://"+tf.Name() {
		t.Fatalf("iso_url should be modified: %s", b.config.ISOUrl)
	}
}

func TestBuilderPrepare_OutputDir(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with existing dir
	dir, err := ioutil.TempDir("", "packer")
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.RemoveAll(dir)

	config["output_directory"] = dir
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["output_directory"] = "i-hope-i-dont-exist"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with a bad value
	config["shutdown_timeout"] = "this is not good"
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["shutdown_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHHostPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["ssh_host_port_min"] = 1000
	config["ssh_host_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["ssh_host_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["ssh_host_port_min"] = 500
	config["ssh_host_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHUser(t *testing.T) {
	var b Builder
	config := testConfig()

	config["ssh_username"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["ssh_username"] = "exists"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "ssh_wait_timeout")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawSSHWaitTimeout != "20m" {
		t.Fatalf("bad value: %s", b.config.RawSSHWaitTimeout)
	}

	// Test with a bad value
	config["ssh_wait_timeout"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["ssh_wait_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_VBoxManage(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with empty
	delete(config, "vboxmanage")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if !reflect.DeepEqual(b.config.VBoxManage, [][]string{}) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}

	// Test with a good one
	config["vboxmanage"] = [][]interface{}{
		[]interface{}{"foo", "bar", "baz"},
	}

	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	expected := [][]string{
		[]string{"foo", "bar", "baz"},
	}

	if !reflect.DeepEqual(b.config.VBoxManage, expected) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}
}

func TestBuilderPrepare_VBoxVersionFile(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test empty
	delete(config, "virtualbox_version_file")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.VBoxVersionFile != ".vbox_version" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}

	// Test with a good one
	config["virtualbox_version_file"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.VBoxVersionFile != "foo" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}
}
<|endoftext|>


<commit_before><commit_msg>Create mail.go<commit_after><|endoftext|>


<commit_before><commit_msg>auth now errors early if no vault targeted<commit_after><|endoftext|>


<commit_before><commit_msg>Added env-file flag, disabled autoload, moved error logging more general<commit_after><|endoftext|>


<commit_before><commit_msg>Fix typo<commit_after><|endoftext|>