<commit_before>package gitlab

import (
	"fmt"
	"net/url"
)

// GroupBadge represents a group badge.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html
type GroupBadge struct {
	ID               int    `json:"id"`
	LinkURL          string `json:"link_url"`
	ImageURL         string `json:"image_url"`
	RenderedLinkURL  string `json:"rendered_link_url"`
	RenderedImageURL string `json:"rendered_image_url"`
	// Kind represents a project badge kind. Can be empty, when used PreviewProjectBadge().
	Kind string `json:"kind"`
}

// GroupBadgesService handles communication with the group badges
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html
type GroupBadgesService struct {
	client *Client
}

// ListGroupBadgesOptions represents the available ListGroupBadges() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group
type ListGroupBadgesOptions ListOptions

// ListGroupBadges gets a list of a group badges.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group
func (s *GroupBadgesService) ListGroupBadges(gid interface{}, opt *ListGroupBadgesOptions, options ...OptionFunc) ([]*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges", url.QueryEscape(group))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var gb []*GroupBadge
	resp, err := s.client.Do(req, &gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// GetGroupBadge gets a group badge.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#get-a-badge-of-a-group
func (s *GroupBadgesService) GetGroupBadge(gid interface{}, badge int, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges/%d", url.QueryEscape(group), badge)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// AddGroupBadgeOptions represents the available AddGroupBadge() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group
type AddGroupBadgeOptions struct {
	LinkURL  *string `url:"link_url,omitempty" json:"link_url,omitempty"`
	ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
}

// AddGroupBadge adds a badge to a group.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group
func (s *GroupBadgesService) AddGroupBadge(gid interface{}, opt *AddGroupBadgeOptions, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges", url.QueryEscape(group))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// EditGroupBadgeOptions represents the available EditGroupBadge() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group
type EditGroupBadgeOptions struct {
	LinkURL  *string `url:"link_url,omitempty" json:"link_url,omitempty"`
	ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
}

// EditGroupBadge updates a badge of a group.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group
func (s *GroupBadgesService) EditGroupBadge(gid interface{}, badge int, opt *EditGroupBadgeOptions, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges/%d", url.QueryEscape(group), badge)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// DeleteGroupBadge removes a badge from a group.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#remove-a-badge-from-a-group
func (s *GroupBadgesService) DeleteGroupBadge(gid interface{}, badge int, options ...OptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("group/%s/badges/%d", url.QueryEscape(group), badge)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}

// GroupBadgePreviewOptions represents the available PreviewGroupBadge() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group
type GroupBadgePreviewOptions struct {
	LinkURL  *string `url:"link_url,omitempty" json:"link_url,omitempty"`
	ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
}

// PreviewGroupBadge returns how the link_url and image_url final URLs would be after
// resolving the placeholder interpolation.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group
func (s *GroupBadgesService) PreviewGroupBadge(gid interface{}, opt *GroupBadgePreviewOptions, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges/render", url.QueryEscape(group))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, &gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}
<commit_msg>introduced type for badge kind + some code clean up<commit_after>package gitlab

import (
	"fmt"
	"net/url"
)

// GroupBadgesService handles communication with the group badges
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html
type GroupBadgesService struct {
	client *Client
}

// BadgeKind represents a GitLab Badge Kind
type BadgeKind string

// all possible values Badge Kind
const (
	ProjectBadgeKind BadgeKind = "project"
	GroupBadgeKind BadgeKind = "group"
)

// GroupBadge represents a group badge.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html
type GroupBadge struct {
	ID               int    `json:"id"`
	LinkURL          string `json:"link_url"`
	ImageURL         string `json:"image_url"`
	RenderedLinkURL  string `json:"rendered_link_url"`
	RenderedImageURL string `json:"rendered_image_url"`
	Kind BadgeKind `json:"kind"`
}

// ListGroupBadgesOptions represents the available ListGroupBadges() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group
type ListGroupBadgesOptions ListOptions

// ListGroupBadges gets a list of a group badges.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#list-all-badges-of-a-group
func (s *GroupBadgesService) ListGroupBadges(gid interface{}, opt *ListGroupBadgesOptions, options ...OptionFunc) ([]*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges", url.QueryEscape(group))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var gb []*GroupBadge
	resp, err := s.client.Do(req, &gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// GetGroupBadge gets a group badge.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#get-a-badge-of-a-group
func (s *GroupBadgesService) GetGroupBadge(gid interface{}, badge int, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges/%d", url.QueryEscape(group), badge)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// AddGroupBadgeOptions represents the available AddGroupBadge() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group
type AddGroupBadgeOptions struct {
	LinkURL  *string `url:"link_url,omitempty" json:"link_url,omitempty"`
	ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
}

// AddGroupBadge adds a badge to a group.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#add-a-badge-to-a-group
func (s *GroupBadgesService) AddGroupBadge(gid interface{}, opt *AddGroupBadgeOptions, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges", url.QueryEscape(group))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// EditGroupBadgeOptions represents the available EditGroupBadge() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group
type EditGroupBadgeOptions struct {
	LinkURL  *string `url:"link_url,omitempty" json:"link_url,omitempty"`
	ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
}

// EditGroupBadge updates a badge of a group.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#edit-a-badge-of-a-group
func (s *GroupBadgesService) EditGroupBadge(gid interface{}, badge int, opt *EditGroupBadgeOptions, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges/%d", url.QueryEscape(group), badge)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}

// DeleteGroupBadge removes a badge from a group.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#remove-a-badge-from-a-group
func (s *GroupBadgesService) DeleteGroupBadge(gid interface{}, badge int, options ...OptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/badges/%d", url.QueryEscape(group), badge)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}

// GroupBadgePreviewOptions represents the available PreviewGroupBadge() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group
type GroupBadgePreviewOptions struct {
	LinkURL  *string `url:"link_url,omitempty" json:"link_url,omitempty"`
	ImageURL *string `url:"image_url,omitempty" json:"image_url,omitempty"`
}

// PreviewGroupBadge returns how the link_url and image_url final URLs would be after
// resolving the placeholder interpolation.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/group_badges.html#preview-a-badge-from-a-group
func (s *GroupBadgesService) PreviewGroupBadge(gid interface{}, opt *GroupBadgePreviewOptions, options ...OptionFunc) (*GroupBadge, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/badges/render", url.QueryEscape(group))

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gb := new(GroupBadge)
	resp, err := s.client.Do(req, &gb)
	if err != nil {
		return nil, resp, err
	}

	return gb, resp, err
}
<|endoftext|>


<commit_before>package gumble

import (
	"github.com/bontibon/gopus"
)

type AudioFlag int

const (
	AudioSource AudioFlag = 1 << iota // An audio stream that creates outgoing audio
	AudioSink                         // An audio stream that processes incoming audio
)

const (
	SampleRate = 48000
)

type AudioStream interface {
	OnAttach() error
	OnAttachSource(chan<- AudioPacket) error
	OnAttachSink() (chan<- AudioPacket, error)
	OnDetach()
}

type Audio struct {
	client   *Client
	stream   AudioStream
	flags    AudioFlag
	outgoing chan AudioPacket
	incoming chan<- AudioPacket
}

func (a *Audio) Detach() {
	if a.client.audio != a {
		return
	}
	a.client.audio = nil
	a.stream.OnDetach()
	if a.IsSource() {
		close(a.outgoing)
	}
}

func (a *Audio) IsSource() bool {
	return (a.flags & AudioSource) != 0
}

func (a *Audio) IsSink() bool {
	return (a.flags & AudioSink) != 0
}

func (a *Audio) outgoingRoutine() {
	message := audioMessage{
		Format: audioOpus,
		Target: audioNormal,
	}
	encoder, _ := gopus.NewEncoder(SampleRate, 1, gopus.Voip)
	encoder.SetVbr(false)
	encoder.SetBitrate(40000)
	for {
		if buf, ok := <-a.outgoing; !ok {
			return
		} else {
			if opusBuf, err := encoder.Encode(buf.Pcm, SampleRate/100, 1024); err == nil {
				message.sequence = (message.sequence + 1) % 10000
				message.opus = opusBuf
				a.client.Send(&message)
			}
		}
	}
}

type AudioPacket struct {
	Sender   *User
	Sequence int
	Pcm      []int16
}
<commit_msg>change ordering in audio.go<commit_after>package gumble

import (
	"github.com/bontibon/gopus"
)

type AudioFlag int

const (
	AudioSource AudioFlag = 1 << iota // An audio stream that creates outgoing audio
	AudioSink                         // An audio stream that processes incoming audio
)

const (
	SampleRate = 48000
)

type AudioPacket struct {
	Sender   *User
	Sequence int
	Pcm      []int16
}

type AudioStream interface {
	OnAttach() error
	OnAttachSource(chan<- AudioPacket) error
	OnAttachSink() (chan<- AudioPacket, error)
	OnDetach()
}

type Audio struct {
	client   *Client
	stream   AudioStream
	flags    AudioFlag
	outgoing chan AudioPacket
	incoming chan<- AudioPacket
}

func (a *Audio) Detach() {
	if a.client.audio != a {
		return
	}
	a.client.audio = nil
	a.stream.OnDetach()
	if a.IsSource() {
		close(a.outgoing)
	}
}

func (a *Audio) IsSource() bool {
	return (a.flags & AudioSource) != 0
}

func (a *Audio) IsSink() bool {
	return (a.flags & AudioSink) != 0
}

func (a *Audio) outgoingRoutine() {
	message := audioMessage{
		Format: audioOpus,
		Target: audioNormal,
	}
	encoder, _ := gopus.NewEncoder(SampleRate, 1, gopus.Voip)
	encoder.SetVbr(false)
	encoder.SetBitrate(40000)
	for {
		if buf, ok := <-a.outgoing; !ok {
			return
		} else {
			if opusBuf, err := encoder.Encode(buf.Pcm, SampleRate/100, 1024); err == nil {
				message.sequence = (message.sequence + 1) % 10000
				message.opus = opusBuf
				a.client.Send(&message)
			}
		}
	}
}
<|endoftext|>


<commit_before>package infuse_test

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

	"github.com/sclevine/infuse"
)

func buildHandler(name string, nexts int) func(http.ResponseWriter, *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		fmt.Fprintf(response, "start %s\n", name)

		for i := 0; i < nexts; i++ {
			fmt.Fprintf(response, "attempting next for %s\n", name)
			if infuse.Next(response, request) {
				fmt.Fprintf(response, "finished next for %s\n", name)
			} else {
				fmt.Fprintf(response, "no next for %s\n", name)
			}
		}

		fmt.Fprintf(response, "end %s\n", name)
	}
}

func panicHandler(response http.ResponseWriter, _ *http.Request) {
	if infuse.Get(response) != nil {
		fmt.Fprintf(response, "already panicked\n")
	} else {
		fmt.Fprintf(response, "panicking\n")
		infuse.Set(response, true)
		panic("some error")
	}
}

func recoverHandler(response http.ResponseWriter, request *http.Request) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprint(response, "recovered and attempting next\n")
			infuse.Next(response, request)
			fmt.Fprint(response, "finished next after recovery\n")
		}
	}()
	fmt.Fprint(response, "start recoverable\n")
	infuse.Next(response, request)
	fmt.Fprint(response, "end recoverable\n")
}

func createMapHandler(response http.ResponseWriter, request *http.Request) {
	infuse.Set(response, make(map[string]string))
	infuse.Next(response, request)
}

func buildOutputMapHandler(key string) func(http.ResponseWriter, *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		shared := infuse.Get(response).(map[string]string)
		fmt.Fprintf(response, "%s: %s\n", key, shared[key])
		infuse.Next(response, request)
	}
}

func buildSetMapHandler(key, value string) func(http.ResponseWriter, *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		shared := infuse.Get(response).(map[string]string)
		shared[key] = value
		infuse.Next(response, request)
	}
}

func serve(t *testing.T, handler infuse.Handler) string {
	request, err := http.NewRequest("GET", "http://example.com", nil)
	if err != nil {
		t.Fatalf("Failed to generate request: %s", err)
	}
	response := httptest.NewRecorder()
	handler.ServeHTTP(response, request)
	return response.Body.String()
}

func testHandlerResponse(t *testing.T, handler infuse.Handler, fixture string) {
	if body := serve(t, handler); body != fixture {
		t.Fatalf("Expected:\n%s\nGot:\n%s\n", fixture, body)
	}
}

func TestNew(t *testing.T) {
	testHandlerResponse(t, infuse.New(), "")
}

func TestHandler(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("first", 1))
	handler = handler.HandleFunc(buildHandler("second", 1))
	handler = handler.HandleFunc(buildHandler("third", 1))
	testHandlerResponse(t, handler, threeHandlerFixture)
}

func TestNestedHandlers(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("third", 1))
	handler = infuse.New().HandleFunc(buildHandler("second", 1)).Handle(handler)
	handler = infuse.New().HandleFunc(buildHandler("first", 1)).Handle(handler)
	testHandlerResponse(t, handler, threeHandlerFixture)
}

func TestComplexNestedHandlers(t *testing.T) {
	firstGroup := infuse.New().HandleFunc(buildHandler("first-first", 1))
	firstGroup = firstGroup.HandleFunc(buildHandler("first-second", 1))

	secondGroup := infuse.New().HandleFunc(buildHandler("second-first", 1))
	secondGroup = secondGroup.HandleFunc(buildHandler("second-second", 1))

	handler := firstGroup.Handle(secondGroup)
	testHandlerResponse(t, handler, complexHandlerFixture)
}

func TestBranchedHandlers(t *testing.T) {
	base := infuse.New().HandleFunc(buildHandler("base", 1))
	first := base.HandleFunc(buildHandler("first", 1))
	second := base.HandleFunc(buildHandler("second", 1))
	handler := first.Handle(second)
	testHandlerResponse(t, handler, branchedHandlerFixture)
}

func TestMultipleNextCalls(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("first", 2))
	handler = handler.HandleFunc(buildHandler("second", 3))
	testHandlerResponse(t, handler, multipleCallHandlerFixture)
}

func TestStackedHandlers(t *testing.T) {
	firstGroup := infuse.New().StackFunc(buildHandler("first stacked", 0))
	firstGroup = firstGroup.StackFunc(buildHandler("second stacked", 0))

	secondGroup := infuse.New().StackFunc(buildHandler("third stacked", 0))
	secondGroup = secondGroup.HandleFunc(buildHandler("fourth handled", 1))
	secondGroup = secondGroup.StackFunc(buildHandler("fifth stacked", 0))

	handler := firstGroup.Stack(secondGroup)
	testHandlerResponse(t, handler, stackedHandlerFixture)
}

func TestGetAndSet(t *testing.T) {
	handler := infuse.New().HandleFunc(createMapHandler)
	handler = handler.HandleFunc(buildSetMapHandler("first key", "first value"))
	handler = handler.HandleFunc(buildSetMapHandler("second key", "second value"))
	handler = handler.HandleFunc(buildSetMapHandler("first key", "new first value"))
	handler = handler.HandleFunc(buildOutputMapHandler("first key"))
	handler = handler.HandleFunc(buildOutputMapHandler("second key"))
	testHandlerResponse(t, handler, "first key: new first value\nsecond key: second value\n")
}

func TestGetAndSetForNestedHandlers(t *testing.T) {
	firstGroup := infuse.New().HandleFunc(createMapHandler)
	firstGroup = firstGroup.HandleFunc(buildSetMapHandler("key", "first value"))

	secondGroup := infuse.New().HandleFunc(createMapHandler)
	secondGroup = secondGroup.HandleFunc(buildSetMapHandler("key", "second value"))
	secondGroup = secondGroup.HandleFunc(buildOutputMapHandler("key"))

	handler := firstGroup.Stack(secondGroup)
	handler = handler.HandleFunc(buildOutputMapHandler("key"))

	testHandlerResponse(t, handler, "key: second value\nkey: first value\n")
}

func TestPanicRecovery(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("first", 1))
	handler = handler.HandleFunc(recoverHandler)
	handler = handler.HandleFunc(buildHandler("second", 1))
	handler = handler.HandleFunc(buildHandler("third", 1))
	handler = handler.HandleFunc(panicHandler)
	testHandlerResponse(t, handler, panicRecoveryHandlerFixture)
}

func TestInvalidResponse(t *testing.T) {
	if context := infuse.Get(nil); context != nil {
		t.Fatalf("Expected nil context from invalid response, got %s.", context)
	}
	if ok := infuse.Set(nil, "value"); ok {
		t.Fatal("Expected failure to set context on invalid response.")
	}
	if ok := infuse.Next(nil, &http.Request{}); ok {
		t.Fatal("Expected failure to serve next handler with invalid response.")
	}
}
<commit_msg>Minor test refactorings<commit_after>package infuse_test

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

	"github.com/sclevine/infuse"
)

