<commit_before>// +build all integration

package gocql

import (
	"reflect"
	"testing"
)

func TestTupleSimple(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_test(
		id int,
		coord frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	err = session.Query("INSERT INTO tuple_test(id, coord) VALUES(?, (?, ?))", 1, 100, -100).Exec()
	if err != nil {
		t.Fatal(err)
	}

	var (
		id    int
		coord struct {
			x int
			y int
		}
	)

	iter := session.Query("SELECT id, coord FROM tuple_test WHERE id=?", 1)
	if err := iter.Scan(&id, &coord.x, &coord.y); err != nil {
		t.Fatal(err)
	}

	if id != 1 {
		t.Errorf("expected to get id=1 got: %v", id)
	} else if coord.x != 100 {
		t.Errorf("expected to get coord.x=100 got: %v", coord.x)
	} else if coord.y != -100 {
		t.Errorf("expected to get coord.y=-100 got: %v", coord.y)
	}

}

func TestTuple_NullTuple(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_nil_test(
		id int,
		coord frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	const id = 1

	err = session.Query("INSERT INTO tuple_nil_test(id, coord) VALUES(?, (?, ?))", id, nil, nil).Exec()
	if err != nil {
		t.Fatal(err)
	}

	x := new(int)
	y := new(int)
	iter := session.Query("SELECT coord FROM tuple_nil_test WHERE id=?", id)
	if err := iter.Scan(&x, &y); err != nil {
		t.Fatal(err)
	}

	if x != nil {
		t.Fatalf("should be nil got %+#v", x)
	} else if y != nil {
		t.Fatalf("should be nil got %+#v", y)
	}

}

func TestTuple_TupleNotSet(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_not_set_test(
		id int,
		coord frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	const id = 1

	err = session.Query("INSERT INTO tuple_not_set_test(id,coord) VALUES(?, (?,?))", id, 1, 2).Exec()
	if err != nil {
		t.Fatal(err)
	}
	err = session.Query("INSERT INTO tuple_not_set_test(id) VALUES(?)", id+1).Exec()
	if err != nil {
		t.Fatal(err)
	}

	x := new(int)
	y := new(int)
	iter := session.Query("SELECT coord FROM tuple_not_set_test WHERE id=?", id)
	if err := iter.Scan(x, y); err != nil {
		t.Fatal(err)
	}
	if x == nil || *x != 1 {
		t.Fatalf("x should be %d got %+#v, value=%d", 1, x, *x)
	}
	if y == nil || *y != 2 {
		t.Fatalf("y should be %d got %+#v, value=%d", 2, y, *y)
	}

	// Check if the supplied targets are reset to nil
	iter = session.Query("SELECT coord FROM tuple_not_set_test WHERE id=?", id+1)
	if err := iter.Scan(x, y); err != nil {
		t.Fatal(err)
	}
	if x == nil || *x != 0 {
		t.Fatalf("x should be %d got %+#v, value=%d", 0, x, *x)
	}
	if y == nil || *y != 0 {
		t.Fatalf("y should be %d got %+#v, value=%d", 0, y, *y)
	}
}

func TestTupleMapScan(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_map_scan(
		id int,
		val frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	if err := session.Query(`INSERT INTO tuple_map_scan (id, val) VALUES (1, (1, 2));`).Exec(); err != nil {
		t.Fatal(err)
	}

	m := make(map[string]interface{})
	err = session.Query(`SELECT * FROM tuple_map_scan`).MapScan(m)
	if err != nil {
		t.Fatal(err)
	}
	if m["val[0]"] != 1 {
		t.Fatalf("expacted val[0] to be %d but was %d", 1, m["val[0]"])
	}
	if m["val[1]"] != 2 {
		t.Fatalf("expacted val[1] to be %d but was %d", 2, m["val[1]"])
	}
}

func TestTupleMapScanNil(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}
	err := createTable(session, `CREATE TABLE gocql_test.tuple_map_scan_nil(
			id int,
			val frozen<tuple<int, int>>,

			primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}
	if err := session.Query(`INSERT INTO tuple_map_scan_nil (id, val) VALUES (?,(?,?));`, 1, nil, nil).Exec(); err != nil {
		t.Fatal(err)
	}

	m := make(map[string]interface{})
	err = session.Query(`SELECT * FROM tuple_map_scan_nil`).MapScan(m)
	if err != nil {
		t.Fatal(err)
	}
	if m["val[0]"] != 0 {
		t.Fatalf("expacted val[0] to be %d but was %d", 0, m["val[0]"])
	}
	if m["val[1]"] != 0 {
		t.Fatalf("expacted val[1] to be %d but was %d", 0, m["val[1]"])
	}
}

func TestTupleMapScanNotSet(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}
	err := createTable(session, `CREATE TABLE gocql_test.tuple_map_scan_not_set(
			id int,
			val frozen<tuple<int, int>>,

			primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}
	if err := session.Query(`INSERT INTO tuple_map_scan_not_set (id) VALUES (?);`, 1).Exec(); err != nil {
		t.Fatal(err)
	}

	m := make(map[string]interface{})
	err = session.Query(`SELECT * FROM tuple_map_scan_not_set`).MapScan(m)
	if err != nil {
		t.Fatal(err)
	}
	if m["val[0]"] != 0 {
		t.Fatalf("expacted val[0] to be %d but was %d", 0, m["val[0]"])
	}
	if m["val[1]"] != 0 {
		t.Fatalf("expacted val[1] to be %d but was %d", 0, m["val[1]"])
	}
}

func TestTuple_NestedCollection(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.nested_tuples(
		id int,
		val list<frozen<tuple<int, text>>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	type typ struct {
		A int
		B string
	}

	tests := []struct {
		name string
		val  interface{}
	}{
		{name: "slice", val: [][]interface{}{{1, "2"}, {3, "4"}}},
		{name: "array", val: [][2]interface{}{{1, "2"}, {3, "4"}}},
		{name: "struct", val: []typ{{1, "2"}, {3, "4"}}},
	}

	for i, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if err := session.Query(`INSERT INTO nested_tuples (id, val) VALUES (?, ?);`, i, test.val).Exec(); err != nil {
				t.Fatal(err)
			}

			rv := reflect.ValueOf(test.val)
			res := reflect.New(rv.Type()).Elem().Addr().Interface()

			err = session.Query(`SELECT val FROM nested_tuples WHERE id=?`, i).Scan(res)
			if err != nil {
				t.Fatal(err)
			}
		})
	}
}
<commit_msg>tuple_test: check unmarshaled results in nested collection test<commit_after>// +build all integration

package gocql

import (
	"reflect"
	"testing"
)

func TestTupleSimple(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_test(
		id int,
		coord frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	err = session.Query("INSERT INTO tuple_test(id, coord) VALUES(?, (?, ?))", 1, 100, -100).Exec()
	if err != nil {
		t.Fatal(err)
	}

	var (
		id    int
		coord struct {
			x int
			y int
		}
	)

	iter := session.Query("SELECT id, coord FROM tuple_test WHERE id=?", 1)
	if err := iter.Scan(&id, &coord.x, &coord.y); err != nil {
		t.Fatal(err)
	}

	if id != 1 {
		t.Errorf("expected to get id=1 got: %v", id)
	} else if coord.x != 100 {
		t.Errorf("expected to get coord.x=100 got: %v", coord.x)
	} else if coord.y != -100 {
		t.Errorf("expected to get coord.y=-100 got: %v", coord.y)
	}

}

func TestTuple_NullTuple(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_nil_test(
		id int,
		coord frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	const id = 1

	err = session.Query("INSERT INTO tuple_nil_test(id, coord) VALUES(?, (?, ?))", id, nil, nil).Exec()
	if err != nil {
		t.Fatal(err)
	}

	x := new(int)
	y := new(int)
	iter := session.Query("SELECT coord FROM tuple_nil_test WHERE id=?", id)
	if err := iter.Scan(&x, &y); err != nil {
		t.Fatal(err)
	}

	if x != nil {
		t.Fatalf("should be nil got %+#v", x)
	} else if y != nil {
		t.Fatalf("should be nil got %+#v", y)
	}

}

func TestTuple_TupleNotSet(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_not_set_test(
		id int,
		coord frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	const id = 1

	err = session.Query("INSERT INTO tuple_not_set_test(id,coord) VALUES(?, (?,?))", id, 1, 2).Exec()
	if err != nil {
		t.Fatal(err)
	}
	err = session.Query("INSERT INTO tuple_not_set_test(id) VALUES(?)", id+1).Exec()
	if err != nil {
		t.Fatal(err)
	}

	x := new(int)
	y := new(int)
	iter := session.Query("SELECT coord FROM tuple_not_set_test WHERE id=?", id)
	if err := iter.Scan(x, y); err != nil {
		t.Fatal(err)
	}
	if x == nil || *x != 1 {
		t.Fatalf("x should be %d got %+#v, value=%d", 1, x, *x)
	}
	if y == nil || *y != 2 {
		t.Fatalf("y should be %d got %+#v, value=%d", 2, y, *y)
	}

	// Check if the supplied targets are reset to nil
	iter = session.Query("SELECT coord FROM tuple_not_set_test WHERE id=?", id+1)
	if err := iter.Scan(x, y); err != nil {
		t.Fatal(err)
	}
	if x == nil || *x != 0 {
		t.Fatalf("x should be %d got %+#v, value=%d", 0, x, *x)
	}
	if y == nil || *y != 0 {
		t.Fatalf("y should be %d got %+#v, value=%d", 0, y, *y)
	}
}

func TestTupleMapScan(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.tuple_map_scan(
		id int,
		val frozen<tuple<int, int>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	if err := session.Query(`INSERT INTO tuple_map_scan (id, val) VALUES (1, (1, 2));`).Exec(); err != nil {
		t.Fatal(err)
	}

	m := make(map[string]interface{})
	err = session.Query(`SELECT * FROM tuple_map_scan`).MapScan(m)
	if err != nil {
		t.Fatal(err)
	}
	if m["val[0]"] != 1 {
		t.Fatalf("expacted val[0] to be %d but was %d", 1, m["val[0]"])
	}
	if m["val[1]"] != 2 {
		t.Fatalf("expacted val[1] to be %d but was %d", 2, m["val[1]"])
	}
}

func TestTupleMapScanNil(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}
	err := createTable(session, `CREATE TABLE gocql_test.tuple_map_scan_nil(
			id int,
			val frozen<tuple<int, int>>,

			primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}
	if err := session.Query(`INSERT INTO tuple_map_scan_nil (id, val) VALUES (?,(?,?));`, 1, nil, nil).Exec(); err != nil {
		t.Fatal(err)
	}

	m := make(map[string]interface{})
	err = session.Query(`SELECT * FROM tuple_map_scan_nil`).MapScan(m)
	if err != nil {
		t.Fatal(err)
	}
	if m["val[0]"] != 0 {
		t.Fatalf("expacted val[0] to be %d but was %d", 0, m["val[0]"])
	}
	if m["val[1]"] != 0 {
		t.Fatalf("expacted val[1] to be %d but was %d", 0, m["val[1]"])
	}
}

func TestTupleMapScanNotSet(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}
	err := createTable(session, `CREATE TABLE gocql_test.tuple_map_scan_not_set(
			id int,
			val frozen<tuple<int, int>>,

			primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}
	if err := session.Query(`INSERT INTO tuple_map_scan_not_set (id) VALUES (?);`, 1).Exec(); err != nil {
		t.Fatal(err)
	}

	m := make(map[string]interface{})
	err = session.Query(`SELECT * FROM tuple_map_scan_not_set`).MapScan(m)
	if err != nil {
		t.Fatal(err)
	}
	if m["val[0]"] != 0 {
		t.Fatalf("expacted val[0] to be %d but was %d", 0, m["val[0]"])
	}
	if m["val[1]"] != 0 {
		t.Fatalf("expacted val[1] to be %d but was %d", 0, m["val[1]"])
	}
}

func TestTuple_NestedCollection(t *testing.T) {
	session := createSession(t)
	defer session.Close()
	if session.cfg.ProtoVersion < protoVersion3 {
		t.Skip("tuple types are only available of proto>=3")
	}

	err := createTable(session, `CREATE TABLE gocql_test.nested_tuples(
		id int,
		val list<frozen<tuple<int, text>>>,

		primary key(id))`)
	if err != nil {
		t.Fatal(err)
	}

	type typ struct {
		A int
		B string
	}

	tests := []struct {
		name string
		val  interface{}
	}{
		{name: "slice", val: [][]interface{}{{1, "2"}, {3, "4"}}},
		{name: "array", val: [][2]interface{}{{1, "2"}, {3, "4"}}},
		{name: "struct", val: []typ{{1, "2"}, {3, "4"}}},
	}

	for i, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if err := session.Query(`INSERT INTO nested_tuples (id, val) VALUES (?, ?);`, i, test.val).Exec(); err != nil {
				t.Fatal(err)
			}

			rv := reflect.ValueOf(test.val)
			res := reflect.New(rv.Type()).Elem().Addr().Interface()

			err = session.Query(`SELECT val FROM nested_tuples WHERE id=?`, i).Scan(res)
			if err != nil {
				t.Fatal(err)
			}

			resVal := reflect.ValueOf(res).Elem().Interface()
			if !reflect.DeepEqual(test.val, resVal) {
				t.Fatalf("unmarshaled value not equal to the original value: expected %#v, got %#v", test.val, resVal)
			}
		})
	}
}
<|endoftext|>


<commit_before>package repository

import (
	"fmt"
	"regexp"
	"strings"
)

// InsecureRegistryEx contains a regex string to match insecure registries
var InsecureRegistryEx = `^(127\..*|::1|localhost)(:[0-9]+)?$`

// RefSpec is a description of a valid registry specification
const RefSpec = "[REGISTRY[:PORT]/]REPOSITORY[:TAG|=TAG1,TAG2,TAGn|~/FILTER_REGEXP/]"

const (
	refWithNothing   = "[REGISTRY[:PORT]/]REPOSITORY"
	refWithSingleTag = "[REGISTRY[:PORT]/]REPOSITORY:TAG"
	refWithManyTags  = "[REGISTRY[:PORT]/]REPOSITORY=TAG1,TAG2,TAGn"
	refWithFilter    = "[REGISTRY[:PORT]/]REPOSITORY~/FILTER_REGEXP/"
)

const (
	registryEx = `[a-z0-9][a-z0-9\-\.]+[a-z0-9](:[0-9]+)?/`
	repoPathEx = `[a-z0-9_][a-z0-9_\-\.\/]+[a-z0-9_]`
	tagEx      = `[a-zA-Z0-9_\-\.]+`
	filterEx   = `\/.*\/`
)

var validRefExprs = map[string]*regexp.Regexp{
	refWithNothing:   regexp.MustCompile(fmt.Sprintf("^(%s)?%s$", registryEx, repoPathEx)),
	refWithSingleTag: regexp.MustCompile(fmt.Sprintf("^(%s)?%s:%s$", registryEx, repoPathEx, tagEx)),
	refWithManyTags:  regexp.MustCompile(fmt.Sprintf("^(%s)?%s=%s(,%s)*$", registryEx, repoPathEx, tagEx, tagEx)),
	refWithFilter:    regexp.MustCompile(fmt.Sprintf("^(%s)?%s~%s$", registryEx, repoPathEx, filterEx)),
}

const defaultRegistry = "registry.hub.docker.com"

// Repository represents parsed repository reference
type Repository struct {
	ref      string
	registry string
	fullRepo string
	repoTags []string
	filterRE *regexp.Regexp
	isSecure bool
	isSingle bool
}

// Ref gets original repository reference
func (r *Repository) Ref() string {
	return r.ref
}

// Registry gets registry ADDR[:PORT]
func (r *Repository) Registry() string {
	return r.registry
}

// IsDefaultRegistry tells us if we use default registry (DockerHub)
func (r *Repository) IsDefaultRegistry() bool {
	return r.registry == defaultRegistry
}

// Full gives us repository in form REGISTRY[:PORT]/REPOSITORY
func (r *Repository) Full() string {
	return r.fullRepo
}

// Name is same as full but cuts leading REGISTRY[:PORT]/ if we use default registry (DockerHub)
func (r *Repository) Name() string {
	if r.IsDefaultRegistry() {
		return strings.Join(strings.Split(r.Full(), "/")[1:], "/")
	}

	return r.Full()
}

// Path gives us remote repository path on the registry e.g. "library/alpine"
func (r *Repository) Path() string {
	path := strings.Join(strings.Split(r.Full(), "/")[1:], "/")

	if r.IsDefaultRegistry() && !strings.Contains(path, "/") {
		return "library/" + path
	}

	return path
}

// HasTags tells us if we've specified some concrete tags for this repository
func (r *Repository) HasTags() bool {
	return r.repoTags != nil && len(r.repoTags) != 0
}

// Tags gives us list of repository tags we use
func (r *Repository) Tags() []string {
	if !r.HasTags() {
		return []string{}
	}

	return r.repoTags
}

// HasFilter tells us if we've specified /FILTER/ regexp to match tags for this repository
func (r *Repository) HasFilter() bool {
	return r.filterRE != nil
}

// Filter gives us a string form of /FILTER/ regexp we use to match repository tags
func (r *Repository) Filter() string {
	if !r.HasFilter() {
		return ""
	}

	return r.filterRE.String()
}

// IsSecure tells us if we will use secure connection for this repository
func (r *Repository) IsSecure() bool {
	return r.isSecure
}

// WebSchema gives us HTTP protocol we will use to connect to repository
func (r *Repository) WebSchema() string {
	if !r.IsSecure() {
		return "http://"
	}

	return "https://"
}

// IsSingle tells us if we created repo from "refWithSingleTag" reference
func (r *Repository) IsSingle() bool {
	return r.isSingle
}

// MatchTag matches passed tag against repository tag and filter specification
func (r *Repository) MatchTag(tag string) bool {
	return r.isTagSpecified(tag) || r.doesTagMatchesFilter(tag)
}

func (r *Repository) isTagSpecified(tag string) bool {
	if r.HasFilter() {
		return false
	}

	for _, t := range r.Tags() {
		if t == tag {
			return true
		}
	}

	return false
}

func (r *Repository) doesTagMatchesFilter(tag string) bool {
	if !r.HasFilter() {
		return false
	}

	return r.filterRE.MatchString(tag)
}

// PushPrefix generates prefix path for repository in a "push" registry
func (r *Repository) PushPrefix() string {
	allParts := strings.Split(r.Registry(), ":")
	hostPart := allParts[0]

	return "/" + strings.Replace(hostPart, ".", "/", -1) + "/"
}

func validateRef(ref string) (string, error) {
	for spec, re := range validRefExprs {
		if re.MatchString(ref) {
			return spec, nil
		}
	}

	return "", fmt.Errorf(
		"repository reference '%s' failed to match specification: %s", ref, RefSpec,
	)
}

func isHostname(s string) bool {
	if strings.Contains(s, ".") {
		return true
	}

	if strings.Contains(s, ":") {
		return true
	}

	if s == "localhost" {
		return true
	}

	return false
}

// GetRegistry extracts registry address from the repository reference
func GetRegistry(ref string) string {
	if !strings.Contains(ref, "/") {
		return defaultRegistry
	}

	registry := strings.Split(ref, "/")[0]

	if isHostname(registry) {
		return registry
	}

	return defaultRegistry
}

func getFullRef(ref, registry string) string {
	if strings.HasPrefix(ref, registry) {
		return ref
	}

	return registry + "/" + ref
}

// ParseRef takes a string repository reference and transforms into a Repository
func ParseRef(ref string) (*Repository, error) {
	spec, err := validateRef(ref)
	if err != nil {
		return nil, err
	}

	var registry = GetRegistry(ref)

	fullRef := getFullRef(ref, registry)

	var fullRepo string
	var repoTags []string
	var filterRE *regexp.Regexp
	var isSingle bool

	switch spec {
	case refWithNothing:
		fullRepo = fullRef
		filterRE = regexp.MustCompile(".*")
	case refWithSingleTag:
		refParts := strings.Split(fullRef, ":")
		fullRepo = strings.TrimRight(fullRef, ":"+refParts[len(refParts)-1])
		repoTags = []string{refParts[len(refParts)-1]}
		isSingle = true
	case refWithManyTags:
		refParts := strings.Split(fullRef, "=")
		fullRepo = refParts[0]
		repoTags = strings.Split(refParts[1], ",")
	case refWithFilter:
		refParts := strings.Split(fullRef, "~")
		fullRepo = refParts[0]
		filterRE = regexp.MustCompile(refParts[1][1 : len(refParts[1])-1])
	default:
		return nil, fmt.Errorf("unknown repository  reference specification: %s", spec)
	}

	return &Repository{
		ref:      ref,
		registry: registry,
		fullRepo: fullRepo,
		repoTags: repoTags,
		filterRE: filterRE,
		isSecure: !regexp.MustCompile(InsecureRegistryEx).MatchString(registry),
		isSingle: isSingle,
	}, nil
}

// ParseRefs is a shorthand for ParseRef to parse multiple repository references at once
func ParseRefs(refs []string) ([]*Repository, error) {
	repos := make([]*Repository, len(refs))

	for i, ref := range refs {
		repo, err := ParseRef(ref)
		if err != nil {
			return nil, err
		}

		repos[i] = repo
	}

	return repos, nil
}
<commit_msg>docs(repository): Update comments for GoDoc<commit_after>// Package repository provides Repository abstraction to handle Docker repositories.
// This includes parsing and validation of repo specification passed in a text form,
// as well as association of the Docker repository with tags (images) it should contain.
package repository

import (
	"fmt"
	"regexp"
	"strings"
)

// InsecureRegistryEx contains a regex string to match insecure (non-HTTPS) registries
var InsecureRegistryEx = `^(127\..*|::1|localhost)(:[0-9]+)?$`

// RefSpec is the description of a valid Docker repository specification
const RefSpec = "[REGISTRY[:PORT]/]REPOSITORY[:TAG|=TAG1,TAG2,TAGn|~/FILTER_REGEXP/]"

const (
	refWithNothing   = "[REGISTRY[:PORT]/]REPOSITORY"
	refWithSingleTag = "[REGISTRY[:PORT]/]REPOSITORY:TAG"
	refWithManyTags  = "[REGISTRY[:PORT]/]REPOSITORY=TAG1,TAG2,TAGn"
	refWithFilter    = "[REGISTRY[:PORT]/]REPOSITORY~/FILTER_REGEXP/"
)

const (
	registryEx = `[a-z0-9][a-z0-9\-\.]+[a-z0-9](:[0-9]+)?/`
	repoPathEx = `[a-z0-9_][a-z0-9_\-\.\/]+[a-z0-9_]`
	tagEx      = `[a-zA-Z0-9_\-\.]+`
	filterEx   = `\/.*\/`
)

var validRefExprs = map[string]*regexp.Regexp{
	refWithNothing:   regexp.MustCompile(fmt.Sprintf("^(%s)?%s$", registryEx, repoPathEx)),
	refWithSingleTag: regexp.MustCompile(fmt.Sprintf("^(%s)?%s:%s$", registryEx, repoPathEx, tagEx)),
	refWithManyTags:  regexp.MustCompile(fmt.Sprintf("^(%s)?%s=%s(,%s)*$", registryEx, repoPathEx, tagEx, tagEx)),
	refWithFilter:    regexp.MustCompile(fmt.Sprintf("^(%s)?%s~%s$", registryEx, repoPathEx, filterEx)),
}

const defaultRegistry = "registry.hub.docker.com"

// Repository is a parsed, valid Docker repository reference
type Repository struct {
	ref      string
	registry string
	fullRepo string
	repoTags []string
	filterRE *regexp.Regexp
	isSecure bool
	isSingle bool
}

// Ref gets original repository reference string
func (r *Repository) Ref() string {
	return r.ref
}

// Registry gets registry ADDR[:PORT]
func (r *Repository) Registry() string {
	return r.registry
}

// IsDefaultRegistry tells us if we use default registry (DockerHub)
func (r *Repository) IsDefaultRegistry() bool {
	return r.registry == defaultRegistry
}

// Full gives us repository in a "full" form REGISTRY[:PORT]/REPOSITORY
func (r *Repository) Full() string {
	return r.fullRepo
}

// Name is same as Full() but cuts leading REGISTRY[:PORT]/ if we use default registry (DockerHub)
func (r *Repository) Name() string {
	if r.IsDefaultRegistry() {
		return strings.Join(strings.Split(r.Full(), "/")[1:], "/")
	}

	return r.Full()
}

// Path gives us repository path without registry hostname e.g. "library/alpine"
func (r *Repository) Path() string {
	path := strings.Join(strings.Split(r.Full(), "/")[1:], "/")

	if r.IsDefaultRegistry() && !strings.Contains(path, "/") {
		return "library/" + path
	}

	return path
}

// HasTags tells us if we've specified some concrete tags for this repository
func (r *Repository) HasTags() bool {
	return r.repoTags != nil && len(r.repoTags) != 0
}

// Tags gives us list of tags we specified for this repository
// (It will return `[]string{}` if we have not specified any)
func (r *Repository) Tags() []string {
	if !r.HasTags() {
		return []string{}
	}

	return r.repoTags
}

// HasFilter tells us if we've specified /FILTER/ regexp to match tags for this repository
func (r *Repository) HasFilter() bool {
	return r.filterRE != nil
}

// Filter gives us a string form of /FILTER/ regexp we use to match repository tags
func (r *Repository) Filter() string {
	if !r.HasFilter() {
		return ""
	}

	return r.filterRE.String()
}

// IsSecure tells us if we use secure (HTTPS) connection for this registry/repository
func (r *Repository) IsSecure() bool {
	return r.isSecure
}

// WebSchema tells us we use "http://" or "https://" to connect to this registry/repository
func (r *Repository) WebSchema() string {
	if !r.IsSecure() {
		return "http://"
	}

	return "https://"
}

// IsSingle tells us if we created repo from reference having only single tag specified
func (r *Repository) IsSingle() bool {
	return r.isSingle
}

// MatchTag matches passed tag against repository tag and filter specification
func (r *Repository) MatchTag(tag string) bool {
	return r.isTagSpecified(tag) || r.doesTagMatchesFilter(tag)
}

func (r *Repository) isTagSpecified(tag string) bool {
	if r.HasFilter() {
		return false
	}

	for _, t := range r.Tags() {
		if t == tag {
			return true
		}
	}

	return false
}

func (r *Repository) doesTagMatchesFilter(tag string) bool {
	if !r.HasFilter() {
		return false
	}

	return r.filterRE.MatchString(tag)
}

// PushPrefix generates prefix path for repository in a "push" registry
func (r *Repository) PushPrefix() string {
	allParts := strings.Split(r.Registry(), ":")
	hostPart := allParts[0]

	return "/" + strings.Replace(hostPart, ".", "/", -1) + "/"
}

func validateRef(ref string) (string, error) {
	for spec, re := range validRefExprs {
		if re.MatchString(ref) {
			return spec, nil
		}
	}

	return "", fmt.Errorf(
		"repository reference '%s' failed to match specification: %s", ref, RefSpec,
	)
}

func isHostname(s string) bool {
	if strings.Contains(s, ".") {
		return true
	}

	if strings.Contains(s, ":") {
		return true
	}

	if s == "localhost" {
		return true
	}

	return false
}

// GetRegistry extracts registry address from the repository reference
func GetRegistry(ref string) string {
	if !strings.Contains(ref, "/") {
		return defaultRegistry
	}

	registry := strings.Split(ref, "/")[0]

	if isHostname(registry) {
		return registry
	}

	return defaultRegistry
}

func getFullRef(ref, registry string) string {
	if strings.HasPrefix(ref, registry) {
		return ref
	}

	return registry + "/" + ref
}

// ParseRef takes a string repository reference and transforms it into a Repository structure
func ParseRef(ref string) (*Repository, error) {
	spec, err := validateRef(ref)
	if err != nil {
		return nil, err
	}

	var registry = GetRegistry(ref)

	fullRef := getFullRef(ref, registry)

	var fullRepo string
	var repoTags []string
	var filterRE *regexp.Regexp
	var isSingle bool

	switch spec {
	case refWithNothing:
		fullRepo = fullRef
		filterRE = regexp.MustCompile(".*")
	case refWithSingleTag:
		refParts := strings.Split(fullRef, ":")
		fullRepo = strings.TrimRight(fullRef, ":"+refParts[len(refParts)-1])
		repoTags = []string{refParts[len(refParts)-1]}
		isSingle = true
	case refWithManyTags:
		refParts := strings.Split(fullRef, "=")
		fullRepo = refParts[0]
		repoTags = strings.Split(refParts[1], ",")
	case refWithFilter:
		refParts := strings.Split(fullRef, "~")
		fullRepo = refParts[0]
		filterRE = regexp.MustCompile(refParts[1][1 : len(refParts[1])-1])
	default:
		return nil, fmt.Errorf("unknown repository  reference specification: %s", spec)
	}

	return &Repository{
		ref:      ref,
		registry: registry,
		fullRepo: fullRepo,
		repoTags: repoTags,
		filterRE: filterRE,
		isSecure: !regexp.MustCompile(InsecureRegistryEx).MatchString(registry),
		isSingle: isSingle,
	}, nil
}

// ParseRefs is a shorthand for ParseRef to parse multiple repository references at once
func ParseRefs(refs []string) ([]*Repository, error) {
	repos := make([]*Repository, len(refs))

	for i, ref := range refs {
		repo, err := ParseRef(ref)
		if err != nil {
			return nil, err
		}

		repos[i] = repo
	}

	return repos, nil
}
<|endoftext|>


<commit_before>package requests

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestRequest(T *testing.T) {
	//test adding a token to a response
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		//make a new Request out of it
		testReq := new(Request)
		testReq.Request = r
		testReq.Response = w
		token = AddCSRFTokenToResponse(testReq)
		//check to ensure that the encoded length is the expected 44 characters long
		if len(token) != 44 {
			T.Errorf("Unexpected CSRF token length!")
		}
	}))
	defer ts.Close()

	response, _ := http.Get(ts.URL)

	//check to ensure the cookie value and the token match
	csrfCookie := response.Cookies()[0]
	cookieToken := csrfCookie.Value
	if cookieToken != token {
		T.Errorf("Cookie and generated token values do not match!")
	}
}
<commit_msg>Fixed test for session. still 100% coverage 8)<commit_after>package requests

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestRequest(T *testing.T) {
	var token string
	//test adding a token to a response
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		//make a new Request out of it
		testReq := new(Request)
		testReq.Request = r
		testReq.Response = w
		token = testReq.AddCSRFToken()
		//check to ensure that the encoded length is the expected 44 characters long
		if len(token) != 44 {
			T.Errorf("Unexpected CSRF token length!")
		}
	}))
	defer ts.Close()

	response, _ := http.Get(ts.URL)

	//check to ensure the cookie value and the token match
	csrfCookie := response.Cookies()[0]
	cookieToken := csrfCookie.Value
	if cookieToken != token {
		T.Errorf("Cookie and generated token values do not match!")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"image"
	"image/color"
	"image/png"
	"os"
	"runtime"
	"math/rand"
)

