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

package bettercsv

import (
	"reflect"
	"strings"
	"testing"
)

var readTests = []struct {
	Name               string
	Input              string
	Output             [][]string
	OutputMap          []map[string]string
	UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1
	UseHeaders         bool // true means use Headers methods for reading
	UseHeadersAndErrs  bool // true means use HeadersAndErrors methods for reading

	// These fields are copied into the Reader
	Comma            rune
	Comment          rune
	FieldsPerRecord  int
	LazyQuotes       bool
	TrailingComma    bool
	TrimLeadingSpace bool
	SkipLineOnErr    bool

	Error  string
	Line   int // Expected error line if != 0
	Column int // Expected error column if line != 0
	Errors []string
}{
	{
		Name:   "Simple",
		Input:  "a,b,c\n",
		Output: [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "CRLF",
		Input:  "a,b\r\nc,d\r\n",
		Output: [][]string{{"a", "b"}, {"c", "d"}},
	},
	{
		Name:   "BareCR",
		Input:  "a,b\rc,d\r\n",
		Output: [][]string{{"a", "b\rc", "d"}},
	},
	{
		Name:               "RFC4180test",
		UseFieldsPerRecord: true,
		Input: `#field1,field2,field3
"aaa","bb
b","ccc"
"a,a","b""bb","ccc"
zzz,yyy,xxx
`,
		Output: [][]string{
			{"#field1", "field2", "field3"},
			{"aaa", "bb\nb", "ccc"},
			{"a,a", `b"bb`, "ccc"},
			{"zzz", "yyy", "xxx"},
		},
	},
	{
		Name:   "NoEOLTest",
		Input:  "a,b,c",
		Output: [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "Semicolon",
		Comma:  ';',
		Input:  "a;b;c\n",
		Output: [][]string{{"a", "b", "c"}},
	},
	{
		Name: "MultiLine",
		Input: `"two
line","one line","three
line
field"`,
		Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}},
	},
	{
		Name:  "BlankLine",
		Input: "a,b,c\n\nd,e,f\n\n",
		Output: [][]string{
			{"a", "b", "c"},
			{"d", "e", "f"},
		},
	},
	{
		Name:             "TrimSpace",
		Input:            " a,  b,   c\n",
		TrimLeadingSpace: true,
		Output:           [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "LeadingSpace",
		Input:  " a,  b,   c\n",
		Output: [][]string{{" a", "  b", "   c"}},
	},
	{
		Name:    "Comment",
		Comment: '#',
		Input:   "#1,2,3\na,b,c\n#comment",
		Output:  [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "NoComment",
		Input:  "#1,2,3\na,b,c",
		Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}},
	},
	{
		Name:       "LazyQuotes",
		LazyQuotes: true,
		Input:      `a "word","1"2",a","b`,
		Output:     [][]string{{`a "word"`, `1"2`, `a"`, `b`}},
	},
	{
		Name:       "BareQuotes",
		LazyQuotes: true,
		Input:      `a "word","1"2",a"`,
		Output:     [][]string{{`a "word"`, `1"2`, `a"`}},
	},
	{
		Name:       "BareDoubleQuotes",
		LazyQuotes: true,
		Input:      `a""b,c`,
		Output:     [][]string{{`a""b`, `c`}},
	},
	{
		Name:  "BadDoubleQuotes",
		Input: `a""b,c`,
		Error: `bare " in non-quoted-field`, Line: 1, Column: 1,
	},
	{
		Name:             "TrimQuote",
		Input:            ` "a"," b",c`,
		TrimLeadingSpace: true,
		Output:           [][]string{{"a", " b", "c"}},
	},
	{
		Name:  "BadBareQuote",
		Input: `a "word","b"`,
		Error: `bare " in non-quoted-field`, Line: 1, Column: 2,
	},
	{
		Name:  "BadTrailingQuote",
		Input: `"a word",b"`,
		Error: `bare " in non-quoted-field`, Line: 1, Column: 10,
	},
	{
		Name:  "ExtraneousQuote",
		Input: `"a "word","b"`,
		Error: `extraneous " in field`, Line: 1, Column: 3,
	},
	{
		Name:               "BadFieldCount",
		UseFieldsPerRecord: true,
		Input:              "a,b,c\nd,e",
		Error:              "wrong number of fields", Line: 2,
	},
	{
		Name:               "BadFieldCount1",
		UseFieldsPerRecord: true,
		FieldsPerRecord:    2,
		Input:              `a,b,c`,
		Error:              "wrong number of fields", Line: 1,
	},
	{
		Name:   "FieldCount",
		Input:  "a,b,c\nd,e",
		Output: [][]string{{"a", "b", "c"}, {"d", "e"}},
	},
	{
		Name:   "TrailingCommaEOF",
		Input:  "a,b,c,",
		Output: [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:   "TrailingCommaEOL",
		Input:  "a,b,c,\n",
		Output: [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:             "TrailingCommaSpaceEOF",
		TrimLeadingSpace: true,
		Input:            "a,b,c, ",
		Output:           [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:             "TrailingCommaSpaceEOL",
		TrimLeadingSpace: true,
		Input:            "a,b,c, \n",
		Output:           [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:             "TrailingCommaLine3",
		TrimLeadingSpace: true,
		Input:            "a,b,c\nd,e,f\ng,hi,",
		Output:           [][]string{{"a", "b", "c"}, {"d", "e", "f"}, {"g", "hi", ""}},
	},
	{
		Name:   "NotTrailingComma3",
		Input:  "a,b,c, \n",
		Output: [][]string{{"a", "b", "c", " "}},
	},
	{
		Name:          "CommaFieldTest",
		TrailingComma: true,
		Input: `x,y,z,w
x,y,z,
x,y,,
x,,,
,,,
"x","y","z","w"
"x","y","z",""
"x","y","",""
"x","","",""
"","","",""
`,
		Output: [][]string{
			{"x", "y", "z", "w"},
			{"x", "y", "z", ""},
			{"x", "y", "", ""},
			{"x", "", "", ""},
			{"", "", "", ""},
			{"x", "y", "z", "w"},
			{"x", "y", "z", ""},
			{"x", "y", "", ""},
			{"x", "", "", ""},
			{"", "", "", ""},
		},
	},
	{
		Name:             "TrailingCommaIneffective1",
		TrailingComma:    true,
		TrimLeadingSpace: true,
		Input:            "a,b,\nc,d,e",
		Output: [][]string{
			{"a", "b", ""},
			{"c", "d", "e"},
		},
	},
	{
		Name:             "TrailingCommaIneffective2",
		TrailingComma:    false,
		TrimLeadingSpace: true,
		Input:            "a,b,\nc,d,e",
		Output: [][]string{
			{"a", "b", ""},
			{"c", "d", "e"},
		},
	},
	{
		Name:          "SkipLine1DoubleQuote",
		SkipLineOnErr: true,
		Input:         "a\nb\"\nc",
		Output:        [][]string{{"a"}, {"c"}},
		Errors:        []string{"line 2, column 2: bare \" in non-quoted-field"},
	},
	{
		Name:          "SkipLine2DoubleQuote",
		SkipLineOnErr: true,
		Input:         "a\nb\"b\"\nc",
		Output:        [][]string{{"a"}, {"c"}},
		Errors:        []string{"line 2, column 4: bare \" in non-quoted-field"},
	},
	{
		Name:               "SkipLineNoOfArgs",
		SkipLineOnErr:      true,
		UseFieldsPerRecord: true,
		Input:              "a,b,c\nd,e,f,g\nh,i,j",
		Output:             [][]string{{"a", "b", "c"}, {"h", "i", "j"}},
		Errors:             []string{"line 2, column 0: wrong number of fields in line"},
	},
	{
		Name:          "SkipLineExtraneousQuote",
		SkipLineOnErr: true,
		Input:         "a,b,c\nd,\"e\"e\",f\ng,h,i",
		Output:        [][]string{{"a", "b", "c"}, {"g", "h", "i"}},
		Errors:        []string{"line 2, column 8: extraneous \" in field"},
	},
	{
		Name:               "SkipLineMultilineFieldWithErrors",
		SkipLineOnErr:      true,
		UseFieldsPerRecord: true,
		Input:              "a,b,c\nd,\"e\"\nf\",g\nh,i,j",
		Output:             [][]string{{"a", "b", "c"}, {"h", "i", "j"}},
		Errors:             []string{"line 2, column 0: wrong number of fields in line", "line 3, column 4: bare \" in non-quoted-field"},
	},
	{
		Name:               "ReadAllWithHeaders",
		UseFieldsPerRecord: true,
		UseHeaders:         true,
		Input:              "a,b,c\n1,2,3\n4,5,6",
		OutputMap: []map[string]string{
			{"a": "a", "b": "b", "c": "c"},
			{"a": "1", "b": "2", "c": "3"},
			{"a": "4", "b": "5", "c": "6"}},
	},
	{
		Name:               "ReadAllWithHeadersAndErrors",
		UseFieldsPerRecord: true,
		UseHeadersAndErrs:  true,
		Input:              "a,b,c\n1,2\",3\n4,5,6\n7,8,9,10\n11,12,13",
		Errors:             []string{"line 2, column 6: bare \" in non-quoted-field", "line 4, column 0: wrong number of fields in line"},
		OutputMap: []map[string]string{
			{"a": "a", "b": "b", "c": "c"},
			{"a": "4", "b": "5", "c": "6"},
			{"a": "11", "b": "12", "c": "13"}},
	},
}

func TestRead(t *testing.T) {
	for _, tt := range readTests {
		r := NewReader(strings.NewReader(tt.Input))
		r.Comment = tt.Comment
		if tt.UseFieldsPerRecord {
			r.FieldsPerRecord = tt.FieldsPerRecord
		} else {
			r.FieldsPerRecord = -1
		}
		r.LazyQuotes = tt.LazyQuotes
		r.TrailingComma = tt.TrailingComma
		r.TrimLeadingSpace = tt.TrimLeadingSpace
		r.SkipLineOnErr = tt.SkipLineOnErr
		if tt.Comma != 0 {
			r.Comma = tt.Comma
		}
		if tt.SkipLineOnErr {
			out, errors := r.ReadAllWithErrors()
			var errorStrings []string
			for _, err := range errors {
				errorStrings = append(errorStrings, err.Error())
			}
			if !reflect.DeepEqual(errorStrings, tt.Errors) {
				t.Errorf("%s: errors=%q want %q", tt.Name, errors, tt.Errors)
			}
			if !reflect.DeepEqual(out, tt.Output) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
			}
		} else if tt.UseHeaders {
			out, err := r.ReadAllWithHeaders()
			if err != nil {
				t.Errorf("%s: unexpected error %v", tt.Name, err)
			} else if !reflect.DeepEqual(out, tt.OutputMap) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.OutputMap)
			}
		} else if tt.UseHeadersAndErrs {
			out, errs := r.ReadAllWithHeadersAndErrors()
			if !reflect.DeepEqual(out, tt.OutputMap) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.OutputMap)
			}
			var errorStrings []string
			for _, err := range errs {
				errorStrings = append(errorStrings, err.Error())
			}
			if !reflect.DeepEqual(errorStrings, tt.Errors) {
				t.Errorf("%s: errors=%q want %q", tt.Name, errorStrings, tt.Errors)
			}
		} else {
			out, err := r.ReadAll()
			perr, _ := err.(*ParseError)
			if tt.Error != "" && !tt.SkipLineOnErr {
				if err == nil || !strings.Contains(err.Error(), tt.Error) {
					t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error)
				} else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) {
					t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column)
				}
			} else if err != nil && !tt.SkipLineOnErr {
				t.Errorf("%s: unexpected error %v", tt.Name, err)
			} else if !reflect.DeepEqual(out, tt.Output) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
			}
		}
	}
}
<commit_msg>Change anonymous struct to Test<commit_after>// Copyright 2014 John DeWyze. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bettercsv

import (
	"reflect"
	"strings"
	"testing"
)

type Test struct {
	Name               string
	Input              string
	Output             [][]string
	OutputMap          []map[string]string
	UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1
	UseHeaders         bool // true means use Headers methods for reading
	UseHeadersAndErrs  bool // true means use HeadersAndErrors methods for reading

	// These fields are copied into the Reader
	Comma            rune
	Comment          rune
	FieldsPerRecord  int
	LazyQuotes       bool
	TrailingComma    bool
	TrimLeadingSpace bool
	SkipLineOnErr    bool

	Error  string
	Line   int // Expected error line if != 0
	Column int // Expected error column if line != 0
	Errors []string
}