func buildHandler(name string, nexts int) func(http.ResponseWriter, *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		fmt.Fprintf(response, "start %s\n", name)

		for i := 0; i < nexts; i++ {
			fmt.Fprintf(response, "attempting next for %s\n", name)
			if infuse.Next(response, request) {
				fmt.Fprintf(response, "finished next for %s\n", name)
			} else {
				fmt.Fprintf(response, "no next for %s\n", name)
			}
		}

		fmt.Fprintf(response, "end %s\n", name)
	}
}

func panicHandler(response http.ResponseWriter, _ *http.Request) {
	if infuse.Get(response) != nil {
		fmt.Fprintf(response, "already panicked\n")
	} else {
		fmt.Fprintf(response, "panicking\n")
		infuse.Set(response, true)
		panic("some error")
	}
}

func recoverHandler(response http.ResponseWriter, request *http.Request) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintln(response, "recovered and attempting next")
			infuse.Next(response, request)
			fmt.Fprintln(response, "finished next after recovery")
		}
	}()
	fmt.Fprintln(response, "start recoverable")
	infuse.Next(response, request)
	fmt.Fprintln(response, "end recoverable")
}

func createMapHandler(response http.ResponseWriter, request *http.Request) {
	infuse.Set(response, make(map[string]string))
	infuse.Next(response, request)
}

func buildOutputMapHandler(key string) func(http.ResponseWriter, *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		shared := infuse.Get(response).(map[string]string)
		fmt.Fprintf(response, "%s: %s\n", key, shared[key])
		infuse.Next(response, request)
	}
}

func buildSetMapHandler(key, value string) func(http.ResponseWriter, *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		shared := infuse.Get(response).(map[string]string)
		shared[key] = value
		infuse.Next(response, request)
	}
}

func serve(t *testing.T, handler infuse.Handler) string {
	response := httptest.NewRecorder()
	handler.ServeHTTP(response, &http.Request{})
	return response.Body.String()
}

func testHandlerResponse(t *testing.T, handler infuse.Handler, fixture string) {
	if body := serve(t, handler); body != fixture {
		t.Fatalf("Expected:\n%s\nGot:\n%s\n", fixture, body)
	}
}

func TestNew(t *testing.T) {
	testHandlerResponse(t, infuse.New(), "")
}

func TestHandler(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("first", 1))
	handler = handler.HandleFunc(buildHandler("second", 1))
	handler = handler.HandleFunc(buildHandler("third", 1))
	testHandlerResponse(t, handler, threeHandlerFixture)
}

func TestNestedHandlers(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("third", 1))
	handler = infuse.New().HandleFunc(buildHandler("second", 1)).Handle(handler)
	handler = infuse.New().HandleFunc(buildHandler("first", 1)).Handle(handler)
	testHandlerResponse(t, handler, threeHandlerFixture)
}

func TestComplexNestedHandlers(t *testing.T) {
	firstGroup := infuse.New().HandleFunc(buildHandler("first-first", 1))
	firstGroup = firstGroup.HandleFunc(buildHandler("first-second", 1))

	secondGroup := infuse.New().HandleFunc(buildHandler("second-first", 1))
	secondGroup = secondGroup.HandleFunc(buildHandler("second-second", 1))

	handler := firstGroup.Handle(secondGroup)
	testHandlerResponse(t, handler, complexHandlerFixture)
}

func TestBranchedHandlers(t *testing.T) {
	base := infuse.New().HandleFunc(buildHandler("base", 1))
	first := base.HandleFunc(buildHandler("first", 1))
	second := base.HandleFunc(buildHandler("second", 1))
	handler := first.Handle(second)
	testHandlerResponse(t, handler, branchedHandlerFixture)
}

func TestMultipleNextCalls(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("first", 2))
	handler = handler.HandleFunc(buildHandler("second", 3))
	testHandlerResponse(t, handler, multipleCallHandlerFixture)
}

func TestStackedHandlers(t *testing.T) {
	firstGroup := infuse.New().StackFunc(buildHandler("first stacked", 0))
	firstGroup = firstGroup.StackFunc(buildHandler("second stacked", 0))

	secondGroup := infuse.New().StackFunc(buildHandler("third stacked", 0))
	secondGroup = secondGroup.HandleFunc(buildHandler("fourth handled", 1))
	secondGroup = secondGroup.StackFunc(buildHandler("fifth stacked", 0))

	handler := firstGroup.Stack(secondGroup)
	testHandlerResponse(t, handler, stackedHandlerFixture)
}

func TestGetAndSet(t *testing.T) {
	handler := infuse.New().HandleFunc(createMapHandler)
	handler = handler.HandleFunc(buildSetMapHandler("first key", "first value"))
	handler = handler.HandleFunc(buildSetMapHandler("second key", "second value"))
	handler = handler.HandleFunc(buildSetMapHandler("first key", "new first value"))
	handler = handler.HandleFunc(buildOutputMapHandler("first key"))
	handler = handler.HandleFunc(buildOutputMapHandler("second key"))
	testHandlerResponse(t, handler, "first key: new first value\nsecond key: second value\n")
}

func TestGetAndSetForNestedHandlers(t *testing.T) {
	firstGroup := infuse.New().HandleFunc(createMapHandler)
	firstGroup = firstGroup.HandleFunc(buildSetMapHandler("key", "first value"))

	secondGroup := infuse.New().HandleFunc(createMapHandler)
	secondGroup = secondGroup.HandleFunc(buildSetMapHandler("key", "second value"))
	secondGroup = secondGroup.HandleFunc(buildOutputMapHandler("key"))

	handler := firstGroup.Stack(secondGroup)
	handler = handler.HandleFunc(buildOutputMapHandler("key"))

	testHandlerResponse(t, handler, "key: second value\nkey: first value\n")
}

