<commit_before>package main

import (
  "bufio"
  "fmt"
  "launchpad.net/xmlpath"
  "log"
  "os"
  "regexp"
  "strings"
)

type Command struct {
  Cmd        string
  Parameters []string
}

type Book struct {
  Title  string
  Editor string
  Year   int
  Page   int
  Isbn   string
}

type Quote struct {
  Text   string
  Author string
  Book   Book
  Topic  string
}

func markupExtractor(body string) []Command {
  markup, _ := regexp.Compile("(?s){{[^}]+}}")

  strCommands := markup.FindAllString(body, -1)

  commands := make([]Command, len(strCommands))

  for i, cmd := range strCommands {
    cmd = cmd[2 : len(cmd)-2]
    args := strings.Split(cmd, "|")
    cmd := strings.ToLower(args[0])

    commands[i] = Command{Cmd: cmd, Parameters: args[1:]}
  }
  return commands
}

func main() {
  pageXPath := xmlpath.MustCompile("/mediawiki/page")
  textXPath := xmlpath.MustCompile(("revision/text"))
  //  fi, err := os.Open("frwikiquote-20140622-pages-articles-multistream.xml")
  fi, err := os.Open("sample.xml")

  if err != nil {

    panic(err)
  }
  // close fi on exit and check for its returned error
  defer func() {
    if err := fi.Close(); err != nil {
      panic(err)
    }
  }()
  // make a read buffer
  r := bufio.NewReader(fi)

  root, err := xmlpath.Parse(r)
  if err != nil {
    log.Fatal(err)
  }
  iter := pageXPath.Iter(root)
  for iter.Next() {
    page := iter.Node()
    content, _ := textXPath.String(page)
    commands := markupExtractor(content)
    var buffer *Command = nil
    for _, cmd := range commands {
      if len(cmd.Cmd) > 2 && cmd.Cmd[0:4] == "réf" {
        if buffer != nil {
          fmt.Println("Quote")
        } else {
          fmt.Println("Found ref without quote")
          fmt.Println(cmd)
        }
        buffer = nil
      } else if strings.Index(cmd.Cmd, "citation") == 0 {
        buffer = &cmd
      } else {
        fmt.Println("Unknown command")
        fmt.Println(cmd.Cmd)
        buffer = nil
      }
    }
  }
}
<commit_msg>Now we dump the statistics<commit_after>package main

import (
  "bufio"
  "fmt"
  "launchpad.net/xmlpath"
  "log"
  "os"
  "regexp"
  "sort"
  "strings"
)

type Command struct {
  Cmd            string
  Arguments      []string
  NamedArguments map[string]string
}

func (cmd *Command) ArgOrEmpty(key string) string {
  return cmd.ArgOrElse(key, "")
}

func (cmd *Command) ArgOrElse(key string, def string) string {
  ret, has := cmd.NamedArguments[key]
  if !has {
    return def
  }
  return ret
}

type Book struct {
  Title  string
  Author string
  Editor string
  Year   string
  Page   string
  Isbn   string
}

type Quote struct {
  Text   string
  Author string
  Book   Book
}

type BookQuote struct {
  Book  Book
  Quote Quote
}

func (bq *BookQuote) ToString() string {
  var out string
  out = fmt.Sprintf("Quote: \"%s\", by %s, from %s, page, %d published in %d", bq.Quote.Text, bq.Quote.Author, bq.Book.Title, bq.Book.Page, bq.Book.Year)
  return out
}

// Thank you andrew https://groups.google.com/d/msg/golang-nuts/FT7cjmcL7gw/Gj4_aEsE_IsJ
// A data structure to hold a key/value pair.
type Pair struct {
  Key   string
  Value int
}

// A slice of Pairs that implements sort.Interface to sort by Value.
type PairList []Pair

func (p PairList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p PairList) Len() int           { return len(p) }
func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }

// A function to turn a map into a PairList, then sort and return it.
func sortMapByValue(m map[string]int) PairList {
  p := make(PairList, len(m))
  i := 0
  for k, v := range m {
    p[i] = Pair{k, v}
    i += 1
  }
  sort.Sort(sort.Reverse(p))
  return p
}

func markupExtractor(body string) []Command {
  markup := regexp.MustCompile("(?s){{[^}]+}}")
  param := regexp.MustCompile("([^=]+)=(.*)")

  strCommands := markup.FindAllString(body, -1)

  commands := make([]Command, len(strCommands))
  pos := 0

  for _, cmd := range strCommands {
    cmd = cmd[2 : len(cmd)-2]

    arguments := make([]string, 10000)
    argumentsIndex := 0
    kvArguments := make(map[string]string, 1000)

    for _, arg := range strings.Split(cmd, "|") {
      kv := param.FindStringSubmatch(arg)
      if len(kv) == 3 {
        key := strings.TrimSpace(strings.ToLower(kv[1]))
        val, exists := kvArguments[key]
        if exists && val != kv[0] {
          // FIXME: handle the issue
          // panic(fmt.Sprintf("Parameter %s already exists with value \"%s\", here wants : \"%s\"", key, val, kv[0]))
        } else {
          kvArguments[key] = kv[2]
        }
      } else {
        arguments[argumentsIndex] = arg
        argumentsIndex += 1
      }
    }

    cmd := strings.TrimSpace(strings.ToLower(arguments[0]))
    // Ignore the empty command
    if cmd != "" {
      commands[pos] = Command{Cmd: cmd, Arguments: arguments[1:], NamedArguments: kvArguments}
      pos += 1
    }
  }
  return commands
}

func BuildQuote(qCommand Command, reference Command) {
  quote, hasQuote := qCommand.NamedArguments["citation"]
  if !hasQuote {
    quote = qCommand.Arguments[0]
    hasQuote = true
  }

  author := reference.ArgOrEmpty("auteur")
  title := reference.ArgOrEmpty("titre")
  page := reference.ArgOrEmpty("page")
  editor := reference.ArgOrEmpty("éditeur")
  year := reference.ArgOrEmpty("année")
  isbn := reference.ArgOrEmpty("isbn")

  if quote == "" || author == "" || title == "" || page == "" || editor == "" || year == "" || isbn == "" {
    fmt.Println("Some fields are missing")
    fmt.Println("", reference)
  }

}

func ExtractQuotes(commands []Command) {
  var buffer *Command = nil
  for ix, cmd := range commands {
    if len(cmd.Cmd) > 2 && cmd.Cmd[0:4] == "réf" {
      if buffer != nil {
        BuildQuote(*buffer, cmd)
      } else {
        fmt.Println("Found ref without quote")
        fmt.Println(cmd)
      }
      buffer = nil
    } else if strings.Index(cmd.Cmd, "citation") == 0 {
      buffer = &commands[ix]
    } else {
      fmt.Println("Unknown command:", cmd.Cmd)
      buffer = nil
    }
  }
}

func ExtractStats(commands []Command) {
  commandPopularity := make(map[string]int, 1000)
  argsPopularity := make(map[string]map[string]int, 100)

  var count int
  var hasCommand bool
  var aCount int
  var hasArg bool

  for _, cmd := range commands {
    count, hasCommand = commandPopularity[cmd.Cmd]
    if hasCommand {
      commandPopularity[cmd.Cmd] = count + 1
    } else {
      commandPopularity[cmd.Cmd] = 1
      argsPopularity[cmd.Cmd] = make(map[string]int, 100)
    }

    for k := range cmd.NamedArguments {
      aCount, hasArg = argsPopularity[cmd.Cmd][k]
      if hasArg {
        argsPopularity[cmd.Cmd][k] = aCount + 1
      } else {
        argsPopularity[cmd.Cmd][k] = 1
      }
    }
  }

  for _, pl := range sortMapByValue(commandPopularity) {
    fmt.Printf("## %s (%d occ.)\n", pl.Key, pl.Value)
    for _, ar := range sortMapByValue(argsPopularity[pl.Key]) {
      fmt.Printf("- %s (%d occ.)\n", ar.Key, ar.Value)
    }
  }
}

func main() {
  pageXPath := xmlpath.MustCompile("/mediawiki/page")
  textXPath := xmlpath.MustCompile(("revision/text"))
  fi, err := os.Open("frwikiquote-20140622-pages-articles-multistream.xml")
  // fi, err := os.Open("sample.xml")

  if err != nil {

    panic(err)
  }
  // close fi on exit and check for its returned error
  defer func() {
    if err := fi.Close(); err != nil {
      panic(err)
    }
  }()
  // make a read buffer
  r := bufio.NewReader(fi)

  root, err := xmlpath.Parse(r)
  if err != nil {
    log.Fatal(err)
  }
  commands := make([]Command, 100000)
  iter := pageXPath.Iter(root)
  for iter.Next() {
    page := iter.Node()
    content, _ := textXPath.String(page)
    commands = append(commands, markupExtractor(content)...)
  }
  ExtractStats(commands)
}
<|endoftext|>


<commit_before>package spam

import (
	"bytes"
	"fmt"
)

type Parser struct {
	l *Lexer

	buf []buf
	n   int
}

func NewParser(l *Lexer) *Parser {
	return &Parser{
		l: l,
	}
}

func (p *Parser) Parse() *Spam {
	s := &Spam{}

	for {
		n := p.n
		tok, _ := p.scanSkipWhitespace()
		if tok == EOF {
			break
		}

		p.unscan()

		stmt, err := p.parseStatement()
		if err == nil {
			s.words = append(s.words, stmt)
		} else {
			p.reset(n)
		}

	}

	return s
}

func (p *Parser) parseStatement() (fmt.Stringer, error) {
	if p.is(OpenStatement) {
		return p.parseOptions()
	}

	return p.parseWords()
}

func (p *Parser) parseOptions() (fmt.Stringer, error) {
	tok, lit := p.scan()
	if tok != OpenStatement {
		return nil, fmt.Errorf("Syntax error: Was expecting '{', got '%v'", lit)
	}

	firstWord, err := p.parseWord()
	if err != nil {
		return nil, err
	}

	tok, lit = p.scanSkipWhitespace()
	if tok != Or {
		return nil, fmt.Errorf("Syntax error: Was expecting '|', got '%v'", lit)
	}

	if p.is(Whitespace) {
		p.scan()
	}

	secondWord, err := p.parseWord()
	if err != nil {
		return nil, err
	}

	tok, lit = p.scanSkipWhitespace()
	if tok != CloseStatement {
		return nil, fmt.Errorf("Syntax error: Was expecting '}', got '%v'", lit)
	}

	return Option{
		Either: []string{
			firstWord.String(),
			secondWord.String(),
		},
	}, nil
}

func (p *Parser) parseWords() (fmt.Stringer, error) {
	word, err := p.parseWord()
	if err != nil {
		return nil, err
	}

	return Text{word.String()}, nil
}

func (p *Parser) parseWord() (bytes.Buffer, error) {
	var buf bytes.Buffer

	for {
		tok, lit := p.scan()
		if tok == EOF {
			break
		}

		if tok != Illegal && tok != Whitespace {
			p.unscan()
			break
		}

		buf.WriteString(lit)
	}

	return buf, nil
}

func (p *Parser) is(ts ...Token) bool {
	for _, t := range ts {
		tok, _ := p.scan()

		defer func() { p.unscan() }()

		if t == Any {
			continue
		}

		if tok != t {
			return false
		}
	}

	return true
}

