<commit_before>package integrate

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"

	"github.com/pkg/errors"
	"github.com/sourcegraph/jsonrpc2"
)

type httpsObjectStream struct {
	address   string
	secret    string
	cid       string
	client    *http.Client
	transport *http.Transport

	id int64

	ctx      context.Context
	cancel   context.CancelFunc
	listenCh chan struct{}

	feedChan chan []byte

	errors chan error
}

var _ jsonrpc2.ObjectStream = (*httpsObjectStream)(nil)
var cidSeed int64 = 222

func (s *httpsObjectStream) Go() {
	s.ctx, s.cancel = context.WithCancel(context.Background())
	s.feedChan = make(chan []byte)
	s.cid = fmt.Sprintf("testcid-%d", cidSeed)
	cidSeed++
	s.errors = make(chan error)
	s.client = &http.Client{
		Transport: s.transport,
	}
	s.listenCh = make(chan struct{})

	go func() {
		s.errors <- s.listen()
	}()
}

func (s *httpsObjectStream) onMsg(msg map[string]string) error {
	_, hasId := msg["id"]
	_, hasData := msg["data"]
	if hasId && hasData {
		s.feedChan <- []byte(msg["data"])
		return nil
	} else {
		// ignore
		return nil
	}
}

func (s *httpsObjectStream) listen() error {
	var once sync.Once
	defer once.Do(func() {
		close(s.listenCh)
	})

	query := make(url.Values)
	query.Set("secret", s.secret)
	query.Set("cid", s.cid)
	feedURL := "https://" + s.address + "/feed?" + query.Encode()

	req, err := http.NewRequest("GET", feedURL, nil)
	if err != nil {
		return err
	}
	req = req.WithContext(s.ctx)

	res, err := s.client.Do(req)
	if err != nil {
		return err
	}
	once.Do(func() {
		close(s.listenCh)
	})
	defer res.Body.Close()

	if res.StatusCode != 200 {
		body, _ := ioutil.ReadAll(res.Body)

		return errors.Errorf("Expected HTTP %d but got %d: %s", 200, res.StatusCode, string(body))
	}

	if res.Header.Get("content-type") != "text/event-stream" {
		return errors.Errorf("Expected content-type (%s) but got (%s)", "text/event-stream", res.Header.Get("content-type"))
	}

	scan := bufio.NewScanner(res.Body)
	msg := make(map[string]string)
	// cf. https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
	for scan.Scan() {
		line := scan.Text()

		if line == "" {
			// If the line is empty (a blank line)
			// Dispatch the event
			err := s.onMsg(msg)
			if err != nil {
				return err
			}

			for k := range msg {
				delete(msg, k)
			}
		} else if strings.HasPrefix(line, ":") {
			// If the line starts with a U+003A COLON character (:)
			// Ignore the line.
		} else if strings.ContainsAny(line, ":") {
			// If the line contains a U+003A COLON character (:)
			tokens := strings.SplitN(line, ":", 2)

			// Collect the characters on the line before the first U+003A COLON character (:), and let field be that string.
			field := tokens[0]

			// Collect the characters on the line after the first U+003A COLON character (:), and let value be that string.
			value := tokens[1]
			// If value starts with a U+0020 SPACE character, remove it from value.
			value = strings.TrimPrefix(value, " ")

			// Process the field using the steps described below, using field as the field name and value as the field value.
			msg[field] = value
		}
	}

	err = scan.Err()
	if err != nil {
		return err
	}

	return nil
}

func (s *httpsObjectStream) WriteObject(obj interface{}) error {
	marshalled, err := json.Marshal(obj)
	if err != nil {
		return err
	}

	go func() {
		err := s.writeObject(marshalled)
		if err != nil {
			log.Printf("While writing object %s: %+v", marshalled, err)
			s.cancel()
		}
	}()
	return nil
}

func (s *httpsObjectStream) writeObject(marshalled []byte) error {
	var url string

	intermediate := make(map[string]interface{})
	err := json.Unmarshal(marshalled, &intermediate)
	if err != nil {
		return err
	}

	_, hasMethod := intermediate["method"]
	expectedStatus := 200
	if hasMethod {
		// it's a call!
		url = "https://" + s.address + "/call/" + intermediate["method"].(string)

		marshalled, err = json.Marshal(intermediate["params"])
		if err != nil {
			return err
		}
	} else {
		// it's a reply
		expectedStatus = 204
		url = "https://" + s.address + "/reply"
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(marshalled))
	if err != nil {
		return err
	}
	req = req.WithContext(s.ctx)
	req.Header.Set("x-secret", s.secret)
	req.Header.Set("x-cid", s.cid)

	if hasMethod {
		req.Header.Set("x-id", strconv.FormatInt(s.id, 10))
		s.id++
	}

	res, err := s.client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != expectedStatus {
		body, _ := ioutil.ReadAll(res.Body)

		return errors.Errorf("Expected HTTP %d, but got %d: %s", expectedStatus, res.StatusCode, string(body))
	}

	if expectedStatus == 200 {
		response, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}
		s.feedChan <- response
	}

	return nil
}

func (s *httpsObjectStream) ReadObject(obj interface{}) error {
	select {
	case msg := <-s.feedChan:
		return json.Unmarshal(msg, obj)
	case <-s.ctx.Done():
		return io.EOF
	}
}

func (s *httpsObjectStream) Close() error {
	s.cancel()
	return nil
}
<commit_msg>Attempt to make tests less flasky<commit_after>package integrate

import (
	"bufio"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"

	"github.com/pkg/errors"
	"github.com/sourcegraph/jsonrpc2"
)

type httpsObjectStream struct {
	address   string
	secret    string
	cid       string
	client    *http.Client
	transport *http.Transport

	id int64

	ctx      context.Context
	cancel   context.CancelFunc
	listenCh chan struct{}

	feedChan chan []byte

	errors chan error
}

var _ jsonrpc2.ObjectStream = (*httpsObjectStream)(nil)
var cidSeed int64 = 222

func (s *httpsObjectStream) Go() {
	s.ctx, s.cancel = context.WithCancel(context.Background())
	s.feedChan = make(chan []byte)
	s.cid = fmt.Sprintf("testcid-%d", cidSeed)
	cidSeed++
	s.errors = make(chan error)
	s.client = &http.Client{
		Transport: s.transport,
	}
	s.listenCh = make(chan struct{})

	go func() {
		s.errors <- s.listen()
	}()
}

func (s *httpsObjectStream) onMsg(msg map[string]string) error {
	_, hasId := msg["id"]
	_, hasData := msg["data"]
	if hasId && hasData {
		s.feedChan <- []byte(msg["data"])
		return nil
	} else {
		// ignore
		return nil
	}
}

func (s *httpsObjectStream) listen() error {
	var once sync.Once
	defer once.Do(func() {
		close(s.listenCh)
	})

	query := make(url.Values)
	query.Set("secret", s.secret)
	query.Set("cid", s.cid)
	feedURL := "https://" + s.address + "/feed?" + query.Encode()

	req, err := http.NewRequest("GET", feedURL, nil)
	if err != nil {
		return err
	}
	req = req.WithContext(s.ctx)

	res, err := s.client.Do(req)
	if err != nil {
		return err
	}
	once.Do(func() {
		close(s.listenCh)
	})
	defer res.Body.Close()

	if res.StatusCode != 200 {
		body, _ := ioutil.ReadAll(res.Body)

		return errors.Errorf("Expected HTTP %d but got %d: %s", 200, res.StatusCode, string(body))
	}

	if res.Header.Get("content-type") != "text/event-stream" {
		return errors.Errorf("Expected content-type (%s) but got (%s)", "text/event-stream", res.Header.Get("content-type"))
	}

	scan := bufio.NewScanner(res.Body)
	msg := make(map[string]string)
	// cf. https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
	for scan.Scan() {
		line := scan.Text()

		if line == "" {
			// If the line is empty (a blank line)
			// Dispatch the event
			err := s.onMsg(msg)
			if err != nil {
				return err
			}

			for k := range msg {
				delete(msg, k)
			}
		} else if strings.HasPrefix(line, ":") {
			// If the line starts with a U+003A COLON character (:)
			// Ignore the line.
		} else if strings.ContainsAny(line, ":") {
			// If the line contains a U+003A COLON character (:)
			tokens := strings.SplitN(line, ":", 2)

			// Collect the characters on the line before the first U+003A COLON character (:), and let field be that string.
			field := tokens[0]

			// Collect the characters on the line after the first U+003A COLON character (:), and let value be that string.
			value := tokens[1]
			// If value starts with a U+0020 SPACE character, remove it from value.
			value = strings.TrimPrefix(value, " ")

			// Process the field using the steps described below, using field as the field name and value as the field value.
			msg[field] = value
		}
	}

	err = scan.Err()
	if err != nil {
		return err
	}

	return nil
}

func (s *httpsObjectStream) WriteObject(obj interface{}) error {
	marshalled, err := json.Marshal(obj)
	if err != nil {
		return err
	}

	err = s.writeObject(marshalled)
	if err != nil {
		return err
	}
	return nil
}

func (s *httpsObjectStream) writeObject(marshalled []byte) error {
	var url string

	intermediate := make(map[string]interface{})
	err := json.Unmarshal(marshalled, &intermediate)
	if err != nil {
		return err
	}

	_, hasMethod := intermediate["method"]
	expectedStatus := 200
	if hasMethod {
		// it's a call!
		url = "https://" + s.address + "/call/" + intermediate["method"].(string)

		marshalled, err = json.Marshal(intermediate["params"])
		if err != nil {
			return err
		}
	} else {
		// it's a reply
		expectedStatus = 204
		url = "https://" + s.address + "/reply"
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(marshalled))
	if err != nil {
		return err
	}
	req = req.WithContext(s.ctx)
	req.Header.Set("x-secret", s.secret)
	req.Header.Set("x-cid", s.cid)

	if hasMethod {
		req.Header.Set("x-id", strconv.FormatInt(s.id, 10))
		s.id++
	}

	send := func() error {
		res, err := s.client.Do(req)
		if err != nil {
			return err
		}
		defer res.Body.Close()

		if res.StatusCode != expectedStatus {
			body, _ := ioutil.ReadAll(res.Body)

			return errors.Errorf("Expected HTTP %d, but got %d: %s", expectedStatus, res.StatusCode, string(body))
		}

		if expectedStatus == 200 {
			response, err := ioutil.ReadAll(res.Body)
			if err != nil {
				return err
			}
			s.feedChan <- response
		}
		return nil
	}

	go func() {
		err := send()
		if err != nil {
			select {
			case <-s.ctx.Done():
				// disregard errors after cancel
			default:
				log.Printf("While sending %s, got: %+v", string(marshalled), err)
				s.cancel()
			}
		}
	}()

	return nil
}

func (s *httpsObjectStream) ReadObject(obj interface{}) error {
	select {
	case msg := <-s.feedChan:
		return json.Unmarshal(msg, obj)
	case <-s.ctx.Done():
		return io.EOF
	}
}

func (s *httpsObjectStream) Close() error {
	s.cancel()
	return nil
}
<|endoftext|>


<commit_before>package german