func TestPanicRecovery(t *testing.T) {
	handler := infuse.New().HandleFunc(buildHandler("first", 1))
	handler = handler.HandleFunc(recoverHandler)
	handler = handler.HandleFunc(buildHandler("second", 1))
	handler = handler.HandleFunc(buildHandler("third", 1))
	handler = handler.HandleFunc(panicHandler)
	testHandlerResponse(t, handler, panicRecoveryHandlerFixture)
}

func TestInvalidResponse(t *testing.T) {
	if context := infuse.Get(nil); context != nil {
		t.Fatalf("Expected nil context from invalid response, got %s.", context)
	}
	if ok := infuse.Set(nil, "value"); ok {
		t.Fatal("Expected failure to set context on invalid response.")
	}
	if ok := infuse.Next(nil, &http.Request{}); ok {
		t.Fatal("Expected failure to serve next handler with invalid response.")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"testing"
)

var _ = Suite(&S{})

type S struct{}

func Test(t *testing.T) { TestingT(t) }

type InChecker struct{}

func (c *InChecker) Info() *CheckerInfo {
	return &CheckerInfo{Name: "In", Params: []string{"value", "list"}}
}

func (c *InChecker) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "you should provide two parameters"
	}
	value, ok := params[0].(string)
	if !ok {
		return false, "first parameter should be a string"
	}
	list, ok := params[1].([]string)
	if !ok {
		return false, "second parameter should be a slice"
	}
	for _, item := range list {
		if value == item {
			return true, ""
		}
	}
	return false, ""
}

var In Checker = &InChecker{}

func (s *S) TestAdd(c *C) {
	request, err := http.NewRequest("POST", "/resources/", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Add(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
}

func (s *S) TestBindShouldReturnsTheVariables(c *C) {
	request, err := http.NewRequest("POST", "/resources/someapp?:name=someapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Bind(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	result, err := ioutil.ReadAll(recorder.Body)
	c.Assert(err, IsNil)
	expected := map[string]string{
		"MONGO_URI":           "127.0.0.1:27017",
		"MONGO_USER":          "someapp",
		"MONGO_PASSWORD":      "",
		"MONGO_DATABASE_NAME": "someapp",
	}
	data := map[string]string{}
	json.Unmarshal(result, &data)
	c.Assert(data, DeepEquals, expected)
}

func (s *S) TestBindShouldCreateTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/someapp?:name=someapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Bind(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	databases, err := Session.DatabaseNames()
	c.Assert("someapp", In, databases)
}

func (s *S) TestBindShouldAddUserInTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/someapp?:name=someapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Bind(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	collection := Session.DB("someapp").C("system.users")
	lenght, err := collection.Find(bson.M{"user": "someapp"}).Count()
	c.Assert(lenght, Equals, 1)
}

func (s *S) TestUnbindShouldRemoveTheUser(c *C) {
	request, err := http.NewRequest("DELETE", "/resources/myapp/hostname/10.10.10.10?:name=myapp&hostname=10.10.10.10", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Unbind(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	collection := Session.DB("myapp").C("system.users")
	lenght, err := collection.Find(bson.M{"user": "myapp"}).Count()
	c.Assert(lenght, Equals, 0)
}

func (s *S) TestRemoveShouldRemovesTheDatabase(c *C) {
	request, err := http.NewRequest("DELETE", "/resources/name?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Remove(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	databases, err := Session.DatabaseNames()
	c.Assert("myapp", Not(In), databases)
}

func (s *S) TestStatus(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Bind(recorder, request)

	c.Assert(recorder.Code, Equals, http.StatusCreated)
	request, err = http.NewRequest("GET", "/resources/myapp/status?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder = httptest.NewRecorder()
	Status(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusNoContent)

	request, err = http.NewRequest("DELETE", "/resources/myapp/hostname/10.10.10.10?:name=myapp&hostname=10.10.10.10", nil)
	c.Assert(err, IsNil)
	recorder = httptest.NewRecorder()
	Unbind(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusOK)
}

func (s *S) TestStatusShouldReturns500WhenMongoIsNotUp(c *C) {
	request, err := http.NewRequest("GET", "/resources/myapp/status?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Status(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusInternalServerError)
}
<commit_msg>making the tests are atomic<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"testing"
)

var _ = Suite(&S{})

type S struct{}

func Test(t *testing.T) { TestingT(t) }

type InChecker struct{}

func (c *InChecker) Info() *CheckerInfo {
	return &CheckerInfo{Name: "In", Params: []string{"value", "list"}}
}

func (c *InChecker) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "you should provide two parameters"
	}
	value, ok := params[0].(string)
	if !ok {
		return false, "first parameter should be a string"
	}
	list, ok := params[1].([]string)
	if !ok {
		return false, "second parameter should be a slice"
	}
	for _, item := range list {
		if value == item {
			return true, ""
		}
	}
	return false, ""
}

var In Checker = &InChecker{}

func (s *S) TestAdd(c *C) {
	request, err := http.NewRequest("POST", "/resources/", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Add(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
}

func (s *S) TestBindShouldReturnsTheVariables(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Bind(recorder, request)
	defer func() {
		database := Session.DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	result, err := ioutil.ReadAll(recorder.Body)
	c.Assert(err, IsNil)
	expected := map[string]string{
		"MONGO_URI":           "127.0.0.1:27017",
		"MONGO_USER":          "myapp",
		"MONGO_PASSWORD":      "",
		"MONGO_DATABASE_NAME": "myapp",
	}
	data := map[string]string{}
	json.Unmarshal(result, &data)
	c.Assert(data, DeepEquals, expected)
}

func (s *S) TestBindShouldCreateTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Bind(recorder, request)
	defer func() {
		database := Session.DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	databases, err := Session.DatabaseNames()
	c.Assert("myapp", In, databases)
}

func (s *S) TestBindShouldAddUserInTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Bind(recorder, request)
	defer func() {
		database := Session.DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	collection := Session.DB("myapp").C("system.users")
	lenght, err := collection.Find(bson.M{"user": "myapp"}).Count()
	c.Assert(lenght, Equals, 1)
}

func (s *S) TestUnbindShouldRemoveTheUser(c *C) {
	name := "myapp"
	database := Session.DB(name)
	database.AddUser(name, "", false)
	defer func() {
		database.DropDatabase()
	}()
	request, err := http.NewRequest("DELETE", "/resources/myapp/hostname/10.10.10.10?:name=myapp&hostname=10.10.10.10", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Unbind(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	collection := Session.DB(name).C("system.users")
	lenght, err := collection.Find(bson.M{"user": name}).Count()
	c.Assert(lenght, Equals, 0)
}

func (s *S) TestRemoveShouldRemovesTheDatabase(c *C) {
	name := "myapp"
	database := Session.DB(name)
	database.AddUser(name, "", false)
	request, err := http.NewRequest("DELETE", "/resources/name?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Remove(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	databases, err := Session.DatabaseNames()
	c.Assert(name, Not(In), databases)
}

func (s *S) TestStatus(c *C) {
	name := "myapp"
	database := Session.DB(name)
	database.AddUser(name, "", false)
	defer func() {
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	request, err := http.NewRequest("GET", "/resources/myapp/status?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Status(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusNoContent)
}

func (s *S) TestStatusShouldReturns500WhenMongoIsNotUp(c *C) {
	request, err := http.NewRequest("GET", "/resources/myapp/status?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Status(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusInternalServerError)
}
<|endoftext|>


<commit_before>package assert

import (
	"fmt"
	"reflect"
)

const(
	greater = 1
	equal = 0
	less = -1
)

func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
	switch kind {
	case reflect.Int:
		{
			intobj1 := obj1.(int)
			intobj2 := obj2.(int)
			if intobj1 > intobj2 {
				return greater, true
			}
			if intobj1 == intobj2 {
				return equal, true
			}
			if intobj1 < intobj2 {
				return less, true
			}
		}
	case reflect.Int8:
		{
			int8obj1 := obj1.(int8)
			int8obj2 := obj2.(int8)
			if int8obj1 > int8obj2 {
				return greater, true
			}
			if int8obj1 == int8obj2 {
				return equal, true
			}
			if int8obj1 < int8obj2 {
				return less, true
			}
		}
	case reflect.Int16:
		{
			int16obj1 := obj1.(int16)
			int16obj2 := obj2.(int16)
			if int16obj1 > int16obj2 {
				return greater, true
			}
			if int16obj1 == int16obj2 {
				return equal, true
			}
			if int16obj1 < int16obj2 {
				return less, true
			}
		}
	case reflect.Int32:
		{
			int32obj1 := obj1.(int32)
			int32obj2 := obj2.(int32)
			if int32obj1 > int32obj2 {
				return greater, true
			}
			if int32obj1 == int32obj2 {
				return equal, true
			}
			if int32obj1 < int32obj2 {
				return less, true
			}
		}
	case reflect.Int64:
		{
			int64obj1 := obj1.(int64)
			int64obj2 := obj2.(int64)
			if int64obj1 > int64obj2 {
				return greater, true
			}
			if int64obj1 == int64obj2 {
				return equal, true
			}
			if int64obj1 < int64obj2 {
				return less, true
			}
		}
	case reflect.Uint:
		{
			uintobj1 := obj1.(uint)
			uintobj2 := obj2.(uint)
			if uintobj1 > uintobj2 {
				return greater, true
			}
			if uintobj1 == uintobj2 {
				return equal, true
			}
			if uintobj1 < uintobj2 {
				return less, true
			}
		}
	case reflect.Uint8:
		{
			uint8obj1 := obj1.(uint8)
			uint8obj2 := obj2.(uint8)
			if uint8obj1 > uint8obj2 {
				return greater, true
			}
			if uint8obj1 == uint8obj2 {
				return equal, true
			}
			if uint8obj1 < uint8obj2 {
				return less, true
			}
		}
	case reflect.Uint16:
		{
			uint16obj1 := obj1.(uint16)
			uint16obj2 := obj2.(uint16)
			if uint16obj1 > uint16obj2 {
				return greater, true
			}
			if uint16obj1 == uint16obj2 {
				return equal, true
			}
			if uint16obj1 < uint16obj2 {
				return less, true
			}
		}
	case reflect.Uint32:
		{
			uint32obj1 := obj1.(uint32)
			uint32obj2 := obj2.(uint32)
			if uint32obj1 > uint32obj2 {
				return greater, true
			}
			if uint32obj1 == uint32obj2 {
				return equal, true
			}
			if uint32obj1 < uint32obj2 {
				return less, true
			}
		}
	case reflect.Uint64:
		{
			uint64obj1 := obj1.(uint64)
			uint64obj2 := obj2.(uint64)
			if uint64obj1 > uint64obj2 {
				return greater, true
			}
			if uint64obj1 == uint64obj2 {
				return equal, true
			}
			if uint64obj1 < uint64obj2 {
				return less, true
			}
		}
	case reflect.Float32:
		{
			float32obj1 := obj1.(float32)
			float32obj2 := obj2.(float32)
			if float32obj1 > float32obj2 {
				return greater, true
			}
			if float32obj1 == float32obj2 {
				return equal, true
			}
			if float32obj1 < float32obj2 {
				return less, true
			}
		}
	case reflect.Float64:
		{
			float64obj1 := obj1.(float64)
			float64obj2 := obj2.(float64)
			if float64obj1 > float64obj2 {
				return greater, true
			}
			if float64obj1 == float64obj2 {
				return equal, true
			}
			if float64obj1 < float64obj2 {
				return less, true
			}
		}
	case reflect.String:
		{
			stringobj1 := obj1.(string)
			stringobj2 := obj2.(string)
			if stringobj1 > stringobj2 {
				return greater, true
			}
			if stringobj1 == stringobj2 {
				return equal, true
			}
			if stringobj1 < stringobj2 {
				return less, true
			}
		}
	}

	return equal, false
}

// Greater asserts that the first element is greater than the second
//
//    assert.Greater(t, 2, 1)
//    assert.Greater(t, float64(2), float64(1))
//    assert.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int {greater}, "\"%s\" is not greater than \"%s\"", msgAndArgs);
}

// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
//    assert.GreaterOrEqual(t, 2, 1)
//    assert.GreaterOrEqual(t, 2, 2)
//    assert.GreaterOrEqual(t, "b", "a")
//    assert.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int {greater, equal}, "\"%s\" is not greater or equal than \"%s\"", msgAndArgs);
}

// Less asserts that the first element is less than the second
//
//    assert.Less(t, 1, 2)
//    assert.Less(t, float64(1), float64(2))
//    assert.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int {less}, "\"%s\" is not less than \"%s\"", msgAndArgs);
}

// LessOrEqual asserts that the first element is less than or equal to the second
//
//    assert.LessOrEqual(t, 1, 2)
//    assert.LessOrEqual(t, 2, 2)
//    assert.LessOrEqual(t, "a", "b")
//    assert.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int {less, equal}, "\"%s\" is not less or equal than \"%s\"", msgAndArgs);
}

func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []int, failMessage string, msgAndArgs ...interface{}) bool {
	if h, ok := t.(tHelper); ok {
		h.Helper()
	}

	e1Kind := reflect.ValueOf(e1).Kind()
	e2Kind := reflect.ValueOf(e2).Kind()
	if e1Kind != e2Kind {
		return Fail(t, "Elements should be the same type", msgAndArgs...)
	}

	compareResult, isComparable := compare(e1, e2, e1Kind)
	if !isComparable {
		return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
	}

	if !containsValue(allowedComparesResults, compareResult) {
		return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...)
	}

	return true
}

func containsValue(values []int, value int) bool{
    for _, v := range values {
        if (v == value) {
            return true
        }
    }

    return false
}<commit_msg>fix with gofmt tool<commit_after>package assert

import (
	"fmt"
	"reflect"
)

const (
	greater = 1
	equal   = 0
	less    = -1
)

func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
	switch kind {
	case reflect.Int:
		{
			intobj1 := obj1.(int)
			intobj2 := obj2.(int)
			if intobj1 > intobj2 {
				return greater, true
			}
			if intobj1 == intobj2 {
				return equal, true
			}
			if intobj1 < intobj2 {
				return less, true
			}
		}
	case reflect.Int8:
		{
			int8obj1 := obj1.(int8)
			int8obj2 := obj2.(int8)
			if int8obj1 > int8obj2 {
				return greater, true
			}
			if int8obj1 == int8obj2 {
				return equal, true
			}
			if int8obj1 < int8obj2 {
				return less, true
			}
		}
	case reflect.Int16:
		{
			int16obj1 := obj1.(int16)
			int16obj2 := obj2.(int16)
			if int16obj1 > int16obj2 {
				return greater, true
			}
			if int16obj1 == int16obj2 {
				return equal, true
			}
			if int16obj1 < int16obj2 {
				return less, true
			}
		}
	case reflect.Int32:
		{
			int32obj1 := obj1.(int32)
			int32obj2 := obj2.(int32)
			if int32obj1 > int32obj2 {
				return greater, true
			}
			if int32obj1 == int32obj2 {
				return equal, true
			}
			if int32obj1 < int32obj2 {
				return less, true
			}
		}
	case reflect.Int64:
		{
			int64obj1 := obj1.(int64)
			int64obj2 := obj2.(int64)
			if int64obj1 > int64obj2 {
				return greater, true
			}
			if int64obj1 == int64obj2 {
				return equal, true
			}
			if int64obj1 < int64obj2 {
				return less, true
			}
		}
	case reflect.Uint:
		{
			uintobj1 := obj1.(uint)
			uintobj2 := obj2.(uint)
			if uintobj1 > uintobj2 {
				return greater, true
			}
			if uintobj1 == uintobj2 {
				return equal, true
			}
			if uintobj1 < uintobj2 {
				return less, true
			}
		}
	case reflect.Uint8:
		{
			uint8obj1 := obj1.(uint8)
			uint8obj2 := obj2.(uint8)
			if uint8obj1 > uint8obj2 {
				return greater, true
			}
			if uint8obj1 == uint8obj2 {
				return equal, true
			}
			if uint8obj1 < uint8obj2 {
				return less, true
			}
		}
	case reflect.Uint16:
		{
			uint16obj1 := obj1.(uint16)
			uint16obj2 := obj2.(uint16)
			if uint16obj1 > uint16obj2 {
				return greater, true
			}
			if uint16obj1 == uint16obj2 {
				return equal, true
			}
			if uint16obj1 < uint16obj2 {
				return less, true
			}
		}
	case reflect.Uint32:
		{
			uint32obj1 := obj1.(uint32)
			uint32obj2 := obj2.(uint32)
			if uint32obj1 > uint32obj2 {
				return greater, true
			}
			if uint32obj1 == uint32obj2 {
				return equal, true
			}
			if uint32obj1 < uint32obj2 {
				return less, true
			}
		}
	case reflect.Uint64:
		{
			uint64obj1 := obj1.(uint64)
			uint64obj2 := obj2.(uint64)
			if uint64obj1 > uint64obj2 {
				return greater, true
			}
			if uint64obj1 == uint64obj2 {
				return equal, true
			}
			if uint64obj1 < uint64obj2 {
				return less, true
			}
		}
	case reflect.Float32:
		{
			float32obj1 := obj1.(float32)
			float32obj2 := obj2.(float32)
			if float32obj1 > float32obj2 {
				return greater, true
			}
			if float32obj1 == float32obj2 {
				return equal, true
			}
			if float32obj1 < float32obj2 {
				return less, true
			}
		}
	case reflect.Float64:
		{
			float64obj1 := obj1.(float64)
			float64obj2 := obj2.(float64)
			if float64obj1 > float64obj2 {
				return greater, true
			}
			if float64obj1 == float64obj2 {
				return equal, true
			}
			if float64obj1 < float64obj2 {
				return less, true
			}
		}
	case reflect.String:
		{
			stringobj1 := obj1.(string)
			stringobj2 := obj2.(string)
			if stringobj1 > stringobj2 {
				return greater, true
			}
			if stringobj1 == stringobj2 {
				return equal, true
			}
			if stringobj1 < stringobj2 {
				return less, true
			}
		}
	}

	return equal, false
}

// Greater asserts that the first element is greater than the second
//
//    assert.Greater(t, 2, 1)
//    assert.Greater(t, float64(2), float64(1))
//    assert.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int{greater}, "\"%s\" is not greater than \"%s\"", msgAndArgs)
}

// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
//    assert.GreaterOrEqual(t, 2, 1)
//    assert.GreaterOrEqual(t, 2, 2)
//    assert.GreaterOrEqual(t, "b", "a")
//    assert.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int{greater, equal}, "\"%s\" is not greater or equal than \"%s\"", msgAndArgs)
}

// Less asserts that the first element is less than the second
//
//    assert.Less(t, 1, 2)
//    assert.Less(t, float64(1), float64(2))
//    assert.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int{less}, "\"%s\" is not less than \"%s\"", msgAndArgs)
}

// LessOrEqual asserts that the first element is less than or equal to the second
//
//    assert.LessOrEqual(t, 1, 2)
//    assert.LessOrEqual(t, 2, 2)
//    assert.LessOrEqual(t, "a", "b")
//    assert.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
	return compareTwoValues(t, e1, e2, []int{less, equal}, "\"%s\" is not less or equal than \"%s\"", msgAndArgs)
}

func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []int, failMessage string, msgAndArgs ...interface{}) bool {
	if h, ok := t.(tHelper); ok {
		h.Helper()
	}

	e1Kind := reflect.ValueOf(e1).Kind()
	e2Kind := reflect.ValueOf(e2).Kind()
	if e1Kind != e2Kind {
		return Fail(t, "Elements should be the same type", msgAndArgs...)
	}

	compareResult, isComparable := compare(e1, e2, e1Kind)
	if !isComparable {
		return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
	}

	if !containsValue(allowedComparesResults, compareResult) {
		return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...)
	}

	return true
}