const size = 1000
const max_iter = 2000
const procs = 4

func to_img(brot* [size][size]uint, max uint) {
	gray := image.NewGray16(image.Rect(0,0,size,size))
	norm_gray := image.NewGray16(image.Rect(0,0,size,size))
	for x:=0; x<size; x++ {
		for y:=0; y<size; y++ {
			pix := brot[x][y]
			norm := float64(brot[x][y]*1000)/float64(max)*65534
			if norm > 65535{
				norm = 65535
			}
			if pix > 65535{
				pix = 65535
			}
			gray.SetGray16(
				x, y,
				color.Gray16{uint16(pix)})
			norm_gray.SetGray16(
				x, y,
				color.Gray16{uint16(norm)})
		}
	}
	w, _ := os.OpenFile("./brot.png", os.O_CREATE|os.O_WRONLY, 0666)
	png.Encode(w, gray)
	n, _ := os.OpenFile("./brot-norm.png", os.O_CREATE|os.O_WRONLY, 0666)
	png.Encode(n, norm_gray)
}

func cartesian_2_complex(x, y int) complex128 {
	return complex(
		-2 + (float64(x)/size * 3),
		-1.5 + (float64(y)/size * 3))
}

func complex_2_cartesian(point complex128) (float64, float64) {
	x := (real(point)+2)/3 * size
	y := (imag(point)+1.5)/3 * size
	return x, y
}

