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

package xsrf_test

import (
	"context"
	"github.com/google/go-cmp/cmp"
	"github.com/google/go-safeweb/safehttp"
	"github.com/google/go-safeweb/safehttp/plugins/xsrf"
	"github.com/google/go-safeweb/safehttp/safehttptest"
	"golang.org/x/net/xsrftoken"
	"strings"
	"testing"
)

type userIdentifier struct{}

func (userIdentifier) UserID(r *safehttp.IncomingRequest) (string, error) {
	return "1234", nil
}

func TestTokenPost(t *testing.T) {
	methods := []string{safehttp.MethodPost, safehttp.MethodPatch}
	tests := []struct {
		name       string
		userID     string
		actionID   string
		wantStatus safehttp.StatusCode
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name:       "Valid token",
			userID:     "1234",
			actionID:   "https://foo.com/pizza",
			wantStatus: safehttp.StatusOK,
			wantHeader: map[string][]string{},
			wantBody:   "",
		},
		{
			name:       "Token mismatch for invalid host",
			userID:     "1234",
			actionID:   "https://bar.com/pizza",
			wantStatus: safehttp.StatusForbidden,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Token mismatch for invalid path",
			userID:     "1234",
			actionID:   "https://foo.com/spaghetti",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Token mismatch for invalid protocol",
			userID:     "1234",
			actionID:   "http://foo.com/spaghetti",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Token mismatch for invalid userID",
			userID:     "5678",
			actionID:   "http://foo.com/pizza",
			wantStatus: safehttp.StatusForbidden,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
	}
	for _, method := range methods {
		for _, test := range tests {
			t.Run(method+test.name, func(t *testing.T) {
				i := xsrf.Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
				tok := xsrftoken.Generate("xsrf", test.userID, test.actionID)
				req := safehttptest.NewRequest(method, "https://foo.com/pizza", strings.NewReader(xsrf.TokenKey+"="+tok))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				rec := safehttptest.NewResponseRecorder()

				i.Before(rec.ResponseWriter, req, nil)

				if rec.Status() != test.wantStatus {
					t.Errorf("response status: got %v, want %v", rec.Status(), test.wantStatus)
				}
				if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
					t.Errorf("rec.Header() mismatch (-want +got):\n%s", diff)
				}
				if got := rec.Body(); got != test.wantBody {
					t.Errorf("response body: got %q want %q", got, test.wantBody)
				}
			})
		}
	}
}