var readTests = []Test{
	{
		Name:   "Simple",
		Input:  "a,b,c\n",
		Output: [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "CRLF",
		Input:  "a,b\r\nc,d\r\n",
		Output: [][]string{{"a", "b"}, {"c", "d"}},
	},
	{
		Name:   "BareCR",
		Input:  "a,b\rc,d\r\n",
		Output: [][]string{{"a", "b\rc", "d"}},
	},
	{
		Name:               "RFC4180test",
		UseFieldsPerRecord: true,
		Input: `#field1,field2,field3
"aaa","bb
b","ccc"
"a,a","b""bb","ccc"
zzz,yyy,xxx
`,
		Output: [][]string{
			{"#field1", "field2", "field3"},
			{"aaa", "bb\nb", "ccc"},
			{"a,a", `b"bb`, "ccc"},
			{"zzz", "yyy", "xxx"},
		},
	},
	{
		Name:   "NoEOLTest",
		Input:  "a,b,c",
		Output: [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "Semicolon",
		Comma:  ';',
		Input:  "a;b;c\n",
		Output: [][]string{{"a", "b", "c"}},
	},
	{
		Name: "MultiLine",
		Input: `"two
line","one line","three
line
field"`,
		Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}},
	},
	{
		Name:  "BlankLine",
		Input: "a,b,c\n\nd,e,f\n\n",
		Output: [][]string{
			{"a", "b", "c"},
			{"d", "e", "f"},
		},
	},
	{
		Name:             "TrimSpace",
		Input:            " a,  b,   c\n",
		TrimLeadingSpace: true,
		Output:           [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "LeadingSpace",
		Input:  " a,  b,   c\n",
		Output: [][]string{{" a", "  b", "   c"}},
	},
	{
		Name:    "Comment",
		Comment: '#',
		Input:   "#1,2,3\na,b,c\n#comment",
		Output:  [][]string{{"a", "b", "c"}},
	},
	{
		Name:   "NoComment",
		Input:  "#1,2,3\na,b,c",
		Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}},
	},
	{
		Name:       "LazyQuotes",
		LazyQuotes: true,
		Input:      `a "word","1"2",a","b`,
		Output:     [][]string{{`a "word"`, `1"2`, `a"`, `b`}},
	},
	{
		Name:       "BareQuotes",
		LazyQuotes: true,
		Input:      `a "word","1"2",a"`,
		Output:     [][]string{{`a "word"`, `1"2`, `a"`}},
	},
	{
		Name:       "BareDoubleQuotes",
		LazyQuotes: true,
		Input:      `a""b,c`,
		Output:     [][]string{{`a""b`, `c`}},
	},
	{
		Name:  "BadDoubleQuotes",
		Input: `a""b,c`,
		Error: `bare " in non-quoted-field`, Line: 1, Column: 1,
	},
	{
		Name:             "TrimQuote",
		Input:            ` "a"," b",c`,
		TrimLeadingSpace: true,
		Output:           [][]string{{"a", " b", "c"}},
	},
	{
		Name:  "BadBareQuote",
		Input: `a "word","b"`,
		Error: `bare " in non-quoted-field`, Line: 1, Column: 2,
	},
	{
		Name:  "BadTrailingQuote",
		Input: `"a word",b"`,
		Error: `bare " in non-quoted-field`, Line: 1, Column: 10,
	},
	{
		Name:  "ExtraneousQuote",
		Input: `"a "word","b"`,
		Error: `extraneous " in field`, Line: 1, Column: 3,
	},
	{
		Name:               "BadFieldCount",
		UseFieldsPerRecord: true,
		Input:              "a,b,c\nd,e",
		Error:              "wrong number of fields", Line: 2,
	},
	{
		Name:               "BadFieldCount1",
		UseFieldsPerRecord: true,
		FieldsPerRecord:    2,
		Input:              `a,b,c`,
		Error:              "wrong number of fields", Line: 1,
	},
	{
		Name:   "FieldCount",
		Input:  "a,b,c\nd,e",
		Output: [][]string{{"a", "b", "c"}, {"d", "e"}},
	},
	{
		Name:   "TrailingCommaEOF",
		Input:  "a,b,c,",
		Output: [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:   "TrailingCommaEOL",
		Input:  "a,b,c,\n",
		Output: [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:             "TrailingCommaSpaceEOF",
		TrimLeadingSpace: true,
		Input:            "a,b,c, ",
		Output:           [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:             "TrailingCommaSpaceEOL",
		TrimLeadingSpace: true,
		Input:            "a,b,c, \n",
		Output:           [][]string{{"a", "b", "c", ""}},
	},
	{
		Name:             "TrailingCommaLine3",
		TrimLeadingSpace: true,
		Input:            "a,b,c\nd,e,f\ng,hi,",
		Output:           [][]string{{"a", "b", "c"}, {"d", "e", "f"}, {"g", "hi", ""}},
	},
	{
		Name:   "NotTrailingComma3",
		Input:  "a,b,c, \n",
		Output: [][]string{{"a", "b", "c", " "}},
	},
	{
		Name:          "CommaFieldTest",
		TrailingComma: true,
		Input: `x,y,z,w
x,y,z,
x,y,,
x,,,
,,,
"x","y","z","w"
"x","y","z",""
"x","y","",""
"x","","",""
"","","",""
`,
		Output: [][]string{
			{"x", "y", "z", "w"},
			{"x", "y", "z", ""},
			{"x", "y", "", ""},
			{"x", "", "", ""},
			{"", "", "", ""},
			{"x", "y", "z", "w"},
			{"x", "y", "z", ""},
			{"x", "y", "", ""},
			{"x", "", "", ""},
			{"", "", "", ""},
		},
	},
	{
		Name:             "TrailingCommaIneffective1",
		TrailingComma:    true,
		TrimLeadingSpace: true,
		Input:            "a,b,\nc,d,e",
		Output: [][]string{
			{"a", "b", ""},
			{"c", "d", "e"},
		},
	},
	{
		Name:             "TrailingCommaIneffective2",
		TrailingComma:    false,
		TrimLeadingSpace: true,
		Input:            "a,b,\nc,d,e",
		Output: [][]string{
			{"a", "b", ""},
			{"c", "d", "e"},
		},
	},
	{
		Name:          "SkipLine1DoubleQuote",
		SkipLineOnErr: true,
		Input:         "a\nb\"\nc",
		Output:        [][]string{{"a"}, {"c"}},
		Errors:        []string{"line 2, column 2: bare \" in non-quoted-field"},
	},
	{
		Name:          "SkipLine2DoubleQuote",
		SkipLineOnErr: true,
		Input:         "a\nb\"b\"\nc",
		Output:        [][]string{{"a"}, {"c"}},
		Errors:        []string{"line 2, column 4: bare \" in non-quoted-field"},
	},
	{
		Name:               "SkipLineNoOfArgs",
		SkipLineOnErr:      true,
		UseFieldsPerRecord: true,
		Input:              "a,b,c\nd,e,f,g\nh,i,j",
		Output:             [][]string{{"a", "b", "c"}, {"h", "i", "j"}},
		Errors:             []string{"line 2, column 0: wrong number of fields in line"},
	},
	{
		Name:          "SkipLineExtraneousQuote",
		SkipLineOnErr: true,
		Input:         "a,b,c\nd,\"e\"e\",f\ng,h,i",
		Output:        [][]string{{"a", "b", "c"}, {"g", "h", "i"}},
		Errors:        []string{"line 2, column 8: extraneous \" in field"},
	},
	{
		Name:               "SkipLineMultilineFieldWithErrors",
		SkipLineOnErr:      true,
		UseFieldsPerRecord: true,
		Input:              "a,b,c\nd,\"e\"\nf\",g\nh,i,j",
		Output:             [][]string{{"a", "b", "c"}, {"h", "i", "j"}},
		Errors:             []string{"line 2, column 0: wrong number of fields in line", "line 3, column 4: bare \" in non-quoted-field"},
	},
	{
		Name:               "ReadAllWithHeaders",
		UseFieldsPerRecord: true,
		UseHeaders:         true,
		Input:              "a,b,c\n1,2,3\n4,5,6",
		OutputMap: []map[string]string{
			{"a": "a", "b": "b", "c": "c"},
			{"a": "1", "b": "2", "c": "3"},
			{"a": "4", "b": "5", "c": "6"}},
	},
	{
		Name:               "ReadAllWithHeadersAndErrors",
		UseFieldsPerRecord: true,
		UseHeadersAndErrs:  true,
		Input:              "a,b,c\n1,2\",3\n4,5,6\n7,8,9,10\n11,12,13",
		Errors:             []string{"line 2, column 6: bare \" in non-quoted-field", "line 4, column 0: wrong number of fields in line"},
		OutputMap: []map[string]string{
			{"a": "a", "b": "b", "c": "c"},
			{"a": "4", "b": "5", "c": "6"},
			{"a": "11", "b": "12", "c": "13"}},
	},
}

func TestRead(t *testing.T) {
	for _, tt := range readTests {
		r := NewReader(strings.NewReader(tt.Input))
		r.Comment = tt.Comment
		if tt.UseFieldsPerRecord {
			r.FieldsPerRecord = tt.FieldsPerRecord
		} else {
			r.FieldsPerRecord = -1
		}
		r.LazyQuotes = tt.LazyQuotes
		r.TrailingComma = tt.TrailingComma
		r.TrimLeadingSpace = tt.TrimLeadingSpace
		r.SkipLineOnErr = tt.SkipLineOnErr
		if tt.Comma != 0 {
			r.Comma = tt.Comma
		}
		if tt.SkipLineOnErr {
			out, errors := r.ReadAllWithErrors()
			var errorStrings []string
			for _, err := range errors {
				errorStrings = append(errorStrings, err.Error())
			}
			if !reflect.DeepEqual(errorStrings, tt.Errors) {
				t.Errorf("%s: errors=%q want %q", tt.Name, errors, tt.Errors)
			}
			if !reflect.DeepEqual(out, tt.Output) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
			}
		} else if tt.UseHeaders {
			out, err := r.ReadAllWithHeaders()
			if err != nil {
				t.Errorf("%s: unexpected error %v", tt.Name, err)
			} else if !reflect.DeepEqual(out, tt.OutputMap) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.OutputMap)
			}
		} else if tt.UseHeadersAndErrs {
			out, errs := r.ReadAllWithHeadersAndErrors()
			if !reflect.DeepEqual(out, tt.OutputMap) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.OutputMap)
			}
			var errorStrings []string
			for _, err := range errs {
				errorStrings = append(errorStrings, err.Error())
			}
			if !reflect.DeepEqual(errorStrings, tt.Errors) {
				t.Errorf("%s: errors=%q want %q", tt.Name, errorStrings, tt.Errors)
			}
		} else {
			out, err := r.ReadAll()
			perr, _ := err.(*ParseError)
			if tt.Error != "" && !tt.SkipLineOnErr {
				if err == nil || !strings.Contains(err.Error(), tt.Error) {
					t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error)
				} else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) {
					t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column)
				}
			} else if err != nil && !tt.SkipLineOnErr {
				t.Errorf("%s: unexpected error %v", tt.Name, err)
			} else if !reflect.DeepEqual(out, tt.Output) {
				t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
			}
		}
	}
}
<|endoftext|>


<commit_before>package readon

import (
	"os"
	"regexp"
	"testing"
)

func TestRemovesScriptTags(t *testing.T) {
	file, _ := os.Open("fixtures/heise.html")
	output, _ := Readon(file)
	re := regexp.MustCompile(`<script`)

	if re.MatchString(output) {
		t.Fatal("Script tags were not removed")
	}
}

func TestRemovesComments(t *testing.T) {
	file, _ := os.Open("fixtures/heise.html")
	output, _ := Readon(file)
	re := regexp.MustCompile(`class="rss"`)
	if re.MatchString(output) {
		t.Fatal("rss class was not removed")
	}
}

func TestRemovesBr(t *testing.T) {
	file, _ := os.Open("fixtures/heise.html")
	output, _ := Readon(file)
	re := regexp.MustCompile(`<br\s?/?>`)
	if re.MatchString(output) {
		t.Fatal("br tags were not removed")
	}
}
<commit_msg>Use t.Error<commit_after>package readon

import (
	"os"
	"regexp"
	"testing"
)

func TestRemovesScriptTags(t *testing.T) {
	file, _ := os.Open("fixtures/heise.html")
	output, _ := Readon(file)
	re := regexp.MustCompile(`<script`)

	if re.MatchString(output) {
		t.Error("Script tags were not removed")
	}
}

func TestRemovesComments(t *testing.T) {
	file, _ := os.Open("fixtures/heise.html")
	output, _ := Readon(file)
	re := regexp.MustCompile(`class="rss"`)
	if re.MatchString(output) {
		t.Error("rss class was not removed")
	}
}