func buddahbrot_renderer(brot* [size][size]uint, orbits chan []complex128,
	finished chan uint) {
	done := 0
	max := uint(0)
	next := func() ([] complex128){
		orbit := <- orbits
		for orbit == nil && done < procs-1  {
			fmt.Printf("%v", done)
			done += 1
			orbit = <- orbits
		}
		return orbit
	}
	orbit := next()
	for orbit != nil {
		for _, point := range orbit {
			fx, fy := complex_2_cartesian(point)
			x, y := int(fx), int(fy)
			if (0<x && x<size && 0<y && y<size){
				brot[x][y] += 1
				if (brot[x][y] > max){
					max = brot[x][y]
				}
			}
		}
		orbit = next()
	}
	fmt.Printf("max: %v\n", max)
	finished <- max
}

func mandelbrot(c complex128) (uint, []complex128) {
	orbit := make([]complex128, max_iter)
	z := c
	var iterations = uint(0)
	x, y := real(z), imag(z)
	for (iterations<max_iter && x*x+y*y<4) {
		z = z*z + c
		orbit[iterations] = z
		iterations++
		x, y = real(z), imag(z)
	}
	return iterations, orbit[0:iterations]
}

func brot_routine(brot *[size][size]uint, points chan complex128,
	orbits chan []complex128) {
	point, open := <- points
	for open {
		iterations, orbit := mandelbrot(point)
		if iterations < max_iter {
			orbits <- orbit
		}
		point, open = <- points
	}
	orbits <- nil
}

func main() {
	runtime.GOMAXPROCS(procs)
	rand.Seed(92388)
	var brot [size][size]uint
	points := make(chan complex128, 12*procs)
	orbits := make(chan []complex128, 12*procs)
	finished := make(chan uint)
	for i:=0; i<procs; i++ {
		go brot_routine(&brot, points, orbits)
	}
	go buddahbrot_renderer(&brot, orbits, finished)
	exposure := uint64(40000000)
	fe := float64(exposure)
	for i:=uint64(0); i<exposure; i++ {
		points <- complex(-2+rand.Float64()*3, -1.5+rand.Float64()*3)
		if (i%100000==0){
			fmt.Printf("%v %%\n", float64(i)/fe*100)
		}
	}
	close(points)
	fmt.Print("done\n")
	max := <- finished
	to_img(&brot, max)
}<commit_msg>long lost changeset: boost by 4 not 1000 parranoid change about max_int<commit_after>package main

import (
	"fmt"
	"image"
	"image/color"
	"image/png"
	"os"
	"runtime"
	"math/rand"
)

const size = 1000
const max_iter = 2000
const procs = 4

func to_img(brot* [size][size]uint, max uint) {
	gray := image.NewGray16(image.Rect(0,0,size,size))
	norm_gray := image.NewGray16(image.Rect(0,0,size,size))
	for x:=0; x<size; x++ {
		for y:=0; y<size; y++ {
			pix := brot[x][y]
			norm := float64(brot[x][y]*4)/float64(max)*65534
			if norm > 65534{
				norm = 65534
			}
			if pix > 65534{
				pix = 65534
			}
			gray.SetGray16(
				x, y,
				color.Gray16{uint16(pix)})
			norm_gray.SetGray16(
				x, y,
				color.Gray16{uint16(norm)})
		}
	}
	w, _ := os.OpenFile("./brot.png", os.O_CREATE|os.O_WRONLY, 0666)
	png.Encode(w, gray)
	n, _ := os.OpenFile("./brot-norm.png", os.O_CREATE|os.O_WRONLY, 0666)
	png.Encode(n, norm_gray)
}

func cartesian_2_complex(x, y int) complex128 {
	return complex(
		-2 + (float64(x)/size * 3),
		-1.5 + (float64(y)/size * 3))
}

func complex_2_cartesian(point complex128) (float64, float64) {
	x := (real(point)+2)/3 * size
	y := (imag(point)+1.5)/3 * size
	return x, y
}

func buddahbrot_renderer(brot* [size][size]uint, orbits chan []complex128,
	finished chan uint) {
	done := 0
	max := uint(0)
	next := func() ([] complex128){
		orbit := <- orbits
		for orbit == nil && done < procs-1  {
			fmt.Printf("%v", done)
			done += 1
			orbit = <- orbits
		}
		return orbit
	}
	orbit := next()
	for orbit != nil {
		for _, point := range orbit {
			fx, fy := complex_2_cartesian(point)
			x, y := int(fx), int(fy)
			if (0<x && x<size && 0<y && y<size){
				brot[x][y] += 1
				if (brot[x][y] > max){
					max = brot[x][y]
				}
			}
		}
		orbit = next()
	}
	fmt.Printf("max: %v\n", max)
	finished <- max
}

