<commit_before>package webhooks

import (
	"time"
)

type PayloadBase struct {
	Sender     *User       `json:"sender"`
	Repository *Repository `json:"repository"`
}

type User struct {
	Login             string `json:"login"`
	Id                int64  `json:"id"`
	AvatarUrl         string `json:"avatar_url"`
	GravatarId        string `json:"gravatar_id"`
	Url               string `json:"url"`
	HtmlUrl           string `json:"html_url"`
	FollowersUrl      string `json:"followers_url"`
	FollowingUrl      string `json:"following_url"`
	GistsUrl          string `json:"gists_url"`
	StarredUrl        string `json:"starred_url"`
	SubscriptionsUrl  string `json:"subscriptions_url"`
	OrganizationsUrl  string `json:"organizations_url"`
	ReposUrl          string `json:"repos_url"`
	EventsUrl         string `json:"events_url"`
	ReceivedEventsUrl string `json:"received_events_url"`
	Type              string `json:"type"`
	SiteAdmin         bool   `json:"site_admin"`
}

type Repository struct {
	Id               int64  `json:"id"`
	Name             string `json:"name"`
	FullName         string `json:"full_name"`
	Owner            *User  `json:"owner"`
	Private          bool   `json:"private"`
	HtmlUrl          string `json:"html_url"`
	Descriprion      string `json:"description"`
	Fork             bool   `json:"fork"`
	Url              string `json:"url"`
	ForksUrl         string `json:"forks_url"`
	KeysUrl          string `json:"keys_url"`
	CollaboratorsUrl string `json:"collaborators_url"`
	TeamsUrl         string `json:"teams_url"`
	HooksUrl         string `json:"hooks_url"`
	IssueEventsUrl   string `json:"issue_events_url"`
	EventsUrl        string `json:"events_url"`
	AssigneesUrl     string `json:"assignees_url"`
	BranchesUrl      string `json:"branches_url"`
	TagsUrl          string `json:"tags_url"`
	BlobsUrl         string `json:"blobs_url"`
	GitTagsUrl       string `json:"git_tags_url"`
	GitRefsUrl       string `json:"git_refs_url"`
	TreesUrl         string `json:"trees_url"`
	StatusesUrl      string `json:"statuses_url"`
	LanguagesUrl     string `json:"languages_url"`
	StargazersUrl    string `json:"stargazers_url"`
	ContributorsUrl  string `json:"contributors_url"`
	SubscribersUrl   string `json:"subscribers_url"`
	SubscriptionUrl  string `json:"subscription_url"`
	CommitsUrl       string `json:"commits_url"`
	GitCommitsUrl    string `json:"git_commits_url"`
	CommentsUrl      string `json:"comments_url"`
	IssueCommentUrl  string `json:"issue_comment_url"`
	ContentsUrl      string `json:"contents_url"`
	CompareUrl       string `json:"compare_url"`
	MergesUrl        string `json:"merges_url"`
	ArchiveUrl       string `json:"archive_url"`
	DownloadsUrl     string `json:"downloads_url"`
	IssuesUrl        string `json:"issues_url"`
	PullsUrl         string `json:"pulls_url"`
	MilestonesUrl    string `json:"milestones_url"`
	NotificationsUrl string `json:"notifications_url"`
	LabelsUrl        string `json:"labels_url"`
	ReleasesUrl      string `json:"releases_url"`
	CreatedAt        string `json:"created_at"`
	UpdatedAt        string `json:"updated_at"`
	PushedAt         string `json:"pushed_at"`
	GitUrl           string `json:"git_url"`
	SshUrl           string `json:"ssh_url"`
	CloneUrl         string `json:"clone_url"`
	SvnUrl           string `json:"svn_url"`
	Homepage         string `json:"homepage"`
	Size             int    `json:"size"`
	StargazersCount  int    `json:"stargazers_count"`
	WatchersCount    int    `json:"watchers_count"`
	Language         string `json:"language"`
	HasIssues        bool   `json:"has_issues"`
	HasDownloads     bool   `json:"has_downloads"`
	HasWiki          bool   `json:"has_wiki"`
	HasPages         bool   `json:"has_pages"`
	ForksCount       int    `json:"forks_count"`
	MirrorUrl        string `json:"mirror_url"`
	OpenIssuesCount  int    `json:"open_issues_count"`
	Forks            int    `json:"forks"`
	OpenIssues       int    `json:"open_issues"`
	DefaultBranch    string `json:"default_branch"`
}

type Comment struct {
	HtmlUrl   string     `json:"html_url"`
	Url       string     `json:"url"`
	Id        int64      `json:"id"`
	Body      string     `json:"body"`
	Path      string     `json:"path"`
	Position  int        `json:"position"`
	Line      int        `json:"line"`
	CommitId  string     `json:"commit_id"`
	User      *User      `json:"user"`
	CreatedAt *time.Time `json:"created_at"`
	UpdatedAt *time.Time `json:"updated_at"`
}

type Commit struct {
	Id        string   `json:"id"`
	Distinct  bool     `json:"distinct"`
	Message   string   `json:"message"`
	Timestamp string   `json:"timestamp"`
	Url       string   `json:"url"`
	Author    string   `json:"author"`
	Committer string   `json:"committer"`
	Added     []string `json:"added"`
	Removed   []string `json:"removed"`
	Modified  []string `json:"modified"`
}

type Hook struct {
	Id        int64    `json:"id"`
	Url       string   `json:"url"`
	TestUrl   string   `json:"test_url"`
	PingUrl   string   `json:"ping_url"`
	Name      string   `json:"name"`
	Events    []string `json:"events"`
	Active    bool     `json:"active"`
	CreatedAt string   `json:"created_at"`
	UpdatedAt string   `json:"updated_at"`
	Config    struct {
		Url         string `json:"url"`
		ContentType string `json:"content_type"`
	} `json:"config"`
}

type Label struct {
	Url   string `json:"url"`
	Name  string `json:"name"`
	Color string `json:"color"`
}

type Issue struct {
	Url          string      `json:"url"`
	LabelsUrl    string      `json:"labels_url"`
	CommentsUrl  string      `json:"comments_url"`
	EventsUrl    string      `json:"events_url"`
	HtmlUrl      string      `json:"html_url"`
	Id           int64       `json:"id"`
	Number       int64       `json:"number"`
	Title        string      `json:"title"`
	User         *User       `json:"user"`
	Labels       []*Label    `json:"labels"`
	State        string      `json:"state"`
	Locked       bool        `json:"locked"`
	Assignee     *User       `json:"assignee"`
	Milestone    interface{} `json:"milestone"`
	CommentCount int64       `json:"comments"`
	CreatedAt    string      `json:"created_at"`
	UpdatedAt    string      `json:"updated_at"`
	ClosedAt     string      `json:"closed_at"`
	Body         string      `json:"body"`
}

type PullRequest struct {
	Issue
	DiffUrl            string      `json:"diff_url"`
	PatchUrl           string      `json:"patch_url"`
	IssueUrl           string      `json:"issue_url"`
	MergedAt           string      `json:"merged_at"`
	MergeCommitSha     string      `json:"merge_commit_sha"`
	CommitsUrl         string      `json:"commits_url"`
	ReviewCommentsUrl  string      `json:"review_comments_url"`
	ReviewCommentUrl   string      `json:"review_comment_url"`
	StatusesUrl        string      `json:"statuses_url"`
	Head               interface{} `json:"head"` // not sure what this type is quite yet
	Base               interface{} `json:"base"` // same type as Head
	Merged             bool        `json:"merged"`
	Mergeable          bool        `json:"mergable"`
	MergableState      string      `json:"mergable_state"`
	MergedBy           *User       `json:"merged_by"`
	ReviewCommentCount int64       `json:"review_comments"`
	CommitCount        int64       `json:"commits"`
	Additions          int64       `json:"additions"`
	Deletions          int64       `json:"deletions"`
	ChangedFiles       int64       `json:"changed_files"`
}

type Committer struct {
	Name     string `json:"name"`
	Email    string `json:"email"`
	Username string `json:"username"`
}

type CommitCommentEvent struct {
	PayloadBase
	Comment *Comment `json:"comment"`
}

type CreateEvent struct {
	PayloadBase
	RefType      string `json:"ref_type"`
	Ref          string `json:"ref"`
	MasterBranch string `json:"master_branch"`
	Description  string `json:"description"`
}

type DeleteEvent struct {
	PayloadBase
	RefType string `json:"ref_type"`
	Ref     string `json:"ref"`
}

type DeploymentEvent struct {
	PayloadBase
	Deployment struct {
		Url           string      `json:"url"`
		Id            int64       `json:"id"`
		Sha           string      `json:"sha"`
		Ref           string      `json:"ref"`
		Task          string      `json:"task"`
		Payload       interface{} `json:"payload"`
		Environment   string      `json:"environment"`
		Description   string      `json:"description"`
		Creator       *User       `json:"creator"`
		CreatedAt     string      `json:"created_at"`
		UpdatedAt     string      `json:"updated_at"`
		StatusesUrl   string      `json:"statuses_url"`
		RepositoryUrl string      `json:"repository_url"`
	} `json:"deployment"`
}

type IssueCommentEvent struct {
	PayloadBase
	Action  *Issue `json:"issue"`
	Comment string `json:"comment"`
}

type PingEvent struct {
	PayloadBase
	Zen    string `json:"zen"`
	HookId int64  `json:"hook_id"`
	Hook   *Hook  `json:"hook"`
}

type PullRequestEvent struct {
	PayloadBase
	Action      string       `json:"action"`
	Number      int64        `json:"number"`
	PullRequest *PullRequest `json:"pull_request"`
	Label       *Label       `json:"label"`
}

type PushEvent struct {
	PayloadBase
	Ref        string     `json:"ref"`
	Before     string     `json:"before"`
	After      string     `json:"after"`
	Created    bool       `json:"created"`
	Deleted    bool       `json:"deleted"`
	Forced     bool       `json:"forced"`
	BaseRef    string     `json:"base_ref"`
	Compare    string     `json:"compare"`
	Commits    []*Commit  `json:"commits"`
	HeadCommit *Commit    `json:"head_commit"`
	Pusher     *Committer `json:"pusher"`
}
<commit_msg>types suck<commit_after>package webhooks

import (
	"time"
)

type PayloadBase struct {
	Sender     *User       `json:"sender"`
	Repository *Repository `json:"repository"`
}

type User struct {
	Login             string `json:"login"`
	Id                int64  `json:"id"`
	AvatarUrl         string `json:"avatar_url"`
	GravatarId        string `json:"gravatar_id"`
	Url               string `json:"url"`
	HtmlUrl           string `json:"html_url"`
	FollowersUrl      string `json:"followers_url"`
	FollowingUrl      string `json:"following_url"`
	GistsUrl          string `json:"gists_url"`
	StarredUrl        string `json:"starred_url"`
	SubscriptionsUrl  string `json:"subscriptions_url"`
	OrganizationsUrl  string `json:"organizations_url"`
	ReposUrl          string `json:"repos_url"`
	EventsUrl         string `json:"events_url"`
	ReceivedEventsUrl string `json:"received_events_url"`
	Type              string `json:"type"`
	SiteAdmin         bool   `json:"site_admin"`
}

