<commit_before>package horizon

import (
	"net/http"

	"github.com/stellar/go-horizon/db"
	"github.com/stellar/go-horizon/render"
	"github.com/stellar/go-horizon/render/hal"
	"github.com/stellar/go-horizon/render/problem"
	"github.com/stellar/go-horizon/render/sse"
	"github.com/zenazn/goji/web"
)

func ledgerIndexAction(c web.C, w http.ResponseWriter, r *http.Request) {
	ah := &ActionHelper{c: c, r: r}
	ctx := ah.Context()

	// construct query
	ah.ValidateInt64(ParamCursor)
	query := db.LedgerPageQuery{
		SqlQuery:  ah.App().HistoryQuery(),
		PageQuery: ah.GetPageQuery(),
	}

	if ah.Err() != nil {
		problem.Render(ctx, w, ah.Err())
		return
	}

	var records []db.LedgerRecord

	render := render.Renderer{}
	render.JSON = func() {
		// load records
		err := db.Select(ctx, query, &records)
		if err != nil {
			problem.Render(ctx, w, err)
		}

		page, err := NewLedgerPageResource(records, query.PageQuery)
		if err != nil {
			problem.Render(ctx, w, err)
		}

		hal.RenderPage(w, page)
	}

	render.SSE = func(stream sse.Stream) {
		err := db.Select(ctx, query, &records)
		if err != nil {
			stream.Err(err)
			return
		}

		records = records[stream.SentCount():]

		for _, record := range records {
			stream.Send(sse.Event{
				ID:   record.PagingToken(),
				Data: NewLedgerResource(record),
			})
		}

		if stream.SentCount() >= int(query.Limit) {
			stream.Done()
		}
	}

	render.Render(ctx, w, r)
}

func ledgerShowAction(c web.C, w http.ResponseWriter, r *http.Request) {
	ah := &ActionHelper{c: c, r: r}
	app := ah.App()
	sequence := ah.GetInt32("id")

	if ah.Err() != nil {
		problem.Render(ah.Context(), w, problem.NotFound)
		return
	}

	query := db.LedgerBySequenceQuery{
		SqlQuery: app.HistoryQuery(),
		Sequence: sequence,
	}

	render.Single(ah.Context(), w, r, query, ledgerRecordToResource)
}

func ledgerRecordToResource(record db.Record) (render.Resource, error) {
	return NewLedgerResource(record.(db.LedgerRecord)), nil
}
<commit_msg>Update /ledgers/:id action to new renderer<commit_after>package horizon

import (
	"net/http"

	"github.com/stellar/go-horizon/db"
	"github.com/stellar/go-horizon/render"
	"github.com/stellar/go-horizon/render/hal"
	"github.com/stellar/go-horizon/render/problem"
	"github.com/stellar/go-horizon/render/sse"
	"github.com/zenazn/goji/web"
)

func ledgerIndexAction(c web.C, w http.ResponseWriter, r *http.Request) {
	ah := &ActionHelper{c: c, r: r}
	ctx := ah.Context()

	// construct query
	ah.ValidateInt64(ParamCursor)
	query := db.LedgerPageQuery{
		SqlQuery:  ah.App().HistoryQuery(),
		PageQuery: ah.GetPageQuery(),
	}

	if ah.Err() != nil {
		problem.Render(ctx, w, ah.Err())
		return
	}

	var records []db.LedgerRecord

	render := render.Renderer{}
	render.JSON = func() {
		// load records
		err := db.Select(ctx, query, &records)
		if err != nil {
			problem.Render(ctx, w, err)
		}

		page, err := NewLedgerPageResource(records, query.PageQuery)
		if err != nil {
			problem.Render(ctx, w, err)
		}

		hal.RenderPage(w, page)
	}

	render.SSE = func(stream sse.Stream) {
		err := db.Select(ctx, query, &records)
		if err != nil {
			stream.Err(err)
			return
		}

		records = records[stream.SentCount():]

		for _, record := range records {
			stream.Send(sse.Event{
				ID:   record.PagingToken(),
				Data: NewLedgerResource(record),
			})
		}

		if stream.SentCount() >= int(query.Limit) {
			stream.Done()
		}
	}

	render.Render(ctx, w, r)
}

func ledgerShowAction(c web.C, w http.ResponseWriter, r *http.Request) {
	ah := &ActionHelper{c: c, r: r}
	app := ah.App()

	// construct query
	query := db.LedgerBySequenceQuery{
		SqlQuery: app.HistoryQuery(),
		Sequence: ah.GetInt32("id"),
	}
	if ah.Err() != nil {
		problem.Render(ah.Context(), w, ah.Err())
		return
	}

	// find ledger
	found, err := db.First(ah.Context(), query)
	if err != nil {
		problem.Render(ah.Context(), w, ah.Err())
		return
	}

	ledger, ok := found.(db.LedgerRecord)
	if !ok {
		problem.Render(ah.Context(), w, problem.NotFound)
		return
	}

	render := render.Renderer{}
	render.JSON = func() {
		hal.Render(w, NewLedgerResource(ledger))
	}

	render.Render(ah.Context(), w, r)
}
<|endoftext|>


<commit_before>// Package etree provides XML services through an Element Tree
// abstraction.
package etree

import (
	"bufio"
	"encoding/xml"
	"errors"
	"io"
)

const (
	NoIndent = -1
)

var (
	ErrInvalidFormat = errors.New("etree: invalid XML format")
)

// A Token is an empty interface that represents an Element,
// Comment, CharData, Directive or ProcInst.
type Token interface {
	writeTo(w *bufio.Writer)
}

// A Document is the root level object in an etree.  It represents the
// XML document as a whole.  It embeds an Element type but only uses the
// Element type's Child tokens.
type Document struct {
	Element
}

// An Element represents an XML element, its attributes, and its child tokens.
type Element struct {
	Tag   string  // The element tag
	Attr  []Attr  // The element's list of key-value attribute pairs
	Child []Token // The element's child tokens (elements, comments, etc.)
}

// An Attr represents a key-value attribute of an XML element.
type Attr struct {
	Key   string
	Value string
}

// A Comment represents an XML comment.
type Comment struct {
	Data string
}

// CharData represents character data within XML.
type CharData struct {
	Data       string
	whitespace bool
}

// A ProcInst represents an XML processing instruction.
type ProcInst struct {
	Target string
	Inst   string
}

// NewDocument creates an empty XML document and returns it.
func NewDocument() *Document {
	d := new(Document)
	d.Child = make([]Token, 0)
	return d
}

// ReadFrom reads XML from the reader r and adds the result as
// a new child of the receiving document.
func (d *Document) ReadFrom(r io.Reader) error {
	return d.Element.ReadFrom(r)
}

// WriteTo serializes an XML document into the writer w.
func (d *Document) WriteTo(w io.Writer) error {
	b := bufio.NewWriter(w)
	for _, c := range d.Child {
		c.writeTo(b)
	}
	return b.Flush()
}

// Indent modifies the document's element tree by inserting
// CharData entities containing carriage returns and indentation.
// The amount of indenting per depth level is equal to spaces.
// Use etree.NoIndent for spaces if you want no indentation at all.
func (d *Document) Indent(spaces int) {
	d.stripIndent()
	n := len(d.Child)
	if n == 0 {
		return
	}

	newChild := make([]Token, n*2-1)
	for i, c := range d.Child {
		j := i * 2
		newChild[j] = c
		if j+1 < len(newChild) {
			newChild[j+1] = newIndentCharData(0, spaces)
		}
		if e, ok := c.(*Element); ok {
			e.indent(1, spaces)
		}
	}
	d.Child = newChild
}

// NewElement creates an XML element with the specified name.
// In most cases, you should use NewDocument and create elements
// with the CreateElement function.
func NewElement(tag string) *Element {
	return &Element{
		Tag:   tag,
		Attr:  make([]Attr, 0),
		Child: make([]Token, 0),
	}
}

// Text returns the characters immediately following the element's
// opening tag.
func (e *Element) Text() string {
	if len(e.Child) == 0 {
		return ""
	}
	if cd, ok := e.Child[0].(*CharData); ok {
		return cd.Data
	} else {
		return ""
	}
}

// SetText replaces an element's subsidiary CharData text with a new
// string.
func (e *Element) SetText(text string) {
	if len(e.Child) > 0 {
		if cd, ok := e.Child[0].(*CharData); ok {
			cd.Data = text
			return
		}
	}
	e.Child = append(e.Child, nil)
	copy(e.Child[1:], e.Child[0:])
	c := newCharData(text, false)
	e.Child[0] = c
}

// CreateElement creates a child element of the receiving element and
// gives it the specified name.
func (e *Element) CreateElement(name string) *Element {
	c := NewElement(name)
	e.addChild(c)
	return c
}

// An element stack is a simple stack of elements used by ReadFrom.
type elementStack []*Element

func (s *elementStack) push(e *Element) {
	*s = append(*s, e)
}

func (s *elementStack) pop() {
	(*s)[len(*s)-1] = nil
	*s = (*s)[:len(*s)-1]
}

func (s *elementStack) peek() *Element {
	return (*s)[len(*s)-1]
}

// ReadFrom reads XML from the reader r and stores the result as
// a new child of the receiving element.
func (e *Element) ReadFrom(r io.Reader) error {
	stack := elementStack{e}
	dec := xml.NewDecoder(r)
	for {
		t, err := dec.RawToken()
		switch {
		case err == io.EOF:
			return nil
		case err != nil:
			return err
		case len(stack) == 0:
			return ErrInvalidFormat
		}

		top := stack.peek()

		switch t := t.(type) {
		case xml.StartElement:
			e := top.CreateElement(t.Name.Local)
			for _, a := range t.Attr {
				e.CreateAttr(a.Name.Local, a.Value)
			}
			stack.push(e)
		case xml.EndElement:
			stack.pop()
		case xml.CharData:
			data := string(t)
			top.createCharData(data, isWhitespace(data))
		case xml.Comment:
			top.CreateComment(string(t))
		case xml.ProcInst:
			top.CreateProcInst(t.Target, string(t.Inst))
		}
	}
}

// WriteTo serializes the element and its children as XML into
// the writer w.
func (e *Element) WriteTo(w io.Writer) error {
	b := bufio.NewWriter(w)
	e.writeTo(b)
	return b.Flush()
}

// ChildElements returns all elements that are children of the
// receiving element.
func (e *Element) ChildElements() []*Element {
	elements := make([]*Element, 0)
	for _, c := range e.Child {
		if e, ok := c.(*Element); ok {
			elements = append(elements, e)
		}
	}
	return elements
}

// Indent modifies the element's element tree by inserting
// CharData entities containing carriage returns and indentation.
// The amount of indenting per depth level is equal to spaces.
// Use etree.NoIndent for spaces if you want no indentation at all.
func (e *Element) Indent(spaces int) {
	e.indent(1, spaces)
}

// indent recursively inserts proper indentation between an
// XML element's child tokens.
func (e *Element) indent(depth, spaces int) {
	e.stripIndent()
	n := len(e.Child)
	if n == 0 {
		return
	}

	oldChild := e.Child
	e.Child = make([]Token, 0, n*2+1)
	isCharData := false
	for _, c := range oldChild {
		_, isCharData = c.(*CharData)
		if !isCharData && spaces >= 0 {
			e.addChild(newIndentCharData(depth, spaces))
		}
		e.addChild(c)
		if ce, ok := c.(*Element); ok {
			ce.indent(depth+1, spaces)
		}
	}
	if !isCharData && spaces >= 0 {
		e.addChild(newIndentCharData(depth-1, spaces))
	}
}

// stripIndent removes any previously inserted indentation.
func (e *Element) stripIndent() {
	// Count the number of non-indent child tokens
	n := len(e.Child)
	for _, c := range e.Child {
		if cd, ok := c.(*CharData); ok && cd.whitespace {
			n--
		}
	}
	if n == len(e.Child) {
		return
	}

	// Strip out indent CharData
	newChild := make([]Token, n)
	j := 0
	for _, c := range e.Child {
		if cd, ok := c.(*CharData); ok && cd.whitespace {
			continue
		}
		newChild[j] = c
		j++
	}
	e.Child = newChild
}