func TestTokenMultipart(t *testing.T) {
	methods := []string{safehttp.MethodPost, safehttp.MethodPatch}
	tests := []struct {
		name       string
		userID     string
		actionID   string
		wantStatus safehttp.StatusCode
		wantHeader map[string][]string
		wantBody   string
	}{
		{
			name:       "Valid token",
			userID:     "1234",
			actionID:   "https://foo.com/pizza",
			wantStatus: safehttp.StatusOK,
			wantHeader: map[string][]string{},
			wantBody:   "",
		},
		{
			name:       "Token mismatch for invalid host",
			userID:     "1234",
			actionID:   "https://bar.com/pizza",
			wantStatus: 403,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Token mismatch for invalid path",
			userID:     "1234",
			actionID:   "https://foo.com/spaghetti",
			wantStatus: safehttp.StatusForbidden,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Token mismatch for invalid protocol",
			userID:     "1234",
			actionID:   "http://foo.com/spaghetti",
			wantStatus: safehttp.StatusForbidden,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Token mismatch for invalid user ID",
			userID:     "5678",
			actionID:   "http://foo.com/pizza",
			wantStatus: safehttp.StatusForbidden,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
	}
	for _, method := range methods {
		for _, test := range tests {
			t.Run(method+test.name, func(t *testing.T) {
				i := xsrf.Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
				tok := xsrftoken.Generate("xsrf", test.userID, test.actionID)
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"xsrf-token\"\r\n" +
					"\r\n" +
					tok + "\r\n" +
					"--123--\r\n"
				req := safehttptest.NewRequest(method, "https://foo.com/pizza", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				rec := safehttptest.NewResponseRecorder()

				i.Before(rec.ResponseWriter, req, nil)

				if rec.Status() != test.wantStatus {
					t.Errorf("response status: got %v, want %v", rec.Status(), test.wantStatus)
				}
				if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
					t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
				}
				if got := rec.Body(); got != test.wantBody {
					t.Errorf("response body: got %q want %q", got, test.wantBody)
				}
			})
		}
	}
}

func TestMissingTokenInBody(t *testing.T) {
	tests := []struct {
		name string
		req  *safehttp.IncomingRequest
	}{
		{
			name: "Missing token in POST request with form",
			req: func() *safehttp.IncomingRequest {
				req := safehttptest.NewRequest(safehttp.MethodPost, "/", strings.NewReader("foo=bar"))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				return req
			}(),
		},
		{
			name: "Missing token in PATCH request with form",
			req: func() *safehttp.IncomingRequest {
				req := safehttptest.NewRequest(safehttp.MethodPatch, "/", strings.NewReader("foo=bar"))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				return req
			}(),
		},
		{
			name: "Missing token in POST request with multipart form",
			req: func() *safehttp.IncomingRequest {
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"foo\"\r\n" +
					"\r\n" +
					"bar\r\n" +
					"--123--\r\n"
				req := safehttptest.NewRequest(safehttp.MethodPost, "/", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				return req
			}(),
		},
		{
			name: "Missing token in PATCH request with multipart form",
			req: func() *safehttp.IncomingRequest {
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"foo\"\r\n" +
					"\r\n" +
					"bar\r\n" +
					"--123--\r\n"
				req := safehttptest.NewRequest(safehttp.MethodPatch, "/", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				return req
			}(),
		},
	}
	for _, test := range tests {
		i := xsrf.Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
		rec := safehttptest.NewResponseRecorder()

		i.Before(rec.ResponseWriter, test.req, nil)

		if want, got := safehttp.StatusUnauthorized, rec.Status(); got != want {
			t.Errorf("response status: got %v, want %v", got, want)
		}
		wantHeaders := map[string][]string{
			"Content-Type":           {"text/plain; charset=utf-8"},
			"X-Content-Type-Options": {"nosniff"},
		}
		if diff := cmp.Diff(wantHeaders, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
		}
		if want, got := "Unauthorized\n", rec.Body(); got != want {
			t.Errorf("response body: got %q want %q", got, want)
		}
	}
}

func TestTokenRequestContext(t *testing.T) {
	tests := []struct {
		name     string
		userID   string
		actionID string
		match    bool
	}{
		{
			name:     "Valid token",
			userID:   "1234",
			actionID: "https://foo.com/pizza",
			match:    true,
		},
		{
			name:     "Token mismatch for invalid host",
			userID:   "1234",
			actionID: "https://bar.com/pizza",
			match:    false,
		},
		{
			name:     "Token mismatch for invalid path",
			userID:   "1234",
			actionID: "https://foo.com/spaghetti",
			match:    false,
		},
		{
			name:     "Token mismatch for invalid protocol",
			userID:   "1234",
			actionID: "http://foo.com/spaghetti",
			match:    false,
		},
		{
			name:     "Token mismatch for invalid user ID",
			userID:   "5678",
			actionID: "http://foo.com/pizza",
			match:    false,
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			i := xsrf.Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
			req := safehttptest.NewRequest(safehttp.MethodGet, "https://foo.com/pizza", nil)
			rec := safehttptest.NewResponseRecorder()

			i.Before(rec.ResponseWriter, req, nil)

			gotTok := xsrf.Token(req)
			if ok := xsrftoken.Valid(gotTok, "xsrf", test.userID, test.actionID); ok != test.match {
				t.Errorf("xsrf.Token(req): invalid token")
			}

			if want, got := safehttp.StatusOK, safehttp.StatusCode(rec.Status()); want != got {
				t.Errorf("response status: got %v, want %v", got, want)
			}
			if diff := cmp.Diff(map[string][]string{}, map[string][]string(rec.Header())); diff != "" {
				t.Errorf("rec.Header() mismatch (-want +got):\n%s", diff)
			}
			if want, got := "", rec.Body(); got != want {
				t.Errorf("response body: got %q want %q", got, want)
			}
		})
	}

}

func TestMissingTokenRequestContext(t *testing.T) {
	req := safehttptest.NewRequest(safehttp.MethodGet, "/", nil)
	req.SetContext(context.Background())

	if want, got := "", xsrf.Token(req); want != got {
		t.Errorf("xsrf.Token(req): got %v, want %v", got, want)
	}
}
<commit_msg>Move inpu for checking form token outside tests to not repeat it in two tests<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package xsrf

import (
	"context"
	"github.com/google/go-cmp/cmp"
	"github.com/google/go-safeweb/safehttp"
	"github.com/google/go-safeweb/safehttp/safehttptest"
	"golang.org/x/net/xsrftoken"
	"strings"
	"testing"
)

type userIdentifier struct{}

func (userIdentifier) UserID(r *safehttp.IncomingRequest) (string, error) {
	return "1234", nil
}

var (
	stateChangingMet = []string{safehttp.MethodPost, safehttp.MethodPatch}
	formTokenTests   = []struct {
		name, userID, actionID, wantBody string
		wantStatus                       safehttp.StatusCode
		wantHeader                       map[string][]string
	}{
		{
			name:       "Valid token",
			userID:     "1234",
			actionID:   "https://foo.com/pizza",
			wantStatus: safehttp.StatusOK,
			wantHeader: map[string][]string{},
			wantBody:   "",
		},
		{
			name:       "Invalid actionID in token generation",
			userID:     "1234",
			actionID:   "http://bar.com/pizza",
			wantStatus: safehttp.StatusForbidden,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
		{
			name:       "Invalid userID in token generation",
			userID:     "5678",
			actionID:   "http://foo.com/pizza",
			wantStatus: safehttp.StatusForbidden,
			wantHeader: map[string][]string{
				"Content-Type":           {"text/plain; charset=utf-8"},
				"X-Content-Type-Options": {"nosniff"},
			},
			wantBody: "Forbidden\n",
		},
	}
)

func TestTokenPost(t *testing.T) {
	for _, method := range stateChangingMet {
		for _, test := range formTokenTests {
			t.Run(method+" "+test.name, func(t *testing.T) {
				i := Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
				tok := xsrftoken.Generate("xsrf", test.userID, test.actionID)
				req := safehttptest.NewRequest(method, "https://foo.com/pizza", strings.NewReader(TokenKey+"="+tok))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				rec := safehttptest.NewResponseRecorder()

				i.Before(rec.ResponseWriter, req, nil)

				if got := safehttp.StatusCode(rec.Status()); got != test.wantStatus {
					t.Errorf("response status: got %v, want %v", got, test.wantStatus)
				}
				if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
					t.Errorf("rec.Header() mismatch (-want +got):\n%s", diff)
				}
				if got := rec.Body(); got != test.wantBody {
					t.Errorf("response body: got %q want %q", got, test.wantBody)
				}
			})
		}
	}
}

func TestTokenMultipart(t *testing.T) {
	for _, method := range stateChangingMet {
		for _, test := range formTokenTests {
			t.Run(method+" "+test.name, func(t *testing.T) {
				i := Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
				tok := xsrftoken.Generate("xsrf", test.userID, test.actionID)
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"xsrf-token\"\r\n" +
					"\r\n" +
					tok + "\r\n" +
					"--123--\r\n"
				req := safehttptest.NewRequest(method, "https://foo.com/pizza", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				rec := safehttptest.NewResponseRecorder()

				i.Before(rec.ResponseWriter, req, nil)

				if got := safehttp.StatusCode(rec.Status()); got != test.wantStatus {
					t.Errorf("response status: got %v, want %v", got, test.wantStatus)
				}
				if diff := cmp.Diff(test.wantHeader, map[string][]string(rec.Header())); diff != "" {
					t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
				}
				if got := rec.Body(); got != test.wantBody {
					t.Errorf("response body: got %q want %q", got, test.wantBody)
				}
			})
		}
	}
}

func TestMissingTokenInBody(t *testing.T) {
	tests := []struct {
		name string
		req  *safehttp.IncomingRequest
	}{
		{
			name: "Missing token in POST request with form",
			req: func() *safehttp.IncomingRequest {
				req := safehttptest.NewRequest(safehttp.MethodPost, "/", strings.NewReader("foo=bar"))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				return req
			}(),
		},
		{
			name: "Missing token in PATCH request with form",
			req: func() *safehttp.IncomingRequest {
				req := safehttptest.NewRequest(safehttp.MethodPatch, "/", strings.NewReader("foo=bar"))
				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
				return req
			}(),
		},
		{
			name: "Missing token in POST request with multipart form",
			req: func() *safehttp.IncomingRequest {
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"foo\"\r\n" +
					"\r\n" +
					"bar\r\n" +
					"--123--\r\n"
				req := safehttptest.NewRequest(safehttp.MethodPost, "/", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				return req
			}(),
		},
		{
			name: "Missing token in PATCH request with multipart form",
			req: func() *safehttp.IncomingRequest {
				b := "--123\r\n" +
					"Content-Disposition: form-data; name=\"foo\"\r\n" +
					"\r\n" +
					"bar\r\n" +
					"--123--\r\n"
				req := safehttptest.NewRequest(safehttp.MethodPatch, "/", strings.NewReader(b))
				req.Header.Set("Content-Type", `multipart/form-data; boundary="123"`)
				return req
			}(),
		},
	}
	for _, test := range tests {
		i := Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
		rec := safehttptest.NewResponseRecorder()

		i.Before(rec.ResponseWriter, test.req, nil)

		if want, got := safehttp.StatusUnauthorized, rec.Status(); got != want {
			t.Errorf("response status: got %v, want %v", got, want)
		}
		wantHeaders := map[string][]string{
			"Content-Type":           {"text/plain; charset=utf-8"},
			"X-Content-Type-Options": {"nosniff"},
		}
		if diff := cmp.Diff(wantHeaders, map[string][]string(rec.Header())); diff != "" {
			t.Errorf("rw.header mismatch (-want +got):\n%s", diff)
		}
		if want, got := "Unauthorized\n", rec.Body(); got != want {
			t.Errorf("response body: got %q want %q", got, want)
		}
	}
}

func TestBeforeTokenInRequestContext(t *testing.T) {
	i := Interceptor{AppKey: "xsrf", Identifier: userIdentifier{}}
	req := safehttptest.NewRequest(safehttp.MethodGet, "https://foo.com/pizza", nil)
	rec := safehttptest.NewResponseRecorder()

	i.Before(rec.ResponseWriter, req, nil)

	tok, err := Token(req)
	if tok == "" {
		t.Error(`Token(req): got "", want token`)
	}
	if err != nil {
		t.Errorf("Token(req): got %v, want nil", err)
	}

	if want, got := safehttp.StatusOK, safehttp.StatusCode(rec.Status()); want != got {
		t.Errorf("response status: got %v, want %v", got, want)
	}
	if diff := cmp.Diff(map[string][]string{}, map[string][]string(rec.Header())); diff != "" {
		t.Errorf("rec.Header() mismatch (-want +got):\n%s", diff)
	}
	if want, got := "", rec.Body(); got != want {
		t.Errorf("response body: got %q want %q", got, want)
	}

}

func TestTokenInRequestContext(t *testing.T) {
	req := safehttptest.NewRequest(safehttp.MethodGet, "/", nil)
	req.SetContext(context.WithValue(req.Context(), tokenCtxKey{}, "pizza"))

	got, err := Token(req)
	if want := "pizza"; want != got {
		t.Errorf("Token(req): got %v, want %v", got, want)
	}
	if err != nil {
		t.Errorf("Token(req): got %v, want nil", err)
	}
}

func TestMissingTokenInRequestContext(t *testing.T) {
	req := safehttptest.NewRequest(safehttp.MethodGet, "/", nil)
	req.SetContext(context.Background())

	got, err := Token(req)
	if want := ""; want != got {
		t.Errorf("Token(req): got %v, want %v", got, want)
	}
	if err == nil {
		t.Error("Token(req): got nil, want error")
	}
}
<|endoftext|>


<commit_before>package actions

import (
	"errors"
	"fmt"
	"github.com/docker/go-units"
	"github.com/sjoerdsimons/fakemachine"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"

	"github.com/go-debos/debos"
)

type Partition struct {
	number int
	Name   string
	Start  string
	End    string
	FS     string
	Flags  []string
	FSUUID string
}

type Mountpoint struct {
	Mountpoint string
	Partition  string
	Options    []string
	part       *Partition
}

type ImagePartitionAction struct {
	debos.BaseAction    `yaml:",inline"`
	ImageName     string
	ImageSize     string
	PartitionType string
	Partitions    []Partition
	Mountpoints   []Mountpoint
	size          int64
	usingLoop     bool
}

func (i *ImagePartitionAction) generateFSTab(context *debos.DebosContext) error {
	context.ImageFSTab.Reset()

	for _, m := range i.Mountpoints {
		options := []string{"defaults"}
		options = append(options, m.Options...)
		if m.part.FSUUID == "" {
			return fmt.Errorf("Missing fs UUID for partition %s!?!", m.part.Name)
		}
		context.ImageFSTab.WriteString(fmt.Sprintf("UUID=%s\t%s\t%s\t%s\t0\t0\n",
			m.part.FSUUID, m.Mountpoint, m.part.FS,
			strings.Join(options, ",")))
	}

	return nil
}

func (i *ImagePartitionAction) generateKernelRoot(context *debos.DebosContext) error {
	for _, m := range i.Mountpoints {
		if m.Mountpoint == "/" {
			if m.part.FSUUID == "" {
				return errors.New("No fs UUID for root partition !?!")
			}
			context.ImageKernelRoot = fmt.Sprintf("root=UUID=%s", m.part.FSUUID)
			break
		}
	}

	return nil
}

func (i ImagePartitionAction) getPartitionDevice(number int, context debos.DebosContext) string {
	/* If the iamge device has a digit as the last character, the partition
	 * suffix is p<number> else it's just <number> */
	last := context.Image[len(context.Image)-1]
	if last >= '0' && last <= '9' {
		return fmt.Sprintf("%sp%d", context.Image, number)
	} else {
		return fmt.Sprintf("%s%d", context.Image, number)
	}
}

func (i ImagePartitionAction) PreMachine(context *debos.DebosContext, m *fakemachine.Machine,
	args *[]string) error {
	err := m.CreateImage(i.ImageName, i.size)
	if err != nil {
		return err
	}

	context.Image = "/dev/vda"
	*args = append(*args, "--internal-image", "/dev/vda")
	return nil
}

func (i ImagePartitionAction) formatPartition(p *Partition, context debos.DebosContext) error {
	label := fmt.Sprintf("Formatting partition %d", p.number)
	path := i.getPartitionDevice(p.number, context)

	cmdline := []string{}
	switch p.FS {
	case "fat32":
		cmdline = append(cmdline, "mkfs.vfat", "-n", p.Name)
	default:
		cmdline = append(cmdline, fmt.Sprintf("mkfs.%s", p.FS), "-L", p.Name)
	}
	cmdline = append(cmdline, path)

	debos.Command{}.Run(label, cmdline...)

	uuid, err := exec.Command("blkid", "-o", "value", "-s", "UUID", "-p", "-c", "none", path).Output()
	if err != nil {
		return fmt.Errorf("Failed to get uuid: %s", err)
	}
	p.FSUUID = strings.TrimSpace(string(uuid[:]))

	return nil
}

func (i ImagePartitionAction) PreNoMachine(context *debos.DebosContext) error {

	img, err := os.OpenFile(i.ImageName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("Couldn't open image file: %v", err)
	}

	err = img.Truncate(i.size)
	if err != nil {
		return fmt.Errorf("Couldn't resize image file: %v", err)
	}

	img.Close()

	loop, err := exec.Command("losetup", "-f", "--show", i.ImageName).Output()
	if err != nil {
		return fmt.Errorf("Failed to setup loop device")
	}
	context.Image = strings.TrimSpace(string(loop[:]))
	i.usingLoop = true

	return nil
}

func (i ImagePartitionAction) Run(context *debos.DebosContext) error {
	i.LogStart()
	err := debos.Command{}.Run("parted", "parted", "-s", context.Image, "mklabel", i.PartitionType)
	if err != nil {
		return err
	}
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		var name string
		if i.PartitionType == "gpt" {
			name = p.Name
		} else {
			name = "primary"
		}
		err = debos.Command{}.Run("parted", "parted", "-a", "none", "-s", context.Image, "mkpart",
			name, p.FS, p.Start, p.End)
		if err != nil {
			return err
		}

		if p.Flags != nil {
			for _, flag := range p.Flags {
				err = debos.Command{}.Run("parted", "parted", "-s", context.Image, "set",
					fmt.Sprintf("%d", p.number), flag, "on")
				if err != nil {
					return err
				}
			}
		}

		err = i.formatPartition(p, *context)
		if err != nil {
			return err
		}
	}

	context.ImageMntDir = path.Join(context.Scratchdir, "mnt")
	os.MkdirAll(context.ImageMntDir, 755)
	for _, m := range i.Mountpoints {
		dev := i.getPartitionDevice(m.part.number, *context)
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		os.MkdirAll(mntpath, 755)
		var fs string
		switch m.part.FS {
		case "fat32":
			fs = "vfat"
		default:
			fs = m.part.FS
		}
		err := syscall.Mount(dev, mntpath, fs, 0, "")
		if err != nil {
			return fmt.Errorf("%s mount failed: %v", m.part.Name, err)
		}
	}

	err = i.generateFSTab(context)
	if err != nil {
		return err
	}

	err = i.generateKernelRoot(context)
	if err != nil {
		return err
	}

	return nil
}

func (i ImagePartitionAction) Cleanup(context debos.DebosContext) error {
	for idx := len(i.Mountpoints) - 1; idx >= 0; idx-- {
		m := i.Mountpoints[idx]
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		syscall.Unmount(mntpath, 0)
	}

	if i.usingLoop {
		exec.Command("losetup", "-d", context.Image).Run()
	}

	return nil
}

func (i *ImagePartitionAction) Verify(context *debos.DebosContext) error {
	num := 1
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		p.number = num
		num++
		if p.Name == "" {
			return fmt.Errorf("Partition without a name")
		}
		if p.Start == "" {
			return fmt.Errorf("Partition %s missing start", p.Name)
		}
		if p.End == "" {
			return fmt.Errorf("Partition %s missing end", p.Name)
		}

		if p.FS == "" {
			return fmt.Errorf("Partition %s missing fs type", p.Name)
		}
	}

	for idx, _ := range i.Mountpoints {
		m := &i.Mountpoints[idx]
		for pidx, _ := range i.Partitions {
			p := &i.Partitions[pidx]
			if m.Partition == p.Name {
				m.part = p
				break
			}
		}
		if m.part == nil {
			return fmt.Errorf("Couldn't fount partition for %s", m.Mountpoint)
		}
	}

	size, err := units.FromHumanSize(i.ImageSize)
	if err != nil {
		return fmt.Errorf("Failed to parse image size: %s", i.ImageSize)
	}

	i.size = size
	return nil
}
<commit_msg>actions: image-partition: fix fstab entry generation for 'fat32'<commit_after>package actions

import (
	"errors"
	"fmt"
	"github.com/docker/go-units"
	"github.com/sjoerdsimons/fakemachine"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"

	"github.com/go-debos/debos"
)

type Partition struct {
	number int
	Name   string
	Start  string
	End    string
	FS     string
	Flags  []string
	FSUUID string
}

type Mountpoint struct {
	Mountpoint string
	Partition  string
	Options    []string
	part       *Partition
}

type ImagePartitionAction struct {
	debos.BaseAction    `yaml:",inline"`
	ImageName     string
	ImageSize     string
	PartitionType string
	Partitions    []Partition
	Mountpoints   []Mountpoint
	size          int64
	usingLoop     bool
}

func (i *ImagePartitionAction) generateFSTab(context *debos.DebosContext) error {
	context.ImageFSTab.Reset()

	for _, m := range i.Mountpoints {
		options := []string{"defaults"}
		options = append(options, m.Options...)
		if m.part.FSUUID == "" {
			return fmt.Errorf("Missing fs UUID for partition %s!?!", m.part.Name)
		}
		fs := m.part.FS
		switch m.part.FS {
		case "fat32":
			fs = "vfat"
		}
		context.ImageFSTab.WriteString(fmt.Sprintf("UUID=%s\t%s\t%s\t%s\t0\t0\n",
			m.part.FSUUID, m.Mountpoint, fs,
			strings.Join(options, ",")))
	}

	return nil
}

func (i *ImagePartitionAction) generateKernelRoot(context *debos.DebosContext) error {
	for _, m := range i.Mountpoints {
		if m.Mountpoint == "/" {
			if m.part.FSUUID == "" {
				return errors.New("No fs UUID for root partition !?!")
			}
			context.ImageKernelRoot = fmt.Sprintf("root=UUID=%s", m.part.FSUUID)
			break
		}
	}

	return nil
}

func (i ImagePartitionAction) getPartitionDevice(number int, context debos.DebosContext) string {
	/* If the iamge device has a digit as the last character, the partition
	 * suffix is p<number> else it's just <number> */
	last := context.Image[len(context.Image)-1]
	if last >= '0' && last <= '9' {
		return fmt.Sprintf("%sp%d", context.Image, number)
	} else {
		return fmt.Sprintf("%s%d", context.Image, number)
	}
}

func (i ImagePartitionAction) PreMachine(context *debos.DebosContext, m *fakemachine.Machine,
	args *[]string) error {
	err := m.CreateImage(i.ImageName, i.size)
	if err != nil {
		return err
	}

	context.Image = "/dev/vda"
	*args = append(*args, "--internal-image", "/dev/vda")
	return nil
}

func (i ImagePartitionAction) formatPartition(p *Partition, context debos.DebosContext) error {
	label := fmt.Sprintf("Formatting partition %d", p.number)
	path := i.getPartitionDevice(p.number, context)

	cmdline := []string{}
	switch p.FS {
	case "fat32":
		cmdline = append(cmdline, "mkfs.vfat", "-n", p.Name)
	default:
		cmdline = append(cmdline, fmt.Sprintf("mkfs.%s", p.FS), "-L", p.Name)
	}
	cmdline = append(cmdline, path)

	debos.Command{}.Run(label, cmdline...)

	uuid, err := exec.Command("blkid", "-o", "value", "-s", "UUID", "-p", "-c", "none", path).Output()
	if err != nil {
		return fmt.Errorf("Failed to get uuid: %s", err)
	}
	p.FSUUID = strings.TrimSpace(string(uuid[:]))

	return nil
}

func (i ImagePartitionAction) PreNoMachine(context *debos.DebosContext) error {

	img, err := os.OpenFile(i.ImageName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("Couldn't open image file: %v", err)
	}

	err = img.Truncate(i.size)
	if err != nil {
		return fmt.Errorf("Couldn't resize image file: %v", err)
	}

	img.Close()

	loop, err := exec.Command("losetup", "-f", "--show", i.ImageName).Output()
	if err != nil {
		return fmt.Errorf("Failed to setup loop device")
	}
	context.Image = strings.TrimSpace(string(loop[:]))
	i.usingLoop = true

	return nil
}

func (i ImagePartitionAction) Run(context *debos.DebosContext) error {
	i.LogStart()
	err := debos.Command{}.Run("parted", "parted", "-s", context.Image, "mklabel", i.PartitionType)
	if err != nil {
		return err
	}
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		var name string
		if i.PartitionType == "gpt" {
			name = p.Name
		} else {
			name = "primary"
		}
		err = debos.Command{}.Run("parted", "parted", "-a", "none", "-s", context.Image, "mkpart",
			name, p.FS, p.Start, p.End)
		if err != nil {
			return err
		}

		if p.Flags != nil {
			for _, flag := range p.Flags {
				err = debos.Command{}.Run("parted", "parted", "-s", context.Image, "set",
					fmt.Sprintf("%d", p.number), flag, "on")
				if err != nil {
					return err
				}
			}
		}

		err = i.formatPartition(p, *context)
		if err != nil {
			return err
		}
	}

	context.ImageMntDir = path.Join(context.Scratchdir, "mnt")
	os.MkdirAll(context.ImageMntDir, 755)
	for _, m := range i.Mountpoints {
		dev := i.getPartitionDevice(m.part.number, *context)
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		os.MkdirAll(mntpath, 755)
		var fs string
		switch m.part.FS {
		case "fat32":
			fs = "vfat"
		default:
			fs = m.part.FS
		}
		err := syscall.Mount(dev, mntpath, fs, 0, "")
		if err != nil {
			return fmt.Errorf("%s mount failed: %v", m.part.Name, err)
		}
	}

	err = i.generateFSTab(context)
	if err != nil {
		return err
	}

	err = i.generateKernelRoot(context)
	if err != nil {
		return err
	}

	return nil
}

func (i ImagePartitionAction) Cleanup(context debos.DebosContext) error {
	for idx := len(i.Mountpoints) - 1; idx >= 0; idx-- {
		m := i.Mountpoints[idx]
		mntpath := path.Join(context.ImageMntDir, m.Mountpoint)
		syscall.Unmount(mntpath, 0)
	}

	if i.usingLoop {
		exec.Command("losetup", "-d", context.Image).Run()
	}

	return nil
}

func (i *ImagePartitionAction) Verify(context *debos.DebosContext) error {
	num := 1
	for idx, _ := range i.Partitions {
		p := &i.Partitions[idx]
		p.number = num
		num++
		if p.Name == "" {
			return fmt.Errorf("Partition without a name")
		}
		if p.Start == "" {
			return fmt.Errorf("Partition %s missing start", p.Name)
		}
		if p.End == "" {
			return fmt.Errorf("Partition %s missing end", p.Name)
		}

		if p.FS == "" {
			return fmt.Errorf("Partition %s missing fs type", p.Name)
		}
	}

	for idx, _ := range i.Mountpoints {
		m := &i.Mountpoints[idx]
		for pidx, _ := range i.Partitions {
			p := &i.Partitions[pidx]
			if m.Partition == p.Name {
				m.part = p
				break
			}
		}
		if m.part == nil {
			return fmt.Errorf("Couldn't fount partition for %s", m.Mountpoint)
		}
	}

	size, err := units.FromHumanSize(i.ImageSize)
	if err != nil {
		return fmt.Errorf("Failed to parse image size: %s", i.ImageSize)
	}

	i.size = size
	return nil
}
<|endoftext|>


<commit_before>package chatroom

import (
	// "chant/app/factory"
	"container/list"
	// "encoding/json"
	// "html"
	// "time"

	"chant.v1/app/models"
	"chant.v1/app/repository"
	// "github.com/revel/revel"

	"log"

	// "github.com/otiai10/rodeo"
	"fmt"
)

var rooms = map[string]*Room{
	"default": nil,
}

type Room struct {
	entrance    chan Subscription
	exit        chan Subscription
	publish     chan *models.Event
	terminate   chan interface{}
	subscribers *list.List
	members     *list.List
}

// Open Roomごとに部屋を開く. foreverなgoroutineをつくる.
func (room *Room) Serve() {
	for {
		select {
		// Roomは、
		// エントランスからsubscription依頼が来たら
		// subscriptionをRoomのsubscribersに登録しつつ
		// 受信用のチャンネルを返してあげる必要がある.
		case sub := <-room.entrance:
			room.subscribers.PushBack(sub)
			// Roomは、
		// 出口にsubscriptionを投げられたら
		// subscriptionをRoomのsubscribersから抹消する必要がある.

		case sub := <-room.exit:
			for one := room.subscribers.Front(); one != nil; one = one.Next() {
				if the, ok := one.Value.(Subscription); ok && the == sub {
					room.subscribers.Remove(one)
				}
			}
			room.drain(sub)
		// Roomは、
		// publish用のチャンネルに新しいイベントを流し込まれたとき、
		// そのイベントを登録されている全Subscribersに配信する必要がある.
		case ev := <-room.publish:
			for one := room.subscribers.Front(); one != nil; one = one.Next() {
				if the, ok := one.Value.(Subscription); ok {
					the.New <- ev
				}
			}
		// Roomは、
		// なんらかの不具合があったときに
		// foreverなルーチンを終了して死ぬ.
		case cause := <-room.terminate:
			log.Println(cause)
			return
		}
	}
}

func newRoom() *Room {
	room := &Room{
		entrance:    make(chan Subscription),
		exit:        make(chan Subscription),
		publish:     make(chan *models.Event),
		subscribers: list.New(),
		members:     list.New(),
	}
	go room.Serve()
	return room
}

func GetRoom(id ...string) *Room {
	id = append(id, "default") // id指定がなければdefaultを使う
	room, ok := rooms[id[0]]
	if !ok || room == nil {
		room = newRoom()
		rooms[id[0]] = room
	}
	return room
}

// Subscribe は呼ばれると、このroomのsubscribersに登録されたsubscriptionが提供される。
func (room *Room) Subscribe() Subscription {
	subscription := Subscription{New: make(chan *models.Event)}
	room.entrance <- subscription
	return subscription
}

// Unsubscribe は呼ばれると、このroomのsubscribersから抜ける（べき）。
func (room *Room) Unsubscribe(subscription Subscription) {
	room.exit <- subscription
	room.drain(subscription)
}

// 不要になったsubscriptionからの流し込みを受けるだけのメソッド。
func (room *Room) drain(subscription Subscription) {
	for {
		select {
		case _, ok := <-subscription.New:
			if !ok {
				return
			}
		default:
			return
		}
	}
}

// Subscription 新しいイベントを伝えるためのチャンネルラッパー
type Subscription struct {
	New chan *models.Event // 新しいイベントをこのsubscriberに伝えるチャンネル
}

func (room *Room) Say(user *models.User, msg string) {
	event, err := models.ConstructEvent(user, msg)
	if err != nil {
		fmt.Println("construct event error", err)
		// TODO: なんかする
		return
	}
	repository.PushMessage(event)
	room.publish <- event
}

func (room *Room) Join(user *models.User) {
	room.members.PushBack(user)
	event := new(models.Event)
	event.User = user
	event.Type = models.JOIN
	event.Value = room.getUniqueUsers()
	room.publish <- event
}

func (room *Room) Leave(user *models.User) {
	room.removeOneUser(user)
	event := new(models.Event)
	event.User = user
	event.Type = models.LEAVE
	event.Value = room.getUniqueUsers()
	room.publish <- event
}

func (room *Room) getUniqueUsers() map[string]*models.User {
	res := map[string]*models.User{}
	for e := room.members.Front(); e != nil; e = e.Next() {
		user := e.Value.(*models.User)
		res[user.IDstr] = user
	}
	return res
}

func (room *Room) removeOneUser(user *models.User) {
	for e := room.members.Front(); e != nil; e = e.Next() {
		if the := e.Value.(*models.User); the.IDstr == user.IDstr {
			room.members.Remove(e)
			return
		}
	}
}
<commit_msg>Fix #85 stucked chant<commit_after>package chatroom

import (
	// "chant/app/factory"
	"container/list"
	// "encoding/json"
	// "html"
	// "time"

	"chant.v1/app/models"
	"chant.v1/app/repository"
	// "github.com/revel/revel"

	"log"

	// "github.com/otiai10/rodeo"
	"fmt"
)

var rooms = map[string]*Room{
	"default": nil,
}

type Room struct {
	entrance    chan Subscription
	exit        chan Subscription
	publish     chan *models.Event
	terminate   chan interface{}
	subscribers *list.List
	members     *list.List
}

// Open Roomごとに部屋を開く. foreverなgoroutineをつくる.
func (room *Room) Serve() {
	for {
		select {
		// Roomは、
		// エントランスからsubscription依頼が来たら
		// subscriptionをRoomのsubscribersに登録しつつ
		// 受信用のチャンネルを返してあげる必要がある.
		case sub := <-room.entrance:
			room.subscribers.PushBack(sub)
			// Roomは、
		// 出口にsubscriptionを投げられたら
		// subscriptionをRoomのsubscribersから抹消する必要がある.

		case sub := <-room.exit:
			for one := room.subscribers.Front(); one != nil; one = one.Next() {
				if the, ok := one.Value.(Subscription); ok && the == sub {
					room.subscribers.Remove(one)
				}
			}
			// unhandlableなsubscriptionが残ってると、そいつのせいでblockするので
			// exitに来たchanは必ずdrainにかけなければならない
			// XXX: これ、room.subscribers.Removeの前にinvokeしてもいいんじゃね？
			room.drain(sub)
		// Roomは、
		// publish用のチャンネルに新しいイベントを流し込まれたとき、
		// そのイベントを登録されている全Subscribersに配信する必要がある.
		case ev := <-room.publish:
			for one := room.subscribers.Front(); one != nil; one = one.Next() {
				if the, ok := one.Value.(Subscription); ok {
					// 誰かへのpublishが詰まっても、全体として詰まらないようにするため、
					// 各人へのpublishはgoroutineにして独立させる.
					// 逆にいえば、ここはsub.Newへの流し込みが、チャンネルの先でhandle仕切れてない
					// ので詰まり現象が発生しているのではないかと推測している.
					go func(sub Subscription, ev *models.Event) {
						sub.New <- ev
					}(the, ev)
				}
			}
		// Roomは、
		// なんらかの不具合があったときに
		// foreverなルーチンを終了して死ぬ.
		case cause := <-room.terminate:
			log.Println(cause)
			return
		}
	}
}

func newRoom() *Room {
	room := &Room{
		entrance:    make(chan Subscription),
		exit:        make(chan Subscription),
		publish:     make(chan *models.Event),
		subscribers: list.New(),
		members:     list.New(),
	}
	go room.Serve()
	return room
}

func GetRoom(id ...string) *Room {
	id = append(id, "default") // id指定がなければdefaultを使う
	room, ok := rooms[id[0]]
	if !ok || room == nil {
		room = newRoom()
		rooms[id[0]] = room
	}
	return room
}

// Subscribe は呼ばれると、このroomのsubscribersに登録されたsubscriptionが提供される。
func (room *Room) Subscribe() Subscription {
	subscription := Subscription{New: make(chan *models.Event)}
	room.entrance <- subscription
	return subscription
}

// Unsubscribe は呼ばれると、このroomのsubscribersから抜ける（べき）。
func (room *Room) Unsubscribe(subscription Subscription) {
	room.exit <- subscription
	room.drain(subscription)
}

// 不要になったsubscriptionからの流し込みを受けるだけのメソッド。
func (room *Room) drain(subscription Subscription) {
	for {
		select {
		case _, ok := <-subscription.New:
			if !ok {
				return
			}
		default:
			return
		}
	}
}

// Subscription 新しいイベントを伝えるためのチャンネルラッパー
type Subscription struct {
	New chan *models.Event // 新しいイベントをこのsubscriberに伝えるチャンネル
}

func (room *Room) Say(user *models.User, msg string) {
	event, err := models.ConstructEvent(user, msg)
	if err != nil {
		fmt.Println("construct event error", err)
		// TODO: なんかする
		return
	}
	repository.PushMessage(event)
	room.publish <- event
}

func (room *Room) Join(user *models.User) {
	room.members.PushBack(user)
	event := new(models.Event)
	event.User = user
	event.Type = models.JOIN
	event.Value = room.getUniqueUsers()
	room.publish <- event
}

func (room *Room) Leave(user *models.User) {
	room.removeOneUser(user)
	event := new(models.Event)
	event.User = user
	event.Type = models.LEAVE
	event.Value = room.getUniqueUsers()
	room.publish <- event
}

func (room *Room) getUniqueUsers() map[string]*models.User {
	res := map[string]*models.User{}
	for e := room.members.Front(); e != nil; e = e.Next() {
		user := e.Value.(*models.User)
		res[user.IDstr] = user
	}
	return res
}

func (room *Room) removeOneUser(user *models.User) {
	for e := room.members.Front(); e != nil; e = e.Next() {
		if the := e.Value.(*models.User); the.IDstr == user.IDstr {
			room.members.Remove(e)
			return
		}
	}
}
<|endoftext|>


<commit_before>package db

import (
  . "seeme/models"

	"errors"
)

func GetConnectionsMap(user string) (map[string]bool, error) {
  return GetQueryResultsMap("SELECT connection FROM connections WHERE username = ?", user)
}

func GetNetworkList(user string) ([]User, error) {
  query := "SELECT first_name, last_name, role, users.username, secret, discoverable, ssid, connections.status FROM users LEFT JOIN networks USING (network_id) INNER JOIN connections ON users.username = connections.connection AND connections.username = ? OR users.username = connections.username AND connections.connection = ?"
  return GetQueryUserList(query, 8, user, user)
}

func InsertNewConnection(username string, connection string) (error) {
	db := GetDatabaseInstance()
	_, err := db.Exec("INSERT INTO connections VALUES (?, ?, 'pending')", username, connection)
	return err
}

func UpdateConnectionStatus(username string, connection string) (error) {
	db := GetDatabaseInstance()
	_, err := db.Exec("UPDATE connections SET status = 'connected' WHERE username = ? AND connection = ?",
												connection, username)
	return err
}

func DeleteConnection(username string, connection string) (int64, error) {
  primaryUser, connectUser, err := getUserRelationship(username, connection)
  if err != nil {
    return 0, errors.New("Connection Search Error!")
  }
  return PostDeleteQuery("DELETE FROM connections WHERE username = ? AND connection = ?",
                              primaryUser, connectUser)
}

func getUserRelationship(username string, connection string) (string, string, error) {
  userMap, err := GetConnectionsMap(connection)
  if err != nil {
    return username, connection, err
  }
  if userMap[username] {
    primaryUser := connection
    connectUser := username
    return primaryUser, connectUser, nil
  }

  return username, connection, nil
}
<commit_msg>added call to getUserRelationship to fix issue with UpdateUserConnection<commit_after>package db

import (
  . "seeme/models"

	"errors"
)

func GetConnectionsMap(user string) (map[string]bool, error) {
  return GetQueryResultsMap("SELECT connection FROM connections WHERE username = ?", user)
}

func GetNetworkList(user string) ([]User, error) {
  query := "SELECT first_name, last_name, role, users.username, secret, discoverable, ssid, connections.status FROM users LEFT JOIN networks USING (network_id) INNER JOIN connections ON users.username = connections.connection AND connections.username = ? OR users.username = connections.username AND connections.connection = ?"
  return GetQueryUserList(query, 8, user, user)
}

func InsertNewConnection(username string, connection string) (error) {
	db := GetDatabaseInstance()
	_, err := db.Exec("INSERT INTO connections VALUES (?, ?, 'pending')", username, connection)
	return err
}

func UpdateConnectionStatus(username string, connection string) (error) {
	db := GetDatabaseInstance()
  primaryUser, connectUser, err := getUserRelationship(username, connection)
  if err != nil {
    return err
  }
	_, err = db.Exec("UPDATE connections SET status = 'connected' WHERE username = ? AND connection = ?",
												primaryUser, connectUser)
	return err
}

func DeleteConnection(username string, connection string) (int64, error) {
  primaryUser, connectUser, err := getUserRelationship(username, connection)
  if err != nil {
    return 0, errors.New("Connection Search Error!")
  }
  return PostDeleteQuery("DELETE FROM connections WHERE username = ? AND connection = ?",
                              primaryUser, connectUser)
}

func getUserRelationship(username string, connection string) (string, string, error) {
  userMap, err := GetConnectionsMap(connection)
  if err != nil {
    return username, connection, err
  }
  if userMap[username] {
    primaryUser := connection
    connectUser := username
    return primaryUser, connectUser, nil
  }

  return username, connection, nil
}
<|endoftext|>


<commit_before>package bild

import "image"

// Box Blur returns a blurred (average) version of the image
func Box(src image.Image) *image.NRGBA {
	k := Kernel{[3][3]int32{
		{1, 1, 1},
		{1, 1, 1},
		{1, 1, 1},
	}}

	img := cloneAsNRGBA(src)
	return convolute(img, &k)
}

// Gaussian Blur returns a blurred version of the image using
// an approximation to the Gaussian function
func Gaussian(src image.Image, iterations int) *image.NRGBA {
	k := Kernel{[3][3]int32{
		{1, 2, 1},
		{2, 4, 2},
		{1, 2, 1},
	}}

	result := cloneAsNRGBA(src)
	for i := 0; i < iterations; i++ {
		result = convolute(result, &k)
	}

	return result
}
<commit_msg>simplified blur functions<commit_after>package bild

import (
	"image"
	"math"
)

// Box Blur returns a blurred (average) version of the image
func Box(src image.Image, size int) *image.NRGBA {
	k := NewKernel(size)

	for x := 0; x < size; x++ {
		for y := 0; y < size; y++ {
			k.Matrix[x][y] = 1
		}
	}

	img := cloneAsNRGBA(src)
	return convolute(img, k)
}

// Gaussian Blur returns a blurred version of the image using
// an approximation to the Gaussian function
func Gaussian(src image.Image, radius float64) *image.NRGBA {
	size := int(math.Ceil(radius) * 2)
	k := NewKernel(size + 1)

	for x := 0; x <= size; x++ {
		for y := 0; y <= size; y++ {
			k.Matrix[x][y] = gaussianFunc(float64(x)-radius, float64(y)-radius, radius)
		}
	}

	img := cloneAsNRGBA(src)
	return convolute(img, k)
}
<|endoftext|>


<commit_before>package xmltree_test

import (
	"fmt"
	"log"

	"aqwari.net/xml/xmltree"
)

func ExampleElement_Search() {
	data := `
	  <Staff>
        <Person>
            <FullName>Ira Glass</FullName>
        </Person>
        <Person>
            <FullName>Tom Magliozzi</FullName>
        </Person>
        <Person>
            <FullName>Terry Gross</FullName>
        </Person>
    </Staff>
	`
	root, err := xmltree.Parse([]byte(data))
	if err != nil {
		log.Fatal(err)
	}
	for _, el := range root.Search("", "FullName") {
		fmt.Printf("%s\n", el.Content)
	}

	// Output:
	// Ira Glass
	// Tom Magliozzi
	// Terry Gross
}

func ExampleElement_Resolve() {
	data := `
    <collection xmlns:ns="http://ns1.net/">
      <record xmlns:ns="http://ns2.net/">
        <name>Old Town</name>
        <artist xmlns:ns="http://ns3.net/">
          <name>Mustafa Grits</name>
        </artist>
      </record>
      <record xmlns:ns="http://ns4.net/">
        <name>New Town</name>
      </record>
    </collection>
	`
	root, err := xmltree.Parse([]byte(data))
	if err != nil {
		log.Fatal(err)
	}

	// Flatten the tree in depth-first order
	flattened := root.SearchFunc(func(*xmltree.Element) bool { return true })

	fmt.Printf("%s <%s>\n", root.Resolve("ns:foo").Space, root.Name.Local)
	for _, el := range flattened {
		fmt.Printf("%s <%s>\n", el.Resolve("ns:foo").Space, el.Name.Local)
	}

	// Output:
	// http://ns1.net/ <collection>
	// http://ns2.net/ <record>
	// http://ns2.net/ <name>
	// http://ns3.net/ <artist>
	// http://ns3.net/ <name>
	// http://ns4.net/ <record>
	// http://ns4.net/ <name>
}

func ExampleElement_SearchFunc() {
	data := `
	  <People>
        <Person>
            <FullName>Grace R. Emlin</FullName>
            <Email where="home">
                <Addr>gre@example.com</Addr>
            </Email>
            <Email where='work'>
                <Addr>gre@work.com</Addr>
            </Email>
        </Person>
        <Person>
            <FullName>Michael P. Thompson</FullName>
            <Email where="home">
                <Addr>michaelp@example.com</Addr>
            </Email>
            <Email where='work'>
                <Addr>michaelp@work.com</Addr>
                <Addr>michael.thompson@work.com</Addr>
            </Email>
        </Person>
    </People>
	`

	root, err := xmltree.Parse([]byte(data))
	if err != nil {
		log.Fatal(err)
	}

	workEmails := root.SearchFunc(func(el *xmltree.Element) bool {
		return el.Name.Local == "Email" && el.Attr("", "where") == "work"
	})

	for _, el := range workEmails {
		for _, addr := range el.Children {
			fmt.Printf("%s\n", addr.Content)
		}
	}

	// Output:
	// gre@work.com
	// michaelp@work.com
	// michael.thompson@work.com
}
<commit_msg>Add examples for marshal/unmarshal<commit_after>package xmltree_test

import (
	"fmt"
	"log"

	"aqwari.net/xml/xmltree"
)

func ExampleElement_Search() {
	data := `
	  <Staff>
        <Person>
            <FullName>Ira Glass</FullName>
        </Person>
        <Person>
            <FullName>Tom Magliozzi</FullName>
        </Person>
        <Person>
            <FullName>Terry Gross</FullName>
        </Person>
    </Staff>
	`
	root, err := xmltree.Parse([]byte(data))
	if err != nil {
		log.Fatal(err)
	}
	for _, el := range root.Search("", "FullName") {
		fmt.Printf("%s\n", el.Content)
	}

	// Output:
	// Ira Glass
	// Tom Magliozzi
	// Terry Gross
}

func ExampleElement_Resolve() {
	data := `
    <collection xmlns:ns="http://ns1.net/">
      <record xmlns:ns="http://ns2.net/">
        <name>Old Town</name>
        <artist xmlns:ns="http://ns3.net/">
          <name>Mustafa Grits</name>
        </artist>
      </record>
      <record xmlns:ns="http://ns4.net/">
        <name>New Town</name>
      </record>
    </collection>
	`
	root, err := xmltree.Parse([]byte(data))
	if err != nil {
		log.Fatal(err)
	}

	// Flatten the tree in depth-first order
	flattened := root.SearchFunc(func(*xmltree.Element) bool { return true })

	fmt.Printf("%s <%s>\n", root.Resolve("ns:foo").Space, root.Name.Local)
	for _, el := range flattened {
		fmt.Printf("%s <%s>\n", el.Resolve("ns:foo").Space, el.Name.Local)
	}

	// Output:
	// http://ns1.net/ <collection>
	// http://ns2.net/ <record>
	// http://ns2.net/ <name>
	// http://ns3.net/ <artist>
	// http://ns3.net/ <name>
	// http://ns4.net/ <record>
	// http://ns4.net/ <name>
}

func ExampleElement_SearchFunc() {
	data := `
	  <People>
        <Person>
            <FullName>Grace R. Emlin</FullName>
            <Email where="home">
                <Addr>gre@example.com</Addr>
            </Email>
            <Email where='work'>
                <Addr>gre@work.com</Addr>
            </Email>
        </Person>
        <Person>
            <FullName>Michael P. Thompson</FullName>
            <Email where="home">
                <Addr>michaelp@example.com</Addr>
            </Email>
            <Email where='work'>
                <Addr>michaelp@work.com</Addr>
                <Addr>michael.thompson@work.com</Addr>
            </Email>
        </Person>
    </People>
	`

	root, err := xmltree.Parse([]byte(data))
	if err != nil {
		log.Fatal(err)
	}

	workEmails := root.SearchFunc(func(el *xmltree.Element) bool {
		return el.Name.Local == "Email" && el.Attr("", "where") == "work"
	})

	for _, el := range workEmails {
		for _, addr := range el.Children {
			fmt.Printf("%s\n", addr.Content)
		}
	}

	// Output:
	// gre@work.com
	// michaelp@work.com
	// michael.thompson@work.com
}

func ExampleUnmarshal() {
	var input = []byte(`<mediawiki xml:lang="en">
	  <page>
	    <title>Page title</title>
	    <restrictions>edit=sysop:move=sysop</restrictions>
	    <revision>
	      <timestamp>2001-01-15T13:15:00Z</timestamp>
	      <contributor><username>Foobar</username></contributor>
	      <comment>I have just one thing to say!</comment>
	      <text>A bunch of [[text]] here.</text>
	      <minor />
	    </revision>
	    <revision>
	      <timestamp>2001-01-15T13:10:27Z</timestamp>
	      <contributor><ip>10.0.0.2</ip></contributor>
	      <comment>new!</comment>
	      <text>An earlier [[revision]].</text>
	    </revision>
	  </page>

	  <page>
	    <title>Talk:Page title</title>
	    <revision>
	      <timestamp>2001-01-15T14:03:00Z</timestamp>
	      <contributor><ip>10.0.0.2</ip></contributor>
	      <comment>hey</comment>
	      <text>WHYD YOU LOCK PAGE??!!! i was editing that jerk</text>
	    </revision>
	  </page>
	</mediawiki>`)

	type revision struct {
		Timestamp   string   `xml:"timestamp"`
		Contributor string   `xml:"contributor>ip"`
		Comment     string   `xml:"comment"`
		Text        []string `xml:"text"`
	}

	root, err := xmltree.Parse(input)
	if err != nil {
		log.Fatal(err)
	}

	// Pull all <revision> items from the input
	for _, el := range root.Search("", "revision") {
		var rev revision
		if err := xmltree.Unmarshal(el, &rev); err != nil {
			log.Print(err)
			continue
		}
		fmt.Println(rev.Timestamp, rev.Comment)
	}

	// Output:
	// 2001-01-15T13:15:00Z I have just one thing to say!
	// 2001-01-15T13:10:27Z new!
	// 2001-01-15T14:03:00Z hey
}

func ExampleMarshal() {
	var input = []byte(`<?xml version="1.0" encoding="UTF-8"?>
	<toc>
	  <chapter-list>
	    <chapter>
	      <title>Civilizing Huck.Miss Watson.Tom Sawyer Waits.</title>
	      <number>1</number>
	    </chapter>
	    <chapter>
	      <title>The Boys Escape Jim.Torn Sawyer's Gang.Deep-laid Plans.</title>
	      <number>2</number>
	    </chapter>
	    <chapter>
	      <title>A Good Going-over.Grace Triumphant."One of Tom Sawyers's Lies".</title>
	      <number>3</number>
	    </chapter>
	    <chapter>
	      <title>Huck and the Judge.Superstition.</title>
	      <number>4</number>
	    </chapter>
	  </chapter-list>
	</toc>`)

	var chapters []xmltree.Element
	root, err := xmltree.Parse(input)
	if err != nil {
		log.Fatal(err)
	}

	for _, el := range root.Search("", "chapter") {
		for _, child := range el.Search("", "title") {
			el.Content = child.Content
		}
		el.Children = nil
		chapters = append(chapters, *el)
	}
	root.Children = chapters
	fmt.Printf("%s\n", xmltree.MarshalIndent(root, "", "  "))

	// Output:
	// <toc>
	//   <chapter>Civilizing Huck.Miss Watson.Tom Sawyer Waits.</chapter>
	//   <chapter>The Boys Escape Jim.Torn Sawyer's Gang.Deep-laid Plans.</chapter>
	//   <chapter>A Good Going-over.Grace Triumphant."One of Tom Sawyers's Lies".</chapter>
	//   <chapter>Huck and the Judge.Superstition.</chapter>
	// </toc>
}
<|endoftext|>


<commit_before>package bone

import "net/http"

type Mux struct {
	Handlers map[string]http.Handler
	NotFound http.Handler
}

func NewMux() *Mux {
	return &Mux{make(map[string]http.Handler), nil}
}

func (m *Mux) SetNotFound(h http.Handler) {
	m.NotFound = h
}

func (m *Mux) Handle(path string, h http.Handler) {
	if path != "" {
		m.Handlers[path] = h
	} else {
		panic("Non-Valid Path")
	}
}

func (m *Mux) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var valid = ""
	for k, _ := range m.Handlers {
		if req.URL.Path == k {
			valid = k
		}
	}
	if valid != "" {
		m.Handlers[valid].ServeHTTP(rw, req)
	} else {
		if m.NotFound != nil {
			m.NotFound.ServeHTTP(rw, req)
		} else {
			http.NotFound(rw, req)
		}
	}

}
<commit_msg>Add HTTP method function<commit_after>package bone