type Repository struct {
	Id               int64     `json:"id"`
	Name             string    `json:"name"`
	FullName         string    `json:"full_name"`
	Owner            *User     `json:"owner"`
	Private          bool      `json:"private"`
	HtmlUrl          string    `json:"html_url"`
	Descriprion      string    `json:"description"`
	Fork             bool      `json:"fork"`
	Url              string    `json:"url"`
	ForksUrl         string    `json:"forks_url"`
	KeysUrl          string    `json:"keys_url"`
	CollaboratorsUrl string    `json:"collaborators_url"`
	TeamsUrl         string    `json:"teams_url"`
	HooksUrl         string    `json:"hooks_url"`
	IssueEventsUrl   string    `json:"issue_events_url"`
	EventsUrl        string    `json:"events_url"`
	AssigneesUrl     string    `json:"assignees_url"`
	BranchesUrl      string    `json:"branches_url"`
	TagsUrl          string    `json:"tags_url"`
	BlobsUrl         string    `json:"blobs_url"`
	GitTagsUrl       string    `json:"git_tags_url"`
	GitRefsUrl       string    `json:"git_refs_url"`
	TreesUrl         string    `json:"trees_url"`
	StatusesUrl      string    `json:"statuses_url"`
	LanguagesUrl     string    `json:"languages_url"`
	StargazersUrl    string    `json:"stargazers_url"`
	ContributorsUrl  string    `json:"contributors_url"`
	SubscribersUrl   string    `json:"subscribers_url"`
	SubscriptionUrl  string    `json:"subscription_url"`
	CommitsUrl       string    `json:"commits_url"`
	GitCommitsUrl    string    `json:"git_commits_url"`
	CommentsUrl      string    `json:"comments_url"`
	IssueCommentUrl  string    `json:"issue_comment_url"`
	ContentsUrl      string    `json:"contents_url"`
	CompareUrl       string    `json:"compare_url"`
	MergesUrl        string    `json:"merges_url"`
	ArchiveUrl       string    `json:"archive_url"`
	DownloadsUrl     string    `json:"downloads_url"`
	IssuesUrl        string    `json:"issues_url"`
	PullsUrl         string    `json:"pulls_url"`
	MilestonesUrl    string    `json:"milestones_url"`
	NotificationsUrl string    `json:"notifications_url"`
	LabelsUrl        string    `json:"labels_url"`
	ReleasesUrl      string    `json:"releases_url"`
	CreatedAt        int64     `json:"created_at"`
	UpdatedAt        time.Time `json:"updated_at"`
	PushedAt         int64     `json:"pushed_at"`
	GitUrl           string    `json:"git_url"`
	SshUrl           string    `json:"ssh_url"`
	CloneUrl         string    `json:"clone_url"`
	SvnUrl           string    `json:"svn_url"`
	Homepage         string    `json:"homepage"`
	Size             int       `json:"size"`
	StargazersCount  int       `json:"stargazers_count"`
	WatchersCount    int       `json:"watchers_count"`
	Language         string    `json:"language"`
	HasIssues        bool      `json:"has_issues"`
	HasDownloads     bool      `json:"has_downloads"`
	HasWiki          bool      `json:"has_wiki"`
	HasPages         bool      `json:"has_pages"`
	ForksCount       int       `json:"forks_count"`
	MirrorUrl        string    `json:"mirror_url"`
	OpenIssuesCount  int       `json:"open_issues_count"`
	Forks            int       `json:"forks"`
	OpenIssues       int       `json:"open_issues"`
	DefaultBranch    string    `json:"default_branch"`
}

type Comment struct {
	HtmlUrl   string    `json:"html_url"`
	Url       string    `json:"url"`
	Id        int64     `json:"id"`
	Body      string    `json:"body"`
	Path      string    `json:"path"`
	Position  int       `json:"position"`
	Line      int       `json:"line"`
	CommitId  string    `json:"commit_id"`
	User      *User     `json:"user"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

type Commit struct {
	Id        string     `json:"id"`
	Distinct  bool       `json:"distinct"`
	Message   string     `json:"message"`
	Timestamp time.Time  `json:"timestamp"`
	Url       string     `json:"url"`
	Author    *Committer `json:"author"`
	Committer *Committer `json:"committer"`
	Added     []string   `json:"added"`
	Removed   []string   `json:"removed"`
	Modified  []string   `json:"modified"`
}

type Hook struct {
	Id        int64     `json:"id"`
	Url       string    `json:"url"`
	TestUrl   string    `json:"test_url"`
	PingUrl   string    `json:"ping_url"`
	Name      string    `json:"name"`
	Events    []string  `json:"events"`
	Active    bool      `json:"active"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	Config    struct {
		Url         string `json:"url"`
		ContentType string `json:"content_type"`
	} `json:"config"`
}

type Label struct {
	Url   string `json:"url"`
	Name  string `json:"name"`
	Color string `json:"color"`
}

type Issue struct {
	Url          string      `json:"url"`
	LabelsUrl    string      `json:"labels_url"`
	CommentsUrl  string      `json:"comments_url"`
	EventsUrl    string      `json:"events_url"`
	HtmlUrl      string      `json:"html_url"`
	Id           int64       `json:"id"`
	Number       int64       `json:"number"`
	Title        string      `json:"title"`
	User         *User       `json:"user"`
	Labels       []*Label    `json:"labels"`
	State        string      `json:"state"`
	Locked       bool        `json:"locked"`
	Assignee     *User       `json:"assignee"`
	Milestone    interface{} `json:"milestone"`
	CommentCount int64       `json:"comments"`
	CreatedAt    time.Time   `json:"created_at"`
	UpdatedAt    time.Time   `json:"updated_at"`
	ClosedAt     *time.Time  `json:"closed_at"`
	Body         string      `json:"body"`
}

type PullRequest struct {
	Issue
	DiffUrl            string      `json:"diff_url"`
	PatchUrl           string      `json:"patch_url"`
	IssueUrl           string      `json:"issue_url"`
	MergedAt           *time.Time  `json:"merged_at"`
	MergeCommitSha     string      `json:"merge_commit_sha"`
	CommitsUrl         string      `json:"commits_url"`
	ReviewCommentsUrl  string      `json:"review_comments_url"`
	ReviewCommentUrl   string      `json:"review_comment_url"`
	StatusesUrl        string      `json:"statuses_url"`
	Head               interface{} `json:"head"` // not sure what this type is quite yet
	Base               interface{} `json:"base"` // same type as Head
	Merged             bool        `json:"merged"`
	Mergeable          bool        `json:"mergable"`
	MergableState      string      `json:"mergable_state"`
	MergedBy           *User       `json:"merged_by"`
	ReviewCommentCount int64       `json:"review_comments"`
	CommitCount        int64       `json:"commits"`
	Additions          int64       `json:"additions"`
	Deletions          int64       `json:"deletions"`
	ChangedFiles       int64       `json:"changed_files"`
}

type Committer struct {
	Name     string `json:"name"`
	Email    string `json:"email"`
	Username string `json:"username"`
}

type CommitCommentEvent struct {
	PayloadBase
	Comment *Comment `json:"comment"`
}

type CreateEvent struct {
	PayloadBase
	RefType      string `json:"ref_type"`
	Ref          string `json:"ref"`
	MasterBranch string `json:"master_branch"`
	Description  string `json:"description"`
}

type DeleteEvent struct {
	PayloadBase
	RefType string `json:"ref_type"`
	Ref     string `json:"ref"`
}

type DeploymentEvent struct {
	PayloadBase
	Deployment struct {
		Url           string      `json:"url"`
		Id            int64       `json:"id"`
		Sha           string      `json:"sha"`
		Ref           string      `json:"ref"`
		Task          string      `json:"task"`
		Payload       interface{} `json:"payload"`
		Environment   string      `json:"environment"`
		Description   string      `json:"description"`
		Creator       *User       `json:"creator"`
		CreatedAt     time.Time   `json:"created_at"`
		UpdatedAt     time.Time   `json:"updated_at"`
		StatusesUrl   string      `json:"statuses_url"`
		RepositoryUrl string      `json:"repository_url"`
	} `json:"deployment"`
}

type IssueCommentEvent struct {
	PayloadBase
	Action  *Issue `json:"issue"`
	Comment string `json:"comment"`
}

type PingEvent struct {
	PayloadBase
	Zen    string `json:"zen"`
	HookId int64  `json:"hook_id"`
	Hook   *Hook  `json:"hook"`
}

type PullRequestEvent struct {
	PayloadBase
	Action      string       `json:"action"`
	Number      int64        `json:"number"`
	PullRequest *PullRequest `json:"pull_request"`
	Label       *Label       `json:"label"`
}

type PushEvent struct {
	PayloadBase
	Ref        string     `json:"ref"`
	Before     string     `json:"before"`
	After      string     `json:"after"`
	Created    bool       `json:"created"`
	Deleted    bool       `json:"deleted"`
	Forced     bool       `json:"forced"`
	BaseRef    string     `json:"base_ref"`
	Compare    string     `json:"compare"`
	Commits    []*Commit  `json:"commits"`
	HeadCommit *Commit    `json:"head_commit"`
	Pusher     *Committer `json:"pusher"`
}
<|endoftext|>


<commit_before>package pdfhandler

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var (
	single = PDF{
		FileName: "OoPdfFormExample.pdf",
		Fields:   map[string]string{"Family Name Text Box": "Barsson"},
	}
	multi = []PDF{
		{
			FileName: "OoPdfFormExample.pdf",
			Fields:   map[string]string{"Family Name Text Box": "Barsson"},
		},
		{
			FileName: "OoPdfFormExample.pdf",
			Fields:   map[string]string{"Family Name Text Box": "Barsson"},
		},
	}
	multiWithContent = []PDF{
		{
			FileName: "OoPdfFormExample.pdf",
			Fields:   map[string]string{"Family Name Text Box": "Barsson"},
		},
		{
			FileName: "FakeName.pdf",
			Content:  testB64,
		},
	}
)

type testLogger struct {
	t *testing.T
}

func (l *testLogger) Debugf(format string, args ...interface{}) {
	l.t.Logf(format, args)
}
func (l *testLogger) Errorf(format string, args ...interface{}) {
	l.t.Logf(format, args)
}

func TestMain(m *testing.M) {
	pdfHandler, _ := New("./pdf-test")
	ts = httptest.NewServer(pdfHandler)
	defer ts.Close()
	os.Exit(m.Run())
}