import (
	"errors"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type Sich string

const (
	Without   Sich = ""
	Acusative      = "a"
	Dative         = "d"
)

type Article string

const (
	Der Article = "r"
	Die         = "e"
	Das         = "s"
)

const learnedForm = "2006-01-02"

var (
	NounRegexp = regexp.MustCompile("^([ers/]+) ([^,]+),(.*)$")
	VerbRegexp = regexp.MustCompile("^([sh/]+) ([^+]*)([+](.*))?$")
)

type Word interface {
	GetGerman() string
	GetEnglish() []Meaning
	GetThird() []Meaning
	GetCategory() string
	GetUser() string
	GetScore() int
	GetLearned() time.Time
	IsOk() bool
}

type Meaning struct {
	Main        string `bson:"main" json:"main"`
	Paranthases string `bson:"paranthases" json:"paranthases"`
}

func NewMeanings(allMeanings string) []Meaning {
	meanings := []Meaning{}

	for _, word := range strings.Split(allMeanings, ";") {
		meanings = append(meanings, Meaning{word, ""})
	}

	return meanings
}

type DefaultWord struct {
	German   string    `bson:"german" json:"german"`
	English  []Meaning `bson:"english" json:"english"`
	Third    []Meaning `bson:"third" json:"third"`
	Category string    `bson:"category" json:"category"`
	User     string    `bson:"user" json:"user"`
	Learned  time.Time `bson:"learned" json:"learned"`
	Score    int       `bson:"score" json:"score"`
	Ok       bool      `bson:"ok", json:"ok"`
}

func NewDefaultWord(german, english, third, category, user, learned, score string) DefaultWord {
	englishMeanings, thirdMeanings := NewMeanings(english), NewMeanings(third)

	scoreParsed, err := strconv.ParseInt(score, 0, 0)
	if err != nil || scoreParsed < 0 || scoreParsed > 10 {
		scoreParsed = 5
	}

	learnedParsed, err := time.Parse(learnedForm, learned)
	if err != nil {
		learnedParsed = time.Now()
	}

	return DefaultWord{german, englishMeanings, thirdMeanings, category, user, learnedParsed, int(scoreParsed), true}
}

func (w *DefaultWord) GetGerman() string {
	return w.German
}

func (w *DefaultWord) GetEnglish() []Meaning {
	return w.English
}

func (w *DefaultWord) GetThird() []Meaning {
	return w.Third
}

func (w *DefaultWord) GetCategory() string {
	return w.Category
}

func (w *DefaultWord) GetScore() int {
	return w.Score
}

func (w *DefaultWord) GetUser() string {
	return w.User
}

func (w *DefaultWord) GetLearned() time.Time {
	return w.Learned
}

func (w *DefaultWord) IsOk() bool {
	return w.Ok
}

type Verb struct {
	DefaultWord    `bson:"word" json:"word"`
	Auxiliary      []string `bson:"auxiliary" json:"auxiliary"`
	PastParticiple []string `bson:"pastParticiple" json:"pastParticiple"`
	Preterite      []string `bson:"preterite" json:"preterite"`
	Ich            []string `bson:"ich" json:"ich"`
	Du             []string `bson:"du" json:"du"`
	Er             []string `bson:"er" json:"er"`
	Wir            []string `bson:"wir" json:"wir"`
	Ihr            []string `bson:"ihr" json:"ihr"`
	Sie            []string `bson:"sie" json:"sie"`
	Sich           Sich     `bson:"sich" json:"sich"`
	Arguments      []string `bson:"arguments" json:"arguments"`
}

func NewVerb(german, english, third, user, learned, score string) *Verb {
	pastParticiple := ""
	preterite := ""
	ich := ""
	du := ""
	er := ""
	wir := ""
	ihr := ""
	sie := ""

	matches := VerbRegexp.FindStringSubmatch(german)

	main := strings.Split(matches[2], ",")
	switch len(main) {
	case 1:
		german = main[0]
		break
	case 3:
		german, pastParticiple, preterite = main[0], main[1], main[2]
		break
	case 5:
		german, pastParticiple, preterite, du, er = main[0], main[1], main[2], main[3], main[4]
		break
	case 9:
		german, ich, du, er, wir, ihr, sie, pastParticiple, preterite = main[0], main[1], main[2], main[3], main[4], main[5], main[6], main[7], main[8]
		break
	default:
		return nil
	}

	sich, arguments, err := parseArguments(matches[3])
	if err != nil {
		return nil
	}

	return &Verb{
		NewDefaultWord(german, english, third, "verb", user, learned, score),
		strings.Split(matches[1], "/"),
		strings.Split(pastParticiple, "/"),
		strings.Split(preterite, "/"),
		strings.Split(ich, "/"),
		strings.Split(du, "/"),
		strings.Split(er, "/"),
		strings.Split(wir, "/"),
		strings.Split(ihr, "/"),
		strings.Split(sie, "/"),
		sich,
		arguments,
	}
}

func parseArguments(rawArguments string) (Sich, []string, error) {
	if rawArguments == "" {
		return Without, []string{}, nil
	}
	arguments := strings.Split(rawArguments, "+")

	if strings.Contains(arguments[0], "sich (A)") {
		return Acusative, arguments[1:], nil
	}

	if strings.Contains(arguments[0], "sich (D)") {
		return Dative, arguments[1:], nil
	}

	if strings.Contains(arguments[0], "sich") {
		return Without, []string{}, errors.New("Sich definition is invalid")
	}

	return Without, []string{}, nil
}

type Noun struct {
	DefaultWord `bson:"word" json:"word"`
	Articles    []Article `bson:"article" json:"article"`
	Plural      []string  `bson:"plural" json:"plural"`
}

func NewNoun(german, english, third, user, learned, score string) *Noun {
	matches := NounRegexp.FindStringSubmatch(german)

	articles := []Article{}
	for _, article := range strings.Split(matches[1], "/") {
		switch article {
		case "r":
			articles = append(articles, Der)
			break
		case "e":
			articles = append(articles, Die)
			break
		case "s":
			articles = append(articles, Das)
			break
		default:
			return nil
		}
	}

	return &Noun{
		NewDefaultWord(german, english, third, "noun", user, learned, score),
		articles,
		strings.Split(matches[3], "/"),
	}
}

type Adjective struct {
	DefaultWord `bson:"word" json:"word"`
	Comparative []string `bson:"comparative" json:"comparative"`
	Superlative []string `bson:"superlative" json:"superlative"`
}

func NewAdjective(german, english, third, user, learned, score string) *Adjective {
	adjectiveParts := strings.Split(german, ",")

	comparative := []string{}
	superlative := []string{}

	if len(adjectiveParts) > 1 {
		comparative = strings.Split(adjectiveParts[1], "/")
	}
	if len(adjectiveParts) > 2 {
		superlative = strings.Split(adjectiveParts[2], "/")
	}

	return &Adjective{
		NewDefaultWord(german, english, third, "adjective", user, learned, score),
		comparative,
		superlative,
	}
}

type Any struct {
	DefaultWord `bson:"word" json:"word"`
}

func NewAny(german, english, third, category, user, learned, score string, ok bool) *Any {
	d := NewDefaultWord(german, english, third, category, user, learned, score)

	d.Ok = ok

	return &Any{d}
}
<commit_msg>Disallowing 0 scores<commit_after>package german

import (
	"errors"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type Sich string

const (
	Without   Sich = ""
	Acusative      = "a"
	Dative         = "d"
)

type Article string

const (
	Der Article = "r"
	Die         = "e"
	Das         = "s"
)

const learnedForm = "2006-01-02"

var (
	NounRegexp = regexp.MustCompile("^([ers/]+) ([^,]+),(.*)$")
	VerbRegexp = regexp.MustCompile("^([sh/]+) ([^+]*)([+](.*))?$")
)

type Word interface {
	GetGerman() string
	GetEnglish() []Meaning
	GetThird() []Meaning
	GetCategory() string
	GetUser() string
	GetScore() int
	GetLearned() time.Time
	IsOk() bool
}

type Meaning struct {
	Main        string `bson:"main" json:"main"`
	Paranthases string `bson:"paranthases" json:"paranthases"`
}

func NewMeanings(allMeanings string) []Meaning {
	meanings := []Meaning{}

	for _, word := range strings.Split(allMeanings, ";") {
		meanings = append(meanings, Meaning{word, ""})
	}

	return meanings
}

type DefaultWord struct {
	German   string    `bson:"german" json:"german"`
	English  []Meaning `bson:"english" json:"english"`
	Third    []Meaning `bson:"third" json:"third"`
	Category string    `bson:"category" json:"category"`
	User     string    `bson:"user" json:"user"`
	Learned  time.Time `bson:"learned" json:"learned"`
	Score    int       `bson:"score" json:"score"`
	Ok       bool      `bson:"ok", json:"ok"`
}

func NewDefaultWord(german, english, third, category, user, learned, score string) DefaultWord {
	englishMeanings, thirdMeanings := NewMeanings(english), NewMeanings(third)

	scoreParsed, err := strconv.ParseInt(score, 0, 0)
	if err != nil || scoreParsed < 1 || scoreParsed > 10 {
		scoreParsed = 5
	}

	learnedParsed, err := time.Parse(learnedForm, learned)
	if err != nil {
		learnedParsed = time.Now()
	}

	return DefaultWord{german, englishMeanings, thirdMeanings, category, user, learnedParsed, int(scoreParsed), true}
}

func (w *DefaultWord) GetGerman() string {
	return w.German
}

func (w *DefaultWord) GetEnglish() []Meaning {
	return w.English
}

func (w *DefaultWord) GetThird() []Meaning {
	return w.Third
}

func (w *DefaultWord) GetCategory() string {
	return w.Category
}

func (w *DefaultWord) GetScore() int {
	return w.Score
}

func (w *DefaultWord) GetUser() string {
	return w.User
}

func (w *DefaultWord) GetLearned() time.Time {
	return w.Learned
}

func (w *DefaultWord) IsOk() bool {
	return w.Ok
}

type Verb struct {
	DefaultWord    `bson:"word" json:"word"`
	Auxiliary      []string `bson:"auxiliary" json:"auxiliary"`
	PastParticiple []string `bson:"pastParticiple" json:"pastParticiple"`
	Preterite      []string `bson:"preterite" json:"preterite"`
	Ich            []string `bson:"ich" json:"ich"`
	Du             []string `bson:"du" json:"du"`
	Er             []string `bson:"er" json:"er"`
	Wir            []string `bson:"wir" json:"wir"`
	Ihr            []string `bson:"ihr" json:"ihr"`
	Sie            []string `bson:"sie" json:"sie"`
	Sich           Sich     `bson:"sich" json:"sich"`
	Arguments      []string `bson:"arguments" json:"arguments"`
}

func NewVerb(german, english, third, user, learned, score string) *Verb {
	pastParticiple := ""
	preterite := ""
	ich := ""
	du := ""
	er := ""
	wir := ""
	ihr := ""
	sie := ""

	matches := VerbRegexp.FindStringSubmatch(german)

	main := strings.Split(matches[2], ",")
	switch len(main) {
	case 1:
		german = main[0]
		break
	case 3:
		german, pastParticiple, preterite = main[0], main[1], main[2]
		break
	case 5:
		german, pastParticiple, preterite, du, er = main[0], main[1], main[2], main[3], main[4]
		break
	case 9:
		german, ich, du, er, wir, ihr, sie, pastParticiple, preterite = main[0], main[1], main[2], main[3], main[4], main[5], main[6], main[7], main[8]
		break
	default:
		return nil
	}

	sich, arguments, err := parseArguments(matches[3])
	if err != nil {
		return nil
	}

	return &Verb{
		NewDefaultWord(german, english, third, "verb", user, learned, score),
		strings.Split(matches[1], "/"),
		strings.Split(pastParticiple, "/"),
		strings.Split(preterite, "/"),
		strings.Split(ich, "/"),
		strings.Split(du, "/"),
		strings.Split(er, "/"),
		strings.Split(wir, "/"),
		strings.Split(ihr, "/"),
		strings.Split(sie, "/"),
		sich,
		arguments,
	}
}

func parseArguments(rawArguments string) (Sich, []string, error) {
	if rawArguments == "" {
		return Without, []string{}, nil
	}
	arguments := strings.Split(rawArguments, "+")

	if strings.Contains(arguments[0], "sich (A)") {
		return Acusative, arguments[1:], nil
	}

	if strings.Contains(arguments[0], "sich (D)") {
		return Dative, arguments[1:], nil
	}

	if strings.Contains(arguments[0], "sich") {
		return Without, []string{}, errors.New("Sich definition is invalid")
	}

	return Without, []string{}, nil
}

type Noun struct {
	DefaultWord `bson:"word" json:"word"`
	Articles    []Article `bson:"article" json:"article"`
	Plural      []string  `bson:"plural" json:"plural"`
}

func NewNoun(german, english, third, user, learned, score string) *Noun {
	matches := NounRegexp.FindStringSubmatch(german)

	articles := []Article{}
	for _, article := range strings.Split(matches[1], "/") {
		switch article {
		case "r":
			articles = append(articles, Der)
			break
		case "e":
			articles = append(articles, Die)
			break
		case "s":
			articles = append(articles, Das)
			break
		default:
			return nil
		}
	}

	return &Noun{
		NewDefaultWord(german, english, third, "noun", user, learned, score),
		articles,
		strings.Split(matches[3], "/"),
	}
}

type Adjective struct {
	DefaultWord `bson:"word" json:"word"`
	Comparative []string `bson:"comparative" json:"comparative"`
	Superlative []string `bson:"superlative" json:"superlative"`
}

func NewAdjective(german, english, third, user, learned, score string) *Adjective {
	adjectiveParts := strings.Split(german, ",")

	comparative := []string{}
	superlative := []string{}

	if len(adjectiveParts) > 1 {
		comparative = strings.Split(adjectiveParts[1], "/")
	}
	if len(adjectiveParts) > 2 {
		superlative = strings.Split(adjectiveParts[2], "/")
	}

	return &Adjective{
		NewDefaultWord(german, english, third, "adjective", user, learned, score),
		comparative,
		superlative,
	}
}

type Any struct {
	DefaultWord `bson:"word" json:"word"`
}

func NewAny(german, english, third, category, user, learned, score string, ok bool) *Any {
	d := NewDefaultWord(german, english, third, category, user, learned, score)

	d.Ok = ok

	return &Any{d}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package testutils

// This file contains test setup logic, and is named with a _test.go suffix to
// ensure it's only compiled with tests.

import (
	"flag"
	"fmt"
	"net"
	"sync/atomic"
	"testing"

	"golang.org/x/net/context"

	"github.com/uber/tchannel-go"
	"github.com/uber/tchannel-go/raw"
)

var connectionLog = flag.Bool("connectionLog", false, "Enables connection logging in tests")

// Default service names for the test channels.
const (
	DefaultServerName = "testService"
	DefaultClientName = "testService-client"
)

// ChannelOpts contains options to create a test channel using WithServer
type ChannelOpts struct {
	// ServiceName defaults to "testServer"
	ServiceName string

	// ProcessName defaults to ServiceName + "-[port]"
	ProcessName string

	// EnableLog defaults to false.
	EnableLog bool

	// StatsReporter specifies the StatsReporter to use.
	StatsReporter tchannel.StatsReporter

	// TraceReporter specified the TraceReporter to use.
	TraceReporter tchannel.TraceReporter

	// DefaultConnectionOptions specifies the channel's default connection options.
	DefaultConnectionOptions tchannel.ConnectionOptions
}

func defaultString(v string, defaultValue string) string {
	if v == "" {
		return defaultValue
	}
	return v
}

func getChannelOptions(opts *ChannelOpts, processName string) *tchannel.ChannelOptions {
	var logger tchannel.Logger
	if opts.EnableLog || *connectionLog {
		logger = tchannel.SimpleLogger
	}

	return &tchannel.ChannelOptions{
		ProcessName: processName,
		Logger:      logger,
		DefaultConnectionOptions: opts.DefaultConnectionOptions,
		StatsReporter:            opts.StatsReporter,
		TraceReporter:            opts.TraceReporter,
	}
}

// WithServer sets up a TChannel that is listening and runs the given function with the channel.
func WithServer(opts *ChannelOpts, f func(ch *tchannel.Channel, hostPort string)) error {
	ch, err := NewServer(opts)
	if err != nil {
		return err
	}
	f(ch, ch.PeerInfo().HostPort)
	ch.Close()
	return nil
}

// NewServer creates a TChannel that is listening and returns the channel.
func NewServer(opts *ChannelOpts) (*tchannel.Channel, error) {
	if opts == nil {
		opts = &ChannelOpts{}
	}

	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return nil, fmt.Errorf("failed to listen: %v", err)
	}
	_, port, err := net.SplitHostPort(l.Addr().String())
	if err != nil {
		return nil, fmt.Errorf("could not get listening port from %v: %v", l.Addr().String(), err)
	}

	serviceName := defaultString(opts.ServiceName, DefaultServerName)
	processName := defaultString(opts.ProcessName, serviceName+"-"+port)
	ch, err := tchannel.NewChannel(serviceName, getChannelOptions(opts, processName))
	if err != nil {
		return nil, fmt.Errorf("NewChannel failed: %v", err)
	}

	if err := ch.Serve(l); err != nil {
		return nil, fmt.Errorf("Serve failed: %v", err)
	}

	return ch, nil
}

var totalClients uint32

// NewClient creates a TChannel that is not listening.
func NewClient(opts *ChannelOpts) (*tchannel.Channel, error) {
	if opts == nil {
		opts = &ChannelOpts{}
	}

	clientNum := atomic.AddUint32(&totalClients, 1)
	serviceName := defaultString(opts.ServiceName, DefaultClientName)
	processName := defaultString(opts.ProcessName, serviceName+"-"+fmt.Sprint(clientNum))
	return tchannel.NewChannel(serviceName, getChannelOptions(opts, processName))
}

type rawFuncHandler struct {
	t *testing.T
	f func(context.Context, *raw.Args) (*raw.Res, error)
}

func (h rawFuncHandler) OnError(ctx context.Context, err error) {
	h.t.Errorf("simpleHandler OnError: %v %v", ctx, err)
}

func (h rawFuncHandler) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	return h.f(ctx, args)
}

// RegisterFunc registers a function as a handler for the given operation name.
func RegisterFunc(t *testing.T, ch *tchannel.Channel, name string,
	f func(ctx context.Context, args *raw.Args) (*raw.Res, error)) {

	ch.Register(raw.Wrap(rawFuncHandler{t, f}), name)
}
<commit_msg>Allow custom Logger in testutils/channel<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package testutils

// This file contains test setup logic, and is named with a _test.go suffix to
// ensure it's only compiled with tests.

import (
	"flag"
	"fmt"
	"net"
	"sync/atomic"
	"testing"

	"golang.org/x/net/context"

	"github.com/uber/tchannel-go"
	"github.com/uber/tchannel-go/raw"
)

var connectionLog = flag.Bool("connectionLog", false, "Enables connection logging in tests")

// Default service names for the test channels.
const (
	DefaultServerName = "testService"
	DefaultClientName = "testService-client"
)

// ChannelOpts contains options to create a test channel using WithServer
type ChannelOpts struct {
	// ServiceName defaults to "testServer"
	ServiceName string

	// ProcessName defaults to ServiceName + "-[port]"
	ProcessName string

	// Logger sets the logger.
	Logger tchannel.Logger

	// StatsReporter specifies the StatsReporter to use.
	StatsReporter tchannel.StatsReporter

	// TraceReporter specified the TraceReporter to use.
	TraceReporter tchannel.TraceReporter

	// DefaultConnectionOptions specifies the channel's default connection options.
	DefaultConnectionOptions tchannel.ConnectionOptions
}

func defaultString(v string, defaultValue string) string {
	if v == "" {
		return defaultValue
	}
	return v
}

func getChannelOptions(opts *ChannelOpts, processName string) *tchannel.ChannelOptions {
	var logger tchannel.Logger
	if opts.Logger != nil {
		logger = opts.Logger
	} else if *connectionLog {
		logger = tchannel.SimpleLogger
	}

	return &tchannel.ChannelOptions{
		ProcessName: processName,
		Logger:      logger,
		DefaultConnectionOptions: opts.DefaultConnectionOptions,
		StatsReporter:            opts.StatsReporter,
		TraceReporter:            opts.TraceReporter,
	}
}

// WithServer sets up a TChannel that is listening and runs the given function with the channel.
func WithServer(opts *ChannelOpts, f func(ch *tchannel.Channel, hostPort string)) error {
	ch, err := NewServer(opts)
	if err != nil {
		return err
	}
	f(ch, ch.PeerInfo().HostPort)
	ch.Close()
	return nil
}

// NewServer creates a TChannel that is listening and returns the channel.
func NewServer(opts *ChannelOpts) (*tchannel.Channel, error) {
	if opts == nil {
		opts = &ChannelOpts{}
	}

	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return nil, fmt.Errorf("failed to listen: %v", err)
	}
	_, port, err := net.SplitHostPort(l.Addr().String())
	if err != nil {
		return nil, fmt.Errorf("could not get listening port from %v: %v", l.Addr().String(), err)
	}

	serviceName := defaultString(opts.ServiceName, DefaultServerName)
	processName := defaultString(opts.ProcessName, serviceName+"-"+port)
	ch, err := tchannel.NewChannel(serviceName, getChannelOptions(opts, processName))
	if err != nil {
		return nil, fmt.Errorf("NewChannel failed: %v", err)
	}

	if err := ch.Serve(l); err != nil {
		return nil, fmt.Errorf("Serve failed: %v", err)
	}

	return ch, nil
}