import (
	"net/http"
)

type Mux struct {
	handlers map[string]map[string]http.Handler
	NotFound http.Handler
}

func NewMux() *Mux {
	return &Mux{make(map[string]map[string]http.Handler), nil}
}

func (m *Mux) SetNotFound(h http.HandlerFunc) {
	m.NotFound = h
}

func (m *Mux) handle(meth string, path string, h http.Handler) {
	if path != "" {
		if m.handlers[path] != nil {
			m.handlers[path][meth] = h
		} else {
			m.handlers[path] = make(map[string]http.Handler)
			m.handlers[path][meth] = h
		}
	} else {
		panic("Non-Valid Path")
	}
}

// GET set Handler valid method to GET only.
func (m *Mux) GET(path string, h http.Handler) {
	m.handle("GET", path, h)
}

// POST set Handler valid method to POST only.
func (m *Mux) POST(path string, h http.Handler) {
	m.handle("POST", path, h)
}

// DELETE set Handler valid method to DELETE only.
func (m *Mux) DELETE(path string, h http.Handler) {
	m.handle("DELETE", path, h)
}

// PUT set Handler valid method to PUT only.
func (m *Mux) PUT(path string, h http.Handler) {
	m.handle("PUT", path, h)
}

func (m *Mux) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	var path = req.URL.Path
	var meth = req.Method

	if h, ok := m.handlers[path]; ok {
		if m, ok := h[meth]; ok {
			m.ServeHTTP(rw, req)
		} else {
			http.Error(rw, "Bad HTTP Method", http.StatusBadRequest)
		}
	} else {
		switch m.NotFound {
		case nil:
			http.NotFound(rw, req)
		default:
			m.NotFound.ServeHTTP(rw, req)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"text/template"

	"github.com/deis/deis/pkg/aboutme"
	"github.com/deis/deis/tests/utils"
)

type Secret struct {
	Host      string
	KeyID     string
	AccessKey string
}

const configdir = "/home/minio/.minio/"
const templv3 = `{
	"version": "3",
	"alias": {
		"dl": "https://dl.minio.io:9000",
		"localhost": "http://localhost:9000",
		"play": "https://play.minio.io:9000",
		"s3": "https://s3.amazonaws.com"
	},
  "hosts": {
  {{range .}}
		"{{.Host}}": {
			"access-key-id": "{{.KeyID}}" ,
			"secret-access-key": "{{.AccessKey}}"
		},
    {{end}}
		"127.0.0.1:*": {
			"access-key-id": "",
			"secret-access-key": ""
		}
	}
}
`

const templv2 = `{
	"version": "2",
	"credentials": {
  {{range .}}
		"accessKeyId": "{{.KeyID}}",
		"secretAccessKey": "{{.AccessKey}}"
  {{end}}
	},
	"mongoLogger": {
		"addr": "",
		"db": "",
		"collection": ""
	},
	"syslogLogger": {
		"network": "",
		"addr": ""
	},
	"fileLogger": {
		"filename": ""
	}
}`

func run(cmd string) {
	var cmdBuf bytes.Buffer
	tmpl := template.Must(template.New("cmd").Parse(cmd))
	if err := tmpl.Execute(&cmdBuf, nil); err != nil {
		log.Fatal(err)
	}
	cmdString := cmdBuf.String()
	fmt.Println(cmdString)
	var cmdl *exec.Cmd
	cmdl = exec.Command("sh", "-c", cmdString)
	if _, _, err := utils.RunCommandWithStdoutStderr(cmdl); err != nil {
		log.Fatal(err)
	} else {
		fmt.Println("ok")
	}
}

func readSecrets() (string, string) {
	keyID, err := ioutil.ReadFile("/var/run/secrets/deis/minio/admin/access-key-id")
	checkError(err)
	accessKey, err := ioutil.ReadFile("/var/run/secrets/deis/minio/admin/access-secret-key")
	checkError(err)
	return strings.TrimSpace(string(keyID)), strings.TrimSpace(string(accessKey))
}

func main() {
	pod, err := aboutme.FromEnv()
	checkError(err)
	key, access := readSecrets()
	secrets := []Secret{
		{
			Host:      pod.IP,
			KeyID:     key,
			AccessKey: access,
		},
	}
	t := template.New("Secret template")

	t, err = t.Parse(templv2)

	checkError(err)
	err = os.MkdirAll(configdir, 0755)
	checkError(err)
	output, err := os.Create(configdir + "config.json")
	err = t.Execute(output, secrets)
	checkError(err)
<<<<<<< 96acc9aed140bcf5522c9fad23036fd68faa81c3
	os.Args[0] = "/usr/bin/minio"
=======
	os.Args[0] = "minio"
>>>>>>> feat(minio): add starter program for minio
	mc := strings.Join(os.Args, " ")
	run(mc)
}

func checkError(err error) {
	if err != nil {
		fmt.Println("Fatal error ", err.Error())
		os.Exit(1)
	}
}
<commit_msg>feat(minio): add starter program for minio<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"text/template"

	"github.com/deis/deis/pkg/aboutme"
	"github.com/deis/deis/tests/utils"
)