// writeTo serializes the element to the writer w.
func (e *Element) writeTo(w *bufio.Writer) {
	w.WriteByte('<')
	w.WriteString(e.Tag)
	for _, a := range e.Attr {
		w.WriteByte(' ')
		a.writeTo(w)
	}
	if len(e.Child) > 0 {
		w.WriteString(">")
		for _, c := range e.Child {
			c.writeTo(w)
		}
		w.Write([]byte{'<', '/'})
		w.WriteString(e.Tag)
		w.WriteByte('>')
	} else {
		w.Write([]byte{'/', '>'})
	}
}

// addChild adds a child token to the receiving element.
func (e *Element) addChild(t Token) {
	e.Child = append(e.Child, t)
}

// CreateAttr creates an attribute and adds it to the receiving element.
func (e *Element) CreateAttr(key, value string) Attr {
	a := Attr{key, value}
	e.Attr = append(e.Attr, a)
	return a
}

// writeTo serializes the attribute to the writer.
func (a *Attr) writeTo(w *bufio.Writer) {
	w.WriteString(a.Key)
	w.WriteString(`="`)
	w.WriteString(a.Value)
	w.WriteByte('"')
}

// newCharData creates an XML character data entity.
func newCharData(data string, whitespace bool) *CharData {
	return &CharData{Data: data, whitespace: whitespace}
}

// CreateCharData creates an XML character data entity and adds it
// as a child of the receiving element.
func (e *Element) CreateCharData(data string) *CharData {
	return e.createCharData(data, false)
}

// CreateCharData creates an XML character data entity and adds it
// as a child of the receiving element.
func (e *Element) createCharData(data string, whitespace bool) *CharData {
	c := newCharData(data, whitespace)
	e.addChild(c)
	return c
}

// writeTo serializes the character data entity to the writer.
func (c *CharData) writeTo(w *bufio.Writer) {
	w.WriteString(escape(c.Data))
}

// NewComment creates an XML comment.
func newComment(comment string) *Comment {
	return &Comment{Data: comment}
}

// CreateComment creates an XML comment and adds it as a child of the
// receiving element.
func (e *Element) CreateComment(comment string) *Comment {
	c := newComment(comment)
	e.addChild(c)
	return c
}

// writeTo serialies the comment to the writer.
func (c *Comment) writeTo(w *bufio.Writer) {
	w.WriteString("<!--")
	w.WriteString(c.Data)
	w.WriteString("-->")
}

// newProcInst creates a new processing instruction.
func newProcInst(target, inst string) *ProcInst {
	return &ProcInst{Target: target, Inst: inst}
}

// CreateProcInst creates a processing instruction and adds it as a
// child of the receiving element
func (e *Element) CreateProcInst(target, inst string) *ProcInst {
	p := newProcInst(target, inst)
	e.addChild(p)
	return p
}

// writeTo serializes the processing instruction to the writer.
func (p *ProcInst) writeTo(w *bufio.Writer) {
	w.WriteString("<?")
	w.WriteString(p.Target)
	w.WriteByte(' ')
	w.WriteString(p.Inst)
	w.WriteString("?>")
}

// newIndentCharData returns the indentation CharData token for the given
// depth level with the given number of spaces per level.
func newIndentCharData(depth, spaces int) *CharData {
	return newCharData(crSpaces(depth*spaces), true)
}
<commit_msg>add SelectElement, SelectElements, SelectAttr and CreateElementIterator<commit_after>// Package etree provides XML services through an Element Tree
// abstraction.
package etree

import (
	"bufio"
	"encoding/xml"
	"errors"
	"io"
)

const (
	NoIndent = -1
)

var (
	ErrInvalidFormat = errors.New("etree: invalid XML format")
)

// A Token is an empty interface that represents an Element,
// Comment, CharData, Directive or ProcInst.
type Token interface {
	writeTo(w *bufio.Writer)
}

// A Document is the root level object in an etree.  It represents the
// XML document as a whole.  It embeds an Element type but only uses the
// Element type's Child tokens.
type Document struct {
	Element
}

// An Element represents an XML element, its attributes, and its child tokens.
type Element struct {
	Tag   string  // The element tag
	Attr  []Attr  // The element's list of key-value attribute pairs
	Child []Token // The element's child tokens (elements, comments, etc.)
}

// An Attr represents a key-value attribute of an XML element.
type Attr struct {
	Key   string
	Value string
}

// A Comment represents an XML comment.
type Comment struct {
	Data string
}

// CharData represents character data within XML.
type CharData struct {
	Data       string
	whitespace bool
}

// A ProcInst represents an XML processing instruction.
type ProcInst struct {
	Target string
	Inst   string
}

// NewDocument creates an empty XML document and returns it.
func NewDocument() *Document {
	d := new(Document)
	d.Child = make([]Token, 0)
	return d
}

// ReadFrom reads XML from the reader r and adds the result as
// a new child of the receiving document.
func (d *Document) ReadFrom(r io.Reader) error {
	return d.Element.ReadFrom(r)
}

// WriteTo serializes an XML document into the writer w.
func (d *Document) WriteTo(w io.Writer) error {
	b := bufio.NewWriter(w)
	for _, c := range d.Child {
		c.writeTo(b)
	}
	return b.Flush()
}

// Indent modifies the document's element tree by inserting
// CharData entities containing carriage returns and indentation.
// The amount of indenting per depth level is equal to spaces.
// Use etree.NoIndent for spaces if you want no indentation at all.
func (d *Document) Indent(spaces int) {
	d.stripIndent()
	n := len(d.Child)
	if n == 0 {
		return
	}

	newChild := make([]Token, n*2-1)
	for i, c := range d.Child {
		j := i * 2
		newChild[j] = c
		if j+1 < len(newChild) {
			newChild[j+1] = newIndentCharData(0, spaces)
		}
		if e, ok := c.(*Element); ok {
			e.indent(1, spaces)
		}
	}
	d.Child = newChild
}

// NewElement creates an XML element with the specified name.
// In most cases, you should use NewDocument and create elements
// with the CreateElement function.
func NewElement(tag string) *Element {
	return &Element{
		Tag:   tag,
		Attr:  make([]Attr, 0),
		Child: make([]Token, 0),
	}
}

// Text returns the characters immediately following the element's
// opening tag.
func (e *Element) Text() string {
	if len(e.Child) == 0 {
		return ""
	}
	if cd, ok := e.Child[0].(*CharData); ok {
		return cd.Data
	} else {
		return ""
	}
}

// SetText replaces an element's subsidiary CharData text with a new
// string.
func (e *Element) SetText(text string) {
	if len(e.Child) > 0 {
		if cd, ok := e.Child[0].(*CharData); ok {
			cd.Data = text
			return
		}
	}
	e.Child = append(e.Child, nil)
	copy(e.Child[1:], e.Child[0:])
	c := newCharData(text, false)
	e.Child[0] = c
}

// CreateElement creates a child element of the receiving element and
// gives it the specified name.
func (e *Element) CreateElement(name string) *Element {
	c := NewElement(name)
	e.addChild(c)
	return c
}

// An element stack is a simple stack of elements used by ReadFrom.
type elementStack []*Element

func (s *elementStack) push(e *Element) {
	*s = append(*s, e)
}

func (s *elementStack) pop() {
	(*s)[len(*s)-1] = nil
	*s = (*s)[:len(*s)-1]
}

func (s *elementStack) peek() *Element {
	return (*s)[len(*s)-1]
}

// ReadFrom reads XML from the reader r and stores the result as
// a new child of the receiving element.
func (e *Element) ReadFrom(r io.Reader) error {
	stack := elementStack{e}
	dec := xml.NewDecoder(r)
	for {
		t, err := dec.RawToken()
		switch {
		case err == io.EOF:
			return nil
		case err != nil:
			return err
		case len(stack) == 0:
			return ErrInvalidFormat
		}

		top := stack.peek()

		switch t := t.(type) {
		case xml.StartElement:
			e := top.CreateElement(t.Name.Local)
			for _, a := range t.Attr {
				e.CreateAttr(a.Name.Local, a.Value)
			}
			stack.push(e)
		case xml.EndElement:
			stack.pop()
		case xml.CharData:
			data := string(t)
			top.createCharData(data, isWhitespace(data))
		case xml.Comment:
			top.CreateComment(string(t))
		case xml.ProcInst:
			top.CreateProcInst(t.Target, string(t.Inst))
		}
	}
}

// WriteTo serializes the element and its children as XML into
// the writer w.
func (e *Element) WriteTo(w io.Writer) error {
	b := bufio.NewWriter(w)
	e.writeTo(b)
	return b.Flush()
}

// SelectAttr finds an element attribute matching the requested key
// and returns its value if found.
func (e *Element) SelectAttr(key string) (value string, found bool) {
	for _, a := range e.Attr {
		if a.Key == key {
			return a.Value, true
		}
	}
	return "", false
}

// SelectElement returns the first child element with the given tag.
func (e *Element) SelectElement(tag string) *Element {
	for _, ce := range e.Child {
		if c, ok := ce.(*Element); ok && c.Tag == tag {
			return c
		}
	}
	return nil
}

// SelectElements returns a slice of all child elements with the given tag.
func (e *Element) SelectElements(tag string) []*Element {
	elements := make([]*Element, 0)
	for _, ce := range e.Child {
		if c, ok := ce.(*Element); ok && c.Tag == tag {
			elements = append(elements, c)
		}
	}
	return elements
}

// ChildElements returns all elements that are children of the
// receiving element.
func (e *Element) ChildElements() []*Element {
	elements := make([]*Element, 0)
	for _, c := range e.Child {
		if e, ok := c.(*Element); ok {
			elements = append(elements, e)
		}
	}
	return elements
}

// Indent modifies the element's element tree by inserting
// CharData entities containing carriage returns and indentation.
// The amount of indenting per depth level is equal to spaces.
// Use etree.NoIndent for spaces if you want no indentation at all.
func (e *Element) Indent(spaces int) {
	e.indent(1, spaces)
}

// indent recursively inserts proper indentation between an
// XML element's child tokens.
func (e *Element) indent(depth, spaces int) {
	e.stripIndent()
	n := len(e.Child)
	if n == 0 {
		return
	}

	oldChild := e.Child
	e.Child = make([]Token, 0, n*2+1)
	isCharData := false
	for _, c := range oldChild {
		_, isCharData = c.(*CharData)
		if !isCharData && spaces >= 0 {
			e.addChild(newIndentCharData(depth, spaces))
		}
		e.addChild(c)
		if ce, ok := c.(*Element); ok {
			ce.indent(depth+1, spaces)
		}
	}
	if !isCharData && spaces >= 0 {
		e.addChild(newIndentCharData(depth-1, spaces))
	}
}

// stripIndent removes any previously inserted indentation.
func (e *Element) stripIndent() {
	// Count the number of non-indent child tokens
	n := len(e.Child)
	for _, c := range e.Child {
		if cd, ok := c.(*CharData); ok && cd.whitespace {
			n--
		}
	}
	if n == len(e.Child) {
		return
	}

	// Strip out indent CharData
	newChild := make([]Token, n)
	j := 0
	for _, c := range e.Child {
		if cd, ok := c.(*CharData); ok && cd.whitespace {
			continue
		}
		newChild[j] = c
		j++
	}
	e.Child = newChild
}

// writeTo serializes the element to the writer w.
func (e *Element) writeTo(w *bufio.Writer) {
	w.WriteByte('<')
	w.WriteString(e.Tag)
	for _, a := range e.Attr {
		w.WriteByte(' ')
		a.writeTo(w)
	}
	if len(e.Child) > 0 {
		w.WriteString(">")
		for _, c := range e.Child {
			c.writeTo(w)
		}
		w.Write([]byte{'<', '/'})
		w.WriteString(e.Tag)
		w.WriteByte('>')
	} else {
		w.Write([]byte{'/', '>'})
	}
}

// addChild adds a child token to the receiving element.
func (e *Element) addChild(t Token) {
	e.Child = append(e.Child, t)
}

// CreateAttr creates an attribute and adds it to the receiving element.
func (e *Element) CreateAttr(key, value string) Attr {
	a := Attr{key, value}
	e.Attr = append(e.Attr, a)
	return a
}