func TestRemovesBr(t *testing.T) {
	file, _ := os.Open("fixtures/heise.html")
	output, _ := Readon(file)
	re := regexp.MustCompile(`<br/?>`)
	if re.MatchString(output) {
		t.Error("br tags were not removed")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/url"
	"strings"
	"text/template"

	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/host/types"
	tc "github.com/flynn/flynn/test/cluster"
	"github.com/flynn/flynn/updater/types"
	c "github.com/flynn/go-check"
)

type ReleaseSuite struct {
	Helper
}

var _ = c.ConcurrentSuite(&ReleaseSuite{})

func (s *ReleaseSuite) addReleaseHosts(t *c.C) *tc.BootResult {
	res, err := testCluster.AddReleaseHosts()
	t.Assert(err, c.IsNil)
	t.Assert(res.Instances, c.HasLen, 4)
	return res
}

var releaseScript = bytes.NewReader([]byte(`
export TUF_TARGETS_PASSPHRASE="flynn-test"
export TUF_SNAPSHOT_PASSPHRASE="flynn-test"
export TUF_TIMESTAMP_PASSPHRASE="flynn-test"

export GOPATH=~/go
src="${GOPATH}/src/github.com/flynn/flynn"

# send all output to stderr so only version.json is output to stdout
(

  # rebuild components.
  #
  # ideally we would use tup to do this, but it hangs waiting on the
  # FUSE socket after building, so for now we do it manually.
  #
  # See https://github.com/flynn/flynn/issues/949
  pushd "${src}" >/dev/null
  sed "s/{{TUF-ROOT-KEYS}}/$(tuf --dir test/release root-keys)/g" host/cli/root_keys.go.tmpl > host/cli/root_keys.go
  vpkg="github.com/flynn/flynn/pkg/version"
  go build -o host/bin/flynn-host -ldflags="-X ${vpkg}.commit notdev -X ${vpkg}.branch dev -X ${vpkg}.tag v20150131.0-test -X ${vpkg}.dirty false" ./host
  gzip -9 --keep --force host/bin/flynn-host
  sed "s/{{FLYNN-HOST-CHECKSUM}}/$(sha512sum host/bin/flynn-host.gz | cut -d " " -f 1)/g" script/install-flynn.tmpl > script/install-flynn

  # create new images
  test/scripts/wait-for-docker
  for name in $(docker images | grep ^flynn | awk '{print $1}'); do
    docker build -t $name - < <(echo -e "FROM $name\nRUN /bin/true")
  done

  util/release/flynn-release manifest util/release/version_template.json > version.json
  popd >/dev/null

  "${src}/script/export-components" --no-compress "${src}/test/release"
  "${src}/script/release-channel" --tuf-dir "${src}/test/release" --no-sync "stable" "v20150131.0-test"

  dir=$(mktemp --directory)
  ln -s "${src}/test/release/repository" "${dir}/tuf"
  ln -s "${src}/script/install-flynn" "${dir}/install-flynn"

  # create a slug for testing slug based app updates
  tar c -C "${src}/test/apps/http" . | docker run -i -a stdin -a stdout -a stderr flynn/slugbuilder - > "${dir}/slug.tgz"

  # start a file server to serve the exported components
  sudo start-stop-daemon \
    --start \
    --background \
    --chdir "${dir}" \
    --exec "${src}/test/bin/flynn-test-file-server"
) >&2

cat "${src}/version.json"
`))

var installScript = template.Must(template.New("install-script").Parse(`
# download to a tmp file so the script fails on download error rather than
# executing nothing and succeeding
curl -sL --fail http://{{ .Blobstore }}/install-flynn > /tmp/install-flynn
bash -e /tmp/install-flynn -r "http://{{ .Blobstore }}"
`))

var updateScript = template.Must(template.New("update-script").Parse(`
timeout --signal=QUIT --kill-after=10 10m bash -ex <<-SCRIPT
cd ~/go/src/github.com/flynn/flynn
tuf --dir test/release root-keys | tuf-client init --store /tmp/tuf.db http://{{ .Blobstore }}/tuf
echo stable | sudo tee /etc/flynn/channel.txt
flynn-host update --repository http://{{ .Blobstore }}/tuf --tuf-db /tmp/tuf.db
SCRIPT
`))

func (s *ReleaseSuite) TestReleaseImages(t *c.C) {
	if testCluster == nil {
		t.Skip("cannot boot release cluster")
	}

	// stream script output to t.Log
	logReader, logWriter := io.Pipe()
	defer logWriter.Close()
	go func() {
		buf := bufio.NewReader(logReader)
		for {
			line, err := buf.ReadString('\n')
			if err != nil {
				return
			}
			debug(t, line[0:len(line)-1])
		}
	}()

	// boot the release cluster, release components to a blobstore and output the new version.json
	releaseCluster := s.addReleaseHosts(t)
	buildHost := releaseCluster.Instances[0]
	var versionJSON bytes.Buffer
	t.Assert(buildHost.Run("bash -ex", &tc.Streams{Stdin: releaseScript, Stdout: &versionJSON, Stderr: logWriter}), c.IsNil)
	var versions map[string]string
	t.Assert(json.Unmarshal(versionJSON.Bytes(), &versions), c.IsNil)

	// install Flynn from the blobstore on the vanilla host
	blobstore := struct{ Blobstore string }{buildHost.IP + ":8080"}
	installHost := releaseCluster.Instances[3]
	var script bytes.Buffer
	installScript.Execute(&script, blobstore)
	var installOutput bytes.Buffer
	out := io.MultiWriter(logWriter, &installOutput)
	t.Assert(installHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check the flynn-host version is correct
	var hostVersion bytes.Buffer
	t.Assert(installHost.Run("flynn-host version", &tc.Streams{Stdout: &hostVersion}), c.IsNil)
	t.Assert(strings.TrimSpace(hostVersion.String()), c.Equals, "v20150131.0-test")

	// check rebuilt images were downloaded
	for name, id := range versions {
		expected := fmt.Sprintf("%s image %s downloaded", name, id)
		if !strings.Contains(installOutput.String(), expected) {
			t.Fatalf(`expected install to download %s %s`, name, id)
		}
	}

	// installing on an instance with Flynn running should not fail
	script.Reset()
	installScript.Execute(&script, blobstore)
	t.Assert(buildHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: logWriter, Stderr: logWriter}), c.IsNil)

	// create a controller client for the release cluster
	pin, err := base64.StdEncoding.DecodeString(releaseCluster.ControllerPin)
	t.Assert(err, c.IsNil)
	client, err := controller.NewClientWithConfig(
		"https://"+buildHost.IP,
		releaseCluster.ControllerKey,
		controller.Config{Pin: pin, Domain: releaseCluster.ControllerDomain},
	)
	t.Assert(err, c.IsNil)

	// deploy a slug based app
	slugApp := &ct.App{}
	t.Assert(client.CreateApp(slugApp), c.IsNil)
	gitreceive, err := client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	imageArtifact := &ct.Artifact{Type: host.ArtifactTypeDocker, URI: gitreceive.Env["SLUGRUNNER_IMAGE_URI"]}
	t.Assert(client.CreateArtifact(imageArtifact), c.IsNil)
	slugArtifact := &ct.Artifact{Type: host.ArtifactTypeFile, URI: fmt.Sprintf("http://%s:8080/slug.tgz", buildHost.IP)}
	t.Assert(client.CreateArtifact(slugArtifact), c.IsNil)
	release := &ct.Release{
		ArtifactIDs: []string{imageArtifact.ID, slugArtifact.ID},
		Processes:   map[string]ct.ProcessType{"web": {Cmd: []string{"bin/http"}}},
	}
	t.Assert(client.CreateRelease(release), c.IsNil)
	t.Assert(client.SetAppRelease(slugApp.ID, release.ID), c.IsNil)
	watcher, err := client.WatchJobEvents(slugApp.ID, release.ID)
	t.Assert(err, c.IsNil)
	defer watcher.Close()
	t.Assert(client.PutFormation(&ct.Formation{
		AppID:     slugApp.ID,
		ReleaseID: release.ID,
		Processes: map[string]int{"web": 1},
	}), c.IsNil)
	err = watcher.WaitFor(ct.JobEvents{"web": {ct.JobStateUp: 1}}, scaleTimeout, nil)
	t.Assert(err, c.IsNil)

	// run a cluster update from the blobstore
	updateHost := releaseCluster.Instances[1]
	script.Reset()
	updateScript.Execute(&script, blobstore)
	var updateOutput bytes.Buffer
	out = io.MultiWriter(logWriter, &updateOutput)
	t.Assert(updateHost.Run("bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check rebuilt images were downloaded
	for name := range versions {
		for _, host := range releaseCluster.Instances[0:2] {
			expected := fmt.Sprintf(`"pulled image" host=%s name=%s`, host.ID, name)
			if !strings.Contains(updateOutput.String(), expected) {
				t.Fatalf(`expected update to download %s on host %s`, name, host.ID)
			}
		}
	}

	assertImage := func(uri, image string) {
		u, err := url.Parse(uri)
		t.Assert(err, c.IsNil)
		t.Assert(u.Query().Get("id"), c.Equals, versions[image])
	}

	// check system apps were deployed correctly
	for _, app := range updater.SystemApps {
		if app.ImageOnly {
			continue // we don't deploy ImageOnly updates
		}
		if app.Image == "" {
			app.Image = "flynn/" + app.Name
		}
		debugf(t, "checking new %s release is using image %s", app.Name, versions[app.Image])
		expected := fmt.Sprintf(`"finished deploy of system app" name=%s`, app.Name)
		if !strings.Contains(updateOutput.String(), expected) {
			t.Fatalf(`expected update to deploy %s`, app.Name)
		}
		release, err := client.GetAppRelease(app.Name)
		t.Assert(err, c.IsNil)
		debugf(t, "new %s release ID: %s", app.Name, release.ID)
		artifact, err := client.GetArtifact(release.ImageArtifactID())
		t.Assert(err, c.IsNil)
		debugf(t, "new %s artifact: %+v", app.Name, artifact)
		assertImage(artifact.URI, app.Image)
	}

	// check gitreceive has the correct slug env vars
	gitreceive, err = client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	assertImage(gitreceive.Env["SLUGBUILDER_IMAGE_URI"], "flynn/slugbuilder")
	assertImage(gitreceive.Env["SLUGRUNNER_IMAGE_URI"], "flynn/slugrunner")

	// check slug based app was deployed correctly
	release, err = client.GetAppRelease(slugApp.Name)
	t.Assert(err, c.IsNil)
	imageArtifact, err = client.GetArtifact(release.ImageArtifactID())
	t.Assert(err, c.IsNil)
	assertImage(imageArtifact.URI, "flynn/slugrunner")
}
<commit_msg>test: Don't generate a changelog in TestReleaseImages<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/url"
	"strings"
	"text/template"

	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/host/types"
	tc "github.com/flynn/flynn/test/cluster"
	"github.com/flynn/flynn/updater/types"
	c "github.com/flynn/go-check"
)

type ReleaseSuite struct {
	Helper
}

var _ = c.ConcurrentSuite(&ReleaseSuite{})

func (s *ReleaseSuite) addReleaseHosts(t *c.C) *tc.BootResult {
	res, err := testCluster.AddReleaseHosts()
	t.Assert(err, c.IsNil)
	t.Assert(res.Instances, c.HasLen, 4)
	return res
}

var releaseScript = bytes.NewReader([]byte(`
export TUF_TARGETS_PASSPHRASE="flynn-test"
export TUF_SNAPSHOT_PASSPHRASE="flynn-test"
export TUF_TIMESTAMP_PASSPHRASE="flynn-test"

export GOPATH=~/go
src="${GOPATH}/src/github.com/flynn/flynn"

# send all output to stderr so only version.json is output to stdout
(

  # rebuild components.
  #
  # ideally we would use tup to do this, but it hangs waiting on the
  # FUSE socket after building, so for now we do it manually.
  #
  # See https://github.com/flynn/flynn/issues/949
  pushd "${src}" >/dev/null
  sed "s/{{TUF-ROOT-KEYS}}/$(tuf --dir test/release root-keys)/g" host/cli/root_keys.go.tmpl > host/cli/root_keys.go
  vpkg="github.com/flynn/flynn/pkg/version"
  go build -o host/bin/flynn-host -ldflags="-X ${vpkg}.commit notdev -X ${vpkg}.branch dev -X ${vpkg}.tag v20150131.0-test -X ${vpkg}.dirty false" ./host
  gzip -9 --keep --force host/bin/flynn-host
  sed "s/{{FLYNN-HOST-CHECKSUM}}/$(sha512sum host/bin/flynn-host.gz | cut -d " " -f 1)/g" script/install-flynn.tmpl > script/install-flynn

  # create new images
  test/scripts/wait-for-docker
  for name in $(docker images | grep ^flynn | awk '{print $1}'); do
    docker build -t $name - < <(echo -e "FROM $name\nRUN /bin/true")
  done

  util/release/flynn-release manifest util/release/version_template.json > version.json
  popd >/dev/null

  "${src}/script/export-components" --no-compress "${src}/test/release"
  "${src}/script/release-channel" --tuf-dir "${src}/test/release" --no-sync --no-changelog "stable" "v20150131.0-test"

  dir=$(mktemp --directory)
  ln -s "${src}/test/release/repository" "${dir}/tuf"
  ln -s "${src}/script/install-flynn" "${dir}/install-flynn"

  # create a slug for testing slug based app updates
  tar c -C "${src}/test/apps/http" . | docker run -i -a stdin -a stdout -a stderr flynn/slugbuilder - > "${dir}/slug.tgz"

  # start a file server to serve the exported components
  sudo start-stop-daemon \
    --start \
    --background \
    --chdir "${dir}" \
    --exec "${src}/test/bin/flynn-test-file-server"
) >&2

cat "${src}/version.json"
`))

var installScript = template.Must(template.New("install-script").Parse(`
# download to a tmp file so the script fails on download error rather than
# executing nothing and succeeding
curl -sL --fail http://{{ .Blobstore }}/install-flynn > /tmp/install-flynn
bash -e /tmp/install-flynn -r "http://{{ .Blobstore }}"
`))

var updateScript = template.Must(template.New("update-script").Parse(`
timeout --signal=QUIT --kill-after=10 10m bash -ex <<-SCRIPT
cd ~/go/src/github.com/flynn/flynn
tuf --dir test/release root-keys | tuf-client init --store /tmp/tuf.db http://{{ .Blobstore }}/tuf
echo stable | sudo tee /etc/flynn/channel.txt
flynn-host update --repository http://{{ .Blobstore }}/tuf --tuf-db /tmp/tuf.db
SCRIPT
`))

func (s *ReleaseSuite) TestReleaseImages(t *c.C) {
	if testCluster == nil {
		t.Skip("cannot boot release cluster")
	}

	// stream script output to t.Log
	logReader, logWriter := io.Pipe()
	defer logWriter.Close()
	go func() {
		buf := bufio.NewReader(logReader)
		for {
			line, err := buf.ReadString('\n')
			if err != nil {
				return
			}
			debug(t, line[0:len(line)-1])
		}
	}()

	// boot the release cluster, release components to a blobstore and output the new version.json
	releaseCluster := s.addReleaseHosts(t)
	buildHost := releaseCluster.Instances[0]
	var versionJSON bytes.Buffer
	t.Assert(buildHost.Run("bash -ex", &tc.Streams{Stdin: releaseScript, Stdout: &versionJSON, Stderr: logWriter}), c.IsNil)
	var versions map[string]string
	t.Assert(json.Unmarshal(versionJSON.Bytes(), &versions), c.IsNil)

	// install Flynn from the blobstore on the vanilla host
	blobstore := struct{ Blobstore string }{buildHost.IP + ":8080"}
	installHost := releaseCluster.Instances[3]
	var script bytes.Buffer
	installScript.Execute(&script, blobstore)
	var installOutput bytes.Buffer
	out := io.MultiWriter(logWriter, &installOutput)
	t.Assert(installHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check the flynn-host version is correct
	var hostVersion bytes.Buffer
	t.Assert(installHost.Run("flynn-host version", &tc.Streams{Stdout: &hostVersion}), c.IsNil)
	t.Assert(strings.TrimSpace(hostVersion.String()), c.Equals, "v20150131.0-test")

	// check rebuilt images were downloaded
	for name, id := range versions {
		expected := fmt.Sprintf("%s image %s downloaded", name, id)
		if !strings.Contains(installOutput.String(), expected) {
			t.Fatalf(`expected install to download %s %s`, name, id)
		}
	}

	// installing on an instance with Flynn running should not fail
	script.Reset()
	installScript.Execute(&script, blobstore)
	t.Assert(buildHost.Run("sudo bash -ex", &tc.Streams{Stdin: &script, Stdout: logWriter, Stderr: logWriter}), c.IsNil)

	// create a controller client for the release cluster
	pin, err := base64.StdEncoding.DecodeString(releaseCluster.ControllerPin)
	t.Assert(err, c.IsNil)
	client, err := controller.NewClientWithConfig(
		"https://"+buildHost.IP,
		releaseCluster.ControllerKey,
		controller.Config{Pin: pin, Domain: releaseCluster.ControllerDomain},
	)
	t.Assert(err, c.IsNil)

	// deploy a slug based app
	slugApp := &ct.App{}
	t.Assert(client.CreateApp(slugApp), c.IsNil)
	gitreceive, err := client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	imageArtifact := &ct.Artifact{Type: host.ArtifactTypeDocker, URI: gitreceive.Env["SLUGRUNNER_IMAGE_URI"]}
	t.Assert(client.CreateArtifact(imageArtifact), c.IsNil)
	slugArtifact := &ct.Artifact{Type: host.ArtifactTypeFile, URI: fmt.Sprintf("http://%s:8080/slug.tgz", buildHost.IP)}
	t.Assert(client.CreateArtifact(slugArtifact), c.IsNil)
	release := &ct.Release{
		ArtifactIDs: []string{imageArtifact.ID, slugArtifact.ID},
		Processes:   map[string]ct.ProcessType{"web": {Cmd: []string{"bin/http"}}},
	}
	t.Assert(client.CreateRelease(release), c.IsNil)
	t.Assert(client.SetAppRelease(slugApp.ID, release.ID), c.IsNil)
	watcher, err := client.WatchJobEvents(slugApp.ID, release.ID)
	t.Assert(err, c.IsNil)
	defer watcher.Close()
	t.Assert(client.PutFormation(&ct.Formation{
		AppID:     slugApp.ID,
		ReleaseID: release.ID,
		Processes: map[string]int{"web": 1},
	}), c.IsNil)
	err = watcher.WaitFor(ct.JobEvents{"web": {ct.JobStateUp: 1}}, scaleTimeout, nil)
	t.Assert(err, c.IsNil)

	// run a cluster update from the blobstore
	updateHost := releaseCluster.Instances[1]
	script.Reset()
	updateScript.Execute(&script, blobstore)
	var updateOutput bytes.Buffer
	out = io.MultiWriter(logWriter, &updateOutput)
	t.Assert(updateHost.Run("bash -ex", &tc.Streams{Stdin: &script, Stdout: out, Stderr: out}), c.IsNil)

	// check rebuilt images were downloaded
	for name := range versions {
		for _, host := range releaseCluster.Instances[0:2] {
			expected := fmt.Sprintf(`"pulled image" host=%s name=%s`, host.ID, name)
			if !strings.Contains(updateOutput.String(), expected) {
				t.Fatalf(`expected update to download %s on host %s`, name, host.ID)
			}
		}
	}

	assertImage := func(uri, image string) {
		u, err := url.Parse(uri)
		t.Assert(err, c.IsNil)
		t.Assert(u.Query().Get("id"), c.Equals, versions[image])
	}

	// check system apps were deployed correctly
	for _, app := range updater.SystemApps {
		if app.ImageOnly {
			continue // we don't deploy ImageOnly updates
		}
		if app.Image == "" {
			app.Image = "flynn/" + app.Name
		}
		debugf(t, "checking new %s release is using image %s", app.Name, versions[app.Image])
		expected := fmt.Sprintf(`"finished deploy of system app" name=%s`, app.Name)
		if !strings.Contains(updateOutput.String(), expected) {
			t.Fatalf(`expected update to deploy %s`, app.Name)
		}
		release, err := client.GetAppRelease(app.Name)
		t.Assert(err, c.IsNil)
		debugf(t, "new %s release ID: %s", app.Name, release.ID)
		artifact, err := client.GetArtifact(release.ImageArtifactID())
		t.Assert(err, c.IsNil)
		debugf(t, "new %s artifact: %+v", app.Name, artifact)
		assertImage(artifact.URI, app.Image)
	}

	// check gitreceive has the correct slug env vars
	gitreceive, err = client.GetAppRelease("gitreceive")
	t.Assert(err, c.IsNil)
	assertImage(gitreceive.Env["SLUGBUILDER_IMAGE_URI"], "flynn/slugbuilder")
	assertImage(gitreceive.Env["SLUGRUNNER_IMAGE_URI"], "flynn/slugrunner")

	// check slug based app was deployed correctly
	release, err = client.GetAppRelease(slugApp.Name)
	t.Assert(err, c.IsNil)
	imageArtifact, err = client.GetArtifact(release.ImageArtifactID())
	t.Assert(err, c.IsNil)
	assertImage(imageArtifact.URI, "flynn/slugrunner")
}
<|endoftext|>


<commit_before>package rpc

import (
	"cgl.tideland.biz/asserts"
	"net/rpc"
	"testing"
)

func TestServer_Address_PanicIfNotStarted(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	defer func() {
		p := recover()
		assert.NotNil(p, "should panic")
		assert.Equal(p.(string), "Server not listening.", "right panic")
	}()

	NewServer().Address()
}

func TestServer_Start(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	s := NewServer()

	// Verify it can start
	err := s.Start()
	assert.Nil(err, "should start without err")
	addr := s.Address()

	// Verify we can connect to it!
	_, err = rpc.Dial("tcp", addr)
	assert.Nil(err, "should be able to connect to RPC")

	// Verify it stops
	s.Stop()
	_, err = rpc.Dial("tcp", addr)
	assert.NotNil(err, "should NOT be able to connect to RPC")
}
<commit_msg>Test regisering a UI with the server<commit_after>package rpc

import (
	"cgl.tideland.biz/asserts"
	"net/rpc"
	"testing"
)

func TestServer_Address_PanicIfNotStarted(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	defer func() {
		p := recover()
		assert.NotNil(p, "should panic")
		assert.Equal(p.(string), "Server not listening.", "right panic")
	}()

	NewServer().Address()
}

func TestServer_Start(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	s := NewServer()

	// Verify it can start
	err := s.Start()
	assert.Nil(err, "should start without err")
	addr := s.Address()

	// Verify we can connect to it!
	_, err = rpc.Dial("tcp", addr)
	assert.Nil(err, "should be able to connect to RPC")

	// Verify it stops
	s.Stop()
	_, err = rpc.Dial("tcp", addr)
	assert.NotNil(err, "should NOT be able to connect to RPC")
}

func TestServer_RegisterUi(t *testing.T) {
	assert := asserts.NewTestingAsserts(t, true)

	ui := &testUi{}

	// Start the server with a UI
	s := NewServer()
	s.RegisterUi(ui)
	assert.Nil(s.Start(), "should start properly")
	defer s.Stop()

	// Verify it works
	client, err := rpc.Dial("tcp", s.Address())
	assert.Nil(err, "should connect via RPC")

	uiClient := &Ui{client}
	uiClient.Say("format")

	assert.Equal(ui.sayFormat, "format", "format should be correct")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/FarmRadioHangar/fessboxconfig/gsm"
	"github.com/gernest/hot"
	"github.com/gorilla/mux"
)

type Config struct {
	Port           int64  `json:"port"`
	Host           string `json:"host"`
	StaticDir      string `json:"static_dir"`
	TemplatesDir   string `json:"templates_dir"`
	AsteriskConfig string `json:"asterisk_config_dir"`
}

func defaultConfig() *Config {
	return &Config{
		Port:           8080,
		Host:           "",
		StaticDir:      "static",
		TemplatesDir:   "templates",
		AsteriskConfig: "/etc/asterisk",
	}
}

func main() {
	c := flag.String("c", "conf/config.json", "path to the configuration file")
	flag.Parse()
	b, err := ioutil.ReadFile(*c)
	if err != nil {
		log.Fatal(err)
	}
	cfg := &Config{}
	err = json.Unmarshal(b, cfg)
	if err != nil {
		log.Fatal(err)
	}
	s := newServer(cfg)
	log.Printf(" starting server on  localhost:%d\n", cfg.Port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), s))
}