func mandelbrot(c complex128) (uint, []complex128) {
	orbit := make([]complex128, max_iter)
	z := c
	var iterations = uint(0)
	x, y := real(z), imag(z)
	for (iterations<max_iter && x*x+y*y<4) {
		z = z*z + c
		orbit[iterations] = z
		iterations++
		x, y = real(z), imag(z)
	}
	return iterations, orbit[0:iterations]
}

func brot_routine(brot *[size][size]uint, points chan complex128,
	orbits chan []complex128) {
	point, open := <- points
	for open {
		iterations, orbit := mandelbrot(point)
		if iterations == max_iter {
			orbits <- orbit
		}
		point, open = <- points
	}
	orbits <- nil
}

func main() {
	runtime.GOMAXPROCS(procs)
	rand.Seed(92388)
	var brot [size][size]uint
	points := make(chan complex128, 12*procs)
	orbits := make(chan []complex128, 12*procs)
	finished := make(chan uint)
	for i:=0; i<procs; i++ {
		go brot_routine(&brot, points, orbits)
	}
	go buddahbrot_renderer(&brot, orbits, finished)
	exposure := uint64(40000000)
	fe := float64(exposure)
	for i:=uint64(0); i<exposure; i++ {
		points <- complex(-2+rand.Float64()*3, -1.5+rand.Float64()*3)
		if (i%100000==0){
			fmt.Printf("%v %%\n", float64(i)/fe*100)
		}
	}
	close(points)
	fmt.Print("done\n")
	max := <- finished
	to_img(&brot, max)
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Yanko Bolanos
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */
package tail

import (
	"bufio"
	"bytes"
	"context"
	"errors"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/fsnotify.v1"
)

const (
	SLEEP_TIMEOUT = time.Second * 1
	FD_TIMEOUT    = time.Minute * 10
)

var (
	gDelim = regexp.MustCompile(`\r?\n`)
)

type Tail struct {
	Filename       string
	LineChan       chan string
	Cancel         context.CancelFunc
	Follow         bool
	Context        context.Context
	RetryFileOpen  bool // keep trying to re-open the file, helpful when the file doesn't exist yet
	lineStartSplit bool // logic for handling begining of line split (splunk like, by timestamp)
	delim          *regexp.Regexp
	SeekToEnd      bool
}

func NewTail(path string) *Tail {

	ctx, cancel := context.WithCancel(context.Background())

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         true,
		Context:        ctx,
		RetryFileOpen:  true,
		lineStartSplit: false,
		delim:          gDelim,
		SeekToEnd:      false,
	}

	return t
}

func (t *Tail) Start() {
	go t.watchFile(t.Context, t.Filename)
}

func NewTailWithCtx(ctx context.Context, path string, follow, retryFileOpen bool, delim *regexp.Regexp, lineStartSplit bool) *Tail {

	ctx, cancel := context.WithCancel(ctx)

	d := gDelim
	if delim != nil {
		d = delim
	}

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         follow,
		Context:        ctx,
		RetryFileOpen:  retryFileOpen,
		lineStartSplit: lineStartSplit,
		delim:          d,
		SeekToEnd:      false,
	}

	t.Start()
	return t
}

func (t *Tail) Close() {
	t.Cancel()
	close(t.LineChan)
}

func (t *Tail) openFile(path string) (*os.File, error) {

	var f *os.File
	var err error
	for {

		if !t.RetryFileOpen {
			select {
			case <-t.Context.Done():
				return nil, errors.New("Tail context cancelled.")
			default:
				break
			}
		}

		f, err = os.Open(path)
		if err != nil {
			log.Infof("Unable to open. %s. Waiting 5 seconds and retrying", err.Error())
			time.Sleep(time.Second * 5)
		} else {
			if finfo, err := os.Stat(path); err == nil && t.SeekToEnd {
				f.Seek(finfo.Size(), 0)
			}
			break
		}
	}

	return f, nil
}

func (t *Tail) watchFile(parent context.Context, path string) {

	ctx, ctxCancel := context.WithCancel(parent)

	fileIn, err := t.openFile(path)
	if err != nil {
		log.Infof("1. Unable to openFile. %s. Waiting 5 seconds and retrying", err.Error())
		return
	}
	defer fileIn.Close()

	r := bufio.NewReader(fileIn)

	accum := new(bytes.Buffer)

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	err = watcher.Add(path)
	if err != nil {
		log.Fatal(err)
	}

loop:
	for {

		if t.lineStartSplit {
			readFrontSplit(ctx, t.delim, t.LineChan, r, accum)
		} else {
			buffer := read(ctx, t.delim, r, accum)
			reader := bufio.NewReader(buffer)
			for {
				select {
				case <-ctx.Done():
					return
				default:
					break
				}

				line, err := reader.ReadString('\n')
				if err != nil && err != io.EOF {
					log.WithField("file", path).Error(err.Error())
					break

				}

				if len(line) > 0 {
					t.LineChan <- string([]rune(strings.TrimRight(line, "\n")))
				}

				if err == io.EOF {
					if !t.Follow {
						t.Close()
						return
					}
					break
				}

			}
		}

		select {
		case <-time.After(SLEEP_TIMEOUT):
			if t.lineStartSplit && accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			break
		case event := <-watcher.Events:
			if event.Op&fsnotify.Rename == fsnotify.Rename {
				log.WithField("file", path).Info("File renamed. Monitoring old fd for 10 minutes")
				go t.watchFile(ctx, path)
				time.AfterFunc(FD_TIMEOUT, func() {
					log.WithField("file", path).Info("Closing old fd")
					ctxCancel()
				})
			}
			break
		case err := <-watcher.Errors:
			log.WithField("file", path).Errorf("inotify error: %v", err)
			break
		case <-ctx.Done():
			if accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			break loop
		}
	}
}

func read(ctx context.Context, delim *regexp.Regexp, f io.Reader, accum *bytes.Buffer) io.Reader {

	r, w := io.Pipe()
	buffer_size := 1048576 // 1MB

	go func() {
		defer w.Close()

		buffer := make([]byte, buffer_size)
		for {

			select {
			case <-ctx.Done():
				return
			default:
				break
			}

			n, err := f.Read(buffer)
			if err != nil {
				w.Close()
				break
			}

			slice := buffer[:n]
			locs := delim.FindAllSubmatchIndex(slice, -1)

			if len(locs) == 0 {
				accum.Write(slice)
			} else {
				start_idx := 0
				end_idx := 0
				for _, loc := range locs {
					end_idx = loc[1]
					data := append(accum.Bytes(), slice[start_idx:end_idx]...)
					w.Write(data)
					accum.Reset()
					start_idx = end_idx
				}

				if end_idx < n {
					accum.Write(slice[end_idx:])
				}
			}
		}

	}()

	return r
}

func readFrontSplit(ctx context.Context, delim *regexp.Regexp, lineChan chan string, f io.Reader, accum *bytes.Buffer) {

	buffer_size := 1048576 // 1MB

	// go func() {
	// defer w.Close()

	buffer := make([]byte, buffer_size)
	first := true
	for {
		select {
		case <-ctx.Done():
			return
		default:
			break
		}

		n, err := f.Read(buffer)
		if err != nil {
			break
		}

		slice := buffer[:n]
		locs := delim.FindAllSubmatchIndex(slice, -1)

		if len(locs) == 0 {
			accum.Write(slice)
		} else {

			line_begin_idx := 0
			line_end_idx := 0
			next_start := 0
			for _, loc := range locs {
				if first {
					first = false
					next_start = loc[0]
					if loc[0] == 0 && accum.Len() > 0 {
						lineChan <- accum.String()
						accum.Reset()
					}
					continue
				} else {
					line_begin_idx = next_start
				}

				line_end_idx = loc[0]
				next_start = loc[1] - (loc[1] - loc[0])
				data := bytes.Replace(slice[line_begin_idx:line_end_idx], []byte("\x0A"), nil, -1)
				data = append(accum.Bytes(), data...)
				lineChan <- string(data)
				accum.Reset()
				// data_trim := bytes.TrimRight(data, "\n")
				// log.Printf("%v -> %v", line_begin_idx, line_end_idx)
				// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", line_begin_idx, data_trim, line_end_idx)

			}

			data := slice[next_start:n]
			accum.Write(data)
			// w.Write(data)
			// lineChan <- string(data)
			// data_trim := bytes.TrimRight(data, "\n")
			// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", next_start, data, n)
		}
	}

	// lineChan <- string(accum.Bytes())
	// accum.Reset()
	// }()

	// <-ctx.Done()

}
<commit_msg>tail fix<commit_after>/*
 * Copyright (c) 2016 Yanko Bolanos
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */
package tail

import (
	"bufio"
	"bytes"
	"context"
	"errors"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/fsnotify.v1"
)

const (
	SLEEP_TIMEOUT = time.Second * 1
	FD_TIMEOUT    = time.Minute * 10
)

var (
	gDelim = regexp.MustCompile(`\r?\n`)
)

type Tail struct {
	Filename       string
	LineChan       chan string
	Cancel         context.CancelFunc
	Follow         bool
	Context        context.Context
	RetryFileOpen  bool // keep trying to re-open the file, helpful when the file doesn't exist yet
	lineStartSplit bool // logic for handling begining of line split (splunk like, by timestamp)
	delim          *regexp.Regexp
	SeekToEnd      bool
}

func NewTail(path string) *Tail {

	ctx, cancel := context.WithCancel(context.Background())

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         true,
		Context:        ctx,
		RetryFileOpen:  true,
		lineStartSplit: false,
		delim:          gDelim,
		SeekToEnd:      false,
	}

	return t
}

func (t *Tail) Start() {
	go t.watchFile(t.Context, t.Filename)
}

func NewTailWithCtx(ctx context.Context, path string, follow, retryFileOpen bool, delim *regexp.Regexp, lineStartSplit bool) *Tail {

	ctx, cancel := context.WithCancel(ctx)

	d := gDelim
	if delim != nil {
		d = delim
	}

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         follow,
		Context:        ctx,
		RetryFileOpen:  retryFileOpen,
		lineStartSplit: lineStartSplit,
		delim:          d,
		SeekToEnd:      false,
	}

	t.Start()
	return t
}

func (t *Tail) Close() {
	close(t.LineChan)
}

func (t *Tail) openFile(path string) (*os.File, error) {

	var f *os.File
	var err error
	for {

		if !t.RetryFileOpen {
			select {
			case <-t.Context.Done():
				return nil, errors.New("Tail context cancelled.")
			default:
				break
			}
		}

		f, err = os.Open(path)
		if err != nil {
			log.Infof("Unable to open. %s. Waiting 5 seconds and retrying", err.Error())
			time.Sleep(time.Second * 5)
		} else {
			if finfo, err := os.Stat(path); err == nil && t.SeekToEnd {
				f.Seek(finfo.Size(), 0)
			}
			break
		}
	}

	return f, nil
}

func (t *Tail) watchFile(parent context.Context, path string) {

	ctx, ctxCancel := context.WithCancel(parent)

	fileIn, err := t.openFile(path)
	if err != nil {
		log.Infof("1. Unable to openFile. %s. Waiting 5 seconds and retrying", err.Error())
		return
	}
	defer fileIn.Close()

	r := bufio.NewReader(fileIn)

	accum := new(bytes.Buffer)

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	err = watcher.Add(path)
	if err != nil {
		log.Fatal(err)
	}

	for {

		if t.lineStartSplit {
			readFrontSplit(ctx, t.delim, t.LineChan, r, accum)
		} else {
			buffer := read(ctx, t.delim, r, accum)
			reader := bufio.NewReader(buffer)
			for {
				select {
				case <-ctx.Done():
					return
				default:
					break
				}

				line, err := reader.ReadString('\n')
				if err != nil && err != io.EOF {
					log.WithField("file", path).Error(err.Error())
					break

				}

				if len(line) > 0 {
					t.LineChan <- string([]rune(strings.TrimRight(line, "\n")))
				}

				if err == io.EOF {
					if !t.Follow {
						t.Close()
						return
					}
					break
				}

			}
		}

		select {
		case <-time.After(SLEEP_TIMEOUT):
			if t.lineStartSplit && accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			break
		case event := <-watcher.Events:
			if event.Op&fsnotify.Rename == fsnotify.Rename {
				log.WithField("file", path).Info("File renamed. Monitoring old fd for 10 minutes")
				go t.watchFile(ctx, path)
				time.AfterFunc(FD_TIMEOUT, func() {
					log.WithField("file", path).Info("Closing old fd")
					ctxCancel()
				})
			}
			break
		case err := <-watcher.Errors:
			log.WithField("file", path).Errorf("inotify error: %v", err)
			break
		case <-ctx.Done():
			if accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			t.Close()
			return
		}
	}
}