// CreateElementIterator creates a child element iterator that iterates
// through all child elements with the given tag.
func (e *Element) CreateElementIterator(tag string) *ElementIterator {
	i := &ElementIterator{
		parent: e,
		tag:    tag,
		index:  -1,
	}
	i.Next()
	return i
}

// writeTo serializes the attribute to the writer.
func (a *Attr) writeTo(w *bufio.Writer) {
	w.WriteString(a.Key)
	w.WriteString(`="`)
	w.WriteString(a.Value)
	w.WriteByte('"')
}

// newCharData creates an XML character data entity.
func newCharData(data string, whitespace bool) *CharData {
	return &CharData{Data: data, whitespace: whitespace}
}

// CreateCharData creates an XML character data entity and adds it
// as a child of the receiving element.
func (e *Element) CreateCharData(data string) *CharData {
	return e.createCharData(data, false)
}

// CreateCharData creates an XML character data entity and adds it
// as a child of the receiving element.
func (e *Element) createCharData(data string, whitespace bool) *CharData {
	c := newCharData(data, whitespace)
	e.addChild(c)
	return c
}

// writeTo serializes the character data entity to the writer.
func (c *CharData) writeTo(w *bufio.Writer) {
	w.WriteString(escape(c.Data))
}

// NewComment creates an XML comment.
func newComment(comment string) *Comment {
	return &Comment{Data: comment}
}

// CreateComment creates an XML comment and adds it as a child of the
// receiving element.
func (e *Element) CreateComment(comment string) *Comment {
	c := newComment(comment)
	e.addChild(c)
	return c
}

// writeTo serialies the comment to the writer.
func (c *Comment) writeTo(w *bufio.Writer) {
	w.WriteString("<!--")
	w.WriteString(c.Data)
	w.WriteString("-->")
}

// newProcInst creates a new processing instruction.
func newProcInst(target, inst string) *ProcInst {
	return &ProcInst{Target: target, Inst: inst}
}

// CreateProcInst creates a processing instruction and adds it as a
// child of the receiving element
func (e *Element) CreateProcInst(target, inst string) *ProcInst {
	p := newProcInst(target, inst)
	e.addChild(p)
	return p
}

// writeTo serializes the processing instruction to the writer.
func (p *ProcInst) writeTo(w *bufio.Writer) {
	w.WriteString("<?")
	w.WriteString(p.Target)
	w.WriteByte(' ')
	w.WriteString(p.Inst)
	w.WriteString("?>")
}

// newIndentCharData returns the indentation CharData token for the given
// depth level with the given number of spaces per level.
func newIndentCharData(depth, spaces int) *CharData {
	return newCharData(crSpaces(depth*spaces), true)
}

// An ElementIterator allows the caller to iterate through the child elements
// of an element.
type ElementIterator struct {
	Element *Element
	parent  *Element
	tag     string
	index   int
}

// Valid returns true if the ElementIterator currently points to a valid element.
func (i *ElementIterator) Valid() bool {
	return i.Element != nil
}

// Next advances to the next child element with the appropriate tag.
func (i *ElementIterator) Next() {
	for {
		i.index++
		if i.index == len(i.parent.Child) {
			i.Element = nil
			return
		}
		c := i.parent.Child[i.index]
		if n, ok := c.(*Element); ok && n.Tag == i.tag {
			i.Element = n
			return
		}
	}
}
<|endoftext|>


<commit_before>package redisserver

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"Go-Redis-Admin/src/common/request"
	"Go-Redis-Admin/src/common/response"
)

type redisapi struct {
	input request.Input
	output response.Output
	Redisconn redis.Conn
}

func (re *redisapi) Connect() {
	if re.input.Request.Method!="POST"{
		fmt.Println("请求错误")
	}
	body,_:=re.input.InputBody()
	fmt.Println(body)
	re.input.Request.ParseForm()
	var network string=re.input.Request.FormValue("network")
	var address string=re.input.Request.FormValue("address")
	var password string=re.input.Request.FormValue("password")
	option:=redis.DialOption{}
	if password!=""{
		option=redis.DialPassword(password)
	}
	conn, err := redis.Dial(network, address,option)
	if err != nil {
		fmt.Println("connect error:", err.Error())
	} else {
		fmt.Println("connect redis success")
	}
	re.Redisconn = conn
	re.output.ResponseWriter.WriteHeader(200)
	//c:=NewConnection(conn)
	//conn.Close()
}
func (re *redisapi) Ping() {
	reply,err:=re.Redisconn.Do("PING","test")
	if err!=nil{
		fmt.Println(err.Error())
	}else {
		fmt.Println(redis.String(reply,err))
	}
}
func (re *redisapi)Set(){
	var args []interface{}
	reply,err:=re.Redisconn.Do("SET",args)
	redis.String(reply,err)
	if err!=nil {
		fmt.Println(err.Error())
	}else {
		fmt.Println(reply)
	}
}

func (re *redisapi) Get(){
	var key string
	reply,err:=re.Redisconn.Do("GET",key)
	if err!=nil{
		fmt.Println(err.Error())
	}else {
		fmt.Println(reply)
	}

}

func (re *redisapi) Delete(){
	var args []interface{}
	reply,err:=re.Redisconn.Do("DEL",args)
	if err!=nil{
		fmt.Println(err.Error())
	}else {
		fmt.Println(reply)
	}
}
<commit_msg>modify redisapi<commit_after>package redisserver

import (
	"fmt"
	"github.com/garyburd/redigo/redis"
	"Go-Redis-Admin/src/common/request"
	"Go-Redis-Admin/src/common/response"
)

type redisapi struct {
	input request.Input
	output response.Output
	Redisconn redis.Conn
}

func (re *redisapi) Connect() {
	if re.input.Request.Method!="POST"{
		fmt.Println("请求错误")
	}
	body,_:=re.input.InputBody()
	fmt.Println(body)
	re.input.Request.ParseForm()
	var network string=re.input.Request.FormValue("network")
	var address string=re.input.Request.FormValue("address")
	var password string=re.input.Request.FormValue("password")
	option:=redis.DialOption{}
	if password!=""{
		option=redis.DialPassword(password)
	}
	conn, err := redis.Dial(network, address,option)
	if err != nil {
		fmt.Println("connect error:", err.Error())
	} else {
		fmt.Println("connect redis success")
	}
	re.Redisconn = conn
	re.output.ResponseWriter.WriteHeader(200)
	//c:=NewConnection(conn)
	//conn.Close()
}
func (re *redisapi) Ping() {
	reply,err:=re.Redisconn.Do("PING","test")
	if err!=nil{
		fmt.Println(err.Error())
	}else {
		fmt.Println(redis.String(reply,err))
	}
	result,_:=redis.String(reply,err)
	re.output.WriteString(result)
}
func (re *redisapi)Set(){
	var args []interface{}
	reply,err:=re.Redisconn.Do("SET",args)
	redis.String(reply,err)
	if err!=nil {
		fmt.Println(err.Error())
	}else {
		fmt.Println(reply)
	}
	result,_:=redis.String(reply,err)
	re.output.WriteString(result)
}

func (re *redisapi) Get(){
	var key string
	reply,err:=re.Redisconn.Do("GET",key)
	if err!=nil{
		fmt.Println(err.Error())
	}else {
		fmt.Println(reply)
	}

}

func (re *redisapi) Delete(){
	var args []interface{}
	reply,err:=re.Redisconn.Do("DEL",args)
	if err!=nil{
		fmt.Println(err.Error())
	}else {
		fmt.Println(reply)
	}
}
func(re *redisapi)Pool(){

}<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/log"
)

const (
	namespace = "apache" // For Prometheus metrics.
)

var (
	listeningAddress = flag.String("telemetry.address", ":9117", "Address on which to expose metrics.")
	metricsEndpoint  = flag.String("telemetry.endpoint", "/metrics", "Path under which to expose metrics.")
	scrapeURI        = flag.String("scrape_uri", "http://localhost/server-status/?auto", "URI to apache stub status page.")
	insecure         = flag.Bool("insecure", false, "Ignore server certificate if using https.")
)

type Exporter struct {
	URI    string
	mutex  sync.Mutex
	client *http.Client

	up             prometheus.Gauge
	scrapeFailures prometheus.Counter
	accessesTotal  prometheus.Counter
	kBytesTotal    prometheus.Counter
	uptime         prometheus.Counter
	workers        *prometheus.GaugeVec
	scoreboard     *prometheus.GaugeVec
	connections    *prometheus.GaugeVec
}

func NewExporter(uri string) *Exporter {
	return &Exporter{
		URI: uri,
		up: prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "up",
			Help:      "Could the apache server be reached.",
		}),
		scrapeFailures: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "exporter_scrape_failures_total",
			Help:      "Number of errors while scraping apache.",
		}),
		accessesTotal: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "accesses_total",
			Help:      "Current total apache accesses",
		}),
		kBytesTotal: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "sent_kilobytes_total",
			Help:      "Current total kbytes sent",
		}),
		uptime: prometheus.NewCounter(prometheus.CounterOpts{
			Namespace: namespace,
			Name:      "uptime_seconds_total",
			Help:      "Current uptime in seconds",
		}),
		workers: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "workers",
			Help:      "Apache worker statuses",
		},
			[]string{"state"},
		),
		scoreboard: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "scoreboard",
			Help:      "Apache scoreboard statuses",
		},
			[]string{"state"},
		),
		connections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "connections",
			Help:      "Apache connection statuses",
		},
			[]string{"state"},
		),
		client: &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: *insecure},
			},
		},
	}
}

func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
	e.up.Describe(ch)
	e.scrapeFailures.Describe(ch)
	e.accessesTotal.Describe(ch)
	e.kBytesTotal.Describe(ch)
	e.uptime.Describe(ch)
	e.workers.Describe(ch)
	e.scoreboard.Describe(ch)
	e.connections.Describe(ch)
}

// Split colon separated string into two fields
func splitkv(s string) (string, string) {

	if len(s) == 0 {
		return s, s
	}

	slice := strings.SplitN(s, ":", 2)

	if len(slice) == 1 {
		return slice[0], ""
	}

	return strings.TrimSpace(slice[0]), strings.TrimSpace(slice[1])
}

func (e *Exporter) updateScoreboard(scoreboard string) {
	e.scoreboard.Reset()
	for _, worker_status := range scoreboard {
		s := string(worker_status)
		switch {
		case s == "_":
			e.scoreboard.WithLabelValues("idle").Inc()
		case s == "S":
			e.scoreboard.WithLabelValues("startup").Inc()
		case s == "R":
			e.scoreboard.WithLabelValues("read").Inc()
		case s == "W":
			e.scoreboard.WithLabelValues("reply").Inc()
		case s == "K":
			e.scoreboard.WithLabelValues("keepalive").Inc()
		case s == "D":
			e.scoreboard.WithLabelValues("dns").Inc()
		case s == "C":
			e.scoreboard.WithLabelValues("closing").Inc()
		case s == "L":
			e.scoreboard.WithLabelValues("logging").Inc()
		case s == "G":
			e.scoreboard.WithLabelValues("graceful_stop").Inc()
		case s == "I":
			e.scoreboard.WithLabelValues("idle_cleanup").Inc()
		case s == ".":
			e.scoreboard.WithLabelValues("open_slot").Inc()
		}
	}
}