var totalClients uint32

// NewClient creates a TChannel that is not listening.
func NewClient(opts *ChannelOpts) (*tchannel.Channel, error) {
	if opts == nil {
		opts = &ChannelOpts{}
	}

	clientNum := atomic.AddUint32(&totalClients, 1)
	serviceName := defaultString(opts.ServiceName, DefaultClientName)
	processName := defaultString(opts.ProcessName, serviceName+"-"+fmt.Sprint(clientNum))
	return tchannel.NewChannel(serviceName, getChannelOptions(opts, processName))
}

type rawFuncHandler struct {
	t *testing.T
	f func(context.Context, *raw.Args) (*raw.Res, error)
}

func (h rawFuncHandler) OnError(ctx context.Context, err error) {
	h.t.Errorf("simpleHandler OnError: %v %v", ctx, err)
}

func (h rawFuncHandler) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	return h.f(ctx, args)
}

// RegisterFunc registers a function as a handler for the given operation name.
func RegisterFunc(t *testing.T, ch *tchannel.Channel, name string,
	f func(ctx context.Context, args *raw.Args) (*raw.Res, error)) {

	ch.Register(raw.Wrap(rawFuncHandler{t, f}), name)
}
<|endoftext|>


<commit_before>package pkglib

// Thin wrappers around git CLI invocations

import (
	"bufio"
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	log "github.com/sirupsen/logrus"
)

// 040000 tree 7804129bd06218b72c298139a25698a748d253c6\tpkg/init
var treeHashRe *regexp.Regexp

func init() {
	treeHashRe = regexp.MustCompile("^[0-7]{6} [^ ]+ ([0-9a-f]{40})\t.+\n$")
}

type git struct {
	dir string
}

// Returns git==nil and no error if the path is not within a git repository
func newGit(dir string) (*git, error) {
	g := &git{dir}

	// Check if dir really is within a git directory
	ok, err := g.isWorkTree(dir)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, nil
	}
	return g, nil
}

func (g git) mkCmd(args ...string) *exec.Cmd {
	return exec.Command("git", append([]string{"-C", g.dir}, args...)...)
}

func (g git) commandStdout(stderr io.Writer, args ...string) (string, error) {
	cmd := g.mkCmd(args...)
	cmd.Stderr = stderr
	log.Debugf("Executing: %v", cmd.Args)

	out, err := cmd.Output()
	if err != nil {
		return "", err
	}
	return string(out), nil
}