func TestPDFStruct(t *testing.T) {
	_, err := single.render("./pdf-test")
	if err != nil {
		t.Fatal(err)
	}
}

func TestGet(t *testing.T) {
	req, err := http.NewRequest("GET", ts.URL, nil)
	req.Header.Set("Accept", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	assert.Equal(t, resp.StatusCode, http.StatusOK)
}

func TestPostSingle(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(single)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	req.Header.Set("Accept", "application/pdf")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	assert.Equal(t, resp.StatusCode, http.StatusOK)
}

func TestPostMulti(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multi)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	req.Header.Set("Accept", "application/pdf")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		var buf bytes.Buffer
		buf.ReadFrom(resp.Body)
		t.Fatalf("Got status %d and body %q", resp.StatusCode, buf.String())
	}
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/pdf")
}

func TestPostMultiFilename(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multi)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	req.Header.Set("Accept", "application/pdf")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Filename", "myfile")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		var buf bytes.Buffer
		buf.ReadFrom(resp.Body)
		t.Fatalf("Got status %d and body %q", resp.StatusCode, buf.String())
	}
	t.Logf("%q", resp.Header)
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/pdf")
	cd := resp.Header.Get("Content-Disposition")
	assert.Equal(t, cd, fmt.Sprintf("attachment; filename=%s", "myfile.pdf"))
}

func TestPostMultiZip(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multi)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Accept", "application/zip")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatal("Not working")
	}
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/zip")
}

func TestPostMultiContentZip(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multiWithContent)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Accept", "application/zip")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatal("Not working")
	}
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/zip")
	t.Logf("Response: %v", resp)
}

func TestInvalidContentType(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString(""))
	req.Header.Set("Content-Type", "something else")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
}

func TestInvalidAccept(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString(""))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "something else")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
}

func TestInvalidBody(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString(""))
	req.Header.Set("Accept", "application/zip")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
}

func TestInvalidMethod(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("DELETE", ts.URL, bytes.NewBufferString(""))
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusMethodNotAllowed)
}
<commit_msg>Fix printf<commit_after>package pdfhandler

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

var ts *httptest.Server
var (
	single = PDF{
		FileName: "OoPdfFormExample.pdf",
		Fields:   map[string]string{"Family Name Text Box": "Barsson"},
	}
	multi = []PDF{
		{
			FileName: "OoPdfFormExample.pdf",
			Fields:   map[string]string{"Family Name Text Box": "Barsson"},
		},
		{
			FileName: "OoPdfFormExample.pdf",
			Fields:   map[string]string{"Family Name Text Box": "Barsson"},
		},
	}
	multiWithContent = []PDF{
		{
			FileName: "OoPdfFormExample.pdf",
			Fields:   map[string]string{"Family Name Text Box": "Barsson"},
		},
		{
			FileName: "FakeName.pdf",
			Content:  testB64,
		},
	}
)

type testLogger struct {
	t *testing.T
}

func (l *testLogger) Debugf(format string, args ...interface{}) {
	l.t.Logf(format, args...)
}

func (l *testLogger) Errorf(format string, args ...interface{}) {
	l.t.Logf(format, args...)
}

func TestMain(m *testing.M) {
	pdfHandler, _ := New("./pdf-test")
	ts = httptest.NewServer(pdfHandler)
	defer ts.Close()
	os.Exit(m.Run())
}

func TestPDFStruct(t *testing.T) {
	_, err := single.render("./pdf-test")
	if err != nil {
		t.Fatal(err)
	}
}

func TestGet(t *testing.T) {
	req, err := http.NewRequest("GET", ts.URL, nil)
	req.Header.Set("Accept", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	assert.Equal(t, resp.StatusCode, http.StatusOK)
}

func TestPostSingle(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(single)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	req.Header.Set("Accept", "application/pdf")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	assert.Equal(t, resp.StatusCode, http.StatusOK)
}

func TestPostMulti(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multi)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	req.Header.Set("Accept", "application/pdf")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		var buf bytes.Buffer
		buf.ReadFrom(resp.Body)
		t.Fatalf("Got status %d and body %q", resp.StatusCode, buf.String())
	}
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/pdf")
}

func TestPostMultiFilename(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multi)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	req.Header.Set("Accept", "application/pdf")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Filename", "myfile")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		var buf bytes.Buffer
		buf.ReadFrom(resp.Body)
		t.Fatalf("Got status %d and body %q", resp.StatusCode, buf.String())
	}
	t.Logf("%q", resp.Header)
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/pdf")
	cd := resp.Header.Get("Content-Disposition")
	assert.Equal(t, cd, fmt.Sprintf("attachment; filename=%s", "myfile.pdf"))
}

func TestPostMultiZip(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multi)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Accept", "application/zip")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatal("Not working")
	}
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/zip")
}

func TestPostMultiContentZip(t *testing.T) {
	SetLogger(&testLogger{t})
	b, err := json.Marshal(multiWithContent)
	if err != nil {
		t.Fatal(err)
	}
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBuffer(b))
	if err != nil {
		t.Fatal(err)
	}
	req.Header.Set("Accept", "application/zip")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		t.Fatal("Not working")
	}
	ct := resp.Header.Get("Content-Type")
	assert.Equal(t, ct, "application/zip")
	t.Logf("Response: %v", resp)
}

func TestInvalidContentType(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString(""))
	req.Header.Set("Content-Type", "something else")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
}

func TestInvalidAccept(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString(""))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "something else")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
}

func TestInvalidBody(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString(""))
	req.Header.Set("Accept", "application/zip")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
}

func TestInvalidMethod(t *testing.T) {
	SetLogger(&testLogger{t})
	req, err := http.NewRequest("DELETE", ts.URL, bytes.NewBufferString(""))
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, resp.StatusCode, http.StatusMethodNotAllowed)
}
<|endoftext|>


<commit_before>package steps

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/howeyc/gopass"
	"github.com/mitchellh/multistep"
)

type StepAuthorizeGithub struct{}

type AuthorizeResponse struct {
	Token string `json:"token"`
}

// The authorization sequence, required for someone without a ~/.getconfig
func (*StepAuthorizeGithub) Run(state multistep.StateBag) multistep.StepAction {
	log.Println("Begin authorization sequence...")

	pwd := os.Getenv("PWD")
	fmt.Printf("Enter the path to store respositories (%s if blank): ", pwd)

	var path string
	_, err := fmt.Scanf("%s", &path)

	if path == "" {
		path = pwd
	}

	// Let the user know what will happen.
	fmt.Println(`
Your username and password will be used once to obtain a unique
authorization token from GitHub's API, which will be stored in
~/.gethubconfig.
`)

	// Asks the user for credentials, and then makes a request to the
	// GitHub API to get an authorization token to store in ~/.getconfig
	log.Println("Asking user for credentials...")

	fmt.Printf("Please enter your GitHub username: ")
	var username string
	_, err = fmt.Scanf("%s", &username)

	if err != nil {
		log.Println(err)
	}

	fmt.Printf("Please enter your personal access token (Skip if you do not use two factor authentication):")

	t := gopass.GetPasswd()
	token := string(t)

	if (token != "") {
		state.Put("token", token)
		state.Put("username", username)
		state.Put("path", path)

		resp, err := http.Get("https://api.github.com/user?access_token=" + token)

		if err != nil {
			fmt.Println(err)
		}

		defer resp.Body.Close()

		if resp.StatusCode != 200 {
			body, err := ioutil.ReadAll(resp.Body)

			if err != nil {
				fmt.Println(err)
			}

			fmt.Println(RED + "Uh oh, there was an error authenticating with GitHub. Here's what we got back:\n" + CLEAR)
			fmt.Println(string(body))
			return multistep.ActionHalt
		} else {
			fmt.Println(GREEN + "Succesfully authenticated with Github. Try running `gethub`." + CLEAR)
		}

		return multistep.ActionContinue
	}

	fmt.Printf("Please enter your GitHub password: ")

	p := gopass.GetPasswd()
	fmt.Printf("\n")

	password := string(p)

	client := &http.Client{}

	reqBody := strings.NewReader(`
        {"scopes":["repo"],
        "note":"gethub command line client",
        "note_url": "https://github.com/pearkes/gethub"}`)

	req, err := http.NewRequest("POST",
		"https://api.github.com/authorizations", reqBody)

	req.Header.Add("Content-Type", "application/json")
	req.SetBasicAuth(username, password)

	resp, err := client.Do(req)

	if err != nil {
		fmt.Println(err)
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Println(err)
	}

	dec := json.NewDecoder(bytes.NewReader(body))

	log.Println(dec)

	auth := AuthorizeResponse{}

	dec.Decode(&auth)

	log.Println(resp.Status)

	if resp.StatusCode != 201 {
		fmt.Println(RED + "Uh oh, there was an error authenticating with GitHub. Here's what we got back:\n" + CLEAR)
		fmt.Println(string(body))
		return multistep.ActionHalt
	} else {
		fmt.Println(GREEN + "Succesfully authenticated with Github. Try running `gethub`." + CLEAR)
	}

	log.Println(string(body))

	// Set the discovered credentials into the bag of state
	state.Put("token", auth.Token)
	state.Put("username", username)
	state.Put("path", path)

	log.Println(username)

	return multistep.ActionContinue
}

func (*StepAuthorizeGithub) Cleanup(multistep.StateBag) {}
<commit_msg>authorize: clarify language<commit_after>package steps

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/howeyc/gopass"
	"github.com/mitchellh/multistep"
)

type StepAuthorizeGithub struct{}

type AuthorizeResponse struct {
	Token string `json:"token"`
}

