<commit_before>package readahead_test

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"

	"fmt"

	"github.com/klauspost/readahead"
)

func TestReader(t *testing.T) {
	buf := bytes.NewBufferString("Testbuffer")
	ar, err := readahead.NewReaderSize(buf, 4, 10000)
	if err != nil {
		t.Fatal("error when creating:", err)
	}

	var dst = make([]byte, 100)
	n, err := ar.Read(dst)
	if err != nil {
		t.Fatal("error when reading:", err)
	}
	if n != 10 {
		t.Fatal("unexpected length, expected 10, got ", n)
	}

	n, err = ar.Read(dst)
	if err != io.EOF {
		t.Fatal("expected io.EOF, got", err)
	}
	if n != 0 {
		t.Fatal("unexpected length, expected 0, got ", n)
	}

	// Test read after error
	n, err = ar.Read(dst)
	if err != io.EOF {
		t.Fatal("expected io.EOF, got", err)
	}
	if n != 0 {
		t.Fatal("unexpected length, expected 0, got ", n)
	}

	err = ar.Close()
	if err != nil {
		t.Fatal("error when closing:", err)
	}

	// Test Close without reading everything
	buf = bytes.NewBuffer(make([]byte, 50000))
	ar, err = readahead.NewReaderSize(buf, 4, 100)
	if err != nil {
		t.Fatal("error when creating:", err)
	}
	err = ar.Close()
	if err != nil {
		t.Fatal("error when closing:", err)
	}
}

func TestWriteTo(t *testing.T) {
	buf := bytes.NewBufferString("Testbuffer")
	ar, err := readahead.NewReaderSize(buf, 4, 10000)
	if err != nil {
		t.Fatal("error when creating:", err)
	}

	var dst = &bytes.Buffer{}
	n, err := io.Copy(dst, ar)
	if err != io.EOF {
		t.Fatal("error when reading:", err)
	}
	if n != 10 {
		t.Fatal("unexpected length, expected 10, got ", n)
	}

	// Should still return EOF
	n, err = io.Copy(dst, ar)
	if err != io.EOF {
		t.Fatal("expected io.EOF, got", err)
	}
	if n != 0 {
		t.Fatal("unexpected length, expected 0, got ", n)
	}

	err = ar.Close()
	if err != nil {
		t.Fatal("error when closing:", err)
	}
}

func TestNilReader(t *testing.T) {
	ar := readahead.NewReader(nil)
	if ar != nil {
		t.Fatalf("expected a nil, got %#v", ar)
	}
	buf := bytes.NewBufferString("Testbuffer")
	ar = readahead.NewReader(buf)
	if ar == nil {
		t.Fatalf("got nil when expecting object")
	}
}

func TestReaderErrors(t *testing.T) {
	// test nil reader
	_, err := readahead.NewReaderSize(nil, 4, 10000)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}

	// invalid buffer number
	buf := ioutil.NopCloser(bytes.NewBufferString("Testbuffer"))
	_, err = readahead.NewReaderSize(buf, 0, 10000)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}
	_, err = readahead.NewReaderSize(buf, -1, 10000)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}

	// invalid buffer size
	_, err = readahead.NewReaderSize(buf, 4, 0)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}
	_, err = readahead.NewReaderSize(buf, 4, -1)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}
}

// Complex read tests, leveraged from "bufio".

type readMaker struct {
	name string
	fn   func(io.Reader) io.Reader
}

var readMakers = []readMaker{
	{"full", func(r io.Reader) io.Reader { return r }},
	{"byte", iotest.OneByteReader},
	{"half", iotest.HalfReader},
	{"data+err", iotest.DataErrReader},
	{"timeout", iotest.TimeoutReader},
}

// Call Read to accumulate the text of a file
func reads(buf io.Reader, m int) string {
	var b [1000]byte
	nb := 0
	for {
		n, err := buf.Read(b[nb : nb+m])
		nb += n
		if err == io.EOF {
			break
		} else if err != nil && err != iotest.ErrTimeout {
			panic("Data: " + err.Error())
		} else if err != nil {
			break
		}
	}
	return string(b[0:nb])
}

type bufReader struct {
	name string
	fn   func(io.Reader) string
}

var bufreaders = []bufReader{
	{"1", func(b io.Reader) string { return reads(b, 1) }},
	{"2", func(b io.Reader) string { return reads(b, 2) }},
	{"3", func(b io.Reader) string { return reads(b, 3) }},
	{"4", func(b io.Reader) string { return reads(b, 4) }},
	{"5", func(b io.Reader) string { return reads(b, 5) }},
	{"7", func(b io.Reader) string { return reads(b, 7) }},
}

const minReadBufferSize = 16

var bufsizes = []int{
	0, minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
}

// Test various  input buffer sizes, number of buffers and read sizes.
func TestReaderSizes(t *testing.T) {
	var texts [31]string
	str := ""
	all := ""
	for i := 0; i < len(texts)-1; i++ {
		texts[i] = str + "\n"
		all += texts[i]
		str += string(i%26 + 'a')
	}
	texts[len(texts)-1] = all

	for h := 0; h < len(texts); h++ {
		text := texts[h]
		for i := 0; i < len(readMakers); i++ {
			for j := 0; j < len(bufreaders); j++ {
				for k := 0; k < len(bufsizes); k++ {
					for l := 1; l < 10; l++ {
						readmaker := readMakers[i]
						bufreader := bufreaders[j]
						bufsize := bufsizes[k]
						read := readmaker.fn(strings.NewReader(text))
						buf := bufio.NewReaderSize(read, bufsize)
						ar, _ := readahead.NewReaderSize(buf, l, 100)
						s := bufreader.fn(ar)
						// "timeout" expects the Reader to recover, asyncReader does not.
						if s != text && readmaker.name != "timeout" {
							t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
								readmaker.name, bufreader.name, bufsize, text, s)
						}
						err := ar.Close()
						if err != nil {
							t.Fatal("Unexpected close error:", err)
						}
					}
				}
			}
		}
	}
}

// Test various input buffer sizes, number of buffers and read sizes.
func TestReaderWriteTo(t *testing.T) {
	var texts [31]string
	str := ""
	all := ""
	for i := 0; i < len(texts)-1; i++ {
		texts[i] = str + "\n"
		all += texts[i]
		str += string(i%26 + 'a')
	}
	texts[len(texts)-1] = all

	for h := 0; h < len(texts); h++ {
		text := texts[h]
		for i := 0; i < len(readMakers); i++ {
			for j := 0; j < len(bufreaders); j++ {
				for k := 0; k < len(bufsizes); k++ {
					for l := 1; l < 10; l++ {
						readmaker := readMakers[i]
						bufreader := bufreaders[j]
						bufsize := bufsizes[k]
						read := readmaker.fn(strings.NewReader(text))
						buf := bufio.NewReaderSize(read, bufsize)
						ar, _ := readahead.NewReaderSize(buf, l, 100)
						dst := &bytes.Buffer{}
						wt := ar.(io.WriterTo)
						_, err := wt.WriteTo(dst)
						if err != nil && err != io.EOF && err != iotest.ErrTimeout {
							t.Fatal("Copy:", err)
						}
						s := dst.String()
						// "timeout" expects the Reader to recover, asyncReader does not.
						if s != text && readmaker.name != "timeout" {
							t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
								readmaker.name, bufreader.name, bufsize, text, s)
						}
						err = ar.Close()
						if err != nil {
							t.Fatal("Unexpected close error:", err)
						}
					}
				}
			}
		}
	}
}

func ExampleReader() {
	// Buf is our input.
	buf := bytes.NewBufferString("Example data")

	// Create a Reader with default settings
	reader := readahead.NewReader(buf)
	defer reader.Close()

	// Copy the content to dst
	var dst = &bytes.Buffer{}
	_, err := io.Copy(dst, reader)
	if err != io.EOF {
		panic("error when reading: " + err.Error())
	}

	fmt.Println(dst.String())
	// OUTPUT: Example data
}
<commit_msg>Make package example.<commit_after>package readahead_test

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"

	"fmt"

	"github.com/klauspost/readahead"
)

func TestReader(t *testing.T) {
	buf := bytes.NewBufferString("Testbuffer")
	ar, err := readahead.NewReaderSize(buf, 4, 10000)
	if err != nil {
		t.Fatal("error when creating:", err)
	}

	var dst = make([]byte, 100)
	n, err := ar.Read(dst)
	if err != nil {
		t.Fatal("error when reading:", err)
	}
	if n != 10 {
		t.Fatal("unexpected length, expected 10, got ", n)
	}

	n, err = ar.Read(dst)
	if err != io.EOF {
		t.Fatal("expected io.EOF, got", err)
	}
	if n != 0 {
		t.Fatal("unexpected length, expected 0, got ", n)
	}

	// Test read after error
	n, err = ar.Read(dst)
	if err != io.EOF {
		t.Fatal("expected io.EOF, got", err)
	}
	if n != 0 {
		t.Fatal("unexpected length, expected 0, got ", n)
	}

	err = ar.Close()
	if err != nil {
		t.Fatal("error when closing:", err)
	}

	// Test Close without reading everything
	buf = bytes.NewBuffer(make([]byte, 50000))
	ar, err = readahead.NewReaderSize(buf, 4, 100)
	if err != nil {
		t.Fatal("error when creating:", err)
	}
	err = ar.Close()
	if err != nil {
		t.Fatal("error when closing:", err)
	}
}

func TestWriteTo(t *testing.T) {
	buf := bytes.NewBufferString("Testbuffer")
	ar, err := readahead.NewReaderSize(buf, 4, 10000)
	if err != nil {
		t.Fatal("error when creating:", err)
	}

	var dst = &bytes.Buffer{}
	n, err := io.Copy(dst, ar)
	if err != io.EOF {
		t.Fatal("error when reading:", err)
	}
	if n != 10 {
		t.Fatal("unexpected length, expected 10, got ", n)
	}

	// Should still return EOF
	n, err = io.Copy(dst, ar)
	if err != io.EOF {
		t.Fatal("expected io.EOF, got", err)
	}
	if n != 0 {
		t.Fatal("unexpected length, expected 0, got ", n)
	}

	err = ar.Close()
	if err != nil {
		t.Fatal("error when closing:", err)
	}
}

func TestNilReader(t *testing.T) {
	ar := readahead.NewReader(nil)
	if ar != nil {
		t.Fatalf("expected a nil, got %#v", ar)
	}
	buf := bytes.NewBufferString("Testbuffer")
	ar = readahead.NewReader(buf)
	if ar == nil {
		t.Fatalf("got nil when expecting object")
	}
}

func TestReaderErrors(t *testing.T) {
	// test nil reader
	_, err := readahead.NewReaderSize(nil, 4, 10000)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}

	// invalid buffer number
	buf := ioutil.NopCloser(bytes.NewBufferString("Testbuffer"))
	_, err = readahead.NewReaderSize(buf, 0, 10000)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}
	_, err = readahead.NewReaderSize(buf, -1, 10000)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}

	// invalid buffer size
	_, err = readahead.NewReaderSize(buf, 4, 0)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}
	_, err = readahead.NewReaderSize(buf, 4, -1)
	if err == nil {
		t.Fatal("expected error when creating, but got nil")
	}
}