func (g git) command(args ...string) error {
	cmd := g.mkCmd(args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Debugf("Executing: %v", cmd.Args)

	return cmd.Run()
}

func (g git) isWorkTree(pkg string) (bool, error) {
	tf, err := g.commandStdout(nil, "rev-parse", "--is-inside-work-tree")
	if err != nil {
		// If we executed git ok but it errored then that's because this isn't a git repo
		if _, ok := err.(*exec.ExitError); ok {
			return false, nil
		}
		return false, err
	}

	tf = strings.TrimSpace(tf)

	if tf == "true" {
		return true, nil
	}

	return false, fmt.Errorf("unexpected output from git rev-parse --is-inside-work-tree: %s", tf)
}

func (g git) contentHash() (string, error) {
	hash := sha256.New()
	out, err := g.commandStdout(nil, "ls-files")
	if err != nil {
		return "", err
	}
	scanner := bufio.NewScanner(strings.NewReader(strings.TrimSpace(out)))
	for scanner.Scan() {
		f, err := os.Open(filepath.Join(g.dir, scanner.Text()))
		if err != nil {
			return "", err
		}
		if _, err := io.Copy(hash, f); err != nil {
			_ = f.Close()
			return "", err
		}
		if err = f.Close(); err != nil {
			return "", err
		}
	}
	if err = scanner.Err(); err != nil {
		return "", err
	}
	return fmt.Sprintf("%x", hash.Sum(nil)), nil
}

func (g git) treeHash(pkg, commit string) (string, error) {
	// we have to check if pkg is at the top level of the git tree,
	// if that's the case we need to use tree hash from the commit itself
	out, err := g.commandStdout(nil, "rev-parse", "--prefix", pkg, "--show-toplevel")
	if err != nil {
		return "", err
	}
	if strings.TrimSpace(out) == pkg {
		out, err = g.commandStdout(nil, "show", "--format=%T", "-s", commit)
		if err != nil {
			return "", err
		}
		return strings.TrimSpace(out), nil
	}

	out, err = g.commandStdout(os.Stderr, "ls-tree", "--full-tree", commit, "--", pkg)
	if err != nil {
		return "", err
	}

	if out == "" {
		return "", fmt.Errorf("Package %s is not in git", pkg)
	}

	matches := treeHashRe.FindStringSubmatch(out)
	if len(matches) != 2 {
		return "", fmt.Errorf("Unable to parse ls-tree output: %q", out)
	}

	return matches[1], nil
}

func (g git) commitHash(commit string) (string, error) {
	out, err := g.commandStdout(os.Stderr, "rev-parse", commit)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(out), nil
}

func (g git) commitTag(commit string) (string, error) {
	out, err := g.commandStdout(os.Stderr, "tag", "-l", "--points-at", commit)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(out), nil
}

func (g git) isDirty(pkg, commit string) (bool, error) {
	// If it isn't HEAD it can't be dirty
	if commit != "HEAD" {
		return false, nil
	}

	// Update cache, otherwise files which have an updated
	// timestamp but no actual changes are marked as changes
	// because `git diff-index` only uses the `lstat` result and
	// not the actual file contents. Running `git update-index
	// --refresh` updates the cache.
	if err := g.command("update-index", "-q", "--refresh"); err != nil {
		return false, err
	}

	err := g.command("diff-index", "--quiet", commit, "--", pkg)
	if err == nil {
		return false, nil
	}
	switch err.(type) {
	case *exec.ExitError:
		// diff-index exits with an error if there are differences
		return true, nil
	default:
		return false, err
	}
}
<commit_msg>Skip files in contentHash()<commit_after>package pkglib

// Thin wrappers around git CLI invocations

import (
	"bufio"
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	log "github.com/sirupsen/logrus"
)

// 040000 tree 7804129bd06218b72c298139a25698a748d253c6\tpkg/init
var treeHashRe *regexp.Regexp

func init() {
	treeHashRe = regexp.MustCompile("^[0-7]{6} [^ ]+ ([0-9a-f]{40})\t.+\n$")
}

type git struct {
	dir string
}

// Returns git==nil and no error if the path is not within a git repository
func newGit(dir string) (*git, error) {
	g := &git{dir}

	// Check if dir really is within a git directory
	ok, err := g.isWorkTree(dir)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, nil
	}
	return g, nil
}

func (g git) mkCmd(args ...string) *exec.Cmd {
	return exec.Command("git", append([]string{"-C", g.dir}, args...)...)
}

func (g git) commandStdout(stderr io.Writer, args ...string) (string, error) {
	cmd := g.mkCmd(args...)
	cmd.Stderr = stderr
	log.Debugf("Executing: %v", cmd.Args)

	out, err := cmd.Output()
	if err != nil {
		return "", err
	}
	return string(out), nil
}

func (g git) command(args ...string) error {
	cmd := g.mkCmd(args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	log.Debugf("Executing: %v", cmd.Args)

	return cmd.Run()
}

func (g git) isWorkTree(pkg string) (bool, error) {
	tf, err := g.commandStdout(nil, "rev-parse", "--is-inside-work-tree")
	if err != nil {
		// If we executed git ok but it errored then that's because this isn't a git repo
		if _, ok := err.(*exec.ExitError); ok {
			return false, nil
		}
		return false, err
	}

	tf = strings.TrimSpace(tf)

	if tf == "true" {
		return true, nil
	}

	return false, fmt.Errorf("unexpected output from git rev-parse --is-inside-work-tree: %s", tf)
}

func (g git) contentHash() (string, error) {
	hash := sha256.New()
	out, err := g.commandStdout(nil, "ls-files")
	if err != nil {
		return "", err
	}
	scanner := bufio.NewScanner(strings.NewReader(strings.TrimSpace(out)))
	for scanner.Scan() {
		filename := filepath.Join(g.dir, scanner.Text())
		info, err := os.Lstat(filename)
		if err != nil {
			log.Debugf("cannot stat %s: %s, skipped", filename, err)
			continue
		}
		if info.IsDir() || info.Mode()&os.ModeSymlink != 0 {
			// we do not want to calculate hash of directory or symlinks
			continue
		}
		f, err := os.Open(filename)
		if err != nil {
			log.Debugf("cannot open %s: %s, skipped", filename, err)
			continue
		}
		if _, err := io.Copy(hash, f); err != nil {
			_ = f.Close()
			return "", err
		}
		if err = f.Close(); err != nil {
			return "", err
		}
	}
	if err = scanner.Err(); err != nil {
		return "", err
	}
	return fmt.Sprintf("%x", hash.Sum(nil)), nil
}

func (g git) treeHash(pkg, commit string) (string, error) {
	// we have to check if pkg is at the top level of the git tree,
	// if that's the case we need to use tree hash from the commit itself
	out, err := g.commandStdout(nil, "rev-parse", "--prefix", pkg, "--show-toplevel")
	if err != nil {
		return "", err
	}
	if strings.TrimSpace(out) == pkg {
		out, err = g.commandStdout(nil, "show", "--format=%T", "-s", commit)
		if err != nil {
			return "", err
		}
		return strings.TrimSpace(out), nil
	}

	out, err = g.commandStdout(os.Stderr, "ls-tree", "--full-tree", commit, "--", pkg)
	if err != nil {
		return "", err
	}

	if out == "" {
		return "", fmt.Errorf("Package %s is not in git", pkg)
	}

	matches := treeHashRe.FindStringSubmatch(out)
	if len(matches) != 2 {
		return "", fmt.Errorf("Unable to parse ls-tree output: %q", out)
	}

	return matches[1], nil
}

func (g git) commitHash(commit string) (string, error) {
	out, err := g.commandStdout(os.Stderr, "rev-parse", commit)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(out), nil
}

func (g git) commitTag(commit string) (string, error) {
	out, err := g.commandStdout(os.Stderr, "tag", "-l", "--points-at", commit)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(out), nil
}

func (g git) isDirty(pkg, commit string) (bool, error) {
	// If it isn't HEAD it can't be dirty
	if commit != "HEAD" {
		return false, nil
	}

	// Update cache, otherwise files which have an updated
	// timestamp but no actual changes are marked as changes
	// because `git diff-index` only uses the `lstat` result and
	// not the actual file contents. Running `git update-index
	// --refresh` updates the cache.
	if err := g.command("update-index", "-q", "--refresh"); err != nil {
		return false, err
	}

	err := g.command("diff-index", "--quiet", commit, "--", pkg)
	if err == nil {
		return false, nil
	}
	switch err.(type) {
	case *exec.ExitError:
		// diff-index exits with an error if there are differences
		return true, nil
	default:
		return false, err
	}
}
<|endoftext|>


<commit_before>package cloudatgost

import(
	"net/http"
	"net/url"
)

type TemplateList struct {
	Status string `json:"status"`
	Time int `json:"time"`
	Data []struct {
		ID string `json:"id"`
		Detail string `json:"detail"`
	} `json:"data"`
}

func (c *Client) ListTemplates() (*TemplateList) {
	v := &TemplateList{}
	Url, err := url.Parse(c.BaseURL)
	if err != nil {
		panic("boom! Busted :F")
	}
	Url.Path += "listtemplates.php"
	parameters := url.Values{}
	parameters.Add("key", c.Token)
	parameters.Add("login", c.Login)
	Url.RawQuery = parameters.Encode()

	request, err := http.NewRequest("GET", Url.String(), nil)
	if err != nil {
		return nil
	}

	c.Do(request, &v)
	return v
}
<commit_msg>listtemplates.go properly commented<commit_after>package cloudatgost

import(
	"net/http"
	"net/url"
)

// A TemplateList represents an API response for machine templates
// currently available.
type TemplateList struct {
	Status string `json:"status"`
	Time int `json:"time"`
	Data []struct {
		ID string `json:"id"`
		Detail string `json:"detail"`
	} `json:"data"`
}

// ListTemplates formulates an HTTP request to the listtemplates.php
// endpoint and maps the JSON response through Do to a TemplateList
// structure.
func (c *Client) ListTemplates() (*TemplateList) {
	v := &TemplateList{}
	Url, err := url.Parse(c.BaseURL)
	if err != nil {
		panic("boom! Busted :F")
	}
	Url.Path += "listtemplates.php"
	parameters := url.Values{}
	parameters.Add("key", c.Token)
	parameters.Add("login", c.Login)
	Url.RawQuery = parameters.Encode()

	request, err := http.NewRequest("GET", Url.String(), nil)
	if err != nil {
		return nil
	}

	c.Do(request, &v)
	return v
}
<|endoftext|>


<commit_before>package straumur

type EventFeed interface {
	Updates() <-chan *Event
	Close() error
}

//Queryable Data store
type DataBackend interface {
	Save(e *Event) error
	GetById(id int) (*Event, error)
	Query(q Query) ([]*Event, error)
	AggregateType(q Query, s string) (map[string]int, error)
}

type Broadcaster interface {
	Broadcast(e *Event)
}

type DataService interface {
	Run(d DataBackend, ec chan error)
}
<commit_msg>Broadcaster Run<commit_after>package straumur

type EventFeed interface {
	Updates() <-chan *Event
	Close() error
}

//Queryable Data store
type DataBackend interface {
	Save(e *Event) error
	GetById(id int) (*Event, error)
	Query(q Query) ([]*Event, error)
	AggregateType(q Query, s string) (map[string]int, error)
}

type Broadcaster interface {
	Broadcast(e *Event)
	Run(ec chan error)
}

type DataService interface {
	Run(d DataBackend, ec chan error)
}
<|endoftext|>


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

package ipam

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/romana/core/common"
	"log"
	"strings"
)

// Endpoint represents an endpoint (a VM, a Kubernetes Pod, etc.)
// that is to get an IP address.
type Endpoint struct {
	Ip           string         `json:"ip,omitempty"`
	TenantID     string         `json:"tenant_id,omitempty"`
	SegmentID    string         `json:"segment_id,omitempty"`
	HostId       string         `json:"host_id,omitempty"`
	Name         string         `json:"name,omitempty"`
	RequestToken sql.NullString `json:"request_token" sql:"unique"`
	// Ordinal number of this Endpoint in the host/tenant combination
	NetworkID uint64 `json:"-"`
	// Calculated effective network ID of this Endpoint --
	// taking into account stride (endpoint space bits)
	// and alignment thereof. This is used in IP calculation.
	EffectiveNetworkID uint64 `json:"-"`
	// Whether it is in use (for purposes of reclaiming)
	InUse bool   `json:"-"`
	Id    uint64 `sql:"AUTO_INCREMENT",json:"-"`
}
type ipamStore struct {
	common.DbStore
}