type Secret struct {
	Host      string
	KeyID     string
	AccessKey string
}

const configdir = "/home/minio/.minio/"
const templv3 = `{
	"version": "3",
	"alias": {
		"dl": "https://dl.minio.io:9000",
		"localhost": "http://localhost:9000",
		"play": "https://play.minio.io:9000",
		"s3": "https://s3.amazonaws.com"
	},
  "hosts": {
  {{range .}}
		"{{.Host}}": {
			"access-key-id": "{{.KeyID}}" ,
			"secret-access-key": "{{.AccessKey}}"
		},
    {{end}}
		"127.0.0.1:*": {
			"access-key-id": "",
			"secret-access-key": ""
		}
	}
}
`

const templv2 = `{
	"version": "2",
	"credentials": {
  {{range .}}
		"accessKeyId": "{{.KeyID}}",
		"secretAccessKey": "{{.AccessKey}}"
  {{end}}
	},
	"mongoLogger": {
		"addr": "",
		"db": "",
		"collection": ""
	},
	"syslogLogger": {
		"network": "",
		"addr": ""
	},
	"fileLogger": {
		"filename": ""
	}
}`

func run(cmd string) {
	var cmdBuf bytes.Buffer
	tmpl := template.Must(template.New("cmd").Parse(cmd))
	if err := tmpl.Execute(&cmdBuf, nil); err != nil {
		log.Fatal(err)
	}
	cmdString := cmdBuf.String()
	fmt.Println(cmdString)
	var cmdl *exec.Cmd
	cmdl = exec.Command("sh", "-c", cmdString)
	if _, _, err := utils.RunCommandWithStdoutStderr(cmdl); err != nil {
		log.Fatal(err)
	} else {
		fmt.Println("ok")
	}
}