func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
	resp, err := e.client.Get(e.URI)
	if err != nil {
		e.up.Set(0)
		e.up.Collect(ch)
		return fmt.Errorf("Error scraping apache: %v", err)
	}
	e.up.Set(1)
	e.up.Collect(ch)

	data, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if resp.StatusCode != 200 {
		if err != nil {
			data = []byte(err.Error())
		}
		return fmt.Errorf("Status %s (%d): %s", resp.Status, resp.StatusCode, data)
	}

	lines := strings.Split(string(data), "\n")

	connectionInfo := false

	for _, l := range lines {
		key, v := splitkv(l)
		if err != nil {
			continue
		}

		switch {
		case key == "Total Accesses":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.accessesTotal.Set(val)
			e.accessesTotal.Collect(ch)
		case key == "Total kBytes":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.kBytesTotal.Set(val)
			e.kBytesTotal.Collect(ch)
		case key == "Uptime":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.uptime.Set(val)
			e.uptime.Collect(ch)
		case key == "BusyWorkers":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.workers.WithLabelValues("busy").Set(val)
		case key == "IdleWorkers":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.workers.WithLabelValues("idle").Set(val)
		case key == "Scoreboard":
			e.updateScoreboard(v)
			e.scoreboard.Collect(ch)
		case key == "ConnsTotal":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.connections.WithLabelValues("total").Set(val)
			connectionInfo = true
		case key == "ConnsAsyncWriting":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.connections.WithLabelValues("writing").Set(val)
			connectionInfo = true
		case key == "ConnsAsyncKeepAlive":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}
			e.connections.WithLabelValues("keepalive").Set(val)
			connectionInfo = true
		case key == "ConnsAsyncClosing":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}
			e.connections.WithLabelValues("closing").Set(val)
			connectionInfo = true
		}

	}

	e.workers.Collect(ch)
	if connectionInfo {
		e.connections.Collect(ch)
	}

	return nil
}

func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
	e.mutex.Lock() // To protect metrics from concurrent collects.
	defer e.mutex.Unlock()
	if err := e.collect(ch); err != nil {
		log.Printf("Error scraping apache: %s", err)
		e.scrapeFailures.Inc()
		e.scrapeFailures.Collect(ch)
	}
	return
}

func main() {
	flag.Parse()

	exporter := NewExporter(*scrapeURI)
	prometheus.MustRegister(exporter)

	log.Printf("Starting Server: %s", *listeningAddress)
	http.Handle(*metricsEndpoint, prometheus.Handler())
	log.Fatal(http.ListenAndServe(*listeningAddress, nil))
}
<commit_msg>Change `NewCounter` to `MustNewConstMetric` for some metrics<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/log"
)

const (
	namespace = "apache" // For Prometheus metrics.
)

var (
	listeningAddress = flag.String("telemetry.address", ":9117", "Address on which to expose metrics.")
	metricsEndpoint  = flag.String("telemetry.endpoint", "/metrics", "Path under which to expose metrics.")
	scrapeURI        = flag.String("scrape_uri", "http://localhost/server-status/?auto", "URI to apache stub status page.")
	insecure         = flag.Bool("insecure", false, "Ignore server certificate if using https.")
)

type Exporter struct {
	URI    string
	mutex  sync.Mutex
	client *http.Client

	up             *prometheus.Desc
	scrapeFailures prometheus.Counter
	accessesTotal  *prometheus.Desc
	kBytesTotal    *prometheus.Desc
	uptime         *prometheus.Desc
	workers        *prometheus.GaugeVec
	scoreboard     *prometheus.GaugeVec
	connections    *prometheus.GaugeVec
}

func NewExporter(uri string) *Exporter {
	return &Exporter{
		URI: uri,
		up: prometheus.NewDesc(
                        prometheus.BuildFQName(namespace, "", "up"),
                        "Could the apache server be reached",
                        nil,
			nil),
                scrapeFailures: prometheus.NewCounter(prometheus.CounterOpts{
                        Namespace: namespace,
                        Name:      "exporter_scrape_failures_total",
                        Help:      "Number of errors while scraping apache.",
                }),
                accessesTotal: prometheus.NewDesc(
                        prometheus.BuildFQName(namespace, "", "accesses_total"),
                        "Current total apache accesses",
                        nil,
                        nil),
                kBytesTotal: prometheus.NewDesc(
                        prometheus.BuildFQName(namespace, "", "sent_kilobytes_total"),
                        "Current total kbytes sent",
                        nil,
                        nil),
                uptime: prometheus.NewDesc(
                        prometheus.BuildFQName(namespace, "", "uptime_seconds_total"),
                        "Current uptime in seconds",
                        nil,
                        nil),
		workers: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "workers",
			Help:      "Apache worker statuses",
		},
			[]string{"state"},
		),
		scoreboard: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "scoreboard",
			Help:      "Apache scoreboard statuses",
		},
			[]string{"state"},
		),
		connections: prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Namespace: namespace,
			Name:      "connections",
			Help:      "Apache connection statuses",
		},
			[]string{"state"},
		),
		client: &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: *insecure},
			},
		},
	}
}

func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
        ch <- e.up
        ch <- e.accessesTotal
        ch <- e.kBytesTotal
        ch <- e.uptime
        e.scrapeFailures.Describe(ch)
        e.workers.Describe(ch)
        e.scoreboard.Describe(ch)
        e.connections.Describe(ch)
}

// Split colon separated string into two fields
func splitkv(s string) (string, string) {

	if len(s) == 0 {
		return s, s
	}

	slice := strings.SplitN(s, ":", 2)

	if len(slice) == 1 {
		return slice[0], ""
	}

	return strings.TrimSpace(slice[0]), strings.TrimSpace(slice[1])
}

func (e *Exporter) updateScoreboard(scoreboard string) {
	e.scoreboard.Reset()
	for _, worker_status := range scoreboard {
		s := string(worker_status)
		switch {
		case s == "_":
			e.scoreboard.WithLabelValues("idle").Inc()
		case s == "S":
			e.scoreboard.WithLabelValues("startup").Inc()
		case s == "R":
			e.scoreboard.WithLabelValues("read").Inc()
		case s == "W":
			e.scoreboard.WithLabelValues("reply").Inc()
		case s == "K":
			e.scoreboard.WithLabelValues("keepalive").Inc()
		case s == "D":
			e.scoreboard.WithLabelValues("dns").Inc()
		case s == "C":
			e.scoreboard.WithLabelValues("closing").Inc()
		case s == "L":
			e.scoreboard.WithLabelValues("logging").Inc()
		case s == "G":
			e.scoreboard.WithLabelValues("graceful_stop").Inc()
		case s == "I":
			e.scoreboard.WithLabelValues("idle_cleanup").Inc()
		case s == ".":
			e.scoreboard.WithLabelValues("open_slot").Inc()
		}
	}
}

func (e *Exporter) collect(ch chan<- prometheus.Metric) error {
	resp, err := e.client.Get(e.URI)
	if err != nil {
                ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 0)
		return fmt.Errorf("Error scraping apache: %v", err)
	}
        ch <- prometheus.MustNewConstMetric(e.up, prometheus.GaugeValue, 1)

	data, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if resp.StatusCode != 200 {
		if err != nil {
			data = []byte(err.Error())
		}
		return fmt.Errorf("Status %s (%d): %s", resp.Status, resp.StatusCode, data)
	}

	lines := strings.Split(string(data), "\n")

	connectionInfo := false

	for _, l := range lines {
		key, v := splitkv(l)
		if err != nil {
			continue
		}

		switch {
		case key == "Total Accesses":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

                ch <- prometheus.MustNewConstMetric(e.accessesTotal, prometheus.CounterValue, val)
		case key == "Total kBytes":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

                ch <- prometheus.MustNewConstMetric(e.kBytesTotal, prometheus.CounterValue, val)
		case key == "Uptime":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

                ch <- prometheus.MustNewConstMetric(e.uptime, prometheus.CounterValue, val)
		case key == "BusyWorkers":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.workers.WithLabelValues("busy").Set(val)
		case key == "IdleWorkers":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.workers.WithLabelValues("idle").Set(val)
		case key == "Scoreboard":
			e.updateScoreboard(v)
			e.scoreboard.Collect(ch)
		case key == "ConnsTotal":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.connections.WithLabelValues("total").Set(val)
			connectionInfo = true
		case key == "ConnsAsyncWriting":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}

			e.connections.WithLabelValues("writing").Set(val)
			connectionInfo = true
		case key == "ConnsAsyncKeepAlive":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}
			e.connections.WithLabelValues("keepalive").Set(val)
			connectionInfo = true
		case key == "ConnsAsyncClosing":
			val, err := strconv.ParseFloat(v, 64)
			if err != nil {
				return err
			}
			e.connections.WithLabelValues("closing").Set(val)
			connectionInfo = true
		}

	}

	e.workers.Collect(ch)
	if connectionInfo {
		e.connections.Collect(ch)
	}

	return nil
}

func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
	e.mutex.Lock() // To protect metrics from concurrent collects.
	defer e.mutex.Unlock()
	if err := e.collect(ch); err != nil {
		log.Printf("Error scraping apache: %s", err)
		e.scrapeFailures.Inc()
		e.scrapeFailures.Collect(ch)
	}
	return
}

func main() {
	flag.Parse()

	exporter := NewExporter(*scrapeURI)
	prometheus.MustRegister(exporter)

	log.Printf("Starting Server: %s", *listeningAddress)
	http.Handle(*metricsEndpoint, prometheus.Handler())
	log.Fatal(http.ListenAndServe(*listeningAddress, nil))
}
<|endoftext|>


<commit_before>package zest

import "fmt"

// APIError defines the format of Zest API errors.
type APIError struct {
	// The status code.
	Status int `json:"status"`
	// The description of the API error.
	Description string `json:"description"`
	// A raw description of what triggered the API error.
	Raw string `json:"raw"`
	// The token uniquely identifying the API error.
	ErrorCode string `json:"errorCode"`
}

func (e APIError) Error() string {
	return fmt.Sprintf("%s : %s", e.ErrorCode, e.Description)
}
<commit_msg>Params added in Zest api errors.<commit_after>package zest

import "fmt"

// APIError defines the format of Zest API errors.
type APIError struct {
	// The status code.
	Status int `json:"status"`
	// The description of the API error.
	Description string `json:"description"`
	// A raw description of what triggered the API error.
	Raw string `json:"raw"`
	// The token uniquely identifying the API error.
	ErrorCode string `json:"errorCode"`
	// Additional infos.
	Params map[string]interface{} `json:"params"`
}

func (e APIError) Error() string {
	return fmt.Sprintf("%s : %s", e.ErrorCode, e.Description)
}
<|endoftext|>


<commit_before>// Package awsfaker supports the creation of test doubles for AWS APIs.
//
// To use, build a "backend" for each AWS service that you use.
// The backend should implement the subset of that API that you need.
// Each API call should be implemented as a backend method like this
//	func (b *MyBackend) SomeAction(input *service.SomeActionInput) (*service.SomeActionOutput, error)
// Then initialize an HTTP server for each backend
//	myBackend := &MyBackend{ ... }
//	fakeServer := httptest.NewServer(awsfaker.New(myBackend))
// Finally, initialize your code under test, overriding the default AWS endpoint
// to instead use your fake:
//	app := myapp.App{ AWSEndpointOverride: fakeServer.URL }
//	app.Run()
//
// The method signatures of the backend match those of the service
// interfaces of the package github.com/aws/aws-sdk-go
// For example, a complete implementation of AWS CloudFormation would match the
// CloudFormationAPI interface here: https://godoc.org/github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface
// But your backend need only implement those methods used by your code under test.
package awsfaker

import (
	"fmt"
	"net/http"

	"github.com/rosenhouse/awsfaker/protocols/query"
)

// New returns a new FakeHandler that will dispatch incoming requests to
// the given service backend.
//
// A service backend should represent one AWS service, e.g. EC2
// A backend should implement some or all of the actions of the service.
// The methods on the backend should have signatures like
//	func (b *MyBackend) SomeAction(input *service.SomeActionInput) (*service.SomeActionOutput, error)
// where the input and output types are those in github.com/aws/aws-sdk-go
// When returning an error from a backend method, use the ErrorResponse type.
func New(serviceBackend interface{}) http.Handler {
	return query.New(serviceBackend)
}

// An ErrorResponse represents an error from a backend method
//
// If a backend method returns an instance of ErrorResponse, then ServeHTTP
// will respond with the given HTTPStatusCode and marshal the AWSErrorCode and
// AWSErrorMessage fields appropriately in the HTTP response body.
type ErrorResponse struct {
	AWSErrorCode    string
	AWSErrorMessage string
	HTTPStatusCode  int
}