// The authorization sequence, required for someone without a ~/.getconfig
func (*StepAuthorizeGithub) Run(state multistep.StateBag) multistep.StepAction {
	log.Println("Begin authorization sequence...")

	pwd := os.Getenv("PWD")
	fmt.Printf("Enter the path to store respositories (%s if blank): ", pwd)

	var path string
	_, err := fmt.Scanf("%s", &path)

	if path == "" {
		path = pwd
	}

	// Let the user know what will happen.
	fmt.Println(`
Your username and password will be used once to obtain a unique
authorization token from GitHub's API, which will be stored in
~/.gethubconfig.
`)

	// Asks the user for credentials, and then makes a request to the
	// GitHub API to get an authorization token to store in ~/.getconfig
	log.Println("Asking user for credentials...")

	fmt.Printf("Please enter your GitHub username: ")
	var username string
	_, err = fmt.Scanf("%s", &username)

	if err != nil {
		log.Println(err)
	}

	fmt.Printf("If you use Two-Factor Authentication, enter a generated personal access token now. (Otherwise, press enter to skip and use a password): ")

	t := gopass.GetPasswd()
	token := string(t)

	if token != "" {
		state.Put("token", token)
		state.Put("username", username)
		state.Put("path", path)

		resp, err := http.Get("https://api.github.com/user?access_token=" + token)

		if err != nil {
			fmt.Println(err)
		}

		defer resp.Body.Close()

		if resp.StatusCode != 200 {
			body, err := ioutil.ReadAll(resp.Body)

			if err != nil {
				fmt.Println(err)
			}

			fmt.Println(RED + "Uh oh, there was an error authenticating with GitHub. Here's what we got back:\n" + CLEAR)
			fmt.Println(string(body))
			return multistep.ActionHalt
		} else {
			fmt.Println(GREEN + "Succesfully authenticated with Github. Try running `gethub`." + CLEAR)
		}

		return multistep.ActionContinue
	}

	fmt.Printf("Please enter your GitHub password: ")

	p := gopass.GetPasswd()
	fmt.Printf("\n")

	password := string(p)

	client := &http.Client{}

	reqBody := strings.NewReader(`
        {"scopes":["repo"],
        "note":"gethub command line client",
        "note_url": "https://github.com/pearkes/gethub"}`)

	req, err := http.NewRequest("POST",
		"https://api.github.com/authorizations", reqBody)

	req.Header.Add("Content-Type", "application/json")
	req.SetBasicAuth(username, password)

	resp, err := client.Do(req)

	if err != nil {
		fmt.Println(err)
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Println(err)
	}

	dec := json.NewDecoder(bytes.NewReader(body))

	log.Println(dec)

	auth := AuthorizeResponse{}

	dec.Decode(&auth)

	log.Println(resp.Status)

	if resp.StatusCode != 201 {
		fmt.Println(RED + "Uh oh, there was an error authenticating with GitHub. Here's what we got back:\n" + CLEAR)
		fmt.Println(string(body))
		return multistep.ActionHalt
	} else {
		fmt.Println(GREEN + "Succesfully authenticated with Github. Try running `gethub`." + CLEAR)
	}

	log.Println(string(body))

	// Set the discovered credentials into the bag of state
	state.Put("token", auth.Token)
	state.Put("username", username)
	state.Put("path", path)

	log.Println(username)

	return multistep.ActionContinue
}

func (*StepAuthorizeGithub) Cleanup(multistep.StateBag) {}
<|endoftext|>


<commit_before>package ogdatv21

import "testing"

func TestLoadOGDATV21SpecFile(t *testing.T) {
	if spec := loadogdatv21spec(ogdatv21specfile); spec != nil {
		if nspec := len(spec); nspec != 31 {
			t.Errorf("Should contain 31 records but found %d", nspec)
		} else {
			// t.Error("SUCCESS")
		}
	} else {
	  t.Log("Specification file %s not loaded", ogdatv21specfile)
	}
}
<commit_msg>go fmt<commit_after>package ogdatv21

import "testing"

func TestLoadOGDATV21SpecFile(t *testing.T) {
	if spec := loadogdatv21spec(ogdatv21specfile); spec != nil {
		if nspec := len(spec); nspec != 31 {
			t.Errorf("Should contain 31 records but found %d", nspec)
		} else {
			// t.Error("SUCCESS")
		}
	} else {
		t.Log("Specification file %s not loaded", ogdatv21specfile)
	}
}
<|endoftext|>


<commit_before>// +build !k8s

package k8s

import (
	"context"
	"fmt"

	"k8s.io/client-go/rest"
)

func getEmbedded(ctx context.Context) (context.Context, *rest.Config, error) {
	return ctx, nil, fmt.Errorf("embedded support is not compiled in, rebuild with -tags k8s")
}
<commit_msg>Fix method signature for the non-embedded verison<commit_after>// +build !k8s

package k8s

import (
	"context"
	"fmt"

	"k8s.io/client-go/rest"
)

func getEmbedded(ctx context.Context) (bool, context.Context, *rest.Config, error) {
	return false, ctx, nil, fmt.Errorf("embedded support is not compiled in, rebuild with -tags k8s")
}
<|endoftext|>


<commit_before>// peekaboo registers the current machine (or provided IP) to a Rackspace load
// balancer, enabling (or disabling) itself.

package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"strconv"
	"strings"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/pagination"
	"github.com/rackspace/gophercloud/rackspace"
	"github.com/rackspace/gophercloud/rackspace/lb/v1/lbs"
	"github.com/rackspace/gophercloud/rackspace/lb/v1/nodes"
)

// waitForReady waits for the load balancer with id loadBalancerID to become
// ACTIVE. It times out after 60 seconds and streamrolls on ahead.
func waitForReady(client *gophercloud.ServiceClient, loadBalancerID int, timeout int) {

	// Ensure the load balancer is ready
	gophercloud.WaitFor(timeout, func() (bool, error) {
		lb, err := lbs.Get(client, loadBalancerID).Extract()
		if err != nil {
			return false, err
		}

		if lb.Status != lbs.ACTIVE {
			// It has not yet reached ACTIVE
			return false, nil
		}

		// It has reached ACTIVE
		return true, nil
	})

}

// findNodeByIPPort gets a load balancer node by IP and Port
func findNodeByIPPort(
	client *gophercloud.ServiceClient,
	loadBalancerID int,
	address string,
	port int,
) *nodes.Node {

	// nil until found
	var found *nodes.Node

	pager := nodes.List(client, loadBalancerID, nil)

	pager.EachPage(func(page pagination.Page) (bool, error) {
		lbNodes, err := nodes.ExtractNodes(page)
		if err != nil {
			log.Fatalf("Error during paging load balancer: %v", err)
		}

		for _, trialNode := range lbNodes {
			if trialNode.Address == address && trialNode.Port == port {
				found = &trialNode
				return false, nil
			}

		}

		return true, nil
	})

	return found
}

// getIP tries to best guess what IP to work with
//
// Precedence for IP is determined by
//  - ipPtr being non-nil (peekaboo's -ip flag)
//  - Service Net Environment variable $RAX_SERVICENET_IPV4
//  - Public Net Environment variable $RAX_PUBLICNET_IPV4
//  - Gleaning a 10 dot out of the network interfaces (likely service net)
//  - eth0
func getIP(ipPtr *string) (string, error) {

	serviceNetIPv4 := os.Getenv("RAX_SERVICENET_IPV4")
	publicNetIPv4 := os.Getenv("RAX_PUBLICNET_IPV4")

	switch {
	case *ipPtr != "":
		return *ipPtr, nil
	case serviceNetIPv4 != "":
		return serviceNetIPv4, nil
	case publicNetIPv4 != "":
		return publicNetIPv4, nil
	}

	addrs, err := net.InterfaceAddrs()

	if err != nil {
		return "", err
	}

	for _, addr := range addrs {
		cidr := addr.String()
		ip := strings.Split(cidr, "/")[0]

		if strings.HasPrefix(ip, "10.") {
			return ip, nil
		}
	}

	// Find eth0
	eth0, err := net.InterfaceByName("eth0")
	if err != nil {
		return "", fmt.Errorf("trouble finding eth0: %v", err)
	}

	addrs, err = eth0.Addrs()
	if err != nil {
		return "", err
	}

	for _, addr := range addrs {
		cidr := addr.String()
		ip := strings.Split(cidr, "/")[0]

		// Pick out IPv4
		if strings.ContainsRune(ip, '.') {
			return ip, err
		}
	}

	return "", errors.New("unable to determine an IP for load balancing")

}

func main() {
	var err error

	disabledPtr := flag.Bool("disable", false, "Disable the node on the load balancer")
	drainingPtr := flag.Bool("drain", false, "Drain the node from the load balancer")
	deletePtr := flag.Bool("delete", false, "Delete the node from the load balancer")

	//NOTE: peekaboo allows setting the IP by using
	//        - environment variables: RAX_SERVICENET_IPV4 or RAX_PUBLICNET_IPV4
	//        - finding an ip on the system starting with 10. (service net)
	//        - locating the eth0 interface
	//        - providing an ip as a flag is fine too and will take precedence
	ipPtr := flag.String("ip", "", "IP address to register/deregister on the load balancer")
	timeout := flag.Int("timeout", 60, "Seconds to wait for the load balancer to become available")

	flag.Parse()

	username := os.Getenv("OS_USERNAME")
	APIKey := os.Getenv("OS_PASSWORD")
	region := os.Getenv("OS_REGION_NAME")

	if username == "" || APIKey == "" || region == "" {
		log.Fatalf("One or more of $OS_USERNAME, $OS_PASSWORD, and $OS_REGION_NAME not set")
	}

	// These get converted into integers later
	strLoadBalancerID := os.Getenv("LOAD_BALANCER_ID")
	strAppPort := os.Getenv("APP_PORT")

	/**
	 * Retrieve port for load balancer's node, defaulting to 80
	 */
	var nodePort = 80

	if strAppPort == "" {
		log.Printf("$APP_PORT not set, defaulting to 80")
	} else {
		nodePort, err = strconv.Atoi(strAppPort)
		if err != nil {
			log.Fatalf("Unable to parse integer from $APP_PORT: %v\n", strAppPort)
		}
	}

	/**
	 * Determine the IP Address for the load balancer's node
	 */
	nodeAddress, err := getIP(ipPtr)
	if err != nil {
		log.Fatalln(err)
	}

	/**
	 * Retrive Load Balancer ID
	 */
	if strLoadBalancerID == "" {
		log.Fatalln("$LOAD_BALANCER_ID must be set")
	}
	loadBalancerID, err := strconv.Atoi(strLoadBalancerID)
	if err != nil {
		log.Fatalf("$LOAD_BALANCER_ID not an integer: %v\n", loadBalancerID)
	}

	provider, err := rackspace.AuthenticatedClient(gophercloud.AuthOptions{
		Username: username,
		APIKey:   APIKey,
	})

	if err != nil {
		log.Fatalf("Trouble authenticating to Rackspace: %v\n", err)
	}

	client, err := rackspace.NewLBV1(provider, gophercloud.EndpointOpts{
		Region: region,
	})

	if err != nil {
		log.Fatalf("Creating load balancer client in %v failed: %v\n", region, err)
	}

	waitForReady(client, loadBalancerID, *timeout)

	nodePtr := findNodeByIPPort(client, loadBalancerID, nodeAddress, nodePort)

	if !*deletePtr {
		// Transition an existing node to the desired state. Create a new node if one doesn't exist
		// already.

		condition := nodes.ENABLED
		if *disabledPtr {
			condition = nodes.DISABLED
		} else if *drainingPtr {
			//TODO: Watch the interface on the right process/container to determine
			//      when connections have dropped, and set to DISABLED
			condition = nodes.DRAINING
		}

		log.Printf("Setting %v:%v to be %v on load balancer %v\n",
			nodeAddress, nodePort,
			condition,
			loadBalancerID)

		if nodePtr != nil {
			log.Printf("Updating existing node %v", *nodePtr)

			opts := nodes.UpdateOpts{
				Condition: condition,
			}

			updateResult := nodes.Update(client, loadBalancerID, nodePtr.ID, opts)
			err = updateResult.ExtractErr()
			if err != nil {
				log.Panicf("Updating node failed: %v", err)
			}

		} else {
			log.Printf("Creating new node")
			opts := nodes.CreateOpts{
				nodes.CreateOpt{
					Address:   nodeAddress,
					Port:      nodePort,
					Condition: condition,
				},
			}

			nodeList, err := nodes.Create(client, loadBalancerID, opts).ExtractNodes()
			if err != nil {
				log.Fatalf("Error enumerating created nodes: %v", err)
			}
			if len(nodeList) != 1 {
				log.Panicf("Something went terribly wrong on node creation: %#v\n", nodeList)
			}
			nodePtr = &nodeList[0]
		}

		waitForReady(client, loadBalancerID, *timeout)

		// After update, get the version of the node Rackspace has
		result := nodes.Get(client, loadBalancerID, nodePtr.ID)
		nodePtr, err = result.Extract()
		if err != nil {
			log.Panicln(err)
		}

		log.Printf("Final node state: %v\n", *nodePtr)
	} else {
		// Delete an existing node from the balancer. Do nothing if no node exists.
		if nodePtr != nil {
			log.Printf("Deleting existing node %v", *nodePtr)

			err := nodes.Delete(client, loadBalancerID, nodePtr.ID).ExtractErr()
			if err != nil {
				log.Fatalf("Unable to delete node %d: %v", nodePtr.ID, err)
			}

			waitForReady(client, loadBalancerID, *timeout)
			log.Println("Final node state: Deleted")
		} else {
			log.Println("Node is already gone. Hooray?")
		}
	}

}
<commit_msg>Implement a backoff function.<commit_after>// peekaboo registers the current machine (or provided IP) to a Rackspace load
// balancer, enabling (or disabling) itself.