func readSecrets() (string, string) {
	keyID, err := ioutil.ReadFile("/var/run/secrets/deis/minio/admin/access-key-id")
	checkError(err)
	accessKey, err := ioutil.ReadFile("/var/run/secrets/deis/minio/admin/access-secret-key")
	checkError(err)
	return strings.TrimSpace(string(keyID)), strings.TrimSpace(string(accessKey))
}

func main() {
	pod, err := aboutme.FromEnv()
	checkError(err)
	key, access := readSecrets()
	secrets := []Secret{
		{
			Host:      pod.IP,
			KeyID:     key,
			AccessKey: access,
		},
	}
	t := template.New("Secret template")

	t, err = t.Parse(templv2)

	checkError(err)
	err = os.MkdirAll(configdir, 0755)
	checkError(err)
	output, err := os.Create(configdir + "config.json")
	err = t.Execute(output, secrets)
	checkError(err)
	os.Args[0] = "minio"
	mc := strings.Join(os.Args, " ")
	run(mc)
}

func checkError(err error) {
	if err != nil {
		fmt.Println("Fatal error ", err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


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

// +build darwin dragonfly freebsd linux,amd64 linux,arm netbsd openbsd

package tcp

import (
	"syscall"
	"unsafe"
)

func getsockopt(fd int, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
	if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
		return error(errno)
	}
	return nil
}

func getsockoptIntByIoctl(fd, ioc int) (int, error) {
	var i int
	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(ioc), uintptr(unsafe.Pointer(&i))); errno != 0 {
		return 0, error(errno)
	}
	return i, nil
}
<commit_msg>tcp: add support for linux/{ppc64,ppc64le}<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux,amd64 linux,arm linux,ppc64 linux,ppc64le netbsd openbsd

package tcp

import (
	"syscall"
	"unsafe"
)

func getsockopt(fd int, level, name int, v unsafe.Pointer, l *sysSockoptLen) error {
	if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
		return error(errno)
	}
	return nil
}