func (e *ErrorResponse) Error() string {
	return fmt.Sprintf("%T: %+v", e, *e)
}
<commit_msg>Godoc updates<commit_after>// Package awsfaker supports the creation of test doubles for AWS APIs.
//
// To use, build a "backend" for each AWS service that you use.
// The backend should implement the subset of that API that you need.
// Each API call should be implemented as a backend method like this
//	func (b *MyBackend) SomeAction(input *service.SomeActionInput) (*service.SomeActionOutput, error)
// Then initialize an HTTP server for each backend
//	myBackend := &MyBackend{ ... }
//	fakeServer := httptest.NewServer(awsfaker.New(myBackend))
// Finally, initialize your code under test, overriding the default AWS endpoint
// to instead use your fake:
//	app := myapp.App{ AWSEndpointOverride: fakeServer.URL }
//	app.Run()
//
// The method signatures of the backend match those of the service
// interfaces of the package github.com/aws/aws-sdk-go
// For example, a complete implementation of AWS CloudFormation would match the
// CloudFormationAPI interface here: https://godoc.org/github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface
// But your backend need only implement those methods used by your code under test.
package awsfaker

import (
	"fmt"
	"net/http"

	"github.com/rosenhouse/awsfaker/protocols/query"
)

// New returns a new http.Handler that will dispatch incoming requests to
// the given service backend, decoding requests and encoding responses in the
// format used by that service.
//
// A backend should represent one AWS service, e.g. EC2, and implement the subset
// of API actions required by the code under test.
// The methods on the backend should have signatures like
//	func (b *MyBackend) SomeAction(input *service.SomeActionInput) (*service.SomeActionOutput, error)
// where the input and output types are those in github.com/aws/aws-sdk-go
// When returning an error from a backend method, use the ErrorResponse type.
func New(serviceBackend interface{}) http.Handler {
	return query.New(serviceBackend)
}

// An ErrorResponse represents an error from a backend method
//
// If a backend method returns an instance of ErrorResponse, then the handler
// will respond with the given HTTPStatusCode and marshal the AWSErrorCode and
// AWSErrorMessage fields appropriately in the HTTP response body.
type ErrorResponse struct {
	AWSErrorCode    string
	AWSErrorMessage string
	HTTPStatusCode  int
}

func (e *ErrorResponse) Error() string {
	return fmt.Sprintf("%T: %+v", e, *e)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 bigquery

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

	gax "github.com/googleapis/gax-go"

	"cloud.google.com/go/internal"
	"cloud.google.com/go/internal/version"

	"google.golang.org/api/googleapi"
	"google.golang.org/api/option"
	htransport "google.golang.org/api/transport/http"

	"golang.org/x/net/context"
	bq "google.golang.org/api/bigquery/v2"
)

const (
	prodAddr  = "https://www.googleapis.com/bigquery/v2/"
	Scope     = "https://www.googleapis.com/auth/bigquery"
	userAgent = "gcloud-golang-bigquery/20160429"
)

var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo)

func setClientHeader(headers http.Header) {
	headers.Set("x-goog-api-client", xGoogHeader)
}

// Client may be used to perform BigQuery operations.
type Client struct {
	projectID string
	bqs       *bq.Service
}

// NewClient constructs a new Client which can perform BigQuery operations.
// Operations performed via the client are billed to the specified GCP project.
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
	o := []option.ClientOption{
		option.WithEndpoint(prodAddr),
		option.WithScopes(Scope),
		option.WithUserAgent(userAgent),
	}
	o = append(o, opts...)
	httpClient, endpoint, err := htransport.NewClient(ctx, o...)
	if err != nil {
		return nil, fmt.Errorf("bigquery: dialing: %v", err)
	}
	bqs, err := bq.New(httpClient)
	if err != nil {
		return nil, fmt.Errorf("bigquery: constructing client: %v", err)
	}
	bqs.BasePath = endpoint
	c := &Client{
		projectID: projectID,
		bqs:       bqs,
	}
	return c, nil
}

// Close closes any resources held by the client.
// Close should be called when the client is no longer needed.
// It need not be called at program exit.
func (c *Client) Close() error {
	return nil
}

// Calls the Jobs.Insert RPC and returns a Job.
func (c *Client) insertJob(ctx context.Context, job *bq.Job, media io.Reader) (*Job, error) {
	call := c.bqs.Jobs.Insert(c.projectID, job).Context(ctx)
	setClientHeader(call.Header())
	if media != nil {
		call.Media(media)
	}
	var res *bq.Job
	var err error
	invoke := func() error {
		res, err = call.Do()
		return err
	}
	// A job with a client-generated ID can be retried; the presence of the
	// ID makes the insert operation idempotent.
	// We don't retry if there is media, because it is an io.Reader. We'd
	// have to read the contents and keep it in memory, and that could be expensive.
	// TODO(jba): Look into retrying if media != nil.
	if job.JobReference != nil && media == nil {
		err = runWithRetry(ctx, invoke)
	} else {
		err = invoke()
	}
	if err != nil {
		return nil, err
	}
	return bqToJob(res, c)
}

// Convert a number of milliseconds since the Unix epoch to a time.Time.
// Treat an input of zero specially: convert it to the zero time,
// rather than the start of the epoch.
func unixMillisToTime(m int64) time.Time {
	if m == 0 {
		return time.Time{}
	}
	return time.Unix(0, m*1e6)
}

// runWithRetry calls the function until it returns nil or a non-retryable error, or
// the context is done.
// See the similar function in ../storage/invoke.go. The main difference is the
// reason for retrying.
func runWithRetry(ctx context.Context, call func() error) error {
	// These parameters match the suggestions in https://cloud.google.com/bigquery/sla.
	backoff := gax.Backoff{
		Initial:    1 * time.Second,
		Max:        32 * time.Second,
		Multiplier: 2,
	}
	return internal.Retry(ctx, backoff, func() (stop bool, err error) {
		err = call()
		if err == nil {
			return true, nil
		}
		return !retryableError(err), err
	})
}

// This is the correct definition of retryable according to the BigQuery team.
func retryableError(err error) bool {
	e, ok := err.(*googleapi.Error)
	if !ok {
		return false
	}
	var reason string
	if len(e.Errors) > 0 {
		reason = e.Errors[0].Reason
	}
	return reason == "backendError" || reason == "rateLimitExceeded"
}
<commit_msg>bigquery: retry on status code 502<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 bigquery

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

	gax "github.com/googleapis/gax-go"

	"cloud.google.com/go/internal"
	"cloud.google.com/go/internal/version"

	"google.golang.org/api/googleapi"
	"google.golang.org/api/option"
	htransport "google.golang.org/api/transport/http"

	"golang.org/x/net/context"
	bq "google.golang.org/api/bigquery/v2"
)

const (
	prodAddr  = "https://www.googleapis.com/bigquery/v2/"
	Scope     = "https://www.googleapis.com/auth/bigquery"
	userAgent = "gcloud-golang-bigquery/20160429"
)

var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo)

func setClientHeader(headers http.Header) {
	headers.Set("x-goog-api-client", xGoogHeader)
}

// Client may be used to perform BigQuery operations.
type Client struct {
	projectID string
	bqs       *bq.Service
}

// NewClient constructs a new Client which can perform BigQuery operations.
// Operations performed via the client are billed to the specified GCP project.
func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
	o := []option.ClientOption{
		option.WithEndpoint(prodAddr),
		option.WithScopes(Scope),
		option.WithUserAgent(userAgent),
	}
	o = append(o, opts...)
	httpClient, endpoint, err := htransport.NewClient(ctx, o...)
	if err != nil {
		return nil, fmt.Errorf("bigquery: dialing: %v", err)
	}
	bqs, err := bq.New(httpClient)
	if err != nil {
		return nil, fmt.Errorf("bigquery: constructing client: %v", err)
	}
	bqs.BasePath = endpoint
	c := &Client{
		projectID: projectID,
		bqs:       bqs,
	}
	return c, nil
}

// Close closes any resources held by the client.
// Close should be called when the client is no longer needed.
// It need not be called at program exit.
func (c *Client) Close() error {
	return nil
}

// Calls the Jobs.Insert RPC and returns a Job.
func (c *Client) insertJob(ctx context.Context, job *bq.Job, media io.Reader) (*Job, error) {
	call := c.bqs.Jobs.Insert(c.projectID, job).Context(ctx)
	setClientHeader(call.Header())
	if media != nil {
		call.Media(media)
	}
	var res *bq.Job
	var err error
	invoke := func() error {
		res, err = call.Do()
		return err
	}
	// A job with a client-generated ID can be retried; the presence of the
	// ID makes the insert operation idempotent.
	// We don't retry if there is media, because it is an io.Reader. We'd
	// have to read the contents and keep it in memory, and that could be expensive.
	// TODO(jba): Look into retrying if media != nil.
	if job.JobReference != nil && media == nil {
		err = runWithRetry(ctx, invoke)
	} else {
		err = invoke()
	}
	if err != nil {
		return nil, err
	}
	return bqToJob(res, c)
}

// Convert a number of milliseconds since the Unix epoch to a time.Time.
// Treat an input of zero specially: convert it to the zero time,
// rather than the start of the epoch.
func unixMillisToTime(m int64) time.Time {
	if m == 0 {
		return time.Time{}
	}
	return time.Unix(0, m*1e6)
}

// runWithRetry calls the function until it returns nil or a non-retryable error, or
// the context is done.
// See the similar function in ../storage/invoke.go. The main difference is the
// reason for retrying.
func runWithRetry(ctx context.Context, call func() error) error {
	// These parameters match the suggestions in https://cloud.google.com/bigquery/sla.
	backoff := gax.Backoff{
		Initial:    1 * time.Second,
		Max:        32 * time.Second,
		Multiplier: 2,
	}
	return internal.Retry(ctx, backoff, func() (stop bool, err error) {
		err = call()
		if err == nil {
			return true, nil
		}
		return !retryableError(err), err
	})
}

// This is the correct definition of retryable according to the BigQuery team.
func retryableError(err error) bool {
	e, ok := err.(*googleapi.Error)
	if !ok {
		return false
	}
	var reason string
	if len(e.Errors) > 0 {
		reason = e.Errors[0].Reason
	}
	return e.Code == http.StatusBadGateway || reason == "backendError" || reason == "rateLimitExceeded"
}
<|endoftext|>


<commit_before>// Copyright 2015-2018 CoreOS, Inc.
//
// 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 main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"

	"github.com/coreos/mantle/kola"
	"github.com/coreos/mantle/platform"
	"github.com/coreos/mantle/platform/conf"
	"github.com/coreos/mantle/platform/machine/qemu"
)

var (
	cmdSpawn = &cobra.Command{
		Run:    runSpawn,
		PreRun: preRun,
		Use:    "spawn",
		Short:  "spawn a CoreOS instance",
	}

	spawnNodeCount      int
	spawnUserData       string
	spawnDetach         bool
	spawnShell          bool
	spawnRemove         bool
	spawnVerbose        bool
	spawnMachineOptions string
	spawnSetSSHKeys     bool
	spawnSSHKeys        []string
)

func init() {
	cmdSpawn.Flags().IntVarP(&spawnNodeCount, "nodecount", "c", 1, "number of nodes to spawn")
	cmdSpawn.Flags().StringVarP(&spawnUserData, "userdata", "u", "", "file containing userdata to pass to the instances")
	cmdSpawn.Flags().BoolVarP(&spawnDetach, "detach", "t", false, "-kv --shell=false --remove=false")
	cmdSpawn.Flags().BoolVarP(&spawnShell, "shell", "s", true, "spawn a shell in an instance before exiting")
	cmdSpawn.Flags().BoolVarP(&spawnRemove, "remove", "r", true, "remove instances after shell exits")
	cmdSpawn.Flags().BoolVarP(&spawnVerbose, "verbose", "v", false, "output information about spawned instances")
	cmdSpawn.Flags().StringVar(&spawnMachineOptions, "qemu-options", "", "experimental: path to QEMU machine options json")
	cmdSpawn.Flags().BoolVarP(&spawnSetSSHKeys, "keys", "k", false, "add SSH keys from --key options")
	cmdSpawn.Flags().StringSliceVar(&spawnSSHKeys, "key", nil, "path to SSH public key (default: SSH agent + ~/.ssh/id_{rsa,dsa,ecdsa,ed25519}.pub)")
	root.AddCommand(cmdSpawn)
}

func runSpawn(cmd *cobra.Command, args []string) {
	if err := doSpawn(cmd, args); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}