// deleteEndpoint releases the IP(s) owned by the endpoint into assignable
// pool.
func (ipamStore *ipamStore) deleteEndpoint(ip string) (Endpoint, error) {
	tx := ipamStore.DbStore.Db.Begin()
	results := make([]Endpoint, 0)
	tx.Where(&Endpoint{Ip: ip}).Find(&results)
	if len(results) == 0 {
		tx.Rollback()
		return Endpoint{}, common.NewError404("endpoint", ip)
	}
	if len(results) > 1 {
		// This cannot happen by constraints...
		tx.Rollback()
		errMsg := fmt.Sprintf("Expected one result for ip %s, got %v", ip, results)
		log.Printf(errMsg)
		return Endpoint{}, common.NewError500(errors.New(errMsg))
	}
	tx = tx.Model(Endpoint{}).Where("ip = ?", ip).Update("in_use", false)
	err := common.MakeMultiError(tx.GetErrors())
	if err != nil {
		tx.Rollback()
		return Endpoint{}, err
	}
	tx.Commit()
	return results[0], nil
}

// addEndpoint allocates an IP address and stores it in the
// database.
func (ipamStore *ipamStore) addEndpoint(endpoint *Endpoint, upToEndpointIpInt uint64, dc common.Datacenter) error {

	var err error
	tx := ipamStore.DbStore.Db.Begin()

	if endpoint.RequestToken.Valid && endpoint.RequestToken.String != "" {
		var existingEndpoints []Endpoint
		var count int
		tx.Where("request_token = ?", endpoint.RequestToken.String).Find(&existingEndpoints).Count(&count)
		err = common.GetDbErrors(tx)
		if err != nil {
			log.Printf("IPAM Errors 1: %v", err)
			tx.Rollback()
			return err
		}
		if count > 0 {
			// This will only be 1, because of unique constraint.
			tx.Rollback()
			log.Printf("Found existing %s: %+v", endpoint.RequestToken.String, existingEndpoints[0])
			endpoint.EffectiveNetworkID = existingEndpoints[0].EffectiveNetworkID
			endpoint.HostId = existingEndpoints[0].HostId
			endpoint.Id = existingEndpoints[0].Id
			endpoint.InUse = existingEndpoints[0].InUse
			endpoint.Name = existingEndpoints[0].Name
			endpoint.NetworkID = existingEndpoints[0].NetworkID
			endpoint.RequestToken = existingEndpoints[0].RequestToken
			endpoint.SegmentID = existingEndpoints[0].SegmentID
			endpoint.TenantID = existingEndpoints[0].TenantID
			return nil
		}
	}

	hostId := endpoint.HostId
	endpoint.InUse = true
	tenantId := endpoint.TenantID
	segId := endpoint.SegmentID
	filter := "host_id = ? AND tenant_id = ? AND segment_id = ? "

	var sel string
	// First, find the MAX network ID available for this host/segment combination.
	sel = "IFNULL(MAX(network_id),-1)+1"
	log.Printf("IpamStore: Calling SELECT %s FROM endpoints WHERE %s;", sel, fmt.Sprintf(strings.Replace(filter, "?", "%s", 3), hostId, tenantId, segId))
	row := tx.Model(Endpoint{}).Where(filter, hostId, tenantId, segId).Select(sel).Row()
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 2: %v", err)
		tx.Rollback()
		return err
	}

	netID := sql.NullInt64{}
	row.Scan(&netID)
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 3: %v", err)
		tx.Rollback()
		return err
	}

	log.Printf("IpamStore: max net ID: %v", netID)

	maxEffNetID := uint64(1<<(dc.EndpointSpaceBits+dc.EndpointBits) - 1)

	// Does this exceed max bits?
	endpoint.NetworkID = uint64(netID.Int64)
	endpoint.EffectiveNetworkID = getEffectiveNetworkID(endpoint.NetworkID, dc.EndpointSpaceBits)
	if endpoint.EffectiveNetworkID <= maxEffNetID {
		// Does not exceed max bits, all good.
		//		log.Printf("IpamStore: Effective network ID for network ID %d (stride %d): %d\n", endpoint.NetworkID, dc.EndpointSpaceBits, endpoint.EffectiveNetworkID)
		ipInt := upToEndpointIpInt | endpoint.EffectiveNetworkID
		//		log.Printf("IpamStore: %d | %d = %d", upToEndpointIpInt, endpoint.EffectiveNetworkID, ipInt)
		endpoint.Ip = common.IntToIPv4(ipInt).String()
		tx = tx.Create(endpoint)
		err = common.GetDbErrors(tx)
		if err != nil {
			log.Printf("IPAM Errors 4: %v", err)
			tx.Rollback()
			return err
		}
		tx.Commit()
		return nil
	}

	// Out of bits, see if we can reuse an earlier allocated address...
	log.Printf("IpamStore: New effective network ID is %d, exceeds maximum %d\n", endpoint.EffectiveNetworkID, maxEffNetID)
	// See if there is a formerly allocated IP already that has been released
	// (marked "in_use")
	sel = "MIN(network_id), ip"
	log.Printf("IpamStore: Calling SELECT %s FROM endpoints WHERE %s;", sel, fmt.Sprintf(strings.Replace(filter+"AND in_use = 0", "?", "%s", 3), hostId, tenantId, segId))
	// In containerized setup, not using group by leads to failure due to
	// incompatible sql mode, thus use "GROUP BY network_id, ip" to avoid
	// this failure.
	row = tx.Model(Endpoint{}).Where(filter+"AND in_use = 0", hostId, tenantId, segId).Select(sel).Group("ip").Row()
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 5: %v", err)
		tx.Rollback()
		return err
	}
	netID = sql.NullInt64{}
	var ip string
	row.Scan(&netID, &ip)
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 6: %v", err)
		tx.Rollback()
		return err
	}
	if netID.Valid {
		endpoint.Ip = ip
		tx = tx.Model(Endpoint{}).Where("ip = ?", ip).Update("in_use", true)
		err = common.GetDbErrors(tx)
		if err != nil {
			log.Printf("IPAM Errors 7: %v", err)
			tx.Rollback()
			return err
		}
		tx.Commit()
		return nil
	}
	tx.Rollback()
	return common.NewError("Out of IP addresses.")

}

// getEffectiveNetworkID gets effective number of an Endpoint
// on a given host (see endpoint.EffectiveNetworkID).
func getEffectiveNetworkID(EndpointNetworkID uint64, stride uint) uint64 {
	var effectiveEndpointNetworkID uint64
	// We start with 3 because we reserve 1 for gateway
	// and 2 for DHCP.
	effectiveEndpointNetworkID = 3 + (1<<stride)*EndpointNetworkID
	return effectiveEndpointNetworkID
}

// Entities implements Entities method of Service interface.
func (ipamStore *ipamStore) Entities() []interface{} {
	retval := make([]interface{}, 1)
	retval[0] = &Endpoint{}
	return retval
}

// CreateSchemaPostProcess implements CreateSchemaPostProcess method of
// Service interface.
func (ipamStore *ipamStore) CreateSchemaPostProcess() error {
	db := ipamStore.Db
	log.Printf("ipamStore.CreateSchemaPostProcess(), DB is %v", db)
	db.Model(&Endpoint{}).AddUniqueIndex("idx_tenant_segment_host_network_id", "tenant_id", "segment_id", "host_id", "network_id")
	db.Model(&Endpoint{}).AddUniqueIndex("idx_ip", "ip")
	err := common.MakeMultiError(db.GetErrors())
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>group by should not include the field being aggregated<commit_after>// Copyright (c) 2016 Pani Networks
// All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package ipam

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/romana/core/common"
	"log"
	"strings"
)

// Endpoint represents an endpoint (a VM, a Kubernetes Pod, etc.)
// that is to get an IP address.
type Endpoint struct {
	Ip           string         `json:"ip,omitempty"`
	TenantID     string         `json:"tenant_id,omitempty"`
	SegmentID    string         `json:"segment_id,omitempty"`
	HostId       string         `json:"host_id,omitempty"`
	Name         string         `json:"name,omitempty"`
	RequestToken sql.NullString `json:"request_token" sql:"unique"`
	// Ordinal number of this Endpoint in the host/tenant combination
	NetworkID uint64 `json:"-"`
	// Calculated effective network ID of this Endpoint --
	// taking into account stride (endpoint space bits)
	// and alignment thereof. This is used in IP calculation.
	EffectiveNetworkID uint64 `json:"-"`
	// Whether it is in use (for purposes of reclaiming)
	InUse bool   `json:"-"`
	Id    uint64 `sql:"AUTO_INCREMENT",json:"-"`
}
type ipamStore struct {
	common.DbStore
}

// deleteEndpoint releases the IP(s) owned by the endpoint into assignable
// pool.
func (ipamStore *ipamStore) deleteEndpoint(ip string) (Endpoint, error) {
	tx := ipamStore.DbStore.Db.Begin()
	results := make([]Endpoint, 0)
	tx.Where(&Endpoint{Ip: ip}).Find(&results)
	if len(results) == 0 {
		tx.Rollback()
		return Endpoint{}, common.NewError404("endpoint", ip)
	}
	if len(results) > 1 {
		// This cannot happen by constraints...
		tx.Rollback()
		errMsg := fmt.Sprintf("Expected one result for ip %s, got %v", ip, results)
		log.Printf(errMsg)
		return Endpoint{}, common.NewError500(errors.New(errMsg))
	}
	tx = tx.Model(Endpoint{}).Where("ip = ?", ip).Update("in_use", false)
	err := common.MakeMultiError(tx.GetErrors())
	if err != nil {
		tx.Rollback()
		return Endpoint{}, err
	}
	tx.Commit()
	return results[0], nil
}