func getsockoptIntByIoctl(fd, ioc int) (int, error) {
	var i int
	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(ioc), uintptr(unsafe.Pointer(&i))); errno != 0 {
		return 0, error(errno)
	}
	return i, nil
}
<|endoftext|>


<commit_before>package plugins

import (
	"strconv"
	"ircclient"
	"fmt"
	"regexp"
)

type AuthPlugin struct {
	ic       *ircclient.IRCClient
	confplugin *ConfigPlugin
}

func NewAuthPlugin() *AuthPlugin {
	return &AuthPlugin{nil, nil}
}
func (a *AuthPlugin) Register(cl *ircclient.IRCClient) {
	a.ic = cl
	plugin, ok := a.ic.GetPlugin("config")
	if !ok {
		panic("AuthPlugin: Register: Unable to get configuration manager plugin")
	}
	a.confplugin, _ = plugin.(*ConfigPlugin)
	if !a.confplugin.Conf.HasSection("Auth") {
		panic("No \"Auth\" section in config file present")
	}
	options, _ := a.confplugin.Conf.Options("Auth")
	for _, mask := range options {
		if _, err := regexp.Compile(mask); err != nil {
			panic(err.String())
		}
	}
}
func (a *AuthPlugin) String() string {
	return "auth"
}
func (a *AuthPlugin) ProcessLine(msg *ircclient.IRCMessage) {
	// Empty
}
func (a *AuthPlugin) Unregister() {
	// Empty
}
func (a *AuthPlugin) Info() string {
	return "Access control manager"
}
func (a *AuthPlugin) ProcessCommand(cmd *ircclient.IRCCommand) {
	switch cmd.Command {
	case "myaccess": fallthrough
	case "mya":
		level := a.GetAccessLevel(cmd.Source)
		slevel := fmt.Sprintf("%d", level)
		a.ic.Reply(cmd, "Your access level is: " + slevel)
	case "addaccess":
		fmt.Printf("%#v\n", cmd.Args)
		if len(cmd.Args) != 2 {
			a.ic.Reply(cmd, "addaccess takes two arguments: mask and access level")
			return
		}
		level := a.GetAccessLevel(cmd.Source)
		newlevel, err := strconv.Atoi(cmd.Args[1])
		if err != nil {
			a.ic.Reply(cmd, "Error: " + err.String())
		}
		if level < newlevel || level < 400 {
			a.ic.Reply(cmd, "You are not authorized to do this")
		}
		a.confplugin.Lock()
		a.confplugin.Conf.AddOption("Auth", cmd.Args[0], fmt.Sprintf("%d", newlevel))
		a.confplugin.Unlock()
		a.ic.Reply(cmd, "Permissions granted")
	}
}
func (a *AuthPlugin) GetAccessLevel(host string) int {
	a.confplugin.Lock()
	options, _ := a.confplugin.Conf.Options("Auth")
	maxaccess := 0
	for _, mask := range options {
		fmt.Println(mask)
		if match, _ := regexp.MatchString(mask, host); match == true {
			newaccess, _ := a.confplugin.Conf.Int("Auth", mask)
			if newaccess > maxaccess {
				maxaccess = newaccess
			}
		}
	}
	defer a.confplugin.Unlock()
	return maxaccess
}
<commit_msg>Remove debugging output<commit_after>package plugins

import (
	"strconv"
	"ircclient"
	"fmt"
	"regexp"
)

type AuthPlugin struct {
	ic       *ircclient.IRCClient
	confplugin *ConfigPlugin
}

func NewAuthPlugin() *AuthPlugin {
	return &AuthPlugin{nil, nil}
}
func (a *AuthPlugin) Register(cl *ircclient.IRCClient) {
	a.ic = cl
	plugin, ok := a.ic.GetPlugin("config")
	if !ok {
		panic("AuthPlugin: Register: Unable to get configuration manager plugin")
	}
	a.confplugin, _ = plugin.(*ConfigPlugin)
	if !a.confplugin.Conf.HasSection("Auth") {
		panic("No \"Auth\" section in config file present")
	}
	options, _ := a.confplugin.Conf.Options("Auth")
	for _, mask := range options {
		if _, err := regexp.Compile(mask); err != nil {
			panic(err.String())
		}
	}
}
func (a *AuthPlugin) String() string {
	return "auth"
}
func (a *AuthPlugin) ProcessLine(msg *ircclient.IRCMessage) {
	// Empty
}
func (a *AuthPlugin) Unregister() {
	// Empty
}
func (a *AuthPlugin) Info() string {
	return "Access control manager"
}
func (a *AuthPlugin) ProcessCommand(cmd *ircclient.IRCCommand) {
	switch cmd.Command {
	case "myaccess": fallthrough
	case "mya":
		level := a.GetAccessLevel(cmd.Source)
		slevel := fmt.Sprintf("%d", level)
		a.ic.Reply(cmd, "Your access level is: " + slevel)
	case "addaccess":
		if len(cmd.Args) != 2 {
			a.ic.Reply(cmd, "addaccess takes two arguments: mask and access level")
			return
		}
		level := a.GetAccessLevel(cmd.Source)
		newlevel, err := strconv.Atoi(cmd.Args[1])
		if err != nil {
			a.ic.Reply(cmd, "Error: " + err.String())
		}
		if level < newlevel || level < 400 {
			a.ic.Reply(cmd, "You are not authorized to do this")
		}
		a.confplugin.Lock()
		a.confplugin.Conf.AddOption("Auth", cmd.Args[0], fmt.Sprintf("%d", newlevel))
		a.confplugin.Unlock()
		a.ic.Reply(cmd, "Permissions granted")
	}
}
func (a *AuthPlugin) GetAccessLevel(host string) int {
	a.confplugin.Lock()
	options, _ := a.confplugin.Conf.Options("Auth")
	maxaccess := 0
	for _, mask := range options {
		if match, _ := regexp.MatchString(mask, host); match == true {
			newaccess, _ := a.confplugin.Conf.Int("Auth", mask)
			if newaccess > maxaccess {
				maxaccess = newaccess
			}
		}
	}
	defer a.confplugin.Unlock()
	return maxaccess
}
<|endoftext|>


<commit_before>package tally

import (
	"fmt"
	"io"
	"log"
	"time"

	"github.com/qmsk/e2/client"
	"github.com/qmsk/e2/discovery"
)

func newSource(tally *Tally, discoveryPacket discovery.Packet, clientOptions client.Options) (Source, error) {
	source := Source{
		options:         tally.options,
		created:         time.Now(),
		discoveryPacket: discoveryPacket,
		clientOptions:   clientOptions,
	}

	// do not connect to slave VPs
	if discoveryPacket.MasterMac != discoveryPacket.MacAddress {
		return source, nil
	}

	// give updates every 10s when idle
	clientOptions.ReadKeepalive = true

	if xmlClient, err := clientOptions.XMLClient(); err != nil {
		return source, err
	} else {
		source.xmlClient = xmlClient
	}

	go source.run(tally.sourceChan)

	return source, nil
}

// E2 XML source
//
// A source can either be in a running state with err == nil, or in a failed state with err != nil
type Source struct {
	options Options
	created time.Time
	updated time.Time

	discoveryPacket discovery.Packet
	clientOptions   client.Options
	xmlClient       *client.XMLClient

	system client.System
	closed bool
	err    error
}

func (source Source) String() string {
	return source.clientOptions.String()
}

func (source Source) run(updateChan chan Source) {
	for {
		if system, err := source.xmlClient.Read(); err == nil {
			source.system = system
		} else if err == io.EOF {
			source.closed = true
		} else {
			source.err = err
		}

		updateChan <- source

		if source.closed || source.err != nil {
			log.Printf("tally:Source %v: closed", source)
			return
		}
	}
}

func (source Source) updateState(state *State) error {
	tallySource := source.String()

	if source.err != nil {
		return source.err
	}

	if source.xmlClient == nil {
		// not connected
		return nil
	}

	system := source.system

	for sourceID, systemSource := range system.SrcMgr.SourceCol.List() {
		// lookup Input from inputCfg with tally=
		if systemSource.InputCfgIndex < 0 {
			continue
		}
		inputCfg := system.SrcMgr.InputCfgCol[systemSource.InputCfgIndex]
		inputName := inputCfg.Name

		// resolve ID
		var tallyID ID

		if match := source.options.contactIDRegexp.FindStringSubmatch(inputCfg.ConfigContact); match == nil {
			continue
		} else if _, err := fmt.Sscanf(match[1], "%d", &tallyID); err != nil {
			return fmt.Errorf("Invalid Input Contact=%v: %v\n", inputCfg.ConfigContact, err)
		}

		input := state.addInput(tallySource, inputName, tallyID, inputCfg.InputCfgVideoStatus.String())

		// input state
		if inputCfg.InputCfgVideoStatus == client.InputVideoStatusBad {
			state.addTallyError(tallyID, input, fmt.Errorf("Source %v Input %v video status: %v", tallySource, inputName, inputCfg.InputCfgVideoStatus))
		}

		// lookup active Links
		for _, screen := range system.DestMgr.ScreenDestCol {
			// ignore?
			if source.options.ignoreDestRegexp != nil && source.options.ignoreDestRegexp.MatchString(screen.Name) {
				continue
			}

			var status Status

			if screen.IsActive > 0 {
				status.Active = true
			}

			if screen.Transition[0].InProgress() {
				status.Transition = screen.Transition[0].Progress()

				log.Printf("tally:Source %v: Screen %v: Transition in progress: %#v", source, screen.Name, status.Transition)
			}

			for _, layer := range screen.LayerCollection {
				if layer.LastSrcIdx == sourceID {
					if layer.PvwMode > 0 {
						status.Preview = true
					}
					if layer.PgmMode > 0 {
						status.Program = true
					}
				}
			}

			output := state.addOutput(tallySource, screen.Name)

			if status.Preview || status.Program {
				state.addLink(Link{
					Tally:  tallyID,
					Input:  input,
					Output: output,
					Status: status,
				})
			}
		}

		for _, aux := range system.DestMgr.AuxDestCol {
			// ignore?
			if source.options.ignoreDestRegexp != nil && source.options.ignoreDestRegexp.MatchString(aux.Name) {
				continue
			}

			output := state.addOutput(tallySource, aux.Name)

			if aux.PvwLastSrcIndex == sourceID || aux.PgmLastSrcIndex == sourceID {
				state.addLink(Link{
					Tally:  tallyID,
					Input:  input,
					Output: output,
					Status: Status{
						Preview: (aux.PvwLastSrcIndex == sourceID),
						Program: (aux.PgmLastSrcIndex == sourceID),
						Active:  (aux.IsActive > 0),
					},
				})
			}
		}
	}

	return nil
}

// close, causing run() to exit
func (source Source) close() {
	if source.xmlClient != nil {
		source.xmlClient.Close()
	}
}

func (source Source) isClosed() bool {
	return source.xmlClient == nil || source.closed
}
<commit_msg>BUGFIX: Deleting inputs caused de-sync on tally mappings<commit_after>package tally

import (
	"fmt"
	"io"
	"log"
	"time"

	"github.com/qmsk/e2/client"
	"github.com/qmsk/e2/discovery"
)

func newSource(tally *Tally, discoveryPacket discovery.Packet, clientOptions client.Options) (Source, error) {
	source := Source{
		options:         tally.options,
		created:         time.Now(),
		discoveryPacket: discoveryPacket,
		clientOptions:   clientOptions,
	}

	// do not connect to slave VPs
	if discoveryPacket.MasterMac != discoveryPacket.MacAddress {
		return source, nil
	}

	// give updates every 10s when idle
	clientOptions.ReadKeepalive = true

	if xmlClient, err := clientOptions.XMLClient(); err != nil {
		return source, err
	} else {
		source.xmlClient = xmlClient
	}

	go source.run(tally.sourceChan)

	return source, nil
}

// E2 XML source
//
// A source can either be in a running state with err == nil, or in a failed state with err != nil
type Source struct {
	options Options
	created time.Time
	updated time.Time

	discoveryPacket discovery.Packet
	clientOptions   client.Options
	xmlClient       *client.XMLClient

	system client.System
	closed bool
	err    error
}

func (source Source) String() string {
	return source.clientOptions.String()
}

func (source Source) run(updateChan chan Source) {
	for {
		if system, err := source.xmlClient.Read(); err == nil {
			source.system = system
		} else if err == io.EOF {
			source.closed = true
		} else {
			source.err = err
		}

		updateChan <- source

		if source.closed || source.err != nil {
			log.Printf("tally:Source %v: closed", source)
			return
		}
	}
}