// Complex read tests, leveraged from "bufio".

type readMaker struct {
	name string
	fn   func(io.Reader) io.Reader
}

var readMakers = []readMaker{
	{"full", func(r io.Reader) io.Reader { return r }},
	{"byte", iotest.OneByteReader},
	{"half", iotest.HalfReader},
	{"data+err", iotest.DataErrReader},
	{"timeout", iotest.TimeoutReader},
}

// Call Read to accumulate the text of a file
func reads(buf io.Reader, m int) string {
	var b [1000]byte
	nb := 0
	for {
		n, err := buf.Read(b[nb : nb+m])
		nb += n
		if err == io.EOF {
			break
		} else if err != nil && err != iotest.ErrTimeout {
			panic("Data: " + err.Error())
		} else if err != nil {
			break
		}
	}
	return string(b[0:nb])
}

type bufReader struct {
	name string
	fn   func(io.Reader) string
}

var bufreaders = []bufReader{
	{"1", func(b io.Reader) string { return reads(b, 1) }},
	{"2", func(b io.Reader) string { return reads(b, 2) }},
	{"3", func(b io.Reader) string { return reads(b, 3) }},
	{"4", func(b io.Reader) string { return reads(b, 4) }},
	{"5", func(b io.Reader) string { return reads(b, 5) }},
	{"7", func(b io.Reader) string { return reads(b, 7) }},
}

const minReadBufferSize = 16

var bufsizes = []int{
	0, minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
}

// Test various  input buffer sizes, number of buffers and read sizes.
func TestReaderSizes(t *testing.T) {
	var texts [31]string
	str := ""
	all := ""
	for i := 0; i < len(texts)-1; i++ {
		texts[i] = str + "\n"
		all += texts[i]
		str += string(i%26 + 'a')
	}
	texts[len(texts)-1] = all

	for h := 0; h < len(texts); h++ {
		text := texts[h]
		for i := 0; i < len(readMakers); i++ {
			for j := 0; j < len(bufreaders); j++ {
				for k := 0; k < len(bufsizes); k++ {
					for l := 1; l < 10; l++ {
						readmaker := readMakers[i]
						bufreader := bufreaders[j]
						bufsize := bufsizes[k]
						read := readmaker.fn(strings.NewReader(text))
						buf := bufio.NewReaderSize(read, bufsize)
						ar, _ := readahead.NewReaderSize(buf, l, 100)
						s := bufreader.fn(ar)
						// "timeout" expects the Reader to recover, asyncReader does not.
						if s != text && readmaker.name != "timeout" {
							t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
								readmaker.name, bufreader.name, bufsize, text, s)
						}
						err := ar.Close()
						if err != nil {
							t.Fatal("Unexpected close error:", err)
						}
					}
				}
			}
		}
	}
}

// Test various input buffer sizes, number of buffers and read sizes.
func TestReaderWriteTo(t *testing.T) {
	var texts [31]string
	str := ""
	all := ""
	for i := 0; i < len(texts)-1; i++ {
		texts[i] = str + "\n"
		all += texts[i]
		str += string(i%26 + 'a')
	}
	texts[len(texts)-1] = all

	for h := 0; h < len(texts); h++ {
		text := texts[h]
		for i := 0; i < len(readMakers); i++ {
			for j := 0; j < len(bufreaders); j++ {
				for k := 0; k < len(bufsizes); k++ {
					for l := 1; l < 10; l++ {
						readmaker := readMakers[i]
						bufreader := bufreaders[j]
						bufsize := bufsizes[k]
						read := readmaker.fn(strings.NewReader(text))
						buf := bufio.NewReaderSize(read, bufsize)
						ar, _ := readahead.NewReaderSize(buf, l, 100)
						dst := &bytes.Buffer{}
						wt := ar.(io.WriterTo)
						_, err := wt.WriteTo(dst)
						if err != nil && err != io.EOF && err != iotest.ErrTimeout {
							t.Fatal("Copy:", err)
						}
						s := dst.String()
						// "timeout" expects the Reader to recover, asyncReader does not.
						if s != text && readmaker.name != "timeout" {
							t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
								readmaker.name, bufreader.name, bufsize, text, s)
						}
						err = ar.Close()
						if err != nil {
							t.Fatal("Unexpected close error:", err)
						}
					}
				}
			}
		}
	}
}

func Example() {
	// Buf is our input.
	buf := bytes.NewBufferString("Example data")

	// Create a Reader with default settings
	reader := readahead.NewReader(buf)
	defer reader.Close()

	// Copy the content to dst
	var dst = &bytes.Buffer{}
	_, err := io.Copy(dst, reader)
	if err != io.EOF {
		panic("error when reading: " + err.Error())
	}

	fmt.Println(dst.String())
	// Output: Example data
}
<|endoftext|>


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

package yacr_test

import (
	"reflect"
	"strings"
	"testing"
	. "github.com/gwenn/yacr"
)

func makeReader(s string, quoted bool) *Reader {
	return NewReader(strings.NewReader(s), ',', quoted, false)
}

func readRow(r *Reader) []string {
	row := make([]string, 0, 10)
	for r.Scan() {
		if r.EmptyLine() { // skip empty line (or line comment)
			continue
		}
		row = append(row, r.Text())
		if r.EndOfRecord() {
			break
		}
	}
	return row
}

func checkValueCount(t *testing.T, expected int, values []string) {
	if len(values) != expected {
		t.Errorf("got %d value(s) (%#v); want %d", len(values), values, expected)
	}
}

func checkNoError(t *testing.T, e error) {
	if e != nil {
		t.Fatal(e)
	}
}

func checkEquals(t *testing.T, expected, actual []string) {
	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("got %#v; want %#v", actual, expected)
	}
}

func TestSingleValue(t *testing.T) {
	expected := "Foo"
	r := makeReader(expected, true)
	ok := r.Scan()
	if !ok {
		t.Error("expected one value")
	}
	checkNoError(t, r.Err())
	if expected != r.Text() {
		t.Errorf("Got: %q; want: %q", r.Text(), expected)
	}
	ok = r.Scan()
	if ok {
		t.Error("expected no value")
	}
	checkNoError(t, r.Err())
	/*if len(r.Text()) != 0 {
		t.Errorf("expected no value, got: %q", r.Text())
	}*/
}

func TestTwoValues(t *testing.T) {
	r := makeReader("Foo,Bar", true)
	ok := r.Scan()
	if !ok {
		t.Error("expected one value")
	}
	checkNoError(t, r.Err())
	if "Foo" != r.Text() {
		t.Errorf("got: %q; want: %q", r.Text(), "Foo")
	}
	ok = r.Scan()
	if !ok {
		t.Error("expected another value")
	}
	checkNoError(t, r.Err())
	if "Bar" != r.Text() {
		t.Errorf("got: %q; want: %q", r.Text(), "Bar")
	}
	ok = r.Scan()
	if ok {
		t.Error("expected no value")
	}
	checkNoError(t, r.Err())
	/*if len(r.Text()) != 0 {
		t.Errorf("expected no value, got: %q", r.Text())
	}*/
}

func TestLastEmpty(t *testing.T) {
	r := makeReader("Foo,Bar,\n", true)
	n := 0
	for r.Scan() {
		n++
		if r.EndOfRecord() {
			break
		}
	}
	if n != 3 {
		t.Errorf("got %d values; want %d", n, 3)
	}
	checkNoError(t, r.Err())
}

func TestTwoLines(t *testing.T) {
	row1 := strings.Repeat("1,2,3,4,5,6,7,8,9,10,", 5)
	row2 := strings.Repeat("a,b,c,d,e,f,g,h,i,j,", 3)
	content := strings.Join([]string{row1, row2}, "\n")
	r := makeReader(content, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 51, values)
	values = readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 31, values)
}

func TestLongLine(t *testing.T) {
	content := strings.Repeat("1,2,3,4,5,6,7,8,9,10,", 200)
	r := makeReader(content, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 2001, values)
}