//newServer returns a http.Handler with all the routes for configuring supported
//devices registered.
func newServer(c *Config) http.Handler {
	s := mux.NewRouter()
	w := newWeb(c)
	s.HandleFunc("/device/dongle", w.Dongle)
	s.PathPrefix("/static/").
		Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(c.StaticDir))))
	s.HandleFunc("/", w.Home)
	return s
}

type web struct {
	cfg *Config
	tpl *hot.Template
}

func newWeb(cfg *Config) *web {
	w := &web{cfg: cfg}
	config := &hot.Config{
		Watch:          true,
		BaseName:       "fconf",
		Dir:            cfg.TemplatesDir,
		FilesExtension: []string{".tpl", ".html", ".tmpl"},
	}

	tpl, err := hot.New(config)
	if err != nil {
		panic(err)
	}
	w.tpl = tpl
	return w
}

func (ww *web) Home(w http.ResponseWriter, r *http.Request) {
	err := ww.tpl.Execute(w, "index.html", nil)
	if err != nil {
		log.Println(err)
	}
}

type errMSG struct {
	Message string `json; "error"`
}

func (ww *web) Dongle(w http.ResponseWriter, r *http.Request) {
	fName := filepath.Join(ww.cfg.AsteriskConfig, "dongle.conf")
	enc := json.NewEncoder(w)

	f, err := os.Open(fName)
	if err != nil {
		log.Println(err)
		enc.Encode(&errMSG{"trouble opening dongle configuration"})
		return
	}
	defer f.Close()
	p, err := gsm.NewParser(f)
	if err != nil {
		log.Println(err)
		enc.Encode(&errMSG{"trouble scanning dongle configuration"})
		return
	}
	ast, err := p.Parse()
	if err != nil {
		log.Println(err)
		enc.Encode(&errMSG{"trouble parsing dongle configuration"})
		return
	}
	err = ast.ToJSON(w)
	if err != nil {
		log.Println(err)
	}
}
<commit_msg>Fix typo on json tag<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/FarmRadioHangar/fessboxconfig/gsm"
	"github.com/gernest/hot"
	"github.com/gorilla/mux"
)

type Config struct {
	Port           int64  `json:"port"`
	Host           string `json:"host"`
	StaticDir      string `json:"static_dir"`
	TemplatesDir   string `json:"templates_dir"`
	AsteriskConfig string `json:"asterisk_config_dir"`
}

func defaultConfig() *Config {
	return &Config{
		Port:           8080,
		Host:           "",
		StaticDir:      "static",
		TemplatesDir:   "templates",
		AsteriskConfig: "/etc/asterisk",
	}
}