func read(ctx context.Context, delim *regexp.Regexp, f io.Reader, accum *bytes.Buffer) io.Reader {

	r, w := io.Pipe()
	buffer_size := 1048576 // 1MB

	go func() {
		defer w.Close()

		buffer := make([]byte, buffer_size)
		for {

			select {
			case <-ctx.Done():
				return
			default:
				break
			}

			n, err := f.Read(buffer)
			if err != nil {
				w.Close()
				break
			}

			slice := buffer[:n]
			locs := delim.FindAllSubmatchIndex(slice, -1)

			if len(locs) == 0 {
				accum.Write(slice)
			} else {
				start_idx := 0
				end_idx := 0
				for _, loc := range locs {
					end_idx = loc[1]
					data := append(accum.Bytes(), slice[start_idx:end_idx]...)
					w.Write(data)
					accum.Reset()
					start_idx = end_idx
				}

				if end_idx < n {
					accum.Write(slice[end_idx:])
				}
			}
		}

	}()

	return r
}

func readFrontSplit(ctx context.Context, delim *regexp.Regexp, lineChan chan string, f io.Reader, accum *bytes.Buffer) {

	buffer_size := 1048576 // 1MB

	// go func() {
	// defer w.Close()

	buffer := make([]byte, buffer_size)
	first := true
	for {
		select {
		case <-ctx.Done():
			return
		default:
			break
		}

		n, err := f.Read(buffer)
		if err != nil {
			break
		}

		slice := buffer[:n]
		locs := delim.FindAllSubmatchIndex(slice, -1)

		if len(locs) == 0 {
			accum.Write(slice)
		} else {

			line_begin_idx := 0
			line_end_idx := 0
			next_start := 0
			for _, loc := range locs {
				if first {
					first = false
					next_start = loc[0]
					if loc[0] == 0 && accum.Len() > 0 {
						lineChan <- accum.String()
						accum.Reset()
					}
					continue
				} else {
					line_begin_idx = next_start
				}

				line_end_idx = loc[0]
				next_start = loc[1] - (loc[1] - loc[0])
				data := bytes.Replace(slice[line_begin_idx:line_end_idx], []byte("\x0A"), nil, -1)
				data = append(accum.Bytes(), data...)
				lineChan <- string(data)
				accum.Reset()
				// data_trim := bytes.TrimRight(data, "\n")
				// log.Printf("%v -> %v", line_begin_idx, line_end_idx)
				// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", line_begin_idx, data_trim, line_end_idx)

			}

			data := slice[next_start:n]
			accum.Write(data)
			// w.Write(data)
			// lineChan <- string(data)
			// data_trim := bytes.TrimRight(data, "\n")
			// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", next_start, data, n)
		}
	}

	// lineChan <- string(accum.Bytes())
	// accum.Reset()
	// }()

	// <-ctx.Done()

}
<|endoftext|>


<commit_before>package isbn

// Source: exercism/problem-specifications
// Commit: adb99f7 isbn-verifier: Add test case with only 9 digits (#1221)
// Problem Specifications Version: 2.4.0

var testCases = []struct {
	isbn        string
	expected    bool
	description string
}{
	{"3-598-21508-8", true, "valid isbn number"},
	{"3-598-21508-9", false, "invalid isbn check digit"},
	{"3-598-21507-X", true, "valid isbn number with a check digit of 10"},
	{"3-598-21507-A", false, "check digit is a character other than X"},
	{"3-598-P1581-X", false, "invalid character in isbn"},
	{"3-598-2X507-9", false, "X is only valid as a check digit"},
	{"3598215088", true, "valid isbn without separating dashes"},
	{"359821507X", true, "isbn without separating dashes and X as check digit"},
	{"359821507", false, "isbn without check digit and dashes"},
	{"3598215078X", false, "too long isbn and no dashes"},
	{"3-598-21507", false, "isbn without check digit"},
	{"3-598-21507-XX", false, "too long isbn"},
	{"3-598-21515-X", false, "check digit of X should not be used for 0"},
	{"", false, "empty isbn"},
	{"134456729", false, "input is 9 characters"},
}
<commit_msg>isbn-verifier: update for new test cases<commit_after>package isbn

// Source: exercism/problem-specifications
// Commit: 3134243 isbn-verifier: Crafted input to catch more incorrect algorithms (#1255)
// Problem Specifications Version: 2.7.0

var testCases = []struct {
	isbn        string
	expected    bool
	description string
}{
	{"3-598-21508-8", true, "valid isbn number"},
	{"3-598-21508-9", false, "invalid isbn check digit"},
	{"3-598-21507-X", true, "valid isbn number with a check digit of 10"},
	{"3-598-21507-A", false, "check digit is a character other than X"},
	{"3-598-P1581-X", false, "invalid character in isbn"},
	{"3-598-2X507-9", false, "X is only valid as a check digit"},
	{"3598215088", true, "valid isbn without separating dashes"},
	{"359821507X", true, "isbn without separating dashes and X as check digit"},
	{"359821507", false, "isbn without check digit and dashes"},
	{"3598215078X", false, "too long isbn and no dashes"},
	{"00", false, "too short isbn"},
	{"3-598-21507", false, "isbn without check digit"},
	{"3-598-21515-X", false, "check digit of X should not be used for 0"},
	{"", false, "empty isbn"},
	{"134456729", false, "input is 9 characters"},
	{"3132P34035", false, "invalid characters are not ignored"},
	{"98245726788", false, "input is too long but contains a valid isbn"},
}
<|endoftext|>


<commit_before>package mig

import (
	"encoding/json"
	"errors"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"math/rand"
	"time"
)

type Action struct {
	ID uint64
	Name, Target, Check string
	ScheduledDate, ExpirationDate time.Time
	Arguments interface{}
	PGPSignature string
	PGPSignatureDate time.Time
}

type ExtendedAction struct{
	Action Action
	Status string
	StartTime, FinishTime, LastUpdateTime time.Time
	CommandIDs []uint64
	CmdCompleted, CmdCancelled, CmdTimedOut int
}

// ActionFromFile() reads an action from a local file on the file system
// and returns a mig.ExtendedAction structure
func ActionFromFile(path string) (ea ExtendedAction, err error){
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("mig.ActionFromFile(): %v", e)
		}
	}()
	// parse the json of the action into a mig.ExtendedAction
	fd, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(fd, &ea.Action)
	if err != nil {
		panic(err)
	}

	// syntax checking
	err = checkAction(ea.Action)
	if err != nil {
		panic(err)
	}

	// Populate the Extended attributes of the action
	ea.StartTime = time.Now().UTC()

	return
}

// genID returns an ID composed of a unix timestamp and a random CRC32
func GenID() uint64 {
	h := crc32.NewIEEE()
	t := time.Now().UTC().Format(time.RFC3339Nano)
	r := rand.New(rand.NewSource(65537))
	rand := string(r.Intn(1000000000))
	h.Write([]byte(t + rand))
	// concatenate timestamp and hash into 64 bits ID
	// id = <32 bits unix ts><32 bits CRC hash>
	id := uint64(time.Now().Unix())
	id = id << 32
	id += uint64(h.Sum32())
	return id
}

// checkAction verifies that the Action received contained all the
// necessary fields, and returns an error when it doesn't.
func checkAction(action Action) error {
	if action.Name == "" {
		return errors.New("Action.Name is empty. Expecting string.")
	}
	if action.Target == "" {
		return errors.New("Action.Target is empty. Expecting string.")
	}
	if action.Check == "" {
		return errors.New("Action.Check is empty. Expecting string.")
	}
	if action.ScheduledDate.String() == "" {
		return errors.New("Action.RunDate is empty. Expecting string.")
	}
	if action.ExpirationDate.String() == "" {
		return errors.New("Action.Expiration is empty. Expecting string.")
	}
	if action.Arguments == nil {
		return errors.New("Action.Arguments is nil. Expecting string.")
	}
	return nil
}

//  concatenates Action components into a string
func (a Action) String() (str string, err error) {
	str = "name=" + a.Name + "; "
	str += "target=" + a.Target + "; "
	str += "check=" + a.Check + "; "
	str += "scheduleddate=" + a.ScheduledDate.String() + "; "
	str += "expirationdate=" + a.ExpirationDate.String() + "; "

	args, err := json.Marshal(a.Arguments)
	str += "arguments='" + fmt.Sprintf("%s", args) + "';"

	return
}

<commit_msg>Action: add Validation function that verifies PGP signature<commit_after>package mig

import (
	"encoding/json"
	"errors"
	"fmt"
	"hash/crc32"
	"io/ioutil"
	"math/rand"
	"mig/pgp/verify"
	"time"
)

type Action struct {
	ID uint64
	Name, Target, Check string
	ScheduledDate, ExpirationDate time.Time
	Arguments interface{}
	PGPSignature string
	PGPSignatureDate time.Time
}

type ExtendedAction struct{
	Action Action
	Status string
	StartTime, FinishTime, LastUpdateTime time.Time
	CommandIDs []uint64
	CmdCompleted, CmdCancelled, CmdTimedOut int
}

// ActionFromFile() reads an action from a local file on the file system
// and returns a mig.ExtendedAction structure
func ActionFromFile(path string) (ea ExtendedAction, err error){
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("mig.ActionFromFile(): %v", e)
		}
	}()
	// parse the json of the action into a mig.ExtendedAction
	fd, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(fd, &ea.Action)
	if err != nil {
		panic(err)
	}

	// Populate the Extended attributes of the action
	ea.StartTime = time.Now().UTC()

	return
}

// genID returns an ID composed of a unix timestamp and a random CRC32
func GenID() uint64 {
	h := crc32.NewIEEE()
	t := time.Now().UTC().Format(time.RFC3339Nano)
	r := rand.New(rand.NewSource(65537))
	rand := string(r.Intn(1000000000))
	h.Write([]byte(t + rand))
	// concatenate timestamp and hash into 64 bits ID
	// id = <32 bits unix ts><32 bits CRC hash>
	id := uint64(time.Now().Unix())
	id = id << 32
	id += uint64(h.Sum32())
	return id
}

// checkAction verifies that the Action received contained all the
// necessary fields, and returns an error when it doesn't.
func (a Action) Validate() (err error) {
	if a.Name == "" {
		return errors.New("Action.Name is empty. Expecting string.")
	}
	if a.Target == "" {
		return errors.New("Action.Target is empty. Expecting string.")
	}
	if a.Check == "" {
		return errors.New("Action.Check is empty. Expecting string.")
	}
	if a.ScheduledDate.String() == "" {
		return errors.New("Action.RunDate is empty. Expecting string.")
	}
	if a.ExpirationDate.String() == "" {
		return errors.New("Action.Expiration is empty. Expecting string.")
	}
	if a.ScheduledDate.After(a.ExpirationDate) {
		return errors.New("Action.ExpirationDate is set before Action.ScheduledDate.")
	}
	if time.Now().After(a.ExpirationDate) {
		return errors.New("Action.ExpirationDate is passed. Action has expired.")
	}
	if a.Arguments == nil {
		return errors.New("Action.Arguments is nil. Expecting string.")
	}
	if a.PGPSignature == "" {
		return errors.New("Action.PGPSignature is empty. Expecting string.")
	}

	// Verify the signature
	astr, err := a.String()
	if err != nil {
		return errors.New("Failed to stringify action")
	}
	valid, _, err := verify.Verify(astr, a.PGPSignature)
	if err != nil {
		return errors.New("Failed to verify PGP Signature")
	}
	if !valid {
		return errors.New("Invalid PGP Signature")
	}

	return nil
}