func TestQuotedLine(t *testing.T) {
	r := makeReader("\"a\",b,\"c,d\"", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
	expected := []string{"a", "b", "c,d"}
	checkEquals(t, expected, values)
}

func TestEscapedQuoteLine(t *testing.T) {
	r := makeReader(`"a",b,"c""d"`, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
	expected := []string{"a", "b", "c\"d"}
	checkEquals(t, expected, values)
}

func TestEmbeddedNewline(t *testing.T) {
	r := makeReader("a,\"b\nb\",\"c\n\n\",d", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 4, values)
	expected := []string{"a", "b\nb", "c\n\n", "d"}
	checkEquals(t, expected, values)
}

func TestEscapedQuoteAndEmbeddedNewLine(t *testing.T) {
	r := makeReader("\"a\"\"b\",\"c\"\"\r\nd\"", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 2, values)
	expected := []string{"a\"b", "c\"\r\nd"}
	checkEquals(t, expected, values)
}

func TestGuess(t *testing.T) {
	r := NewReader(strings.NewReader("a,b;c\td:e|f;g"), ',', true, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	if ';' != r.Sep() {
		t.Errorf("got '%q'; want '%q'", r.Sep(), ';')
	}
	checkValueCount(t, 3, values)
	expected := []string{"a,b", "c\td:e|f", "g"}
	checkEquals(t, expected, values)
}

func TestTrim(t *testing.T) {
	r := makeReader(` a,b ," c ", d `, true)
	r.Trim = true
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 4, values)
	expected := []string{"a", "b", " c ", "d"}
	checkEquals(t, expected, values)
}

func TestLineComment(t *testing.T) {
	r := makeReader("a,#\n# comment\nb\n# comment", true)
	r.Comment = '#'
	values := readRow(r)
	checkNoError(t, r.Err())
	checkEquals(t, []string{"a", "#"}, values)
	values = readRow(r)
	checkNoError(t, r.Err())
	checkEquals(t, []string{"b"}, values)
	if r.Scan() {
		t.Error("expected no value")
	}
	checkNoError(t, r.Err())
}

func TestEmptyLine(t *testing.T) {
	r := makeReader("a,b,c\n\nd,e,f", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
	values = readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
}
<commit_msg>Improve tests coverage.<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package yacr_test

import (
	"reflect"
	"strings"
	"testing"
	. "github.com/gwenn/yacr"
)

func makeReader(s string, quoted bool) *Reader {
	return NewReader(strings.NewReader(s), ',', quoted, false)
}

func readRow(r *Reader) []string {
	row := make([]string, 0, 10)
	for r.Scan() {
		if r.EmptyLine() { // skip empty line (or line comment)
			continue
		}
		row = append(row, r.Text())
		if r.EndOfRecord() {
			break
		}
	}
	return row
}

func checkValueCount(t *testing.T, expected int, values []string) {
	if len(values) != expected {
		t.Errorf("got %d value(s) (%#v); want %d", len(values), values, expected)
	}
}

func checkNoError(t *testing.T, e error) {
	if e != nil {
		t.Fatal(e)
	}
}

func checkEquals(t *testing.T, expected, actual []string) {
	if !reflect.DeepEqual(expected, actual) {
		t.Errorf("got %#v; want %#v", actual, expected)
	}
}

func TestSingleValue(t *testing.T) {
	expected := "Foo"
	r := makeReader(expected, true)
	ok := r.Scan()
	if !ok {
		t.Error("expected one value")
	}
	checkNoError(t, r.Err())
	if expected != r.Text() {
		t.Errorf("Got: %q; want: %q", r.Text(), expected)
	}
	ok = r.Scan()
	if ok {
		t.Error("expected no value")
	}
	checkNoError(t, r.Err())
	/*if len(r.Text()) != 0 {
		t.Errorf("expected no value, got: %q", r.Text())
	}*/
}

func TestTwoValues(t *testing.T) {
	r := makeReader("Foo,Bar", true)
	ok := r.Scan()
	if !ok {
		t.Error("expected one value")
	}
	checkNoError(t, r.Err())
	if "Foo" != r.Text() {
		t.Errorf("got: %q; want: %q", r.Text(), "Foo")
	}
	ok = r.Scan()
	if !ok {
		t.Error("expected another value")
	}
	checkNoError(t, r.Err())
	if "Bar" != r.Text() {
		t.Errorf("got: %q; want: %q", r.Text(), "Bar")
	}
	ok = r.Scan()
	if ok {
		t.Error("expected no value")
	}
	checkNoError(t, r.Err())
	/*if len(r.Text()) != 0 {
		t.Errorf("expected no value, got: %q", r.Text())
	}*/
}

func TestLastEmpty(t *testing.T) {
	r := makeReader("Foo,Bar,\n", true)
	n := 0
	for r.Scan() {
		n++
		if r.EndOfRecord() {
			break
		}
	}
	if n != 3 {
		t.Errorf("got %d values; want %d", n, 3)
	}
	checkNoError(t, r.Err())
}

func TestTwoLines(t *testing.T) {
	row1 := strings.Repeat("1,2,3,4,5,6,7,8,9,10,", 5)
	row2 := strings.Repeat("a,b,c,d,e,f,g,h,i,j,", 3)
	content := strings.Join([]string{row1, row2}, "\n")
	r := makeReader(content, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 51, values)
	values = readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 31, values)
}

func TestLongLine(t *testing.T) {
	content := strings.Repeat("1,2,3,4,5,6,7,8,9,10,", 200)
	r := makeReader(content, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 2001, values)
}

func TestQuotedLine(t *testing.T) {
	r := makeReader("\"a\",b,\"c,d\"", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
	expected := []string{"a", "b", "c,d"}
	checkEquals(t, expected, values)
}

func TestEscapedQuoteLine(t *testing.T) {
	r := makeReader(`"a",b,"c""d"`, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
	expected := []string{"a", "b", "c\"d"}
	checkEquals(t, expected, values)
}

func TestEmbeddedNewline(t *testing.T) {
	r := makeReader("a,\"b\nb\",\"c\n\n\",d", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 4, values)
	expected := []string{"a", "b\nb", "c\n\n", "d"}
	checkEquals(t, expected, values)
}

func TestEscapedQuoteAndEmbeddedNewLine(t *testing.T) {
	r := makeReader("\"a\"\"b\",\"c\"\"\r\nd\"", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 2, values)
	expected := []string{"a\"b", "c\"\r\nd"}
	checkEquals(t, expected, values)
}

func TestGuess(t *testing.T) {
	r := NewReader(strings.NewReader("a,b;c\td:e|f;g"), ',', true, true)
	values := readRow(r)
	checkNoError(t, r.Err())
	if ';' != r.Sep() {
		t.Errorf("got '%q'; want '%q'", r.Sep(), ';')
	}
	checkValueCount(t, 3, values)
	expected := []string{"a,b", "c\td:e|f", "g"}
	checkEquals(t, expected, values)
}

func TestTrim(t *testing.T) {
	r := makeReader(` a,b ," c ", d `, true)
	r.Trim = true
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 4, values)
	expected := []string{"a", "b", " c ", "d"}
	checkEquals(t, expected, values)
}

func TestLineComment(t *testing.T) {
	r := makeReader("a,#\n# comment\nb\n# comment", true)
	r.Comment = '#'
	values := readRow(r)
	checkNoError(t, r.Err())
	checkEquals(t, []string{"a", "#"}, values)
	values = readRow(r)
	checkNoError(t, r.Err())
	checkEquals(t, []string{"b"}, values)
	if r.Scan() {
		t.Error("expected no value")
	}
	checkNoError(t, r.Err())
}

func TestEmptyLine(t *testing.T) {
	r := makeReader("a,b,\"c\"\n\nd,e,f", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
	values = readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
}

func TestWindowsEndOfLine(t *testing.T) {
	r := makeReader("a,b,c\r\nd,e,\"f\"\r\n", true)
	values := readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
	values = readRow(r)
	checkNoError(t, r.Err())
	checkValueCount(t, 3, values)
}
<|endoftext|>


<commit_before>package phases

import (
	"fmt"
	"net/http"
	"time"

	"github.com/Everlane/evan/common"
	"github.com/Everlane/evan/heroku"
)

type HerokuBuildPhase struct {
	Client *heroku.Client
	AppId  string
}

type HerokuBuildPhaseContext struct {
	TarballUrl string
}

func (hbp *HerokuBuildPhase) CanPreload() bool {
	return true
}

func (hbp *HerokuBuildPhase) Preload(deployment common.Deployment) (interface{}, error) {
	githubRepo := common.NewGithubRepositoryFromDeployment(deployment)
	tarballUrl, err := githubRepo.GetArchiveLink(common.Tarball)
	if err != nil {
		return nil, err
	}

	return &HerokuBuildPhaseContext{
		TarballUrl: tarballUrl,
	}, nil
}

func (hbp *HerokuBuildPhase) Execute(deployment common.Deployment, data interface{}) error {
	context := data.(*HerokuBuildPhaseContext)

	build, err := hbp.createBuild(deployment, context)
	if err != nil {
		return err
	}

	build, err = hbp.PollBuildStatus(build)
	if err != nil {
		return err
	}
	if build.Status == "failed" {
		return fmt.Errorf("Build %v failed", build.Id)
	}

	// Heroku will have automatically deployed that new build as a release, so
	// we can consider this phase done.
	return nil
}

func (hbp *HerokuBuildPhase) createBuild(deployment common.Deployment, context *HerokuBuildPhaseContext) (*heroku.Build, error) {
	build, resp, err := hbp.Client.BuildCreate(hbp.AppId, &heroku.SourceBlob{
		Url:     context.TarballUrl,
		Version: deployment.Ref(),
	})
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusCreated {
		fmt.Printf("Received error from Heroku when creating build: %v\n", resp)
		return nil, fmt.Errorf("Non-creation status code (expected %v, got %v)", http.StatusCreated, resp.StatusCode)
	}

	return build, nil
}

func (hbp *HerokuBuildPhase) PollBuildStatus(sourceBuild *heroku.Build) (*heroku.Build, error) {
	for true {
		build, _, err := hbp.Client.BuildInfo(hbp.AppId, sourceBuild.Id)
		if err != nil {
			return nil, err
		}

		if build.Status == "pending" {
			time.Sleep(10 * time.Second)
			continue
		}

		return build, nil
	}

	panic("Unreachable!")
}
<commit_msg>Allow setting Heroku Platform API token to be used through build flags<commit_after>package phases

import (
	"fmt"
	"net/http"
	"time"

	"github.com/Everlane/evan/common"
	"github.com/Everlane/evan/heroku"
)

const TOKEN_FLAG string = "heroku.token"

type HerokuBuildPhase struct {
	// Will use this client if no client is passed through build flags.
	DefaultClient *heroku.Client
	AppId         string
}

type HerokuBuildPhaseContext struct {
	Client     *heroku.Client
	TarballUrl string
}

func (hbp *HerokuBuildPhase) CanPreload() bool {
	return true
}

func (hbp *HerokuBuildPhase) Preload(deployment common.Deployment) (interface{}, error) {
	client := hbp.DefaultClient
	if deployment.HasFlag(TOKEN_FLAG) {
		token := deployment.Flag(TOKEN_FLAG).(string)
		client = heroku.NewClient(token)
	}
	if client == nil {
		return nil, fmt.Errorf("No Heroku Platform API client found")
	}

	githubRepo := common.NewGithubRepositoryFromDeployment(deployment)
	tarballUrl, err := githubRepo.GetArchiveLink(common.Tarball)
	if err != nil {
		return nil, err
	}

	return &HerokuBuildPhaseContext{
		TarballUrl: tarballUrl,
		Client:     client,
	}, nil
}

func (hbp *HerokuBuildPhase) Execute(deployment common.Deployment, data interface{}) error {
	context := data.(*HerokuBuildPhaseContext)

	build, err := hbp.createBuild(deployment, context)
	if err != nil {
		return err
	}

	build, err = hbp.PollBuildStatus(build, context)
	if err != nil {
		return err
	}
	if build.Status == "failed" {
		return fmt.Errorf("Build %v failed", build.Id)
	}

	// Heroku will have automatically deployed that new build as a release, so
	// we can consider this phase done.
	return nil
}

func (hbp *HerokuBuildPhase) createBuild(deployment common.Deployment, context *HerokuBuildPhaseContext) (*heroku.Build, error) {
	build, resp, err := context.Client.BuildCreate(hbp.AppId, &heroku.SourceBlob{
		Url:     context.TarballUrl,
		Version: deployment.Ref(),
	})
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusCreated {
		fmt.Printf("Received error from Heroku when creating build: %v\n", resp)
		return nil, fmt.Errorf("Non-creation status code (expected %v, got %v)", http.StatusCreated, resp.StatusCode)
	}

	return build, nil
}

func (hbp *HerokuBuildPhase) PollBuildStatus(sourceBuild *heroku.Build, context *HerokuBuildPhaseContext) (*heroku.Build, error) {
	for true {
		build, _, err := context.Client.BuildInfo(hbp.AppId, sourceBuild.Id)
		if err != nil {
			return nil, err
		}

		if build.Status == "pending" {
			time.Sleep(10 * time.Second)
			continue
		}

		return build, nil
	}

	panic("Unreachable!")
}
<|endoftext|>


<commit_before><commit_msg>lntest/itest: resolve mempool flake in multi-hop htlc local timeout test<commit_after><|endoftext|>


<commit_before>package resources

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

	"github.com/pkg/errors"

	"github.com/lxc/lxd/shared/api"
)

var sysClassBlock = "/sys/class/block"

// GetStorage returns a filled api.ResourcesStorage struct ready for use by LXD
func GetStorage() (*api.ResourcesStorage, error) {
	storage := api.ResourcesStorage{}
	storage.Disks = []api.ResourcesStorageDisk{}

	// Detect all block devices
	if sysfsExists(sysClassBlock) {
		entries, err := ioutil.ReadDir(sysClassBlock)
		if err != nil {
			return nil, errors.Wrapf(err, "Failed to list \"%s\"", sysClassBlock)
		}

		// Iterate and add to our list
		for _, entry := range entries {
			entryName := entry.Name()
			entryPath := filepath.Join(sysClassBlock, entryName)
			devicePath := filepath.Join(entryPath, "device")

			// Only keep the main entries not partitions
			if !sysfsExists(devicePath) {
				continue
			}

			// Setup the entry
			disk := api.ResourcesStorageDisk{}
			disk.ID = entryName

			// Device node
			diskDev, err := ioutil.ReadFile(filepath.Join(entryPath, "dev"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "dev"))
			}
			disk.Device = strings.TrimSpace(string(diskDev))

			// NUMA node
			if sysfsExists(filepath.Join(devicePath, "numa_node")) {
				numaNode, err := readInt(filepath.Join(devicePath, "numa_node"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "numa_node"))
				}

				if numaNode > 0 {
					disk.NUMANode = uint64(numaNode)
				}
			}

			// Disk model
			if sysfsExists(filepath.Join(devicePath, "model")) {
				diskModel, err := ioutil.ReadFile(filepath.Join(devicePath, "model"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "model"))
				}

				disk.Model = strings.TrimSpace(string(diskModel))
			}

			// Disk type
			if sysfsExists(filepath.Join(devicePath, "subsystem")) {
				diskSubsystem, err := filepath.EvalSymlinks(filepath.Join(devicePath, "subsystem"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to track down \"%s\"", filepath.Join(devicePath, "subsystem"))
				}

				disk.Type = filepath.Base(diskSubsystem)
			}

			// Read-only
			diskRo, err := readUint(filepath.Join(entryPath, "ro"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "ro"))
			}
			disk.ReadOnly = diskRo == 1

			// Size
			diskSize, err := readUint(filepath.Join(entryPath, "size"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "size"))
			}
			disk.Size = diskSize * 512

			// Removable
			diskRemovable, err := readUint(filepath.Join(entryPath, "removable"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "removable"))
			}
			disk.Removable = diskRemovable == 1

			// WWN
			if sysfsExists(filepath.Join(entryPath, "wwid")) {
				diskWWN, err := ioutil.ReadFile(filepath.Join(entryPath, "wwid"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "wwid"))
				}
				disk.WWN = strings.TrimSpace(string(diskWWN))
			}

			// Look for partitions
			disk.Partitions = []api.ResourcesStorageDiskPartition{}
			for _, subEntry := range entries {
				subEntryName := subEntry.Name()
				subEntryPath := filepath.Join(sysClassBlock, subEntryName)

				if !strings.HasPrefix(subEntryName, entryName) {
					continue
				}

				if !sysfsExists(filepath.Join(subEntryPath, "partition")) {
					continue
				}

				// Setup the entry
				partition := api.ResourcesStorageDiskPartition{}
				partition.ID = subEntryName

				// Parse the partition number
				partitionNumber, err := readUint(filepath.Join(subEntryPath, "partition"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "partition"))
				}
				partition.Partition = partitionNumber

				// Device node
				partitionDev, err := ioutil.ReadFile(filepath.Join(subEntryPath, "dev"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "dev"))
				}
				partition.Device = strings.TrimSpace(string(partitionDev))

				// Read-only
				partitionRo, err := readUint(filepath.Join(subEntryPath, "ro"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "ro"))
				}
				partition.ReadOnly = partitionRo == 1

				// Size
				partitionSize, err := readUint(filepath.Join(subEntryPath, "size"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "size"))
				}
				partition.Size = partitionSize * 512

				// Add to list
				disk.Partitions = append(disk.Partitions, partition)
			}

			// Add to list
			storage.Disks = append(storage.Disks, disk)
		}
	}

	storage.Total = 0
	for _, card := range storage.Disks {
		if storage.Disks != nil {
			storage.Total += uint64(len(card.Partitions))
		}

		storage.Total++
	}

	return &storage, nil
}
<commit_msg>lxd/resources: Add extra storage fields<commit_after>package resources

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/sys/unix"

	"github.com/lxc/lxd/shared/api"
)