// addEndpoint allocates an IP address and stores it in the
// database.
func (ipamStore *ipamStore) addEndpoint(endpoint *Endpoint, upToEndpointIpInt uint64, dc common.Datacenter) error {

	var err error
	tx := ipamStore.DbStore.Db.Begin()

	if endpoint.RequestToken.Valid && endpoint.RequestToken.String != "" {
		var existingEndpoints []Endpoint
		var count int
		tx.Where("request_token = ?", endpoint.RequestToken.String).Find(&existingEndpoints).Count(&count)
		err = common.GetDbErrors(tx)
		if err != nil {
			log.Printf("IPAM Errors 1: %v", err)
			tx.Rollback()
			return err
		}
		if count > 0 {
			// This will only be 1, because of unique constraint.
			tx.Rollback()
			log.Printf("Found existing %s: %+v", endpoint.RequestToken.String, existingEndpoints[0])
			endpoint.EffectiveNetworkID = existingEndpoints[0].EffectiveNetworkID
			endpoint.HostId = existingEndpoints[0].HostId
			endpoint.Id = existingEndpoints[0].Id
			endpoint.InUse = existingEndpoints[0].InUse
			endpoint.Name = existingEndpoints[0].Name
			endpoint.NetworkID = existingEndpoints[0].NetworkID
			endpoint.RequestToken = existingEndpoints[0].RequestToken
			endpoint.SegmentID = existingEndpoints[0].SegmentID
			endpoint.TenantID = existingEndpoints[0].TenantID
			endpoint.Ip = existingEndpoints[0].Ip
			return nil
		}
	}

	hostId := endpoint.HostId
	endpoint.InUse = true
	tenantId := endpoint.TenantID
	segId := endpoint.SegmentID
	filter := "host_id = ? AND tenant_id = ? AND segment_id = ? "

	var sel string
	// First, find the MAX network ID available for this host/segment combination.
	sel = "IFNULL(MAX(network_id),-1)+1"
	log.Printf("IpamStore: Calling SELECT %s FROM endpoints WHERE %s;", sel, fmt.Sprintf(strings.Replace(filter, "?", "%s", 3), hostId, tenantId, segId))
	row := tx.Model(Endpoint{}).Where(filter, hostId, tenantId, segId).Select(sel).Row()
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 2: %v", err)
		tx.Rollback()
		return err
	}

	netID := sql.NullInt64{}
	row.Scan(&netID)
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 3: %v", err)
		tx.Rollback()
		return err
	}

	log.Printf("IpamStore: max net ID: %v", netID)

	maxEffNetID := uint64(1<<(dc.EndpointSpaceBits+dc.EndpointBits) - 1)

	// Does this exceed max bits?
	endpoint.NetworkID = uint64(netID.Int64)
	endpoint.EffectiveNetworkID = getEffectiveNetworkID(endpoint.NetworkID, dc.EndpointSpaceBits)
	if endpoint.EffectiveNetworkID <= maxEffNetID {
		// Does not exceed max bits, all good.
		//		log.Printf("IpamStore: Effective network ID for network ID %d (stride %d): %d\n", endpoint.NetworkID, dc.EndpointSpaceBits, endpoint.EffectiveNetworkID)
		ipInt := upToEndpointIpInt | endpoint.EffectiveNetworkID
		//		log.Printf("IpamStore: %d | %d = %d", upToEndpointIpInt, endpoint.EffectiveNetworkID, ipInt)
		endpoint.Ip = common.IntToIPv4(ipInt).String()
		tx = tx.Create(endpoint)
		err = common.GetDbErrors(tx)
		if err != nil {
			log.Printf("IPAM Errors 4: %v", err)
			tx.Rollback()
			return err
		}
		log.Printf("IpamStore: Allocated %d: %s", endpoint.NetworkID, endpoint.Ip)
		tx.Commit()
		return nil
	}

	// Out of bits, see if we can reuse an earlier allocated address...
	log.Printf("IpamStore: New effective network ID is %d, exceeds maximum %d\n", endpoint.EffectiveNetworkID, maxEffNetID)
	// See if there is a formerly allocated IP already that has been released
	// (marked "in_use")
	sel = "MIN(network_id), ip"
	log.Printf("IpamStore: Calling SELECT %s FROM endpoints WHERE %s;", sel, fmt.Sprintf(strings.Replace(filter+"AND in_use = 0", "?", "%s", 3), hostId, tenantId, segId))
	// In containerized setup, not using group by leads to failure due to
	// incompatible sql mode, thus use "GROUP BY network_id, ip" to avoid
	// this failure.
	row = tx.Model(Endpoint{}).Where(filter+"AND in_use = 0", hostId, tenantId, segId).Select(sel).Group("ip").Order("network_id ASC").Row()
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 5: %v", err)
		tx.Rollback()
		return err
	}
	netID = sql.NullInt64{}
	var ip string
	row.Scan(&netID, &ip)
	err = common.GetDbErrors(tx)
	if err != nil {
		log.Printf("IPAM Errors 6: %v", err)
		tx.Rollback()
		return err
	}
	if netID.Valid {
		log.Printf("IpamStore: Reusing %d: %s", netID.Int64, ip)
		endpoint.Ip = ip
		tx = tx.Model(Endpoint{}).Where("ip = ?", ip).Update("in_use", true)
		err = common.GetDbErrors(tx)
		if err != nil {
			log.Printf("IPAM Errors 7: %v", err)
			tx.Rollback()
			return err
		}
		tx.Commit()
		return nil
	}
	tx.Rollback()
	return common.NewError("Out of IP addresses.")

}

// getEffectiveNetworkID gets effective number of an Endpoint
// on a given host (see endpoint.EffectiveNetworkID).
func getEffectiveNetworkID(EndpointNetworkID uint64, stride uint) uint64 {
	var effectiveEndpointNetworkID uint64
	// We start with 3 because we reserve 1 for gateway
	// and 2 for DHCP.
	effectiveEndpointNetworkID = 3 + (1<<stride)*EndpointNetworkID
	return effectiveEndpointNetworkID
}

// Entities implements Entities method of Service interface.
func (ipamStore *ipamStore) Entities() []interface{} {
	retval := make([]interface{}, 1)
	retval[0] = &Endpoint{}
	return retval
}

// CreateSchemaPostProcess implements CreateSchemaPostProcess method of
// Service interface.
func (ipamStore *ipamStore) CreateSchemaPostProcess() error {
	db := ipamStore.Db
	log.Printf("ipamStore.CreateSchemaPostProcess(), DB is %v", db)
	db.Model(&Endpoint{}).AddUniqueIndex("idx_tenant_segment_host_network_id", "tenant_id", "segment_id", "host_id", "network_id")
	db.Model(&Endpoint{}).AddUniqueIndex("idx_ip", "ip")
	err := common.MakeMultiError(db.GetErrors())
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package editor

import (
	"fmt"
	"strings"

	"github.com/elpinal/coco3/screen"
)

type exCommand struct {
	name string
	fn   func(*commandline, []string) continuity
}

// exComands represents a table of Ex commands and corresponding functions.
// The order is important. Precede commands have higher precedence.
var exCommands = []exCommand{
	{"help", (*commandline).help},
	{"delete", (*commandline).delete},
	{"quit", (*commandline).quit},
	{"substitute", (*commandline).substitute},
}

type commandline struct {
	streamSet
	*editor

	basic *basic
}

func newCommandline(s streamSet, e *editor) *commandline {
	return &commandline{
		streamSet: s,
		editor:    e,
		basic:     &basic{},
	}
}

func (e *commandline) Mode() mode {
	return modeCommandline
}

func (e *commandline) Position() int {
	return e.basic.pos + 1
}

func (e *commandline) Runes() []rune {
	return e.buf
}

func (e *commandline) Message() []rune {
	return append([]rune{':'}, e.basic.buf...)
}

func (e *commandline) Highlight() *screen.Hi {
	return nil
}

func (e *commandline) Run() (end continuity, next modeChanger, err error) {
	r, _, err := e.streamSet.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	switch r {
	case CharCtrlM, CharCtrlJ:
	case CharEscape, CharCtrlC:
		next = norm()
		return end, next, err
	case CharBackspace, CharCtrlH:
		if len(e.basic.buf) == 0 {
			next = norm()
			return
		}
		e.basic.delete(e.basic.pos-1, e.basic.pos)
	case CharCtrlB:
		e.basic.move(0)
	case CharCtrlE:
		e.basic.move(len(e.basic.buf))
	case CharCtrlU:
		e.basic.delete(0, e.basic.pos)
	case CharCtrlW:
		// FIXME: It's redundant.
		ed := newEditor()
		ed.pos = e.basic.pos
		ed.buf = e.basic.buf
		pos := ed.pos
		ed.wordBackward()
		e.basic.delete(pos, ed.pos)
		return
	default:
		e.basic.insert([]rune{r}, e.basic.pos)
	}
	if r != CharCtrlM && r != CharCtrlJ {
		return
	}
	next = norm()
	var candidate exCommand
	s := string(e.basic.buf)
	if s == "" {
		return
	}
	for _, cmd := range exCommands {
		if !strings.HasPrefix(cmd.name, s) {
			continue
		}
		if cmd.name == s {
			end = cmd.fn(e, nil)
			return
		}
		if candidate.name == "" {
			candidate = cmd
		}
	}
	if candidate.name != "" {
		end = candidate.fn(e, nil)
		return
	}
	err = fmt.Errorf("not a command: %q", s)
	return
}

func (e *commandline) quit(args []string) continuity {
	return exit
}

func (e *commandline) delete(args []string) (_ continuity) {
	e.editor.delete(0, len(e.editor.buf))
	return
}

func (e *commandline) help(args []string) continuity {
	e.buf = []rune("help")
	e.pos = 4
	return execute
}

func (e *commandline) substitute(args []string) (_ continuity) {
	if len(args) != 2 {
		return
	}
	return
}
<commit_msg>Split arguments in command-line<commit_after>package editor

import (
	"fmt"
	"strings"

	"github.com/elpinal/coco3/screen"
)

type exCommand struct {
	name string
	fn   func(*commandline, []string) continuity
}

// exComands represents a table of Ex commands and corresponding functions.
// The order is important. Precede commands have higher precedence.
var exCommands = []exCommand{
	{"help", (*commandline).help},
	{"delete", (*commandline).delete},
	{"quit", (*commandline).quit},
	{"substitute", (*commandline).substitute},
}

type commandline struct {
	streamSet
	*editor

	basic *basic
}

func newCommandline(s streamSet, e *editor) *commandline {
	return &commandline{
		streamSet: s,
		editor:    e,
		basic:     &basic{},
	}
}

func (e *commandline) Mode() mode {
	return modeCommandline
}

func (e *commandline) Position() int {
	return e.basic.pos + 1
}

func (e *commandline) Runes() []rune {
	return e.buf
}

func (e *commandline) Message() []rune {
	return append([]rune{':'}, e.basic.buf...)
}

func (e *commandline) Highlight() *screen.Hi {
	return nil
}

func (e *commandline) Run() (end continuity, next modeChanger, err error) {
	r, _, err := e.streamSet.in.ReadRune()
	if err != nil {
		return end, next, err
	}
	switch r {
	case CharCtrlM, CharCtrlJ:
	case CharEscape, CharCtrlC:
		next = norm()
		return end, next, err
	case CharBackspace, CharCtrlH:
		if len(e.basic.buf) == 0 {
			next = norm()
			return
		}
		e.basic.delete(e.basic.pos-1, e.basic.pos)
	case CharCtrlB:
		e.basic.move(0)
	case CharCtrlE:
		e.basic.move(len(e.basic.buf))
	case CharCtrlU:
		e.basic.delete(0, e.basic.pos)
	case CharCtrlW:
		// FIXME: It's redundant.
		ed := newEditor()
		ed.pos = e.basic.pos
		ed.buf = e.basic.buf
		pos := ed.pos
		ed.wordBackward()
		e.basic.delete(pos, ed.pos)
		return
	default:
		e.basic.insert([]rune{r}, e.basic.pos)
	}
	if r != CharCtrlM && r != CharCtrlJ {
		return
	}
	next = norm()
	var candidate exCommand
	s := string(e.basic.buf)
	if s == "" {
		return
	}
	args := strings.Split(s, " ")
	s = args[0]
	for _, cmd := range exCommands {
		if !strings.HasPrefix(cmd.name, s) {
			continue
		}
		if cmd.name == s {
			end = cmd.fn(e, nil)
			return
		}
		if candidate.name == "" {
			candidate = cmd
		}
	}
	if candidate.name != "" {
		end = candidate.fn(e, nil)
		return
	}
	err = fmt.Errorf("not a command: %q", s)
	return
}

func (e *commandline) quit(args []string) continuity {
	return exit
}

func (e *commandline) delete(args []string) (_ continuity) {
	e.editor.delete(0, len(e.editor.buf))
	return
}

func (e *commandline) help(args []string) continuity {
	e.buf = []rune("help")
	e.pos = 4
	return execute
}

func (e *commandline) substitute(args []string) (_ continuity) {
	if len(args) != 2 {
		return
	}
	return
}
<|endoftext|>


<commit_before>package aws

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

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

func resourceAwsNetworkAcl() *schema.Resource {

	return &schema.Resource{
		Create: resourceAwsNetworkAclCreate,
		Read:   resourceAwsNetworkAclRead,
		Delete: resourceAwsNetworkAclDelete,
		Update: resourceAwsNetworkAclUpdate,

		Schema: map[string]*schema.Schema{
			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				Computed: false,
			},
			"subnet_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: false,
			},
			"ingress": &schema.Schema{
				Type:     schema.TypeSet,
				Required: false,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"rule_no": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"action": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"cidr_block": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
				Set: resourceAwsNetworkAclEntryHash,
			},
			"egress": &schema.Schema{
				Type:     schema.TypeSet,
				Required: false,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"rule_no": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"action": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"cidr_block": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
				Set: resourceAwsNetworkAclEntryHash,
			},
			"tags": tagsSchema(),
		},
	}
}

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

	conn := meta.(*AWSClient).ec2conn

	// Create the Network Acl
	createOpts := &ec2.CreateNetworkACLInput{
		VPCID: aws.String(d.Get("vpc_id").(string)),
	}

	log.Printf("[DEBUG] Network Acl create config: %#v", createOpts)
	resp, err := conn.CreateNetworkACL(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating network acl: %s", err)
	}

	// Get the ID and store it
	networkAcl := resp.NetworkACL
	d.SetId(*networkAcl.NetworkACLID)
	log.Printf("[INFO] Network Acl ID: %s", *networkAcl.NetworkACLID)

	// Update rules and subnet association once acl is created
	return resourceAwsNetworkAclUpdate(d, meta)
}

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

	resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsInput{
		NetworkACLIDs: []*string{aws.String(d.Id())},
	})

	if err != nil {
		return err
	}
	if resp == nil {
		return nil
	}

	networkAcl := resp.NetworkACLs[0]
	var ingressEntries []*ec2.NetworkACLEntry
	var egressEntries []*ec2.NetworkACLEntry

	// separate the ingress and egress rules
	for _, e := range networkAcl.Entries {
		if *e.Egress == true {
			egressEntries = append(egressEntries, e)
		} else {
			ingressEntries = append(ingressEntries, e)
		}
	}

	d.Set("vpc_id", networkAcl.VPCID)
	d.Set("ingress", ingressEntries)
	d.Set("egress", egressEntries)
	d.Set("tags", tagsToMapSDK(networkAcl.Tags))

	return nil
}

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

	if d.HasChange("ingress") {
		err := updateNetworkAclEntries(d, "ingress", conn)
		if err != nil {
			return err
		}
	}

	if d.HasChange("egress") {
		err := updateNetworkAclEntries(d, "egress", conn)
		if err != nil {
			return err
		}
	}

	if d.HasChange("subnet_id") {
		//associate new subnet with the acl.
		_, n := d.GetChange("subnet_id")
		newSubnet := n.(string)
		association, err := findNetworkAclAssociation(newSubnet, conn)
		if err != nil {
			return fmt.Errorf("Failed to update acl %s with subnet %s: %s", d.Id(), newSubnet, err)
		}
		_, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{
			AssociationID: association.NetworkACLAssociationID,
			NetworkACLID:  aws.String(d.Id()),
		})
		if err != nil {
			return err
		}
	}

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

	d.Partial(false)
	return resourceAwsNetworkAclRead(d, meta)
}