// If it can pull n from tokens, do that... else scan new tok
// and add it to the buf
func (p *Parser) scan() (Token, string) {
	defer func() {
		p.n++
	}()

	if p.n >= len(p.buf) {
		tok, lit := p.l.Scan()
		p.buf = append(p.buf, buf{
			tok: tok,
			lit: lit,
		})

		return tok, lit
	}

	b := p.buf[p.n]

	return b.tok, b.lit
}

func (p *Parser) unscan() {
	p.n--
}

func (p *Parser) scanSkipWhitespace() (Token, string) {
	for {
		tok, lit := p.scan()

		if tok != Whitespace {
			return tok, lit
		}
	}
}

func (p *Parser) reset(n int) {
	for p.n > n {
		p.unscan()
	}
}

type buf struct {
	tok Token
	lit string
}
<commit_msg>Add multiple options<commit_after>package spam

import (
	"bytes"
	"fmt"
)

type Parser struct {
	l *Lexer

	buf []buf
	n   int
}

func NewParser(l *Lexer) *Parser {
	return &Parser{
		l: l,
	}
}

func (p *Parser) Parse() *Spam {
	s := &Spam{}

	for {
		n := p.n
		tok, _ := p.scanSkipWhitespace()
		if tok == EOF {
			break
		}

		p.unscan()

		stmt, err := p.parseStatement()
		if err == nil {
			s.words = append(s.words, stmt)
		} else {
			p.reset(n)
		}

	}

	return s
}

func (p *Parser) parseStatement() (fmt.Stringer, error) {
	if p.is(OpenStatement) {
		return p.parseOptions()
	}

	return p.parseWords()
}

func (p *Parser) parseOptions() (fmt.Stringer, error) {
	tok, lit := p.scan()
	if tok != OpenStatement {
		return nil, fmt.Errorf("Syntax error: Was expecting '{', got '%v'", lit)
	}

	var words []string
	for {
		word, err := p.parseWord()
		if err != nil {
			return nil, err
		}

		words = append(words, word.String())

		tok, lit = p.scanSkipWhitespace()
		if tok != Or {
			p.unscan()
			break
		}
	}

	tok, lit = p.scanSkipWhitespace()
	if tok != CloseStatement {
		return nil, fmt.Errorf("Syntax error: Was expecting '}', got '%v'", lit)
	}

	return Option{
		Either: words,
	}, nil
}

func (p *Parser) parseWords() (fmt.Stringer, error) {
	word, err := p.parseWord()
	if err != nil {
		return nil, err
	}

	return Text{word.String()}, nil
}

func (p *Parser) parseWord() (bytes.Buffer, error) {
	var buf bytes.Buffer

	for {
		tok, lit := p.scan()
		if tok == EOF {
			break
		}

		if tok != Illegal && tok != Whitespace {
			p.unscan()
			break
		}

		buf.WriteString(lit)
	}

	return buf, nil
}

func (p *Parser) is(ts ...Token) bool {
	for _, t := range ts {
		tok, _ := p.scan()

		defer func() { p.unscan() }()

		if t == Any {
			continue
		}

		if tok != t {
			return false
		}
	}

	return true
}

// If it can pull n from tokens, do that... else scan new tok
// and add it to the buf
func (p *Parser) scan() (Token, string) {
	defer func() {
		p.n++
	}()

	if p.n >= len(p.buf) {
		tok, lit := p.l.Scan()
		p.buf = append(p.buf, buf{
			tok: tok,
			lit: lit,
		})

		return tok, lit
	}

	b := p.buf[p.n]

	return b.tok, b.lit
}

func (p *Parser) unscan() {
	p.n--
}

func (p *Parser) scanSkipWhitespace() (Token, string) {
	for {
		tok, lit := p.scan()

		if tok != Whitespace {
			return tok, lit
		}
	}
}

func (p *Parser) reset(n int) {
	for p.n > n {
		p.unscan()
	}
}

type buf struct {
	tok Token
	lit string
}
<|endoftext|>


<commit_before>package classy

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
)

const ClassFileMagic uint32 = 0xCAFEBABE

// Deserialize a classfile from its raw byte representation into a ClassFile.
func ReadClassFile(raw []byte) (classFile *ClassFile, err error) {
	defer func() {
		if e := recover(); e != nil {
			classFile = nil
			err = e.(error)
		}
	}()
	classFile = new(ClassFile)
	err = nil

	reader := bytes.NewReader(raw)
	safeReadBinary(reader, binary.BigEndian, &classFile.Magic)

	if classFile.Magic != ClassFileMagic {
		panic(fmt.Errorf("Invalid magic: %v", classFile.Magic))
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.MinorVersion)
	safeReadBinary(reader, binary.BigEndian, &classFile.MajorVersion)
	safeReadBinary(reader, binary.BigEndian, &classFile.ConstantPoolCount)

	// Read constant pool entries
	for i := uint16(1); i <= classFile.ConstantPoolCount-1; i++ {
		ent := readCpEntry(reader)
		classFile.ConstantPool = append(classFile.ConstantPool, ent)
		// Check to see if the entry is one of the 8-byte varieties
		// If so, we skip a slot
		if _, ok := ent.(*CONSTANT_Double_info); ok {
			classFile.ConstantPool = append(classFile.ConstantPool, nil)
			i++
		}
		if _, ok := ent.(*CONSTANT_Long_info); ok {
			classFile.ConstantPool = append(classFile.ConstantPool, nil)
			i++
		}
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.AccessFlags)
	safeReadBinary(reader, binary.BigEndian, &classFile.ThisClass)
	safeReadBinary(reader, binary.BigEndian, &classFile.SuperClass)
	safeReadBinary(reader, binary.BigEndian, &classFile.InterfacesCount)

	classFile.Interfaces = make([]uint16, classFile.InterfacesCount)
	for i := uint16(0); i < classFile.InterfacesCount; i++ {
		safeReadBinary(reader, binary.BigEndian, &classFile.Interfaces[i])
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.FieldsCount)
	for i := uint16(0); i < classFile.FieldsCount; i++ {
		classFile.Fields = append(classFile.Fields, readField(reader))
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.MethodsCount)
	for i := uint16(0); i < classFile.MethodsCount; i++ {
		classFile.Methods = append(classFile.Methods, readMethod(reader))
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.AttrsCount)
	for i := uint16(0); i < classFile.AttrsCount; i++ {
		classFile.Attrs = append(classFile.Attrs, readAttr(reader))
	}

	return
}

// Read a constant pool entry from the classfile
func readCpEntry(reader *bytes.Reader) CpEntry {
	var tag ConstantTag
	safeReadBinary(reader, binary.BigEndian, &tag)
	//fmt.Printf("tag %v\n", tag)
	switch tag {
	case CONSTANT_Class:
		var info CONSTANT_Class_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.NameIndex)
		return &info
	case CONSTANT_Fieldref:
		var info CONSTANT_Fieldref_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ClassIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	case CONSTANT_Methodref:
		var info CONSTANT_Methodref_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ClassIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	case CONSTANT_InterfaceMethodref:
		var info CONSTANT_InterfaceMethodref_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ClassIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	case CONSTANT_String:
		var info CONSTANT_String_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.StringIndex)
		return &info
	case CONSTANT_Integer:
		var info CONSTANT_Integer_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.Value)
		return &info
	case CONSTANT_Float:
		var info CONSTANT_Float_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.Value)
		return &info
	case CONSTANT_Long:
		var info CONSTANT_Long_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.HighBytes)
		safeReadBinary(reader, binary.BigEndian, &info.LowBytes)
		// Push a BS copy as well
		return &info
	case CONSTANT_Double:
		var info CONSTANT_Double_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.HighBytes)
		safeReadBinary(reader, binary.BigEndian, &info.LowBytes)
		return &info
	case CONSTANT_NameAndType:
		var info CONSTANT_NameAndType_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.NameIndex)
		safeReadBinary(reader, binary.BigEndian, &info.DescriptorIndex)
		return &info
	case CONSTANT_Utf8:
		var info CONSTANT_Utf8_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.Length)
		info.Bytes = make([]byte, info.Length)
		io.ReadFull(reader, info.Bytes)
		return &info
	case CONSTANT_MethodHandle:
		var info CONSTANT_MethodHandle_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ReferenceKind)
		safeReadBinary(reader, binary.BigEndian, &info.ReferenceIndex)
		return &info
	case CONSTANT_MethodType:
		var info CONSTANT_MethodType_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.DescriptorIndex)
		return &info
	case CONSTANT_InvokeDynamic:
		var info CONSTANT_InvokeDynamic_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.BootstrapMethodAttrIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	default:
		panic(fmt.Errorf("Invalid Tag '%v' for constant pool entry", tag))
	}
}

// Read a field_info struct
func readField(reader *bytes.Reader) FieldInfo {
	var fieldInfo FieldInfo
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.AccessFlags)
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.NameIndex)
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.DescriptorIndex)
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.AttrsCount)
	for i := uint16(0); i < fieldInfo.AttrsCount; i++ {
		fieldInfo.Attrs = append(fieldInfo.Attrs, readAttr(reader))
	}
	return fieldInfo
}

// Read an attribute_info struct
func readAttr(reader *bytes.Reader) AttrInfo {
	var attrInfo AttrInfo
	safeReadBinary(reader, binary.BigEndian, &attrInfo.NameIndex)
	safeReadBinary(reader, binary.BigEndian, &attrInfo.AttrLength)
	attrInfo.AttrData = make([]byte, attrInfo.AttrLength)
	io.ReadFull(reader, attrInfo.AttrData)
	return attrInfo
}

// Reads a method_info struct
func readMethod(reader *bytes.Reader) MethodInfo {
	var methodInfo MethodInfo
	safeReadBinary(reader, binary.BigEndian, &methodInfo.AccessFlags)
	safeReadBinary(reader, binary.BigEndian, &methodInfo.NameIndex)
	safeReadBinary(reader, binary.BigEndian, &methodInfo.DescriptorIndex)
	safeReadBinary(reader, binary.BigEndian, &methodInfo.AttrsCount)
	for i := uint16(0); i < methodInfo.AttrsCount; i++ {
		methodInfo.Attrs = append(methodInfo.Attrs, readAttr(reader))
	}
	return methodInfo
}

func safeReadBinary(reader io.Reader, order binary.ByteOrder, location interface{}) {
	if err := binary.Read(reader, order, location); err != nil {
		panic(err)
	}
}
<commit_msg>Display invalid magic in hex<commit_after>package classy

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
)

const ClassFileMagic uint32 = 0xCAFEBABE