func containsValue(values []int, value int) bool {
	for _, v := range values {
		if v == value {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package overcurrent

import (
	"context"
	"fmt"
	"math/rand"
	"time"

	"github.com/efritz/backoff"
	"github.com/efritz/glock"
)

type (
	// CircuitBreaker protects the invocation of a function and monitors failures.
	// After a certain failure threshold is reached, future invocations will instead
	// return an ErrErrCircuitOpen instead of attempting to invoke the function again.
	CircuitBreaker interface {
		// Trip manually trips the circuit breaker. The circuit breaker will remain open
		// until it is manually reset.
		Trip()

		// Reset the circuit breaker.
		Reset()

		// ShouldTry returns true if the circuit breaker is closed or half-closed with
		// some probability. Successive calls to this method may yield different results
		// depending on the registered trip condition.
		ShouldTry() bool

		// MarkResult takes the result of the protected section and marks it as a success if
		// the error is nil or if the failure interpreter decides not to trip on this error.
		MarkResult(err error) bool

		// Call attempts to call the given function if the circuit breaker is closed, or if
		// the circuit breaker is half-closed (with some probability). Otherwise, return an
		// ErrCircuitOpen. If the function times out, the circuit breaker will fail with an
		// ErrInvocationTimeout. If the function is invoked and yields a value before the
		// timeout elapses, that value is returned.
		Call(f BreakerFunc) error

		// CallAsync invokes the given function in a goroutine, returning a channel which
		// may receive one non-nil error value and then close. The channel will close without
		// writing a value on success.
		CallAsync(f BreakerFunc) <-chan error
	}

	BreakerConfig func(*circuitBreaker)
	BreakerFunc   func(ctx context.Context) error

	circuitBreaker struct {
		invocationTimeout          time.Duration
		halfClosedRetryProbability float64
		resetBackoff               backoff.Backoff
		failureInterpreter         FailureInterpreter
		tripCondition              TripCondition
		collector                  MetricCollector
		clock                      glock.Clock
		state                      circuitState
		hardTrip                   bool
		lastFailureTime            *time.Time
		resetTimeout               *time.Duration
		maxConcurrency             int
		maxConcurrencyTimeout      time.Duration
	}

	circuitState int
)

const (
	openState       circuitState = iota // Failure state
	closedState                         // Success state
	halfClosedState                     // Cautious, probabilistic retry state
)

var (
	// ErrCircuitOpen occurs when the Call method fails immediately.
	ErrCircuitOpen = fmt.Errorf("circuit is open")

	// ErrInvocationTimeout occurs when the method takes too long to execute.
	ErrInvocationTimeout = fmt.Errorf("invocation has timed out")
)

// NewCircuitBreaker creates a new CircuitBreaker.
func NewCircuitBreaker(configs ...BreakerConfig) CircuitBreaker {
	return newCircuitBreaker(configs...)
}

func newCircuitBreaker(configs ...BreakerConfig) *circuitBreaker {
	breaker := &circuitBreaker{
		invocationTimeout:          100 * time.Millisecond,
		halfClosedRetryProbability: 0.5,
		resetBackoff:               backoff.NewConstantBackoff(1000 * time.Millisecond),
		failureInterpreter:         NewAnyErrorFailureInterpreter(),
		tripCondition:              NewConsecutiveFailureTripCondition(5),
		collector:                  defaultCollector,
		clock:                      glock.NewRealClock(),
		state:                      closedState,
		maxConcurrency:             100,
		maxConcurrencyTimeout:      time.Millisecond * 100,
	}

	for _, config := range configs {
		config(breaker)
	}

	return breaker
}

func WithInvocationTimeout(timeout time.Duration) BreakerConfig {
	return func(cb *circuitBreaker) { cb.invocationTimeout = timeout }
}

func WithHalfClosedRetryProbability(probability float64) BreakerConfig {
	return func(cb *circuitBreaker) { cb.halfClosedRetryProbability = probability }
}

func WithResetBackoff(resetBackoff backoff.Backoff) BreakerConfig {
	return func(cb *circuitBreaker) { cb.resetBackoff = resetBackoff }
}

func WithFailureInterpreter(failureInterpreter FailureInterpreter) BreakerConfig {
	return func(cb *circuitBreaker) { cb.failureInterpreter = failureInterpreter }
}

func WithTripCondition(tripCondition TripCondition) BreakerConfig {
	return func(cb *circuitBreaker) { cb.tripCondition = tripCondition }
}

func WithMaxConcurrency(maxConcurrency int) BreakerConfig {
	return func(cb *circuitBreaker) { cb.maxConcurrency = maxConcurrency }
}

func WithMaxConcurrencyTimeout(timeout time.Duration) BreakerConfig {
	return func(cb *circuitBreaker) { cb.maxConcurrencyTimeout = timeout }
}

func WithCollector(collector MetricCollector) BreakerConfig {
	return func(cb *circuitBreaker) { cb.collector = collector }
}

func withClock(clock glock.Clock) BreakerConfig {
	return func(cb *circuitBreaker) { cb.clock = clock }
}

//
// Breaker Implementation

func (cb *circuitBreaker) Trip() {
	cb.hardTrip = true
}

func (cb *circuitBreaker) Reset() {
	cb.hardTrip = false
	cb.resetTimeout = nil

	cb.resetBackoff.Reset()
	cb.tripCondition.Success()
}

func (cb *circuitBreaker) ShouldTry() bool {
	if cb.hardTrip {
		return false
	}

	if !cb.tripCondition.ShouldTrip() {
		cb.state = closedState
		return true
	}

	if cb.state == closedState {
		cb.resetBackoff.Reset()
	}

	if cb.state != openState {
		reset := cb.resetBackoff.NextInterval()
		cb.resetTimeout = &reset
	}

	if cb.resetTimeoutElapsed() {
		cb.state = halfClosedState
		return rand.Float64() < cb.halfClosedRetryProbability
	}

	cb.state = openState
	return false
}

func (cb *circuitBreaker) resetTimeoutElapsed() bool {
	if cb.state != openState {
		return false
	}

	if cb.lastFailureTime == nil || cb.resetTimeout == nil {
		return false
	}

	return cb.clock.Now().Sub(*cb.lastFailureTime) >= *cb.resetTimeout
}

func (cb *circuitBreaker) MarkResult(err error) bool {
	// TODO - test that this doesn't go to failure interpreter
	if err != nil && (err == ErrInvocationTimeout || cb.failureInterpreter.ShouldTrip(err)) {
		now := cb.clock.Now()
		cb.lastFailureTime = &now
		cb.tripCondition.Failure()
		return false
	}

	cb.Reset()
	return true
}

func (cb *circuitBreaker) Call(f BreakerFunc) error {
	cb.collector.Report(EventTypeAttempt)

	if !cb.ShouldTry() {
		cb.collector.Report(EventTypeShortCircuit)
		return ErrCircuitOpen
	}

	start := time.Now()
	err := callWithTimeout(f, cb.clock, cb.invocationTimeout)
	elapsed := time.Now().Sub(start)

	cb.collector.ReportDuration(EventTypeRunDuration, elapsed)

	if !cb.MarkResult(err) {
		if err == ErrInvocationTimeout {
			cb.collector.Report(EventTypeTimeout)
			return err
		}

		cb.collector.Report(EventTypeError)
		return err
	}

	return nil
}

func (cb *circuitBreaker) CallAsync(f BreakerFunc) <-chan error {
	return toErrChan(func() error { return cb.Call(f) })
}

func callWithTimeout(f BreakerFunc, clock glock.Clock, timeout time.Duration) error {
	if timeout == 0 {
		return f(context.Background())
	}

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

	ch := toErrChan(func() error {
		return f(ctx)
	})

	select {
	case err := <-ch:
		return err

	case <-clock.After(timeout):
		return ErrInvocationTimeout
	}
}
<commit_msg>Export CircuitState.<commit_after>package overcurrent

import (
	"context"
	"fmt"
	"math/rand"
	"time"

	"github.com/efritz/backoff"
	"github.com/efritz/glock"
)

type (
	// CircuitBreaker protects the invocation of a function and monitors failures.
	// After a certain failure threshold is reached, future invocations will instead
	// return an ErrErrCircuitOpen instead of attempting to invoke the function again.
	CircuitBreaker interface {
		// Trip manually trips the circuit breaker. The circuit breaker will remain open
		// until it is manually reset.
		Trip()

		// Reset the circuit breaker.
		Reset()

		// ShouldTry returns true if the circuit breaker is closed or half-closed with
		// some probability. Successive calls to this method may yield different results
		// depending on the registered trip condition.
		ShouldTry() bool

		// MarkResult takes the result of the protected section and marks it as a success if
		// the error is nil or if the failure interpreter decides not to trip on this error.
		MarkResult(err error) bool

		// Call attempts to call the given function if the circuit breaker is closed, or if
		// the circuit breaker is half-closed (with some probability). Otherwise, return an
		// ErrCircuitOpen. If the function times out, the circuit breaker will fail with an
		// ErrInvocationTimeout. If the function is invoked and yields a value before the
		// timeout elapses, that value is returned.
		Call(f BreakerFunc) error

		// CallAsync invokes the given function in a goroutine, returning a channel which
		// may receive one non-nil error value and then close. The channel will close without
		// writing a value on success.
		CallAsync(f BreakerFunc) <-chan error
	}

	BreakerConfig func(*circuitBreaker)
	BreakerFunc   func(ctx context.Context) error

	circuitBreaker struct {
		invocationTimeout          time.Duration
		halfClosedRetryProbability float64
		resetBackoff               backoff.Backoff
		failureInterpreter         FailureInterpreter
		tripCondition              TripCondition
		collector                  MetricCollector
		clock                      glock.Clock
		state                      CircuitState
		hardTrip                   bool
		lastFailureTime            *time.Time
		resetTimeout               *time.Duration
		maxConcurrency             int
		maxConcurrencyTimeout      time.Duration
	}

	CircuitState int
)

const (
	StateOpen       CircuitState = iota // Failure state
	StateClosed                         // Success state
	StateHalfClosed                     // Cautious, probabilistic retry state
)

var (
	// ErrCircuitOpen occurs when the Call method fails immediately.
	ErrCircuitOpen = fmt.Errorf("circuit is open")

	// ErrInvocationTimeout occurs when the method takes too long to execute.
	ErrInvocationTimeout = fmt.Errorf("invocation has timed out")
)

// NewCircuitBreaker creates a new CircuitBreaker.
func NewCircuitBreaker(configs ...BreakerConfig) CircuitBreaker {
	return newCircuitBreaker(configs...)
}

func newCircuitBreaker(configs ...BreakerConfig) *circuitBreaker {
	breaker := &circuitBreaker{
		invocationTimeout:          100 * time.Millisecond,
		halfClosedRetryProbability: 0.5,
		resetBackoff:               backoff.NewConstantBackoff(1000 * time.Millisecond),
		failureInterpreter:         NewAnyErrorFailureInterpreter(),
		tripCondition:              NewConsecutiveFailureTripCondition(5),
		collector:                  defaultCollector,
		clock:                      glock.NewRealClock(),
		state:                      StateClosed,
		maxConcurrency:             100,
		maxConcurrencyTimeout:      time.Millisecond * 100,
	}

	for _, config := range configs {
		config(breaker)
	}

	return breaker
}

func WithInvocationTimeout(timeout time.Duration) BreakerConfig {
	return func(cb *circuitBreaker) { cb.invocationTimeout = timeout }
}

func WithHalfClosedRetryProbability(probability float64) BreakerConfig {
	return func(cb *circuitBreaker) { cb.halfClosedRetryProbability = probability }
}

func WithResetBackoff(resetBackoff backoff.Backoff) BreakerConfig {
	return func(cb *circuitBreaker) { cb.resetBackoff = resetBackoff }
}

func WithFailureInterpreter(failureInterpreter FailureInterpreter) BreakerConfig {
	return func(cb *circuitBreaker) { cb.failureInterpreter = failureInterpreter }
}

func WithTripCondition(tripCondition TripCondition) BreakerConfig {
	return func(cb *circuitBreaker) { cb.tripCondition = tripCondition }
}

func WithMaxConcurrency(maxConcurrency int) BreakerConfig {
	return func(cb *circuitBreaker) { cb.maxConcurrency = maxConcurrency }
}

func WithMaxConcurrencyTimeout(timeout time.Duration) BreakerConfig {
	return func(cb *circuitBreaker) { cb.maxConcurrencyTimeout = timeout }
}

func WithCollector(collector MetricCollector) BreakerConfig {
	return func(cb *circuitBreaker) { cb.collector = collector }
}

func withClock(clock glock.Clock) BreakerConfig {
	return func(cb *circuitBreaker) { cb.clock = clock }
}

//
// Breaker Implementation

func (cb *circuitBreaker) Trip() {
	cb.hardTrip = true
}

func (cb *circuitBreaker) Reset() {
	cb.hardTrip = false
	cb.resetTimeout = nil

	cb.resetBackoff.Reset()
	cb.tripCondition.Success()
}

func (cb *circuitBreaker) ShouldTry() bool {
	if cb.hardTrip {
		return false
	}

	if !cb.tripCondition.ShouldTrip() {
		cb.state = StateClosed
		return true
	}

	if cb.state == StateClosed {
		cb.resetBackoff.Reset()
	}

	if cb.state != StateOpen {
		reset := cb.resetBackoff.NextInterval()
		cb.resetTimeout = &reset
	}

	if cb.resetTimeoutElapsed() {
		cb.state = StateHalfClosed
		return rand.Float64() < cb.halfClosedRetryProbability
	}

	cb.state = StateOpen
	return false
}

func (cb *circuitBreaker) resetTimeoutElapsed() bool {
	if cb.state != StateOpen {
		return false
	}

	if cb.lastFailureTime == nil || cb.resetTimeout == nil {
		return false
	}

	return cb.clock.Now().Sub(*cb.lastFailureTime) >= *cb.resetTimeout
}

func (cb *circuitBreaker) MarkResult(err error) bool {
	// TODO - test that this doesn't go to failure interpreter
	if err != nil && (err == ErrInvocationTimeout || cb.failureInterpreter.ShouldTrip(err)) {
		now := cb.clock.Now()
		cb.lastFailureTime = &now
		cb.tripCondition.Failure()
		return false
	}

	cb.Reset()
	return true
}

func (cb *circuitBreaker) Call(f BreakerFunc) error {
	cb.collector.Report(EventTypeAttempt)

	if !cb.ShouldTry() {
		cb.collector.Report(EventTypeShortCircuit)
		return ErrCircuitOpen
	}

	start := time.Now()
	err := callWithTimeout(f, cb.clock, cb.invocationTimeout)
	elapsed := time.Now().Sub(start)

	cb.collector.ReportDuration(EventTypeRunDuration, elapsed)

	if !cb.MarkResult(err) {
		if err == ErrInvocationTimeout {
			cb.collector.Report(EventTypeTimeout)
			return err
		}

		cb.collector.Report(EventTypeError)
		return err
	}

	return nil
}

func (cb *circuitBreaker) CallAsync(f BreakerFunc) <-chan error {
	return toErrChan(func() error { return cb.Call(f) })
}

func callWithTimeout(f BreakerFunc, clock glock.Clock, timeout time.Duration) error {
	if timeout == 0 {
		return f(context.Background())
	}

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

	ch := toErrChan(func() error {
		return f(ctx)
	})

	select {
	case err := <-ch:
		return err

	case <-clock.After(timeout):
		return ErrInvocationTimeout
	}
}
<|endoftext|>


<commit_before>package docker

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path"
	"strings"
	"time"
)

type Builder struct {
	runtime      *Runtime
	repositories *TagStore
	graph        *Graph
}

func NewBuilder(runtime *Runtime) *Builder {
	return &Builder{
		runtime:      runtime,
		graph:        runtime.graph,
		repositories: runtime.repositories,
	}
}

func (builder *Builder) mergeConfig(userConf, imageConf *Config) {
	if userConf.Hostname != "" {
		userConf.Hostname = imageConf.Hostname
	}
	if userConf.User != "" {
		userConf.User = imageConf.User
	}
	if userConf.Memory == 0 {
		userConf.Memory = imageConf.Memory
	}
	if userConf.MemorySwap == 0 {
		userConf.MemorySwap = imageConf.MemorySwap
	}
	if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
		userConf.PortSpecs = imageConf.PortSpecs
	}
	if !userConf.Tty {
		userConf.Tty = userConf.Tty
	}
	if !userConf.OpenStdin {
		userConf.OpenStdin = imageConf.OpenStdin
	}
	if !userConf.StdinOnce {
		userConf.StdinOnce = imageConf.StdinOnce
	}
	if userConf.Env == nil || len(userConf.Env) == 0 {
		userConf.Env = imageConf.Env
	}
	if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
		userConf.Cmd = imageConf.Cmd
	}
	if userConf.Dns == nil || len(userConf.Dns) == 0 {
		userConf.Dns = imageConf.Dns
	}
}