var devDiskByPath = "/dev/disk/by-path"
var runUdevData = "/run/udev/data"
var sysClassBlock = "/sys/class/block"

func storageAddDriveInfo(devicePath string, disk *api.ResourcesStorageDisk) error {
	// Attempt to open the device path
	f, err := os.Open(devicePath)
	if err != nil {
		if !os.IsPermission(err) && !os.IsNotExist(err) {
			return err
		}
	} else {
		defer f.Close()
		fd := int(f.Fd())

		// Retrieve the block size
		res, err := unix.IoctlGetInt(fd, unix.BLKPBSZGET)
		if err != nil {
			return err
		}

		disk.BlockSize = uint64(res)
	}

	// Retrieve udev information
	udevInfo := filepath.Join(runUdevData, fmt.Sprintf("b%s", disk.Device))
	if sysfsExists(udevInfo) {
		// Get the udev information
		f, err := os.Open(udevInfo)
		if err != nil {
			return errors.Wrapf(err, "Failed to open \"%s\"", udevInfo)
		}
		defer f.Close()

		udevInfo := bufio.NewScanner(f)
		for udevInfo.Scan() {
			line := strings.TrimSpace(udevInfo.Text())

			if !strings.HasPrefix(line, "E:") {
				continue
			}

			fields := strings.SplitN(line, "=", 2)
			if len(fields) != 2 {
				continue
			}

			key := strings.TrimSpace(fields[0])
			value := strings.TrimSpace(fields[1])

			// Finer grained disk type
			if key == "E:ID_ATA_SATA" && value == "1" {
				disk.Type = "sata"
			}

			if key == "E:ID_USB_DRIVER" && value == "usb-storage" {
				disk.Type = "usb"
			}

			// Model revision number
			if key == "E:ID_REVISION" && disk.ModelRevision == "" {
				disk.ModelRevision = value
			}

			// Serial number
			if key == "E:ID_SERIAL_SHORT" && disk.Serial == "" {
				disk.Serial = value
			}

			// Rotation per minute
			if key == "E:ID_ATA_ROTATION_RATE_RPM" && disk.RPM == 0 {
				valueUint, err := strconv.ParseUint(value, 10, 64)
				if err != nil {
					return errors.Wrap(err, "Failed to parse RPM value")
				}

				disk.RPM = valueUint
			}
		}
	}

	return nil
}

// GetStorage returns a filled api.ResourcesStorage struct ready for use by LXD
func GetStorage() (*api.ResourcesStorage, error) {
	storage := api.ResourcesStorage{}
	storage.Disks = []api.ResourcesStorageDisk{}

	// Detect all block devices
	if sysfsExists(sysClassBlock) {
		entries, err := ioutil.ReadDir(sysClassBlock)
		if err != nil {
			return nil, errors.Wrapf(err, "Failed to list \"%s\"", sysClassBlock)
		}

		// Iterate and add to our list
		for _, entry := range entries {
			entryName := entry.Name()
			entryPath := filepath.Join(sysClassBlock, entryName)
			devicePath := filepath.Join(entryPath, "device")

			// Only keep the main entries not partitions
			if !sysfsExists(devicePath) {
				continue
			}

			// Setup the entry
			disk := api.ResourcesStorageDisk{}
			disk.ID = entryName

			// Firmware revision
			if sysfsExists(filepath.Join(devicePath, "firmware_rev")) {
				firmwareRevision, err := ioutil.ReadFile(filepath.Join(devicePath, "firmware_rev"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "firmware_rev"))
				}

				disk.FirmwareVersion = strings.TrimSpace(string(firmwareRevision))
			}

			// Device node
			diskDev, err := ioutil.ReadFile(filepath.Join(entryPath, "dev"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "dev"))
			}
			disk.Device = strings.TrimSpace(string(diskDev))

			// NUMA node
			if sysfsExists(filepath.Join(devicePath, "numa_node")) {
				numaNode, err := readInt(filepath.Join(devicePath, "numa_node"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "numa_node"))
				}

				if numaNode > 0 {
					disk.NUMANode = uint64(numaNode)
				}
			}

			// Disk model
			if sysfsExists(filepath.Join(devicePath, "model")) {
				diskModel, err := ioutil.ReadFile(filepath.Join(devicePath, "model"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "model"))
				}

				disk.Model = strings.TrimSpace(string(diskModel))
			}

			// Disk type
			if sysfsExists(filepath.Join(devicePath, "subsystem")) {
				diskSubsystem, err := filepath.EvalSymlinks(filepath.Join(devicePath, "subsystem"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to track down \"%s\"", filepath.Join(devicePath, "subsystem"))
				}

				disk.Type = filepath.Base(diskSubsystem)
			}

			// Read-only
			diskRo, err := readUint(filepath.Join(entryPath, "ro"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "ro"))
			}
			disk.ReadOnly = diskRo == 1

			// Size
			diskSize, err := readUint(filepath.Join(entryPath, "size"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "size"))
			}
			disk.Size = diskSize * 512

			// Removable
			diskRemovable, err := readUint(filepath.Join(entryPath, "removable"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "removable"))
			}
			disk.Removable = diskRemovable == 1

			// WWN
			if sysfsExists(filepath.Join(entryPath, "wwid")) {
				diskWWN, err := ioutil.ReadFile(filepath.Join(entryPath, "wwid"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "wwid"))
				}
				disk.WWN = strings.TrimSpace(string(diskWWN))
			}

			// Look for partitions
			disk.Partitions = []api.ResourcesStorageDiskPartition{}
			for _, subEntry := range entries {
				subEntryName := subEntry.Name()
				subEntryPath := filepath.Join(sysClassBlock, subEntryName)

				if !strings.HasPrefix(subEntryName, entryName) {
					continue
				}

				if !sysfsExists(filepath.Join(subEntryPath, "partition")) {
					continue
				}

				// Setup the entry
				partition := api.ResourcesStorageDiskPartition{}
				partition.ID = subEntryName

				// Parse the partition number
				partitionNumber, err := readUint(filepath.Join(subEntryPath, "partition"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "partition"))
				}
				partition.Partition = partitionNumber

				// Device node
				partitionDev, err := ioutil.ReadFile(filepath.Join(subEntryPath, "dev"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "dev"))
				}
				partition.Device = strings.TrimSpace(string(partitionDev))

				// Read-only
				partitionRo, err := readUint(filepath.Join(subEntryPath, "ro"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "ro"))
				}
				partition.ReadOnly = partitionRo == 1

				// Size
				partitionSize, err := readUint(filepath.Join(subEntryPath, "size"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "size"))
				}
				partition.Size = partitionSize * 512

				// Add to list
				disk.Partitions = append(disk.Partitions, partition)
			}

			// Try to find the udev device path
			if sysfsExists(devDiskByPath) {
				links, err := ioutil.ReadDir(devDiskByPath)
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to list the links in \"%s\"", devDiskByPath)
				}

				for _, link := range links {
					linkName := link.Name()
					linkPath := filepath.Join(devDiskByPath, linkName)

					linkTarget, err := filepath.EvalSymlinks(linkPath)
					if err != nil {
						return nil, errors.Wrapf(err, "Failed to track down \"%s\"", linkPath)
					}

					if linkTarget == filepath.Join("/dev", entryName) {
						disk.DevicePath = linkName
					}
				}
			}

			// Pull direct disk information
			err = storageAddDriveInfo(filepath.Join("/dev", entryName), &disk)
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to retrieve disk information from \"%s\"", filepath.Join("/dev", entryName))
			}

			// Add to list
			storage.Disks = append(storage.Disks, disk)
		}
	}

	storage.Total = 0
	for _, card := range storage.Disks {
		if storage.Disks != nil {
			storage.Total += uint64(len(card.Partitions))
		}

		storage.Total++
	}

	return &storage, nil
}
<|endoftext|>