// Deserialize a classfile from its raw byte representation into a ClassFile.
func ReadClassFile(raw []byte) (classFile *ClassFile, err error) {
	defer func() {
		if e := recover(); e != nil {
			classFile = nil
			err = e.(error)
		}
	}()
	classFile = new(ClassFile)
	err = nil

	reader := bytes.NewReader(raw)
	safeReadBinary(reader, binary.BigEndian, &classFile.Magic)

	if classFile.Magic != ClassFileMagic {
		panic(fmt.Errorf("Invalid magic: 0x%X", classFile.Magic))
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.MinorVersion)
	safeReadBinary(reader, binary.BigEndian, &classFile.MajorVersion)
	safeReadBinary(reader, binary.BigEndian, &classFile.ConstantPoolCount)

	// Read constant pool entries
	for i := uint16(1); i <= classFile.ConstantPoolCount-1; i++ {
		ent := readCpEntry(reader)
		classFile.ConstantPool = append(classFile.ConstantPool, ent)
		// Check to see if the entry is one of the 8-byte varieties
		// If so, we skip a slot
		if _, ok := ent.(*CONSTANT_Double_info); ok {
			classFile.ConstantPool = append(classFile.ConstantPool, nil)
			i++
		}
		if _, ok := ent.(*CONSTANT_Long_info); ok {
			classFile.ConstantPool = append(classFile.ConstantPool, nil)
			i++
		}
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.AccessFlags)
	safeReadBinary(reader, binary.BigEndian, &classFile.ThisClass)
	safeReadBinary(reader, binary.BigEndian, &classFile.SuperClass)
	safeReadBinary(reader, binary.BigEndian, &classFile.InterfacesCount)

	classFile.Interfaces = make([]uint16, classFile.InterfacesCount)
	for i := uint16(0); i < classFile.InterfacesCount; i++ {
		safeReadBinary(reader, binary.BigEndian, &classFile.Interfaces[i])
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.FieldsCount)
	for i := uint16(0); i < classFile.FieldsCount; i++ {
		classFile.Fields = append(classFile.Fields, readField(reader))
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.MethodsCount)
	for i := uint16(0); i < classFile.MethodsCount; i++ {
		classFile.Methods = append(classFile.Methods, readMethod(reader))
	}

	safeReadBinary(reader, binary.BigEndian, &classFile.AttrsCount)
	for i := uint16(0); i < classFile.AttrsCount; i++ {
		classFile.Attrs = append(classFile.Attrs, readAttr(reader))
	}

	return
}

// Read a constant pool entry from the classfile
func readCpEntry(reader *bytes.Reader) CpEntry {
	var tag ConstantTag
	safeReadBinary(reader, binary.BigEndian, &tag)
	//fmt.Printf("tag %v\n", tag)
	switch tag {
	case CONSTANT_Class:
		var info CONSTANT_Class_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.NameIndex)
		return &info
	case CONSTANT_Fieldref:
		var info CONSTANT_Fieldref_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ClassIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	case CONSTANT_Methodref:
		var info CONSTANT_Methodref_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ClassIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	case CONSTANT_InterfaceMethodref:
		var info CONSTANT_InterfaceMethodref_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ClassIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	case CONSTANT_String:
		var info CONSTANT_String_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.StringIndex)
		return &info
	case CONSTANT_Integer:
		var info CONSTANT_Integer_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.Value)
		return &info
	case CONSTANT_Float:
		var info CONSTANT_Float_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.Value)
		return &info
	case CONSTANT_Long:
		var info CONSTANT_Long_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.HighBytes)
		safeReadBinary(reader, binary.BigEndian, &info.LowBytes)
		// Push a BS copy as well
		return &info
	case CONSTANT_Double:
		var info CONSTANT_Double_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.HighBytes)
		safeReadBinary(reader, binary.BigEndian, &info.LowBytes)
		return &info
	case CONSTANT_NameAndType:
		var info CONSTANT_NameAndType_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.NameIndex)
		safeReadBinary(reader, binary.BigEndian, &info.DescriptorIndex)
		return &info
	case CONSTANT_Utf8:
		var info CONSTANT_Utf8_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.Length)
		info.Bytes = make([]byte, info.Length)
		io.ReadFull(reader, info.Bytes)
		return &info
	case CONSTANT_MethodHandle:
		var info CONSTANT_MethodHandle_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.ReferenceKind)
		safeReadBinary(reader, binary.BigEndian, &info.ReferenceIndex)
		return &info
	case CONSTANT_MethodType:
		var info CONSTANT_MethodType_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.DescriptorIndex)
		return &info
	case CONSTANT_InvokeDynamic:
		var info CONSTANT_InvokeDynamic_info
		info.Tag = tag
		safeReadBinary(reader, binary.BigEndian, &info.BootstrapMethodAttrIndex)
		safeReadBinary(reader, binary.BigEndian, &info.NameAndTypeIndex)
		return &info
	default:
		panic(fmt.Errorf("Invalid Tag '%v' for constant pool entry", tag))
	}
}

// Read a field_info struct
func readField(reader *bytes.Reader) FieldInfo {
	var fieldInfo FieldInfo
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.AccessFlags)
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.NameIndex)
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.DescriptorIndex)
	safeReadBinary(reader, binary.BigEndian, &fieldInfo.AttrsCount)
	for i := uint16(0); i < fieldInfo.AttrsCount; i++ {
		fieldInfo.Attrs = append(fieldInfo.Attrs, readAttr(reader))
	}
	return fieldInfo
}

// Read an attribute_info struct
func readAttr(reader *bytes.Reader) AttrInfo {
	var attrInfo AttrInfo
	safeReadBinary(reader, binary.BigEndian, &attrInfo.NameIndex)
	safeReadBinary(reader, binary.BigEndian, &attrInfo.AttrLength)
	attrInfo.AttrData = make([]byte, attrInfo.AttrLength)
	io.ReadFull(reader, attrInfo.AttrData)
	return attrInfo
}

// Reads a method_info struct
func readMethod(reader *bytes.Reader) MethodInfo {
	var methodInfo MethodInfo
	safeReadBinary(reader, binary.BigEndian, &methodInfo.AccessFlags)
	safeReadBinary(reader, binary.BigEndian, &methodInfo.NameIndex)
	safeReadBinary(reader, binary.BigEndian, &methodInfo.DescriptorIndex)
	safeReadBinary(reader, binary.BigEndian, &methodInfo.AttrsCount)
	for i := uint16(0); i < methodInfo.AttrsCount; i++ {
		methodInfo.Attrs = append(methodInfo.Attrs, readAttr(reader))
	}
	return methodInfo
}

func safeReadBinary(reader io.Reader, order binary.ByteOrder, location interface{}) {
	if err := binary.Read(reader, order, location); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package veneur

import (
	"bytes"
	"errors"
	"fmt"
	"hash/fnv"
	"sort"
	"strconv"
	"strings"
)

// Metric is a representation of the sample provided by a client.
type Metric struct {
	Name       string
	Digest     uint32
	Value      float64
	SampleRate float32
	Type       string
	Tags       []string
}

// ParseMetric converts the incoming packet from Datadog DogStatsD
// Datagram format in to a Metric. http://docs.datadoghq.com/guides/dogstatsd/#datagram-format
func ParseMetric(packet []byte) (*Metric, error) {
	parts := bytes.SplitN(packet, []byte(":"), 2)

	var metricName string
	var metricValue float64
	var metricType string
	var metricTags []string
	metricSampleRate := float64(1.0)
	if len(parts) < 2 {
		return nil, errors.New("Invalid metric packet, need at least 1 colon")
	}

	// Create a new hasher for accumulating the data we read
	h := fnv.New32()

	// Add the name to the digest
	h.Write(parts[0])
	metricName = string(parts[0])

	// Use pipes as the delimiter now
	data := bytes.Split(parts[1], []byte("|"))
	if len(data) < 2 {
		return nil, errors.New("Invalid metric packet, need at least 1 pipe for type")
	}
	// Now convert it
	v, err := strconv.ParseFloat(string(data[0]), 64)
	if err != nil {
		return nil, fmt.Errorf("Invalid integer for metric value: %s", parts[1])
	}
	metricValue = v

	// Decide on a type
	switch data[1][0] {
	case 'c':
		metricType = "counter"
	case 'g':
		metricType = "gauge"
	case 'h':
		metricType = "histogram"
	case 'm': // We can ignore the s in "ms"
		metricType = "timer"
	case 's':
		metricType = "set"
	default:
		return nil, errors.New("Invalid type for metric")
	}
	// Add the type to the digest
	h.Write(data[1])

	for i := 2; i < len(data); i++ {
		switch data[i][0] {
		case '@':
			// sample rate!
			sr := string(data[i][1:])
			sampleRate, err := strconv.ParseFloat(sr, 32)
			if err != nil {
				return nil, fmt.Errorf("Invalid float for sample rate: %s", sr)
			}
			metricSampleRate = sampleRate

		case '#':
			// tags!
			tags := strings.Split(string(data[i][1:]), ",")
			sort.Strings(tags)
			h.Write([]byte(strings.Join(tags, ",")))
			metricTags = tags
		}
	}
	if len(Config.Tags) > 0 {
		metricTags = append(metricTags, Config.Tags...)
	}

	digest := h.Sum32()

	return &Metric{Name: metricName, Digest: digest, Value: float64(metricValue), Type: metricType, SampleRate: float32(metricSampleRate), Tags: metricTags}, nil
}
<commit_msg>Use struct literal for return value<commit_after>package veneur

import (
	"bytes"
	"errors"
	"fmt"
	"hash/fnv"
	"sort"
	"strconv"
	"strings"
)

// Metric is a representation of the sample provided by a client.
type Metric struct {
	Name       string
	Digest     uint32
	Value      float64
	SampleRate float32
	Type       string
	Tags       []string
}

// ParseMetric converts the incoming packet from Datadog DogStatsD
// Datagram format in to a Metric. http://docs.datadoghq.com/guides/dogstatsd/#datagram-format
func ParseMetric(packet []byte) (*Metric, error) {
	ret := &Metric{
		SampleRate: 1.0,
	}
	parts := bytes.SplitN(packet, []byte(":"), 2)
	if len(parts) < 2 {
		return nil, errors.New("Invalid metric packet, need at least 1 colon")
	}

	// Create a new hasher for accumulating the data we read
	h := fnv.New32()

	// Add the name to the digest
	h.Write(parts[0])
	ret.Name = string(parts[0])

	// Use pipes as the delimiter now
	data := bytes.Split(parts[1], []byte("|"))
	if len(data) < 2 {
		return nil, errors.New("Invalid metric packet, need at least 1 pipe for type")
	}
	// Now convert it
	v, err := strconv.ParseFloat(string(data[0]), 64)
	if err != nil {
		return nil, fmt.Errorf("Invalid integer for metric value: %s", parts[1])
	}
	ret.Value = v

	// Decide on a type
	switch data[1][0] {
	case 'c':
		ret.Type = "counter"
	case 'g':
		ret.Type = "gauge"
	case 'h':
		ret.Type = "histogram"
	case 'm': // We can ignore the s in "ms"
		ret.Type = "timer"
	case 's':
		ret.Type = "set"
	default:
		return nil, errors.New("Invalid type for metric")
	}
	// Add the type to the digest
	h.Write(data[1])

	for i := 2; i < len(data); i++ {
		switch data[i][0] {
		case '@':
			// sample rate!
			sr := string(data[i][1:])
			sampleRate, err := strconv.ParseFloat(sr, 32)
			if err != nil {
				return nil, fmt.Errorf("Invalid float for sample rate: %s", sr)
			}
			ret.SampleRate = float32(sampleRate)

		case '#':
			// tags!
			tags := strings.Split(string(data[i][1:]), ",")
			sort.Strings(tags)
			h.Write([]byte(strings.Join(tags, ",")))
			ret.Tags = tags
		}
	}
	if len(Config.Tags) > 0 {
		ret.Tags = append(ret.Tags, Config.Tags...)
	}

	ret.Digest = h.Sum32()

	return ret, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/jcuga/golongpoll"
)

func main() {
	// Our chat server is just a longpoll/pub-sub server.
	manager, err := golongpoll.StartLongpoll(golongpoll.Options{})
	if err != nil {
		log.Fatalf("Failed to create chat longpoll manager: %q", err)
	}
	http.HandleFunc("/", Index)
	http.HandleFunc("/post", getChatPostClosure(manager))
	http.HandleFunc("/subscribe", manager.SubscriptionHandler)
	listenAddress := ":8080"
	log.Printf("Launching chat server on %s", listenAddress)
	http.ListenAndServe(listenAddress, nil)
}

type ChatPost struct {
	DisplayName string `json:"display_name"`
	Message     string `json:"message"`
	Topic       string `json:"topic"`
}

// Create a closure that contains a ref to our longpoll manager so we can
// call Publish() from within web handler
// NOTE: the manager is safe to call this way because it relies on channels
func getChatPostClosure(manager *golongpoll.LongpollManager) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "Invalid request method.", 405)
			return
		}
		err := r.ParseForm()
		if err != nil {
			http.Error(w, "Invalid form data.", 405)
			return
		}
		topic := r.PostFormValue("topic")
		display_name := r.PostFormValue("display_name")
		message := r.PostFormValue("message")
		if len(strings.TrimSpace(topic)) == 0 || len(strings.TrimSpace(display_name)) == 0 ||
			len(strings.TrimSpace(message)) == 0 {
			http.Error(w, "Invalid request.  Blank topic, display_name, or message.", 400)
			return
		}
		chat := ChatPost{DisplayName: display_name, Message: message, Topic: topic}
		manager.Publish(topic, chat)
	}
}