func doSpawn(cmd *cobra.Command, args []string) error {
	var err error

	if spawnDetach {
		spawnSetSSHKeys = true
		spawnVerbose = true
		spawnShell = false
		spawnRemove = false
	}

	if spawnNodeCount <= 0 {
		return fmt.Errorf("Cluster Failed: nodecount must be one or more")
	}

	var userdata *conf.UserData
	if spawnUserData != "" {
		userbytes, err := ioutil.ReadFile(spawnUserData)
		if err != nil {
			return fmt.Errorf("Reading userdata failed: %v", err)
		}
		userdata = conf.Unknown(string(userbytes))
	}
	if spawnSetSSHKeys {
		if userdata == nil {
			userdata = conf.Ignition(`{"ignition": {"version": "2.0.0"}}`)
		}
		// If the user explicitly passed empty userdata, the userdata
		// will be non-nil but Empty, and adding SSH keys will
		// silently fail.
		userdata, err = addSSHKeys(userdata)
		if err != nil {
			return err
		}
	}

	outputDir, err = kola.SetupOutputDir(outputDir, kolaPlatform)
	if err != nil {
		return fmt.Errorf("Setup failed: %v", err)
	}

	cluster, err := kola.NewCluster(kolaPlatform, &platform.RuntimeConfig{
		OutputDir:        outputDir,
		AllowFailedUnits: true,
	})
	if err != nil {
		return fmt.Errorf("Cluster failed: %v", err)
	}

	if spawnRemove {
		defer cluster.Destroy()
	}

	var someMach platform.Machine
	for i := 0; i < spawnNodeCount; i++ {
		var mach platform.Machine
		var err error
		if kolaPlatform == "qemu" && spawnMachineOptions != "" {
			var b []byte
			b, err = ioutil.ReadFile(spawnMachineOptions)
			if err != nil {
				return fmt.Errorf("Could not read machine options: %v", err)
			}

			var machineOpts qemu.MachineOptions
			err = json.Unmarshal(b, &machineOpts)
			if err != nil {
				return fmt.Errorf("Could not unmarshal machine options: %v", err)
			}

			mach, err = cluster.(*qemu.Cluster).NewMachineWithOptions(userdata, machineOpts)
		} else {
			mach, err = cluster.NewMachine(userdata)
		}
		if err != nil {
			return fmt.Errorf("Spawning instance failed: %v", err)
		}

		if spawnVerbose {
			fmt.Printf("Machine %v spawned at %v\n", mach.ID(), mach.IP())
		}

		someMach = mach
	}

	if spawnShell {
		if spawnRemove {
			reader := strings.NewReader(`PS1="\033[0;31m[bound]\033[0m $PS1"` + "\n")
			if err := platform.InstallFile(reader, someMach, "/etc/profile.d/kola-spawn-bound.sh"); err != nil {
				return fmt.Errorf("Setting shell prompt failed: %v", err)
			}
		}
		if err := platform.Manhole(someMach); err != nil {
			return fmt.Errorf("Manhole failed: %v", err)
		}
	}
	return nil
}

func addSSHKeys(userdata *conf.UserData) (*conf.UserData, error) {
	// if no keys specified, use keys from agent plus ~/.ssh/id_{rsa,dsa,ecdsa,ed25519}.pub
	if len(spawnSSHKeys) == 0 {
		// add keys directly from the agent
		agentEnv := os.Getenv("SSH_AUTH_SOCK")
		if agentEnv != "" {
			f, err := net.Dial("unix", agentEnv)
			if err != nil {
				return nil, fmt.Errorf("Couldn't connect to unix socket %q: %v", agentEnv, err)
			}
			defer f.Close()

			agent := agent.NewClient(f)
			keys, err := agent.List()
			if err != nil {
				return nil, fmt.Errorf("Couldn't talk to ssh-agent: %v", err)
			}
			for _, key := range keys {
				userdata = userdata.AddKey(*key)
			}
		}

		// populate list of key files
		userInfo, err := user.Current()
		if err != nil {
			return nil, err
		}
		for _, name := range []string{"id_rsa.pub", "id_dsa.pub", "id_ecdsa.pub", "id_ed25519.pub"} {
			path := filepath.Join(userInfo.HomeDir, ".ssh", name)
			if _, err := os.Stat(path); err == nil {
				spawnSSHKeys = append(spawnSSHKeys, path)
			}
		}
	}

	// read key files, failing if any are missing
	for _, path := range spawnSSHKeys {
		keybytes, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, err
		}
		pkey, comment, _, _, err := ssh.ParseAuthorizedKey(keybytes)
		if err != nil {
			return nil, err
		}
		key := agent.Key{
			Format:  pkey.Type(),
			Blob:    pkey.Marshal(),
			Comment: comment,
		}
		userdata = userdata.AddKey(key)
	}
	return userdata, nil
}
<commit_msg>cmd/kola: fix command line wrapping with [bound] in PS1<commit_after>// Copyright 2015-2018 CoreOS, Inc.
//
// 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 main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/user"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"

	"github.com/coreos/mantle/kola"
	"github.com/coreos/mantle/platform"
	"github.com/coreos/mantle/platform/conf"
	"github.com/coreos/mantle/platform/machine/qemu"
)

var (
	cmdSpawn = &cobra.Command{
		Run:    runSpawn,
		PreRun: preRun,
		Use:    "spawn",
		Short:  "spawn a CoreOS instance",
	}

	spawnNodeCount      int
	spawnUserData       string
	spawnDetach         bool
	spawnShell          bool
	spawnRemove         bool
	spawnVerbose        bool
	spawnMachineOptions string
	spawnSetSSHKeys     bool
	spawnSSHKeys        []string
)

func init() {
	cmdSpawn.Flags().IntVarP(&spawnNodeCount, "nodecount", "c", 1, "number of nodes to spawn")
	cmdSpawn.Flags().StringVarP(&spawnUserData, "userdata", "u", "", "file containing userdata to pass to the instances")
	cmdSpawn.Flags().BoolVarP(&spawnDetach, "detach", "t", false, "-kv --shell=false --remove=false")
	cmdSpawn.Flags().BoolVarP(&spawnShell, "shell", "s", true, "spawn a shell in an instance before exiting")
	cmdSpawn.Flags().BoolVarP(&spawnRemove, "remove", "r", true, "remove instances after shell exits")
	cmdSpawn.Flags().BoolVarP(&spawnVerbose, "verbose", "v", false, "output information about spawned instances")
	cmdSpawn.Flags().StringVar(&spawnMachineOptions, "qemu-options", "", "experimental: path to QEMU machine options json")
	cmdSpawn.Flags().BoolVarP(&spawnSetSSHKeys, "keys", "k", false, "add SSH keys from --key options")
	cmdSpawn.Flags().StringSliceVar(&spawnSSHKeys, "key", nil, "path to SSH public key (default: SSH agent + ~/.ssh/id_{rsa,dsa,ecdsa,ed25519}.pub)")
	root.AddCommand(cmdSpawn)
}

func runSpawn(cmd *cobra.Command, args []string) {
	if err := doSpawn(cmd, args); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}

func doSpawn(cmd *cobra.Command, args []string) error {
	var err error

	if spawnDetach {
		spawnSetSSHKeys = true
		spawnVerbose = true
		spawnShell = false
		spawnRemove = false
	}

	if spawnNodeCount <= 0 {
		return fmt.Errorf("Cluster Failed: nodecount must be one or more")
	}

	var userdata *conf.UserData
	if spawnUserData != "" {
		userbytes, err := ioutil.ReadFile(spawnUserData)
		if err != nil {
			return fmt.Errorf("Reading userdata failed: %v", err)
		}
		userdata = conf.Unknown(string(userbytes))
	}
	if spawnSetSSHKeys {
		if userdata == nil {
			userdata = conf.Ignition(`{"ignition": {"version": "2.0.0"}}`)
		}
		// If the user explicitly passed empty userdata, the userdata
		// will be non-nil but Empty, and adding SSH keys will
		// silently fail.
		userdata, err = addSSHKeys(userdata)
		if err != nil {
			return err
		}
	}

	outputDir, err = kola.SetupOutputDir(outputDir, kolaPlatform)
	if err != nil {
		return fmt.Errorf("Setup failed: %v", err)
	}

	cluster, err := kola.NewCluster(kolaPlatform, &platform.RuntimeConfig{
		OutputDir:        outputDir,
		AllowFailedUnits: true,
	})
	if err != nil {
		return fmt.Errorf("Cluster failed: %v", err)
	}

	if spawnRemove {
		defer cluster.Destroy()
	}

	var someMach platform.Machine
	for i := 0; i < spawnNodeCount; i++ {
		var mach platform.Machine
		var err error
		if kolaPlatform == "qemu" && spawnMachineOptions != "" {
			var b []byte
			b, err = ioutil.ReadFile(spawnMachineOptions)
			if err != nil {
				return fmt.Errorf("Could not read machine options: %v", err)
			}

			var machineOpts qemu.MachineOptions
			err = json.Unmarshal(b, &machineOpts)
			if err != nil {
				return fmt.Errorf("Could not unmarshal machine options: %v", err)
			}

			mach, err = cluster.(*qemu.Cluster).NewMachineWithOptions(userdata, machineOpts)
		} else {
			mach, err = cluster.NewMachine(userdata)
		}
		if err != nil {
			return fmt.Errorf("Spawning instance failed: %v", err)
		}

		if spawnVerbose {
			fmt.Printf("Machine %v spawned at %v\n", mach.ID(), mach.IP())
		}

		someMach = mach
	}

	if spawnShell {
		if spawnRemove {
			reader := strings.NewReader(`PS1="\[\033[0;31m\][bound]\[\033[0m\] $PS1"` + "\n")
			if err := platform.InstallFile(reader, someMach, "/etc/profile.d/kola-spawn-bound.sh"); err != nil {
				return fmt.Errorf("Setting shell prompt failed: %v", err)
			}
		}
		if err := platform.Manhole(someMach); err != nil {
			return fmt.Errorf("Manhole failed: %v", err)
		}
	}
	return nil
}

func addSSHKeys(userdata *conf.UserData) (*conf.UserData, error) {
	// if no keys specified, use keys from agent plus ~/.ssh/id_{rsa,dsa,ecdsa,ed25519}.pub
	if len(spawnSSHKeys) == 0 {
		// add keys directly from the agent
		agentEnv := os.Getenv("SSH_AUTH_SOCK")
		if agentEnv != "" {
			f, err := net.Dial("unix", agentEnv)
			if err != nil {
				return nil, fmt.Errorf("Couldn't connect to unix socket %q: %v", agentEnv, err)
			}
			defer f.Close()

			agent := agent.NewClient(f)
			keys, err := agent.List()
			if err != nil {
				return nil, fmt.Errorf("Couldn't talk to ssh-agent: %v", err)
			}
			for _, key := range keys {
				userdata = userdata.AddKey(*key)
			}
		}

		// populate list of key files
		userInfo, err := user.Current()
		if err != nil {
			return nil, err
		}
		for _, name := range []string{"id_rsa.pub", "id_dsa.pub", "id_ecdsa.pub", "id_ed25519.pub"} {
			path := filepath.Join(userInfo.HomeDir, ".ssh", name)
			if _, err := os.Stat(path); err == nil {
				spawnSSHKeys = append(spawnSSHKeys, path)
			}
		}
	}

	// read key files, failing if any are missing
	for _, path := range spawnSSHKeys {
		keybytes, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, err
		}
		pkey, comment, _, _, err := ssh.ParseAuthorizedKey(keybytes)
		if err != nil {
			return nil, err
		}
		key := agent.Key{
			Format:  pkey.Type(),
			Blob:    pkey.Marshal(),
			Comment: comment,
		}
		userdata = userdata.AddKey(key)
	}
	return userdata, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package tester

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/open-policy-agent/opa/topdown"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/cover"
)

// Reporter defines the interface for reporting test results.
type Reporter interface {

	// Report is called with a channel that will contain test results.
	Report(ch chan *Result) error
}

// PrettyReporter reports test results in a simple human readable format.
type PrettyReporter struct {
	Output  io.Writer
	Verbose bool
}