func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2.EC2) error {

	o, n := d.GetChange(entryType)

	if o == nil {
		o = new(schema.Set)
	}
	if n == nil {
		n = new(schema.Set)
	}

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

	toBeDeleted, err := expandNetworkAclEntries(os.Difference(ns).List(), entryType)
	if err != nil {
		return err
	}
	for _, remove := range toBeDeleted {
		// Delete old Acl
		_, err := conn.DeleteNetworkACLEntry(&ec2.DeleteNetworkACLEntryInput{
			NetworkACLID: aws.String(d.Id()),
			RuleNumber:   remove.RuleNumber,
			Egress:       remove.Egress,
		})
		if err != nil {
			return fmt.Errorf("Error deleting %s entry: %s", entryType, err)
		}
	}

	toBeCreated, err := expandNetworkAclEntries(ns.Difference(os).List(), entryType)
	if err != nil {
		return err
	}
	for _, add := range toBeCreated {
		// Add new Acl entry
		_, err := conn.CreateNetworkACLEntry(&ec2.CreateNetworkACLEntryInput{
			NetworkACLID: aws.String(d.Id()),
			CIDRBlock:    add.CIDRBlock,
			Egress:       add.Egress,
			PortRange:    add.PortRange,
			Protocol:     add.Protocol,
			RuleAction:   add.RuleAction,
			RuleNumber:   add.RuleNumber,
		})
		if err != nil {
			return fmt.Errorf("Error creating %s entry: %s", entryType, err)
		}
	}
	return nil
}

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

	log.Printf("[INFO] Deleting Network Acl: %s", d.Id())
	return resource.Retry(5*time.Minute, func() error {
		_, err := conn.DeleteNetworkACL(&ec2.DeleteNetworkACLInput{
			NetworkACLID: aws.String(d.Id()),
		})
		if err != nil {
			ec2err := err.(aws.APIError)
			switch ec2err.Code {
			case "InvalidNetworkAclID.NotFound":
				return nil
			case "DependencyViolation":
				// In case of dependency violation, we remove the association between subnet and network acl.
				// This means the subnet is attached to default acl of vpc.
				association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), conn)
				if err != nil {
					return fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)
				}
				defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), conn)
				if err != nil {
					return fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)
				}
				_, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{
					AssociationID: association.NetworkACLAssociationID,
					NetworkACLID:  defaultAcl.NetworkACLID,
				})
				return resource.RetryError{Err: err}
			default:
				// Any other error, we want to quit the retry loop immediately
				return resource.RetryError{Err: err}
			}
		}
		log.Printf("[Info] Deleted network ACL %s successfully", d.Id())
		return nil
	})
}

func resourceAwsNetworkAclEntryHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["rule_no"].(int)))
	buf.WriteString(fmt.Sprintf("%s-", m["action"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["cidr_block"].(string)))

	if v, ok := m["ssl_certificate_id"]; ok {
		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
	}

	return hashcode.String(buf.String())
}

func getDefaultNetworkAcl(vpc_id string, conn *ec2.EC2) (defaultAcl *ec2.NetworkACL, err error) {
	resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsInput{
		NetworkACLIDs: []*string{},
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name:   aws.String("default"),
				Values: []*string{aws.String("true")},
			},
			&ec2.Filter{
				Name:   aws.String("vpc-id"),
				Values: []*string{aws.String(vpc_id)},
			},
		},
	})

	if err != nil {
		return nil, err
	}
	return resp.NetworkACLs[0], nil
}

func findNetworkAclAssociation(subnetId string, conn *ec2.EC2) (networkAclAssociation *ec2.NetworkACLAssociation, err error) {
	resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsInput{
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name:   aws.String("association.subnet-id"),
				Values: []*string{aws.String(subnetId)},
			},
		},
	})

	if err != nil {
		return nil, err
	}
	if resp.NetworkACLs != nil && len(resp.NetworkACLs) > 0 {
		for _, association := range resp.NetworkACLs[0].Associations {
			if *association.SubnetID == subnetId {
				return association, nil
			}
		}
	}
	return nil, fmt.Errorf("could not find association for subnet %s ", subnetId)
}
<commit_msg>provider/aws: Fix acceptance issue with Network Acls<commit_after>package aws

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

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

func resourceAwsNetworkAcl() *schema.Resource {

	return &schema.Resource{
		Create: resourceAwsNetworkAclCreate,
		Read:   resourceAwsNetworkAclRead,
		Delete: resourceAwsNetworkAclDelete,
		Update: resourceAwsNetworkAclUpdate,

		Schema: map[string]*schema.Schema{
			"vpc_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				Computed: false,
			},
			"subnet_id": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: false,
			},
			"ingress": &schema.Schema{
				Type:     schema.TypeSet,
				Required: false,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"rule_no": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"action": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"cidr_block": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
				Set: resourceAwsNetworkAclEntryHash,
			},
			"egress": &schema.Schema{
				Type:     schema.TypeSet,
				Required: false,
				Optional: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"from_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"to_port": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"rule_no": &schema.Schema{
							Type:     schema.TypeInt,
							Required: true,
						},
						"action": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"cidr_block": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
				Set: resourceAwsNetworkAclEntryHash,
			},
			"tags": tagsSchema(),
		},
	}
}

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

	conn := meta.(*AWSClient).ec2conn

	// Create the Network Acl
	createOpts := &ec2.CreateNetworkACLInput{
		VPCID: aws.String(d.Get("vpc_id").(string)),
	}

	log.Printf("[DEBUG] Network Acl create config: %#v", createOpts)
	resp, err := conn.CreateNetworkACL(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating network acl: %s", err)
	}

	// Get the ID and store it
	networkAcl := resp.NetworkACL
	d.SetId(*networkAcl.NetworkACLID)
	log.Printf("[INFO] Network Acl ID: %s", *networkAcl.NetworkACLID)

	// Update rules and subnet association once acl is created
	return resourceAwsNetworkAclUpdate(d, meta)
}

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

	resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsInput{
		NetworkACLIDs: []*string{aws.String(d.Id())},
	})

	if err != nil {
		return err
	}
	if resp == nil {
		return nil
	}

	networkAcl := resp.NetworkACLs[0]
	var ingressEntries []*ec2.NetworkACLEntry
	var egressEntries []*ec2.NetworkACLEntry

	// separate the ingress and egress rules
	for _, e := range networkAcl.Entries {
		if *e.Egress == true {
			egressEntries = append(egressEntries, e)
		} else {
			ingressEntries = append(ingressEntries, e)
		}
	}

	d.Set("vpc_id", networkAcl.VPCID)
	d.Set("ingress", ingressEntries)
	d.Set("egress", egressEntries)
	d.Set("tags", tagsToMapSDK(networkAcl.Tags))

	return nil
}

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

	if d.HasChange("ingress") {
		err := updateNetworkAclEntries(d, "ingress", conn)
		if err != nil {
			return err
		}
	}

	if d.HasChange("egress") {
		err := updateNetworkAclEntries(d, "egress", conn)
		if err != nil {
			return err
		}
	}

	if d.HasChange("subnet_id") {
		//associate new subnet with the acl.
		_, n := d.GetChange("subnet_id")
		newSubnet := n.(string)
		association, err := findNetworkAclAssociation(newSubnet, conn)
		if err != nil {
			return fmt.Errorf("Failed to update acl %s with subnet %s: %s", d.Id(), newSubnet, err)
		}
		_, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{
			AssociationID: association.NetworkACLAssociationID,
			NetworkACLID:  aws.String(d.Id()),
		})
		if err != nil {
			return err
		}
	}

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

	d.Partial(false)
	return resourceAwsNetworkAclRead(d, meta)
}