func Index(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Invalid request method.", 405)
		return
	}

	// TODO: laod webpage with js that fetches all posts, or by a single topic.
	// TODO:
	// TODO: get list of topics and possibly some sort of activity metric
	// also have a create topic form that post and redir to topic room
	fmt.Fprint(w, "Welcome! todo show current topics and possibly stats about?\n")
}
<commit_msg>done everything but javascript for first pass<commit_after>package main

import (
	"html/template"
	"log"
	"net/http"
	"strings"

	"github.com/jcuga/golongpoll"
)

func main() {
	// Our chat server is just a longpoll/pub-sub server.
	manager, err := golongpoll.StartLongpoll(golongpoll.Options{})
	if err != nil {
		log.Fatalf("Failed to create chat longpoll manager: %q", err)
	}
	http.HandleFunc("/", Index)
	http.HandleFunc("/post", getChatPostClosure(manager))
	http.HandleFunc("/subscribe", manager.SubscriptionHandler)
	listenAddress := ":8080"
	log.Printf("Launching chat server on %s", listenAddress)
	http.ListenAndServe(listenAddress, nil)
}

type ChatPost struct {
	DisplayName string `json:"display_name"`
	Message     string `json:"message"`
	Topic       string `json:"topic"`
}

// Create a closure that contains a ref to our longpoll manager so we can
// call Publish() from within web handler
// NOTE: the manager is safe to call this way because it relies on channels
func getChatPostClosure(manager *golongpoll.LongpollManager) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "Invalid request method.", 405)
			return
		}
		err := r.ParseForm()
		if err != nil {
			http.Error(w, "Invalid form data.", 405)
			return
		}
		topic := r.PostFormValue("topic")
		display_name := r.PostFormValue("display_name")
		message := r.PostFormValue("message")
		if len(strings.TrimSpace(topic)) == 0 || len(strings.TrimSpace(display_name)) == 0 ||
			len(strings.TrimSpace(message)) == 0 {
			http.Error(w, "Invalid request.  Blank topic, display_name, or message.", 400)
			return
		}
		chat := ChatPost{DisplayName: display_name, Message: message, Topic: topic}
		manager.Publish(topic, chat)
	}
}

func Index(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Invalid request method.", 405)
		return
	}
	topic := r.URL.Query().Get("topic")
	t := template.New("chat_homepage")
	t, _ = t.Parse(getIndexTemplateString())
	templateData := struct{ Topic string }{topic}
	t.Execute(w, templateData)
}

func getIndexTemplateString() string {
  // TODO: show all chats in list, include link to topic
  // TODO: go back and add listenaddr to template data (make listen addr a const)
  // TODO: create reserved topic for all chats
  // TODO: add all chat topic const to template data
  // TODO: conditionally subscribe to all or just current
  // TODO: links to filter by topic
  // TODO: show latest chat first
  // TODO: box up top for name, chat, topic (hidden vs text field depending on
  // if topic filter on.)
	return `

      <title>micro-chat</title>

MicroChat in Golang

      {{ if .Topic }}
        Showing chats about: {{ .Topic}} Show all chats.
      {{ else }}
        Showing all chats
      {{ end }}

  `
}
<|endoftext|>


<commit_before>package main

import (
	"time"
)

type Command string
type Commands []Command

// Invocation represents a single execution of a command, including its context,
// exit code and time of execution.
type Invocation struct {
	Id        int       `json:"id"`
	SessionId int       `json:"sessionid"`
	Command   string    `json:"command"`
	Directory string    `json:"directory"`
	User      string    `json:"user"`
	Host      string    `json:"host"`
	Shell     string    `json:"shell"`
	ExitCode  int8      `json:",exitcode"`
	Timestamp time.Time `json:"timestamp"`
	Tags      []string  `json:"tags"`
}

type Invocations []Invocation
<commit_msg>don't need session id anymore<commit_after>package main

import (
	"time"
)

type Command string
type Commands []Command

// Invocation represents a single execution of a command, including its context,
// exit code and time of execution.
type Invocation struct {
	Id        int       `json:"id"`
	Command   string    `json:"command"`
	Directory string    `json:"directory"`
	User      string    `json:"user"`
	Host      string    `json:"host"`
	Shell     string    `json:"shell"`
	ExitCode  int8      `json:",exitcode"`
	Timestamp time.Time `json:"timestamp"`
	Tags      []string  `json:"tags"`
}

type Invocations []Invocation
<|endoftext|>


<commit_before>package shredis

import (
	"errors"
	"fmt"
	"strconv"
)

var (
	// ErrNotExecuted is returned by all Get* commands if the Cmd
	// hasn't been executed by Exec().
	ErrNotExecuted = errors.New("command not executed")
	// ErrAlreadyGot is returned if more than one Cmd.Get* is called for a
	// single Exec().
	ErrAlreadyGot = errors.New("result already retrieved")
)

// Cmd is a redis command.
type Cmd struct {
	key     []byte
	payload []byte
	res     interface{}
	err     error
}

// Build makes a command which will be send to the shard for 'key'. All
// redis commands work, but it's not advised to use commands which are stateful
// ('SELECT'), involve multiple servers ('MGET', 'MGET', 'RENAME'), or are not
// simple command->reply ('WATCH').
func Build(key string, fields ...string) *Cmd {
	return &Cmd{
		key:     []byte(key),
		payload: buildCommand(fields),
		err:     ErrNotExecuted,
	}
}

// Get returns redis' result.
func (c *Cmd) Get() (interface{}, error) {
	err := c.err
	c.err = ErrAlreadyGot
	return c.res, err
}

// GetString returns the value if it's a single string. If the key is not set
// the returned string will be empty.
func (c *Cmd) GetString() (string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return "", err
	}
	if c.res == nil {
		return "", nil
	}
	return resString(c.res)
}

// GetStrings returns the value if it's a string slice. If the key is not set
// the returned slice will be empty.
func (c *Cmd) GetStrings() ([]string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}
	var res []string
	for _, v := range s {
		k, err := resString(v)
		if err != nil {
			return nil, err
		}
		res = append(res, k)
	}
	return res, nil
}

// GetInt returns the value of Get() if it's either a int in REPL, or if it's a
// string which can be converterd to an int. If the key is not set the value
// will be 0.
func (c *Cmd) GetInt() (int, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return 0, err
	}
	if c.res == nil {
		return 0, nil
	}
	return resInt(c.res)
}

// GetMapStringString returns the value if it's a map[string]string. If the key
// is not set the returned map will be empty.
func (c *Cmd) GetMapStringString() (map[string]string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}

	res := make(map[string]string, len(s)/2)
	for len(s) > 1 {
		k, err := resString(s[0])
		if err != nil {
			return nil, err
		}
		v, err := resString(s[1])
		if err != nil {
			return nil, err
		}
		res[k] = v
		s = s[2:]
	}
	return res, nil
}

// GetMapIntString returns the value if it's a map[int]string. If the key
// is not set the returned map will be empty.
func (c *Cmd) GetMapIntString() (map[int]string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}

	res := make(map[int]string, len(s)/2)
	for len(s) > 1 {
		k, err := resInt(s[0])
		if err != nil {
			return nil, err
		}
		v, err := resString(s[1])
		if err != nil {
			return nil, err
		}

		res[k] = v
		s = s[2:]
	}
	return res, nil
}

// GetMapStringInt returns the value if it's a map[string]int. If the key
// is not set the returned map will be empty.
func (c *Cmd) GetMapStringInt() (map[string]int, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}

	res := make(map[string]int, len(s)/2)
	for len(s) > 1 {
		k, err := resString(s[0])
		if err != nil {
			return nil, err
		}
		v, err := resInt(s[1])
		if err != nil {
			return nil, err
		}

		res[k] = v
		s = s[2:]
	}
	return res, nil
}

func resString(x interface{}) (string, error) {
	switch k := x.(type) {
	case string:
		return k, nil
	default:
		return "", fmt.Errorf("unexpected value. have %T, want string", x)
	}
}

func resInt(x interface{}) (int, error) {
	switch k := x.(type) {
	case int:
		return k, nil
	case string:
		return strconv.Atoi(k)
	default:
		return 0, fmt.Errorf("unexpected value. have %T, want int or string", x)
	}
}

func buildCommand(fields []string) []byte {
	b := make([]byte, 0, 64)
	b = append(b, '*')
	b = strconv.AppendInt(b, int64(len(fields)), 10)
	b = append(b, '\r', '\n')
	for _, f := range fields {
		b = append(b, '$')
		b = strconv.AppendInt(b, int64(len(f)), 10)
		b = append(b, '\r', '\n')
		b = append(b, []byte(f)...)
		b = append(b, '\r', '\n')
	}
	return b
}
<commit_msg>no need to convert when appending<commit_after>package shredis

import (
	"errors"
	"fmt"
	"strconv"
)

var (
	// ErrNotExecuted is returned by all Get* commands if the Cmd
	// hasn't been executed by Exec().
	ErrNotExecuted = errors.New("command not executed")
	// ErrAlreadyGot is returned if more than one Cmd.Get* is called for a
	// single Exec().
	ErrAlreadyGot = errors.New("result already retrieved")
)

// Cmd is a redis command.
type Cmd struct {
	key     []byte
	payload []byte
	res     interface{}
	err     error
}