func main() {
	c := flag.String("c", "conf/config.json", "path to the configuration file")
	flag.Parse()
	b, err := ioutil.ReadFile(*c)
	if err != nil {
		log.Fatal(err)
	}
	cfg := &Config{}
	err = json.Unmarshal(b, cfg)
	if err != nil {
		log.Fatal(err)
	}
	s := newServer(cfg)
	log.Printf(" starting server on  localhost:%d\n", cfg.Port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), s))
}

//newServer returns a http.Handler with all the routes for configuring supported
//devices registered.
func newServer(c *Config) http.Handler {
	s := mux.NewRouter()
	w := newWeb(c)
	s.HandleFunc("/device/dongle", w.Dongle)
	s.PathPrefix("/static/").
		Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(c.StaticDir))))
	s.HandleFunc("/", w.Home)
	return s
}

type web struct {
	cfg *Config
	tpl *hot.Template
}

func newWeb(cfg *Config) *web {
	w := &web{cfg: cfg}
	config := &hot.Config{
		Watch:          true,
		BaseName:       "fconf",
		Dir:            cfg.TemplatesDir,
		FilesExtension: []string{".tpl", ".html", ".tmpl"},
	}

	tpl, err := hot.New(config)
	if err != nil {
		panic(err)
	}
	w.tpl = tpl
	return w
}

func (ww *web) Home(w http.ResponseWriter, r *http.Request) {
	err := ww.tpl.Execute(w, "index.html", nil)
	if err != nil {
		log.Println(err)
	}
}

type errMSG struct {
	Message string `json:"error"`
}