package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/pagination"
	"github.com/rackspace/gophercloud/rackspace"
	"github.com/rackspace/gophercloud/rackspace/lb/v1/lbs"
	"github.com/rackspace/gophercloud/rackspace/lb/v1/nodes"
)

// backoff executes a closure that performs a CLB operation and returns its error condition. If
// a 422 (immutable entity) error is returned, wait timeout seconds perturbed by a small random
// amount and try again. If a non-422 error is returned, return that error immediately. If the
// operation is successful, return nil.
func backoff(timeout int, action func() error) error {
	err := action()
	for err != nil {
		err = action()

		if casted, ok := err.(*gophercloud.UnexpectedResponseCodeError); ok {
			if casted.Actual == 422 {
				// Immutable load balancer.
				// Sleep and retry.
				base := time.Duration(timeout) * time.Second
				delta := time.Duration(-1000+rand.Intn(2000)) * time.Millisecond
				d := base + delta

				log.Printf("Load balancer is immutable. Sleeping for %s.", d)
				time.Sleep(d)
			} else {
				// Non-422 error.
				return err
			}
		} else {
			// Non-HTTP error
			return err
		}
	}
	return nil
}

// waitForReady waits for the load balancer with id loadBalancerID to become
// ACTIVE. It times out after 60 seconds and streamrolls on ahead.
func waitForReady(client *gophercloud.ServiceClient, loadBalancerID int, timeout int) {

	// Ensure the load balancer is ready
	gophercloud.WaitFor(timeout, func() (bool, error) {
		lb, err := lbs.Get(client, loadBalancerID).Extract()
		if err != nil {
			return false, err
		}

		if lb.Status != lbs.ACTIVE {
			// It has not yet reached ACTIVE
			return false, nil
		}

		// It has reached ACTIVE
		return true, nil
	})

}

// findNodeByIPPort gets a load balancer node by IP and Port
func findNodeByIPPort(
	client *gophercloud.ServiceClient,
	loadBalancerID int,
	address string,
	port int,
) *nodes.Node {

	// nil until found
	var found *nodes.Node

	pager := nodes.List(client, loadBalancerID, nil)

	pager.EachPage(func(page pagination.Page) (bool, error) {
		lbNodes, err := nodes.ExtractNodes(page)
		if err != nil {
			log.Fatalf("Error during paging load balancer: %v", err)
		}

		for _, trialNode := range lbNodes {
			if trialNode.Address == address && trialNode.Port == port {
				found = &trialNode
				return false, nil
			}

		}

		return true, nil
	})

	return found
}

// getIP tries to best guess what IP to work with
//
// Precedence for IP is determined by
//  - ipPtr being non-nil (peekaboo's -ip flag)
//  - Service Net Environment variable $RAX_SERVICENET_IPV4
//  - Public Net Environment variable $RAX_PUBLICNET_IPV4
//  - Gleaning a 10 dot out of the network interfaces (likely service net)
//  - eth0
func getIP(ipPtr *string) (string, error) {

	serviceNetIPv4 := os.Getenv("RAX_SERVICENET_IPV4")
	publicNetIPv4 := os.Getenv("RAX_PUBLICNET_IPV4")

	switch {
	case *ipPtr != "":
		return *ipPtr, nil
	case serviceNetIPv4 != "":
		return serviceNetIPv4, nil
	case publicNetIPv4 != "":
		return publicNetIPv4, nil
	}

	addrs, err := net.InterfaceAddrs()

	if err != nil {
		return "", err
	}

	for _, addr := range addrs {
		cidr := addr.String()
		ip := strings.Split(cidr, "/")[0]

		if strings.HasPrefix(ip, "10.") {
			return ip, nil
		}
	}

	// Find eth0
	eth0, err := net.InterfaceByName("eth0")
	if err != nil {
		return "", fmt.Errorf("trouble finding eth0: %v", err)
	}

	addrs, err = eth0.Addrs()
	if err != nil {
		return "", err
	}

	for _, addr := range addrs {
		cidr := addr.String()
		ip := strings.Split(cidr, "/")[0]

		// Pick out IPv4
		if strings.ContainsRune(ip, '.') {
			return ip, err
		}
	}

	return "", errors.New("unable to determine an IP for load balancing")

}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	var err error

	disabledPtr := flag.Bool("disable", false, "Disable the node on the load balancer")
	drainingPtr := flag.Bool("drain", false, "Drain the node from the load balancer")
	deletePtr := flag.Bool("delete", false, "Delete the node from the load balancer")

	//NOTE: peekaboo allows setting the IP by using
	//        - environment variables: RAX_SERVICENET_IPV4 or RAX_PUBLICNET_IPV4
	//        - finding an ip on the system starting with 10. (service net)
	//        - locating the eth0 interface
	//        - providing an ip as a flag is fine too and will take precedence
	ipPtr := flag.String("ip", "", "IP address to register/deregister on the load balancer")
	timeout := flag.Int("timeout", 60, "Seconds to wait for the load balancer to become available")

	flag.Parse()

	username := os.Getenv("OS_USERNAME")
	APIKey := os.Getenv("OS_PASSWORD")
	region := os.Getenv("OS_REGION_NAME")

	if username == "" || APIKey == "" || region == "" {
		log.Fatalf("One or more of $OS_USERNAME, $OS_PASSWORD, and $OS_REGION_NAME not set")
	}

	// These get converted into integers later
	strLoadBalancerID := os.Getenv("LOAD_BALANCER_ID")
	strAppPort := os.Getenv("APP_PORT")

	/**
	 * Retrieve port for load balancer's node, defaulting to 80
	 */
	var nodePort = 80

	if strAppPort == "" {
		log.Printf("$APP_PORT not set, defaulting to 80")
	} else {
		nodePort, err = strconv.Atoi(strAppPort)
		if err != nil {
			log.Fatalf("Unable to parse integer from $APP_PORT: %v\n", strAppPort)
		}
	}

	/**
	 * Determine the IP Address for the load balancer's node
	 */
	nodeAddress, err := getIP(ipPtr)
	if err != nil {
		log.Fatalln(err)
	}

	/**
	 * Retrive Load Balancer ID
	 */
	if strLoadBalancerID == "" {
		log.Fatalln("$LOAD_BALANCER_ID must be set")
	}
	loadBalancerID, err := strconv.Atoi(strLoadBalancerID)
	if err != nil {
		log.Fatalf("$LOAD_BALANCER_ID not an integer: %v\n", loadBalancerID)
	}

	provider, err := rackspace.AuthenticatedClient(gophercloud.AuthOptions{
		Username: username,
		APIKey:   APIKey,
	})

	if err != nil {
		log.Fatalf("Trouble authenticating to Rackspace: %v\n", err)
	}

	client, err := rackspace.NewLBV1(provider, gophercloud.EndpointOpts{
		Region: region,
	})

	if err != nil {
		log.Fatalf("Creating load balancer client in %v failed: %v\n", region, err)
	}

	waitForReady(client, loadBalancerID, *timeout)

	nodePtr := findNodeByIPPort(client, loadBalancerID, nodeAddress, nodePort)

	if !*deletePtr {
		// Transition an existing node to the desired state. Create a new node if one doesn't exist
		// already.

		condition := nodes.ENABLED
		if *disabledPtr {
			condition = nodes.DISABLED
		} else if *drainingPtr {
			//TODO: Watch the interface on the right process/container to determine
			//      when connections have dropped, and set to DISABLED
			condition = nodes.DRAINING
		}

		log.Printf("Setting %v:%v to be %v on load balancer %v\n",
			nodeAddress, nodePort,
			condition,
			loadBalancerID)

		if nodePtr != nil {
			log.Printf("Updating existing node %v", *nodePtr)

			opts := nodes.UpdateOpts{
				Condition: condition,
			}

			updateResult := nodes.Update(client, loadBalancerID, nodePtr.ID, opts)
			err = updateResult.ExtractErr()
			if err != nil {
				log.Panicf("Updating node failed: %v", err)
			}

		} else {
			log.Printf("Creating new node")
			opts := nodes.CreateOpts{
				nodes.CreateOpt{
					Address:   nodeAddress,
					Port:      nodePort,
					Condition: condition,
				},
			}

			nodeList, err := nodes.Create(client, loadBalancerID, opts).ExtractNodes()
			if err != nil {
				log.Fatalf("Error enumerating created nodes: %v", err)
			}
			if len(nodeList) != 1 {
				log.Panicf("Something went terribly wrong on node creation: %#v\n", nodeList)
			}
			nodePtr = &nodeList[0]
		}

		waitForReady(client, loadBalancerID, *timeout)

		// After update, get the version of the node Rackspace has
		result := nodes.Get(client, loadBalancerID, nodePtr.ID)
		nodePtr, err = result.Extract()
		if err != nil {
			log.Panicln(err)
		}

		log.Printf("Final node state: %v\n", *nodePtr)
	} else {
		// Delete an existing node from the balancer. Do nothing if no node exists.
		if nodePtr != nil {
			log.Printf("Deleting existing node %v", *nodePtr)

			err := nodes.Delete(client, loadBalancerID, nodePtr.ID).ExtractErr()
			if err != nil {
				log.Fatalf("Unable to delete node %d: %v", nodePtr.ID, err)
			}

			waitForReady(client, loadBalancerID, *timeout)
			log.Println("Final node state: Deleted")
		} else {
			log.Println("Node is already gone. Hooray?")
		}
	}

}
<|endoftext|>