//  concatenates Action components into a string
func (a Action) String() (str string, err error) {
	str = "name=" + a.Name + "; "
	str += "target=" + a.Target + "; "
	str += "check=" + a.Check + "; "
	str += "scheduleddate=" + a.ScheduledDate.String() + "; "
	str += "expirationdate=" + a.ExpirationDate.String() + "; "

	args, err := json.Marshal(a.Arguments)
	str += "arguments='" + fmt.Sprintf("%s", args) + "';"

	return
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"
	"text/scanner"

	"github.com/crgimenes/goConfig"
)

type config struct {
	InputFile  string `json:"i" cfg:"i"`
	OutputFile string `json:"o" cfg:"o"`
}

type fileInfo struct {
	Version     string
	PackageName string
	ObjectName  string
	Height      int
	Width       int
}

func main() {

	cfg := config{}

	goConfig.PrefixEnv = "BMV"
	err := goConfig.Parse(&cfg)
	if err != nil {
		os.Exit(1)
	}

	if cfg.InputFile == "" {
		goConfig.Usage()
		os.Exit(1)
	}

	err = parse(cfg.InputFile)
	if err != nil {
		println(err.Error())
		os.Exit(1)
	}

}

func parse(fileName string) (err error) {
	var iFile *os.File
	//var oFile *os.File

	iFile, err = os.Open(fileName)
	if err != nil {
		return
	}
	defer func() {
		err = iFile.Close()
		if err != nil {
			println(err.Error())
			os.Exit(1)
		}
	}()

	fi := fileInfo{}

	var s scanner.Scanner
	s.Init(iFile)
	s.Filename = fileName
	s.Mode = scanner.ScanIdents |
		scanner.ScanFloats |
		scanner.ScanChars |
		scanner.ScanStrings |
		scanner.ScanRawStrings |
		scanner.ScanComments
	var tok rune

	ntok := 0
	for tok != scanner.EOF {
		tok = s.Scan()
		if tok == scanner.Comment {
			println(s.TokenText())
		} else {

			switch ntok {
			case 0:
				fi.Version = s.TokenText()
			case 1:
				fi.PackageName = s.TokenText()
			case 2:
				fi.ObjectName = s.TokenText()
			case 3:
				var h int
				h, err = strconv.Atoi(s.TokenText())
				if err != nil {
					return
				}
				fi.Height = h
			case 4:
				var w int
				w, err = strconv.Atoi(s.TokenText())
				if err != nil {
					return
				}
				fi.Width = w
			default:
				fmt.Println("At position", s.Pos(), ":", s.TokenText(), ntok)
			}

			ntok++
		}
	}
	return
}
<commit_msg>code generation test<commit_after>package main

import (
	"os"
	"strconv"
	"text/scanner"

	"github.com/crgimenes/goConfig"
)

type config struct {
	InputFile  string `json:"i" cfg:"i"`
	OutputFile string `json:"o" cfg:"o"`
}

type fileInfo struct {
	Version     string
	PackageName string
	ObjectName  string
	Height      int
	Width       int
}

const alert = "/* Automatically generated, do not change manually. */"

func main() {

	cfg := config{}

	goConfig.PrefixEnv = "BMV"
	err := goConfig.Parse(&cfg)
	if err != nil {
		os.Exit(1)
	}

	if cfg.InputFile == "" {
		goConfig.Usage()
		os.Exit(1)
	}

	err = parse(cfg.InputFile)
	if err != nil {
		println(err.Error())
		os.Exit(1)
	}

}

func parse(fileName string) (err error) {

	var out string

	out = alert + "\n\n"

	var iFile *os.File
	//var oFile *os.File

	iFile, err = os.Open(fileName)
	if err != nil {
		return
	}
	defer func() {
		err = iFile.Close()
		if err != nil {
			println(err.Error())
			os.Exit(1)
		}
	}()

	fi := fileInfo{}

	var s scanner.Scanner
	s.Init(iFile)
	s.Filename = fileName
	s.Mode = scanner.ScanIdents |
		scanner.ScanFloats |
		scanner.ScanChars |
		scanner.ScanStrings |
		scanner.ScanRawStrings |
		scanner.ScanComments
	var tok rune

	ntok := 0
	for tok != scanner.EOF {
		tok = s.Scan()
		if tok == scanner.Comment {
			out += s.TokenText() + "\n"
		} else {

			switch ntok {
			case 0:
				fi.Version = s.TokenText()
			case 1:
				fi.PackageName = s.TokenText()
				out += "\npackage " + fi.PackageName + "\n\n"
			case 2:
				fi.ObjectName = s.TokenText()
				out += "var " + fi.PackageName + " [][]byte" + "\n\n"
				out += "func Load" + fi.PackageName + "() {\n\n"
			case 3:
				var h int
				h, err = strconv.Atoi(s.TokenText())
				if err != nil {
					return
				}
				fi.Height = h
			case 4:
				var w int
				w, err = strconv.Atoi(s.TokenText())
				if err != nil {
					return
				}
				fi.Width = w
			default:
				//fmt.Println("At position", s.Pos(), ":", s.TokenText(), ntok)
				out += s.TokenText() + "\n"
			}

			ntok++
		}
	}
	out += "}\n"

	println(out)

	return
}
<|endoftext|>


<commit_before>package urknall

import (
	"testing"
	. "github.com/smartystreets/goconvey/convey"
)

func TestUserHandling(t *testing.T) {
	Convey("Given a host with no user specified", t, func() {
		user := ""
		Convey("When the New function is called", func() {
			h := &Host{User: user}
			Convey("Then a host value is returned", func() {
				So(h, ShouldNotBeNil)
			})
			Convey("The returned host's user equals root", func() {
				So(h.user(), ShouldEqual, "root")
			})
			Convey("The returned host's 'isSudoRequired' predicate return false", func() {
				So(h.isSudoRequired(), ShouldBeFalse)
			})
		})
	})

	Convey("Given a host with user set to 'root'", t, func() {
		user := "root"
		Convey("When the New function is called", func() {
			h := &Host{User: user}
			Convey("Then a host value is returned", func() {
				So(h, ShouldNotBeNil)
			})
			Convey("The returned host's user equals root", func() {
				So(h.user(), ShouldEqual, "root")
			})
			Convey("The returned host's 'isSudoRequired' predicate return false", func() {
				So(h.isSudoRequired(), ShouldBeFalse)
			})
		})
	})

	Convey("Given a host with user set to something not being 'root'", t, func() {
		user := "gfrey"
		Convey("When the New function is called", func() {
			h := &Host{User: user}
			Convey("Then a host value is returned", func() {
				So(h, ShouldNotBeNil)
			})
			Convey("The returned host's user equals the given one", func() {
				So(h.user(), ShouldEqual, user)
			})
			Convey("The returned host's 'isSudoRequired' predicate return true", func() {
				So(h.isSudoRequired(), ShouldBeTrue)
			})
		})
	})
}

func TestInterfaceHandling(t *testing.T) {
	defaultInterface := "eth0"
	Convey("Given a host", t, func() {
		h := &Host{IP: "127.0.0.1"}
		list := &PackageList{}
		Convey("When no interface is set", func() {
			Convey("And the Interface method is called", func() {
				v := h.publicInterface()
				Convey("Then the interface is set to the default", func() {
					So(v, ShouldEqual, defaultInterface)
				})
			})
		})

		Convey("When adding packages", func() {
			So(func() { list.AddPackage("pkg", nil) }, ShouldNotPanic)
			So(func() { list.AddPackage("other_pkg", nil) }, ShouldNotPanic)
			Convey("when adding a package with the same name", func() {
				So(func() { list.AddPackage("pkg", nil) }, ShouldPanic)
			})
		})

		Convey("When the interface is explicitly set to the default", func() {
			h.Interface = defaultInterface
			Convey("And the Interface method is called", func() {
				v := h.publicInterface()
				Convey("Then the interface is set to the default", func() {
					So(v, ShouldEqual, defaultInterface)
				})
			})
		})

		Convey("When the interface is set to 'tun0'", func() {
			h.Interface = "tun0"
			Convey("And the Interface method is called", func() {
				v := h.publicInterface()
				Convey("Then the interface is set to 'tun0'", func() {
					So(v, ShouldEqual, "tun0")
				})
			})
		})
	})
}
<commit_msg>fix tests<commit_after>package urknall

import (
	"testing"

	"github.com/dynport/urknall/ssh"
	. "github.com/smartystreets/goconvey/convey"
)