func (builder *Builder) Create(config *Config) (*Container, error) {
	// Lookup image
	img, err := builder.repositories.LookupImage(config.Image)
	if err != nil {
		return nil, err
	}

	if img.Config != nil {
		builder.mergeConfig(config, img.Config)
	}

	if config.Cmd == nil {
		return nil, fmt.Errorf("No command specified")
	}

	// Generate id
	id := GenerateId()
	// Generate default hostname
	// FIXME: the lxc template no longer needs to set a default hostname
	if config.Hostname == "" {
		config.Hostname = id[:12]
	}

	container := &Container{
		// FIXME: we should generate the ID here instead of receiving it as an argument
		Id:              id,
		Created:         time.Now(),
		Path:            config.Cmd[0],
		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
		Config:          config,
		Image:           img.Id, // Always use the resolved image id
		NetworkSettings: &NetworkSettings{},
		// FIXME: do we need to store this in the container?
		SysInitPath: sysInitPath,
	}
	container.root = builder.runtime.containerRoot(container.Id)
	// Step 1: create the container directory.
	// This doubles as a barrier to avoid race conditions.
	if err := os.Mkdir(container.root, 0700); err != nil {
		return nil, err
	}

	// If custom dns exists, then create a resolv.conf for the container
	if len(config.Dns) > 0 {
		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
		f, err := os.Create(container.ResolvConfPath)
		if err != nil {
			return nil, err
		}
		defer f.Close()
		for _, dns := range config.Dns {
			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
				return nil, err
			}
		}
	} else {
		container.ResolvConfPath = "/etc/resolv.conf"
	}

	// Step 2: save the container json
	if err := container.ToDisk(); err != nil {
		return nil, err
	}
	// Step 3: register the container
	if err := builder.runtime.Register(container); err != nil {
		return nil, err
	}
	return container, nil
}