<commit_before>// Go Concurrency Pattern: Pipelines and Cancellation
//
package main

import (
    "crypto/md5"
    "errors"
    "flag"
    "fmt"
    "io/ioutil"
    "os"
    "path/filepath"
    "sort"
    "sync"
    "time"
)

var workType *int = flag.Int("t", 0, "FileDigester Type: 0, 1, 2, or 3")

// A result is the product of reading and summing a file using MD5.
type result struct {
    path string
    sum  [md5.Size]byte
    err  error
}

////////////////////////////////////////////////////////////////////////////////

type IFileDigester interface {
    MD5All(string) (map[string][md5.Size]byte, error)
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester struct {
}

func (p FileDigester) walk(root string, files *[]string) error {
    infos, err := ioutil.ReadDir(root)
    if err != nil { return err }
    for _, info := range infos {
        switch {
        case info.Mode().IsRegular():
            *files = append(*files, filepath.Join(root, info.Name()))
        case info.Mode().IsDir():
            if err := p.walk(filepath.Join(root, info.Name()), files); err != nil {
                return err
            }
        }
    }
    return nil
}

func (p FileDigester) collect(root string) ([]string, error) {
    files := make([]string, 0)
    err := p.walk(root, &files)
    return files, err
}

func (p FileDigester) md5Worker(files []string, cidx <-chan int, done <-chan struct{}, res *[]result) {
    for {
        select {
        case idx:= <-cidx:
            data, err := ioutil.ReadFile(files[idx])
            (*res)[idx] = result{files[idx], md5.Sum(data), err}
        case <-done:
            return
        }
    }
}

func (p FileDigester) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()

    files, err := p.collect(root)
    if err != nil { return nil, err }

    n := len(files)
    cidx := make(chan int)
    done := make(chan struct{})
    res := make([]result, n)

    for i := 0; i < n; i++ { go p.md5Worker(files, cidx, done, &res) }
    for i := 0; i < n; i++ { cidx <- i }
    for i := 0; i < n; i++ { done <- struct{}{} }

    m := make(map[string][md5.Size]byte)
    for _, r := range res {
        if r.err != nil {
            return nil, r.err
        }
        m[r.path] = r.sum
    }
    return m, nil
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester1 struct {
}

// sumFiles starts goroutines to walk the directory tree at root and digest each
// regular file.  These goroutines send the results of the digests on the result
// channel and send the result of the walk on the error channel.  If done is
// closed, sumFiles abandons its work.
func (p FileDigester1) sumFiles(done <-chan struct{}, root string) (<-chan result, <-chan error) {
    // For each regular file, start a goroutine that sums the file and sends
    // the result on c.  Send the result of the walk on errc.
    c := make(chan result)
    errc := make(chan error, 1)
    go func() { // HL
        var wg sync.WaitGroup
        err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
            if err != nil {
                return err
            }
            if !info.Mode().IsRegular() {
                return nil
            }
            wg.Add(1)
            go func() { // HL
                data, err := ioutil.ReadFile(path)
                select {
                case c <- result{path, md5.Sum(data), err}: // HL
                case <-done: // HL
                }
                wg.Done()
            }()
            // Abort the walk if done is closed.
            select {
            case <-done: // HL
                return errors.New("walk canceled")
            default:
                return nil
            }
        })
        // Walk has returned, so all calls to wg.Add are done.  Start a
        // goroutine to close c once all the sends are done.
        go func() { // HL
            wg.Wait()
            close(c) // HL
        }()
        // No select needed here, since errc is buffered.
        errc <- err // HL
    }()
    return c, errc
}

// MD5All reads all the files in the file tree rooted at root and returns a map
// from file path to the MD5 sum of the file's contents.  If the directory walk
// fails or any read operation fails, MD5All returns an error.  In that case,
// MD5All does not wait for inflight read operations to complete.
func (p FileDigester1) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester1.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()
    // MD5All closes the done channel when it returns; it may do so before
    // receiving all the values from c and errc.
    done := make(chan struct{}) // HLdone
    defer close(done)           // HLdone

    c, errc := p.sumFiles(done, root) // HLdone

    m := make(map[string][md5.Size]byte)
    for r := range c { // HLrange
        if r.err != nil {
            return nil, r.err
        }
        m[r.path] = r.sum
    }
    if err := <-errc; err != nil {
        return nil, err
    }
    return m, nil
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester2 struct {
}

// walkFiles starts a goroutine to walk the directory tree at root and send the
// path of each regular file on the string channel.  It sends the result of the
// walk on the error channel.  If done is closed, walkFiles abandons its work.
func (p FileDigester2) walkFiles(done <-chan struct{}, root string) (<-chan string, <-chan error) {
    paths := make(chan string)
    errc := make(chan error, 1)
    go func() { // HL
        // Close the paths channel after Walk returns.
        defer close(paths) // HL
        // No select needed for this send, since errc is buffered.
        errc <- filepath.Walk(root, func(path string, info os.FileInfo, err error) error { // HL
            if err != nil {
                return err
            }
            if !info.Mode().IsRegular() {
                return nil
            }
            select {
            case paths <- path: // HL
            case <-done: // HL
                return errors.New("walk canceled")
            }
            return nil
        })
    }()
    return paths, errc
}

// digester reads path names from paths and sends digests of the corresponding
// files on c until either paths or done is closed.
func (p FileDigester2) digester(done <-chan struct{}, paths <-chan string, c chan<- result) {
    for path := range paths { // HLpaths
        data, err := ioutil.ReadFile(path)
        select {
        case c <- result{path, md5.Sum(data), err}:
        case <-done:
            return
        }
    }
}

// MD5All reads all the files in the file tree rooted at root and returns a map
// from file path to the MD5 sum of the file's contents.  If the directory walk
// fails or any read operation fails, MD5All returns an error.  In that case,
// MD5All does not wait for inflight read operations to complete.
func (p FileDigester2) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester2.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()
    // MD5All closes the done channel when it returns; it may do so before
    // receiving all the values from c and errc.
    done := make(chan struct{})
    defer close(done)

    paths, errc := p.walkFiles(done, root)

    // Start a fixed number of goroutines to read and digest files.
    c := make(chan result) // HLc
    var wg sync.WaitGroup
    const numDigesters = 20
    wg.Add(numDigesters)
    for i := 0; i < numDigesters; i++ {
        go func() {
            p.digester(done, paths, c) // HLc
            wg.Done()
        }()
    }
    go func() {
        wg.Wait()
        close(c) // HLc
    }()
    // End of pipeline. OMIT

    m := make(map[string][md5.Size]byte)
    for r := range c {
        if r.err != nil {
            return nil, r.err
        }
        m[r.path] = r.sum
    }
    // Check whether the Walk failed.
    if err := <-errc; err != nil { // HLerrc
        return nil, err
    }
    return m, nil
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester3 struct {
}

func (p FileDigester3) walk(root string, cpath chan<- string) <-chan struct{} {
    done := make(chan struct{})
    go func() {
        if infos, err := ioutil.ReadDir(root); err == nil {
            for _, info := range infos {
                switch {
                case info.Mode().IsRegular():
                    cpath <- filepath.Join(root, info.Name())
                case info.Mode().IsDir():
                    <-p.walk(filepath.Join(root, info.Name()), cpath)
                }
            }
        }
        done <- struct{}{}
    }()
    return done
}

func (p FileDigester3) collect(root string) (<-chan string, <-chan struct{}) {
    cpath := make(chan string)
    return cpath, p.walk(root, cpath)
}