func (source Source) updateState(state *State) error {
	tallySource := source.String()

	if source.err != nil {
		return source.err
	}

	if source.xmlClient == nil {
		// not connected
		return nil
	}

	system := source.system

	for sourceID, systemSource := range system.SrcMgr.SourceCol {
		// lookup Input from inputCfg with tally=
		if systemSource.InputCfgIndex < 0 {
			continue
		}
		inputCfg := system.SrcMgr.InputCfgCol[systemSource.InputCfgIndex]
		inputName := inputCfg.Name

		// resolve ID
		var tallyID ID

		if match := source.options.contactIDRegexp.FindStringSubmatch(inputCfg.ConfigContact); match == nil {
			continue
		} else if _, err := fmt.Sscanf(match[1], "%d", &tallyID); err != nil {
			return fmt.Errorf("Invalid Input Contact=%v: %v\n", inputCfg.ConfigContact, err)
		}

		input := state.addInput(tallySource, inputName, tallyID, inputCfg.InputCfgVideoStatus.String())

		// input state
		if inputCfg.InputCfgVideoStatus == client.InputVideoStatusBad {
			state.addTallyError(tallyID, input, fmt.Errorf("Source %v Input %v video status: %v", tallySource, inputName, inputCfg.InputCfgVideoStatus))
		}

		// lookup active Links
		for _, screen := range system.DestMgr.ScreenDestCol {
			// ignore?
			if source.options.ignoreDestRegexp != nil && source.options.ignoreDestRegexp.MatchString(screen.Name) {
				continue
			}

			var status Status

			if screen.IsActive > 0 {
				status.Active = true
			}

			if screen.Transition[0].InProgress() {
				status.Transition = screen.Transition[0].Progress()

				log.Printf("tally:Source %v: Screen %v: Transition in progress: %#v", source, screen.Name, status.Transition)
			}

			for _, layer := range screen.LayerCollection {
				if layer.LastSrcIdx == sourceID {
					if layer.PvwMode > 0 {
						status.Preview = true
					}
					if layer.PgmMode > 0 {
						status.Program = true
					}
				}
			}

			output := state.addOutput(tallySource, screen.Name)

			if status.Preview || status.Program {
				state.addLink(Link{
					Tally:  tallyID,
					Input:  input,
					Output: output,
					Status: status,
				})
			}
		}

		for _, aux := range system.DestMgr.AuxDestCol {
			// ignore?
			if source.options.ignoreDestRegexp != nil && source.options.ignoreDestRegexp.MatchString(aux.Name) {
				continue
			}

			output := state.addOutput(tallySource, aux.Name)

			if aux.PvwLastSrcIndex == sourceID || aux.PgmLastSrcIndex == sourceID {
				state.addLink(Link{
					Tally:  tallyID,
					Input:  input,
					Output: output,
					Status: Status{
						Preview: (aux.PvwLastSrcIndex == sourceID),
						Program: (aux.PgmLastSrcIndex == sourceID),
						Active:  (aux.IsActive > 0),
					},
				})
			}
		}
	}

	return nil
}

// close, causing run() to exit
func (source Source) close() {
	if source.xmlClient != nil {
		source.xmlClient.Close()
	}
}

func (source Source) isClosed() bool {
	return source.xmlClient == nil || source.closed
}
<|endoftext|>


<commit_before>package task2

import (
	"fmt"
	"io"
	"log"
	"log/syslog"
	"net/url"
	"os"
	"path/filepath"

	"sync"
)

var LogDir = filepath.Join(os.TempDir(), "sg-log")

func init() {
	err := os.MkdirAll(LogDir, 0700)
	if err != nil {
		log.Fatal(err)
	}
}

type Logger struct {
	*log.Logger
	io.Writer
	Destination string
	c           []io.Closer
}

func (x *Logger) Close() error {
	if len(x.c) == 0 {
		return nil
	}
	for _, c := range x.c {
		err := c.Close()
		if err != nil {
			return err
		}
	}
	return nil
}

func LogURLForTag(tag string) string {
	return fmt.Sprintf("https://papertrailapp.com/groups/591393/events?q=program:%s", url.QueryEscape(tag))
}

func NewLogger(tag string) *Logger {
	logURL := LogURLForTag(tag)
	pw, err := syslog.Dial("udp", "logs.papertrailapp.com:50140", syslog.LOG_INFO, tag)
	if err != nil {
		log.Fatal(err)
	}

	logFile := filepath.Join(LogDir, tag+".log")
	fw, err := os.Create(logFile)
	if err != nil {
		log.Fatal(err)
	}

	mw := io.MultiWriter(fw, pw)

	closersMu.Lock()
	defer closersMu.Unlock()
	closers = append(closers, pw, fw)

	return &Logger{
		Logger:      log.New(mw, "", 0),
		Writer:      mw,
		Destination: fmt.Sprintf("%s and %s", logURL, logFile),
		c:           []io.Closer{pw, fw},
	}
}

var (
	closers   []io.Closer
	closersMu sync.Mutex
)

func FlushAll() {
	closersMu.Lock()
	defer closersMu.Unlock()
	var w sync.WaitGroup
	for _, c := range closers {
		w.Add(1)
		go func() {
			defer w.Done()
			c.Close()
		}()
	}
	w.Wait()
}
<commit_msg>log to papertrail from sgx serve<commit_after>package task2

import (
	"fmt"
	"io"
	"log"
	"log/syslog"
	"net/url"
	"os"
	"path/filepath"

	"sync"
)

var LogDir = filepath.Join(os.TempDir(), "sg-log")

func init() {
	err := os.MkdirAll(LogDir, 0700)
	if err != nil {
		log.Fatal(err)
	}
}

type Logger struct {
	*log.Logger
	io.Writer
	Destination string
	c           []io.Closer
}

func (x *Logger) Close() error {
	if len(x.c) == 0 {
		return nil
	}
	for _, c := range x.c {
		err := c.Close()
		if err != nil {
			return err
		}
	}
	return nil
}

func LogURLForTag(tag string) string {
	return fmt.Sprintf("https://papertrailapp.com/groups/591393/events?q=program:%s", url.QueryEscape(tag))
}

func NewPapertrailLogger(tag string) *syslog.Writer {
	pw, err := syslog.Dial("udp", "logs.papertrailapp.com:50140", syslog.LOG_INFO, tag)
	if err != nil {
		log.Fatal(err)
	}
	return pw
}

func NewLogger(tag string) *Logger {
	logURL := LogURLForTag(tag)
	pw := NewPapertrailLogger(tag)

	logFile := filepath.Join(LogDir, tag+".log")
	fw, err := os.Create(logFile)
	if err != nil {
		log.Fatal(err)
	}

	mw := io.MultiWriter(fw, pw)

	closersMu.Lock()
	defer closersMu.Unlock()
	closers = append(closers, pw, fw)

	return &Logger{
		Logger:      log.New(mw, "", 0),
		Writer:      mw,
		Destination: fmt.Sprintf("%s and %s", logURL, logFile),
		c:           []io.Closer{pw, fw},
	}
}

var (
	closers   []io.Closer
	closersMu sync.Mutex
)

func FlushAll() {
	closersMu.Lock()
	defer closersMu.Unlock()
	var w sync.WaitGroup
	for _, c := range closers {
		w.Add(1)
		go func() {
			defer w.Done()
			c.Close()
		}()
	}
	w.Wait()
}
<|endoftext|>


<commit_before>package ui

import (
	"strings"

	"github.com/elves/elvish/styled"
	"github.com/elves/elvish/util"
)

// BufferBuilder supports building of Buffer.
type BufferBuilder struct {
	Width, Col, Indent int
	// EagerWrap controls whether to wrap line as soon as the cursor reaches the
	// right edge of the terminal. This is not often desirable as it creates
	// unneessary line breaks, but is is useful when echoing the user input.
	// will otherwise
	EagerWrap bool
	// Lines the content of the buffer.
	Lines [][]Cell
	// Dot is what the user perceives as the cursor.
	Dot Pos
}

// NewBufferBuilder makes a new BufferBuilder, initially with one empty line.
func NewBufferBuilder(width int) *BufferBuilder {
	return &BufferBuilder{Width: width, Lines: [][]Cell{make([]Cell, 0, width)}}
}

func (bb *BufferBuilder) Cursor() Pos {
	return Pos{len(bb.Lines) - 1, bb.Col}
}

// Buffer returns a Buffer built by the BufferBuilder.
func (bb *BufferBuilder) Buffer() *Buffer {
	return NewBuffer(bb.Width).SetLines(bb.Lines...).SetDot(bb.Dot)
}

func (bb *BufferBuilder) SetIndent(indent int) *BufferBuilder {
	bb.Indent = indent
	return bb
}

func (bb *BufferBuilder) SetEagerWrap(v bool) *BufferBuilder {
	bb.EagerWrap = v
	return bb
}

func (bb *BufferBuilder) SetLines(lines ...[]Cell) *BufferBuilder {
	bb.Lines = lines
	bb.Col = CellsWidth(lines[len(lines)-1])
	return bb
}

func (bb *BufferBuilder) SetDot(dot Pos) *BufferBuilder {
	bb.Dot = dot
	return bb
}

func (bb *BufferBuilder) SetDotToCursor() *BufferBuilder {
	return bb.SetDot(bb.Cursor())
}

func (bb *BufferBuilder) appendLine() {
	bb.Lines = append(bb.Lines, make([]Cell, 0, bb.Width))
	bb.Col = 0
}

func (bb *BufferBuilder) appendCell(c Cell) {
	n := len(bb.Lines)
	bb.Lines[n-1] = append(bb.Lines[n-1], c)
	bb.Col += int(c.Width)
}

// Newline starts a newline.
func (bb *BufferBuilder) Newline() *BufferBuilder {
	bb.appendLine()

	if bb.Indent > 0 {
		for i := 0; i < bb.Indent; i++ {
			bb.appendCell(Cell{Text: " ", Width: 1})
		}
	}

	return bb
}

var styleForControlChar = Styles{"inverse"}

// Write writes a single rune to a buffer, wrapping the line when needed. If the
// rune is a control character, it will be written using the caret notation
// (like ^X) and gets the additional style of styleForControlChar.
func (bb *BufferBuilder) Write(r rune, style string) *BufferBuilder {
	if r == '\n' {
		bb.Newline()
		return bb
	}
	wd := util.Wcwidth(r)
	c := Cell{string(r), byte(wd), style}
	if r < 0x20 || r == 0x7f {
		wd = 2
		if style != "" {
			style = style + ";" + styleForControlChar.String()
		} else {
			style = styleForControlChar.String()
		}
		c = Cell{"^" + string(r^0x40), 2, style}
	}

	if bb.Col+wd > bb.Width {
		bb.Newline()
		bb.appendCell(c)
	} else {
		bb.appendCell(c)
		if bb.Col == bb.Width && bb.EagerWrap {
			bb.Newline()
		}
	}
	return bb
}

// WriteString writes a string to a buffer, with one style.
func (bb *BufferBuilder) WriteString(text, style string) *BufferBuilder {
	for _, r := range text {
		bb.Write(r, style)
	}
	return bb
}

// WritePlain writes unstyled plain string.
func (bb *BufferBuilder) WritePlain(text string) *BufferBuilder {
	return bb.WriteString(text, "")
}

// WriteSpaces writes w spaces.
func (bb *BufferBuilder) WriteSpaces(w int, style string) *BufferBuilder {
	return bb.WriteString(strings.Repeat(" ", w), style)
}

// WriteLegacyStyleds writes a styled text.
func (bb *BufferBuilder) WriteStyled(t styled.Text) *BufferBuilder {
	return bb.WriteLegacyStyled(t.ToLegacyType())
}

// WriteLegacyStyleds writes a slice of (legacy) styled structs.
func (bb *BufferBuilder) WriteLegacyStyleds(ss []*Styled) *BufferBuilder {
	for _, s := range ss {
		bb.WriteString(s.Text, s.Styles.String())
	}
	return bb
}

// Extend adds all lines from b2 to the bottom of this buffer. If moveDot is
// true, the dot is updated to match the dot of b2.
func (bb *BufferBuilder) Extend(b2 *Buffer, moveDot bool) *BufferBuilder {
	if b2 != nil && b2.Lines != nil {
		if moveDot {
			bb.Dot.Line = b2.Dot.Line + len(bb.Lines)
			bb.Dot.Col = b2.Dot.Col
		}
		bb.Lines = append(bb.Lines, b2.Lines...)
		bb.Col = b2.Col
	}
	return bb
}

// ExtendRight extends bb to the right. It pads each line in bb to be at least of
// width w and appends the corresponding line in b2 to it, making new lines in bb
// when b2 has more lines than bb.
// BUG(xiaq): after calling ExtendRight, the widths of some lines can exceed
// bb.width.
func (bb *BufferBuilder) ExtendRight(b2 *Buffer, w int) *BufferBuilder {
	i := 0
	for ; i < len(bb.Lines) && i < len(b2.Lines); i++ {
		if w0 := CellsWidth(bb.Lines[i]); w0 < w {
			bb.Lines[i] = append(bb.Lines[i], makeSpacing(w-w0)...)
		}
		bb.Lines[i] = append(bb.Lines[i], b2.Lines[i]...)
	}
	for ; i < len(b2.Lines); i++ {
		row := append(makeSpacing(w), b2.Lines[i]...)
		bb.Lines = append(bb.Lines, row)
	}
	bb.Col = CellsWidth(bb.Lines[len(bb.Lines)-1])
	return bb
}

func makeSpacing(n int) []Cell {
	s := make([]Cell, n)
	for i := 0; i < n; i++ {
		s[i].Text = " "
		s[i].Width = 1
	}
	return s
}
<commit_msg>edit/ui: Fix import cycle and typo.<commit_after>package ui