// Commit creates a new filesystem image from the current state of a container.
// The image can optionally be tagged into a repository
func (builder *Builder) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
	// FIXME: freeze the container before copying it to avoid data corruption?
	// FIXME: this shouldn't be in commands.
	rwTar, err := container.ExportRw()
	if err != nil {
		return nil, err
	}
	// Create a new image from the container's base layers + a new layer from container changes
	img, err := builder.graph.Create(rwTar, container, comment, author, config)
	if err != nil {
		return nil, err
	}
	// Register the image if needed
	if repository != "" {
		if err := builder.repositories.Set(repository, tag, img.Id, true); err != nil {
			return img, err
		}
	}
	return img, nil
}

func (builder *Builder) clearTmp(containers, images map[string]struct{}) {
	for c := range containers {
		tmp := builder.runtime.Get(c)
		builder.runtime.Destroy(tmp)
		Debugf("Removing container %s", c)
	}
	for i := range images {
		builder.runtime.graph.Delete(i)
		Debugf("Removing image %s", i)
	}
}

func (builder *Builder) getCachedImage(image *Image, config *Config) (*Image, error) {
	// Retrieve all images
	images, err := builder.graph.All()
	if err != nil {
		return nil, err
	}

	// Store the tree in a map of map (map[parentId][childId])
	imageMap := make(map[string]map[string]struct{})
	for _, img := range images {
		if _, exists := imageMap[img.Parent]; !exists {
			imageMap[img.Parent] = make(map[string]struct{})
		}
		imageMap[img.Parent][img.Id] = struct{}{}
	}

	// Loop on the children of the given image and check the config
	for elem := range imageMap[image.Id] {
		img, err := builder.graph.Get(elem)
		if err != nil {
			return nil, err
		}
		if CompareConfig(&img.ContainerConfig, config) {
			return img, nil
		}
	}
	return nil, nil
}

func (builder *Builder) Build(dockerfile io.Reader, stdout io.Writer) (*Image, error) {
	var (
		image, base   *Image
		config        *Config
		maintainer    string
		env           map[string]string   = make(map[string]string)
		tmpContainers map[string]struct{} = make(map[string]struct{})
		tmpImages     map[string]struct{} = make(map[string]struct{})
	)
	defer builder.clearTmp(tmpContainers, tmpImages)

	file := bufio.NewReader(dockerfile)
	for {
		line, err := file.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		line = strings.Replace(strings.TrimSpace(line), "	", " ", 1)
		// Skip comments and empty line
		if len(line) == 0 || line[0] == '#' {
			continue
		}
		tmp := strings.SplitN(line, " ", 2)
		if len(tmp) != 2 {
			return nil, fmt.Errorf("Invalid Dockerfile format")
		}
		instruction := strings.Trim(tmp[0], " ")
		arguments := strings.Trim(tmp[1], " ")
		switch strings.ToLower(instruction) {
		case "from":
			fmt.Fprintf(stdout, "FROM %s\n", arguments)
			image, err = builder.runtime.repositories.LookupImage(arguments)
			if err != nil {
				if builder.runtime.graph.IsNotExist(err) {

					var tag, remote string
					if strings.Contains(arguments, ":") {
						remoteParts := strings.Split(arguments, ":")
						tag = remoteParts[1]
						remote = remoteParts[0]
					} else {
						remote = arguments
					}

					if err := builder.runtime.graph.PullRepository(stdout, remote, tag, builder.runtime.repositories, builder.runtime.authConfig); err != nil {
						return nil, err
					}

					image, err = builder.runtime.repositories.LookupImage(arguments)
					if err != nil {
						return nil, err
					}
				} else {
					return nil, err
				}
			}
			config = &Config{}

			break
		case "maintainer":
			fmt.Fprintf(stdout, "MAINTAINER %s\n", arguments)
			maintainer = arguments
			break
		case "run":
			fmt.Fprintf(stdout, "RUN %s\n", arguments)
			if image == nil {
				return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
			}
			config, err := ParseRun([]string{image.Id, "/bin/sh", "-c", arguments}, nil, builder.runtime.capabilities)
			if err != nil {
				return nil, err
			}

			for key, value := range env {
				config.Env = append(config.Env, fmt.Sprintf("%s=%s", key, value))
			}

			if cache, err := builder.getCachedImage(image, config); err != nil {
				return nil, err
			} else if cache != nil {
				image = cache
				fmt.Fprintf(stdout, "===> %s\n", image.ShortId())
				break
			}

			Debugf("Env -----> %v ------ %v\n", config.Env, env)

			// Create the container and start it
			c, err := builder.Create(config)
			if err != nil {
				return nil, err
			}

			if os.Getenv("DEBUG") != "" {
				out, _ := c.StdoutPipe()
				err2, _ := c.StderrPipe()
				go io.Copy(os.Stdout, out)
				go io.Copy(os.Stdout, err2)
			}

			if err := c.Start(); err != nil {
				return nil, err
			}
			tmpContainers[c.Id] = struct{}{}

			// Wait for it to finish
			if result := c.Wait(); result != 0 {
				return nil, fmt.Errorf("!!! '%s' return non-zero exit code '%d'. Aborting.", arguments, result)
			}

			// Commit the container
			base, err = builder.Commit(c, "", "", "", maintainer, nil)
			if err != nil {
				return nil, err
			}
			tmpImages[base.Id] = struct{}{}

			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())

			// use the base as the new image
			image = base

			break
		case "env":
			tmp := strings.SplitN(arguments, " ", 2)
			if len(tmp) != 2 {
				return nil, fmt.Errorf("Invalid ENV format")
			}
			key := strings.Trim(tmp[0], " ")
			value := strings.Trim(tmp[1], " ")
			fmt.Fprintf(stdout, "ENV %s %s\n", key, value)
			env[key] = value
			if image != nil {
				fmt.Fprintf(stdout, "===> %s\n", image.ShortId())
			} else {
				fmt.Fprintf(stdout, "===> <nil>\n")
			}
			break
		case "cmd":
			fmt.Fprintf(stdout, "CMD %s\n", arguments)

			// Create the container and start it
			c, err := builder.Create(&Config{Image: image.Id, Cmd: []string{"", ""}})
			if err != nil {
				return nil, err
			}
			if err := c.Start(); err != nil {
				return nil, err
			}
			tmpContainers[c.Id] = struct{}{}

			cmd := []string{}
			if err := json.Unmarshal([]byte(arguments), &cmd); err != nil {
				return nil, err
			}
			config.Cmd = cmd

			// Commit the container
			base, err = builder.Commit(c, "", "", "", maintainer, config)
			if err != nil {
				return nil, err
			}
			tmpImages[base.Id] = struct{}{}

			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
			image = base
			break
		case "expose":
			ports := strings.Split(arguments, " ")

			fmt.Fprintf(stdout, "EXPOSE %v\n", ports)
			if image == nil {
				return nil, fmt.Errorf("Please provide a source image with `from` prior to copy")
			}

			// Create the container and start it
			c, err := builder.Create(&Config{Image: image.Id, Cmd: []string{"", ""}})
			if err != nil {
				return nil, err
			}
			if err := c.Start(); err != nil {
				return nil, err
			}
			tmpContainers[c.Id] = struct{}{}

			config.PortSpecs = append(ports, config.PortSpecs...)

			// Commit the container
			base, err = builder.Commit(c, "", "", "", maintainer, config)
			if err != nil {
				return nil, err
			}
			tmpImages[base.Id] = struct{}{}

			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
			image = base
			break
		case "insert":
			if image == nil {
				return nil, fmt.Errorf("Please provide a source image with `from` prior to copy")
			}
			tmp = strings.SplitN(arguments, " ", 2)
			if len(tmp) != 2 {
				return nil, fmt.Errorf("Invalid INSERT format")
			}
			sourceUrl := strings.Trim(tmp[0], " ")
			destPath := strings.Trim(tmp[1], " ")
			fmt.Fprintf(stdout, "COPY %s to %s in %s\n", sourceUrl, destPath, base.ShortId())

			file, err := Download(sourceUrl, stdout)
			if err != nil {
				return nil, err
			}
			defer file.Body.Close()

			config, err := ParseRun([]string{base.Id, "echo", "insert", sourceUrl, destPath}, nil, builder.runtime.capabilities)
			if err != nil {
				return nil, err
			}
			c, err := builder.Create(config)
			if err != nil {
				return nil, err
			}

			if err := c.Start(); err != nil {
				return nil, err
			}

			// Wait for echo to finish
			if result := c.Wait(); result != 0 {
				return nil, fmt.Errorf("!!! '%s' return non-zero exit code '%d'. Aborting.", arguments, result)
			}

			if err := c.Inject(file.Body, destPath); err != nil {
				return nil, err
			}

			base, err = builder.Commit(c, "", "", "", maintainer, nil)
			if err != nil {
				return nil, err
			}
			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())

			image = base

			break
		default:
			fmt.Fprintf(stdout, "Skipping unknown instruction %s\n", strings.ToUpper(instruction))
		}
	}
	if image != nil {
		// The build is successful, keep the temporary containers and images
		for i := range tmpImages {
			delete(tmpImages, i)
		}
		for i := range tmpContainers {
			delete(tmpContainers, i)
		}
		fmt.Fprintf(stdout, "Build finished. image id: %s\n", image.ShortId())
		return image, nil
	}
	return nil, fmt.Errorf("An error occured during the build\n")
}
<commit_msg>propagate CpuShares in mergeConfig<commit_after>package docker

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path"
	"strings"
	"time"
)