func (p FileDigester3) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester3.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()

    cpath, done := p.collect(root)
    m := make(map[string][md5.Size]byte)
    for {
        select {
        case path := <-cpath:
            data, err := ioutil.ReadFile(path)
            if err != nil { return nil, err }
            m[path] = md5.Sum(data)
        case <-done:
            return m, nil
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

func main() {
    flag.Parse()

    // Calculate the MD5 sum of all files under the specified directory,
    // then print the results sorted by path name.
    var p IFileDigester
    switch *workType {
    case 1:
        p = &FileDigester1{}
    case 2:
        p = &FileDigester2{}
    case 3:
        p = &FileDigester3{}
    default:
        p = &FileDigester{}
    }

    root := "."
    if flag.NArg() > 0 {
        root = flag.Arg(0)
    }

    m, err := p.MD5All(root)
    if err != nil {
        fmt.Println(err)
        return
    }
    var paths []string
    for path := range m {
        paths = append(paths, path)
    }
    sort.Strings(paths)
    for _, path := range paths {
        fmt.Printf("%x  %s\n", m[path], path)
    }
}
<commit_msg>return error chan for FileDigester3 walk()<commit_after>// Go Concurrency Pattern: Pipelines and Cancellation
//
package main

import (
    "crypto/md5"
    "errors"
    "flag"
    "fmt"
    "io/ioutil"
    "os"
    "path/filepath"
    "sort"
    "sync"
    "time"
)

var workType *int = flag.Int("t", 0, "FileDigester Type: 0, 1, 2, or 3")

// A result is the product of reading and summing a file using MD5.
type result struct {
    path string
    sum  [md5.Size]byte
    err  error
}

////////////////////////////////////////////////////////////////////////////////

type IFileDigester interface {
    MD5All(string) (map[string][md5.Size]byte, error)
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester struct {
}

func (p FileDigester) walk(root string, files *[]string) error {
    infos, err := ioutil.ReadDir(root)
    if err != nil { return err }
    for _, info := range infos {
        switch {
        case info.Mode().IsRegular():
            *files = append(*files, filepath.Join(root, info.Name()))
        case info.Mode().IsDir():
            if err := p.walk(filepath.Join(root, info.Name()), files); err != nil {
                return err
            }
        }
    }
    return nil
}

func (p FileDigester) collect(root string) ([]string, error) {
    files := make([]string, 0)
    err := p.walk(root, &files)
    return files, err
}

func (p FileDigester) md5Worker(files []string, cidx <-chan int, done <-chan struct{}, res *[]result) {
    for {
        select {
        case idx:= <-cidx:
            data, err := ioutil.ReadFile(files[idx])
            (*res)[idx] = result{files[idx], md5.Sum(data), err}
        case <-done:
            return
        }
    }
}

func (p FileDigester) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()

    files, err := p.collect(root)
    if err != nil { return nil, err }

    n := len(files)
    cidx := make(chan int)
    done := make(chan struct{})
    res := make([]result, n)

    for i := 0; i < n; i++ { go p.md5Worker(files, cidx, done, &res) }
    for i := 0; i < n; i++ { cidx <- i }
    for i := 0; i < n; i++ { done <- struct{}{} }

    m := make(map[string][md5.Size]byte)
    for _, r := range res {
        if r.err != nil {
            return nil, r.err
        }
        m[r.path] = r.sum
    }
    return m, nil
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester1 struct {
}

// sumFiles starts goroutines to walk the directory tree at root and digest each
// regular file.  These goroutines send the results of the digests on the result
// channel and send the result of the walk on the error channel.  If done is
// closed, sumFiles abandons its work.
func (p FileDigester1) sumFiles(done <-chan struct{}, root string) (<-chan result, <-chan error) {
    // For each regular file, start a goroutine that sums the file and sends
    // the result on c.  Send the result of the walk on errc.
    c := make(chan result)
    errc := make(chan error, 1)
    go func() { // HL
        var wg sync.WaitGroup
        err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
            if err != nil {
                return err
            }
            if !info.Mode().IsRegular() {
                return nil
            }
            wg.Add(1)
            go func() { // HL
                data, err := ioutil.ReadFile(path)
                select {
                case c <- result{path, md5.Sum(data), err}: // HL
                case <-done: // HL
                }
                wg.Done()
            }()
            // Abort the walk if done is closed.
            select {
            case <-done: // HL
                return errors.New("walk canceled")
            default:
                return nil
            }
        })
        // Walk has returned, so all calls to wg.Add are done.  Start a
        // goroutine to close c once all the sends are done.
        go func() { // HL
            wg.Wait()
            close(c) // HL
        }()
        // No select needed here, since errc is buffered.
        errc <- err // HL
    }()
    return c, errc
}

// MD5All reads all the files in the file tree rooted at root and returns a map
// from file path to the MD5 sum of the file's contents.  If the directory walk
// fails or any read operation fails, MD5All returns an error.  In that case,
// MD5All does not wait for inflight read operations to complete.
func (p FileDigester1) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester1.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()
    // MD5All closes the done channel when it returns; it may do so before
    // receiving all the values from c and errc.
    done := make(chan struct{}) // HLdone
    defer close(done)           // HLdone

    c, errc := p.sumFiles(done, root) // HLdone

    m := make(map[string][md5.Size]byte)
    for r := range c { // HLrange
        if r.err != nil {
            return nil, r.err
        }
        m[r.path] = r.sum
    }
    if err := <-errc; err != nil {
        return nil, err
    }
    return m, nil
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester2 struct {
}

// walkFiles starts a goroutine to walk the directory tree at root and send the
// path of each regular file on the string channel.  It sends the result of the
// walk on the error channel.  If done is closed, walkFiles abandons its work.
func (p FileDigester2) walkFiles(done <-chan struct{}, root string) (<-chan string, <-chan error) {
    paths := make(chan string)
    errc := make(chan error, 1)
    go func() { // HL
        // Close the paths channel after Walk returns.
        defer close(paths) // HL
        // No select needed for this send, since errc is buffered.
        errc <- filepath.Walk(root, func(path string, info os.FileInfo, err error) error { // HL
            if err != nil {
                return err
            }
            if !info.Mode().IsRegular() {
                return nil
            }
            select {
            case paths <- path: // HL
            case <-done: // HL
                return errors.New("walk canceled")
            }
            return nil
        })
    }()
    return paths, errc
}

// digester reads path names from paths and sends digests of the corresponding
// files on c until either paths or done is closed.
func (p FileDigester2) digester(done <-chan struct{}, paths <-chan string, c chan<- result) {
    for path := range paths { // HLpaths
        data, err := ioutil.ReadFile(path)
        select {
        case c <- result{path, md5.Sum(data), err}:
        case <-done:
            return
        }
    }
}

// MD5All reads all the files in the file tree rooted at root and returns a map
// from file path to the MD5 sum of the file's contents.  If the directory walk
// fails or any read operation fails, MD5All returns an error.  In that case,
// MD5All does not wait for inflight read operations to complete.
func (p FileDigester2) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester2.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()
    // MD5All closes the done channel when it returns; it may do so before
    // receiving all the values from c and errc.
    done := make(chan struct{})
    defer close(done)

    paths, errc := p.walkFiles(done, root)

    // Start a fixed number of goroutines to read and digest files.
    c := make(chan result) // HLc
    var wg sync.WaitGroup
    const numDigesters = 20
    wg.Add(numDigesters)
    for i := 0; i < numDigesters; i++ {
        go func() {
            p.digester(done, paths, c) // HLc
            wg.Done()
        }()
    }
    go func() {
        wg.Wait()
        close(c) // HLc
    }()
    // End of pipeline. OMIT

    m := make(map[string][md5.Size]byte)
    for r := range c {
        if r.err != nil {
            return nil, r.err
        }
        m[r.path] = r.sum
    }
    // Check whether the Walk failed.
    if err := <-errc; err != nil { // HLerrc
        return nil, err
    }
    return m, nil
}

////////////////////////////////////////////////////////////////////////////////

type FileDigester3 struct {
}

func (p FileDigester3) walk(root string, cpath chan<- string) <-chan error {
    cerr := make(chan error)
    go func() {
        infos, err := ioutil.ReadDir(root)
        if err != nil { cerr <- err; return }
        for _, info := range infos {
            switch {
            case info.Mode().IsRegular():
                cpath <- filepath.Join(root, info.Name())
            case info.Mode().IsDir():
                err = <-p.walk(filepath.Join(root, info.Name()), cpath)
                if err != nil { cerr <- err; return }
            }
        }
        cerr <- nil
    }()
    return cerr
}

func (p FileDigester3) MD5All(root string) (map[string][md5.Size]byte, error) {
    ts := time.Now()
    defer func() {
        fmt.Printf("FileDigester3.MD5All() execute time: %v\n", time.Now().Sub(ts))
    }()

    cpath := make(chan string)
    cerr := p.walk(root, cpath)
    m := make(map[string][md5.Size]byte)
    for {
        select {
        case path := <-cpath:
            data, err := ioutil.ReadFile(path)
            if err != nil { return nil, err }
            m[path] = md5.Sum(data)
        case err := <-cerr:
            return m, err
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

func main() {
    flag.Parse()

    // Calculate the MD5 sum of all files under the specified directory,
    // then print the results sorted by path name.
    var p IFileDigester
    switch *workType {
    case 1:
        p = &FileDigester1{}
    case 2:
        p = &FileDigester2{}
    case 3:
        p = &FileDigester3{}
    default:
        p = &FileDigester{}
    }

    root := "."
    if flag.NArg() > 0 {
        root = flag.Arg(0)
    }

    m, err := p.MD5All(root)
    if err != nil {
        fmt.Println(err)
        return
    }
    var paths []string
    for path := range m {
        paths = append(paths, path)
    }
    sort.Strings(paths)
    for _, path := range paths {
        fmt.Printf("%x  %s\n", m[path], path)
    }
}
<|endoftext|>


<commit_before>package via

import (
	"github.com/ipfs/go-ipfs-api"
	"os"
)

func IpfsAdd(path Path) (string, error) {
	s := shell.NewShell("172.17.0.1:5001")
	fd, err := os.Open(path.String())
	if err != nil {
		return "", err
	}
	defer fd.Close()
	return s.Add(fd)
}

func HashOnly(path Path) (string, error) {
	s := shell.NewShell("172.17.0.1:5001")
	fd, err := os.Open(path.String())
	if err != nil {
		return "", err
	}
	defer fd.Close()
	return s.Add(fd, shell.OnlyHash(true))
}
<commit_msg>use local shell for ipfs<commit_after>package via

import (
	"github.com/ipfs/go-ipfs-api"
	"os"
)

func IpfsAdd(path Path) (string, error) {
	s := shell.NewLocalShell()
	fd, err := os.Open(path.String())
	if err != nil {
		return "", err
	}
	defer fd.Close()
	return s.Add(fd)
}

func HashOnly(path Path) (string, error) {
	s := shell.NewLocalShell()
	fd, err := os.Open(path.String())
	if err != nil {
		return "", err
	}
	defer fd.Close()
	return s.Add(fd, shell.OnlyHash(true))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/grafov/m3u8"
	"gopkg.in/redis.v1"
	"log"
	"net/http"
	"os/exec"
	"time"
)

var broadcastCursor = make(chan int)
var currentPlaylist string
var client *redis.Client

func init() {
	client = redis.NewTCPClient(&redis.Options{
		Addr: "localhost:6379",
	})

	pong, err := client.Ping().Result()
	log.Println(pong, err)
}

type PlaylistGenerator struct {
	cursor chan int
}

func (pl PlaylistGenerator) VideoFileForSequence(seq int) string {
	prefix := ""
	pref := client.Get("broadcast-prefix").Val()
	prefix = pref

	generated := fmt.Sprintf("fileSequence%d.ts", seq)
	postProcess := fmt.Sprintf("fileSequence%d-post.ts", seq)
	sourceVideo := prefix + generated
	destVideo := prefix + postProcess

	currentTime := time.Now().Format("3:04 PM")

	twoClipsAgo := seq - 2
	if twoClipsAgo > 0 {
		mapKey := fmt.Sprintf("/fileSequence%d-post.ts", twoClipsAgo)
		log.Println("map key is", mapKey)
		if count, ok := lfs.Counter[mapKey]; ok {
			currentTime = fmt.Sprintf("%d active viewers", count)
		}
	}

	err := RenderTextToPNG(currentTime, "time.png")
	if err == nil {
		cmd := exec.Command("avconv", "-i", sourceVideo, "-vf", "movie=time.png [watermark];[in][watermark] overlay=0:0 [out]", "-y", "-map", "0", "-c:a", "copy", "-c:v", "mpeg2video", "-an", destVideo)
		err := cmd.Start()
		if err != nil {
			return sourceVideo
		}
		err = cmd.Wait()
		return destVideo
	}

	return sourceVideo
}

func (pl *PlaylistGenerator) KeepPlaylistUpdated() {
	p, e := m3u8.NewMediaPlaylist(1000, 1000)
	if e != nil {
		log.Println("Error creating media playlist:", e)
		return
	}
	currentPlaylist = p.Encode().String()

	for seqnum := 0; seqnum < 390; seqnum = <-pl.cursor {
		videoFile := pl.VideoFileForSequence(seqnum)
		if err := p.Append(videoFile, 10.0, ""); err != nil {
			log.Println("Error appending item to playlist:", err, fmt.Sprintf("fileSequence%d.ts", seqnum))
		}
		currentPlaylist = p.Encode().String()
	}
}

func (pl *PlaylistGenerator) Start() {
	pl.cursor = make(chan int, 1000)

	go pl.KeepPlaylistUpdated()
	for i := 1; i < 394; i++ {
		log.Println(i)
		pl.cursor <- i
		time.Sleep(10 * time.Second)
	}
}

func (pl PlaylistGenerator) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, currentPlaylist)
}
<commit_msg>use simpler file name generation logic<commit_after>package main

import (
	"fmt"
	"github.com/grafov/m3u8"
	"gopkg.in/redis.v1"
	"log"
	"net/http"
	"os/exec"
	"time"
)

var broadcastCursor = make(chan int)
var currentPlaylist string
var client *redis.Client

func init() {
	client = redis.NewTCPClient(&redis.Options{
		Addr: "localhost:6379",
	})

	pong, err := client.Ping().Result()
	log.Println(pong, err)
}

type PlaylistGenerator struct {
	cursor chan int
}

func (pl PlaylistGenerator) VideoFileForSequence(seq int) string {
	generated := fmt.Sprintf("fileSequence%d.ts", seq)
	return generated
}

func (pl PlaylistGenerator) GeneratedVideoFileForSequence(seq int) string {
	prefix := ""
	pref := client.Get("broadcast-prefix").Val()
	prefix = pref

	generated := fmt.Sprintf("fileSequence%d.ts", seq)
	postProcess := fmt.Sprintf("fileSequence%d-post.ts", seq)
	sourceVideo := prefix + generated
	destVideo := prefix + postProcess

	currentTime := time.Now().Format("3:04 PM")

	twoClipsAgo := seq - 2
	if twoClipsAgo > 0 {
		mapKey := fmt.Sprintf("/fileSequence%d-post.ts", twoClipsAgo)
		log.Println("map key is", mapKey)
		if count, ok := lfs.Counter[mapKey]; ok {
			currentTime = fmt.Sprintf("%d active viewers", count)
		}
	}

	err := RenderTextToPNG(currentTime, "time.png")
	if err == nil {
		cmd := exec.Command("avconv", "-i", sourceVideo, "-vf", "movie=time.png [watermark];[in][watermark] overlay=0:0 [out]", "-y", "-map", "0", "-c:a", "copy", "-c:v", "mpeg2video", "-an", destVideo)
		err := cmd.Start()
		if err != nil {
			return sourceVideo
		}
		err = cmd.Wait()
		return destVideo
	}

	return sourceVideo
}

func (pl *PlaylistGenerator) KeepPlaylistUpdated() {
	p, e := m3u8.NewMediaPlaylist(1000, 1000)
	if e != nil {
		log.Println("Error creating media playlist:", e)
		return
	}
	currentPlaylist = p.Encode().String()

	for seqnum := 0; seqnum < 390; seqnum = <-pl.cursor {
		videoFile := pl.VideoFileForSequence(seqnum)
		if err := p.Append(videoFile, 10.0, ""); err != nil {
			log.Println("Error appending item to playlist:", err, fmt.Sprintf("fileSequence%d.ts", seqnum))
		}
		currentPlaylist = p.Encode().String()
	}
}

func (pl *PlaylistGenerator) Start() {
	pl.cursor = make(chan int, 1000)

	go pl.KeepPlaylistUpdated()
	for i := 1; i < 394; i++ {
		log.Println(i)
		pl.cursor <- i
		time.Sleep(10 * time.Second)
	}
}

func (pl PlaylistGenerator) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, currentPlaylist)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type editorConfig struct {
	screenRows  int
	screenCols  int
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() byte {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	return buffer[0]
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** input ***/

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	}
}