func (ww *web) Dongle(w http.ResponseWriter, r *http.Request) {
	fName := filepath.Join(ww.cfg.AsteriskConfig, "dongle.conf")
	enc := json.NewEncoder(w)

	f, err := os.Open(fName)
	if err != nil {
		log.Println(err)
		enc.Encode(&errMSG{"trouble opening dongle configuration"})
		return
	}
	defer f.Close()
	p, err := gsm.NewParser(f)
	if err != nil {
		log.Println(err)
		enc.Encode(&errMSG{"trouble scanning dongle configuration"})
		return
	}
	ast, err := p.Parse()
	if err != nil {
		log.Println(err)
		enc.Encode(&errMSG{"trouble parsing dongle configuration"})
		return
	}
	err = ast.ToJSON(w)
	if err != nil {
		log.Println(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"image"
	"image/color"
	"log"
	"math/rand"

	"github.com/go-hep/hbook"
	"github.com/go-hep/hplot"
	"github.com/go-hep/hplot/vgshiny"
	"github.com/gonum/plot/plotter"
	"github.com/gonum/plot/vg"
	vgdraw "github.com/gonum/plot/vg/draw"
	"golang.org/x/exp/shiny/driver"
	"golang.org/x/exp/shiny/screen"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/paint"
)

const (
	NPOINTS = 100000
	xmax    = 400
	ymax    = 400
)

var (
	bkgCol = color.Black
)

func newPlot() (*hplot.Plot, error) {
	// Draw some random values from the standard
	// normal distribution.
	hist1 := hbook.NewH1D(100, -5, +5)
	hist2 := hbook.NewH1D(100, -5, +5)
	for i := 0; i < NPOINTS; i++ {
		v1 := rand.NormFloat64() - 1
		v2 := rand.NormFloat64() + 1
		hist1.Fill(v1, 1)
		hist2.Fill(v2, 1)
	}

	// Make a plot and set its title.
	p, err := hplot.New()
	if err != nil {
		return nil, err
	}
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h1, err := hplot.NewH1D(hist1)
	if err != nil {
		return nil, err
	}

	h2, err := hplot.NewH1D(hist2)
	if err != nil {
		return nil, err
	}

	h1.Infos.Style = hplot.HInfoSummary
	h2.Infos.Style = hplot.HInfoNone

	h1.Color = color.Black
	h1.FillColor = nil
	h2.Color = color.RGBA{255, 0, 0, 255}
	h2.FillColor = nil

	p.Add(h1)
	p.Add(h2)

	p.Add(plotter.NewGrid())
	return p, err
}

func main() {
	driver.Main(func(scr screen.Screen) {
		{
			p, err := newPlot()
			if err != nil {
				log.Fatal(err)
			}
			c, err := p.Show(-1, -1, scr)
			if err != nil {
				log.Fatal(err)
			}
			defer c.Release()
		}
		w, err := newWidget(scr, image.Point{xmax, ymax})
		if err != nil {
			log.Fatal(err)
		}
		defer w.Release()

		for {
			switch e := w.canvas.NextEvent().(type) {
			case key.Event:
				repaint := false
				switch e.Code {
				case key.CodeEscape, key.CodeQ:
					return
				case key.CodeR:
					if e.Direction == key.DirPress {
						repaint = true
					}

				case key.CodeN, key.CodeSpacebar:
					p, err := newPlot()
					if err != nil {
						log.Fatal(err)
					}
					p.Draw(vgdraw.New(w.canvas))
					repaint = true
				}
				if repaint {
					w.canvas.Send(paint.Event{})
				}

			case paint.Event:
				w.canvas.Paint()
			}
		}
	})
}

type widget struct {
	s      screen.Screen
	canvas *vgshiny.Canvas
}

func newWidget(s screen.Screen, size image.Point) (*widget, error) {
	c, err := vgshiny.New(s, vg.Length(size.X), vg.Length(size.Y))
	if err != nil {
		return nil, err
	}

	return &widget{s: s, canvas: c}, err
}

func (w *widget) Release() {
	if w.canvas != nil {
		w.canvas.Release()
		w.canvas = nil
	}
	w.s = nil
}
<commit_msg>cmd/iplot: use vgshiny.Canvas runner function<commit_after>package main

import (
	"image"
	"image/color"
	"log"
	"math/rand"

	"github.com/go-hep/hbook"
	"github.com/go-hep/hplot"
	"github.com/go-hep/hplot/vgshiny"
	"github.com/gonum/plot/plotter"
	"github.com/gonum/plot/vg"
	vgdraw "github.com/gonum/plot/vg/draw"
	"golang.org/x/exp/shiny/driver"
	"golang.org/x/exp/shiny/screen"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/paint"
)

const (
	NPOINTS = 100000
	xmax    = 400
	ymax    = 400
)

var (
	bkgCol = color.Black
)

func newPlot() (*hplot.Plot, error) {
	// Draw some random values from the standard
	// normal distribution.
	hist1 := hbook.NewH1D(100, -5, +5)
	hist2 := hbook.NewH1D(100, -5, +5)
	for i := 0; i < NPOINTS; i++ {
		v1 := rand.NormFloat64() - 1
		v2 := rand.NormFloat64() + 1
		hist1.Fill(v1, 1)
		hist2.Fill(v2, 1)
	}

	// Make a plot and set its title.
	p, err := hplot.New()
	if err != nil {
		return nil, err
	}
	p.Title.Text = "Histogram"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	// Create a histogram of our values drawn
	// from the standard normal.
	h1, err := hplot.NewH1D(hist1)
	if err != nil {
		return nil, err
	}

	h2, err := hplot.NewH1D(hist2)
	if err != nil {
		return nil, err
	}

	h1.Infos.Style = hplot.HInfoSummary
	h2.Infos.Style = hplot.HInfoNone

	h1.Color = color.Black
	h1.FillColor = nil
	h2.Color = color.RGBA{255, 0, 0, 255}
	h2.FillColor = nil

	p.Add(h1)
	p.Add(h2)

	p.Add(plotter.NewGrid())
	return p, err
}

func main() {
	driver.Main(func(scr screen.Screen) {
		{
			p, err := newPlot()
			if err != nil {
				log.Fatal(err)
			}
			c, err := p.Show(-1, -1, scr)
			if err != nil {
				log.Fatal(err)
			}
			go func() {
				c.Run(nil)
				c.Release()
			}()
		}
		w, err := newWidget(scr, image.Point{xmax, ymax})
		if err != nil {
			log.Fatal(err)
		}
		defer w.Release()

		w.canvas.Run(func(e interface{}) bool {
			switch e := e.(type) {
			case key.Event:
				repaint := false
				switch e.Code {
				case key.CodeEscape, key.CodeQ:
					if e.Direction == key.DirPress {
						return false
					}
				case key.CodeR:
					if e.Direction == key.DirPress {
						repaint = true
					}

				case key.CodeN, key.CodeSpacebar:
					if e.Direction == key.DirPress {
						p, err := newPlot()
						if err != nil {
							log.Fatal(err)
						}
						p.Draw(vgdraw.New(w.canvas))
						repaint = true
					}
				}
				if repaint {
					w.canvas.Send(paint.Event{})
				}

			case paint.Event:
				w.canvas.Paint()
			}
			return true
		})
	})
}

type widget struct {
	s      screen.Screen
	canvas *vgshiny.Canvas
}

func newWidget(s screen.Screen, size image.Point) (*widget, error) {
	c, err := vgshiny.New(s, vg.Length(size.X), vg.Length(size.Y))
	if err != nil {
		return nil, err
	}

	return &widget{s: s, canvas: c}, err
}

func (w *widget) Release() {
	if w.canvas != nil {
		w.canvas.Release()
		w.canvas = nil
	}
	w.s = nil
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"net/rpc"
	"os"
	"path/filepath"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/utils/exec"
	"launchpad.net/juju-core/worker/uniter/jujuc"

	// Import the providers.
	_ "launchpad.net/juju-core/provider/all"
)

var jujudDoc = `
juju provides easy, intelligent service orchestration on top of environments
such as OpenStack, Amazon AWS, or bare metal. jujud is a component of juju.

https://juju.ubuntu.com/

The jujud command can also forward invocations over RPC for execution by the
juju unit agent. When used in this way, it expects to be called via a symlink
named for the desired remote command, and expects JUJU_AGENT_SOCKET and
JUJU_CONTEXT_ID be set in its environment.
`

func getenv(name string) (string, error) {
	value := os.Getenv(name)
	if value == "" {
		return "", fmt.Errorf("%s not set", name)
	}
	return value, nil
}

func getwd() (string, error) {
	dir, err := os.Getwd()
	if err != nil {
		return "", err
	}
	abs, err := filepath.Abs(dir)
	if err != nil {
		return "", err
	}
	return abs, nil
}

// jujuCMain uses JUJU_CONTEXT_ID and JUJU_AGENT_SOCKET to ask a running unit agent
// to execute a Command on our behalf. Individual commands should be exposed
// by symlinking the command name to this executable.
func jujuCMain(commandName string, args []string) (code int, err error) {
	code = 1
	contextId, err := getenv("JUJU_CONTEXT_ID")
	if err != nil {
		return
	}
	dir, err := getwd()
	if err != nil {
		return
	}
	req := jujuc.Request{
		ContextId:   contextId,
		Dir:         dir,
		CommandName: commandName,
		Args:        args[1:],
	}
	socketPath, err := getenv("JUJU_AGENT_SOCKET")
	if err != nil {
		return
	}
	client, err := rpc.Dial("unix", socketPath)
	if err != nil {
		return
	}
	defer client.Close()
	var resp exec.ExecResponse
	err = client.Call("Jujuc.Main", req, &resp)
	if err != nil {
		return
	}
	os.Stdout.Write(resp.Stdout)
	os.Stderr.Write(resp.Stderr)
	return resp.Code, nil
}

// Main registers subcommands for the jujud executable, and hands over control
// to the cmd package.
func jujuDMain(args []string) (code int, err error) {
	jujud := cmd.NewSuperCommand(cmd.SuperCommandParams{
		Name: "jujud",
		Doc:  jujudDoc,
		Log:  &cmd.Log{},
	})
	jujud.Register(&BootstrapCommand{})
	jujud.Register(&MachineAgent{})
	jujud.Register(&UnitAgent{})
	jujud.Register(&cmd.VersionCommand{})
	code = cmd.Main(jujud, cmd.DefaultContext(), args[1:])
	return code, nil
}

// Main is not redundant with main(), because it provides an entry point
// for testing with arbitrary command line arguments.
func Main(args []string) {
	var code int = 1
	var err error
	commandName := filepath.Base(args[0])
	if commandName == "jujud" {
		code, err = jujuDMain(args)
	} else if commandName == "jujuc" {
		fmt.Fprint(os.Stderr, jujudDoc)
		code = 2
		err = fmt.Errorf("jujuc should not be called directly")
	} else if commandName == "juju-run" {
		code = cmd.Main(&RunCommand{}, cmd.DefaultContext(), args[1:])
	} else {
		code, err = jujuCMain(commandName, args)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
	}
	os.Exit(code)
}

func main() {
	Main(os.Args)
}
<commit_msg>Make sure logging starting with unit. doesn't have filenames and line numbers.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io"
	"net/rpc"
	"os"
	"path/filepath"
	"strings"
	"time"

	"launchpad.net/loggo"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/utils/exec"
	"launchpad.net/juju-core/worker/uniter/jujuc"

	// Import the providers.
	_ "launchpad.net/juju-core/provider/all"
)

var jujudDoc = `
juju provides easy, intelligent service orchestration on top of environments
such as OpenStack, Amazon AWS, or bare metal. jujud is a component of juju.

https://juju.ubuntu.com/

The jujud command can also forward invocations over RPC for execution by the
juju unit agent. When used in this way, it expects to be called via a symlink
named for the desired remote command, and expects JUJU_AGENT_SOCKET and
JUJU_CONTEXT_ID be set in its environment.
`

func getenv(name string) (string, error) {
	value := os.Getenv(name)
	if value == "" {
		return "", fmt.Errorf("%s not set", name)
	}
	return value, nil
}

func getwd() (string, error) {
	dir, err := os.Getwd()
	if err != nil {
		return "", err
	}
	abs, err := filepath.Abs(dir)
	if err != nil {
		return "", err
	}
	return abs, nil
}

// jujuCMain uses JUJU_CONTEXT_ID and JUJU_AGENT_SOCKET to ask a running unit agent
// to execute a Command on our behalf. Individual commands should be exposed
// by symlinking the command name to this executable.
func jujuCMain(commandName string, args []string) (code int, err error) {
	code = 1
	contextId, err := getenv("JUJU_CONTEXT_ID")
	if err != nil {
		return
	}
	dir, err := getwd()
	if err != nil {
		return
	}
	req := jujuc.Request{
		ContextId:   contextId,
		Dir:         dir,
		CommandName: commandName,
		Args:        args[1:],
	}
	socketPath, err := getenv("JUJU_AGENT_SOCKET")
	if err != nil {
		return
	}
	client, err := rpc.Dial("unix", socketPath)
	if err != nil {
		return
	}
	defer client.Close()
	var resp exec.ExecResponse
	err = client.Call("Jujuc.Main", req, &resp)
	if err != nil {
		return
	}
	os.Stdout.Write(resp.Stdout)
	os.Stderr.Write(resp.Stderr)
	return resp.Code, nil
}

// Main registers subcommands for the jujud executable, and hands over control
// to the cmd package.
func jujuDMain(args []string) (code int, err error) {
	jujud := cmd.NewSuperCommand(cmd.SuperCommandParams{
		Name: "jujud",
		Doc:  jujudDoc,
		Log:  &cmd.Log{Factory: &writerFactory{}},
	})
	jujud.Register(&BootstrapCommand{})
	jujud.Register(&MachineAgent{})
	jujud.Register(&UnitAgent{})
	jujud.Register(&cmd.VersionCommand{})
	code = cmd.Main(jujud, cmd.DefaultContext(), args[1:])
	return code, nil
}

// Main is not redundant with main(), because it provides an entry point
// for testing with arbitrary command line arguments.
func Main(args []string) {
	var code int = 1
	var err error
	commandName := filepath.Base(args[0])
	if commandName == "jujud" {
		code, err = jujuDMain(args)
	} else if commandName == "jujuc" {
		fmt.Fprint(os.Stderr, jujudDoc)
		code = 2
		err = fmt.Errorf("jujuc should not be called directly")
	} else if commandName == "juju-run" {
		code = cmd.Main(&RunCommand{}, cmd.DefaultContext(), args[1:])
	} else {
		code, err = jujuCMain(commandName, args)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
	}
	os.Exit(code)
}

func main() {
	Main(os.Args)
}

type writerFactory struct{}

func (*writerFactory) NewWriter(target io.Writer) loggo.Writer {
	return &jujudWriter{target: target}
}

type jujudWriter struct {
	target           io.Writer
	unitFormatter    simpleFormatter
	defaultFormatter loggo.DefaultFormatter
}

var _ loggo.Writer = (*jujudWriter)(nil)

func (w *jujudWriter) Write(level loggo.Level, module, filename string, line int, timestamp time.Time, message string) {
	if strings.HasPrefix(module, "unit.") {
		fmt.Fprintln(w.target, w.unitFormatter.Format(level, module, timestamp, message))
	} else {
		fmt.Fprintln(w.target, w.defaultFormatter.Format(level, module, filename, line, timestamp, message))
	}
}

type simpleFormatter struct{}

func (*simpleFormatter) Format(level loggo.Level, module string, timestamp time.Time, message string) string {
	ts := timestamp.In(time.UTC).Format("2006-01-02 15:04:05")
	// Just show the last element of the module.
	lastDot := strings.LastIndex(module, ".")
	module = module[lastDot+1:]
	return fmt.Sprintf("%s %s %s %s", ts, level, module, message)
}
<|endoftext|>


<commit_before>package main

import (
	"container/heap"
	"fmt"
	"reflect"
	"strconv"
	"sync/atomic"
	"time"
	"unsafe"

	"github.com/hashicorp/go-immutable-radix"
	"github.com/relab/raft/commonpb"
	"github.com/relab/rkv/rkvpb"
)

// SnapTick is the time between finishing taking a snapshot and starting to take
// a new one. TODO Config.
const SnapTick = 20 * time.Second

// Store is an implementation of raft.StateMachine. It holds client session
// information, and a key-value store.
type Store struct {
	kvs         *iradix.Tree
	sessions    *iradix.Tree
	pendingCmds map[uint64]*Cmds

	snapTimer *time.Timer
	snapshot  unsafe.Pointer // *commonpb.Snapshot
}

// NewStore initializes and returns a *Store.
func NewStore() *Store {
	return &Store{
		kvs:         iradix.New(),
		sessions:    iradix.New(),
		pendingCmds: make(map[uint64]*Cmds),
		snapTimer:   time.NewTimer(SnapTick),
		snapshot:    unsafe.Pointer(&commonpb.Snapshot{}),
	}
}

// Apply implements raft.StateMachine.
func (s *Store) Apply(entry *commonpb.Entry) interface{} {
	switch entry.EntryType {
	case commonpb.EntryNormal:
		var cmd rkvpb.Cmd
		err := cmd.Unmarshal(entry.Data)

		if err != nil {
			panic(fmt.Sprintf("could not unmarshal %v: %v", entry.Data, err))
		}

		res := s.applyStore(entry.Index, &cmd)
		s.maybeSnapshot(entry)
		return res
	case commonpb.EntryConfChange:
		// TODO s.snapshotMaybe(entry)?
		panic("not implemented yet")
	default:
		panic(fmt.Sprintf("got unknown entry type: %v", entry.EntryType))
	}
}

func (s *Store) maybeSnapshot(entry *commonpb.Entry) {
	select {
	case <-s.snapTimer.C:
		go s.takeSnapshot(
			atomic.LoadPointer(&s.snapshot),
			entry.Term, entry.Index,
			s.kvs.Root().Iterator(),
			s.sessions.Root().Iterator(),
		)
	default:
	}
}

func (s *Store) applyStore(i uint64, cmd *rkvpb.Cmd) interface{} {
	switch cmd.CmdType {
	case rkvpb.Register:
		id := []byte(strconv.FormatUint(i, 10))
		s.sessions, _, _ = s.sessions.Insert(id, uint64(0))

		var pending Cmds
		heap.Init(&pending)
		s.pendingCmds[i] = &pending

		return i
	case rkvpb.Insert:
		var req rkvpb.InsertRequest
		err := req.Unmarshal(cmd.Data)
		if err != nil {
			panic(fmt.Sprintf("could not unmarshal %v: %v", cmd.Data, err))
		}

		id := []byte(strconv.FormatUint(req.ClientID, 10))
		raw, found := s.sessions.Get(id)

		if !found {
			panic(fmt.Sprintf("clientID %v not found", req.ClientID))
		}

		oldSeq, ok := raw.(uint64)

		if !ok {
			panic(fmt.Sprintf("expected uint64 got %s", reflect.TypeOf(raw)))
		}

		nextSeq := oldSeq

		txn := s.kvs.Txn()

		if req.ClientSeq != nextSeq+1 {
			s.PushCmd(req.ClientID, &req)
		} else {
			txn.Insert([]byte(req.Key), req.Value)
			nextSeq++
		}

		for s.HasCmd(req.ClientID, nextSeq+1) {
			nextReq := s.PopCmd(req.ClientID)
			txn.Insert([]byte(nextReq.Key), nextReq.Value)
			nextSeq++
		}

		s.kvs = txn.CommitOnly()

		if oldSeq != nextSeq {
			s.sessions, _, _ = s.sessions.Insert(id, nextSeq)
		}

		return true
	case rkvpb.Lookup:
		var req rkvpb.LookupRequest
		err := req.Unmarshal(cmd.Data)
		if err != nil {
			panic(err)
		}

		raw, found := s.kvs.Get([]byte(req.Key))

		if !found {
			return "(none)"
		}

		val, ok := raw.(string)

		if !ok {
			panic(fmt.Sprintf("expected string got %s", reflect.TypeOf(raw)))
		}

		return val
	default:
		panic(fmt.Sprintf("got unknown cmd type: %v", cmd.CmdType))
	}
}

// Snapshot implements raft.StateMachine.
func (s *Store) Snapshot() *commonpb.Snapshot {
	snapshot := (*commonpb.Snapshot)(atomic.LoadPointer(&s.snapshot))
	return snapshot
}

func (s *Store) takeSnapshot(old unsafe.Pointer, term, index uint64, iterKvs, iterSessions *iradix.Iterator) {
	start := time.Now()
	defer func() {
		fmt.Println("Snapshot took:", time.Now().Sub(start))
	}()

	var kvs []*rkvpb.KeyValue
	k, v, more := iterKvs.Next()

	for more {
		kvs = append(kvs, &rkvpb.KeyValue{
			Key:   k,
			Value: v.(string),
		})
		k, v, more = iterKvs.Next()
	}

	var sessions []*rkvpb.Session
	k, v, more = iterSessions.Next()

	for more {
		sessions = append(sessions, &rkvpb.Session{
			ClientID:  k,
			ClientSeq: v.(uint64),
		})
		k, v, more = iterSessions.Next()
	}

	snap := &rkvpb.Snapshot{
		Kvs:      kvs,
		Sessions: sessions,
	}

	b, err := snap.Marshal()
	if err != nil {
		panic(fmt.Sprintf("could not marshal %v: %v", snap, err))
	}

	fmt.Println("Snapshot size:", len(b), "bytes")

	// This is supposed to prevent a snapshot in progress from overwriting a
	// call to Restore.
	atomic.CompareAndSwapPointer(&s.snapshot, old, unsafe.Pointer(&commonpb.Snapshot{
		Term:  term,
		Index: index,
		Data:  b,
	}))
	s.snapTimer = time.NewTimer(SnapTick)
}

// Restore implements raft.StateMachine.
func (s *Store) Restore(snapshot *commonpb.Snapshot) {
	// Replace current snapshot.
	atomic.StorePointer(&s.snapshot, unsafe.Pointer(snapshot))

	var snap rkvpb.Snapshot
	err := snap.Unmarshal(snapshot.Data)
	if err != nil {
		panic(fmt.Sprintf("could not unmarshal %v: %v", snapshot.Data, err))
	}

	txn := s.kvs.Txn()
	for _, kv := range snap.Kvs {
		txn.Insert(kv.Key, kv.Value)
	}
	s.kvs = txn.CommitOnly()

	txn = s.sessions.Txn()
	for _, session := range snap.Sessions {
		txn.Insert(session.ClientID, session.ClientSeq)
	}
	s.sessions = txn.CommitOnly()
}
<commit_msg>rkvd: Fix off-by-one and dereference nil pointer errors<commit_after>package main

import (
	"container/heap"
	"fmt"
	"reflect"
	"strconv"
	"sync/atomic"
	"time"
	"unsafe"

	"github.com/hashicorp/go-immutable-radix"
	"github.com/relab/raft/commonpb"
	"github.com/relab/rkv/rkvpb"
)

// SnapTick is the time between finishing taking a snapshot and starting to take
// a new one. TODO Config.
const SnapTick = 20 * time.Second

// Store is an implementation of raft.StateMachine. It holds client session
// information, and a key-value store.
type Store struct {
	kvs         *iradix.Tree
	sessions    *iradix.Tree
	pendingCmds map[uint64]*Cmds

	snapTimer *time.Timer
	snapshot  unsafe.Pointer // *commonpb.Snapshot
}

// NewStore initializes and returns a *Store.
func NewStore() *Store {
	return &Store{
		kvs:         iradix.New(),
		sessions:    iradix.New(),
		pendingCmds: make(map[uint64]*Cmds),
		snapTimer:   time.NewTimer(SnapTick),
		// Important that Index == 1, nextIndex starts at 1, also 0 - 1
		// will overflow uint64.
		snapshot: unsafe.Pointer(&commonpb.Snapshot{Index: 1}),
	}
}

// Apply implements raft.StateMachine.
func (s *Store) Apply(entry *commonpb.Entry) interface{} {
	switch entry.EntryType {
	case commonpb.EntryNormal:
		var cmd rkvpb.Cmd
		err := cmd.Unmarshal(entry.Data)

		if err != nil {
			panic(fmt.Sprintf("could not unmarshal %v: %v", entry.Data, err))
		}

		res, mutated := s.applyStore(entry.Index, &cmd)

		// We can only snapshot if the state was mutated, i.e., on write
		// requests. This is because we currently don't set entry.Index
		// for read requests.
		if mutated {
			s.maybeSnapshot(entry)
		}
		return res
	case commonpb.EntryConfChange:
		// TODO s.snapshotMaybe(entry)?
		panic("not implemented yet")
	default:
		panic(fmt.Sprintf("got unknown entry type: %v", entry.EntryType))
	}
}

func (s *Store) maybeSnapshot(entry *commonpb.Entry) {
	select {
	case <-s.snapTimer.C:
		go s.takeSnapshot(
			atomic.LoadPointer(&s.snapshot),
			entry.Term, entry.Index,
			s.kvs.Root().Iterator(),
			s.sessions.Root().Iterator(),
		)
	default:
	}
}

func (s *Store) applyStore(i uint64, cmd *rkvpb.Cmd) (interface{}, bool) {
	switch cmd.CmdType {
	case rkvpb.Register:
		id := []byte(strconv.FormatUint(i, 10))
		s.sessions, _, _ = s.sessions.Insert(id, uint64(0))

		var pending Cmds
		heap.Init(&pending)
		s.pendingCmds[i] = &pending

		return i, true
	case rkvpb.Insert:
		var req rkvpb.InsertRequest
		err := req.Unmarshal(cmd.Data)
		if err != nil {
			panic(fmt.Sprintf("could not unmarshal %v: %v", cmd.Data, err))
		}

		id := []byte(strconv.FormatUint(req.ClientID, 10))
		raw, found := s.sessions.Get(id)

		if !found {
			panic(fmt.Sprintf("clientID %v not found", req.ClientID))
		}

		oldSeq, ok := raw.(uint64)

		if !ok {
			panic(fmt.Sprintf("expected uint64 got %s", reflect.TypeOf(raw)))
		}

		nextSeq := oldSeq

		txn := s.kvs.Txn()

		if req.ClientSeq != nextSeq+1 {
			s.PushCmd(req.ClientID, &req)
		} else {
			txn.Insert([]byte(req.Key), req.Value)
			nextSeq++
		}

		for s.HasCmd(req.ClientID, nextSeq+1) {
			nextReq := s.PopCmd(req.ClientID)
			txn.Insert([]byte(nextReq.Key), nextReq.Value)
			nextSeq++
		}

		s.kvs = txn.CommitOnly()

		if oldSeq != nextSeq {
			s.sessions, _, _ = s.sessions.Insert(id, nextSeq)
		}

		return true, true
	case rkvpb.Lookup:
		var req rkvpb.LookupRequest
		err := req.Unmarshal(cmd.Data)
		if err != nil {
			panic(err)
		}

		raw, found := s.kvs.Get([]byte(req.Key))

		if !found {
			return "(none)", false
		}

		val, ok := raw.(string)

		if !ok {
			panic(fmt.Sprintf("expected string got %s", reflect.TypeOf(raw)))
		}

		return val, false
	default:
		panic(fmt.Sprintf("got unknown cmd type: %v", cmd.CmdType))
	}
}

// Snapshot implements raft.StateMachine.
func (s *Store) Snapshot() *commonpb.Snapshot {
	snapshot := (*commonpb.Snapshot)(atomic.LoadPointer(&s.snapshot))
	return snapshot
}

func (s *Store) takeSnapshot(old unsafe.Pointer, term, index uint64, iterKvs, iterSessions *iradix.Iterator) {
	start := time.Now()
	defer func() {
		fmt.Println("Snapshot took:", time.Now().Sub(start))
	}()

	var kvs []*rkvpb.KeyValue
	k, v, more := iterKvs.Next()

	for more {
		kvs = append(kvs, &rkvpb.KeyValue{
			Key:   k,
			Value: v.(string),
		})
		k, v, more = iterKvs.Next()
	}

	var sessions []*rkvpb.Session
	k, v, more = iterSessions.Next()

	for more {
		sessions = append(sessions, &rkvpb.Session{
			ClientID:  k,
			ClientSeq: v.(uint64),
		})
		k, v, more = iterSessions.Next()
	}

	snap := &rkvpb.Snapshot{
		Kvs:      kvs,
		Sessions: sessions,
	}

	b, err := snap.Marshal()
	if err != nil {
		panic(fmt.Sprintf("could not marshal %v: %v", snap, err))
	}

	fmt.Println("Snapshot size:", len(b), "bytes")

	// This is supposed to prevent a snapshot in progress from overwriting a
	// call to Restore.
	atomic.CompareAndSwapPointer(&s.snapshot, old, unsafe.Pointer(&commonpb.Snapshot{
		Term:  term,
		Index: index,
		Data:  b,
	}))
	s.snapTimer = time.NewTimer(SnapTick)
}

// Restore implements raft.StateMachine.
func (s *Store) Restore(snapshot *commonpb.Snapshot) {
	// Replace current snapshot.
	atomic.StorePointer(&s.snapshot, unsafe.Pointer(snapshot))

	s.pendingCmds = make(map[uint64]*Cmds)

	// Return if we received the empty snapshot.
	if snapshot.Data == nil {
		return
	}

	var snap rkvpb.Snapshot
	err := snap.Unmarshal(snapshot.Data)
	if err != nil {
		panic(fmt.Sprintf("could not unmarshal %v: %v", snapshot.Data, err))
	}

	txn := s.kvs.Txn()
	for _, kv := range snap.Kvs {
		txn.Insert(kv.Key, kv.Value)
	}
	s.kvs = txn.CommitOnly()

	txn = s.sessions.Txn()
	for _, session := range snap.Sessions {
		txn.Insert(session.ClientID, session.ClientSeq)
		var pending Cmds
		heap.Init(&pending)
		id, _ := strconv.Atoi(string(session.ClientID))
		s.pendingCmds[uint64(id)] = &pending
	}
	s.sessions = txn.CommitOnly()
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mvdan/sh"
)

var (
	write  = flag.Bool("w", false, "write result to file instead of stdout")
	list   = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	indent = flag.Int("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")
)

var (
	config sh.PrintConfig
	buf    bytes.Buffer
)

func main() {
	flag.Parse()
	config.Spaces = *indent
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	anyErr := false
	onError := func(err error) {
		anyErr = true
		fmt.Fprintln(os.Stderr, err)
	}
	for _, path := range flag.Args() {
		if err := walk(path, onError); err != nil {
			onError(err)
		}
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	src, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	prog, err := sh.Parse(src, "", sh.ParseComments)
	if err != nil {
		return err
	}
	return config.Fprint(os.Stdout, prog)
}

var (
	hidden       = regexp.MustCompile(`^\.[^/.]`)
	shellFile    = regexp.MustCompile(`^.*\.(sh|bash)$`)
	validShebang = regexp.MustCompile(`^#!/(usr/)?bin/(env *)?(sh|bash)`)
)

func isShellFile(info os.FileInfo) bool {
	name := info.Name()
	switch {
	case info.IsDir(), hidden.MatchString(name):
		return false
	case shellFile.MatchString(name):
		return true
	case !info.Mode().IsRegular():
		return false
	case strings.Contains(name, "."):
		return false // different extension
	case info.Size() < 8:
		return false // cannot possibly hold valid shebang
	default:
		return true
	}
}

func walk(path string, onError func(error)) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !info.IsDir() {
		return formatPath(path, true)
	}
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if err == nil && isShellFile(info) {
			err = formatPath(path, false)
		}
		if err != nil {
			onError(err)
		}
		return nil
	})
}