func TestUserHandling(t *testing.T) {
	Convey("Given a host with no user specified", t, func() {
		Convey("When the New function is called", func() {
			h := &ssh.Host{Address: "127.0.0.1"}
			Convey("Then a host value is returned", func() {
				So(h, ShouldNotBeNil)
			})
			Convey("The returned host's user equals root", func() {
				So(h.User(), ShouldEqual, "root")
			})
		})
	})

	Convey("Given a host with user set to 'root'", t, func() {
		Convey("When the New function is called", func() {
			h := &ssh.Host{Address: "root@127.0.0.1"}
			Convey("Then a host value is returned", func() {
				So(h, ShouldNotBeNil)
			})
			Convey("The returned host's user equals root", func() {
				So(h.User(), ShouldEqual, "root")
			})
		})
	})

	Convey("Given a host with user set to something not being 'root'", t, func() {
		Convey("When the New function is called", func() {
			h := &ssh.Host{Address: "gfrey@127.0.0.1"}
			Convey("Then a host value is returned", func() {
				So(h, ShouldNotBeNil)
			})
			Convey("The returned host's user equals the given one", func() {
				So(h.User(), ShouldEqual, "gfrey")
			})
		})
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/muka/redzilla/model"
	"github.com/muka/redzilla/service"
	"github.com/spf13/viper"
)

func main() {

	viper.SetDefault("Network", "redzilla")
	viper.SetDefault("APIPort", ":3000")
	viper.SetDefault("Domain", "redzilla.localhost")
	viper.SetDefault("ImageName", "nodered/node-red-docker")
	viper.SetDefault("StorePath", "./data/store")
	viper.SetDefault("InstanceDataPath", "./data/instances")
	viper.SetDefault("InstanceConfigPath", "./data/config")
	viper.SetDefault("LogLevel", "info")
	viper.SetDefault("Autostart", false)
	viper.SetDefault("EnvPrefix", "")
	viper.SetDefault("AuthType", "none")
	viper.SetDefault("AuthHttpMethod", "GET")
	viper.SetDefault("AuthHttpUrl", "")
	viper.SetDefault("AuthHttpHeader", "Authorization")

	viper.SetEnvPrefix("redzilla")
	viper.AutomaticEnv()

	configFile := "./config.yml"
	if os.Getenv("REDZILLA_CONFIG") != "" {
		configFile = os.Getenv("REDZILLA_CONFIG")
	}

	if _, err := os.Stat(configFile); !os.IsNotExist(err) {
		viper.SetConfigFile(configFile)
		err := viper.ReadInConfig()
		if err != nil {
			panic(fmt.Errorf("Failed to read from config file: %s", err))
		}
	}

	cfg := &model.Config{
		Network:            viper.GetString("Network"),
		APIPort:            viper.GetString("APIPort"),
		Domain:             viper.GetString("Domain"),
		ImageName:          viper.GetString("ImageName"),
		StorePath:          viper.GetString("StorePath"),
		InstanceDataPath:   viper.GetString("InstanceDataPath"),
		InstanceConfigPath: viper.GetString("InstanceConfigPath"),
		LogLevel:           viper.GetString("LogLevel"),
		Autostart:          viper.GetBool("Autostart"),
		EnvPrefix:          viper.GetString("EnvPrefix"),
		AuthType:           viper.GetString("AuthType"),
	}

	if strings.ToLower(cfg.AuthType) == "http" {

		a := new(model.AuthHttp)
		a.Method = viper.GetString("AuthHttpMethod"),
		a.URL = viper.GetString("AuthHttpUrl"),
		a.Header = viper.GetString("AuthHttpHeader"),

		//setup the body template
		rawTpl := viper.GetString("AuthHttpHeader")
		if len(rawTpl) > 0 {
			bodyTemplate, err := template.New("").Parse(rawTpl)
			if err != nil {
				panic(fmt.Errorf("Failed to parse template: %s", err))
			}
			cfg.AuthHttpBody = bodyTemplate
		}
	}

	lvl, err := logrus.ParseLevel(cfg.LogLevel)
	if err != nil {
		panic(fmt.Errorf("Failed to parse level %s: %s", cfg.LogLevel, err))
	}
	logrus.SetLevel(lvl)

	if lvl != logrus.DebugLevel {
		gin.SetMode(gin.ReleaseMode)
	}

	logrus.Debugf("%++v", cfg)

	defer service.Stop(cfg)

	err = service.Start(cfg)
	if err != nil {
		logrus.Errorf("Error: %s", err.Error())
		panic(err)
	}

}
<commit_msg>main fix<commit_after>package main

import (
	"fmt"
	"html/template"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/muka/redzilla/model"
	"github.com/muka/redzilla/service"
	"github.com/spf13/viper"
)

func main() {

	viper.SetDefault("Network", "redzilla")
	viper.SetDefault("APIPort", ":3000")
	viper.SetDefault("Domain", "redzilla.localhost")
	viper.SetDefault("ImageName", "nodered/node-red-docker")
	viper.SetDefault("StorePath", "./data/store")
	viper.SetDefault("InstanceDataPath", "./data/instances")
	viper.SetDefault("InstanceConfigPath", "./data/config")
	viper.SetDefault("LogLevel", "info")
	viper.SetDefault("Autostart", false)
	viper.SetDefault("EnvPrefix", "")
	viper.SetDefault("AuthType", "none")
	viper.SetDefault("AuthHttpMethod", "GET")
	viper.SetDefault("AuthHttpUrl", "")
	viper.SetDefault("AuthHttpHeader", "Authorization")

	viper.SetEnvPrefix("redzilla")
	viper.AutomaticEnv()

	configFile := "./config.yml"
	if os.Getenv("REDZILLA_CONFIG") != "" {
		configFile = os.Getenv("REDZILLA_CONFIG")
	}

	if _, err := os.Stat(configFile); !os.IsNotExist(err) {
		viper.SetConfigFile(configFile)
		err := viper.ReadInConfig()
		if err != nil {
			panic(fmt.Errorf("Failed to read from config file: %s", err))
		}
	}

	cfg := &model.Config{
		Network:            viper.GetString("Network"),
		APIPort:            viper.GetString("APIPort"),
		Domain:             viper.GetString("Domain"),
		ImageName:          viper.GetString("ImageName"),
		StorePath:          viper.GetString("StorePath"),
		InstanceDataPath:   viper.GetString("InstanceDataPath"),
		InstanceConfigPath: viper.GetString("InstanceConfigPath"),
		LogLevel:           viper.GetString("LogLevel"),
		Autostart:          viper.GetBool("Autostart"),
		EnvPrefix:          viper.GetString("EnvPrefix"),
		AuthType:           viper.GetString("AuthType"),
	}

	if strings.ToLower(cfg.AuthType) == "http" {

		a := new(model.AuthHttp)
		a.Method = viper.GetString("AuthHttpMethod")
		a.URL = viper.GetString("AuthHttpUrl")
		a.Header = viper.GetString("AuthHttpHeader")

		//setup the body template
		rawTpl := viper.GetString("AuthHttpHeader")
		if len(rawTpl) > 0 {
			bodyTemplate, err := template.New("").Parse(rawTpl)
			if err != nil {
				panic(fmt.Errorf("Failed to parse template: %s", err))
			}
			a.Body = bodyTemplate
		}

		cfg.AuthHttp = a
	}

	lvl, err := logrus.ParseLevel(cfg.LogLevel)
	if err != nil {
		panic(fmt.Errorf("Failed to parse level %s: %s", cfg.LogLevel, err))
	}
	logrus.SetLevel(lvl)

	if lvl != logrus.DebugLevel {
		gin.SetMode(gin.ReleaseMode)
	}

	logrus.Debugf("%++v", cfg)

	defer service.Stop(cfg)

	err = service.Start(cfg)
	if err != nil {
		logrus.Errorf("Error: %s", err.Error())
		panic(err)
	}

}
<|endoftext|>


<commit_before>// Copyright 2016 The StudyGolang Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// http://studygolang.com
// Author: polaris	polaris@studygolang.com

package main

import (
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"strconv"
	"time"

	. "github.com/polaris1119/config"

	"github.com/studygolang/studygolang/modules/global"
	pwm "github.com/studygolang/studygolang/modules/http/middleware"
	"github.com/studygolang/studygolang/modules/http/controller"
	"github.com/studygolang/studygolang/modules/http/controller/admin"
	"github.com/studygolang/studygolang/modules/http/controller/app"
	"github.com/studygolang/studygolang/modules/logic"
	"github.com/studygolang/studygolang/cmd"

	"github.com/fatih/structs"
	echo "github.com/labstack/echo/v4"
	mw "github.com/labstack/echo/v4/middleware"
	"github.com/polaris1119/keyword"
	"github.com/polaris1119/logger"
	thirdmw "github.com/studygolang/studygolang/modules/middleware"
)

func init() {
	// 设置随机数种子
	rand.Seed(time.Now().Unix())

	structs.DefaultTagName = "json"
}

func main() {
	if len(os.Args) >= 2 {
		switch os.Args[1] {
		case "indexer":
			cmd.Indexer()
			return
		case "crawler":
			cmd.Crawler()
			return
		case "migrator":
			cmd.Migrator()
			return
		}
	}

	// 支持根据参数打印版本信息
	global.PrintVersion(os.Stdout)

	savePid()

	global.App.Init(logic.WebsiteSetting.Domain)

	logger.Init(ROOT+"/log", ConfigFile.MustValue("global", "log_level", "DEBUG"))

	go keyword.Extractor.Init(keyword.DefaultProps, true, ROOT+"/data/programming.txt,"+ROOT+"/data/dictionary.txt")

	go logic.Book.ClearRedisUser()

	go ServeBackGround()
	// go pprof
	Pprof(ConfigFile.MustValue("global", "pprof", "127.0.0.1:8096"))

	e := echo.New()

	serveStatic(e)

	e.Use(thirdmw.EchoLogger())
	e.Use(mw.Recover())
	e.Use(pwm.Installed(filterPrefixs))
	e.Use(pwm.HTTPError())
	e.Use(pwm.AutoLogin())

	// 评论后不会立马显示出来，暂时缓存去掉
	// frontG := e.Group("", thirdmw.EchoCache())
	frontG := e.Group("")
	controller.RegisterRoutes(frontG)

	frontG.GET("/admin", echo.HandlerFunc(admin.AdminIndex), pwm.NeedLogin(), pwm.AdminAuth())
	adminG := e.Group("/admin", pwm.NeedLogin(), pwm.AdminAuth())
	admin.RegisterRoutes(adminG)

	// appG := e.Group("/app", thirdmw.EchoCache())
	appG := e.Group("/app")
	app.RegisterRoutes(appG)

	e.Server.Addr = getAddr()
	gracefulRun(e.Server)
}

func getAddr() string {
	host := ConfigFile.MustValue("listen", "host", "")
	if host == "" {
		global.App.Host = "localhost"
	} else {
		global.App.Host = host
	}
	global.App.Port = ConfigFile.MustValue("listen", "port", "8088")
	return host + ":" + global.App.Port
}

func savePid() {
	pidFilename := ROOT + "/pid/" + filepath.Base(os.Args[0]) + ".pid"
	pid := os.Getpid()

	ioutil.WriteFile(pidFilename, []byte(strconv.Itoa(pid)), 0755)
}
<commit_msg>format imports<commit_after>// Copyright 2016 The StudyGolang Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// http://studygolang.com
// Author: polaris	polaris@studygolang.com

package main

import (
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"github.com/studygolang/studygolang/modules/global"
	pwm "github.com/studygolang/studygolang/modules/http/middleware"
	"github.com/studygolang/studygolang/modules/http/controller"
	"github.com/studygolang/studygolang/modules/http/controller/admin"
	"github.com/studygolang/studygolang/modules/http/controller/app"
	"github.com/studygolang/studygolang/modules/logic"
	"github.com/studygolang/studygolang/cmd"
	thirdmw "github.com/studygolang/studygolang/modules/middleware"

	"github.com/fatih/structs"
	echo "github.com/labstack/echo/v4"
	mw "github.com/labstack/echo/v4/middleware"
	"github.com/polaris1119/keyword"
	"github.com/polaris1119/logger"
	. "github.com/polaris1119/config"
)

func init() {
	// 设置随机数种子
	rand.Seed(time.Now().Unix())

	structs.DefaultTagName = "json"
}

func main() {
	if len(os.Args) >= 2 {
		switch os.Args[1] {
		case "indexer":
			cmd.Indexer()
			return
		case "crawler":
			cmd.Crawler()
			return
		case "migrator":
			cmd.Migrator()
			return
		}
	}

	// 支持根据参数打印版本信息
	global.PrintVersion(os.Stdout)

	savePid()

	global.App.Init(logic.WebsiteSetting.Domain)

	logger.Init(ROOT+"/log", ConfigFile.MustValue("global", "log_level", "DEBUG"))

	go keyword.Extractor.Init(keyword.DefaultProps, true, ROOT+"/data/programming.txt,"+ROOT+"/data/dictionary.txt")

	go logic.Book.ClearRedisUser()

	go ServeBackGround()
	// go pprof
	Pprof(ConfigFile.MustValue("global", "pprof", "127.0.0.1:8096"))

	e := echo.New()

	serveStatic(e)

	e.Use(thirdmw.EchoLogger())
	e.Use(mw.Recover())
	e.Use(pwm.Installed(filterPrefixs))
	e.Use(pwm.HTTPError())
	e.Use(pwm.AutoLogin())

	// 评论后不会立马显示出来，暂时缓存去掉
	// frontG := e.Group("", thirdmw.EchoCache())
	frontG := e.Group("")
	controller.RegisterRoutes(frontG)

	frontG.GET("/admin", echo.HandlerFunc(admin.AdminIndex), pwm.NeedLogin(), pwm.AdminAuth())
	adminG := e.Group("/admin", pwm.NeedLogin(), pwm.AdminAuth())
	admin.RegisterRoutes(adminG)

	// appG := e.Group("/app", thirdmw.EchoCache())
	appG := e.Group("/app")
	app.RegisterRoutes(appG)

	e.Server.Addr = getAddr()
	gracefulRun(e.Server)
}

func getAddr() string {
	host := ConfigFile.MustValue("listen", "host", "")
	if host == "" {
		global.App.Host = "localhost"
	} else {
		global.App.Host = host
	}
	global.App.Port = ConfigFile.MustValue("listen", "port", "8088")
	return host + ":" + global.App.Port
}

func savePid() {
	pidFilename := ROOT + "/pid/" + filepath.Base(os.Args[0]) + ".pid"
	pid := os.Getpid()

	ioutil.WriteFile(pidFilename, []byte(strconv.Itoa(pid)), 0755)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/mediocregopher/flagconfig"
	"io"
	"net"
)

var Local, Remote string

func CopyClose(dst io.WriteCloser, src io.ReadCloser) {
	io.Copy(dst, src)
	dst.Close()
	src.Close()
}

func main() {
	fc := flagconfig.New("tcp-proxy")
	fc.DisallowConfig()
	fc.StrParam("local", "Address to listen on", ":4444")
	fc.RequiredStrParam("remote", "Address to proxy to")

	if err := fc.Parse(); err != nil {
		panic(err)
	}

	Local, Remote = fc.GetStr("local"), fc.GetStr("remote")

	l, err := net.Listen("tcp", Local)
	if err != nil {
		panic(err)
	}

	for {
		lconn, err := l.Accept()
		if err != nil {
			panic(err)
		}

		rconn, err := net.Dial("tcp", Remote)
		if err != nil {
			panic(err)
		}

		go CopyClose(lconn, rconn)
		go CopyClose(rconn, lconn)
	}
}
<commit_msg>add better logging and error handling<commit_after>package main

import (
	"io"
	"log"
	"net"

	"github.com/mediocregopher/flagconfig"
)

var Local, Remote string

func CopyClose(dst io.WriteCloser, src io.ReadCloser) {
	io.Copy(dst, src)
	dst.Close()
	src.Close()
}

func main() {
	fc := flagconfig.New("tcp-proxy")
	fc.DisallowConfig()
	fc.StrParam("local", "Address to listen on", ":4444")
	fc.RequiredStrParam("remote", "Address to proxy to")

	if err := fc.Parse(); err != nil {
		log.Fatal(err)
	}

	Local, Remote = fc.GetStr("local"), fc.GetStr("remote")

	l, err := net.Listen("tcp", Local)
	if err != nil {
		log.Fatal(err)
	}

	for {
		lconn, err := l.Accept()
		if err != nil {
			log.Fatal(err)
		}

		rconn, err := net.Dial("tcp", Remote)
		if err != nil {
			log.Print(err)
			lconn.Close()
			continue
		}

		go CopyClose(lconn, rconn)
		go CopyClose(rconn, lconn)
	}
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"log"
	"net/http"
)

const version = "0.1.1"

var printVersion bool

func init() {
	flag.BoolVar(&printVersion, "v", false, "Print version and exit")
	flag.Parse()
}

func buildMux() *pat.PatternServeMux {
	m := pat.New()
	m.Post("/resources", http.HandlerFunc(Add))
	m.Post("/resources/:name", Handler(Bind))
	m.Del("/resources/:name/hostname/:hostname", Handler(Unbind))
	m.Del("/resources/:name", Handler(Remove))
	m.Get("/resources/:name/status", Handler(Status))
	return m
}

func main() {
	if printVersion {
		fmt.Printf("mongoapi version %s", version)
		return
	}
	listen := coalesceEnv("0.0.0.0:3333", "MONGODB_API_LISTEN")
	log.Fatal(http.ListenAndServe(listen, buildMux()))
}
<commit_msg>main: return http.Handler on buildMux<commit_after>// Copyright 2013 mongoapi authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"log"
	"net/http"
)

const version = "0.1.1"

var printVersion bool

func init() {
	flag.BoolVar(&printVersion, "v", false, "Print version and exit")
	flag.Parse()
}

func buildMux() http.Handler {
	m := pat.New()
	m.Post("/resources", http.HandlerFunc(Add))
	m.Post("/resources/:name", Handler(Bind))
	m.Del("/resources/:name/hostname/:hostname", Handler(Unbind))
	m.Del("/resources/:name", Handler(Remove))
	m.Get("/resources/:name/status", Handler(Status))
	return m
}

func main() {
	if printVersion {
		fmt.Printf("mongoapi version %s", version)
		return
	}
	listen := coalesceEnv("0.0.0.0:3333", "MONGODB_API_LISTEN")
	log.Fatal(http.ListenAndServe(listen, buildMux()))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"

	"github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/manifest"
	"github.com/cloudfoundry/cli/plugin"
	go_i18n "github.com/nicksnyder/go-i18n/i18n"
)

var PluginVersion string

type CfPlugin struct {
	Connection plugin.CliConnection
	Deployer   BlueGreenDeployer
}

func (p *CfPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	if len(args) > 0 && args[0] == "CLI-MESSAGE-UNINSTALL" {
		return
	}

	p.Connection = cliConnection

	defaultCfDomain, err := p.DefaultCfDomain()
	if err != nil {
		fmt.Println("Failed to get default shared domain")
		os.Exit(1)
	}

	p.Deployer.Setup(cliConnection)

	if len(args) < 2 {
		fmt.Println("App name must be provided")
		os.Exit(1)
	}

	if !p.Deploy(defaultCfDomain, manifest.ManifestDiskRepository{}, args) {
		fmt.Println("Smoke tests failed")
		os.Exit(1)
	}
}

func (p *CfPlugin) Deploy(defaultCfDomain string, repo manifest.ManifestRepository, args []string) bool {
	appName := args[1]

	p.Deployer.DeleteAllAppsExceptLiveApp(appName)
	liveAppName, liveAppRoutes := p.Deployer.LiveApp(appName)

	newAppName := appName + "-new"

	tempRoute := Route{Host: newAppName, Domain: Domain{Name: defaultCfDomain}}

	p.Deployer.PushNewApp(newAppName, tempRoute)

	newAppRoutes := []Route{}

	f := ManifestAppFinder{AppName: appName, Repo: repo}
	if manifestRoutes := f.RoutesFromManifest(defaultCfDomain); manifestRoutes != nil {
		newAppRoutes = append(newAppRoutes, manifestRoutes...)
	}

	uniqueRoutes := p.UnionRouteLists(newAppRoutes, liveAppRoutes)

	promoteNewApp := true
	smokeTestScript := ExtractIntegrationTestScript(args)
	if smokeTestScript != "" {
		promoteNewApp = p.Deployer.RunSmokeTests(smokeTestScript, tempRoute.FQDN())
	}

	p.Deployer.UnmapRoutesFromApp(newAppName, tempRoute)

	if promoteNewApp {
		if liveAppName != "" {
			p.Deployer.MapRoutesToApp(newAppName, uniqueRoutes...)
			p.Deployer.RenameApp(liveAppName, appName+"-old")
			p.Deployer.RenameApp(newAppName, appName)
			p.Deployer.UnmapRoutesFromApp(appName+"-old", liveAppRoutes...)
		} else {
			p.Deployer.MapRoutesToApp(newAppName, newAppRoutes...)
			p.Deployer.RenameApp(newAppName, appName)
		}
		return true
	} else {
		p.Deployer.RenameApp(newAppName, appName+"-failed")
		return false
	}
}

func (p *CfPlugin) UnionRouteLists(listA []Route, listB []Route) []Route {
	duplicateList := append(listA, listB...)

	routesSet := make(map[Route]struct{})

	for _, route := range duplicateList {
		routesSet[route] = struct{}{}
	}

	uniqueRoutes := []Route{}
	for route := range routesSet {
		uniqueRoutes = append(uniqueRoutes, route)
	}
	return uniqueRoutes
}

func (p *CfPlugin) GetMetadata() plugin.PluginMetadata {
	var major, minor, build int
	fmt.Sscanf(PluginVersion, "%d.%d.%d", &major, &minor, &build)

	return plugin.PluginMetadata{
		Name: "blue-green-deploy",
		Version: plugin.VersionType{
			Major: major,
			Minor: minor,
			Build: build,
		},
		Commands: []plugin.Command{
			{
				Name:     "blue-green-deploy",
				Alias:    "bgd",
				HelpText: "Zero-downtime deploys with smoke tests",
				UsageDetails: plugin.Usage{
					Usage: "blue-green-deploy APP_NAME [--smoke-test TEST_SCRIPT]",
					Options: map[string]string{
						"smoke-test": "The test script to run.",
					},
				},
			},
		},
	}
}

func (p *CfPlugin) DefaultCfDomain() (domain string, err error) {
	var res []string
	if res, err = p.Connection.CliCommandWithoutTerminalOutput("curl", "/v2/shared_domains"); err != nil {
		return
	}

	response := struct {
		Resources []struct {
			Entity struct {
				Name string
			}
		}
	}{}

	if err = json.Unmarshal([]byte(res[0]), &response); err != nil {
		return
	}

	domain = response.Resources[0].Entity.Name
	return
}

func ExtractIntegrationTestScript(args []string) string {
	f := flag.NewFlagSet("blue-green-deploy", flag.ExitOnError)
	script := f.String("smoke-test", "", "")
	f.Parse(args[2:])
	return *script
}

func main() {
	// T needs to point to a translate func, otherwise cf internals blow up
	i18n.T, _ = go_i18n.Tfunc("")
	p := CfPlugin{
		Deployer: &BlueGreenDeploy{
			ErrorFunc: func(message string, err error) {
				fmt.Printf("%v - %v\n", message, err)
				os.Exit(1)
			},
			Out: os.Stdout,
		},
	}

	plugin.Start(&p)
}
<commit_msg>Change order to be more logical<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"

	"github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/manifest"
	"github.com/cloudfoundry/cli/plugin"
	go_i18n "github.com/nicksnyder/go-i18n/i18n"
)