/*** append buffer ***/

type abuf []byte

/*** output ***/

func editorRefreshScreen() {
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	editorDrawRows()
	io.WriteString(os.Stdout, "\x1b[H")
}

func editorDrawRows() {
	for y := 0; y < E.screenRows - 1; y++ {
		io.WriteString(os.Stdout, "~\r\n")
	}
	io.WriteString(os.Stdout, "~")
}

/*** init ***/

func initEditor() {
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<commit_msg>Step 37<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type editorConfig struct {
	screenRows  int
	screenCols  int
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() byte {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	return buffer[0]
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** input ***/

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	}
}

/*** append buffer ***/

type abuf []byte

func abufInit() abuf {
	var p abuf
	return p
}

func (p abuf)abAppend(s []byte) {
	p = append(p, s...)
}

/*** output ***/

func editorRefreshScreen() {
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	editorDrawRows()
	io.WriteString(os.Stdout, "\x1b[H")
}

func editorDrawRows() {
	for y := 0; y < E.screenRows - 1; y++ {
		io.WriteString(os.Stdout, "~\r\n")
	}
	io.WriteString(os.Stdout, "~")
}

/*** init ***/

func initEditor() {
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<|endoftext|>


<commit_before>package integration_tests

import (
	"fmt"
	"path/filepath"
	"runtime"
	"time"

	. "github.com/onsi/ginkgo"
)

// creates a package repository mirror on the given node.
func createPackageRepositoryMirror(repoNode NodeDeets, distro linuxDistro, sshKey string) error {
	var mirrorScript string
	switch distro {
	case CentOS7:
		mirrorScript = "mirror-rpms.sh"
	case Ubuntu1604LTS:
		mirrorScript = "mirror-debs.sh"
	default:
		return fmt.Errorf("unable to create repo mirror for distro %q", distro)
	}
	start := time.Now()
	err := copyFileToRemote("test-resources/disconnected-installation/"+mirrorScript, "/tmp/"+mirrorScript, repoNode, sshKey, 10*time.Second)
	if err != nil {
		return fmt.Errorf("failed to copy script to remote node: %v", err)
	}
	cmds := []string{"chmod +x /tmp/" + mirrorScript, "sudo /tmp/" + mirrorScript}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 120*time.Minute)
	if err != nil {
		return fmt.Errorf("error running mirroring script: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Creating a package repository took", elapsed)
	return nil
}

// seeds a container image registry using the kismatic seed-registry command
func seedRegistry(repoNode NodeDeets, registryCAFile string, registryPort int, sshKey string) error {
	By("Adding the docker registry self-signed cert to the registry node")
	registry := fmt.Sprintf("%s:%d", repoNode.PublicIP, registryPort)
	err := copyFileToRemote(registryCAFile, "/tmp/docker-registry-ca.crt", repoNode, sshKey, 30*time.Second)
	if err != nil {
		return fmt.Errorf("Failed to copy registry cert to registry node: %v", err)
	}
	cmds := []string{
		fmt.Sprintf("sudo mkdir -p /etc/docker/certs.d/%s", registry),
		fmt.Sprintf("sudo mv /tmp/docker-registry-ca.crt /etc/docker/certs.d/%s/ca.crt", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 10*time.Minute)
	if err != nil {
		return fmt.Errorf("Error adding self-signed cert to registry node: %v", err)
	}

	By("Copying KET to the registry node for seeding")
	err = copyFileToRemote(filepath.Join(currentKismaticDir, "kismatic-"+runtime.GOOS+".tar.gz"), "/tmp/kismatic-"+runtime.GOOS+".tar.gz", repoNode, sshKey, 5*time.Minute)
	if err != nil {
		return fmt.Errorf("Error copying KET to the registry node: %v", err)
	}

	By("Seeding the registry")
	start := time.Now()
	cmds = []string{
		fmt.Sprintf("sudo docker login -u kismaticuser -p kismaticpassword %s", registry),
		"sudo mkdir kismatic",
		"sudo tar -xf /tmp/kismatic-" + runtime.GOOS + ".tar.gz -C kismatic",
		fmt.Sprintf("sudo ./kismatic/kismatic seed-registry --server %s", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 90*time.Minute)
	if err != nil {
		return fmt.Errorf("failed to seed the registry: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Seeding the registry took", elapsed)
	return nil
}
<commit_msg>Fix tests timing out by accepting a prompt after docker login<commit_after>package integration_tests

import (
	"fmt"
	"path/filepath"
	"runtime"
	"time"

	. "github.com/onsi/ginkgo"
)

// creates a package repository mirror on the given node.
func createPackageRepositoryMirror(repoNode NodeDeets, distro linuxDistro, sshKey string) error {
	var mirrorScript string
	switch distro {
	case CentOS7:
		mirrorScript = "mirror-rpms.sh"
	case Ubuntu1604LTS:
		mirrorScript = "mirror-debs.sh"
	default:
		return fmt.Errorf("unable to create repo mirror for distro %q", distro)
	}
	start := time.Now()
	err := copyFileToRemote("test-resources/disconnected-installation/"+mirrorScript, "/tmp/"+mirrorScript, repoNode, sshKey, 10*time.Second)
	if err != nil {
		return fmt.Errorf("failed to copy script to remote node: %v", err)
	}
	cmds := []string{"chmod +x /tmp/" + mirrorScript, "sudo /tmp/" + mirrorScript}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 120*time.Minute)
	if err != nil {
		return fmt.Errorf("error running mirroring script: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Creating a package repository took", elapsed)
	return nil
}

// seeds a container image registry using the kismatic seed-registry command
func seedRegistry(repoNode NodeDeets, registryCAFile string, registryPort int, sshKey string) error {
	By("Adding the docker registry self-signed cert to the registry node")
	registry := fmt.Sprintf("%s:%d", repoNode.PublicIP, registryPort)
	err := copyFileToRemote(registryCAFile, "/tmp/docker-registry-ca.crt", repoNode, sshKey, 30*time.Second)
	if err != nil {
		return fmt.Errorf("Failed to copy registry cert to registry node: %v", err)
	}
	cmds := []string{
		fmt.Sprintf("sudo mkdir -p /etc/docker/certs.d/%s", registry),
		fmt.Sprintf("sudo mv /tmp/docker-registry-ca.crt /etc/docker/certs.d/%s/ca.crt", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 10*time.Minute)
	if err != nil {
		return fmt.Errorf("Error adding self-signed cert to registry node: %v", err)
	}

	By("Copying KET to the registry node for seeding")
	err = copyFileToRemote(filepath.Join(currentKismaticDir, "kismatic-"+runtime.GOOS+".tar.gz"), "/tmp/kismatic-"+runtime.GOOS+".tar.gz", repoNode, sshKey, 5*time.Minute)
	if err != nil {
		return fmt.Errorf("Error copying KET to the registry node: %v", err)
	}

	By("Seeding the registry")
	start := time.Now()
	cmds = []string{
		fmt.Sprintf("echo 'y' | sudo docker login -u kismaticuser -p kismaticpassword %s", registry),
		"sudo mkdir kismatic",
		"sudo tar -xf /tmp/kismatic-" + runtime.GOOS + ".tar.gz -C kismatic",
		fmt.Sprintf("sudo ./kismatic/kismatic seed-registry --server %s", registry),
	}
	err = runViaSSH(cmds, []NodeDeets{repoNode}, sshKey, 30*time.Minute)
	if err != nil {
		return fmt.Errorf("failed to seed the registry: %v", err)
	}
	elapsed := time.Since(start)
	fmt.Println("Seeding the registry took", elapsed)
	return nil
}
<|endoftext|>