func empty(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

func formatPath(path string, always bool) error {
	mode := os.O_RDONLY
	if *write {
		mode = os.O_RDWR
	}
	f, err := os.OpenFile(path, mode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	if !always && !validShebang.Match(src[:32]) {
		return nil
	}
	prog, err := sh.Parse(src, path, sh.ParseComments)
	if err != nil {
		return err
	}
	buf.Reset()
	if err := config.Fprint(&buf, prog); err != nil {
		return err
	}
	res := buf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			fmt.Println(path)
		}
		if *write {
			if err := empty(f); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := os.Stdout.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>cmd/shfmt: collapse var blocks<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mvdan/sh"
)

var (
	write  = flag.Bool("w", false, "write result to file instead of stdout")
	list   = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	indent = flag.Int("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")

	config sh.PrintConfig
	buf    bytes.Buffer
)

func main() {
	flag.Parse()
	config.Spaces = *indent
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	anyErr := false
	onError := func(err error) {
		anyErr = true
		fmt.Fprintln(os.Stderr, err)
	}
	for _, path := range flag.Args() {
		if err := walk(path, onError); err != nil {
			onError(err)
		}
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	src, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	prog, err := sh.Parse(src, "", sh.ParseComments)
	if err != nil {
		return err
	}
	return config.Fprint(os.Stdout, prog)
}

var (
	hidden       = regexp.MustCompile(`^\.[^/.]`)
	shellFile    = regexp.MustCompile(`^.*\.(sh|bash)$`)
	validShebang = regexp.MustCompile(`^#!/(usr/)?bin/(env *)?(sh|bash)`)
)

func isShellFile(info os.FileInfo) bool {
	name := info.Name()
	switch {
	case info.IsDir(), hidden.MatchString(name):
		return false
	case shellFile.MatchString(name):
		return true
	case !info.Mode().IsRegular():
		return false
	case strings.Contains(name, "."):
		return false // different extension
	case info.Size() < 8:
		return false // cannot possibly hold valid shebang
	default:
		return true
	}
}

func walk(path string, onError func(error)) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !info.IsDir() {
		return formatPath(path, true)
	}
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if err == nil && isShellFile(info) {
			err = formatPath(path, false)
		}
		if err != nil {
			onError(err)
		}
		return nil
	})
}