// Build makes a command which will be send to the shard for 'key'. All
// redis commands work, but it's not advised to use commands which are stateful
// ('SELECT'), involve multiple servers ('MGET', 'MGET', 'RENAME'), or are not
// simple command->reply ('WATCH').
func Build(key string, fields ...string) *Cmd {
	return &Cmd{
		key:     []byte(key),
		payload: buildCommand(fields),
		err:     ErrNotExecuted,
	}
}

// Get returns redis' result.
func (c *Cmd) Get() (interface{}, error) {
	err := c.err
	c.err = ErrAlreadyGot
	return c.res, err
}

// GetString returns the value if it's a single string. If the key is not set
// the returned string will be empty.
func (c *Cmd) GetString() (string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return "", err
	}
	if c.res == nil {
		return "", nil
	}
	return resString(c.res)
}

// GetStrings returns the value if it's a string slice. If the key is not set
// the returned slice will be empty.
func (c *Cmd) GetStrings() ([]string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}
	var res []string
	for _, v := range s {
		k, err := resString(v)
		if err != nil {
			return nil, err
		}
		res = append(res, k)
	}
	return res, nil
}

// GetInt returns the value of Get() if it's either a int in REPL, or if it's a
// string which can be converterd to an int. If the key is not set the value
// will be 0.
func (c *Cmd) GetInt() (int, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return 0, err
	}
	if c.res == nil {
		return 0, nil
	}
	return resInt(c.res)
}

// GetMapStringString returns the value if it's a map[string]string. If the key
// is not set the returned map will be empty.
func (c *Cmd) GetMapStringString() (map[string]string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}

	res := make(map[string]string, len(s)/2)
	for len(s) > 1 {
		k, err := resString(s[0])
		if err != nil {
			return nil, err
		}
		v, err := resString(s[1])
		if err != nil {
			return nil, err
		}
		res[k] = v
		s = s[2:]
	}
	return res, nil
}

// GetMapIntString returns the value if it's a map[int]string. If the key
// is not set the returned map will be empty.
func (c *Cmd) GetMapIntString() (map[int]string, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}

	res := make(map[int]string, len(s)/2)
	for len(s) > 1 {
		k, err := resInt(s[0])
		if err != nil {
			return nil, err
		}
		v, err := resString(s[1])
		if err != nil {
			return nil, err
		}

		res[k] = v
		s = s[2:]
	}
	return res, nil
}

// GetMapStringInt returns the value if it's a map[string]int. If the key
// is not set the returned map will be empty.
func (c *Cmd) GetMapStringInt() (map[string]int, error) {
	err := c.err
	c.err = ErrAlreadyGot
	if err != nil {
		return nil, err
	}
	if c.res == nil {
		return nil, nil
	}
	s, ok := c.res.([]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected value. have %T, want []interface{}", c.res)
	}

	res := make(map[string]int, len(s)/2)
	for len(s) > 1 {
		k, err := resString(s[0])
		if err != nil {
			return nil, err
		}
		v, err := resInt(s[1])
		if err != nil {
			return nil, err
		}

		res[k] = v
		s = s[2:]
	}
	return res, nil
}

func resString(x interface{}) (string, error) {
	switch k := x.(type) {
	case string:
		return k, nil
	default:
		return "", fmt.Errorf("unexpected value. have %T, want string", x)
	}
}

func resInt(x interface{}) (int, error) {
	switch k := x.(type) {
	case int:
		return k, nil
	case string:
		return strconv.Atoi(k)
	default:
		return 0, fmt.Errorf("unexpected value. have %T, want int or string", x)
	}
}

func buildCommand(fields []string) []byte {
	b := make([]byte, 0, 64)
	b = append(b, '*')
	b = strconv.AppendInt(b, int64(len(fields)), 10)
	b = append(b, '\r', '\n')
	for _, f := range fields {
		b = append(b, '$')
		b = strconv.AppendInt(b, int64(len(f)), 10)
		b = append(b, '\r', '\n')
		b = append(b, f...)
		b = append(b, '\r', '\n')
	}
	return b
}
<|endoftext|>


<commit_before>package eve

type state struct {
	addr  int
	flags byte
}

// Driver uses DCI to communicate with EVE graphics controller. Commands/data
// are received/sent using DCI read/write transactions. R,W, DL, GE methods
// starts new transaction and leaves it in open state. Any subsequent
// transaction implicitly closes current open transaction.
type Driver struct {
	dci           DCI
	buf           []byte
	mmap          *mmap
	width, height uint16
	state         state
	irqf          byte
}

// NewDriver returns new driver to the EVE graphics controller accessed via dci.
// N sets the capacity of the internal buffer (bytes, must be >= 4).
func NewDriver(dci DCI, n int) *Driver {
	d := new(Driver)
	d.dci = dci
	d.buf = make([]byte, 0, n)
	return d
}

// Width returns screen width.
func (d *Driver) Width() int {
	return int(d.width)
}

// Height returns screen height.
func (d *Driver) Height() int {
	return int(d.height)
}

// RAMDL returns the start address of RAM_DL.
func (d *Driver) RAMDL() int {
	return d.mmap.ramdl
}

// RAMCMD returns the start address of RAM_CMD.
func (d *Driver) RAMCMD() int {
	return d.mmap.ramcmd
}

// IRQ returns channel that can be used to wait for IRQ.
func (d *Driver) IRQ() <-chan struct{} {
	return d.dci.IRQ()
}

func (d *Driver) writeByte(addr int, val byte) {
	d.dci.Write([]byte{
		1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr),
		val,
	})
	d.dci.End()
}

func (d *Driver) writeUint16(addr int, val uint16) {
	d.dci.Write([]byte{
		1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr),
		byte(val), byte(val >> 8),
	})
	d.dci.End()
}

func (d *Driver) writeUint32(addr int, val uint32) {
	d.dci.Write([]byte{
		1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr),
		byte(val), byte(val >> 8), byte(val >> 16), byte(val >> 24),
	})
	d.dci.End()
}

func (d *Driver) write(addr int, s []byte) {
	d.dci.Write([]byte{1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr)})
	d.dci.Write(s)
	d.dci.End()
}

func (d *Driver) readByte(addr int) byte {
	buf := [3]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:2])
	d.dci.End()
	return buf[1]
}

func (d *Driver) readUint16(addr int) uint16 {
	buf := [3]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:3])
	d.dci.End()
	return uint16(buf[1]) | uint16(buf[2])<<8
}

func (d *Driver) readUint32(addr int) uint32 {
	buf := [5]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:5])
	d.dci.End()
	return uint32(buf[1]) | uint32(buf[2])<<8 | uint32(buf[3])<<16 |
		uint32(buf[4])<<24
}

func (d *Driver) readTwoUint32(addr int) (a, b uint32) {
	buf := [9]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:9])
	d.dci.End()
	a = uint32(buf[1]) | uint32(buf[2])<<8 | uint32(buf[3])<<16 |
		uint32(buf[4])<<24
	b = uint32(buf[5]) | uint32(buf[6])<<8 | uint32(buf[7])<<16 |
		uint32(buf[8])<<24
	return
}

func (d *Driver) intFlags() byte {
	d.irqf |= d.readByte(d.mmap.regintflags)
	return d.irqf
}

func (d *Driver) clearIntFlags(mask byte) {
	d.irqf |= d.readByte(d.mmap.regintflags)
	d.irqf &^= mask
}

func (d *Driver) intMask() byte {
	return d.readByte(d.mmap.regintflags + ointmask)
}

func (d *Driver) setIntMask(mask byte) {
	d.writeByte(d.mmap.regintflags+ointmask, mask)
}

func (d *Driver) wait(flags byte) {
	if d.irqf&flags != 0 || d.intFlags()&flags != 0 {
		return
	}
	mask := d.intMask()
	d.setIntMask(flags)
	for {
		<-d.IRQ()
		if d.intFlags()&flags != 0 {
			break
		}
	}
	d.setIntMask(mask)
}

func (d *Driver) flush() {
	d.dci.Write(d.buf)
	d.buf = d.buf[:0]
}

const (
	stateRead         = 0
	stateWrite        = 1
	stateWriteCmd     = 2
	stateWriteBulkCmd = 3

	stateOpen = 4
)

func (d *Driver) end() {
	if d.state.flags&stateOpen == 0 {
		return
	}
	if len(d.buf) > 0 {
		d.flush()
	}
	d.dci.End()
	d.state.flags &^= stateOpen
	switch d.state.flags & 3 {
	case stateWriteCmd:
		cmdEnd := uint32(d.state.addr & 4095)
		regcmdwrite := d.mmap.regcmdwrite
		d.writeUint32(regcmdwrite, cmdEnd)
		// Ensure valid interrupt flag.
		d.clearIntFlags(INT_CMDEMPTY)
		if d.readUint32(regcmdwrite+ocmdread) == cmdEnd {
			d.irqf |= INT_CMDEMPTY
		}
	case stateWriteBulkCmd:
		// Ensure valid interrupt flag.
		d.clearIntFlags(INT_CMDEMPTY)
		if d.readUint32(regcmdbspace) == 4092 {
			d.irqf |= INT_CMDEMPTY
		}
	}
}

type HostCmd byte

// HostCmd invokes host command. Param is a command parameter. It must be zero
// in case of commands that do not require parameters.
func (d *Driver) HostCmd(cmd HostCmd, param byte) {
	d.end()
	d.dci.Write([]byte{byte(cmd), param, 0})
	d.dci.End()
}

func checkAddr(addr int) {
	if uint(addr)>>22 != 0 {
		panic("eve: bad addr")
	}
}

// WriteByte writes byte to the EVE memory at address addr.
func (d *Driver) WriteByte(addr int, val byte) {
	d.end()
	checkAddr(addr)
	d.writeByte(addr, val)
}

// WriteUint16 writes 16-bit word to the EVE memory at address addr.
func (d *Driver) WriteUint16(addr int, val uint16) {
	d.end()
	checkAddr(addr)
	d.writeUint16(addr, val)
}

// WriteUint32 writes 32-bit word to the EVE memory at address addr.
func (d *Driver) WriteUint32(addr int, val uint32) {
	d.end()
	checkAddr(addr)
	d.writeUint32(addr, val)
}

// WriteInt writes signed 32-bit word to the EVE memory at address addr.
func (d *Driver) WriteInt(addr int, val int) {
	d.WriteUint32(addr, uint32(val))
}

// WriteInt writes bytes from s at address addr.
func (d *Driver) Write(addr int, s []byte) {
	if len(s) == 0 {
		return
	}
	d.end()
	checkAddr(addr)
	d.write(addr, s)
}

// ReadByte reads byte from EVE memory at address addr.
func (d *Driver) ReadByte(addr int) byte {
	d.end()
	checkAddr(addr)
	return d.readByte(addr)
}

// ReadUint16 reads 16-bit word from EVE memory at address addr.
func (d *Driver) ReadUint16(addr int) uint16 {
	d.end()
	checkAddr(addr)
	return d.readUint16(addr)
}

// ReadUint32 reads 32-bit word from EVE memory at address addr.
func (d *Driver) ReadUint32(addr int) uint32 {
	d.end()
	checkAddr(addr)
	return d.readUint32(addr)
}

// ReadInt reads signed 32-bit word from EVE memory at address addr.
func (d *Driver) ReadInt(addr int) int {
	return int(int32(d.ReadUint32(addr)))
}