type Builder struct {
	runtime      *Runtime
	repositories *TagStore
	graph        *Graph
}

func NewBuilder(runtime *Runtime) *Builder {
	return &Builder{
		runtime:      runtime,
		graph:        runtime.graph,
		repositories: runtime.repositories,
	}
}

func (builder *Builder) mergeConfig(userConf, imageConf *Config) {
	if userConf.Hostname != "" {
		userConf.Hostname = imageConf.Hostname
	}
	if userConf.User != "" {
		userConf.User = imageConf.User
	}
	if userConf.Memory == 0 {
		userConf.Memory = imageConf.Memory
	}
	if userConf.MemorySwap == 0 {
		userConf.MemorySwap = imageConf.MemorySwap
	}
	if userConf.CpuShares == 0 {
		userConf.CpuShares = imageConf.CpuShares
	}
	if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
		userConf.PortSpecs = imageConf.PortSpecs
	}
	if !userConf.Tty {
		userConf.Tty = userConf.Tty
	}
	if !userConf.OpenStdin {
		userConf.OpenStdin = imageConf.OpenStdin
	}
	if !userConf.StdinOnce {
		userConf.StdinOnce = imageConf.StdinOnce
	}
	if userConf.Env == nil || len(userConf.Env) == 0 {
		userConf.Env = imageConf.Env
	}
	if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
		userConf.Cmd = imageConf.Cmd
	}
	if userConf.Dns == nil || len(userConf.Dns) == 0 {
		userConf.Dns = imageConf.Dns
	}
}

func (builder *Builder) Create(config *Config) (*Container, error) {
	// Lookup image
	img, err := builder.repositories.LookupImage(config.Image)
	if err != nil {
		return nil, err
	}

	if img.Config != nil {
		builder.mergeConfig(config, img.Config)
	}

	if config.Cmd == nil {
		return nil, fmt.Errorf("No command specified")
	}

	// Generate id
	id := GenerateId()
	// Generate default hostname
	// FIXME: the lxc template no longer needs to set a default hostname
	if config.Hostname == "" {
		config.Hostname = id[:12]
	}

	container := &Container{
		// FIXME: we should generate the ID here instead of receiving it as an argument
		Id:              id,
		Created:         time.Now(),
		Path:            config.Cmd[0],
		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
		Config:          config,
		Image:           img.Id, // Always use the resolved image id
		NetworkSettings: &NetworkSettings{},
		// FIXME: do we need to store this in the container?
		SysInitPath: sysInitPath,
	}
	container.root = builder.runtime.containerRoot(container.Id)
	// Step 1: create the container directory.
	// This doubles as a barrier to avoid race conditions.
	if err := os.Mkdir(container.root, 0700); err != nil {
		return nil, err
	}

	// If custom dns exists, then create a resolv.conf for the container
	if len(config.Dns) > 0 {
		container.ResolvConfPath = path.Join(container.root, "resolv.conf")
		f, err := os.Create(container.ResolvConfPath)
		if err != nil {
			return nil, err
		}
		defer f.Close()
		for _, dns := range config.Dns {
			if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
				return nil, err
			}
		}
	} else {
		container.ResolvConfPath = "/etc/resolv.conf"
	}

	// Step 2: save the container json
	if err := container.ToDisk(); err != nil {
		return nil, err
	}
	// Step 3: register the container
	if err := builder.runtime.Register(container); err != nil {
		return nil, err
	}
	return container, nil
}

// Commit creates a new filesystem image from the current state of a container.
// The image can optionally be tagged into a repository
func (builder *Builder) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
	// FIXME: freeze the container before copying it to avoid data corruption?
	// FIXME: this shouldn't be in commands.
	rwTar, err := container.ExportRw()
	if err != nil {
		return nil, err
	}
	// Create a new image from the container's base layers + a new layer from container changes
	img, err := builder.graph.Create(rwTar, container, comment, author, config)
	if err != nil {
		return nil, err
	}
	// Register the image if needed
	if repository != "" {
		if err := builder.repositories.Set(repository, tag, img.Id, true); err != nil {
			return img, err
		}
	}
	return img, nil
}

func (builder *Builder) clearTmp(containers, images map[string]struct{}) {
	for c := range containers {
		tmp := builder.runtime.Get(c)
		builder.runtime.Destroy(tmp)
		Debugf("Removing container %s", c)
	}
	for i := range images {
		builder.runtime.graph.Delete(i)
		Debugf("Removing image %s", i)
	}
}

func (builder *Builder) getCachedImage(image *Image, config *Config) (*Image, error) {
	// Retrieve all images
	images, err := builder.graph.All()
	if err != nil {
		return nil, err
	}

	// Store the tree in a map of map (map[parentId][childId])
	imageMap := make(map[string]map[string]struct{})
	for _, img := range images {
		if _, exists := imageMap[img.Parent]; !exists {
			imageMap[img.Parent] = make(map[string]struct{})
		}
		imageMap[img.Parent][img.Id] = struct{}{}
	}

	// Loop on the children of the given image and check the config
	for elem := range imageMap[image.Id] {
		img, err := builder.graph.Get(elem)
		if err != nil {
			return nil, err
		}
		if CompareConfig(&img.ContainerConfig, config) {
			return img, nil
		}
	}
	return nil, nil
}