<commit_before>package reddit

import "strings"

// Comment represents a comment on Reddit (Reddit type t1_).
// https://github.com/reddit/reddit/wiki/JSON#comment-implements-votable--created
type Comment struct {
	ID        string `mapstructure:"id"`
	Name      string `mapstructure:"name"`
	Permalink string `mapstructure:"permalink"`

	CreatedUTC uint64 `mapstructure:"created_utc"`
	Deleted    bool   `mapstructure:"deleted"`

	Ups   int32 `mapstructure:"ups"`
	Downs int32 `mapstructure:"downs"`
	Likes bool  `mapstructure:"likes"`

	Author              string `mapstructure:"author"`
	AuthorFlairCSSClass string `mapstructure:"author_flair_css_class"`
	AuthorFlairText     string `mapstructure:"author_flair_text"`

	LinkAuthor string `mapstructure:"link_author"`
	LinkURL    string `mapstructure:"link_url"`
	LinkTitle  string `mapstructure:"link_title"`

	Subreddit   string `mapstructure:"subreddit"`
	SubredditID string `mapstructure:"subreddit_id"`

	Body     string `mapstructure:"body"`
	BodyHTML string `mapstructure:"body_html"`

	ParentID string     `mapstructure:"parent_id"`
	Replies  []*Comment `mapstructure:"reply_tree"`

	Gilded        int32  `mapstructure:"gilded"`
	Distinguished string `mapstructure:"distinguished"`
}

// IsRoot is true when the comment is a top level comment.
func (c *Comment) IsRoot() bool {
	parentType := strings.Split(c.ParentID, "_")[0]
	return parentType == postKind
}

// Post represents posts on Reddit (Reddit type t3_).
// https://github.com/reddit/reddit/wiki/JSON#link-implements-votable--created
type Post struct {
	ID        string `mapstructure:"id"`
	Name      string `mapstructure:"name"`
	Permalink string `mapstructure:"permalink"`

	CreatedUTC uint64 `mapstructure:"created_utc"`
	Deleted    bool   `mapstructure:"deleted"`

	Ups   int32 `mapstructure:"ups"`
	Downs int32 `mapstructure:"downs"`
	Likes bool  `mapstructure:"likes"`

	Author              string `mapstructure:"author"`
	AuthorFlairCSSClass string `mapstructure:"author_flair_css_class"`
	AuthorFlairText     string `mapstructure:"author_flair_text"`

	Title  string `mapstructure:"title"`
	Score  int32  `mapstructure:"score"`
	URL    string `mapstructure:"url"`
	Domain string `mapstructure:"domain"`
	NSFW   bool   `mapstructure:"over_18"`

	Subreddit   string `mapstructure:"subreddit"`
	SubredditID string `mapstructure:"subreddit_id"`

	IsSelf       bool   `mapstructure:"is_self"`
	SelfText     string `mapstructure:"selftext"`
	SelfTextHTML string `mapstructure:"selftext_html"`

	Replies []*Comment `mapstructure:"reply_tree"`

	Hidden            bool   `mapstructure:"hidden"`
	LinkFlairCSSClass string `mapstructure:"link_flair_css_class"`
	LinkFlairText     string `mapstructure:"link_flair_text"`

	NumComments int32  `mapstructure:"num_comments"`
	Locked      bool   `mapstructure:"locked"`
	Thumbnail   string `mapstructure:"thumbnail"`

	Gilded        int32  `mapstructure:"gilded"`
	Distinguished string `mapstructure:"distinguished"`
	Stickied      bool   `mapstructure:"stickied"`
}

// Message represents messages on Reddit (Reddit type t4_).
// https://github.com/reddit/reddit/wiki/JSON#message-implements-created
type Message struct {
	ID   string `mapstructure:"id"`
	Name string `mapstructure:"name"`

	CreatedUTC uint64 `mapstructure:"created_utc"`

	Author   string `mapstructure:"author"`
	Subject  string `mapstructure:"subject"`
	Body     string `mapstructure:"body"`
	BodyHTML string `mapstructure:"body_html"`

	Context          string `mapstructure:"context"`
	FirstMessageName string `mapstructure:"first_message_name"`
	Likes            bool   `mapstructure:"likes"`
	LinkTitle        string `mapstructure:"link_title"`

	New      bool   `mapstructure:"new"`
	ParentID string `mapstructure:"parent_id"`

	Subreddit  string `mapstructure:"subreddit"`
	WasComment bool   `mapstructure:"was_comment"`
}

// Harvest is a set of all possible elements that Reddit could return in a
// listing.
type Harvest struct {
	Comments []*Comment
	Posts    []*Post
	Messages []*Message
}
<commit_msg>rename IsRoot to IsTopLevel<commit_after>package reddit

import "strings"

// Comment represents a comment on Reddit (Reddit type t1_).
// https://github.com/reddit/reddit/wiki/JSON#comment-implements-votable--created
type Comment struct {
	ID        string `mapstructure:"id"`
	Name      string `mapstructure:"name"`
	Permalink string `mapstructure:"permalink"`

	CreatedUTC uint64 `mapstructure:"created_utc"`
	Deleted    bool   `mapstructure:"deleted"`

	Ups   int32 `mapstructure:"ups"`
	Downs int32 `mapstructure:"downs"`
	Likes bool  `mapstructure:"likes"`

	Author              string `mapstructure:"author"`
	AuthorFlairCSSClass string `mapstructure:"author_flair_css_class"`
	AuthorFlairText     string `mapstructure:"author_flair_text"`

	LinkAuthor string `mapstructure:"link_author"`
	LinkURL    string `mapstructure:"link_url"`
	LinkTitle  string `mapstructure:"link_title"`

	Subreddit   string `mapstructure:"subreddit"`
	SubredditID string `mapstructure:"subreddit_id"`

	Body     string `mapstructure:"body"`
	BodyHTML string `mapstructure:"body_html"`

	ParentID string     `mapstructure:"parent_id"`
	Replies  []*Comment `mapstructure:"reply_tree"`

	Gilded        int32  `mapstructure:"gilded"`
	Distinguished string `mapstructure:"distinguished"`
}

// IsTopLevel is true when the comment is a top level comment.
func (c *Comment) IsTopLevel() bool {
	parentType := strings.Split(c.ParentID, "_")[0]
	return parentType == postKind
}

// Post represents posts on Reddit (Reddit type t3_).
// https://github.com/reddit/reddit/wiki/JSON#link-implements-votable--created
type Post struct {
	ID        string `mapstructure:"id"`
	Name      string `mapstructure:"name"`
	Permalink string `mapstructure:"permalink"`

	CreatedUTC uint64 `mapstructure:"created_utc"`
	Deleted    bool   `mapstructure:"deleted"`

	Ups   int32 `mapstructure:"ups"`
	Downs int32 `mapstructure:"downs"`
	Likes bool  `mapstructure:"likes"`

	Author              string `mapstructure:"author"`
	AuthorFlairCSSClass string `mapstructure:"author_flair_css_class"`
	AuthorFlairText     string `mapstructure:"author_flair_text"`

	Title  string `mapstructure:"title"`
	Score  int32  `mapstructure:"score"`
	URL    string `mapstructure:"url"`
	Domain string `mapstructure:"domain"`
	NSFW   bool   `mapstructure:"over_18"`

	Subreddit   string `mapstructure:"subreddit"`
	SubredditID string `mapstructure:"subreddit_id"`

	IsSelf       bool   `mapstructure:"is_self"`
	SelfText     string `mapstructure:"selftext"`
	SelfTextHTML string `mapstructure:"selftext_html"`

	Replies []*Comment `mapstructure:"reply_tree"`

	Hidden            bool   `mapstructure:"hidden"`
	LinkFlairCSSClass string `mapstructure:"link_flair_css_class"`
	LinkFlairText     string `mapstructure:"link_flair_text"`

	NumComments int32  `mapstructure:"num_comments"`
	Locked      bool   `mapstructure:"locked"`
	Thumbnail   string `mapstructure:"thumbnail"`

	Gilded        int32  `mapstructure:"gilded"`
	Distinguished string `mapstructure:"distinguished"`
	Stickied      bool   `mapstructure:"stickied"`
}

// Message represents messages on Reddit (Reddit type t4_).
// https://github.com/reddit/reddit/wiki/JSON#message-implements-created
type Message struct {
	ID   string `mapstructure:"id"`
	Name string `mapstructure:"name"`

	CreatedUTC uint64 `mapstructure:"created_utc"`

	Author   string `mapstructure:"author"`
	Subject  string `mapstructure:"subject"`
	Body     string `mapstructure:"body"`
	BodyHTML string `mapstructure:"body_html"`

	Context          string `mapstructure:"context"`
	FirstMessageName string `mapstructure:"first_message_name"`
	Likes            bool   `mapstructure:"likes"`
	LinkTitle        string `mapstructure:"link_title"`

	New      bool   `mapstructure:"new"`
	ParentID string `mapstructure:"parent_id"`

	Subreddit  string `mapstructure:"subreddit"`
	WasComment bool   `mapstructure:"was_comment"`
}

// Harvest is a set of all possible elements that Reddit could return in a
// listing.
type Harvest struct {
	Comments []*Comment
	Posts    []*Post
	Messages []*Message
}
<|endoftext|>


<commit_before>package redis

import (
	"errors"
	"strconv"
)

//* Reply

/*
ReplyType describes type of a reply.

Possbile values are:

ReplyStatus --  status reply
ReplyError -- error reply
ReplyInteger -- integer reply
ReplyNil -- nil reply
ReplyString -- string reply (bulk reply)
ReplyMulti -- multi-bulk or multicall reply
*/
type ReplyType uint8

const (
	ReplyStatus ReplyType = iota
	ReplyError
	ReplyInteger
	ReplyNil
	ReplyString
	ReplyMulti
)

// Reply holds a Redis reply.
type Reply struct {
	Cmd   Cmd
	Type  ReplyType
	str   string
	int   int64
	elems []*Reply
	Error *Error
}

// Nil returns true, if the reply is a nil reply, otherwise false.
func (r *Reply) Nil() bool {
	if r.Type == ReplyNil {
		return true
	}

	return false
}

// Str returns the reply value as a string or
// an error, if the reply type is not ReplyStatus or ReplyString.
func (r *Reply) Str() (string, error) {
	if !(r.Type == ReplyStatus || r.Type == ReplyString) {
		return "", errors.New("string value is not available for this reply type")
	}

	return r.str, nil
}

// Bytes is a convenience method for calling Reply.Str() and converting it to []byte.
func (r *Reply) Bytes() ([]byte, error) {
	s, err := r.Str()
	if err != nil {
		return nil, err
	}

	return []byte(s), nil
}

// Int64 returns the reply value as a int64 or
// an error, if the reply type is not ReplyInteger.
func (r *Reply) Int64() (int64, error) {
	if r.Type != ReplyInteger {
		return 0, errors.New("integer value is not available for this reply type")
	}

	return r.int, nil
}