// Report prints the test report to the reporter's output.
func (r PrettyReporter) Report(ch chan *Result) error {

	dirty := false
	var pass, fail, errs int

	var results, failures []*Result
	for tr := range ch {
		if tr.Pass() {
			pass++
		} else if tr.Error != nil {
			errs++
		} else if tr.Fail {
			fail++
			failures = append(failures, tr)
		}
		results = append(results, tr)
	}

	if fail > 0 && r.Verbose {
		fmt.Fprintln(r.Output, "FAILURES")
		r.hl()

		for _, failure := range failures {
			fmt.Fprintln(r.Output, failure)
			fmt.Fprintln(r.Output)
			topdown.PrettyTrace(newIndentingWriter(r.Output), failure.Trace)
			fmt.Fprintln(r.Output)
		}

		fmt.Fprintln(r.Output, "SUMMARY")
		r.hl()
	}

	// Report individual tests.
	for _, tr := range results {
		if !tr.Pass() || r.Verbose {
			fmt.Fprintln(r.Output, tr)
			dirty = true
		}
		if tr.Error != nil {
			fmt.Fprintf(r.Output, "  %v\n", tr.Error)
		}
	}

	// Report summary of test.
	if dirty {
		r.hl()
	}

	total := pass + fail + errs

	if pass != 0 {
		fmt.Fprintln(r.Output, "PASS:", fmt.Sprintf("%d/%d", pass, total))
	}

	if fail != 0 {
		fmt.Fprintln(r.Output, "FAIL:", fmt.Sprintf("%d/%d", fail, total))
	}

	if errs != 0 {
		fmt.Fprintln(r.Output, "ERROR:", fmt.Sprintf("%d/%d", errs, total))
	}

	return nil
}

func (r PrettyReporter) hl() {
	fmt.Fprintln(r.Output, strings.Repeat("-", 80))
}

// JSONReporter reports test results as array of JSON objects.
type JSONReporter struct {
	Output io.Writer
}

// Report prints the test report to the reporter's output.
func (r JSONReporter) Report(ch chan *Result) error {
	var report []*Result
	for tr := range ch {
		report = append(report, tr)
	}

	bs, err := json.MarshalIndent(report, "", "  ")
	if err != nil {
		return err
	}
	fmt.Fprintln(r.Output, string(bs))
	return nil
}

// JSONCoverageReporter reports coverage as a JSON structure.
type JSONCoverageReporter struct {
	Cover   *cover.Cover
	Modules map[string]*ast.Module
	Output  io.Writer
}

// Report prints the test report to the reporter's output. If any tests fail or
// encounter errors, this function returns an error.
func (r JSONCoverageReporter) Report(ch chan *Result) error {
	for tr := range ch {
		if !tr.Pass() {
			if tr.Error != nil {
				return tr.Error
			}
			return errors.New(tr.String())
		}
	}
	report := r.Cover.Report(r.Modules)
	encoder := json.NewEncoder(r.Output)
	encoder.SetIndent("", "  ")
	return encoder.Encode(report)
}

type indentingWriter struct {
	w io.Writer
}

func newIndentingWriter(w io.Writer) indentingWriter {
	return indentingWriter{
		w: w,
	}
}

func (w indentingWriter) Write(bs []byte) (int, error) {
	var written int
	// insert indentation at the start of every line.
	indent := true
	for _, b := range bs {
		if indent {
			wrote, err := w.w.Write([]byte("  "))
			if err != nil {
				return written, err
			}
			written += wrote
			indent = false
		}
		wrote, err := w.w.Write([]byte{b})
		if err != nil {
			return written, err
		}
		written += wrote
		indent = b == '\n'
	}
	return written, nil
}
<commit_msg>tester/reporter: remove ineffectual assignment<commit_after>// Copyright 2017 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package tester

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/open-policy-agent/opa/topdown"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/cover"
)

// Reporter defines the interface for reporting test results.
type Reporter interface {

	// Report is called with a channel that will contain test results.
	Report(ch chan *Result) error
}

// PrettyReporter reports test results in a simple human readable format.
type PrettyReporter struct {
	Output  io.Writer
	Verbose bool
}

// Report prints the test report to the reporter's output.
func (r PrettyReporter) Report(ch chan *Result) error {

	dirty := false
	var pass, fail, errs int

	var results, failures []*Result
	for tr := range ch {
		if tr.Pass() {
			pass++
		} else if tr.Error != nil {
			errs++
		} else if tr.Fail {
			fail++
			failures = append(failures, tr)
		}
		results = append(results, tr)
	}

	if fail > 0 && r.Verbose {
		fmt.Fprintln(r.Output, "FAILURES")
		r.hl()

		for _, failure := range failures {
			fmt.Fprintln(r.Output, failure)
			fmt.Fprintln(r.Output)
			topdown.PrettyTrace(newIndentingWriter(r.Output), failure.Trace)
			fmt.Fprintln(r.Output)
		}

		fmt.Fprintln(r.Output, "SUMMARY")
		r.hl()
	}

	// Report individual tests.
	for _, tr := range results {
		if !tr.Pass() || r.Verbose {
			fmt.Fprintln(r.Output, tr)
			dirty = true
		}
		if tr.Error != nil {
			fmt.Fprintf(r.Output, "  %v\n", tr.Error)
		}
	}

	// Report summary of test.
	if dirty {
		r.hl()
	}

	total := pass + fail + errs

	if pass != 0 {
		fmt.Fprintln(r.Output, "PASS:", fmt.Sprintf("%d/%d", pass, total))
	}

	if fail != 0 {
		fmt.Fprintln(r.Output, "FAIL:", fmt.Sprintf("%d/%d", fail, total))
	}

	if errs != 0 {
		fmt.Fprintln(r.Output, "ERROR:", fmt.Sprintf("%d/%d", errs, total))
	}

	return nil
}

func (r PrettyReporter) hl() {
	fmt.Fprintln(r.Output, strings.Repeat("-", 80))
}

// JSONReporter reports test results as array of JSON objects.
type JSONReporter struct {
	Output io.Writer
}

// Report prints the test report to the reporter's output.
func (r JSONReporter) Report(ch chan *Result) error {
	var report []*Result
	for tr := range ch {
		report = append(report, tr)
	}

	bs, err := json.MarshalIndent(report, "", "  ")
	if err != nil {
		return err
	}
	fmt.Fprintln(r.Output, string(bs))
	return nil
}

// JSONCoverageReporter reports coverage as a JSON structure.
type JSONCoverageReporter struct {
	Cover   *cover.Cover
	Modules map[string]*ast.Module
	Output  io.Writer
}

// Report prints the test report to the reporter's output. If any tests fail or
// encounter errors, this function returns an error.
func (r JSONCoverageReporter) Report(ch chan *Result) error {
	for tr := range ch {
		if !tr.Pass() {
			if tr.Error != nil {
				return tr.Error
			}
			return errors.New(tr.String())
		}
	}
	report := r.Cover.Report(r.Modules)
	encoder := json.NewEncoder(r.Output)
	encoder.SetIndent("", "  ")
	return encoder.Encode(report)
}

type indentingWriter struct {
	w io.Writer
}

func newIndentingWriter(w io.Writer) indentingWriter {
	return indentingWriter{
		w: w,
	}
}

func (w indentingWriter) Write(bs []byte) (int, error) {
	var written int
	// insert indentation at the start of every line.
	indent := true
	for _, b := range bs {
		if indent {
			wrote, err := w.w.Write([]byte("  "))
			if err != nil {
				return written, err
			}
			written += wrote
		}
		wrote, err := w.w.Write([]byte{b})
		if err != nil {
			return written, err
		}
		written += wrote
		indent = b == '\n'
	}
	return written, nil
}
<|endoftext|>


<commit_before>// Title：表格，及其下属控件
//
// Description:
//
// Author:black
//
// Createtime:2013-08-08 09:29
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-08 09:29 black 创建文档
package lessgo

import (
	"bytes"
	"text/template"
)

type gridPanel struct {
	Entity   string   `xml:"entity,attr"`
	PageSize int      `xml:"pageSize,attr"`
	LoadUrl  string   `xml:"loadUrl,attr"`
	Id       string   `xml:"id,attr"`
	Title    string   `xml:"title,attr"`
	Width    string   `xml:"width,attr"`
	Height   string   `xml:"height,attr"`
	Columns  []column `xml:"column"`
	Actions  []action `xml:"action"`
	Searchs  []search `xml:"search"`
}

//link目前可以支持，直接跳转，打开浏览器新窗口跳转，iframe弹窗，询问提示窗
//linkType=currentPage，
//以下为通用配置
//url 必填
//iconUrl 选填 如果有配置iconUrl，则会生成一个可点击的图标
//loadParamName 选填，不填就不带参数
//loadParamValue 如果loadParamName有值，则此配置必填，可取值为id 或者 this
type column struct {
	Field          string `xml:"field,attr"`
	Desc           string `xml:"desc,attr"`
	LinkType       string `xml:"linkType,attr"`
	Url            string `xml:"url,attr"`
	IconUrl        string `xml:"iconUrl,attr"`
	LoadParamName  string `xml:"loadParamName,attr"`
	LoadParamValue string `xml:"loadParamValue,attr"`
	Format         string `xml:"format,attr"`
	Hidden         string `xml:"hidden,attr"`
}

type action struct {
	Desc         string `xml:"desc,attr"`
	Url          string `xml:"url,attr"`
	ActionParams string `xml:"actionParams,attr"`
	LinkType     string `xml:"linkType,attr"`
}

type search struct {
	Field      string `xml:"field,attr"`
	SearchType string `xml:"searchType,attr"`
	InputType  string `xml:"inputType,attr"`
	LocalData  string `xml:"localData,attr"`
	Desc       string `xml:"desc,attr"`
	Url        string `xml:"url,attr"`
	ValueField string `xml:"valueField,attr"`
	DescField  string `xml:"descField,attr"`
	//存储实际的搜索值
	Value string
}

func (gridpanel gridPanel) generate(entity Entity, terminal, packageName string) []byte {

	var t *template.Template

	var buf bytes.Buffer

	gridpanel.Id = packageName + "." + gridpanel.Id

	runtimeComponentContain[gridpanel.Id] = gridpanel

	t = template.New("gridpanel.html")

	t = t.Funcs(template.FuncMap{
		"getComponentId": getComponentId,
		"compareInt":     CompareInt,
		"compareString":  CompareString,
	})

	t, err := t.ParseFiles("../lessgo/template/component/" + terminal + "/gridpanel.html")

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	data := make(map[string]interface{})

	data["Gridpanel"] = gridpanel
	data["Entity"] = entity
	data["Terminal"] = terminal
	data["SearchLength"] = len(gridpanel.Searchs)
	data["ActionLength"] = len(gridpanel.Actions)

	err = t.Execute(&buf, data)

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	return buf.Bytes()

}
<commit_msg>把列渲染暴露出来<commit_after>// Title：表格，及其下属控件
//
// Description:
//
// Author:black
//
// Createtime:2013-08-08 09:29
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-08-08 09:29 black 创建文档
package lessgo

import (
	"bytes"
	"text/template"
)

type gridPanel struct {
	Entity   string   `xml:"entity,attr"`
	PageSize int      `xml:"pageSize,attr"`
	LoadUrl  string   `xml:"loadUrl,attr"`
	Id       string   `xml:"id,attr"`
	Title    string   `xml:"title,attr"`
	Width    string   `xml:"width,attr"`
	Height   string   `xml:"height,attr"`
	Columns  []column `xml:"column"`
	Actions  []action `xml:"action"`
	Searchs  []search `xml:"search"`
}

//link目前可以支持，直接跳转，打开浏览器新窗口跳转，iframe弹窗，询问提示窗
//linkType=currentPage，
//以下为通用配置
//url 必填
//iconUrl 选填 如果有配置iconUrl，则会生成一个可点击的图标
//loadParamName 选填，不填就不带参数
//loadParamValue 如果loadParamName有值，则此配置必填，可取值为id 或者 this
type column struct {
	Field     string `xml:"field,attr"`
	Desc      string `xml:"desc,attr"`
	Hidden    string `xml:"hidden,attr"`
	Formatter string `xml:"formatter"`
}

type action struct {
	Desc         string `xml:"desc,attr"`
	Url          string `xml:"url,attr"`
	ActionParams string `xml:"actionParams,attr"`
	LinkType     string `xml:"linkType,attr"`
}