func (builder *Builder) Build(dockerfile io.Reader, stdout io.Writer) (*Image, error) {
	var (
		image, base   *Image
		config        *Config
		maintainer    string
		env           map[string]string   = make(map[string]string)
		tmpContainers map[string]struct{} = make(map[string]struct{})
		tmpImages     map[string]struct{} = make(map[string]struct{})
	)
	defer builder.clearTmp(tmpContainers, tmpImages)

	file := bufio.NewReader(dockerfile)
	for {
		line, err := file.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		line = strings.Replace(strings.TrimSpace(line), "	", " ", 1)
		// Skip comments and empty line
		if len(line) == 0 || line[0] == '#' {
			continue
		}
		tmp := strings.SplitN(line, " ", 2)
		if len(tmp) != 2 {
			return nil, fmt.Errorf("Invalid Dockerfile format")
		}
		instruction := strings.Trim(tmp[0], " ")
		arguments := strings.Trim(tmp[1], " ")
		switch strings.ToLower(instruction) {
		case "from":
			fmt.Fprintf(stdout, "FROM %s\n", arguments)
			image, err = builder.runtime.repositories.LookupImage(arguments)
			if err != nil {
				if builder.runtime.graph.IsNotExist(err) {

					var tag, remote string
					if strings.Contains(arguments, ":") {
						remoteParts := strings.Split(arguments, ":")
						tag = remoteParts[1]
						remote = remoteParts[0]
					} else {
						remote = arguments
					}

					if err := builder.runtime.graph.PullRepository(stdout, remote, tag, builder.runtime.repositories, builder.runtime.authConfig); err != nil {
						return nil, err
					}

					image, err = builder.runtime.repositories.LookupImage(arguments)
					if err != nil {
						return nil, err
					}
				} else {
					return nil, err
				}
			}
			config = &Config{}

			break
		case "maintainer":
			fmt.Fprintf(stdout, "MAINTAINER %s\n", arguments)
			maintainer = arguments
			break
		case "run":
			fmt.Fprintf(stdout, "RUN %s\n", arguments)
			if image == nil {
				return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
			}
			config, err := ParseRun([]string{image.Id, "/bin/sh", "-c", arguments}, nil, builder.runtime.capabilities)
			if err != nil {
				return nil, err
			}

			for key, value := range env {
				config.Env = append(config.Env, fmt.Sprintf("%s=%s", key, value))
			}

			if cache, err := builder.getCachedImage(image, config); err != nil {
				return nil, err
			} else if cache != nil {
				image = cache
				fmt.Fprintf(stdout, "===> %s\n", image.ShortId())
				break
			}

			Debugf("Env -----> %v ------ %v\n", config.Env, env)

			// Create the container and start it
			c, err := builder.Create(config)
			if err != nil {
				return nil, err
			}

			if os.Getenv("DEBUG") != "" {
				out, _ := c.StdoutPipe()
				err2, _ := c.StderrPipe()
				go io.Copy(os.Stdout, out)
				go io.Copy(os.Stdout, err2)
			}

			if err := c.Start(); err != nil {
				return nil, err
			}
			tmpContainers[c.Id] = struct{}{}

			// Wait for it to finish
			if result := c.Wait(); result != 0 {
				return nil, fmt.Errorf("!!! '%s' return non-zero exit code '%d'. Aborting.", arguments, result)
			}

			// Commit the container
			base, err = builder.Commit(c, "", "", "", maintainer, nil)
			if err != nil {
				return nil, err
			}
			tmpImages[base.Id] = struct{}{}

			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())

			// use the base as the new image
			image = base

			break
		case "env":
			tmp := strings.SplitN(arguments, " ", 2)
			if len(tmp) != 2 {
				return nil, fmt.Errorf("Invalid ENV format")
			}
			key := strings.Trim(tmp[0], " ")
			value := strings.Trim(tmp[1], " ")
			fmt.Fprintf(stdout, "ENV %s %s\n", key, value)
			env[key] = value
			if image != nil {
				fmt.Fprintf(stdout, "===> %s\n", image.ShortId())
			} else {
				fmt.Fprintf(stdout, "===> <nil>\n")
			}
			break
		case "cmd":
			fmt.Fprintf(stdout, "CMD %s\n", arguments)

			// Create the container and start it
			c, err := builder.Create(&Config{Image: image.Id, Cmd: []string{"", ""}})
			if err != nil {
				return nil, err
			}
			if err := c.Start(); err != nil {
				return nil, err
			}
			tmpContainers[c.Id] = struct{}{}

			cmd := []string{}
			if err := json.Unmarshal([]byte(arguments), &cmd); err != nil {
				return nil, err
			}
			config.Cmd = cmd

			// Commit the container
			base, err = builder.Commit(c, "", "", "", maintainer, config)
			if err != nil {
				return nil, err
			}
			tmpImages[base.Id] = struct{}{}

			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
			image = base
			break
		case "expose":
			ports := strings.Split(arguments, " ")

			fmt.Fprintf(stdout, "EXPOSE %v\n", ports)
			if image == nil {
				return nil, fmt.Errorf("Please provide a source image with `from` prior to copy")
			}

			// Create the container and start it
			c, err := builder.Create(&Config{Image: image.Id, Cmd: []string{"", ""}})
			if err != nil {
				return nil, err
			}
			if err := c.Start(); err != nil {
				return nil, err
			}
			tmpContainers[c.Id] = struct{}{}

			config.PortSpecs = append(ports, config.PortSpecs...)

			// Commit the container
			base, err = builder.Commit(c, "", "", "", maintainer, config)
			if err != nil {
				return nil, err
			}
			tmpImages[base.Id] = struct{}{}

			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())
			image = base
			break
		case "insert":
			if image == nil {
				return nil, fmt.Errorf("Please provide a source image with `from` prior to copy")
			}
			tmp = strings.SplitN(arguments, " ", 2)
			if len(tmp) != 2 {
				return nil, fmt.Errorf("Invalid INSERT format")
			}
			sourceUrl := strings.Trim(tmp[0], " ")
			destPath := strings.Trim(tmp[1], " ")
			fmt.Fprintf(stdout, "COPY %s to %s in %s\n", sourceUrl, destPath, base.ShortId())

			file, err := Download(sourceUrl, stdout)
			if err != nil {
				return nil, err
			}
			defer file.Body.Close()

			config, err := ParseRun([]string{base.Id, "echo", "insert", sourceUrl, destPath}, nil, builder.runtime.capabilities)
			if err != nil {
				return nil, err
			}
			c, err := builder.Create(config)
			if err != nil {
				return nil, err
			}

			if err := c.Start(); err != nil {
				return nil, err
			}

			// Wait for echo to finish
			if result := c.Wait(); result != 0 {
				return nil, fmt.Errorf("!!! '%s' return non-zero exit code '%d'. Aborting.", arguments, result)
			}

			if err := c.Inject(file.Body, destPath); err != nil {
				return nil, err
			}

			base, err = builder.Commit(c, "", "", "", maintainer, nil)
			if err != nil {
				return nil, err
			}
			fmt.Fprintf(stdout, "===> %s\n", base.ShortId())

			image = base

			break
		default:
			fmt.Fprintf(stdout, "Skipping unknown instruction %s\n", strings.ToUpper(instruction))
		}
	}
	if image != nil {
		// The build is successful, keep the temporary containers and images
		for i := range tmpImages {
			delete(tmpImages, i)
		}
		for i := range tmpContainers {
			delete(tmpContainers, i)
		}
		fmt.Fprintf(stdout, "Build finished. image id: %s\n", image.ShortId())
		return image, nil
	}
	return nil, fmt.Errorf("An error occured during the build\n")
}
<|endoftext|>


<commit_before>package main

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

	"github.com/Tonkpils/snag/vow"
	fsn "gopkg.in/fsnotify.v1"
)

var (
	mtimes = map[string]time.Time{}
)

const (
	GoExt = ".go"
)

type Bob struct {
	w        *fsn.Watcher
	done     chan struct{}
	watching map[string]struct{}

	packages  string
	buildArgs string
	vetArgs   string
	testArgs  string
}

func NewBuilder(packages, build, vet, test string) (*Bob, error) {
	w, err := fsn.NewWatcher()
	if err != nil {
		return nil, err
	}

	return &Bob{
		w:         w,
		done:      make(chan struct{}),
		watching:  map[string]struct{}{},
		packages:  packages,
		buildArgs: build,
		vetArgs:   vet,
		testArgs:  test,
	}, nil
}

func (b *Bob) Close() {
	b.w.Close()
	close(b.done)
}

func (b *Bob) Watch(path string) error {
	b.watch(path)
	b.execute()

	for {
		select {
		case ev := <-b.w.Events:
			var queueBuild bool
			switch {
			case isCreate(ev.Op):
				queueBuild = b.watch(ev.Name)
			case isDelete(ev.Op):
				if _, ok := b.watching[ev.Name]; ok {
					b.w.Remove(ev.Name)
					delete(b.watching, ev.Name)
				}
				queueBuild = true
			case isModify(ev.Op):
				queueBuild = true
			}
			if queueBuild {
				b.maybeQueue(ev.Name)
			}
		case err := <-b.w.Errors:
			log.Println("error:", err)
		case <-b.done:
			return nil
		}
	}
}

func (b *Bob) maybeQueue(path string) {
	if filepath.Ext(path) != GoExt {
		return
	}

	stat, err := os.Stat(path)
	if err == nil {
		mtime := stat.ModTime()
		lasttime := mtimes[path]
		if !mtime.Equal(lasttime) {
			mtimes[path] = mtime
			b.execute()
		}
	} else {
		delete(mtimes, path)
		b.execute()
	}
}

func (b *Bob) execute() {
	b.clearBuffer()
	vow.To("go", "build", b.packages, b.buildArgs).
		Then("go", "vet", b.packages, b.vetArgs).
		Then("go", "test", b.packages, b.testArgs).
		Exec(os.Stdout)
}

func (b *Bob) clearBuffer() {
	fmt.Print("\033c")
}

func (b *Bob) watch(path string) bool {
	var shouldBuild bool
	if _, ok := b.watching[path]; ok {
		return false
	}
	filepath.Walk(path, func(p string, fileInfo os.FileInfo, err error) error {
		if fileInfo == nil {
			return err
		}
		if fileInfo.IsDir() {
			if err := b.w.Add(p); err != nil {
				return err
			}
			b.watching[p] = struct{}{}
		} else {
			shouldBuild = true
		}
		return nil
	})
	return shouldBuild
}

func isCreate(op fsn.Op) bool {
	return op&fsn.Create == fsn.Create
}

func isDelete(op fsn.Op) bool {
	return op&fsn.Remove == fsn.Remove
}

func isModify(op fsn.Op) bool {
	return op&fsn.Write == fsn.Write ||
		op&fsn.Rename == fsn.Rename
}
<commit_msg>use go test flags instead of package flags<commit_after>package main

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

	"github.com/Tonkpils/snag/vow"
	fsn "gopkg.in/fsnotify.v1"
)

var (
	mtimes = map[string]time.Time{}
)

const (
	GoExt = ".go"
)

type Bob struct {
	w        *fsn.Watcher
	done     chan struct{}
	watching map[string]struct{}

	packages  string
	buildArgs string
	vetArgs   string
	testArgs  string
}

func NewBuilder(packages, build, vet, test string) (*Bob, error) {
	w, err := fsn.NewWatcher()
	if err != nil {
		return nil, err
	}

	return &Bob{
		w:         w,
		done:      make(chan struct{}),
		watching:  map[string]struct{}{},
		packages:  packages,
		buildArgs: build,
		vetArgs:   vet,
		testArgs:  test,
	}, nil
}

func (b *Bob) Close() {
	b.w.Close()
	close(b.done)
}

func (b *Bob) Watch(path string) error {
	b.watch(path)
	b.execute()

	for {
		select {
		case ev := <-b.w.Events:
			var queueBuild bool
			switch {
			case isCreate(ev.Op):
				queueBuild = b.watch(ev.Name)
			case isDelete(ev.Op):
				if _, ok := b.watching[ev.Name]; ok {
					b.w.Remove(ev.Name)
					delete(b.watching, ev.Name)
				}
				queueBuild = true
			case isModify(ev.Op):
				queueBuild = true
			}
			if queueBuild {
				b.maybeQueue(ev.Name)
			}
		case err := <-b.w.Errors:
			log.Println("error:", err)
		case <-b.done:
			return nil
		}
	}
}

func (b *Bob) maybeQueue(path string) {
	if filepath.Ext(path) != GoExt {
		return
	}

	stat, err := os.Stat(path)
	if err == nil {
		mtime := stat.ModTime()
		lasttime := mtimes[path]
		if !mtime.Equal(lasttime) {
			mtimes[path] = mtime
			b.execute()
		}
	} else {
		delete(mtimes, path)
		b.execute()
	}
}

func (b *Bob) execute() {
	b.clearBuffer()
	vow.To("go", "build", b.packages, b.buildArgs).
		Then("go", "vet", b.packages, b.vetArgs).
		Then("go", "test", b.testArgs, b.packages).
		Exec(os.Stdout)
}

func (b *Bob) clearBuffer() {
	fmt.Print("\033c")
}

func (b *Bob) watch(path string) bool {
	var shouldBuild bool
	if _, ok := b.watching[path]; ok {
		return false
	}
	filepath.Walk(path, func(p string, fileInfo os.FileInfo, err error) error {
		if fileInfo == nil {
			return err
		}
		if fileInfo.IsDir() {
			if err := b.w.Add(p); err != nil {
				return err
			}
			b.watching[p] = struct{}{}
		} else {
			shouldBuild = true
		}
		return nil
	})
	return shouldBuild
}

func isCreate(op fsn.Op) bool {
	return op&fsn.Create == fsn.Create
}

func isDelete(op fsn.Op) bool {
	return op&fsn.Remove == fsn.Remove
}

func isModify(op fsn.Op) bool {
	return op&fsn.Write == fsn.Write ||
		op&fsn.Rename == fsn.Rename
}
<|endoftext|>