// Int is a convenience method for calling Reply.Int64() and converting it to int.
func (r *Reply) Int() (int, error) {
	i64, err := r.Int64()
	if err != nil {
		return 0, err
	}

	return int(i64), nil
}

// Bool returns true, if the reply value equals to 1, otherwise false; or
// an error, if the reply type is not ReplyInteger.
func (r *Reply) Bool() (bool, error) {
	i, err := r.Int()
	if err != nil {
		if i == 1 {
			return true, nil
		}

		return false, nil
	}

	return false, errors.New("boolean value is not available for this reply type")
}

// Len returns the number of elements in a multi reply.
// Zero is returned when reply type is not ReplyMulti.
func (r *Reply) Len() int {
	return len(r.elems)
}

// Elems returns the elements (sub-replies) of a multi reply or
// an error, if the reply type is not ReplyMulti.
func (r *Reply) Elems() ([]*Reply, error) {
	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	return r.elems, nil
}

// At returns a Reply of a multi reply by its index or
// an error, if the reply type is not ReplyMulti or if the index is out of range.
func (r *Reply) At(i int) (*Reply, error) {
	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	if i < 0 || i >= len(r.elems) {
		return nil, errors.New("reply index out of range")
	}

	return r.elems[i], nil
}

// List returns a multi-bulk reply as a slice of strings or an error.
// The reply type must be ReplyMulti and its elements must be ReplyString.
// Useful for list commands.
func (r *Reply) List() ([]string, error) {
	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	strings := make([]string, len(r.elems))
	for i, v := range r.elems {
		if v.Type != ReplyString {
			return nil, errors.New("sub-reply type is not ReplyString")
		}

		strings[i] = v.String()
	}

	return strings, nil
}

// Map returns a multi-bulk reply as a map[string]string or an error.
// The reply must have even number of elements and they must be in a
// "key value key value..." order.
// Useful for hash commands.
func (r *Reply) Hash() (map[string]string, error) {
	rmap := map[string]string{}

	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	if r.Len()%2 != 0 {
		return nil, errors.New("reply has odd number of elements")
	}

	for i := 0; i < r.Len()/2; i++ {
		reply, _ := r.At(i * 2)
		key, err := reply.Str()
		if err != nil {
			return nil, errors.New("key element has no string reply")
		}

		reply, _ = r.At(i*2 + 1)
		val, err := reply.Str()
		if err != nil {
			return nil, errors.New("value element has no string reply")
		}

		rmap[key] = val
	}

	return rmap, nil
}

// String returns a string representation of the reply and its sub-replies.
// This method is mainly used for debugging.
// Use method Reply.Str() for fetching a string reply.
func (r *Reply) String() string {
	switch r.Type {
	case ReplyError:
		return r.Error.Error()
	case ReplyStatus:
		fallthrough
	case ReplyString:
		s, _ := r.Str()
		return s
	case ReplyInteger:
		i, _ := r.Int()
		return strconv.Itoa(i)
	case ReplyNil:
		return "<nil>"
	case ReplyMulti:
		s := "[ "
		for _, e := range r.elems {
			s = s + e.String() + " "
		}
		return s + "]"
	}

	// This should never execute
	return ""
}

//* Future

// Future is a channel for fetching the reply of an asynchronous call.
type Future chan *Reply

func newFuture() Future {
	return make(chan *Reply, 1)
}

// Reply returns the reply of the Future.
// It blocks until the reply is available.
func (f Future) Reply() *Reply {
	return <-f
}
<commit_msg>reply: bool -- return string bool<commit_after>package redis

import (
	"errors"
	"strconv"
)

//* Reply

/*
ReplyType describes type of a reply.

Possbile values are:

ReplyStatus --  status reply
ReplyError -- error reply
ReplyInteger -- integer reply
ReplyNil -- nil reply
ReplyString -- string reply (bulk reply)
ReplyMulti -- multi-bulk or multicall reply
*/
type ReplyType uint8

const (
	ReplyStatus ReplyType = iota
	ReplyError
	ReplyInteger
	ReplyNil
	ReplyString
	ReplyMulti
)

// Reply holds a Redis reply.
type Reply struct {
	Cmd   Cmd
	Type  ReplyType
	str   string
	int   int64
	elems []*Reply
	Error *Error
}

// Nil returns true, if the reply is a nil reply, otherwise false.
func (r *Reply) Nil() bool {
	if r.Type == ReplyNil {
		return true
	}

	return false
}

// Str returns the reply value as a string or
// an error, if the reply type is not ReplyStatus or ReplyString.
func (r *Reply) Str() (string, error) {
	if !(r.Type == ReplyStatus || r.Type == ReplyString) {
		return "", errors.New("string value is not available for this reply type")
	}

	return r.str, nil
}

// Bytes is a convenience method for calling Reply.Str() and converting it to []byte.
func (r *Reply) Bytes() ([]byte, error) {
	s, err := r.Str()
	if err != nil {
		return nil, err
	}

	return []byte(s), nil
}

// Int64 returns the reply value as a int64 or
// an error, if the reply type is not ReplyInteger.
func (r *Reply) Int64() (int64, error) {
	if r.Type != ReplyInteger {
		return 0, errors.New("integer value is not available for this reply type")
	}

	return r.int, nil
}

// Int is a convenience method for calling Reply.Int64() and converting it to int.
func (r *Reply) Int() (int, error) {
	i64, err := r.Int64()
	if err != nil {
		return 0, err
	}

	return int(i64), nil
}

// Bool returns true, if the reply value equals to 1 or "1", otherwise false; or
// an error, if the reply type is not ReplyInteger or ReplyString.
func (r *Reply) Bool() (bool, error) {
	i, err := r.Int()
	if err != nil {
		if i == 1 {
			return true, nil
		}

		return false, nil
	}

	s, err := r.Str()
	if err != nil {
		if s == "1" {
			return true, nil
		}

		return false, nil
	}

	return false, errors.New("boolean value is not available for this reply type")
}

// Len returns the number of elements in a multi reply.
// Zero is returned when reply type is not ReplyMulti.
func (r *Reply) Len() int {
	return len(r.elems)
}

// Elems returns the sub-replies of a multi reply or
// an error, if the reply type is not ReplyMulti.
func (r *Reply) Elems() ([]*Reply, error) {
	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	return r.elems, nil
}

// At returns a Reply of a multi reply by its index or
// an error, if the reply type is not ReplyMulti or if the index is out of range.
func (r *Reply) At(i int) (*Reply, error) {
	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	if i < 0 || i >= len(r.elems) {
		return nil, errors.New("reply index out of range")
	}

	return r.elems[i], nil
}

// List returns a multi-bulk reply as a slice of strings or an error.
// The reply type must be ReplyMulti and its elements must be ReplyString.
// Useful for list commands.
func (r *Reply) List() ([]string, error) {
	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	strings := make([]string, len(r.elems))
	for i, v := range r.elems {
		if v.Type != ReplyString {
			return nil, errors.New("sub-reply type is not ReplyString")
		}

		strings[i] = v.String()
	}

	return strings, nil
}

// Map returns a multi-bulk reply as a map[string]string or an error.
// The reply must have even number of elements and they must be in a
// "key value key value..." order.
// Useful for hash commands.
func (r *Reply) Hash() (map[string]string, error) {
	rmap := map[string]string{}

	if r.Type != ReplyMulti {
		return nil, errors.New("reply type is not ReplyMulti")
	}

	if r.Len()%2 != 0 {
		return nil, errors.New("reply has odd number of elements")
	}

	for i := 0; i < r.Len()/2; i++ {
		reply, _ := r.At(i * 2)
		key, err := reply.Str()
		if err != nil {
			return nil, errors.New("key element has no string reply")
		}

		reply, _ = r.At(i*2 + 1)
		val, err := reply.Str()
		if err != nil {
			return nil, errors.New("value element has no string reply")
		}

		rmap[key] = val
	}

	return rmap, nil
}

// String returns a string representation of the reply and its sub-replies.
// This method is mainly used for debugging.
// Use method Reply.Str() for fetching a string reply.
func (r *Reply) String() string {
	switch r.Type {
	case ReplyError:
		return r.Error.Error()
	case ReplyStatus:
		fallthrough
	case ReplyString:
		s, _ := r.Str()
		return s
	case ReplyInteger:
		i, _ := r.Int()
		return strconv.Itoa(i)
	case ReplyNil:
		return "<nil>"
	case ReplyMulti:
		s := "[ "
		for _, e := range r.elems {
			s = s + e.String() + " "
		}
		return s + "]"
	}

	// This should never execute
	return ""
}

//* Future

// Future is a channel for fetching the reply of an asynchronous call.
type Future chan *Reply

func newFuture() Future {
	return make(chan *Reply, 1)
}

// Reply returns the reply of the Future.
// It blocks until the reply is available.
func (f Future) Reply() *Reply {
	return <-f
}
<|endoftext|>


<commit_before>package gorobdd

import (
	"fmt"
	//"testing"
)

func ExampleReduceTrivial() {
	fmt.Println(Reduce(True([]string{})))
	fmt.Println(Reduce(False([]string{})))
	fmt.Println(Reduce(True([]string{"a"})))
	fmt.Println(Reduce(False([]string{"a"})))
	fmt.Println(Reduce(True([]string{"a", "b"})))
	fmt.Println(Reduce(False([]string{"a", "b"})))
	// Output:
	// T <nil>
	// F <nil>
	// T <nil>
	// F <nil>
	// T <nil>
	// F <nil>
}
<commit_msg>Reduce skips plies with both True and False leaves.<commit_after>package gorobdd

import (
	"fmt"
	//"testing"
)

func ExampleReduceTrivial() {
	fmt.Println(Reduce(True([]string{})))
	fmt.Println(Reduce(False([]string{})))
	fmt.Println(Reduce(True([]string{"a"})))
	fmt.Println(Reduce(False([]string{"a"})))
	fmt.Println(Reduce(True([]string{"a", "b"})))
	fmt.Println(Reduce(False([]string{"a", "b"})))
	// Output:
	// T <nil>
	// F <nil>
	// T <nil>
	// F <nil>
	// T <nil>
	// F <nil>
}

func ExampleReduceSkipsPlies() {
	n, _ := FromTuples(
		[]string{"a", "b"},
		[][]bool{{true, true}, {true, false}},
	)
	fmt.Println(Reduce(n))
	// Output:
	// (a/T: T, a/F: F) <nil>
}
<|endoftext|>


<commit_before>package main

import "io"
import "fmt"
import "net/http"
import "os"
import "unicode/utf8"

import "github.com/gorilla/websocket"

// Copy everything from the pty master to the websocket.
func handleOutputWs(ptym *os.File, conn *websocket.Conn) {
	buf := make([]byte, 512)
	var payload, overflow []byte
	// TODO: more graceful exit on socket close / process exit.
	for {
		n, err := ptym.Read(buf)
		if err != nil {
			fmt.Println("failed to read from pty master: ", err)
			return
		}

		// Empty the overflow from the last read into the payload first.
		payload = append(payload[0:], overflow...)
		overflow = nil
		// Then empty the new buf read into the payload.
		payload = append(payload, buf[:n]...)

		// Strip out any incomplete utf-8 from current payload into overflow.
		for !utf8.Valid(payload) {
			overflow = append(overflow[:0], append(payload[len(payload)-1:], overflow[0:]...)...)
			payload = payload[:len(payload)-1]
		}

		// Send out the finished payload as long as it's not empty.
		if len(payload) >= 1 {
			err = conn.WriteMessage(websocket.BinaryMessage, payload[:len(payload)])
			if err != nil {
				fmt.Println("failed to send bytes on websocket: ", err)
				return
			}
		}

		// Empty the payload.
		payload = nil
	}
}