// Err returns and clears the internal error status.
func (d *Driver) Err(clear bool) error {
	d.end()
	return d.dci.Err(clear)
}

// IntFlags reads interrupt flags from EVE and accumulates them (using logical
// OR) in internal variable. It returns accumulated flags.
func (d *Driver) IntFlags() byte {
	d.end()
	return d.intFlags()
}

// ClearIntFlags clears interrupt flags specified by mask.
func (d *Driver) ClearIntFlags(mask byte) {
	d.end()
	d.clearIntFlags(mask)
}

// IntMask returns current interrupt mask.
func (d *Driver) IntMask() byte {
	d.end()
	return d.intMask()
}

// SetIntMask sets interrupt mask.
func (d *Driver) SetIntMask(mask byte) {
	d.end()
	d.setIntMask(mask)
}

// Wait waits for any interrupt in flags.
func (d *Driver) Wait(flags byte) {
	d.end()
	d.wait(flags)
}

// SetBacklight sets backlight PWM duty cycle. Pwmduty range is from 0 to 128.
func (d *Driver) SetBacklight(pwmduty int) {
	d.end()
	d.writeByte(d.mmap.regintflags+opwmduty, byte(pwmduty))
}

// SwapDL clears INT_SWAP and schedules the display lists swap, to be performed
// after rendering the current frame.
func (d *Driver) SwapDL() {
	d.end()
	d.clearIntFlags(INT_SWAP)
	d.writeByte(d.mmap.regdlswap, DLSWAP_FRAME)
}

// CmdSpace returns the number of bytes of available space in coprocessor
// engine command FIFO.
func (d *Driver) CmdSpace() int {
	d.end()
	if d.mmap == &eve1 {
		cmdrd, cmdwr := d.readTwoUint32(d.mmap.regcmdwrite + ocmdread)
		return int(4092 - (cmdwr-cmdrd)&4095)
	}
	return int(d.readUint32(regcmdbspace))
}

// TouchScreenXY the coordinaters of touch point.
func (d *Driver) TouchScreenXY() (x, y int) {
	d.end()
	xy := d.readUint32(d.mmap.regcmdwrite + otouchscreenxy)
	return int(int16(xy >> 16)), int(int16(xy))
}

// TouchTagXY returns the coordinates of touch point corresponding to current
// tag.
func (d *Driver) TouchTagXY() (x, y int) {
	d.end()
	xy := d.readUint32(d.mmap.regcmdwrite + otouchtagxy)
	return int(int16(xy >> 16)), int(int16(xy))
}

// TouchTag returns current touch tag or zero in case of no touch.
func (d *Driver) TouchTag() int {
	d.end()
	return int(d.readUint32(d.mmap.regcmdwrite + otouchtag))
}

// Tracker returns touch value and touch tag.
func (d *Driver) Tracker() (val, tag int) {
	d.end()
	tracker := d.readUint32(d.mmap.regtracker)
	return int(uint16(tracker >> 16)), int(uint16(tracker))
}

// CmdDL returns the offset from RAM_DL of a display list command generated b
// the coprocessor engine.
func (d *Driver) CmdDL() int {
	d.end()
	return int(int32(d.readUint32(d.mmap.regcmdwrite + ocmddl)))
}

// SetCmdDL sets the offset from RAM_DL where the coprocessor engine will start
// to write next commands.
func (d *Driver) SetCmdDL(offset int) {
	d.end()
	d.writeUint32(d.mmap.regcmdwrite+ocmddl, uint32(offset))
}
<commit_msg>display/eve: New Setup method.<commit_after>package eve

type state struct {
	addr  int
	flags byte
}

// Driver uses DCI to communicate with EVE graphics controller. Commands/data
// are received/sent using DCI read/write transactions. R,W, DL, GE methods
// starts new transaction and leaves it in open state. Any subsequent
// transaction implicitly closes current open transaction.
type Driver struct {
	dci           DCI
	buf           []byte
	mmap          *mmap
	width, height uint16
	state         state
	irqf          byte
}

// NewDriver returns new driver to the EVE graphics controller accessed via dci.
// N sets the capacity of the internal buffer (bytes, must be >= 4). New does
// not initialize DCI - Setup method must be used.
func NewDriver(dci DCI, n int) *Driver {
	d := new(Driver)
	d.dci = dci
	d.buf = make([]byte, 0, n)
	return d
}

// Setup configures and enables SPI/QSPI/I2C. Use clkHz <= 11 for SPI (3.4e6 for
// I2C) before caling Init. In case of SPI/QSPI call Setup one more time after
// initialization with clkHz <= 30e6 (25e6 for 4-bit QSPI).
func (d *Driver) Setup(clkHz int) {
	d.dci.Setup(clkHz)
}

// Width returns screen width.
func (d *Driver) Width() int {
	return int(d.width)
}

// Height returns screen height.
func (d *Driver) Height() int {
	return int(d.height)
}

// RAMDL returns the start address of RAM_DL.
func (d *Driver) RAMDL() int {
	return d.mmap.ramdl
}

// RAMCMD returns the start address of RAM_CMD.
func (d *Driver) RAMCMD() int {
	return d.mmap.ramcmd
}

// IRQ returns channel that can be used to wait for IRQ.
func (d *Driver) IRQ() <-chan struct{} {
	return d.dci.IRQ()
}

func (d *Driver) writeByte(addr int, val byte) {
	d.dci.Write([]byte{
		1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr),
		val,
	})
	d.dci.End()
}

func (d *Driver) writeUint16(addr int, val uint16) {
	d.dci.Write([]byte{
		1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr),
		byte(val), byte(val >> 8),
	})
	d.dci.End()
}

func (d *Driver) writeUint32(addr int, val uint32) {
	d.dci.Write([]byte{
		1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr),
		byte(val), byte(val >> 8), byte(val >> 16), byte(val >> 24),
	})
	d.dci.End()
}

func (d *Driver) write(addr int, s []byte) {
	d.dci.Write([]byte{1<<7 | byte(addr>>16), byte(addr >> 8), byte(addr)})
	d.dci.Write(s)
	d.dci.End()
}

func (d *Driver) readByte(addr int) byte {
	buf := [3]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:2])
	d.dci.End()
	return buf[1]
}

func (d *Driver) readUint16(addr int) uint16 {
	buf := [3]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:3])
	d.dci.End()
	return uint16(buf[1]) | uint16(buf[2])<<8
}

func (d *Driver) readUint32(addr int) uint32 {
	buf := [5]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:5])
	d.dci.End()
	return uint32(buf[1]) | uint32(buf[2])<<8 | uint32(buf[3])<<16 |
		uint32(buf[4])<<24
}

func (d *Driver) readTwoUint32(addr int) (a, b uint32) {
	buf := [9]byte{byte(addr >> 16), byte(addr >> 8), byte(addr)}
	d.dci.Write(buf[:3])
	d.dci.Read(buf[:9])
	d.dci.End()
	a = uint32(buf[1]) | uint32(buf[2])<<8 | uint32(buf[3])<<16 |
		uint32(buf[4])<<24
	b = uint32(buf[5]) | uint32(buf[6])<<8 | uint32(buf[7])<<16 |
		uint32(buf[8])<<24
	return
}

func (d *Driver) intFlags() byte {
	d.irqf |= d.readByte(d.mmap.regintflags)
	return d.irqf
}

func (d *Driver) clearIntFlags(mask byte) {
	d.irqf |= d.readByte(d.mmap.regintflags)
	d.irqf &^= mask
}

func (d *Driver) intMask() byte {
	return d.readByte(d.mmap.regintflags + ointmask)
}

func (d *Driver) setIntMask(mask byte) {
	d.writeByte(d.mmap.regintflags+ointmask, mask)
}

func (d *Driver) wait(flags byte) {
	if d.irqf&flags != 0 || d.intFlags()&flags != 0 {
		return
	}
	mask := d.intMask()
	d.setIntMask(flags)
	for {
		<-d.IRQ()
		if d.intFlags()&flags != 0 {
			break
		}
	}
	d.setIntMask(mask)
}

func (d *Driver) flush() {
	d.dci.Write(d.buf)
	d.buf = d.buf[:0]
}

const (
	stateRead         = 0
	stateWrite        = 1
	stateWriteCmd     = 2
	stateWriteBulkCmd = 3

	stateOpen = 4
)

func (d *Driver) end() {
	if d.state.flags&stateOpen == 0 {
		return
	}
	if len(d.buf) > 0 {
		d.flush()
	}
	d.dci.End()
	d.state.flags &^= stateOpen
	switch d.state.flags & 3 {
	case stateWriteCmd:
		cmdEnd := uint32(d.state.addr & 4095)
		regcmdwrite := d.mmap.regcmdwrite
		d.writeUint32(regcmdwrite, cmdEnd)
		// Ensure valid interrupt flag.
		d.clearIntFlags(INT_CMDEMPTY)
		if d.readUint32(regcmdwrite+ocmdread) == cmdEnd {
			d.irqf |= INT_CMDEMPTY
		}
	case stateWriteBulkCmd:
		// Ensure valid interrupt flag.
		d.clearIntFlags(INT_CMDEMPTY)
		if d.readUint32(regcmdbspace) == 4092 {
			d.irqf |= INT_CMDEMPTY
		}
	}
}

type HostCmd byte

// HostCmd invokes host command. Param is a command parameter. It must be zero
// in case of commands that do not require parameters.
func (d *Driver) HostCmd(cmd HostCmd, param byte) {
	d.end()
	d.dci.Write([]byte{byte(cmd), param, 0})
	d.dci.End()
}

func checkAddr(addr int) {
	if uint(addr)>>22 != 0 {
		panic("eve: bad addr")
	}
}

// WriteByte writes byte to the EVE memory at address addr.
func (d *Driver) WriteByte(addr int, val byte) {
	d.end()
	checkAddr(addr)
	d.writeByte(addr, val)
}

// WriteUint16 writes 16-bit word to the EVE memory at address addr.
func (d *Driver) WriteUint16(addr int, val uint16) {
	d.end()
	checkAddr(addr)
	d.writeUint16(addr, val)
}

// WriteUint32 writes 32-bit word to the EVE memory at address addr.
func (d *Driver) WriteUint32(addr int, val uint32) {
	d.end()
	checkAddr(addr)
	d.writeUint32(addr, val)
}

// WriteInt writes signed 32-bit word to the EVE memory at address addr.
func (d *Driver) WriteInt(addr int, val int) {
	d.WriteUint32(addr, uint32(val))
}

// WriteInt writes bytes from s at address addr.
func (d *Driver) Write(addr int, s []byte) {
	if len(s) == 0 {
		return
	}
	d.end()
	checkAddr(addr)
	d.write(addr, s)
}

// ReadByte reads byte from EVE memory at address addr.
func (d *Driver) ReadByte(addr int) byte {
	d.end()
	checkAddr(addr)
	return d.readByte(addr)
}

// ReadUint16 reads 16-bit word from EVE memory at address addr.
func (d *Driver) ReadUint16(addr int) uint16 {
	d.end()
	checkAddr(addr)
	return d.readUint16(addr)
}