var PluginVersion string

type CfPlugin struct {
	Connection plugin.CliConnection
	Deployer   BlueGreenDeployer
}

func (p *CfPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	if len(args) > 0 && args[0] == "CLI-MESSAGE-UNINSTALL" {
		return
	}

	p.Connection = cliConnection

	defaultCfDomain, err := p.DefaultCfDomain()
	if err != nil {
		fmt.Println("Failed to get default shared domain")
		os.Exit(1)
	}

	p.Deployer.Setup(cliConnection)

	if len(args) < 2 {
		fmt.Println("App name must be provided")
		os.Exit(1)
	}

	if !p.Deploy(defaultCfDomain, manifest.ManifestDiskRepository{}, args) {
		fmt.Println("Smoke tests failed")
		os.Exit(1)
	}
}

func (p *CfPlugin) Deploy(defaultCfDomain string, repo manifest.ManifestRepository, args []string) bool {
	appName := args[1]

	p.Deployer.DeleteAllAppsExceptLiveApp(appName)
	liveAppName, liveAppRoutes := p.Deployer.LiveApp(appName)

	newAppName := appName + "-new"
	tempRoute := Route{Host: newAppName, Domain: Domain{Name: defaultCfDomain}}
	p.Deployer.PushNewApp(newAppName, tempRoute)

	promoteNewApp := true
	smokeTestScript := ExtractIntegrationTestScript(args)
	if smokeTestScript != "" {
		promoteNewApp = p.Deployer.RunSmokeTests(smokeTestScript, tempRoute.FQDN())
	}

	newAppRoutes := []Route{}
	f := ManifestAppFinder{AppName: appName, Repo: repo}
	if manifestRoutes := f.RoutesFromManifest(defaultCfDomain); manifestRoutes != nil {
		newAppRoutes = append(newAppRoutes, manifestRoutes...)
	}
	uniqueRoutes := p.UnionRouteLists(newAppRoutes, liveAppRoutes)

	p.Deployer.UnmapRoutesFromApp(newAppName, tempRoute)

	if promoteNewApp {
		if liveAppName != "" {
			p.Deployer.MapRoutesToApp(newAppName, uniqueRoutes...)
			p.Deployer.RenameApp(liveAppName, appName+"-old")
			p.Deployer.RenameApp(newAppName, appName)
			p.Deployer.UnmapRoutesFromApp(appName+"-old", liveAppRoutes...)
		} else {
			p.Deployer.MapRoutesToApp(newAppName, newAppRoutes...)
			p.Deployer.RenameApp(newAppName, appName)
		}
		return true
	} else {
		p.Deployer.RenameApp(newAppName, appName+"-failed")
		return false
	}
}

func (p *CfPlugin) UnionRouteLists(listA []Route, listB []Route) []Route {
	duplicateList := append(listA, listB...)

	routesSet := make(map[Route]struct{})

	for _, route := range duplicateList {
		routesSet[route] = struct{}{}
	}

	uniqueRoutes := []Route{}
	for route := range routesSet {
		uniqueRoutes = append(uniqueRoutes, route)
	}
	return uniqueRoutes
}

func (p *CfPlugin) GetMetadata() plugin.PluginMetadata {
	var major, minor, build int
	fmt.Sscanf(PluginVersion, "%d.%d.%d", &major, &minor, &build)

	return plugin.PluginMetadata{
		Name: "blue-green-deploy",
		Version: plugin.VersionType{
			Major: major,
			Minor: minor,
			Build: build,
		},
		Commands: []plugin.Command{
			{
				Name:     "blue-green-deploy",
				Alias:    "bgd",
				HelpText: "Zero-downtime deploys with smoke tests",
				UsageDetails: plugin.Usage{
					Usage: "blue-green-deploy APP_NAME [--smoke-test TEST_SCRIPT]",
					Options: map[string]string{
						"smoke-test": "The test script to run.",
					},
				},
			},
		},
	}
}

func (p *CfPlugin) DefaultCfDomain() (domain string, err error) {
	var res []string
	if res, err = p.Connection.CliCommandWithoutTerminalOutput("curl", "/v2/shared_domains"); err != nil {
		return
	}

	response := struct {
		Resources []struct {
			Entity struct {
				Name string
			}
		}
	}{}

	if err = json.Unmarshal([]byte(res[0]), &response); err != nil {
		return
	}

	domain = response.Resources[0].Entity.Name
	return
}

func ExtractIntegrationTestScript(args []string) string {
	f := flag.NewFlagSet("blue-green-deploy", flag.ExitOnError)
	script := f.String("smoke-test", "", "")
	f.Parse(args[2:])
	return *script
}

func main() {
	// T needs to point to a translate func, otherwise cf internals blow up
	i18n.T, _ = go_i18n.Tfunc("")
	p := CfPlugin{
		Deployer: &BlueGreenDeploy{
			ErrorFunc: func(message string, err error) {
				fmt.Printf("%v - %v\n", message, err)
				os.Exit(1)
			},
			Out: os.Stdout,
		},
	}

	plugin.Start(&p)
}
<|endoftext|>