// Read from the websocket, copying to the pty master.
func handleInputWs(ptym *os.File, conn *websocket.Conn) {
	for {
		mt, payload, err := conn.ReadMessage()
		if err != nil {
			if err != io.EOF {
				fmt.Println("conn.ReadMessage failed: ", err)
				return
			}
		}

		// The client has likely disconnected.
		if mt == -1 {
			return
		}

		if mt == websocket.BinaryMessage {
			ptym.Write(payload)
		} else {
			fmt.Println("invalid message type: ", mt)
			return
		}
	}
}

func ptyHandlerWs(w http.ResponseWriter, r *http.Request, sizeFlag string) {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1,
		WriteBufferSize: 1,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("websocket upgrade failed: ", err)
	}

	ptySetupWs(conn, sizeFlag)
}

func ptySetupWs(ws *websocket.Conn, sizeFlag string) {
	ptym, cmd := start()
	setPtySize(ptym, sizeFlag)

	go func() {
		handleOutputWs(ptym, ws)
	}()

	go func() {
		handleInputWs(ptym, ws)
	}()

	// Listen for a new winsize on stdin.
	for {
		var newSize string
		_, scanErr := fmt.Scanln(&newSize)
		if scanErr != nil {
			fmt.Println("scan failed: ", scanErr)
		}

		setPtySize(ptym, newSize)
		fmt.Println("new size: ", newSize)
	}

	stop(ptym, cmd)
	ws.Close()
}<commit_msg>Added a disconnected print for websocket<commit_after>package main

import "io"
import "fmt"
import "net/http"
import "os"
import "unicode/utf8"

import "github.com/gorilla/websocket"

// Copy everything from the pty master to the websocket.
func handleOutputWs(ptym *os.File, conn *websocket.Conn) {
	buf := make([]byte, 512)
	var payload, overflow []byte
	// TODO: more graceful exit on socket close / process exit.
	for {
		n, err := ptym.Read(buf)
		if err != nil {
			fmt.Println("failed to read from pty master: ", err)
			return
		}

		// Empty the overflow from the last read into the payload first.
		payload = append(payload[0:], overflow...)
		overflow = nil
		// Then empty the new buf read into the payload.
		payload = append(payload, buf[:n]...)

		// Strip out any incomplete utf-8 from current payload into overflow.
		for !utf8.Valid(payload) {
			overflow = append(overflow[:0], append(payload[len(payload)-1:], overflow[0:]...)...)
			payload = payload[:len(payload)-1]
		}

		// Send out the finished payload as long as it's not empty.
		if len(payload) >= 1 {
			err = conn.WriteMessage(websocket.BinaryMessage, payload[:len(payload)])
			if err != nil {
				fmt.Println("failed to send bytes on websocket: ", err)
				return
			}
		}

		// Empty the payload.
		payload = nil
	}
}

// Read from the websocket, copying to the pty master.
func handleInputWs(ptym *os.File, conn *websocket.Conn) {
	for {
		mt, payload, err := conn.ReadMessage()

		// The client has likely disconnected.
		if mt == -1 {
			fmt.Println("client disconnected.")
			return
		}

		if err != nil && err != io.EOF {
			fmt.Println("conn.ReadMessage failed: ", err)
			return
		}

		if mt == websocket.BinaryMessage {
			ptym.Write(payload)
		} else {
			fmt.Println("invalid message type: ", mt)
			return
		}
	}
}

func ptyHandlerWs(w http.ResponseWriter, r *http.Request, sizeFlag string) {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  1,
		WriteBufferSize: 1,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("websocket upgrade failed: ", err)
	}

	ptySetupWs(conn, sizeFlag)
}

func ptySetupWs(ws *websocket.Conn, sizeFlag string) {
	ptym, cmd := start()
	setPtySize(ptym, sizeFlag)

	go func() {
		handleOutputWs(ptym, ws)
	}()

	go func() {
		handleInputWs(ptym, ws)
	}()

	// Listen for a new winsize on stdin.
	for {
		var newSize string
		_, scanErr := fmt.Scanln(&newSize)
		if scanErr != nil {
			fmt.Println("scan failed: ", scanErr)
		}

		setPtySize(ptym, newSize)
		fmt.Println("new size: ", newSize)
	}

	stop(ptym, cmd)
	ws.Close()
}<|endoftext|>


<commit_before>package chatblast

import (
	"log"
	"sync"
)

type Room struct {
	sync.RWMutex
	Name        string           `json:"name,omitempty"`
	Id          string           `json:"id,omitempty"`
	Private     bool             `json:"private,omitempty"`
	Owner       *User            `json:"owner,omitempty"`
	Subscribers map[string]*User `json:"subscribers,omitempty"`
	Channel     chan *Message    `json:"-"`
}

func (r *Room) GetSubscriber(userId string) (*User, bool) {
	r.RLock()
	defer r.RUnlock()
	user, ok := r.Subscribers[userId]
	return user, ok
}

func (r *Room) SetSubscriber(userId string, u *User) {
	r.Lock()
	defer r.Unlock()
	r.Subscribers[userId] = u
}

func (r *Room) RemoveSubscriber(userId string) {
	r.Lock()
	defer r.Unlock()
	delete(r.Subscribers, userId)
}

func NewRoom(name string, owner *User) *Room {
	newRoom := &Room{
		Name:        name,
		Id:          GUID(),
		Owner:       owner,
		Subscribers: map[string]*User{},
		Channel:     make(chan *Message),
	}
	go newRoom.Listen()
	log.Println("New room", name, "created")
	return newRoom
}

func (r *Room) Listen() {
	for incoming := range r.Channel {
		log.Println("Message sent in room", r.Name)
		for _, user := range r.Subscribers {
			user.Tell(incoming)
		}
	}
}

func (r *Room) Broadcast(msg *Message) {
	r.Channel <- msg
}

func (r *Room) Whisper(msg *Message, userId string) {
	if whisperee, ok := r.Subscribers[userId]; ok {
		whisperee.Tell(msg)
	}
}

func (r *Room) RequestInvite(u *User) {
	msg := &Message{
		Cmd:    "inviterequest",
		RoomId: r.Id,
		UserId: u.Id,
	}
	r.Owner.Channel <- msg
}

func (r *Room) Join(u *User) {
	// TODO Add re-join check
	r.SetSubscriber(u.Id, u)
	msg := &Message{
		Cmd:    "sub",
		User:   u,
		RoomId: r.Id,
		UserId: u.Id,
	}
	r.Broadcast(msg)
}

func (r *Room) Leave(u *User) {
	// TODO Add bad leave request check (i.e. user tries to leave room they
	// aren't subscribed to)
	r.RemoveSubscriber(u.Id)
	msg := &Message{
		Cmd:    "unsub",
		RoomId: r.Id,
		UserId: u.Id,
	}
	r.Broadcast(msg)
}

func (r *Room) CloseRoom(u *User) (closed bool, err error) {
	closed = false
	err = nil
	if r.Owner != nil && u.Id == r.Owner.Id {
		closed = true
	}
	return closed, err

}
<commit_msg>Fix unsub message not going to unsubscribing user<commit_after>package chatblast

import (
	"log"
	"sync"
)

type Room struct {
	sync.RWMutex
	Name        string           `json:"name,omitempty"`
	Id          string           `json:"id,omitempty"`
	Private     bool             `json:"private,omitempty"`
	Owner       *User            `json:"owner,omitempty"`
	Subscribers map[string]*User `json:"subscribers,omitempty"`
	Channel     chan *Message    `json:"-"`
}

func (r *Room) GetSubscriber(userId string) (*User, bool) {
	r.RLock()
	defer r.RUnlock()
	user, ok := r.Subscribers[userId]
	return user, ok
}

func (r *Room) SetSubscriber(userId string, u *User) {
	r.Lock()
	defer r.Unlock()
	r.Subscribers[userId] = u
}

func (r *Room) RemoveSubscriber(userId string) {
	r.Lock()
	defer r.Unlock()
	delete(r.Subscribers, userId)
}

func NewRoom(name string, owner *User) *Room {
	newRoom := &Room{
		Name:        name,
		Id:          GUID(),
		Owner:       owner,
		Subscribers: map[string]*User{},
		Channel:     make(chan *Message),
	}
	go newRoom.Listen()
	log.Println("New room", name, "created")
	return newRoom
}

func (r *Room) Listen() {
	for incoming := range r.Channel {
		log.Println("Message sent in room", r.Name)
		for _, user := range r.Subscribers {
			user.Tell(incoming)
		}
	}
}

func (r *Room) Broadcast(msg *Message) {
	r.Channel <- msg
}

func (r *Room) Whisper(msg *Message, userId string) {
	if whisperee, ok := r.Subscribers[userId]; ok {
		whisperee.Tell(msg)
	}
}

func (r *Room) RequestInvite(u *User) {
	msg := &Message{
		Cmd:    "inviterequest",
		RoomId: r.Id,
		UserId: u.Id,
	}
	r.Owner.Channel <- msg
}

func (r *Room) Join(u *User) {
	// TODO Add re-join check
	r.SetSubscriber(u.Id, u)
	msg := &Message{
		Cmd:    "sub",
		User:   u,
		RoomId: r.Id,
		UserId: u.Id,
	}
	r.Broadcast(msg)
}

func (r *Room) Leave(u *User) {
	// TODO Add bad leave request check (i.e. user tries to leave room they
	// aren't subscribed to)
	r.RemoveSubscriber(u.Id)
	msg := &Message{
		Cmd:    "unsub",
		RoomId: r.Id,
		UserId: u.Id,
	}
	r.Broadcast(msg)
	u.Tell(msg)
}

func (r *Room) CloseRoom(u *User) (closed bool, err error) {
	closed = false
	err = nil
	if r.Owner != nil && u.Id == r.Owner.Id {
		closed = true
	}
	return closed, err

}
<|endoftext|>


<commit_before>package timer

import (
	"github.com/davyxu/cellnet"
	"time"
)

type Loop struct {
	Context      interface{}
	Duration     time.Duration
	userCallback func(*Loop)

	running bool

	Queue cellnet.EventQueue
}

func (self *Loop) Running() bool {
	return self.running
}

func (self *Loop) Start() bool {

	if self.running {
		return false
	}

	self.running = true

	self.rawPost()

	return true
}

func (self *Loop) rawPost() {

	if self.Duration == 0 {
		panic("seconds can be zero in loop")
	}

	if self.running {
		After(self.Queue, self.Duration, func() {

			tick(self, false)
		}, nil)
	}
}

func (self *Loop) NextLoop() {

	self.Queue.Post(func() {
		tick(self, true)
	})
}

func (self *Loop) Stop() {

	self.running = false
}

func (self *Loop) Notify() *Loop {
	self.userCallback(self)
	return self
}