// ReadUint32 reads 32-bit word from EVE memory at address addr.
func (d *Driver) ReadUint32(addr int) uint32 {
	d.end()
	checkAddr(addr)
	return d.readUint32(addr)
}

// ReadInt reads signed 32-bit word from EVE memory at address addr.
func (d *Driver) ReadInt(addr int) int {
	return int(int32(d.ReadUint32(addr)))
}

// Err returns and clears the internal error status.
func (d *Driver) Err(clear bool) error {
	d.end()
	return d.dci.Err(clear)
}

// IntFlags reads interrupt flags from EVE and accumulates them (using logical
// OR) in internal variable. It returns accumulated flags.
func (d *Driver) IntFlags() byte {
	d.end()
	return d.intFlags()
}

// ClearIntFlags clears interrupt flags specified by mask.
func (d *Driver) ClearIntFlags(mask byte) {
	d.end()
	d.clearIntFlags(mask)
}

// IntMask returns current interrupt mask.
func (d *Driver) IntMask() byte {
	d.end()
	return d.intMask()
}

// SetIntMask sets interrupt mask.
func (d *Driver) SetIntMask(mask byte) {
	d.end()
	d.setIntMask(mask)
}

// Wait waits for any interrupt in flags.
func (d *Driver) Wait(flags byte) {
	d.end()
	d.wait(flags)
}

// SetBacklight sets backlight PWM duty cycle. Pwmduty range is from 0 to 128.
func (d *Driver) SetBacklight(pwmduty int) {
	d.end()
	d.writeByte(d.mmap.regintflags+opwmduty, byte(pwmduty))
}

// SwapDL clears INT_SWAP and schedules the display lists swap, to be performed
// after rendering the current frame.
func (d *Driver) SwapDL() {
	d.end()
	d.clearIntFlags(INT_SWAP)
	d.writeByte(d.mmap.regdlswap, DLSWAP_FRAME)
}

// CmdSpace returns the number of bytes of available space in coprocessor
// engine command FIFO.
func (d *Driver) CmdSpace() int {
	d.end()
	if d.mmap == &eve1 {
		cmdrd, cmdwr := d.readTwoUint32(d.mmap.regcmdwrite + ocmdread)
		return int(4092 - (cmdwr-cmdrd)&4095)
	}
	return int(d.readUint32(regcmdbspace))
}

// TouchScreenXY the coordinaters of touch point.
func (d *Driver) TouchScreenXY() (x, y int) {
	d.end()
	xy := d.readUint32(d.mmap.regcmdwrite + otouchscreenxy)
	return int(int16(xy >> 16)), int(int16(xy))
}

// TouchTagXY returns the coordinates of touch point corresponding to current
// tag.
func (d *Driver) TouchTagXY() (x, y int) {
	d.end()
	xy := d.readUint32(d.mmap.regcmdwrite + otouchtagxy)
	return int(int16(xy >> 16)), int(int16(xy))
}

// TouchTag returns current touch tag or zero in case of no touch.
func (d *Driver) TouchTag() int {
	d.end()
	return int(d.readUint32(d.mmap.regcmdwrite + otouchtag))
}

// Tracker returns touch value and touch tag.
func (d *Driver) Tracker() (val, tag int) {
	d.end()
	tracker := d.readUint32(d.mmap.regtracker)
	return int(uint16(tracker >> 16)), int(uint16(tracker))
}

// CmdDL returns the offset from RAM_DL of a display list command generated b
// the coprocessor engine.
func (d *Driver) CmdDL() int {
	d.end()
	return int(int32(d.readUint32(d.mmap.regcmdwrite + ocmddl)))
}

// SetCmdDL sets the offset from RAM_DL where the coprocessor engine will start
// to write next commands.
func (d *Driver) SetCmdDL(offset int) {
	d.end()
	d.writeUint32(d.mmap.regcmdwrite+ocmddl, uint32(offset))
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package uploadconfig

import (
	"fmt"

	"github.com/pkg/errors"
	v1 "k8s.io/api/core/v1"
	rbac "k8s.io/api/rbac/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/klog"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
	rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
)

const (
	// NodesKubeadmConfigClusterRoleName sets the name for the ClusterRole that allows
	// the bootstrap tokens to access the kubeadm-config ConfigMap during the node bootstrap/discovery
	// or during upgrade nodes
	NodesKubeadmConfigClusterRoleName = "kubeadm:nodes-kubeadm-config"
)

// ResetClusterStatusForNode removes the APIEndpoint of a given control-plane node
// from the ClusterStatus and updates the kubeadm ConfigMap
func ResetClusterStatusForNode(nodeName string, client clientset.Interface) error {
	fmt.Printf("[reset] Removing info for node %q from the ConfigMap %q in the %q Namespace\n",
		nodeName, kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)

	return apiclient.MutateConfigMap(client, metav1.ObjectMeta{
		Name:      kubeadmconstants.KubeadmConfigConfigMap,
		Namespace: metav1.NamespaceSystem,
	}, func(cm *v1.ConfigMap) error {
		return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
			// Handle a nil APIEndpoints map. Should only happen if someone manually
			// interacted with the ConfigMap.
			if cs.APIEndpoints == nil {
				return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
					kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
			}
			klog.V(2).Infof("Removing APIEndpoint for Node %q", nodeName)
			delete(cs.APIEndpoints, nodeName)
			return nil
		})
	})
}

// UploadConfiguration saves the InitConfiguration used for later reference (when upgrading for instance)
func UploadConfiguration(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
	fmt.Printf("[upload-config] Storing the configuration used in ConfigMap %q in the %q Namespace\n", kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)

	// Prepare the ClusterConfiguration for upload
	// The components store their config in their own ConfigMaps, then reset the .ComponentConfig struct;
	// We don't want to mutate the cfg itself, so create a copy of it using .DeepCopy of it first
	clusterConfigurationToUpload := cfg.ClusterConfiguration.DeepCopy()
	clusterConfigurationToUpload.ComponentConfigs = kubeadmapi.ComponentConfigs{}

	// Marshal the ClusterConfiguration into YAML
	clusterConfigurationYaml, err := configutil.MarshalKubeadmConfigObject(clusterConfigurationToUpload)
	if err != nil {
		return err
	}

	// Prepare the ClusterStatus for upload
	clusterStatus := &kubeadmapi.ClusterStatus{
		APIEndpoints: map[string]kubeadmapi.APIEndpoint{
			cfg.NodeRegistration.Name: cfg.LocalAPIEndpoint,
		},
	}
	// Marshal the ClusterStatus into YAML
	clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
	if err != nil {
		return err
	}

	err = apiclient.CreateOrMutateConfigMap(client, &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      kubeadmconstants.KubeadmConfigConfigMap,
			Namespace: metav1.NamespaceSystem,
		},
		Data: map[string]string{
			kubeadmconstants.ClusterConfigurationConfigMapKey: string(clusterConfigurationYaml),
			kubeadmconstants.ClusterStatusConfigMapKey:        string(clusterStatusYaml),
		},
	}, func(cm *v1.ConfigMap) error {
		return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
			// Handle a nil APIEndpoints map. Should only happen if someone manually
			// interacted with the ConfigMap.
			if cs.APIEndpoints == nil {
				return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
					kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
			}
			cs.APIEndpoints[cfg.NodeRegistration.Name] = cfg.LocalAPIEndpoint
			return nil
		})
	})
	if err != nil {
		return err
	}

	// Ensure that the NodesKubeadmConfigClusterRoleName exists
	err = apiclient.CreateOrUpdateRole(client, &rbac.Role{
		ObjectMeta: metav1.ObjectMeta{
			Name:      NodesKubeadmConfigClusterRoleName,
			Namespace: metav1.NamespaceSystem,
		},
		Rules: []rbac.PolicyRule{
			rbachelper.NewRule("get").Groups("").Resources("configmaps").Names(kubeadmconstants.KubeadmConfigConfigMap).RuleOrDie(),
		},
	})
	if err != nil {
		return err
	}

	// Binds the NodesKubeadmConfigClusterRoleName to all the bootstrap tokens
	// that are members of the system:bootstrappers:kubeadm:default-node-token group
	// and to all nodes
	return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name:      NodesKubeadmConfigClusterRoleName,
			Namespace: metav1.NamespaceSystem,
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "Role",
			Name:     NodesKubeadmConfigClusterRoleName,
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: kubeadmconstants.NodeBootstrapTokenAuthGroup,
			},
			{
				Kind: rbac.GroupKind,
				Name: kubeadmconstants.NodesGroup,
			},
		},
	})
}

func mutateClusterStatus(cm *v1.ConfigMap, mutator func(*kubeadmapi.ClusterStatus) error) error {
	// Obtain the existing ClusterStatus object
	clusterStatus, err := configutil.UnmarshalClusterStatus(cm.Data)
	if err != nil {
		return err
	}
	// Mutate the ClusterStatus
	if err := mutator(clusterStatus); err != nil {
		return err
	}
	// Marshal the ClusterStatus back into YAML
	clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
	if err != nil {
		return err
	}
	// Write the marshaled mutated cluster status back to the ConfigMap
	cm.Data[kubeadmconstants.ClusterStatusConfigMapKey] = string(clusterStatusYaml)
	return nil
}
<commit_msg>kubeadm: upload the `ClusterConfiguration` during the upgrade<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package uploadconfig

import (
	"fmt"

	"github.com/pkg/errors"
	v1 "k8s.io/api/core/v1"
	rbac "k8s.io/api/rbac/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/klog"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
	rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
)

const (
	// NodesKubeadmConfigClusterRoleName sets the name for the ClusterRole that allows
	// the bootstrap tokens to access the kubeadm-config ConfigMap during the node bootstrap/discovery
	// or during upgrade nodes
	NodesKubeadmConfigClusterRoleName = "kubeadm:nodes-kubeadm-config"
)

// ResetClusterStatusForNode removes the APIEndpoint of a given control-plane node
// from the ClusterStatus and updates the kubeadm ConfigMap
func ResetClusterStatusForNode(nodeName string, client clientset.Interface) error {
	fmt.Printf("[reset] Removing info for node %q from the ConfigMap %q in the %q Namespace\n",
		nodeName, kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)

	return apiclient.MutateConfigMap(client, metav1.ObjectMeta{
		Name:      kubeadmconstants.KubeadmConfigConfigMap,
		Namespace: metav1.NamespaceSystem,
	}, func(cm *v1.ConfigMap) error {
		return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
			// Handle a nil APIEndpoints map. Should only happen if someone manually
			// interacted with the ConfigMap.
			if cs.APIEndpoints == nil {
				return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
					kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
			}
			klog.V(2).Infof("Removing APIEndpoint for Node %q", nodeName)
			delete(cs.APIEndpoints, nodeName)
			return nil
		})
	})
}