import (
	"strings"

	"github.com/elves/elvish/util"
)

// BufferBuilder supports building of Buffer.
type BufferBuilder struct {
	Width, Col, Indent int
	// EagerWrap controls whether to wrap line as soon as the cursor reaches the
	// right edge of the terminal. This is not often desirable as it creates
	// unneessary line breaks, but is is useful when echoing the user input.
	// will otherwise
	EagerWrap bool
	// Lines the content of the buffer.
	Lines [][]Cell
	// Dot is what the user perceives as the cursor.
	Dot Pos
}

// NewBufferBuilder makes a new BufferBuilder, initially with one empty line.
func NewBufferBuilder(width int) *BufferBuilder {
	return &BufferBuilder{Width: width, Lines: [][]Cell{make([]Cell, 0, width)}}
}

func (bb *BufferBuilder) Cursor() Pos {
	return Pos{len(bb.Lines) - 1, bb.Col}
}

// Buffer returns a Buffer built by the BufferBuilder.
func (bb *BufferBuilder) Buffer() *Buffer {
	return NewBuffer(bb.Width).SetLines(bb.Lines...).SetDot(bb.Dot)
}

func (bb *BufferBuilder) SetIndent(indent int) *BufferBuilder {
	bb.Indent = indent
	return bb
}

func (bb *BufferBuilder) SetEagerWrap(v bool) *BufferBuilder {
	bb.EagerWrap = v
	return bb
}

func (bb *BufferBuilder) SetLines(lines ...[]Cell) *BufferBuilder {
	bb.Lines = lines
	bb.Col = CellsWidth(lines[len(lines)-1])
	return bb
}

func (bb *BufferBuilder) SetDot(dot Pos) *BufferBuilder {
	bb.Dot = dot
	return bb
}

func (bb *BufferBuilder) SetDotToCursor() *BufferBuilder {
	return bb.SetDot(bb.Cursor())
}

func (bb *BufferBuilder) appendLine() {
	bb.Lines = append(bb.Lines, make([]Cell, 0, bb.Width))
	bb.Col = 0
}

func (bb *BufferBuilder) appendCell(c Cell) {
	n := len(bb.Lines)
	bb.Lines[n-1] = append(bb.Lines[n-1], c)
	bb.Col += int(c.Width)
}

// Newline starts a newline.
func (bb *BufferBuilder) Newline() *BufferBuilder {
	bb.appendLine()

	if bb.Indent > 0 {
		for i := 0; i < bb.Indent; i++ {
			bb.appendCell(Cell{Text: " ", Width: 1})
		}
	}

	return bb
}

var styleForControlChar = Styles{"inverse"}

// Write writes a single rune to a buffer, wrapping the line when needed. If the
// rune is a control character, it will be written using the caret notation
// (like ^X) and gets the additional style of styleForControlChar.
func (bb *BufferBuilder) Write(r rune, style string) *BufferBuilder {
	if r == '\n' {
		bb.Newline()
		return bb
	}
	wd := util.Wcwidth(r)
	c := Cell{string(r), byte(wd), style}
	if r < 0x20 || r == 0x7f {
		wd = 2
		if style != "" {
			style = style + ";" + styleForControlChar.String()
		} else {
			style = styleForControlChar.String()
		}
		c = Cell{"^" + string(r^0x40), 2, style}
	}

	if bb.Col+wd > bb.Width {
		bb.Newline()
		bb.appendCell(c)
	} else {
		bb.appendCell(c)
		if bb.Col == bb.Width && bb.EagerWrap {
			bb.Newline()
		}
	}
	return bb
}

// WriteString writes a string to a buffer, with one style.
func (bb *BufferBuilder) WriteString(text, style string) *BufferBuilder {
	for _, r := range text {
		bb.Write(r, style)
	}
	return bb
}

// WritePlain writes unstyled plain string.
func (bb *BufferBuilder) WritePlain(text string) *BufferBuilder {
	return bb.WriteString(text, "")
}

// WriteSpaces writes w spaces.
func (bb *BufferBuilder) WriteSpaces(w int, style string) *BufferBuilder {
	return bb.WriteString(strings.Repeat(" ", w), style)
}

// StyledText is an interface satisfied by styled.Text. This package cannot
// import the styled package as that would result in an import cycle.
type StyledText interface {
	ToLegacyType() []*Styled
}

// WriteLegacyStyleds writes a styled text.
func (bb *BufferBuilder) WriteStyled(t StyledText) *BufferBuilder {
	return bb.WriteLegacyStyleds(t.ToLegacyType())
}

// WriteLegacyStyleds writes a slice of (legacy) styled structs.
func (bb *BufferBuilder) WriteLegacyStyleds(ss []*Styled) *BufferBuilder {
	for _, s := range ss {
		bb.WriteString(s.Text, s.Styles.String())
	}
	return bb
}

// Extend adds all lines from b2 to the bottom of this buffer. If moveDot is
// true, the dot is updated to match the dot of b2.
func (bb *BufferBuilder) Extend(b2 *Buffer, moveDot bool) *BufferBuilder {
	if b2 != nil && b2.Lines != nil {
		if moveDot {
			bb.Dot.Line = b2.Dot.Line + len(bb.Lines)
			bb.Dot.Col = b2.Dot.Col
		}
		bb.Lines = append(bb.Lines, b2.Lines...)
		bb.Col = b2.Col
	}
	return bb
}

// ExtendRight extends bb to the right. It pads each line in bb to be at least of
// width w and appends the corresponding line in b2 to it, making new lines in bb
// when b2 has more lines than bb.
// BUG(xiaq): after calling ExtendRight, the widths of some lines can exceed
// bb.width.
func (bb *BufferBuilder) ExtendRight(b2 *Buffer, w int) *BufferBuilder {
	i := 0
	for ; i < len(bb.Lines) && i < len(b2.Lines); i++ {
		if w0 := CellsWidth(bb.Lines[i]); w0 < w {
			bb.Lines[i] = append(bb.Lines[i], makeSpacing(w-w0)...)
		}
		bb.Lines[i] = append(bb.Lines[i], b2.Lines[i]...)
	}
	for ; i < len(b2.Lines); i++ {
		row := append(makeSpacing(w), b2.Lines[i]...)
		bb.Lines = append(bb.Lines, row)
	}
	bb.Col = CellsWidth(bb.Lines[len(bb.Lines)-1])
	return bb
}

func makeSpacing(n int) []Cell {
	s := make([]Cell, n)
	for i := 0; i < n; i++ {
		s[i].Text = " "
		s[i].Width = 1
	}
	return s
}
<|endoftext|>


<commit_before>// Package webprobe implements a HTTP probe.
package webprobe

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"

	"hkjn.me/prober"
	"hkjn.me/probes"
)

var (
	MaxResponse int64 = 1000000 // largest response size accepted
	defaultName       = "WebProber"
)

// WebProber probes a target's HTTP response.
type WebProber struct {
	Target         string // URL to probe
	Method         string // GET, POST, PUT, etc.
	Name           string // name of the prober
	Body           io.Reader
	wantCode       int
	wantInResponse string
}

// Name sets the name for the prober.
func Name(name string) func(*WebProber) {
	return func(p *WebProber) {
		p.Name = fmt.Sprintf("%s_%s", defaultName, name)
	}
}

// Body sets the HTTP request body for the prober.
func Body(body io.Reader) func(*WebProber) {
	return func(p *WebProber) {
		p.Body = body
	}
}

// InResponse applies the option that the prober wants given string in the HTTP response.
func InResponse(str string) func(*WebProber) {
	return func(p *WebProber) {
		p.wantInResponse = str
	}
}

// New returns a new instance of the web probe with specified options.
func New(target, method string, code int, options ...func(*WebProber)) *prober.Probe {
	return NewWithGeneric(target, method, code, []prober.Option{}, options...)
}

// NewWithGeneric returns a new instance of the web probe with specified options.
//
// NewWithGeneric passes through specified prober.Options, after
// applying the webprobe-specific options.
func NewWithGeneric(target, method string, code int, genericOpts []prober.Option, options ...func(*WebProber)) *prober.Probe {
	name := defaultName
	p := &WebProber{Target: target, Name: name, Method: method, wantCode: code}
	for _, opt := range options {
		opt(p)
	}
	return prober.NewProbe(p, p.Name, fmt.Sprintf("Probes HTTP response of %s", target), genericOpts...)
}

// Probe verifies that the target's HTTP response is as expected.
func (p WebProber) Probe() prober.Result {
	req, err := http.NewRequest(p.Method, p.Target, p.Body)
	if err != nil {
		//		return prober.Result{prober.Fail, fmt.Errorf("failed to create HTTP request: %v", err)}
		return prober.FailedWith(fmt.Errorf("failed to create HTTP request: %v", err))
	}

	t := http.Transport{}
	resp, err := t.RoundTrip(req)
	if err != nil {
		return prober.FailedWith(fmt.Errorf("failed to send HTTP request: %v", err))
	}
	defer resp.Body.Close()

	if resp.StatusCode != p.wantCode {
		return prober.FailedWith(fmt.Errorf("bad HTTP response status; want %d, got %d", p.wantCode, resp.StatusCode))
	}
	body, err := ioutil.ReadAll(io.LimitReader(resp.Body, MaxResponse))
	if err != nil {
		return prober.FailedWith(fmt.Errorf("failed to read HTTP response: %v", err))
	}
	sb := string(body)
	if !strings.Contains(sb, p.wantInResponse) {
		return prober.FailedWith(fmt.Errorf("response doesn't contain %q: \n%v\n", p.wantInResponse, sb))
	}
	return prober.Passed()
}

// Alert sends an alert notification via email.
func (p *WebProber) Alert(name, desc string, badness int, records prober.Records) error {
	return probes.SendAlertEmail(name, desc, badness, records)
}
<commit_msg>Remove commented-out code<commit_after>// Package webprobe implements a HTTP probe.
package webprobe

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"

	"hkjn.me/prober"
	"hkjn.me/probes"
)

var (
	MaxResponse int64 = 1000000 // largest response size accepted
	defaultName       = "WebProber"
)

// WebProber probes a target's HTTP response.
type WebProber struct {
	Target         string // URL to probe
	Method         string // GET, POST, PUT, etc.
	Name           string // name of the prober
	Body           io.Reader
	wantCode       int
	wantInResponse string
}

// Name sets the name for the prober.
func Name(name string) func(*WebProber) {
	return func(p *WebProber) {
		p.Name = fmt.Sprintf("%s_%s", defaultName, name)
	}
}

// Body sets the HTTP request body for the prober.
func Body(body io.Reader) func(*WebProber) {
	return func(p *WebProber) {
		p.Body = body
	}
}

// InResponse applies the option that the prober wants given string in the HTTP response.
func InResponse(str string) func(*WebProber) {
	return func(p *WebProber) {
		p.wantInResponse = str
	}
}

// New returns a new instance of the web probe with specified options.
func New(target, method string, code int, options ...func(*WebProber)) *prober.Probe {
	return NewWithGeneric(target, method, code, []prober.Option{}, options...)
}

// NewWithGeneric returns a new instance of the web probe with specified options.
//
// NewWithGeneric passes through specified prober.Options, after
// applying the webprobe-specific options.
func NewWithGeneric(target, method string, code int, genericOpts []prober.Option, options ...func(*WebProber)) *prober.Probe {
	name := defaultName
	p := &WebProber{Target: target, Name: name, Method: method, wantCode: code}
	for _, opt := range options {
		opt(p)
	}
	return prober.NewProbe(p, p.Name, fmt.Sprintf("Probes HTTP response of %s", target), genericOpts...)
}

// Probe verifies that the target's HTTP response is as expected.
func (p WebProber) Probe() prober.Result {
	req, err := http.NewRequest(p.Method, p.Target, p.Body)
	if err != nil {
		return prober.FailedWith(fmt.Errorf("failed to create HTTP request: %v", err))
	}

	t := http.Transport{}
	resp, err := t.RoundTrip(req)
	if err != nil {
		return prober.FailedWith(fmt.Errorf("failed to send HTTP request: %v", err))
	}
	defer resp.Body.Close()

	if resp.StatusCode != p.wantCode {
		return prober.FailedWith(fmt.Errorf("bad HTTP response status; want %d, got %d", p.wantCode, resp.StatusCode))
	}
	body, err := ioutil.ReadAll(io.LimitReader(resp.Body, MaxResponse))
	if err != nil {
		return prober.FailedWith(fmt.Errorf("failed to read HTTP response: %v", err))
	}
	sb := string(body)
	if !strings.Contains(sb, p.wantInResponse) {
		return prober.FailedWith(fmt.Errorf("response doesn't contain %q: \n%v\n", p.wantInResponse, sb))
	}
	return prober.Passed()
}

// Alert sends an alert notification via email.
func (p *WebProber) Alert(name, desc string, badness int, records prober.Records) error {
	return probes.SendAlertEmail(name, desc, badness, records)
}
<|endoftext|>