func tick(ctx interface{}, nextLoop bool) {

	loop := ctx.(*Loop)

	if !nextLoop && loop.running {

		// 即便在Notify中发生了崩溃，也会使用defer再次继续循环
		defer loop.rawPost()
	}

	loop.Notify()
}

func NewLoop(q cellnet.EventQueue, duration time.Duration, callback func(*Loop), context interface{}) *Loop {

	self := &Loop{
		Context:      context,
		Duration:     duration,
		userCallback: callback,
		Queue:        q,
	}

	return self
}
<commit_msg>mod 计时器线程安全<commit_after>package timer

import (
	"github.com/davyxu/cellnet"
	"sync/atomic"
	"time"
)

type Loop struct {
	Context      interface{}
	Duration     time.Duration
	userCallback func(*Loop)

	running int64

	Queue cellnet.EventQueue
}

func (self *Loop) Running() bool {
	return atomic.LoadInt64(&self.running) != 0
}

func (self *Loop) setRunning(v bool) {

	if v {
		atomic.StoreInt64(&self.running, 1)
	} else {
		atomic.StoreInt64(&self.running, 0)
	}

}

func (self *Loop) Start() bool {

	if self.Running() {
		return false
	}

	atomic.StoreInt64(&self.running, 1)

	self.rawPost()

	return true
}

func (self *Loop) rawPost() {

	if self.Duration == 0 {
		panic("seconds can be zero in loop")
	}

	if self.Running() {
		After(self.Queue, self.Duration, func() {

			tick(self, false)
		}, nil)
	}
}

func (self *Loop) NextLoop() {

	self.Queue.Post(func() {
		tick(self, true)
	})
}

func (self *Loop) Stop() {

	self.setRunning(false)
}

func (self *Loop) Notify() *Loop {
	self.userCallback(self)
	return self
}

func tick(ctx interface{}, nextLoop bool) {

	loop := ctx.(*Loop)

	if !nextLoop && loop.Running() {

		// 即便在Notify中发生了崩溃，也会使用defer再次继续循环
		defer loop.rawPost()
	}

	loop.Notify()
}

func NewLoop(q cellnet.EventQueue, duration time.Duration, callback func(*Loop), context interface{}) *Loop {

	self := &Loop{
		Context:      context,
		Duration:     duration,
		userCallback: callback,
		Queue:        q,
	}

	return self
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Perkeep Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package blob

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"sync/atomic"
	"unicode/utf8"

	"perkeep.org/pkg/constants"
)

// Blob represents a blob. Use the methods Size, SizedRef and
// ReadAll to query and get data from Blob.
type Blob struct {
	ref     Ref
	size    uint32
	readAll func(context.Context) ([]byte, error)
	mem     atomic.Value // of []byte, if in memory
}

// NewBlob constructs a Blob from its Ref, size and a function that
// returns an io.ReadCloser from which the blob can be read. Any error
// in the function newReader when constructing the io.ReadCloser should
// be returned upon the first call to Read or Close.
func NewBlob(ref Ref, size uint32, readAll func(ctx context.Context) ([]byte, error)) *Blob {
	return &Blob{
		ref:     ref,
		size:    size,
		readAll: readAll,
	}
}

// Size returns the size of the blob (in bytes).
func (b *Blob) Size() uint32 {
	return b.size
}

// SizedRef returns the SizedRef corresponding to the blob.
func (b *Blob) SizedRef() SizedRef {
	return SizedRef{b.ref, b.size}
}

// Ref returns the blob's reference.
func (b *Blob) Ref() Ref { return b.ref }

// ReadAll reads the blob completely to memory, using the provided
// context, and then returns a reader over it. The Reader will not
// have errors except EOF.
//
// The provided is only ctx is used until ReadAll returns.
func (b *Blob) ReadAll(ctx context.Context) (*bytes.Reader, error) {
	mem, err := b.getMem(ctx)
	if err != nil {
		return nil, err
	}
	return bytes.NewReader(mem), nil
}

func (b *Blob) getMem(ctx context.Context) ([]byte, error) {
	mem, ok := b.mem.Load().([]byte)
	if ok {
		return mem, nil
	}
	mem, err := b.readAll(ctx)
	if err != nil {
		return nil, err
	}
	if uint32(len(mem)) != b.size {
		return nil, fmt.Errorf("Blob.ReadAll read %d bytes of %v; expected %d", len(mem), b.ref, b.size)
	}
	b.mem.Store(mem)
	return mem, nil
}

// ValidContents reports whether the hash of blob's content matches
// its reference.
func (b *Blob) ValidContents(ctx context.Context) error {
	mem, err := b.getMem(ctx)
	if err != nil {
		return err
	}
	h := b.ref.Hash()
	h.Write(mem)
	if !b.ref.HashMatches(h) {
		return fmt.Errorf("blob contents don't match digest for ref %v", b.ref)
	}
	return nil
}

// IsUTF8 reports whether the blob is entirely UTF-8.
func (b *Blob) IsUTF8(ctx context.Context) (bool, error) {
	mem, err := b.getMem(ctx)
	if err != nil {
		return false, err
	}
	return utf8.Valid(mem), nil
}

// A reader reads a blob's contents.
// It adds a no-op Close method to a *bytes.Reader.
type reader struct {
	*bytes.Reader
}

func (reader) Close() error { return nil }

// FromFetcher fetches br from fetcher and slurps its contents to
// memory. It does not validate the blob's digest.  Use the
// Blob.ValidContents method for that.
func FromFetcher(ctx context.Context, fetcher Fetcher, br Ref) (*Blob, error) {
	rc, size, err := fetcher.Fetch(ctx, br)
	if err != nil {
		return nil, err
	}
	defer rc.Close()
	return FromReader(ctx, br, rc, size)
}

// FromReader slurps the given blob from r to memory.
// It does not validate the blob's digest.  Use the
// Blob.ValidContents method for that.
func FromReader(ctx context.Context, br Ref, r io.Reader, size uint32) (*Blob, error) {
	if size > constants.MaxBlobSize {
		return nil, fmt.Errorf("blob: %v with reported size %d is over max size of %d", br, size, constants.MaxBlobSize)
	}
	buf := make([]byte, size)
	// TODO: use ctx here during ReadFull? add context-checking Reader wrapper?
	if n, err := io.ReadFull(r, buf); err != nil {
		return nil, fmt.Errorf("blob: after reading %d bytes of %v: %v", n, br, err)
	}
	n, _ := io.CopyN(ioutil.Discard, r, 1)
	if n > 0 {
		return nil, fmt.Errorf("blob: %v had more than reported %d bytes", br, size)
	}
	b := NewBlob(br, uint32(size), func(context.Context) ([]byte, error) {
		return buf, nil
	})
	b.mem.Store(buf)
	return b, nil
}
<commit_msg>pkg/blob: fix NewBlob doc<commit_after>/*
Copyright 2014 The Perkeep Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package blob

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"sync/atomic"
	"unicode/utf8"

	"perkeep.org/pkg/constants"
)

// Blob represents a blob. Use the methods Size, SizedRef and
// ReadAll to query and get data from Blob.
type Blob struct {
	ref     Ref
	size    uint32
	readAll func(context.Context) ([]byte, error)
	mem     atomic.Value // of []byte, if in memory
}

// NewBlob constructs a Blob from its Ref, size and a function that
// returns the contents of the blob. Any error in the function newReader when
// constructing the io.ReadCloser should be returned upon the first call to Read or
// Close.
func NewBlob(ref Ref, size uint32, readAll func(ctx context.Context) ([]byte, error)) *Blob {
	return &Blob{
		ref:     ref,
		size:    size,
		readAll: readAll,
	}
}

// Size returns the size of the blob (in bytes).
func (b *Blob) Size() uint32 {
	return b.size
}

// SizedRef returns the SizedRef corresponding to the blob.
func (b *Blob) SizedRef() SizedRef {
	return SizedRef{b.ref, b.size}
}

// Ref returns the blob's reference.
func (b *Blob) Ref() Ref { return b.ref }

// ReadAll reads the blob completely to memory, using the provided
// context, and then returns a reader over it. The Reader will not
// have errors except EOF.
//
// The provided is only ctx is used until ReadAll returns.
func (b *Blob) ReadAll(ctx context.Context) (*bytes.Reader, error) {
	mem, err := b.getMem(ctx)
	if err != nil {
		return nil, err
	}
	return bytes.NewReader(mem), nil
}

func (b *Blob) getMem(ctx context.Context) ([]byte, error) {
	mem, ok := b.mem.Load().([]byte)
	if ok {
		return mem, nil
	}
	mem, err := b.readAll(ctx)
	if err != nil {
		return nil, err
	}
	if uint32(len(mem)) != b.size {
		return nil, fmt.Errorf("Blob.ReadAll read %d bytes of %v; expected %d", len(mem), b.ref, b.size)
	}
	b.mem.Store(mem)
	return mem, nil
}

// ValidContents reports whether the hash of blob's content matches
// its reference.
func (b *Blob) ValidContents(ctx context.Context) error {
	mem, err := b.getMem(ctx)
	if err != nil {
		return err
	}
	h := b.ref.Hash()
	h.Write(mem)
	if !b.ref.HashMatches(h) {
		return fmt.Errorf("blob contents don't match digest for ref %v", b.ref)
	}
	return nil
}

// IsUTF8 reports whether the blob is entirely UTF-8.
func (b *Blob) IsUTF8(ctx context.Context) (bool, error) {
	mem, err := b.getMem(ctx)
	if err != nil {
		return false, err
	}
	return utf8.Valid(mem), nil
}

// A reader reads a blob's contents.
// It adds a no-op Close method to a *bytes.Reader.
type reader struct {
	*bytes.Reader
}

func (reader) Close() error { return nil }

// FromFetcher fetches br from fetcher and slurps its contents to
// memory. It does not validate the blob's digest.  Use the
// Blob.ValidContents method for that.
func FromFetcher(ctx context.Context, fetcher Fetcher, br Ref) (*Blob, error) {
	rc, size, err := fetcher.Fetch(ctx, br)
	if err != nil {
		return nil, err
	}
	defer rc.Close()
	return FromReader(ctx, br, rc, size)
}

// FromReader slurps the given blob from r to memory.
// It does not validate the blob's digest.  Use the
// Blob.ValidContents method for that.
func FromReader(ctx context.Context, br Ref, r io.Reader, size uint32) (*Blob, error) {
	if size > constants.MaxBlobSize {
		return nil, fmt.Errorf("blob: %v with reported size %d is over max size of %d", br, size, constants.MaxBlobSize)
	}
	buf := make([]byte, size)
	// TODO: use ctx here during ReadFull? add context-checking Reader wrapper?
	if n, err := io.ReadFull(r, buf); err != nil {
		return nil, fmt.Errorf("blob: after reading %d bytes of %v: %v", n, br, err)
	}
	n, _ := io.CopyN(ioutil.Discard, r, 1)
	if n > 0 {
		return nil, fmt.Errorf("blob: %v had more than reported %d bytes", br, size)
	}
	b := NewBlob(br, uint32(size), func(context.Context) ([]byte, error) {
		return buf, nil
	})
	b.mem.Store(buf)
	return b, nil
}
<|endoftext|>