func empty(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

func formatPath(path string, always bool) error {
	mode := os.O_RDONLY
	if *write {
		mode = os.O_RDWR
	}
	f, err := os.OpenFile(path, mode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	if !always && !validShebang.Match(src[:32]) {
		return nil
	}
	prog, err := sh.Parse(src, path, sh.ParseComments)
	if err != nil {
		return err
	}
	buf.Reset()
	if err := config.Fprint(&buf, prog); err != nil {
		return err
	}
	res := buf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			fmt.Println(path)
		}
		if *write {
			if err := empty(f); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := os.Stdout.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package doit

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"text/tabwriter"

	"github.com/digitalocean/godo"
)

const (
	// NSRoot is a configuration key that signifies this value is at the root.
	NSRoot = "doit"
)

// DisplayOutput displays an object or group of objects to a user. It
// checks to see what the output type should be.
func DisplayOutput(item interface{}, out io.Writer) error {
	output := DoitConfig.GetString(NSRoot, "output")
	if output == "" {
		output = "text"
	}

	switch output {
	case "json":
		return writeJSON(item, out)
	case "text":
		return writeText(item, out)
	default:
		return fmt.Errorf("unknown output type")
	}
}

func writeJSON(item interface{}, w io.Writer) error {
	b, err := json.Marshal(item)
	if err != nil {
		return err
	}

	var out bytes.Buffer
	json.Indent(&out, b, "", "  ")
	_, err = out.WriteTo(w)
	return err
}

func writeText(item interface{}, w io.Writer) error {
	switch i := item.(type) {
	case *godo.Account:
		a := item.(*godo.Account)
		outputAccount(a, w)
	case *godo.Action:
		outputActions([]godo.Action{*i}, w)
	case []godo.Action:
		outputActions(i, w)
	case *godo.Domain:
		outputZone(item.(*godo.Domain), w)
	case []godo.Domain:
		outputDomains(i, w)
	case *godo.DomainRecord:
		outputRecords([]godo.DomainRecord{*i}, w)
	case []godo.DomainRecord:
		outputRecords(i, w)
	case *godo.Droplet:
		outputDroplets([]godo.Droplet{*i}, w)
	case []godo.Droplet:
		outputDroplets(i, w)
	case *godo.Image:
		outputImages([]godo.Image{*i}, w)
	case []godo.Image:
		outputImages(i, w)
	case *godo.Kernel:
		outputKernels([]godo.Kernel{*i}, w)
	case []godo.Kernel:
		outputKernels(i, w)
	case *godo.Key:
		outputSSHKeys([]godo.Key{*i}, w)
	case []godo.Key:
		outputSSHKeys(i, w)

	case []godo.Region:
		outputRegions(i, w)
	case []godo.Size:
		outputSizes(i, w)

	case *godo.FloatingIP:
		outputFloatingIPs([]godo.FloatingIP{*i}, w)
	case []godo.FloatingIP:
		outputFloatingIPs(i, w)

	default:
		panic(fmt.Sprintf("no mapping for %T", item))
	}

	return nil
}

func outputAccount(account *godo.Account, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Email\tDroplet Limit\tEmail Verified\tUUID\t")
	fmt.Fprintf(w, "")
	fmt.Fprintf(w, "%s\t%d\t%t\t%s\t\n", account.Email, account.DropletLimit, account.EmailVerified, account.UUID)
	fmt.Fprintln(w)
	w.Flush()
}

func outputActions(list []godo.Action, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tStatus\tType\tStarted At\tCompleted At\tResource ID\tResource Type\tRegion")

	for _, a := range list {
		fmt.Fprintf(w, "")
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%d\t%s\t%s\n",
			a.ID, a.Status, a.Type, a.StartedAt, a.CompletedAt, a.ResourceID, a.ResourceType, a.RegionSlug)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputDroplets(list []godo.Droplet, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tPublic IPv4\tMemory\tVCPUs\tDisk\tRegion\tImage\tStatus")

	for _, d := range list {
		ip := extractDropletPublicIP(&d)
		image := fmt.Sprintf("%s %s", d.Image.Distribution, d.Image.Name)
		fmt.Fprintf(w, "%d\t%s\t%s\t%d\t%d\t%d\t%s\t%s\t%s\n",
			d.ID, d.Name, ip, d.Memory, d.Vcpus, d.Disk, d.Region.Slug, image, d.Status)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputFloatingIPs(list []godo.FloatingIP, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 4*4, 1, '\t', 0)

	fmt.Fprintln(w, "IP\tRegion\tDroplet")
	for _, ip := range list {
		var droplet string
		if ip.Droplet != nil {
			droplet = fmt.Sprintf("%d", ip.Droplet.ID)
		}
		fmt.Fprintf(w, "%s\t%s\t%s\n", ip.IP, ip.Region.Slug, droplet)
	}

	fmt.Fprintln(w)
	w.Flush()
}

func outputImages(list []godo.Image, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tType\tDistribution\tSlug\tPublic\tMin Disk")

	for _, i := range list {
		publicStatus := false
		if i.Public {
			publicStatus = true
		}

		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%d\n",
			i.ID, i.Name, i.Type, i.Distribution, i.Slug, publicStatus, i.MinDiskSize)

	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputKernels(list []godo.Kernel, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tVersion")

	for _, k := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n", k.ID, k.Name, k.Version)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputRegions(list []godo.Region, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tName\tAvailable")

	for _, r := range list {
		fmt.Fprintf(w, "%s\t%s\t%t\n", r.Slug, r.Name, r.Available)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSizes(list []godo.Size, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tMemory\tVcpus\tDisk\tPrice Monthly\tPrice Hourly")

	for _, s := range list {
		fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%0.2f\t%f\n",
			s.Slug, s.Memory, s.Vcpus, s.Disk, s.PriceMonthly, s.PriceHourly)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSSHKeys(list []godo.Key, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tFingerprint")

	for _, s := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n",
			s.ID, s.Name, s.Fingerprint)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputZone(domain *godo.Domain, out io.Writer) {
	fmt.Fprintln(out, domain.ZoneFile)
}

func outputDomains(list []godo.Domain, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Name")

	for _, d := range list {
		fmt.Fprintf(w, "%s\n", d.Name)
	}

	fmt.Fprintln(w)
	w.Flush()
}

func outputRecords(list []godo.DomainRecord, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tType\tName\tData\tPriority\tPort\tWeight")

	for _, d := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%d\t%d\n", d.ID, d.Type, d.Name, d.Data,
			d.Priority, d.Port, d.Weight)
	}

	fmt.Fprintln(w)
	w.Flush()
}
<commit_msg>Fix column listing for floating IPs<commit_after>package doit

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"text/tabwriter"

	"github.com/digitalocean/godo"
)

const (
	// NSRoot is a configuration key that signifies this value is at the root.
	NSRoot = "doit"
)

// DisplayOutput displays an object or group of objects to a user. It
// checks to see what the output type should be.
func DisplayOutput(item interface{}, out io.Writer) error {
	output := DoitConfig.GetString(NSRoot, "output")
	if output == "" {
		output = "text"
	}

	switch output {
	case "json":
		return writeJSON(item, out)
	case "text":
		return writeText(item, out)
	default:
		return fmt.Errorf("unknown output type")
	}
}

func writeJSON(item interface{}, w io.Writer) error {
	b, err := json.Marshal(item)
	if err != nil {
		return err
	}

	var out bytes.Buffer
	json.Indent(&out, b, "", "  ")
	_, err = out.WriteTo(w)
	return err
}

func writeText(item interface{}, w io.Writer) error {
	switch i := item.(type) {
	case *godo.Account:
		a := item.(*godo.Account)
		outputAccount(a, w)
	case *godo.Action:
		outputActions([]godo.Action{*i}, w)
	case []godo.Action:
		outputActions(i, w)
	case *godo.Domain:
		outputZone(item.(*godo.Domain), w)
	case []godo.Domain:
		outputDomains(i, w)
	case *godo.DomainRecord:
		outputRecords([]godo.DomainRecord{*i}, w)
	case []godo.DomainRecord:
		outputRecords(i, w)
	case *godo.Droplet:
		outputDroplets([]godo.Droplet{*i}, w)
	case []godo.Droplet:
		outputDroplets(i, w)
	case *godo.Image:
		outputImages([]godo.Image{*i}, w)
	case []godo.Image:
		outputImages(i, w)
	case *godo.Kernel:
		outputKernels([]godo.Kernel{*i}, w)
	case []godo.Kernel:
		outputKernels(i, w)
	case *godo.Key:
		outputSSHKeys([]godo.Key{*i}, w)
	case []godo.Key:
		outputSSHKeys(i, w)

	case []godo.Region:
		outputRegions(i, w)
	case []godo.Size:
		outputSizes(i, w)

	case *godo.FloatingIP:
		outputFloatingIPs([]godo.FloatingIP{*i}, w)
	case []godo.FloatingIP:
		outputFloatingIPs(i, w)

	default:
		panic(fmt.Sprintf("no mapping for %T", item))
	}

	return nil
}

func outputAccount(account *godo.Account, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Email\tDroplet Limit\tEmail Verified\tUUID\t")
	fmt.Fprintf(w, "")
	fmt.Fprintf(w, "%s\t%d\t%t\t%s\t\n", account.Email, account.DropletLimit, account.EmailVerified, account.UUID)
	fmt.Fprintln(w)
	w.Flush()
}

func outputActions(list []godo.Action, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tStatus\tType\tStarted At\tCompleted At\tResource ID\tResource Type\tRegion")

	for _, a := range list {
		fmt.Fprintf(w, "")
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%d\t%s\t%s\n",
			a.ID, a.Status, a.Type, a.StartedAt, a.CompletedAt, a.ResourceID, a.ResourceType, a.RegionSlug)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputDroplets(list []godo.Droplet, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tPublic IPv4\tMemory\tVCPUs\tDisk\tRegion\tImage\tStatus")

	for _, d := range list {
		ip := extractDropletPublicIP(&d)
		image := fmt.Sprintf("%s %s", d.Image.Distribution, d.Image.Name)
		fmt.Fprintf(w, "%d\t%s\t%s\t%d\t%d\t%d\t%s\t%s\t%s\n",
			d.ID, d.Name, ip, d.Memory, d.Vcpus, d.Disk, d.Region.Slug, image, d.Status)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputFloatingIPs(list []godo.FloatingIP, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "IP\tRegion\tDroplet")
	for _, ip := range list {
		var droplet string
		if ip.Droplet != nil {
			droplet = fmt.Sprintf("%d", ip.Droplet.ID)
		}
		fmt.Fprintf(w, "%s\t%s\t%s\n", ip.IP, ip.Region.Slug, droplet)
	}

	fmt.Fprintln(w)
	w.Flush()
}

func outputImages(list []godo.Image, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tType\tDistribution\tSlug\tPublic\tMin Disk")

	for _, i := range list {
		publicStatus := false
		if i.Public {
			publicStatus = true
		}

		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%d\n",
			i.ID, i.Name, i.Type, i.Distribution, i.Slug, publicStatus, i.MinDiskSize)

	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputKernels(list []godo.Kernel, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tVersion")

	for _, k := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n", k.ID, k.Name, k.Version)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputRegions(list []godo.Region, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tName\tAvailable")

	for _, r := range list {
		fmt.Fprintf(w, "%s\t%s\t%t\n", r.Slug, r.Name, r.Available)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSizes(list []godo.Size, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tMemory\tVcpus\tDisk\tPrice Monthly\tPrice Hourly")

	for _, s := range list {
		fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%0.2f\t%f\n",
			s.Slug, s.Memory, s.Vcpus, s.Disk, s.PriceMonthly, s.PriceHourly)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSSHKeys(list []godo.Key, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tFingerprint")

	for _, s := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n",
			s.ID, s.Name, s.Fingerprint)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputZone(domain *godo.Domain, out io.Writer) {
	fmt.Fprintln(out, domain.ZoneFile)
}

func outputDomains(list []godo.Domain, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Name")

	for _, d := range list {
		fmt.Fprintf(w, "%s\n", d.Name)
	}

	fmt.Fprintln(w)
	w.Flush()
}

func outputRecords(list []godo.DomainRecord, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tType\tName\tData\tPriority\tPort\tWeight")

	for _, d := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%d\t%d\n", d.ID, d.Type, d.Name, d.Data,
			d.Priority, d.Port, d.Weight)
	}

	fmt.Fprintln(w)
	w.Flush()
}
<|endoftext|>


<commit_before>package progress

import (
	"image/color"
	"io"
	"strconv"

	"github.com/MJKWoolnough/gopherjs/xjs"

	"honnef.co/go/js/dom"
)

type ProgressBar struct {
	*dom.HTMLCanvasElement
	percent                int
	ctx                    *dom.CanvasRenderingContext2D
	width, height          int
	foreground, background string
}

func (p *ProgressBar) Percent(i int) {
	p.percent = i
	p.draw()
}

func (p *ProgressBar) draw() {
	p.ctx.FillStyle = p.background
	p.ctx.FillRect(0, 0, p.width, p.height)
	p.ctx.FillStyle = p.foreground
	p.ctx.FillRect(0, 0, p.width*p.percent/100, p.height)
}

func New(fore, back color.Color, width, height int) *ProgressBar {
	c := xjs.CreateElement("canvas").(*dom.HTMLCanvasElement)
	c.SetAttribute("width", strconv.Itoa(width))
	c.SetAttribute("height", strconv.Itoa(height))
	r, g, b, _ := fore.RGBA()
	foreground := "rgb(" + strconv.Itoa(int(r>>8)) + ", " + strconv.Itoa(int(g>>8)) + ", " + strconv.Itoa(int(b>>8)) + ")"
	r, g, b, _ = back.RGBA()
	background := "rgb(" + strconv.Itoa(int(r>>8)) + ", " + strconv.Itoa(int(g>>8)) + ", " + strconv.Itoa(int(b>>8)) + ")"
	pb := &ProgressBar{
		HTMLCanvasElement: c,
		ctx:               c.GetContext2d(),
		width:             width,
		height:            height,
		foreground:        foreground,
		background:        background,
	}
	pb.draw()
	return pb
}

type ProgressReader struct {
	*ProgressBar
	io.Reader
	offset, size int
}

func (p *ProgressBar) Reader(r io.Reader, size int) *ProgressReader {
	return &ProgressReader{p, r, 0, size}
}

func (pr *ProgressReader) Read(p []byte) (int, error) {
	n, err := pr.Reader.Read(p)
	pr.offset += n
	pr.Percent(100 * pr.offset / pr.size)
	return n, err
}
<commit_msg>Used uint64 to get around overflow bug<commit_after>package progress

import (
	"image/color"
	"io"
	"strconv"

	"github.com/MJKWoolnough/gopherjs/xjs"

	"honnef.co/go/js/dom"
)

type ProgressBar struct {
	*dom.HTMLCanvasElement
	percent                int
	ctx                    *dom.CanvasRenderingContext2D
	width, height          int
	foreground, background string
}

func (p *ProgressBar) Percent(i int) {
	if i != p.percent {
		p.percent = i
		p.draw()
	}
}

func (p *ProgressBar) draw() {
	p.ctx.FillStyle = p.background
	p.ctx.FillRect(0, 0, p.width, p.height)
	p.ctx.FillStyle = p.foreground
	p.ctx.FillRect(0, 0, p.width*p.percent/100, p.height)
}

func New(fore, back color.Color, width, height int) *ProgressBar {
	c := xjs.CreateElement("canvas").(*dom.HTMLCanvasElement)
	c.SetAttribute("width", strconv.Itoa(width))
	c.SetAttribute("height", strconv.Itoa(height))
	r, g, b, _ := fore.RGBA()
	foreground := "rgb(" + strconv.Itoa(int(r>>8)) + ", " + strconv.Itoa(int(g>>8)) + ", " + strconv.Itoa(int(b>>8)) + ")"
	r, g, b, _ = back.RGBA()
	background := "rgb(" + strconv.Itoa(int(r>>8)) + ", " + strconv.Itoa(int(g>>8)) + ", " + strconv.Itoa(int(b>>8)) + ")"
	pb := &ProgressBar{
		HTMLCanvasElement: c,
		ctx:               c.GetContext2d(),
		width:             width,
		height:            height,
		foreground:        foreground,
		background:        background,
	}
	pb.draw()
	return pb
}

type ProgressReader struct {
	*ProgressBar
	io.Reader
	offset, size uint64
}

func (p *ProgressBar) Reader(r io.Reader, size int) *ProgressReader {
	return &ProgressReader{p, r, 0, uint64(size)}
}

func (pr *ProgressReader) Read(p []byte) (int, error) {
	n, err := pr.Reader.Read(p)
	pr.offset += n
	pr.Percent(int(100 * pr.offset / pr.size))
	return n, err
}
<|endoftext|>