func updateNetworkAclEntries(d *schema.ResourceData, entryType string, conn *ec2.EC2) error {

	o, n := d.GetChange(entryType)

	if o == nil {
		o = new(schema.Set)
	}
	if n == nil {
		n = new(schema.Set)
	}

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

	toBeDeleted, err := expandNetworkAclEntries(os.Difference(ns).List(), entryType)
	if err != nil {
		return err
	}
	for _, remove := range toBeDeleted {
		// Delete old Acl
		_, err := conn.DeleteNetworkACLEntry(&ec2.DeleteNetworkACLEntryInput{
			NetworkACLID: aws.String(d.Id()),
			RuleNumber:   remove.RuleNumber,
			Egress:       remove.Egress,
		})
		if err != nil {
			return fmt.Errorf("Error deleting %s entry: %s", entryType, err)
		}
	}

	toBeCreated, err := expandNetworkAclEntries(ns.Difference(os).List(), entryType)
	if err != nil {
		return err
	}
	for _, add := range toBeCreated {
		// Add new Acl entry
		_, err := conn.CreateNetworkACLEntry(&ec2.CreateNetworkACLEntryInput{
			NetworkACLID: aws.String(d.Id()),
			CIDRBlock:    add.CIDRBlock,
			Egress:       add.Egress,
			PortRange:    add.PortRange,
			Protocol:     add.Protocol,
			RuleAction:   add.RuleAction,
			RuleNumber:   add.RuleNumber,
		})
		if err != nil {
			return fmt.Errorf("Error creating %s entry: %s", entryType, err)
		}
	}
	return nil
}

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

	log.Printf("[INFO] Deleting Network Acl: %s", d.Id())
	return resource.Retry(5*time.Minute, func() error {
		_, err := conn.DeleteNetworkACL(&ec2.DeleteNetworkACLInput{
			NetworkACLID: aws.String(d.Id()),
		})
		if err != nil {
			ec2err := err.(aws.APIError)
			switch ec2err.Code {
			case "InvalidNetworkAclID.NotFound":
				return nil
			case "DependencyViolation":
				// In case of dependency violation, we remove the association between subnet and network acl.
				// This means the subnet is attached to default acl of vpc.
				association, err := findNetworkAclAssociation(d.Get("subnet_id").(string), conn)
				if err != nil {
					return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)}
				}
				defaultAcl, err := getDefaultNetworkAcl(d.Get("vpc_id").(string), conn)
				if err != nil {
					return resource.RetryError{Err: fmt.Errorf("Dependency violation: Cannot delete acl %s: %s", d.Id(), err)}
				}
				_, err = conn.ReplaceNetworkACLAssociation(&ec2.ReplaceNetworkACLAssociationInput{
					AssociationID: association.NetworkACLAssociationID,
					NetworkACLID:  defaultAcl.NetworkACLID,
				})
				return resource.RetryError{Err: err}
			default:
				// Any other error, we want to quit the retry loop immediately
				return resource.RetryError{Err: err}
			}
		}
		log.Printf("[Info] Deleted network ACL %s successfully", d.Id())
		return nil
	})
}

func resourceAwsNetworkAclEntryHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int)))
	buf.WriteString(fmt.Sprintf("%d-", m["rule_no"].(int)))
	buf.WriteString(fmt.Sprintf("%s-", m["action"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", m["cidr_block"].(string)))

	if v, ok := m["ssl_certificate_id"]; ok {
		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
	}

	return hashcode.String(buf.String())
}

func getDefaultNetworkAcl(vpc_id string, conn *ec2.EC2) (defaultAcl *ec2.NetworkACL, err error) {
	resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsInput{
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name:   aws.String("default"),
				Values: []*string{aws.String("true")},
			},
			&ec2.Filter{
				Name:   aws.String("vpc-id"),
				Values: []*string{aws.String(vpc_id)},
			},
		},
	})

	if err != nil {
		return nil, err
	}
	return resp.NetworkACLs[0], nil
}

func findNetworkAclAssociation(subnetId string, conn *ec2.EC2) (networkAclAssociation *ec2.NetworkACLAssociation, err error) {
	resp, err := conn.DescribeNetworkACLs(&ec2.DescribeNetworkACLsInput{
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name:   aws.String("association.subnet-id"),
				Values: []*string{aws.String(subnetId)},
			},
		},
	})

	if err != nil {
		return nil, err
	}
	if resp.NetworkACLs != nil && len(resp.NetworkACLs) > 0 {
		for _, association := range resp.NetworkACLs[0].Associations {
			if *association.SubnetID == subnetId {
				return association, nil
			}
		}
	}
	return nil, fmt.Errorf("could not find association for subnet %s ", subnetId)
}
<|endoftext|>


<commit_before>package project_test

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"

	"github.com/getantibody/antibody/project"
	"github.com/stretchr/testify/assert"
)

func TestDownloadAllKinds(t *testing.T) {
	assert := assert.New(t)
	urls := []string{
		"caarlos0/ports",
		"http://github.com/caarlos0/ports",
		"http://github.com/caarlos0/ports.git",
		"https://github.com/caarlos0/ports",
		"https://github.com/caarlos0/ports.git",
		"git://github.com/caarlos0/ports.git",
		"https://gitlab.com/caarlos0/test.git",
		// FIXME: those fail on travis:
		// "git@gitlab.com:caarlos0/test.git",
		// "ssh://git@github.com/caarlos0/ports.git",
		// "git@github.com:caarlos0/ports.git",
	}
	for _, url := range urls {
		home := home()
		assert.NoError(
			project.NewGit(home, url).Download(),
			"Repo "+url+" failed to download",
		)
	}
}

func TestDownloadSubmodules(t *testing.T) {
	var assert = assert.New(t)
	var home = home()
	var proj = project.NewGit(home, "fribmendes/geometry")
	var module = filepath.Join(proj.Folder(), "lib/zsh-async")
	assert.NoError(proj.Download())
	assert.NoError(proj.Update())
	files, err := ioutil.ReadDir(module)
	assert.NoError(err)
	assert.True(len(files) > 1)
}

func TestDownloadAnotherBranch(t *testing.T) {
	assert := assert.New(t)
	home := home()
	assert.NoError(project.NewGit(home, "caarlos0/jvm branch:gh-pages").Download())
}

func TestUpdateNonExistentLocalRepo(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/ports")
	assert.Error(repo.Update())
}

func TestDownloadNonExistentRepo(t *testing.T) {
	var assert = assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/not-a-real-repo")
	assert.Error(repo.Download())
}

func TestDownloadMalformedRepo(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "doesn-not-exist-really branch:also-nope")
	assert.Error(repo.Download())
}

func TestDownloadMultipleTimes(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/ports")
	assert.NoError(repo.Download())
	assert.NoError(repo.Download())
	assert.NoError(repo.Update())
}

func TestDownloadFolderNaming(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/ports")
	assert.Equal(
		home+"/https-COLON--SLASH--SLASH-github.com-SLASH-caarlos0-SLASH-ports",
		repo.Folder(),
	)
}

func home() string {
	home, err := ioutil.TempDir(os.TempDir(), "antibody")
	if err != nil {
		panic(err.Error())
	}
	return home
}
<commit_msg>Add tests for subfolder<commit_after>package project_test

import (
	"io/ioutil"
	"os"
	"path/filepath"
    "strings"
	"testing"

	"github.com/getantibody/antibody/project"
	"github.com/stretchr/testify/assert"
)

func TestDownloadAllKinds(t *testing.T) {
	assert := assert.New(t)
	urls := []string{
		"caarlos0/ports",
		"http://github.com/caarlos0/ports",
		"http://github.com/caarlos0/ports.git",
		"https://github.com/caarlos0/ports",
		"https://github.com/caarlos0/ports.git",
		"git://github.com/caarlos0/ports.git",
		"https://gitlab.com/caarlos0/test.git",
		// FIXME: those fail on travis:
		// "git@gitlab.com:caarlos0/test.git",
		// "ssh://git@github.com/caarlos0/ports.git",
		// "git@github.com:caarlos0/ports.git",
	}
	for _, url := range urls {
		home := home()
		assert.NoError(
			project.NewGit(home, url).Download(),
			"Repo "+url+" failed to download",
		)
	}
}

func TestDownloadSubmodules(t *testing.T) {
	var assert = assert.New(t)
	var home = home()
	var proj = project.NewGit(home, "fribmendes/geometry")
	var module = filepath.Join(proj.Folder(), "lib/zsh-async")
	assert.NoError(proj.Download())
	assert.NoError(proj.Update())
	files, err := ioutil.ReadDir(module)
	assert.NoError(err)
	assert.True(len(files) > 1)
}

func TestDownloadAnotherBranch(t *testing.T) {
	assert := assert.New(t)
	home := home()
	assert.NoError(project.NewGit(home, "caarlos0/jvm branch:gh-pages").Download())
}

func TestUpdateNonExistentLocalRepo(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/ports")
	assert.Error(repo.Update())
}

func TestDownloadNonExistentRepo(t *testing.T) {
	var assert = assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/not-a-real-repo")
	assert.Error(repo.Download())
}

func TestDownloadMalformedRepo(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "doesn-not-exist-really branch:also-nope")
	assert.Error(repo.Download())
}

func TestDownloadMultipleTimes(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/ports")
	assert.NoError(repo.Download())
	assert.NoError(repo.Download())
	assert.NoError(repo.Update())
}

func TestDownloadFolderNaming(t *testing.T) {
	assert := assert.New(t)
	home := home()
	repo := project.NewGit(home, "caarlos0/ports")
	assert.Equal(
		home+"/https-COLON--SLASH--SLASH-github.com-SLASH-caarlos0-SLASH-ports",
		repo.Folder(),
	)
}

func TestSubFolder(t *testing.T) {
    assert := assert.New(t)
    home := home()
    repo := project.NewGit(home, "robbyrussell/oh-my-zsh folder:plugins/aws")
    assert.True(strings.HasSuffix(repo.Folder(), "plugins/aws"))
}

func TestMultipleSubFolders(t *testing.T) {
    assert := assert.New(t)
    home := home()
    assert.NoError(project.NewGit(home, "robbyrussell/oh-my-zsh folder:plugins/aws").Download())
    assert.NoError(project.NewGit(home, "robbyrussell/oh-my-zsh folder:plugins/battery").Download())
}

func home() string {
	home, err := ioutil.TempDir(os.TempDir(), "antibody")
	if err != nil {
		panic(err.Error())
	}
	return home
}
<|endoftext|>


<commit_before>package htmlutil

import (
	"fmt"
	"strings"

	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
)

func Lift(n *html.Node) {
	if n.Parent == nil {
		return
	}
	for {
		c := n.FirstChild
		if c == nil {
			break
		}
		n.RemoveChild(c)
		n.Parent.InsertBefore(c, n)
	}
	Drop(n)
}

func Drop(n *html.Node) {
	if n.Parent != nil {
		n.Parent.RemoveChild(n)
	}
}

func Create(tag string) *html.Node {
	var s string
	if Voids.HasName([]byte(tag)) {
		s = "<" + tag + ">"
	} else {
		s = fmt.Sprintf("<%s></%s>", tag, tag)
	}
	fragments, err := html.ParseFragment(strings.NewReader(s), BodyContext)
	if err != nil {
		return nil
	}
	return fragments[0]
}

func Replace(original, repl *html.Node) {
	if original.Parent == nil {
		panic("replacing not possible: parent is nil")
	}
	if original == repl {
		return
	}
	original.Parent.InsertBefore(repl, original)
	original.Parent.RemoveChild(original)
}

// BodyContext can be used as the context when parsing fragments.
var BodyContext *html.Node

func init() {
	doc, _ := html.Parse(strings.NewReader(`<html><body></body></html>`))
	BodyContext = FindOne(doc, atom.Body)
}
<commit_msg>Drop: return original element<commit_after>package htmlutil

import (
	"fmt"
	"strings"

	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
)

func Lift(n *html.Node) {
	if n.Parent == nil {
		return
	}
	for {
		c := n.FirstChild
		if c == nil {
			break
		}
		n.RemoveChild(c)
		n.Parent.InsertBefore(c, n)
	}
	Drop(n)
}

func Drop(n *html.Node) *html.Node {
	if n.Parent != nil {
		n.Parent.RemoveChild(n)
	}
	return n
}

func Create(tag string) *html.Node {
	var s string
	if Voids.HasName([]byte(tag)) {
		s = "<" + tag + ">"
	} else {
		s = fmt.Sprintf("<%s></%s>", tag, tag)
	}
	fragments, err := html.ParseFragment(strings.NewReader(s), BodyContext)
	if err != nil {
		return nil
	}
	return fragments[0]
}

func Replace(original, repl *html.Node) {
	if original.Parent == nil {
		panic("replacing not possible: parent is nil")
	}
	if original == repl {
		return
	}
	original.Parent.InsertBefore(repl, original)
	original.Parent.RemoveChild(original)
}

// BodyContext can be used as the context when parsing fragments.
var BodyContext *html.Node

func init() {
	doc, _ := html.Parse(strings.NewReader(`<html><body></body></html>`))
	BodyContext = FindOne(doc, atom.Body)
}
<|endoftext|>