type search struct {
	Field      string `xml:"field,attr"`
	SearchType string `xml:"searchType,attr"`
	InputType  string `xml:"inputType,attr"`
	LocalData  string `xml:"localData,attr"`
	Desc       string `xml:"desc,attr"`
	Url        string `xml:"url,attr"`
	ValueField string `xml:"valueField,attr"`
	DescField  string `xml:"descField,attr"`
	//存储实际的搜索值
	Value string
}

func (gridpanel gridPanel) generate(entity Entity, terminal, packageName string) []byte {

	var t *template.Template

	var buf bytes.Buffer

	gridpanel.Id = packageName + "." + gridpanel.Id

	runtimeComponentContain[gridpanel.Id] = gridpanel

	t = template.New("gridpanel.html")

	t = t.Funcs(template.FuncMap{
		"getComponentId": getComponentId,
		"compareInt":     CompareInt,
		"compareString":  CompareString,
	})

	t, err := t.ParseFiles("../lessgo/template/component/" + terminal + "/gridpanel.html")

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	data := make(map[string]interface{})

	data["Gridpanel"] = gridpanel
	data["Entity"] = entity
	data["Terminal"] = terminal
	data["SearchLength"] = len(gridpanel.Searchs)
	data["ActionLength"] = len(gridpanel.Actions)

	err = t.Execute(&buf, data)

	if err != nil {
		Log.Error(err.Error())
		return []byte{}
	}

	return buf.Bytes()

}
<|endoftext|>


<commit_before>package asm

import (
	"bytes"
	"fmt"
	"hash/crc64"
	"io"

	"github.com/vbatts/tar-split/tar/storage"
)

// NewOutputTarStream returns an io.ReadCloser that is an assemble tar archive
// stream.
//
// It takes a storage.FileGetter, for mapping the file payloads that are to be read in,
// and a storage.Unpacker, which has access to the rawbytes and file order
// metadata. With the combination of these two items, a precise assembled Tar
// archive is possible.
func NewOutputTarStream(fg storage.FileGetter, up storage.Unpacker) io.ReadCloser {
	// ... Since these are interfaces, this is possible, so let's not have a nil pointer
	if fg == nil || up == nil {
		return nil
	}
	pr, pw := io.Pipe()
	go func() {
		for {
			entry, err := up.Next()
			if err != nil {
				pw.CloseWithError(err)
				break
			}
			switch entry.Type {
			case storage.SegmentType:
				if _, err := pw.Write(entry.Payload); err != nil {
					pw.CloseWithError(err)
					break
				}
			case storage.FileType:
				if entry.Size == 0 {
					continue
				}
				fh, err := fg.Get(entry.Name)
				if err != nil {
					pw.CloseWithError(err)
					break
				}
				defer fh.Close()
				c := crc64.New(storage.CRCTable)
				tRdr := io.TeeReader(fh, c)
				if _, err := io.Copy(pw, tRdr); err != nil {
					pw.CloseWithError(err)
					break
				}
				if !bytes.Equal(c.Sum(nil), entry.Payload) {
					// I would rather this be a comparable ErrInvalidChecksum or such,
					// but since it's coming through the PipeReader, the context of
					// _which_ file would be lost...
					pw.CloseWithError(fmt.Errorf("file integrity checksum failed for %q", entry.Name))
					break
				}
			}
		}
		pw.Close()
	}()
	return pr
}
<commit_msg>tar/asm: don't defer file closing<commit_after>package asm

import (
	"bytes"
	"fmt"
	"hash/crc64"
	"io"

	"github.com/vbatts/tar-split/tar/storage"
)

// NewOutputTarStream returns an io.ReadCloser that is an assemble tar archive
// stream.
//
// It takes a storage.FileGetter, for mapping the file payloads that are to be read in,
// and a storage.Unpacker, which has access to the rawbytes and file order
// metadata. With the combination of these two items, a precise assembled Tar
// archive is possible.
func NewOutputTarStream(fg storage.FileGetter, up storage.Unpacker) io.ReadCloser {
	// ... Since these are interfaces, this is possible, so let's not have a nil pointer
	if fg == nil || up == nil {
		return nil
	}
	pr, pw := io.Pipe()
	go func() {
		for {
			entry, err := up.Next()
			if err != nil {
				pw.CloseWithError(err)
				break
			}
			switch entry.Type {
			case storage.SegmentType:
				if _, err := pw.Write(entry.Payload); err != nil {
					pw.CloseWithError(err)
					break
				}
			case storage.FileType:
				if entry.Size == 0 {
					continue
				}
				fh, err := fg.Get(entry.Name)
				if err != nil {
					pw.CloseWithError(err)
					break
				}
				c := crc64.New(storage.CRCTable)
				tRdr := io.TeeReader(fh, c)
				if _, err := io.Copy(pw, tRdr); err != nil {
					fh.Close()
					pw.CloseWithError(err)
					break
				}
				if !bytes.Equal(c.Sum(nil), entry.Payload) {
					// I would rather this be a comparable ErrInvalidChecksum or such,
					// but since it's coming through the PipeReader, the context of
					// _which_ file would be lost...
					fh.Close()
					pw.CloseWithError(fmt.Errorf("file integrity checksum failed for %q", entry.Name))
					break
				}
				fh.Close()
			}
		}
		pw.Close()
	}()
	return pr
}
<|endoftext|>


<commit_before>/*
Package stringkey is an implementation of the "github.com/lleo/go-hamt/key"
interface.

Both of these packages are are in separate package namespaces to prevent circular
references between "github.com/lleo/go-hamt" and "github.com/lleo/go-hamt/hamt32"
and/or "github.com/lleo/go-hamt/hamt64".

Additionally, "github.com/lleo/go-hamt/stringKey" is used by the functional
variation of the Hash Array Mapped Trie in "github.com/lleo/go-hamt-fuctional".
*/
package stringkey

import (
	"fmt"

	"github.com/lleo/go-hamt/key"
)

// StringKey is a simple string implementing the key.Key interface.
type StringKey struct {
	key.Base
	str string
}

// New allocates and initializes a StringKey data structure.
func New(str string) *StringKey {
	var k = new(StringKey)

	//Bad for straight assignment  all strings are pointers to structs.
	//But thats ok, cuz all strings are immutable.
	k.str = str

	k.Initialize([]byte(k.str))

	return k
}

// String return a string representation of StringKey data structure.
func (sk StringKey) String() string {
	return fmt.Sprintf("StringKey{%s, str:%q}", sk.Base.String(), sk.str)
}

func (sk StringKey) String30() string {
	return fmt.Sprintf("{%s, %q}", sk.Base.String30(), sk.str)
}

func (sk StringKey) String60() string {
	return fmt.Sprintf("{%s, %q}", sk.Base.String60(), sk.str)
}

// Equals returns true iff the StringKey exactly matches the key passed it. If
// The key.Key passed as an argument is not also a StringKey Equals()
// automatically returns false.
func (sk StringKey) Equals(key key.Key) bool {
	var k, isStrinKey = key.(*StringKey)
	if !isStrinKey {
		panic("type mismatch")
	}
	return sk.str == k.str
}

func (sk StringKey) toByteSlice() []byte {
	return []byte(sk.str)
}

func toByteSlice(str string) []byte {
	return []byte(str)

	////BROKEN: This does not work because StringKey is not a fixed size Struct.
	//var bytebuf bytes.Buffer
	//err := binary.Write(&bytebuf, binary.BigEndian, *sk)
	//if err != nil {
	//	panic(err)
	//}
	//return bytebuf.Bytes()

	////Variation on above: works!
	//var bytebuf bytes.Buffer
	//err := binary.Write(&bytebuf, binary.BigEndian, uint32(0) /* Hash30() */)
	//if err != nil {
	//	panic(err)
	//}
	//err = binary.Write(&bytebuf, binary.BigEndian, []byte(str))
	////err = binary.Write(&bytebuf, binary.BigEndian, str)
	//if err != nil {
	//	panic(err)
	//}
	//return bytebuf.Bytes()

	////ANOTHER variation: does not work, binary.Write() does not like
	//// struct with []byte
	//var d = struct {
	//	hash30 uint32
	//	s      []byte
	//}{0 /*Hash30()*/, []byte(str)}
	//var bytebuf bytes.Buffer
	//err := binary.Write(&bytebuf, binary.BigEndian, d)
	//if err != nil {
	//	panic(err)
	//}
	//return bytebuf.Bytes()

	//ANOTHER IDEA: use encoding/gob; but I don't know that api well enough.

	//ANOThER IDEA: use gopkg.in/mgo.v2/bson; but it requires a third party lib.
}

// Str returns the internal string of StringKey. This allows for read-only
// access to the string field of StringKey.
func (sk StringKey) Str() string {
	return sk.str
}
<commit_msg>removed useless comment<commit_after>/*
Package stringkey is an implementation of the "github.com/lleo/go-hamt/key"
interface.

Both of these packages are are in separate package namespaces to prevent circular
references between "github.com/lleo/go-hamt" and "github.com/lleo/go-hamt/hamt32"
and/or "github.com/lleo/go-hamt/hamt64".

Additionally, "github.com/lleo/go-hamt/stringKey" is used by the functional
variation of the Hash Array Mapped Trie in "github.com/lleo/go-hamt-fuctional".
*/
package stringkey

import (
	"fmt"

	"github.com/lleo/go-hamt/key"
)

// StringKey is a simple string implementing the key.Key interface.
type StringKey struct {
	key.Base
	str string
}

// New allocates and initializes a StringKey data structure.
func New(str string) *StringKey {
	var k = new(StringKey)

	k.str = str

	k.Initialize([]byte(k.str))

	return k
}

// String return a string representation of StringKey data structure.
func (sk StringKey) String() string {
	return fmt.Sprintf("StringKey{%s, str:%q}", sk.Base.String(), sk.str)
}

func (sk StringKey) String30() string {
	return fmt.Sprintf("{%s, %q}", sk.Base.String30(), sk.str)
}

func (sk StringKey) String60() string {
	return fmt.Sprintf("{%s, %q}", sk.Base.String60(), sk.str)
}

// Equals returns true iff the StringKey exactly matches the key passed it. If
// The key.Key passed as an argument is not also a StringKey Equals()
// automatically returns false.
func (sk StringKey) Equals(key key.Key) bool {
	var k, isStrinKey = key.(*StringKey)
	if !isStrinKey {
		panic("type mismatch")
	}
	return sk.str == k.str
}

func (sk StringKey) toByteSlice() []byte {
	return []byte(sk.str)
}

func toByteSlice(str string) []byte {
	return []byte(str)

	////BROKEN: This does not work because StringKey is not a fixed size Struct.
	//var bytebuf bytes.Buffer
	//err := binary.Write(&bytebuf, binary.BigEndian, *sk)
	//if err != nil {
	//	panic(err)
	//}
	//return bytebuf.Bytes()

	////Variation on above: works!
	//var bytebuf bytes.Buffer
	//err := binary.Write(&bytebuf, binary.BigEndian, uint32(0) /* Hash30() */)
	//if err != nil {
	//	panic(err)
	//}
	//err = binary.Write(&bytebuf, binary.BigEndian, []byte(str))
	////err = binary.Write(&bytebuf, binary.BigEndian, str)
	//if err != nil {
	//	panic(err)
	//}
	//return bytebuf.Bytes()

	////ANOTHER variation: does not work, binary.Write() does not like
	//// struct with []byte
	//var d = struct {
	//	hash30 uint32
	//	s      []byte
	//}{0 /*Hash30()*/, []byte(str)}
	//var bytebuf bytes.Buffer
	//err := binary.Write(&bytebuf, binary.BigEndian, d)
	//if err != nil {
	//	panic(err)
	//}
	//return bytebuf.Bytes()

	//ANOTHER IDEA: use encoding/gob; but I don't know that api well enough.

	//ANOThER IDEA: use gopkg.in/mgo.v2/bson; but it requires a third party lib.
}

// Str returns the internal string of StringKey. This allows for read-only
// access to the string field of StringKey.
func (sk StringKey) Str() string {
	return sk.str
}
<|endoftext|>