// UploadConfiguration saves the InitConfiguration used for later reference (when upgrading for instance)
func UploadConfiguration(cfg *kubeadmapi.InitConfiguration, client clientset.Interface) error {
	fmt.Printf("[upload-config] Storing the configuration used in ConfigMap %q in the %q Namespace\n", kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)

	// Prepare the ClusterConfiguration for upload
	// The components store their config in their own ConfigMaps, then reset the .ComponentConfig struct;
	// We don't want to mutate the cfg itself, so create a copy of it using .DeepCopy of it first
	clusterConfigurationToUpload := cfg.ClusterConfiguration.DeepCopy()
	clusterConfigurationToUpload.ComponentConfigs = kubeadmapi.ComponentConfigs{}

	// Marshal the ClusterConfiguration into YAML
	clusterConfigurationYaml, err := configutil.MarshalKubeadmConfigObject(clusterConfigurationToUpload)
	if err != nil {
		return err
	}

	// Prepare the ClusterStatus for upload
	clusterStatus := &kubeadmapi.ClusterStatus{
		APIEndpoints: map[string]kubeadmapi.APIEndpoint{
			cfg.NodeRegistration.Name: cfg.LocalAPIEndpoint,
		},
	}
	// Marshal the ClusterStatus into YAML
	clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
	if err != nil {
		return err
	}

	err = apiclient.CreateOrMutateConfigMap(client, &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      kubeadmconstants.KubeadmConfigConfigMap,
			Namespace: metav1.NamespaceSystem,
		},
		Data: map[string]string{
			kubeadmconstants.ClusterConfigurationConfigMapKey: string(clusterConfigurationYaml),
			kubeadmconstants.ClusterStatusConfigMapKey:        string(clusterStatusYaml),
		},
	}, func(cm *v1.ConfigMap) error {
		// Upgrade will call to UploadConfiguration with a modified KubernetesVersion reflecting the new
		// Kubernetes version. In that case, the mutation path will take place.
		cm.Data[kubeadmconstants.ClusterConfigurationConfigMapKey] = string(clusterConfigurationYaml)
		// Mutate the ClusterStatus now
		return mutateClusterStatus(cm, func(cs *kubeadmapi.ClusterStatus) error {
			// Handle a nil APIEndpoints map. Should only happen if someone manually
			// interacted with the ConfigMap.
			if cs.APIEndpoints == nil {
				return errors.Errorf("APIEndpoints from ConfigMap %q in the %q Namespace is nil",
					kubeadmconstants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
			}
			cs.APIEndpoints[cfg.NodeRegistration.Name] = cfg.LocalAPIEndpoint
			return nil
		})
	})
	if err != nil {
		return err
	}

	// Ensure that the NodesKubeadmConfigClusterRoleName exists
	err = apiclient.CreateOrUpdateRole(client, &rbac.Role{
		ObjectMeta: metav1.ObjectMeta{
			Name:      NodesKubeadmConfigClusterRoleName,
			Namespace: metav1.NamespaceSystem,
		},
		Rules: []rbac.PolicyRule{
			rbachelper.NewRule("get").Groups("").Resources("configmaps").Names(kubeadmconstants.KubeadmConfigConfigMap).RuleOrDie(),
		},
	})
	if err != nil {
		return err
	}

	// Binds the NodesKubeadmConfigClusterRoleName to all the bootstrap tokens
	// that are members of the system:bootstrappers:kubeadm:default-node-token group
	// and to all nodes
	return apiclient.CreateOrUpdateRoleBinding(client, &rbac.RoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name:      NodesKubeadmConfigClusterRoleName,
			Namespace: metav1.NamespaceSystem,
		},
		RoleRef: rbac.RoleRef{
			APIGroup: rbac.GroupName,
			Kind:     "Role",
			Name:     NodesKubeadmConfigClusterRoleName,
		},
		Subjects: []rbac.Subject{
			{
				Kind: rbac.GroupKind,
				Name: kubeadmconstants.NodeBootstrapTokenAuthGroup,
			},
			{
				Kind: rbac.GroupKind,
				Name: kubeadmconstants.NodesGroup,
			},
		},
	})
}

func mutateClusterStatus(cm *v1.ConfigMap, mutator func(*kubeadmapi.ClusterStatus) error) error {
	// Obtain the existing ClusterStatus object
	clusterStatus, err := configutil.UnmarshalClusterStatus(cm.Data)
	if err != nil {
		return err
	}
	// Mutate the ClusterStatus
	if err := mutator(clusterStatus); err != nil {
		return err
	}
	// Marshal the ClusterStatus back into YAML
	clusterStatusYaml, err := configutil.MarshalKubeadmConfigObject(clusterStatus)
	if err != nil {
		return err
	}
	// Write the marshaled mutated cluster status back to the ConfigMap
	cm.Data[kubeadmconstants.ClusterStatusConfigMapKey] = string(clusterStatusYaml)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors 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 cmd

import (
	"encoding/json"
	"os/exec"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"
	"k8s.io/klog/v2"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/mustload"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/reason"
	"k8s.io/minikube/pkg/version"
)

var (
	versionOutput          string
	shortVersion           bool
	listComponentsVersions bool
)

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version of minikube",
	Long:  `Print the version of minikube.`,
	Run: func(command *cobra.Command, args []string) {
		minikubeVersion := version.GetVersion()
		gitCommitID := version.GetGitCommitID()
		data := map[string]string{
			"minikubeVersion": minikubeVersion,
			"commit":          gitCommitID,
		}

		if listComponentsVersions && !shortVersion {
			co := mustload.Running(ClusterFlagValue())
			runner := co.CP.Runner
			versionCMDS := map[string]*exec.Cmd{
				"docker":     exec.Command("docker", "--version"),
				"dockerd":    exec.Command("dockerd", "--version"),
				"containerd": exec.Command("containerd", "--version"),
				"crio":       exec.Command("crio", "--version"),
				"podman":     exec.Command("sudo", "podman", "--version"),
				"crictl":     exec.Command("sudo", "crictl", "--version"),
				"buildctl":   exec.Command("buildctl", "--version"),
				"ctr":        exec.Command("ctr", "--version"),
				"runc":       exec.Command("runc", "--version"),
				"crun":       exec.Command("crun", "--version"),
			}
			for k, v := range versionCMDS {
				rr, err := runner.RunCmd(v)
				if err != nil {
					klog.Warningf("error getting %s's version: %v", k, err)
					data[k] = "error"
				} else {
					version := rr.Stdout.String()
					// remove extra lines after the version
					version = strings.Split(version, "\n")[0]
					data[k] = strings.TrimSpace(version)
				}

			}

		}

		switch versionOutput {
		case "":
			if !shortVersion {
				out.Ln("minikube version: %v", minikubeVersion)
				if gitCommitID != "" {
					out.Ln("commit: %v", gitCommitID)
				}
				keys := make([]string, 0, len(data))
				for k := range data {
					keys = append(keys, k)
				}
				sort.Strings(keys)
				for _, k := range keys {
					v := data[k]
					// for backward compatibility we keep displaying the old way for these two
					if k == "minikubeVersion" || k == "commit" {
						continue
					}
					if v != "" {
						out.Ln("\n%s:\n%s", k, v)
					}
				}
			} else {
				out.Ln("%v", minikubeVersion)
			}
		case "json":
			json, err := json.Marshal(data)
			if err != nil {
				exit.Error(reason.InternalJSONMarshal, "version json failure", err)
			}
			out.Ln(string(json))
		case "yaml":
			yaml, err := yaml.Marshal(data)
			if err != nil {
				exit.Error(reason.InternalYamlMarshal, "version yaml failure", err)
			}
			out.Ln(string(yaml))
		default:
			exit.Message(reason.InternalOutputUsage, "error: --output must be 'yaml' or 'json'")
		}
	},
}

func init() {
	versionCmd.Flags().StringVarP(&versionOutput, "output", "o", "", "One of 'yaml' or 'json'.")
	versionCmd.Flags().BoolVar(&shortVersion, "short", false, "Print just the version number.")
	versionCmd.Flags().BoolVar(&listComponentsVersions, "components", false, "list versions of all components included with minikube. (the cluster must be running)")
}
<commit_msg>Show the version of the cri-dockerd component<commit_after>/*
Copyright 2016 The Kubernetes Authors 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 cmd

import (
	"encoding/json"
	"os/exec"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"
	"k8s.io/klog/v2"
	"k8s.io/minikube/pkg/minikube/exit"
	"k8s.io/minikube/pkg/minikube/mustload"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/reason"
	"k8s.io/minikube/pkg/version"
)

var (
	versionOutput          string
	shortVersion           bool
	listComponentsVersions bool
)

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version of minikube",
	Long:  `Print the version of minikube.`,
	Run: func(command *cobra.Command, args []string) {
		minikubeVersion := version.GetVersion()
		gitCommitID := version.GetGitCommitID()
		data := map[string]string{
			"minikubeVersion": minikubeVersion,
			"commit":          gitCommitID,
		}

		if listComponentsVersions && !shortVersion {
			co := mustload.Running(ClusterFlagValue())
			runner := co.CP.Runner
			versionCMDS := map[string]*exec.Cmd{
				"docker":      exec.Command("docker", "--version"),
				"dockerd":     exec.Command("dockerd", "--version"),
				"cri-dockerd": exec.Command("cri-dockerd", "--version"),
				"containerd":  exec.Command("containerd", "--version"),
				"crio":        exec.Command("crio", "--version"),
				"podman":      exec.Command("sudo", "podman", "--version"),
				"crictl":      exec.Command("sudo", "crictl", "--version"),
				"buildctl":    exec.Command("buildctl", "--version"),
				"ctr":         exec.Command("ctr", "--version"),
				"runc":        exec.Command("runc", "--version"),
				"crun":        exec.Command("crun", "--version"),
			}
			for k, v := range versionCMDS {
				rr, err := runner.RunCmd(v)
				if err != nil {
					klog.Warningf("error getting %s's version: %v", k, err)
					data[k] = "error"
				} else {
					version := rr.Stdout.String()
					// remove extra lines after the version
					version = strings.Split(version, "\n")[0]
					data[k] = strings.TrimSpace(version)
				}

			}

		}

		switch versionOutput {
		case "":
			if !shortVersion {
				out.Ln("minikube version: %v", minikubeVersion)
				if gitCommitID != "" {
					out.Ln("commit: %v", gitCommitID)
				}
				keys := make([]string, 0, len(data))
				for k := range data {
					keys = append(keys, k)
				}
				sort.Strings(keys)
				for _, k := range keys {
					v := data[k]
					// for backward compatibility we keep displaying the old way for these two
					if k == "minikubeVersion" || k == "commit" {
						continue
					}
					if v != "" {
						out.Ln("\n%s:\n%s", k, v)
					}
				}
			} else {
				out.Ln("%v", minikubeVersion)
			}
		case "json":
			json, err := json.Marshal(data)
			if err != nil {
				exit.Error(reason.InternalJSONMarshal, "version json failure", err)
			}
			out.Ln(string(json))
		case "yaml":
			yaml, err := yaml.Marshal(data)
			if err != nil {
				exit.Error(reason.InternalYamlMarshal, "version yaml failure", err)
			}
			out.Ln(string(yaml))
		default:
			exit.Message(reason.InternalOutputUsage, "error: --output must be 'yaml' or 'json'")
		}
	},
}

func init() {
	versionCmd.Flags().StringVarP(&versionOutput, "output", "o", "", "One of 'yaml' or 'json'.")
	versionCmd.Flags().BoolVar(&shortVersion, "short", false, "Print just the version number.")
	versionCmd.Flags().BoolVar(&listComponentsVersions, "components", false, "list versions of all components included with minikube. (the cluster must be running)")
}
<|endoftext|>