<commit_before>// Package apptemplate implements template parsing and code generation.
package apptemplate

import (
  "os"
  "fmt"
  "io"
  "bufio"
  "strings"
  "strconv"
  "path"
  "path/filepath"
  "errors"
  "bytes"
  "go/token"
  "go/parser"
  "go/printer"
  "golang.org/x/tools/go/ast/astutil"
)

var verbose = false
var log = os.Stderr

var sections []*Section     // Stores output sections during template parsing.
var stack []*Entry  // Used to prevent template insertion cycles.

// Section contains the text of a code section or static section.
type Section struct {
  Kind uint
  Text string
}
const (  // These are Section.Kind values.
  StaticSection uint = iota
  CodeSection
)

//--- Linear pattern matching

// Pattern helps us keep track of progress in matching a string.
type Pattern struct {
  Text []rune
  Length, Pos int
}

// NewPattern initializes a Pattern for a given string.
func NewPattern(s string) Pattern {
  runes := []rune(s)
  return Pattern{ Text: runes, Length: len(runes) }
}

// Next returns true when Pos advances past the last character of Text.
func (pattern *Pattern) Next(ch rune) bool {
  // If Pos is past the end of Text, reset it to the beginning.
  if pattern.Pos == pattern.Length {
    pattern.Pos = 0
  }
  // Try to match the current rune in Text.
  if ch == pattern.Text[pattern.Pos] {
    pattern.Pos++
  }
  // Check for a complete match.
  return pattern.Pos == pattern.Length
}

//--- Template parsing and output generation

// Entry contains path and file information about a template.
type Entry struct {
  SitePath, HardPath string  // The site path is relative to the site root,
  FileInfo os.FileInfo       // while the hard path is a physical path in
  InsertionLine int          // the file system. A child template begins
}                            // at an insertion line of a parent template.

// String implements the fmt.Stringer interface for Entry.
func (entry Entry) String() string {
  if entry.InsertionLine == 0 {
    return entry.SitePath
  }
  return fmt.Sprintf("-> line %d: %s", entry.InsertionLine, entry.SitePath)
}

// MakeEntry fills in every field of an Entry, generating
// the hard path and file info based on the details of the site path.
func MakeEntry(siteRoot, startDir, sitePath string,
    insertionLine int) (*Entry, error) {
  hardPath := MakeHardPath(siteRoot, startDir, sitePath)
  fileInfo, error := os.Stat(hardPath)
  if error != nil {
    return nil, error
  }
  entry := Entry{
      SitePath: sitePath,
      HardPath: hardPath,
      FileInfo: fileInfo,
      InsertionLine: insertionLine,
    }
  return &entry, nil
}

// MakeHardPath uses the details of the site path to make a hard path.
// A hard path names a location in the physical file system rather than
// in the website's directory structure. It is either an absolute path
// or a relative path with respect to the starting directory, which is
// where the top-level template is located.
func MakeHardPath(siteRoot, startDir, sitePath string) string {
  var dir string
  if filepath.IsAbs(sitePath) {
    dir = siteRoot
  } else {
    dir = startDir
  }
  hardPath := filepath.Join(dir, sitePath)
  return hardPath
}

// parse makes an entry for the top-level template, initializes the section
// list and the parsing stack, and calls doParse.
func parse(siteRoot, templatePath string) error {
  // We resolve relative paths using the starting directory.
  startDir := filepath.Dir(templatePath)
  entryPoint := filepath.Base(templatePath)
  // Make an insertion stack with a top-level entry.
  entry, error := MakeEntry(siteRoot, startDir, entryPoint, 0)
  if error != nil {
    return error
  }
  sections = []*Section{}
  stack = []*Entry{ entry }
  return doParse(siteRoot, startDir)
}

// doParse recursively parses a template and its children.
func doParse(siteRoot, startDir string) error {
  current := stack[len(stack)-1]
  if verbose {
    fmt.Fprintf(log, "// start \"%s\"\n", current.SitePath)
  }

  // Check for an insertion cycle.
  for i := len(stack)-2; i >= 0; i-- {
    ancestor := stack[i]
    if os.SameFile(ancestor.FileInfo, current.FileInfo) {
      lines := []string{ "doParse: insertion cycle" }
      for j := i; j < len(stack); j++ {           // In the event of a cycle,
        lines = append(lines, stack[j].String())  // generate a stack trace.
      }
      message := fmt.Sprintf(strings.Join(lines, "\n  "))
      return errors.New(message)
    }
  }

  // Open the template file and make a reader.
  var error error
  var file *os.File
  file, error = os.Open(current.HardPath)
  if error != nil {
    return error
  }
  reader := bufio.NewReader(file)

  // There are two opening patterns but only one closing pattern. There is
  // no need to check tag depth because nested tags are not allowed.
  codePattern := NewPattern("<?code")
  insertPattern := NewPattern("<?insert")
  openPatterns := []*Pattern{ &codePattern, &insertPattern }
  var open *Pattern
  close := NewPattern("?>")

  // Each character goes into the buffer, which we empty whenever we match
  // an opening or closing tag. In the former case the buffer must contain
  // static text, while the latter case is code or a template insertion.
  var buffer []rune
  var ch rune
  var size int
  countBytes, countRunes := 0, 0  // Byte and rune counts are logged.
  lineIndex := 1  // The line index is stored in template entries.

  for {
    ch, size, error = reader.ReadRune()
    if error == nil {
      buffer = append(buffer, ch)
      countBytes += size
      countRunes++
      if ch == '\n' {
        lineIndex++
      }
    } else {               // We assume that the read failed due to EOF.
      content := string(buffer)
      emitStatic(content)
      break
    }

    // Once a tag has been opened, we ignore further opening tags until
    // we have come across the closing tag. Nesting is not allowed.
    if open == nil {
      for _, pattern := range openPatterns {
        if pattern.Next(ch) {
          open = pattern
          content := string(buffer[0:len(buffer)-open.Length])  // Remove tag.
          emitStatic(content)  // Text before an opening tag must be static.
          buffer = []rune{}
        }
      }
    } else {
      if close.Next(ch) {
        content := buffer[0:len(buffer)-close.Length]  // Remove tag.
        if open == &codePattern {           // Code sections are just text.
          emitCode(string(content))
        } else if open == &insertPattern {  // Insertion requires more work.
          childPath := strings.TrimSpace(string(content))
          entry, error := MakeEntry(siteRoot, startDir, childPath,
              lineIndex)                    // We have to push a new template
          if error != nil {                 // entry onto the stack and make
            return error                    // a recursive call.
          }
          stack = append(stack, entry)
          error = doParse(siteRoot, startDir)
          if error != nil {
            return error
          }
          stack = stack[0:len(stack)-1]
        }
        open = nil
        buffer = []rune{}
      }
    }
  }
  if verbose {
    fmt.Fprintf(log, "parsed \"%s\"\n", current.SitePath)
    fmt.Fprintf(log, "read %d bytes, %d runes\n", countBytes, countRunes)
    fmt.Fprintf(log, "finished on line %d\n", lineIndex)
  }
  if error == io.EOF {
    return nil
  }
  return error
}

// emitCode makes a code section and adds it to the global sections.
func emitCode(content string) {
  sections = append(sections, &Section{ Kind: CodeSection, Text: content })
}

// emitStatic breaks a string into back-quoted strings and back quotes,
// calling doEmitStatic for each one.
func emitStatic(content string) {
  if len(content) == 0 {
    return
  }
  from := 0
  for pos, ch := range content {
    if ch == '`' {
      if pos != from {
        raw := fmt.Sprintf("`%s`", content[from:pos])
        doEmitStatic(raw)
      }
      doEmitStatic("'`'")
      from = pos+1
    }
  }
  if from != len(content) {
    raw := fmt.Sprintf("`%s`", content[from:len(content)])
    doEmitStatic(raw)
  }
}
// doEmitStatic makes a static section and adds it to the global sections.
func doEmitStatic(chunk string) {
  sections = append(sections, &Section{ Kind: StaticSection, Text: chunk })
}

// Process is the top-level template parsing function. It calls
// parse, then glues the sections together and injects an import statement
// as needed. The final result is printed to the global writer.
func Process(siteRoot, templatePath string, writer *bufio.Writer) {
  // We parse the template to obtain code sections and static sections.
  error := parse(siteRoot, templatePath)
  if error != nil {
    writer.WriteString(fmt.Sprintf("Template parsing error: %s\n", error))
    return
  }

  // Concatenate only the code sections. We're not adding print statements yet
  // because we don't know what the print command is going to look like. We
  // do want to parse the user's code in order to scan the imports.
  output := bytes.Buffer{}
  for _, section := range sections {
    if section.Kind == CodeSection {
      fmt.Fprintf(&output, section.Text)
    }
  }
  fileSet := token.NewFileSet()
  fileNode, error := parser.ParseFile(fileSet, "output", output.Bytes(),
      parser.ParseComments)
  if error != nil {
    writer.Write(output.Bytes())
    writer.WriteString(fmt.Sprintf(
        "\n---\nError parsing code sections: %s\n", error))
    return
  }

  seekPath := "fmt"  // The print command is to be found in this package.
  seekName := path.Base(seekPath)
  printCall := "Print"

  // Has the desired package been imported? Is the name available?
  isImported := false
  var importedAs string          // Use this if the path has been imported.
  seenName := map[string]bool{}  // Consult this if we have to import.

  for _, importSpec := range fileNode.Imports {
    importPath, _ := strconv.Unquote(importSpec.Path.Value)
    var importName string
    if importSpec.Name == nil {
      importName = path.Base(importPath)
    } else {
      importName = importSpec.Name.Name
    }
    seenName[importName] = true  // NB: underscore imports only run a package.
    if !isImported && importPath == seekPath && importName != "_" {
      isImported = true          // If the package is imported several times,
      importedAs = importName    // we use the name in the first occurrence.
    }
  }

  var importAs, printPrefix string  // NB: these are "" by default
  if isImported {
    if importedAs != "." {  // No prefix is needed with a dot import.
      printPrefix = importedAs+"."
    }
  } else {
    if !seenName[seekName] {
      importAs = seekName
    } else {                // Look for a name that hasn't been used yet.
      for i := 0; ; i++ {
        importAs = fmt.Sprintf("%s_%d", seekName, i)
        _, found := seenName[importAs]
        if !found {
          break
        }
      }
    }
    printPrefix = importAs+"."
  }

  // Concatenate the code with static sections wrapped in print statements.
  output.Reset()
  for _, section := range sections {
    if section.Kind == CodeSection {
      fmt.Fprintf(&output, section.Text)
    } else {
      s := fmt.Sprintf(";%s%s(%s);\n", printPrefix, printCall, section.Text)
      fmt.Fprintf(&output, s)
    }
  }
  // Have Go parse the whole output in preparation for import injection
  // and formatted code output.
  fileSet = token.NewFileSet()
  fileNode, error = parser.ParseFile(fileSet, "output", output.Bytes(),
      parser.ParseComments)
  if error != nil {
    writer.Write(output.Bytes())
    writer.WriteString(fmt.Sprintf(
        "\n---\nError parsing entire template output: %s\n", error))
    return
  }
  // Inject an import statement if necessary.
  if !isImported {
    if importAs == seekName {  // Make 'import "fmt"', not 'import fmt "fmt"'.
      astutil.AddImport(fileSet, fileNode, seekPath)
    } else {                   // AddNamedImport would make 'import fmt "fmt"'.
      astutil.AddNamedImport(fileSet, fileNode, importAs, seekPath)
    }
  }

  // Print with a custom configuration: soft tabs of two spaces each.
  config := printer.Config{ Mode: printer.UseSpaces, Tabwidth: 2 }
  (&config).Fprint(writer, fileSet, fileNode)
}

<commit_msg>Delay string breaking; left-trim whitespace<commit_after>// Package apptemplate implements template parsing and code generation.
package apptemplate

import (
  "os"
  "fmt"
  "io"
  "bufio"
  "strings"
  "strconv"
  "path"
  "path/filepath"
  "errors"
  "bytes"
  "unicode"
  "go/token"
  "go/parser"
  "go/printer"
  "golang.org/x/tools/go/ast/astutil"
)

var verbose = false
var log = os.Stderr

var sections []*Section     // Stores output sections during template parsing.
var stack []*Entry  // Used to prevent template insertion cycles.

// Section contains the text of a code section or static section.
type Section struct {
  Kind uint
  Text string
}
const (  // These are Section.Kind values.
  StaticSection uint = iota
  CodeSection
)

//--- Linear pattern matching

// Pattern helps us keep track of progress in matching a string.
type Pattern struct {
  Text []rune
  Length, Pos int
}

// NewPattern initializes a Pattern for a given string.
func NewPattern(s string) Pattern {
  runes := []rune(s)
  return Pattern{ Text: runes, Length: len(runes) }
}

// Next returns true when Pos advances past the last character of Text.
func (pattern *Pattern) Next(ch rune) bool {
  // If Pos is past the end of Text, reset it to the beginning.
  if pattern.Pos == pattern.Length {
    pattern.Pos = 0
  }
  // Try to match the current rune in Text.
  if ch == pattern.Text[pattern.Pos] {
    pattern.Pos++
  }
  // Check for a complete match.
  return pattern.Pos == pattern.Length
}

//--- Template parsing and output generation

// Entry contains path and file information about a template.
type Entry struct {
  SitePath, HardPath string  // The site path is relative to the site root,
  FileInfo os.FileInfo       // while the hard path is a physical path in
  InsertionLine int          // the file system. A child template begins
}                            // at an insertion line of a parent template.

// String implements the fmt.Stringer interface for Entry.
func (entry Entry) String() string {
  if entry.InsertionLine == 0 {
    return entry.SitePath
  }
  return fmt.Sprintf("-> line %d: %s", entry.InsertionLine, entry.SitePath)
}

// MakeEntry fills in every field of an Entry, generating
// the hard path and file info based on the details of the site path.
func MakeEntry(siteRoot, startDir, sitePath string,
    insertionLine int) (*Entry, error) {
  hardPath := MakeHardPath(siteRoot, startDir, sitePath)
  fileInfo, error := os.Stat(hardPath)
  if error != nil {
    return nil, error
  }
  entry := Entry{
      SitePath: sitePath,
      HardPath: hardPath,
      FileInfo: fileInfo,
      InsertionLine: insertionLine,
    }
  return &entry, nil
}

// MakeHardPath uses the details of the site path to make a hard path.
// A hard path names a location in the physical file system rather than
// in the website's directory structure. It is either an absolute path
// or a relative path with respect to the starting directory, which is
// where the top-level template is located.
func MakeHardPath(siteRoot, startDir, sitePath string) string {
  var dir string
  if filepath.IsAbs(sitePath) {
    dir = siteRoot
  } else {
    dir = startDir
  }
  hardPath := filepath.Join(dir, sitePath)
  return hardPath
}

// parse makes an entry for the top-level template, initializes the section
// list and the parsing stack, and calls doParse.
func parse(siteRoot, templatePath string) error {
  // We resolve relative paths using the starting directory.
  startDir := filepath.Dir(templatePath)
  entryPoint := filepath.Base(templatePath)
  // Make an insertion stack with a top-level entry.
  entry, error := MakeEntry(siteRoot, startDir, entryPoint, 0)
  if error != nil {
    return error
  }
  sections = []*Section{}
  stack = []*Entry{ entry }
  return doParse(siteRoot, startDir)
}

// doParse recursively parses a template and its children.
func doParse(siteRoot, startDir string) error {
  current := stack[len(stack)-1]
  if verbose {
    fmt.Fprintf(log, "// start \"%s\"\n", current.SitePath)
  }

  // Check for an insertion cycle.
  for i := len(stack)-2; i >= 0; i-- {
    ancestor := stack[i]
    if os.SameFile(ancestor.FileInfo, current.FileInfo) {
      lines := []string{ "doParse: insertion cycle" }
      for j := i; j < len(stack); j++ {           // In the event of a cycle,
        lines = append(lines, stack[j].String())  // generate a stack trace.
      }
      message := fmt.Sprintf(strings.Join(lines, "\n  "))
      return errors.New(message)
    }
  }

  // Open the template file and make a reader.
  var error error
  var file *os.File
  file, error = os.Open(current.HardPath)
  if error != nil {
    return error
  }
  reader := bufio.NewReader(file)

  // There are two opening patterns but only one closing pattern. There is
  // no need to check tag depth because nested tags are not allowed.
  codePattern := NewPattern("<?code")
  insertPattern := NewPattern("<?insert")
  openPatterns := []*Pattern{ &codePattern, &insertPattern }
  var open *Pattern
  close := NewPattern("?>")

  // Each character goes into the buffer, which we empty whenever we match
  // an opening or closing tag. In the former case the buffer must contain
  // static text, while the latter case is code or a template insertion.
  var buffer []rune
  var ch rune
  var size int
  countBytes, countRunes := 0, 0  // Byte and rune counts are logged.
  lineIndex := 1  // The line index is stored in template entries.

  for {
    ch, size, error = reader.ReadRune()
    if error == nil {
      buffer = append(buffer, ch)
      countBytes += size
      countRunes++
      if ch == '\n' {
        lineIndex++
      }
    } else {               // We assume that the read failed due to EOF.
      content := string(buffer)
      pushStatic(content)
      break
    }

    // Once a tag has been opened, we ignore further opening tags until
    // we have come across the closing tag. Nesting is not allowed.
    if open == nil {
      for _, pattern := range openPatterns {
        if pattern.Next(ch) {
          open = pattern
          content := string(buffer[:len(buffer)-open.Length])  // Remove tag.
          pushStatic(content)  // Text before an opening tag must be static.
          buffer = []rune{}
        }
      }
    } else {
      if close.Next(ch) {
        content := buffer[:len(buffer)-close.Length]  // Remove tag.
        if open == &codePattern {           // Code sections are just text.
          pushCode(string(content))
        } else if open == &insertPattern {  // Insertion requires more work.
          childPath := strings.TrimSpace(string(content))
          entry, error := MakeEntry(siteRoot, startDir, childPath,
              lineIndex)                    // We have to push a new template
          if error != nil {                 // entry onto the stack and make
            return error                    // a recursive call.
          }
          stack = append(stack, entry)
          error = doParse(siteRoot, startDir)
          if error != nil {
            return error
          }
          stack = stack[:len(stack)-1]
        }
        open = nil
        buffer = []rune{}
      }
    }
  }
  if verbose {
    fmt.Fprintf(log, "parsed \"%s\"\n", current.SitePath)
    fmt.Fprintf(log, "read %d bytes, %d runes\n", countBytes, countRunes)
    fmt.Fprintf(log, "finished on line %d\n", lineIndex)
  }
  if error == io.EOF {
    return nil
  }
  return error
}

// pushCode makes a code section and adds it to the global sections.
func pushCode(content string) {
  sections = append(sections, &Section{ Kind: CodeSection, Text: content })
}

// pushStatic makes a static section and adds it to the global sections.
func pushStatic(chunk string) {
  sections = append(sections, &Section{ Kind: StaticSection, Text: chunk })
}

// makeRawStrings splits a string into back-quoted strings and back quotes.
func makeRawStrings(content string) (pieces []string) {
  pieces = []string{}
  from := 0
  for pos, ch := range content {
    if ch == '`' {
      if pos != from {
        pieces = append(pieces, fmt.Sprintf("`%s`", content[from:pos]))
      }
      pieces = append(pieces, "'`'")
      from = pos+1
    }
  }
  if from != len(content) {
    pieces = append(pieces, fmt.Sprintf("`%s`", content[from:]))
  }
  return
}

// Process is the top-level template parsing function. It calls
// parse, then glues the sections together and injects an import statement
// as needed. The final result is printed to the global writer.
func Process(siteRoot, templatePath string, writer *bufio.Writer) {
  // We parse the template to obtain code sections and static sections.
  error := parse(siteRoot, templatePath)
  if error != nil {
    writer.WriteString(fmt.Sprintf("Template parsing error: %s\n", error))
    return
  }

  // Left-trim whitespace from any static text before code.
  for {
    section := sections[0]
    if section.Kind == CodeSection {
      break
    }
    text := section.Text
    firstNonSpace := -1
    for i, ch := range text {
      if !unicode.IsSpace(ch) {
        firstNonSpace = i
        break
      }
    }
    if firstNonSpace == -1 {  // Delete the leftmost section.
      sections = sections[1:]
      if len(sections) == 0 {
        break
      }
    } else {                  // Left-trim the leftmost section
      section.Text = text[firstNonSpace:]
      break
    }
  }

  // Right-trim whitespace from any static text after code.

  // Merge consecutive static sections.

  // Concatenate only the code sections. We're not adding print statements yet
  // because we don't know what the print command is going to look like. We
  // do want to parse the user's code in order to scan the imports.
  output := bytes.Buffer{}
  for _, section := range sections {
    if section.Kind == CodeSection {
      fmt.Fprintf(&output, section.Text)
    }
  }
  fileSet := token.NewFileSet()
  fileNode, error := parser.ParseFile(fileSet, "output", output.Bytes(),
      parser.ParseComments)
  if error != nil {
    writer.Write(output.Bytes())
    writer.WriteString(fmt.Sprintf(
        "\n---\nError parsing code sections: %s\n", error))
    return
  }

  seekPath := "fmt"  // The print command is to be found in this package.
  seekName := path.Base(seekPath)
  printCall := "Print"

  // Has the desired package been imported? Is the name available?
  isImported := false
  var importedAs string          // Use this if the path has been imported.
  seenName := map[string]bool{}  // Consult this if we have to import.

  for _, importSpec := range fileNode.Imports {
    importPath, _ := strconv.Unquote(importSpec.Path.Value)
    var importName string
    if importSpec.Name == nil {
      importName = path.Base(importPath)
    } else {
      importName = importSpec.Name.Name
    }
    seenName[importName] = true  // NB: underscore imports only run a package.
    if !isImported && importPath == seekPath && importName != "_" {
      isImported = true          // If the package is imported several times,
      importedAs = importName    // we use the name in the first occurrence.
    }
  }

  var importAs, printPrefix string  // NB: these are "" by default
  if isImported {
    if importedAs != "." {  // No prefix is needed with a dot import.
      printPrefix = importedAs+"."
    }
  } else {
    if !seenName[seekName] {
      importAs = seekName
    } else {                // Look for a name that hasn't been used yet.
      for i := 0; ; i++ {
        importAs = fmt.Sprintf("%s_%d", seekName, i)
        _, found := seenName[importAs]
        if !found {
          break
        }
      }
    }
    printPrefix = importAs+"."
  }

  // Concatenate the code with static sections wrapped in print statements.
  output.Reset()
  for _, section := range sections {
    if section.Kind == CodeSection {
      fmt.Fprintf(&output, section.Text)
    } else {
      pieces := makeRawStrings(section.Text)
      for _, piece := range pieces {
        s := fmt.Sprintf(";%s%s(%s);\n", printPrefix, printCall, piece)
        fmt.Fprintf(&output, s)
      }
    }
  }
  // Have Go parse the whole output in preparation for import injection
  // and formatted code output.
  fileSet = token.NewFileSet()
  fileNode, error = parser.ParseFile(fileSet, "output", output.Bytes(),
      parser.ParseComments)
  if error != nil {
    writer.Write(output.Bytes())
    writer.WriteString(fmt.Sprintf(
        "\n---\nError parsing entire template output: %s\n", error))
    return
  }
  // Inject an import statement if necessary.
  if !isImported {
    if importAs == seekName {  // Make 'import "fmt"', not 'import fmt "fmt"'.
      astutil.AddImport(fileSet, fileNode, seekPath)
    } else {                   // AddNamedImport would make 'import fmt "fmt"'.
      astutil.AddNamedImport(fileSet, fileNode, importAs, seekPath)
    }
  }

  // Print with a custom configuration: soft tabs of two spaces each.
  config := printer.Config{ Mode: printer.UseSpaces, Tabwidth: 2 }
  (&config).Fprint(writer, fileSet, fileNode)
}

<|endoftext|>


<commit_before>package dns

import "fmt"

// Version is current version of this library.
var Version = v{1, 1, 48}

// v holds the version of this library.
type v struct {
	Major, Minor, Patch int
}

func (v v) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<commit_msg>Release 1.1.49<commit_after>package dns

import "fmt"

// Version is current version of this library.
var Version = v{1, 1, 49}

// v holds the version of this library.
type v struct {
	Major, Minor, Patch int
}

func (v v) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<|endoftext|>


<commit_before>package main

// The git commit that was compiled. This will be filled in by the compiler.
var (
	GitCommit   string
	GitDescribe string
)

// The main version number that is being run at the moment.
const Version = "0.7.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = "dev"
<commit_msg>Preps for a smaller 0.6.1 release before 0.7.<commit_after>package main

// The git commit that was compiled. This will be filled in by the compiler.
var (
	GitCommit   string
	GitDescribe string
)

// The main version number that is being run at the moment.
const Version = "0.6.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = "dev"
<|endoftext|>


<commit_before>package main

const Version = "0.2.1"
<commit_msg>bump to v0.2.1+git<commit_after>package main

const Version = "0.2.1+git"
<|endoftext|>


<commit_before>package bitio

const (
	Name    = "bitio"
	Version = "1.4.1"
)
<commit_msg>bump ver<commit_after>package bitio

const (
	Name    = "bitio"
	Version = "1.4.2"
)
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 0
	appPatch uint = 10

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "alpha"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<commit_msg>Bump for v0.1.0 (#185)<commit_after>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 0
	appMinor uint = 1
	appPatch uint = 0

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = "beta"
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild string

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<|endoftext|>


<commit_before>package dispel

// Version represents the version of the API generated by dispel.
// Any visible change makes this version bump by 1.
const Version = 3
<commit_msg>bump dispel version<commit_after>package dispel

// Version represents the version of the API generated by dispel.
// Any visible change makes this version bump by 1.
const Version = 4
<|endoftext|>


<commit_before>package dsapid

const (
	AppName    string = "Dataset Image Server"
	AppVersion string = "0.6.1"
)
<commit_msg>bump version<commit_after>package dsapid

const (
	AppName    string = "Dataset Image Server"
	AppVersion string = "0.6.2"
)
<|endoftext|>


<commit_before>package version

import (
	"bytes"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

// The compiled regular expression used to test the validity of a version.
var versionRegexp *regexp.Regexp

// The raw regular expression string used for testing the validity
// of a version.
const VersionRegexpRaw string = `([0-9]+(\.[0-9]+){0,2})` +
	`(-([0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?` +
	`(\+([0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?` +
	`?`

// Version represents a single version.
type Version struct {
	metadata string
	pre      string
	segments []int
	si       int
}

func init() {
	versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$")
}

// NewVersion parses the given version and returns a new
// Version.
func NewVersion(v string) (*Version, error) {
	matches := versionRegexp.FindStringSubmatch(v)
	if matches == nil {
		return nil, fmt.Errorf("Malformed version: %s", v)
	}

	segmentsStr := strings.Split(matches[1], ".")
	segments := make([]int, len(segmentsStr), 3)
	si := 0
	for i, str := range segmentsStr {
		val, err := strconv.ParseInt(str, 10, 32)
		if err != nil {
			return nil, fmt.Errorf(
				"Error parsing version: %s", err)
		}

		segments[i] = int(val)
		si += 1
	}
	for i := len(segments); i < 3; i++ {
		segments = append(segments, 0)
	}

	return &Version{
		metadata: matches[7],
		pre:      matches[4],
		segments: segments,
		si:       si,
	}, nil
}

// Compare compares this version to another version. This
// returns -1, 0, or 1 if this version is smaller, equal,
// or larger than the other version, respectively.
//
// If you want boolean results, use the LessThan, Equal,
// or GreaterThan methods.
func (v *Version) Compare(other *Version) int {
	// A quick, efficient equality check
	if v.String() == other.String() {
		return 0
	}

	segmentsSelf := v.Segments()
	segmentsOther := other.Segments()

	// If the segments are the same, we must compare on prerelease info
	if reflect.DeepEqual(segmentsSelf, segmentsOther) {
		preSelf := v.Prerelease()
		preOther := other.Prerelease()
		if preSelf == "" && preOther == "" {
			return 0
		}
		if preSelf == "" {
			return 1
		}
		if preOther == "" {
			return -1
		}

		return comparePrereleases(preSelf, preOther)
	}

	// Compare the segments
	for i := 0; i < len(segmentsSelf); i++ {
		lhs := segmentsSelf[i]
		rhs := segmentsOther[i]

		if lhs == rhs {
			continue
		} else if lhs < rhs {
			return -1
		} else {
			return 1
		}
	}

	panic("should not be reached")
}

func comparePrereleases(v string, other string) int {
	// the same pre release!
	if v == other {
		return 0
	}

	// split both pre releases for analyse their parts
	selfPreReleaseMeta := strings.Split(v, ".")
	otherPreReleaseMeta := strings.Split(other, ".")

	selfPreReleaseLen := len(selfPreReleaseMeta)
	otherPreReleaseLen := len(otherPreReleaseMeta)

	biggestLen := otherPreReleaseLen
	if selfPreReleaseLen > otherPreReleaseLen {
		biggestLen = selfPreReleaseLen
	}

	// loop for parts to find the first difference
	for i:=0; i < biggestLen; i = i +1 {
		partSelfPre := ""
		if i < selfPreReleaseLen {
			partSelfPre = selfPreReleaseMeta[i]
		}

		partOtherPre := ""
		if i < otherPreReleaseLen {
			partOtherPre = otherPreReleaseMeta[i]
		}

		compare := comparePart(partSelfPre, partOtherPre)
		// if parts are equals, continue the loop
		if compare != 0 {
			return compare
		}
	}

	return 0
}

func comparePart(preSelf string, preOther string) int {
	if preSelf == preOther {
		return 0
	}

	// if a part is empty, we use the other to decide
	if preSelf == "" {
		_, notIsNumeric := strconv.ParseInt(preOther, 10, 64)
		if notIsNumeric == nil {
			return -1
		}
		return 1
	}

	if preOther == "" {
		_, notIsNumeric := strconv.ParseInt(preSelf, 10, 64)
		if notIsNumeric == nil {
			return 1
		}
		return -1
	}

	if preSelf > preOther {
		return 1
	}

	return -1
}

// Equal tests if two versions are equal.
func (v *Version) Equal(o *Version) bool {
	return v.Compare(o) == 0
}

// GreaterThan tests if this version is greater than another version.
func (v *Version) GreaterThan(o *Version) bool {
	return v.Compare(o) > 0
}

// LessThan tests if this version is less than another version.
func (v *Version) LessThan(o *Version) bool {
	return v.Compare(o) < 0
}

// Metadata returns any metadata that was part of the version
// string.
//
// Metadata is anything that comes after the "+" in the version.
// For example, with "1.2.3+beta", the metadata is "beta".
func (v *Version) Metadata() string {
	return v.metadata
}

// Prerelease returns any prerelease data that is part of the version,
// or blank if there is no prerelease data.
//
// Prerelease information is anything that comes after the "-" in the
// version (but before any metadata). For example, with "1.2.3-beta",
// the prerelease information is "beta".
func (v *Version) Prerelease() string {
	return v.pre
}

// Segments returns the numeric segments of the version as a slice.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments() []int {
	return v.segments
}

// String returns the full version string included pre-release
// and metadata information.
func (v *Version) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%d.%d.%d", v.segments[0], v.segments[1], v.segments[2])
	if v.pre != "" {
		fmt.Fprintf(&buf, "-%s", v.pre)
	}
	if v.metadata != "" {
		fmt.Fprintf(&buf, "+%s", v.metadata)
	}

	return buf.String()
}
<commit_msg>Move func to alphabetize<commit_after>package version

import (
	"bytes"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
)

// The compiled regular expression used to test the validity of a version.
var versionRegexp *regexp.Regexp

// The raw regular expression string used for testing the validity
// of a version.
const VersionRegexpRaw string = `([0-9]+(\.[0-9]+){0,2})` +
	`(-([0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?` +
	`(\+([0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?` +
	`?`

// Version represents a single version.
type Version struct {
	metadata string
	pre      string
	segments []int
	si       int
}

func init() {
	versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$")
}

// NewVersion parses the given version and returns a new
// Version.
func NewVersion(v string) (*Version, error) {
	matches := versionRegexp.FindStringSubmatch(v)
	if matches == nil {
		return nil, fmt.Errorf("Malformed version: %s", v)
	}

	segmentsStr := strings.Split(matches[1], ".")
	segments := make([]int, len(segmentsStr), 3)
	si := 0
	for i, str := range segmentsStr {
		val, err := strconv.ParseInt(str, 10, 32)
		if err != nil {
			return nil, fmt.Errorf(
				"Error parsing version: %s", err)
		}

		segments[i] = int(val)
		si += 1
	}
	for i := len(segments); i < 3; i++ {
		segments = append(segments, 0)
	}

	return &Version{
		metadata: matches[7],
		pre:      matches[4],
		segments: segments,
		si:       si,
	}, nil
}

// Compare compares this version to another version. This
// returns -1, 0, or 1 if this version is smaller, equal,
// or larger than the other version, respectively.
//
// If you want boolean results, use the LessThan, Equal,
// or GreaterThan methods.
func (v *Version) Compare(other *Version) int {
	// A quick, efficient equality check
	if v.String() == other.String() {
		return 0
	}

	segmentsSelf := v.Segments()
	segmentsOther := other.Segments()

	// If the segments are the same, we must compare on prerelease info
	if reflect.DeepEqual(segmentsSelf, segmentsOther) {
		preSelf := v.Prerelease()
		preOther := other.Prerelease()
		if preSelf == "" && preOther == "" {
			return 0
		}
		if preSelf == "" {
			return 1
		}
		if preOther == "" {
			return -1
		}

		return comparePrereleases(preSelf, preOther)
	}

	// Compare the segments
	for i := 0; i < len(segmentsSelf); i++ {
		lhs := segmentsSelf[i]
		rhs := segmentsOther[i]

		if lhs == rhs {
			continue
		} else if lhs < rhs {
			return -1
		} else {
			return 1
		}
	}

	panic("should not be reached")
}

func comparePart(preSelf string, preOther string) int {
	if preSelf == preOther {
		return 0
	}

	// if a part is empty, we use the other to decide
	if preSelf == "" {
		_, notIsNumeric := strconv.ParseInt(preOther, 10, 64)
		if notIsNumeric == nil {
			return -1
		}
		return 1
	}

	if preOther == "" {
		_, notIsNumeric := strconv.ParseInt(preSelf, 10, 64)
		if notIsNumeric == nil {
			return 1
		}
		return -1
	}

	if preSelf > preOther {
		return 1
	}

	return -1
}

func comparePrereleases(v string, other string) int {
	// the same pre release!
	if v == other {
		return 0
	}

	// split both pre releases for analyse their parts
	selfPreReleaseMeta := strings.Split(v, ".")
	otherPreReleaseMeta := strings.Split(other, ".")

	selfPreReleaseLen := len(selfPreReleaseMeta)
	otherPreReleaseLen := len(otherPreReleaseMeta)

	biggestLen := otherPreReleaseLen
	if selfPreReleaseLen > otherPreReleaseLen {
		biggestLen = selfPreReleaseLen
	}

	// loop for parts to find the first difference
	for i:=0; i < biggestLen; i = i +1 {
		partSelfPre := ""
		if i < selfPreReleaseLen {
			partSelfPre = selfPreReleaseMeta[i]
		}

		partOtherPre := ""
		if i < otherPreReleaseLen {
			partOtherPre = otherPreReleaseMeta[i]
		}

		compare := comparePart(partSelfPre, partOtherPre)
		// if parts are equals, continue the loop
		if compare != 0 {
			return compare
		}
	}

	return 0
}

// Equal tests if two versions are equal.
func (v *Version) Equal(o *Version) bool {
	return v.Compare(o) == 0
}

// GreaterThan tests if this version is greater than another version.
func (v *Version) GreaterThan(o *Version) bool {
	return v.Compare(o) > 0
}

// LessThan tests if this version is less than another version.
func (v *Version) LessThan(o *Version) bool {
	return v.Compare(o) < 0
}

// Metadata returns any metadata that was part of the version
// string.
//
// Metadata is anything that comes after the "+" in the version.
// For example, with "1.2.3+beta", the metadata is "beta".
func (v *Version) Metadata() string {
	return v.metadata
}

// Prerelease returns any prerelease data that is part of the version,
// or blank if there is no prerelease data.
//
// Prerelease information is anything that comes after the "-" in the
// version (but before any metadata). For example, with "1.2.3-beta",
// the prerelease information is "beta".
func (v *Version) Prerelease() string {
	return v.pre
}

// Segments returns the numeric segments of the version as a slice.
//
// This excludes any metadata or pre-release information. For example,
// for a version "1.2.3-beta", segments will return a slice of
// 1, 2, 3.
func (v *Version) Segments() []int {
	return v.segments
}

// String returns the full version string included pre-release
// and metadata information.
func (v *Version) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "%d.%d.%d", v.segments[0], v.segments[1], v.segments[2])
	if v.pre != "" {
		fmt.Fprintf(&buf, "-%s", v.pre)
	}
	if v.metadata != "" {
		fmt.Fprintf(&buf, "+%s", v.metadata)
	}

	return buf.String()
}
<|endoftext|>


<commit_before>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2021

package instana

// Version is the version of Instana sensor
const Version = "1.27.3"
<commit_msg>Bump go-sensor version to 1.27.4<commit_after>// (c) Copyright IBM Corp. 2021
// (c) Copyright Instana Inc. 2021

package instana

// Version is the version of Instana sensor
const Version = "1.27.4"
<|endoftext|>


<commit_before>package dns

import "fmt"

// Version is current version of this library.
var Version = V{1, 1, 16}

// V holds the version of this library.
type V struct {
	Major, Minor, Patch int
}

func (v V) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<commit_msg>Release 1.1.17<commit_after>package dns

import "fmt"

// Version is current version of this library.
var Version = V{1, 1, 17}

// V holds the version of this library.
type V struct {
	Major, Minor, Patch int
}

func (v V) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<|endoftext|>


<commit_before>package main

import (
	"runtime"

	"github.com/samsalisbury/semv"
)

// VersionString is the version of Sous.
const VersionString = "0.1.1-beta"

var (
	// Version is the version of Sous.
	Version = semv.MustParse(VersionString + "+" + Revision)
	// OS is the OS this Sous is running on.
	OS = runtime.GOOS
	// Arch is the architecture this Sous is running on.
	Arch = runtime.GOARCH
	// GoVersion is the version of Go this sous was built with.
	GoVersion = runtime.Version()
	// Revision may be set by the build process using build flags.
	Revision string
)
<commit_msg>Up version to 0.1.1-beta.1<commit_after>package main

import (
	"runtime"

	"github.com/samsalisbury/semv"
)

// VersionString is the version of Sous.
const VersionString = "0.1.1-beta.1"

var (
	// Version is the version of Sous.
	Version = semv.MustParse(VersionString + "+" + Revision)
	// OS is the OS this Sous is running on.
	OS = runtime.GOOS
	// Arch is the architecture this Sous is running on.
	Arch = runtime.GOARCH
	// GoVersion is the version of Go this sous was built with.
	GoVersion = runtime.Version()
	// Revision may be set by the build process using build flags.
	Revision string
)
<|endoftext|>


<commit_before>package main

// App version variables

// Version set in source code
const Version = "0.11"

// Build time filled by make on program build
var Build string

// Commit tag from git, filled in by the compiler.
var Commit string
<commit_msg>v0.12<commit_after>package main

// App version variables

// Version set in source code
const Version = "0.12"

// Build time filled by make on program build
var Build string

// Commit tag from git, filled in by the compiler.
var Commit string
<|endoftext|>


<commit_before>// example/example.go
package main

import (
	"flag"
	"log"
	"time"

	"golang.org/x/net/context"

	"github.com/knq/firebase"
)

type Person struct {
	Name      string                   `json:"name"`
	Birthdate time.Time                `json:"birth_date"`
	Created   firebase.ServerTimestamp `json:"created"`
}

var (
	flagCredentialsFile = flag.String("c", "test-1470ffbcc1d8.json", "credentials file")
)

func main() {
	var err error

	flag.Parse()

	// create initial firebase database ref using Google service account
	// credentials as downloaded from the Google cloud console
	db, err := firebase.NewDatabaseRef(
		firebase.GoogleServiceAccountCredentialsFile(*flagCredentialsFile),
		//firebase.Log(log.Printf, log.Printf), // uncomment this to see the actual HTTP requests
	)
	if err != nil {
		log.Fatal(err)
	}

	// apply security rules
	log.Printf("setting security rules")
	err = db.SetRulesJSON([]byte(securityRules))
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("security rules applied successfully")

	// set up a listen context and start listener
	ctxt, cancel := context.WithCancel(context.Background())
	defer cancel()
	go startListen(db.Ref("/people"), ctxt)

	// do a short wait
	time.Sleep(5 * time.Second)

	john := &Person{
		Name:      "john doe",
		Birthdate: time.Now().Add(-18 * 365 * 24 * time.Hour),
	}

	// push john
	log.Printf("pushing john: %+v", john)
	johnID, err := db.Ref("/people").Push(john)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("created: john (%s)", johnID)

	// retrieve john
	var john1 Person
	err = db.Ref("/people/" + johnID).Get(&john1)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("retrieved john (%s): %+v", johnID, john1)

	// set john (causes all values to be overwritten)
	john.Name = "Jon Dunce"
	log.Printf("setting john (%s) to: %+v", johnID, john)
	err = db.Ref("/people/" + johnID).Set(john)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("successfully set john (%s)", johnID)

	// update a value on john
	log.Printf("adding nickname to john (%s)", johnID)
	err = db.Ref("/people/" + johnID).Update(map[string]interface{}{
		"nickname": "JD",
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("successfully updated john (%s)", johnID)

	// get john again
	log.Printf("retrieving john (%s)", johnID)
	john2 := make(map[string]interface{})
	err = db.Ref("/people/" + johnID).Get(&john2)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("successfully retrieved john (%s): %+v", johnID, john2)

	//-------------------------------------------------------
	emily := Person{
		Name:      "Emily Smith",
		Birthdate: time.Now().Add(-22 * 365 * 24 * time.Hour),
	}

	// create Emily
	log.Printf("pushing emily")
	emilyID, err := db.Ref("/people/").Push(emily)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("created emily (%s)", emilyID)

	// create an authenticated ref for Emily and retrieve john as emily
	emilyDB := db.Ref("/people", firebase.UserID(emilyID))
	var johnE Person
	log.Printf("retrieving john (%s) as emily (%s)", johnID, emilyID)
	err = emilyDB.Ref(johnID).Get(&johnE)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("emily got john: %+v", johnE)

	// try to write as emily to john's data (should error)
	err = emilyDB.Ref(johnID).Update(map[string]interface{}{
		"name": "not john",
	})
	if err == nil {
		log.Fatal("emily should not be able to write to john's entry")
	}
	log.Printf("emily could not write to john as expected (got: %v)", err)

	// create authenticated "admin" ref
	adminDB := db.Ref("/people")
	adminDB.SetQueryOptions(
		firebase.AuthOverride(map[string]interface{}{
			"uid":   "<admin>",
			"admin": true,
		}),
	)

	// retrieve a shallow map (ie, the keys) using the admin ref
	log.Printf("retrieving all keys as admin")
	keys := make(map[string]interface{})
	err = adminDB.Get(&keys, firebase.Shallow)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("admin retrieved keys: %+v", keys)

	// delete keys
	for key, _ := range keys {
		log.Printf("admin removing %s", key)
		err = adminDB.Ref(key).Remove()
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("admin removed %s", key)
	}

	// wait before returning to see at least one keep alive event
	log.Printf("waiting 45 seconds to see at least one keep alive event")
	time.Sleep(45 * time.Second)
}

// startListen starts a listener on the ref.
func startListen(r *firebase.Ref, ctxt context.Context) {
	eventTypes := []firebase.EventType{
		firebase.EventTypePut,
		firebase.EventTypePatch,
		firebase.EventTypeKeepAlive,
	}

	log.Printf("listening for events %v on %s", eventTypes, r.URL().String())

	evs := r.Listen(ctxt, eventTypes)
	for e := range evs {
		if e == nil {
			log.Printf("listen events channel closed")
			return
		}

		log.Printf("server event: %s", e.String())
	}
}

// securityRules provides security rules where only authenticated users can
// read the /people/*/ data, but only the owner or an administrator can write.
const securityRules = `{
  "rules": {
    ".read": "auth !== null",
    ".write": "false",
    "people": {
      "$uid": {
		".read": "auth !== null && auth.uid !== null",
        ".write": "auth !== null && auth.uid !== null && ($uid === auth.uid || auth.admin === true)"
      }
    }
  }
}`
<commit_msg>Fixing spacing in the example.go security rules<commit_after>// example/example.go
package main

import (
	"flag"
	"log"
	"time"

	"golang.org/x/net/context"

	"github.com/knq/firebase"
)

type Person struct {
	Name      string                   `json:"name"`
	Birthdate time.Time                `json:"birth_date"`
	Created   firebase.ServerTimestamp `json:"created"`
}

var (
	flagCredentialsFile = flag.String("c", "test-1470ffbcc1d8.json", "credentials file")
)

func main() {
	var err error

	flag.Parse()

	// create initial firebase database ref using Google service account
	// credentials as downloaded from the Google cloud console
	db, err := firebase.NewDatabaseRef(
		firebase.GoogleServiceAccountCredentialsFile(*flagCredentialsFile),
		//firebase.Log(log.Printf, log.Printf), // uncomment this to see the actual HTTP requests
	)
	if err != nil {
		log.Fatal(err)
	}

	// apply security rules
	log.Printf("setting security rules")
	err = db.SetRulesJSON([]byte(securityRules))
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("security rules applied successfully")

	// set up a listen context and start listener
	ctxt, cancel := context.WithCancel(context.Background())
	defer cancel()
	go startListen(db.Ref("/people"), ctxt)

	// do a short wait
	time.Sleep(5 * time.Second)

	john := &Person{
		Name:      "john doe",
		Birthdate: time.Now().Add(-18 * 365 * 24 * time.Hour),
	}

	// push john
	log.Printf("pushing john: %+v", john)
	johnID, err := db.Ref("/people").Push(john)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("created: john (%s)", johnID)

	// retrieve john
	var john1 Person
	err = db.Ref("/people/" + johnID).Get(&john1)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("retrieved john (%s): %+v", johnID, john1)

	// set john (causes all values to be overwritten)
	john.Name = "Jon Dunce"
	log.Printf("setting john (%s) to: %+v", johnID, john)
	err = db.Ref("/people/" + johnID).Set(john)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("successfully set john (%s)", johnID)

	// update a value on john
	log.Printf("adding nickname to john (%s)", johnID)
	err = db.Ref("/people/" + johnID).Update(map[string]interface{}{
		"nickname": "JD",
	})
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("successfully updated john (%s)", johnID)

	// get john again
	log.Printf("retrieving john (%s)", johnID)
	john2 := make(map[string]interface{})
	err = db.Ref("/people/" + johnID).Get(&john2)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("successfully retrieved john (%s): %+v", johnID, john2)

	//-------------------------------------------------------
	emily := Person{
		Name:      "Emily Smith",
		Birthdate: time.Now().Add(-22 * 365 * 24 * time.Hour),
	}

	// create Emily
	log.Printf("pushing emily")
	emilyID, err := db.Ref("/people/").Push(emily)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("created emily (%s)", emilyID)

	// create an authenticated ref for Emily and retrieve john as emily
	emilyDB := db.Ref("/people", firebase.UserID(emilyID))
	var johnE Person
	log.Printf("retrieving john (%s) as emily (%s)", johnID, emilyID)
	err = emilyDB.Ref(johnID).Get(&johnE)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("emily got john: %+v", johnE)

	// try to write as emily to john's data (should error)
	err = emilyDB.Ref(johnID).Update(map[string]interface{}{
		"name": "not john",
	})
	if err == nil {
		log.Fatal("emily should not be able to write to john's entry")
	}
	log.Printf("emily could not write to john as expected (got: %v)", err)

	// create authenticated "admin" ref
	adminDB := db.Ref("/people")
	adminDB.SetQueryOptions(
		firebase.AuthOverride(map[string]interface{}{
			"uid":   "<admin>",
			"admin": true,
		}),
	)

	// retrieve a shallow map (ie, the keys) using the admin ref
	log.Printf("retrieving all keys as admin")
	keys := make(map[string]interface{})
	err = adminDB.Get(&keys, firebase.Shallow)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("admin retrieved keys: %+v", keys)

	// delete keys
	for key, _ := range keys {
		log.Printf("admin removing %s", key)
		err = adminDB.Ref(key).Remove()
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("admin removed %s", key)
	}

	// wait before returning to see at least one keep alive event
	log.Printf("waiting 45 seconds to see at least one keep alive event")
	time.Sleep(45 * time.Second)
}

// startListen starts a listener on the ref.
func startListen(r *firebase.Ref, ctxt context.Context) {
	eventTypes := []firebase.EventType{
		firebase.EventTypePut,
		firebase.EventTypePatch,
		firebase.EventTypeKeepAlive,
	}

	log.Printf("listening for events %v on %s", eventTypes, r.URL().String())

	evs := r.Listen(ctxt, eventTypes)
	for e := range evs {
		if e == nil {
			log.Printf("listen events channel closed")
			return
		}

		log.Printf("server event: %s", e.String())
	}
}

// securityRules provides security rules where only authenticated users can
// read the /people/*/ data, but only the owner or an administrator can write.
const securityRules = `{
  "rules": {
    ".read": "auth !== null",
    ".write": "false",
    "people": {
      "$uid": {
        ".read": "auth !== null && auth.uid !== null",
        ".write": "auth !== null && auth.uid !== null && ($uid === auth.uid || auth.admin === true)"
      }
    }
  }
}`
<|endoftext|>


<commit_before>package authenticator

import (
	"github.com/gorilla/securecookie"
	"net/http"
	"strings"
)

type Authenticator struct {
	Login  string
	Logout string
	Secret string
	Token  string
}

func NewAuthenticator() *Authenticator {
	return &Authenticator{"/login", "/logout", "secret", "auth"}
}

func (a *Authenticator) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	var hashKey = []byte(a.Secret)
	var blockKey = []byte("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
	var s = securecookie.New(hashKey, blockKey)

	if !strings.Contains(r.URL.Path, "admin") {
		next(rw, r)
		return
	}

	var illegalCookie bool
	if cookie, cookieerr := r.Cookie("user"); cookieerr != nil {
		results := make(map[string]string)
		tampered := s.Decode("user", cookie.Value, &results)
		if tampered != nil {
			http.Error(rw, "Unauthorized", 401)
			illegalCookie = true
		} else {
			illegalCookie = true
		}
	}

	if illegalCookie == false {
		_, err := r.Cookie("user")
		if err != nil {
			r.URL.Path = a.Login
			cookie := http.Cookie{Name: "redirect", Value: r.URL.Path, Path: "/"}
			http.SetCookie(rw, &cookie)
			http.Redirect(rw, r, a.Login, 401)
		} else {
			next(rw, r)
		}
		return
	}
	next(rw, r)
}
<commit_msg>small fixes<commit_after>package authenticator

import (
	"github.com/gorilla/securecookie"
	"net/http"
	"strings"
)

type Authenticator struct {
	Login  string
	Logout string
	Secret string
	Token  string
}

func NewAuthenticator() *Authenticator {
	return &Authenticator{"/login", "/logout", "secret", "auth"}
}

func (a *Authenticator) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	var hashKey = []byte(a.Secret)
	var blockKey = []byte("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
	var s = securecookie.New(hashKey, blockKey)

	if !strings.Contains(r.URL.Path, "admin") {
		next(rw, r)
		return
	}

	var illegalCookie bool
	if cookie, cookieerr := r.Cookie("user"); cookieerr == nil {
		results := make(map[string]string)
		tampered := s.Decode("user", cookie.Value, &results)
		if tampered != nil {
			http.Error(rw, "Unauthorized", 401)
			illegalCookie = true
		} else {
			illegalCookie = false
		}
	} else {
		illegalCookie = false
	}

	if illegalCookie == false {
		_, err := r.Cookie("user")
		if err != nil {
			http.Redirect(rw, r, a.Login, 401)
			cookie := http.Cookie{Name: "redirect", Value: r.URL.Path, Path: "/"}
			http.SetCookie(rw, &cookie)
		} else {
			next(rw, r)
		}
		return
	}
	next(rw, r)
}
<|endoftext|>


<commit_before>package jiracmd

import (
	"fmt"
	"strings"

	"github.com/coryb/figtree"
	"github.com/coryb/oreo"

	"gopkg.in/Netflix-Skunkworks/go-jira.v1"
	"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
	"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

type TransitionOptions struct {
	jiracli.CommonOptions `yaml:",inline" json:",inline" figtree:",inline"`
	Overrides             map[string]string `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	Transition            string            `yaml:"transition,omitempty" json:"transition,omitempty"`
	Issue                 string            `yaml:"issue,omitempty" json:"issue,omitempty"`
	Resolution            string            `yaml:"resolution,omitempty" json:"resolution,omitempty"`
}

func CmdTransitionRegistry(transition string) *jiracli.CommandRegistryEntry {
	opts := TransitionOptions{
		CommonOptions: jiracli.CommonOptions{
			Template: figtree.NewStringOption("transition"),
		},
		Overrides: map[string]string{},
	}

	help := "Transition issue to given state"
	if transition != "" {
		help = fmt.Sprintf("Transition issue to %s state", transition)
		opts.SkipEditing = figtree.NewBoolOption(true)
	}

	return &jiracli.CommandRegistryEntry{
		help,
		func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
			jiracli.LoadConfigs(cmd, fig, &opts)
			if opts.Transition == "" {
				opts.Transition = transition
			}
			return CmdTransitionUsage(cmd, &opts)
		},
		func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
			return CmdTransition(o, globals, &opts)
		},
	}
}

func CmdTransitionUsage(cmd *kingpin.CmdClause, opts *TransitionOptions) error {
	jiracli.BrowseUsage(cmd, &opts.CommonOptions)
	jiracli.TemplateUsage(cmd, &opts.CommonOptions)
	cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
	cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
		opts.Overrides["comment"] = jiracli.FlagValue(ctx, "comment")
		return nil
	}).String()
	cmd.Flag("override", "Set issue property").Short('o').StringMapVar(&opts.Overrides)
	if opts.Transition == "" {
		cmd.Arg("TRANSITION", "State to transition issue to").Required().StringVar(&opts.Transition)
	}
	cmd.Arg("ISSUE", "issue to transition").Required().StringVar(&opts.Issue)
	return nil
}

func defaultResolution(transMeta *jiradata.Transition) string {
	if resField, ok := transMeta.Fields["resolution"]; ok {
		for _, allowedValueRaw := range resField.AllowedValues {
			if allowedValue, ok := allowedValueRaw.(map[string]interface{}); ok {
				if allowedValue["name"] == "Fixed" {
					return "Fixed"
				} else if allowedValue["name"] == "Done" {
					return "Done"
				}
			}
		}
	}
	return ""
}

// CmdTransition will move state of the given issue to the given transtion
func CmdTransition(o *oreo.Client, globals *jiracli.GlobalOptions, opts *TransitionOptions) error {
	issueData, err := jira.GetIssue(o, globals.Endpoint.Value, opts.Issue, nil)
	if err != nil {
		return jiracli.CliError(err)
	}

	meta, err := jira.GetIssueTransitions(o, globals.Endpoint.Value, opts.Issue)
	if err != nil {
		return jiracli.CliError(err)
	}
	transMeta := meta.Transitions.Find(opts.Transition)

	if transMeta == nil {
		possible := []string{}
		for _, trans := range meta.Transitions {
			possible = append(possible, trans.Name)
		}

		if status, ok := issueData.Fields["status"].(map[string]interface{}); ok {
			if name, ok := status["name"].(string); ok {
				return jiracli.CliError(fmt.Errorf("Invalid Transition %q from %q, Available: %s", opts.Transition, name, strings.Join(possible, ", ")))
			}
		}
		return jiracli.CliError(fmt.Errorf("No valid transition found matching %s", opts.Transition))
	}

	// need to default the Resolution, usually Fixed works but sometime need Done
	if opts.Resolution == "" {
		if resField, ok := transMeta.Fields["resolution"]; ok {
			for _, allowedValueRaw := range resField.AllowedValues {
				if allowedValue, ok := allowedValueRaw.(map[string]interface{}); ok {
					if allowedValue["name"] == "Fixed" {
						opts.Resolution = "Fixed"
					} else if allowedValue["name"] == "Done" {
						opts.Resolution = "Done"
					}
				}
			}
		}
	}
	opts.Overrides["resolution"] = opts.Resolution

	type templateInput struct {
		*jiradata.Issue `yaml:",inline"`
		// Yes, Meta and Transition are redundant, but this is for backwards compatibility
		// with old templates
		Meta       *jiradata.Transition `yaml:"meta,omitempty" json:"meta,omitemtpy"`
		Transition *jiradata.Transition `yaml:"transition,omitempty" json:"transition,omitempty"`
		Overrides  map[string]string    `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	}

	issueUpdate := jiradata.IssueUpdate{}
	input := templateInput{
		Issue:      issueData,
		Meta:       transMeta,
		Transition: transMeta,
		Overrides:  opts.Overrides,
	}
	err = jiracli.EditLoop(&opts.CommonOptions, &input, &issueUpdate, func() error {
		return jira.TransitionIssue(o, globals.Endpoint.Value, opts.Issue, &issueUpdate)
	})
	if err != nil {
		return jiracli.CliError(err)
	}
	if !globals.Quiet.Value {
		fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, globals.Endpoint.Value, issueData.Key)
	}

	if opts.Browse.Value {
		return CmdBrowse(globals, opts.Issue)
	}
	return nil
}
<commit_msg>[#45] automatically add comment to issue even if transition does not support comment updates during transtion<commit_after>package jiracmd

import (
	"fmt"
	"strings"

	"github.com/coryb/figtree"
	"github.com/coryb/oreo"

	"gopkg.in/Netflix-Skunkworks/go-jira.v1"
	"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiracli"
	"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

type TransitionOptions struct {
	jiracli.CommonOptions `yaml:",inline" json:",inline" figtree:",inline"`
	Overrides             map[string]string `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	Transition            string            `yaml:"transition,omitempty" json:"transition,omitempty"`
	Issue                 string            `yaml:"issue,omitempty" json:"issue,omitempty"`
	Resolution            string            `yaml:"resolution,omitempty" json:"resolution,omitempty"`
}

func CmdTransitionRegistry(transition string) *jiracli.CommandRegistryEntry {
	opts := TransitionOptions{
		CommonOptions: jiracli.CommonOptions{
			Template: figtree.NewStringOption("transition"),
		},
		Overrides: map[string]string{},
	}

	help := "Transition issue to given state"
	if transition != "" {
		help = fmt.Sprintf("Transition issue to %s state", transition)
		opts.SkipEditing = figtree.NewBoolOption(true)
	}

	return &jiracli.CommandRegistryEntry{
		help,
		func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
			jiracli.LoadConfigs(cmd, fig, &opts)
			if opts.Transition == "" {
				opts.Transition = transition
			}
			return CmdTransitionUsage(cmd, &opts)
		},
		func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
			return CmdTransition(o, globals, &opts)
		},
	}
}

func CmdTransitionUsage(cmd *kingpin.CmdClause, opts *TransitionOptions) error {
	jiracli.BrowseUsage(cmd, &opts.CommonOptions)
	jiracli.TemplateUsage(cmd, &opts.CommonOptions)
	cmd.Flag("noedit", "Disable opening the editor").SetValue(&opts.SkipEditing)
	cmd.Flag("comment", "Comment message for issue").Short('m').PreAction(func(ctx *kingpin.ParseContext) error {
		opts.Overrides["comment"] = jiracli.FlagValue(ctx, "comment")
		return nil
	}).String()
	cmd.Flag("override", "Set issue property").Short('o').StringMapVar(&opts.Overrides)
	if opts.Transition == "" {
		cmd.Arg("TRANSITION", "State to transition issue to").Required().StringVar(&opts.Transition)
	}
	cmd.Arg("ISSUE", "issue to transition").Required().StringVar(&opts.Issue)
	return nil
}

func defaultResolution(transMeta *jiradata.Transition) string {
	if resField, ok := transMeta.Fields["resolution"]; ok {
		for _, allowedValueRaw := range resField.AllowedValues {
			if allowedValue, ok := allowedValueRaw.(map[string]interface{}); ok {
				if allowedValue["name"] == "Fixed" {
					return "Fixed"
				} else if allowedValue["name"] == "Done" {
					return "Done"
				}
			}
		}
	}
	return ""
}

// CmdTransition will move state of the given issue to the given transtion
func CmdTransition(o *oreo.Client, globals *jiracli.GlobalOptions, opts *TransitionOptions) error {
	issueData, err := jira.GetIssue(o, globals.Endpoint.Value, opts.Issue, nil)
	if err != nil {
		return jiracli.CliError(err)
	}

	meta, err := jira.GetIssueTransitions(o, globals.Endpoint.Value, opts.Issue)
	if err != nil {
		return jiracli.CliError(err)
	}
	transMeta := meta.Transitions.Find(opts.Transition)

	if transMeta == nil {
		possible := []string{}
		for _, trans := range meta.Transitions {
			possible = append(possible, trans.Name)
		}

		if status, ok := issueData.Fields["status"].(map[string]interface{}); ok {
			if name, ok := status["name"].(string); ok {
				return jiracli.CliError(fmt.Errorf("Invalid Transition %q from %q, Available: %s", opts.Transition, name, strings.Join(possible, ", ")))
			}
		}
		return jiracli.CliError(fmt.Errorf("No valid transition found matching %s", opts.Transition))
	}

	// need to default the Resolution, usually Fixed works but sometime need Done
	if opts.Resolution == "" {
		if resField, ok := transMeta.Fields["resolution"]; ok {
			for _, allowedValueRaw := range resField.AllowedValues {
				if allowedValue, ok := allowedValueRaw.(map[string]interface{}); ok {
					if allowedValue["name"] == "Fixed" {
						opts.Resolution = "Fixed"
					} else if allowedValue["name"] == "Done" {
						opts.Resolution = "Done"
					}
				}
			}
		}
	}
	opts.Overrides["resolution"] = opts.Resolution

	type templateInput struct {
		*jiradata.Issue `yaml:",inline"`
		// Yes, Meta and Transition are redundant, but this is for backwards compatibility
		// with old templates
		Meta       *jiradata.Transition `yaml:"meta,omitempty" json:"meta,omitemtpy"`
		Transition *jiradata.Transition `yaml:"transition,omitempty" json:"transition,omitempty"`
		Overrides  map[string]string    `yaml:"overrides,omitempty" json:"overrides,omitempty"`
	}

	if _, ok := transMeta.Fields["comment"]; !ok && opts.Overrides["comment"] != "" {
		comment := jiradata.Comment{
			Body: opts.Overrides["comment"],
		}
		if _, err := jira.IssueAddComment(o, globals.Endpoint.Value, opts.Issue, &comment); err != nil {
			return err
		}
	}

	issueUpdate := jiradata.IssueUpdate{}
	input := templateInput{
		Issue:      issueData,
		Meta:       transMeta,
		Transition: transMeta,
		Overrides:  opts.Overrides,
	}
	err = jiracli.EditLoop(&opts.CommonOptions, &input, &issueUpdate, func() error {
		return jira.TransitionIssue(o, globals.Endpoint.Value, opts.Issue, &issueUpdate)
	})
	if err != nil {
		return jiracli.CliError(err)
	}
	if !globals.Quiet.Value {
		fmt.Printf("OK %s %s/browse/%s\n", issueData.Key, globals.Endpoint.Value, issueData.Key)
	}

	if opts.Browse.Value {
		return CmdBrowse(globals, opts.Issue)
	}
	return nil
}
<|endoftext|>


<commit_before>package fsm

import (
	"reflect"
	"testing"

	stdopentracing "github.com/opentracing/opentracing-go"
	"github.com/travisjeffery/jocko/jocko/structs"
	"github.com/travisjeffery/jocko/log"
)

func testStore(t *testing.T) *Store {
	s, err := NewStore(log.New(), stdopentracing.GlobalTracer())
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if s == nil {
		t.Fatalf("missing store")
	}
	return s
}

func testRegisterNode(t *testing.T, s *Store, idx uint64, nodeID int32) {
	testRegisterNodeWithMeta(t, s, idx, nodeID, nil)
}

func testRegisterNodeWithMeta(t *testing.T, s *Store, idx uint64, nodeID int32, meta map[string]string) {
	node := &structs.Node{Node: nodeID, Meta: meta}
	if err := s.EnsureNode(idx, node); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	n, err := tx.First("nodes", "id", nodeID)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := n.(*structs.Node); !ok || result.Node != nodeID {
		t.Fatalf("bad node: %#v", result)
	}
}

func TestStore_maxIndex(t *testing.T) {
	s := testStore(t)
	testRegisterNode(t, s, 0, 1)
	testRegisterNode(t, s, 1, 2)

	if max := s.maxIndex("nodes", "services"); max != 1 {
		t.Fatalf("bad max: %d", max)
	}
}

func TestStore_Abandon(t *testing.T) {
	s := testStore(t)
	abandonCh := s.AbandonCh()
	s.Abandon()
	select {
	case <-abandonCh:
	default:
		t.Fatalf("bad")
	}
}

func TestStore_DeleteNode(t *testing.T) {
	s := testStore(t)

	// add the node
	testRegisterNode(t, s, 0, 1)

	if idx, ns, err := s.GetNodes(); err != nil || len(ns) != 1 || idx != 0 {
		t.Fatalf("bad: %#v %d (err: %#v)", ns, idx, err)
	}

	// delete the node
	if err := s.DeleteNode(1, 1); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, n, err := s.GetNode(1); err != nil || n != nil || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %#v)", n, idx, err)
	}

	if idx, ns, err := s.GetNodes(); err != nil || len(ns) != 0 || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %#v)", ns, idx, err)
	}

	// index is updated
	if idx := s.maxIndex("nodes"); idx != 1 {
		t.Fatalf("bad index: %d", idx)
	}

	// deleting should be idempotent
	if err := s.DeleteNode(4, 1); err != nil {
		t.Fatalf("err: %s", err)
	}
	if idx := s.maxIndex("nodes"); idx != 1 {
		t.Fatalf("bad index: %d", idx)
	}
}

func TestStore_RegisterTopic(t *testing.T) {
	s := testStore(t)

	if _, topic, err := s.GetTopic("unknown-topic"); topic != nil && err != nil {
		t.Fatalf("err: %s, topic: %v", err, topic)
	}

	testRegisterTopic(t, s, 0, "topic1")

	if idx, topics, err := s.GetTopics(); err != nil || idx != 0 || !reflect.DeepEqual(topics, []*structs.Topic{{Topic: "topic1"}}) {
		t.Fatalf("err: %s", err)
	}

	// delete the topic
	if err := s.DeleteTopic(1, "topic1"); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, top, err := s.GetTopic("topic1"); err != nil || top != nil || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %s)", top, idx, err)
	}

	// check index is updated
	if idx := s.maxIndex("topics"); idx != 1 {
		t.Fatalf("err: %v", idx)
	}

	// deleting should be idempotent
	if err := s.DeleteTopic(2, "topic1"); err != nil {
		t.Fatalf("err: %s", err)
	}
	if idx := s.maxIndex("topics"); idx != 1 {
		t.Fatalf("err: %v", idx)
	}
}

func testRegisterTopic(t *testing.T, s *Store, idx uint64, id string) {
	if err := s.EnsureTopic(idx, &structs.Topic{Topic: id}); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	top, err := tx.First("topics", "id", id)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := top.(*structs.Topic); !ok || result.Topic != id {
		t.Fatalf("bad topic: %#v", result)
	}
}

func TestStore_RegisterPartition(t *testing.T) {
	s := testStore(t)

	testRegisterPartition(t, s, 0, 1, "test-topic")

	if _, p, err := s.GetPartition("test-topic", 1); err != nil || p == nil {
		t.Fatalf("err: %s, partition: %v", err, p)
	}

	if _, p, err := s.PartitionsByLeader(partitionLeader); err != nil || p == nil || len(p) != 1 {
		t.Fatalf("err: %s, partition: %v", err, p)
	}

	// delete the partition
	if err := s.DeletePartition(1, "test-topic", 1); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, top, err := s.GetPartition("test-topic", 1); err != nil || top != nil || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %s)", top, idx, err)
	}

	// check index is updated
	if idx := s.maxIndex("partitions"); idx != 1 {
		t.Fatalf("err: %d", idx)
	}

	// deleting should be idempotent
	if err := s.DeletePartition(2, "test-topic", 1); err != nil {
		t.Fatalf("err: %d", err)
	}
	if idx := s.maxIndex("partitions"); idx != 1 {
		t.Fatalf("err: %d", idx)
	}
}

const (
	partitionLeader = 1
)

func testRegisterPartition(t *testing.T, s *Store, idx uint64, id int32, topic string) {
	if err := s.EnsurePartition(idx, &structs.Partition{Partition: id, Topic: topic, Leader: partitionLeader}); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	top, err := tx.First("partitions", "id", topic, id)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := top.(*structs.Partition); !ok || result.Partition != id {
		t.Fatalf("bad partition: %#v", result)
	}
}

func TestStore_RegisterGroup(t *testing.T) {
	s := testStore(t)

	testRegisterGroup(t, s, 0, "test-group")

	if _, p, err := s.GetGroup("test-group"); err != nil || p == nil {
		t.Fatalf("err: %s, group: %v", err, p)
	}

	if err := s.EnsureGroup(1, &structs.Group{Group: "test-group", Coordinator: coordinator, Members: []structs.Member{{ID: "member"}}}); err != nil {
		t.Fatalf("err: %s", err)
	}

	if _, p, err := s.GetGroup("test-group"); err != nil || p == nil || len(p.Members) != 1 || p.Members[0].ID != "member" {
		t.Fatalf("err: %s, group: %v", err, p)
	}

	if err := s.EnsureGroup(1, &structs.Group{Group: "test-group", Coordinator: coordinator, LeaderID: "leader"}); err != nil {
		t.Fatalf("err: %s", err)
	}

	if _, p, err := s.GetGroup("test-group"); err != nil || p == nil || p.LeaderID != "leader" {
		t.Fatalf("err: %s, group: %v", err, p)
	}

	// delete the group
	if err := s.DeleteGroup(2, "test-group"); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, top, err := s.GetGroup("test-group"); err != nil || top != nil || idx != 2 {
		t.Fatalf("bad: %#v %d (err: %s)", top, idx, err)
	}

	// check index is updated
	if idx := s.maxIndex("groups"); idx != 2 {
		t.Fatalf("err: %d", idx)
	}

	// deleting should be idempotent
	if err := s.DeleteGroup(2, "test-group"); err != nil {
		t.Fatalf("err: %d", err)
	}
	if idx := s.maxIndex("groups"); idx != 2 {
		t.Fatalf("err: %d", idx)
	}
}

const (
	coordinator = int32(1)
)

func testRegisterGroup(t *testing.T, s *Store, idx uint64, id string) {
	if err := s.EnsureGroup(idx, &structs.Group{Group: id, Coordinator: coordinator}); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	top, err := tx.First("groups", "id", id)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := top.(*structs.Group); !ok || result.Coordinator != coordinator {
		t.Fatalf("bad group: %#v", result)
	}
}
<commit_msg>fix test<commit_after>package fsm

import (
	"reflect"
	"testing"

	stdopentracing "github.com/opentracing/opentracing-go"
	"github.com/travisjeffery/jocko/jocko/structs"
	"github.com/travisjeffery/jocko/log"
)

func testStore(t *testing.T) *Store {
	s, err := NewStore(log.New(), stdopentracing.GlobalTracer())
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if s == nil {
		t.Fatalf("missing store")
	}
	return s
}

func testRegisterNode(t *testing.T, s *Store, idx uint64, nodeID int32) {
	testRegisterNodeWithMeta(t, s, idx, nodeID, nil)
}

func testRegisterNodeWithMeta(t *testing.T, s *Store, idx uint64, nodeID int32, meta map[string]string) {
	node := &structs.Node{Node: nodeID, Meta: meta}
	if err := s.EnsureNode(idx, node); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	n, err := tx.First("nodes", "id", nodeID)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := n.(*structs.Node); !ok || result.Node != nodeID {
		t.Fatalf("bad node: %#v", result)
	}
}

func TestStore_maxIndex(t *testing.T) {
	s := testStore(t)
	testRegisterNode(t, s, 0, 1)
	testRegisterNode(t, s, 1, 2)

	if max := s.maxIndex("nodes", "services"); max != 1 {
		t.Fatalf("bad max: %d", max)
	}
}

func TestStore_Abandon(t *testing.T) {
	s := testStore(t)
	abandonCh := s.AbandonCh()
	s.Abandon()
	select {
	case <-abandonCh:
	default:
		t.Fatalf("bad")
	}
}

func TestStore_DeleteNode(t *testing.T) {
	s := testStore(t)

	// add the node
	testRegisterNode(t, s, 0, 1)

	if idx, ns, err := s.GetNodes(); err != nil || len(ns) != 1 || idx != 0 {
		t.Fatalf("bad: %#v %d (err: %#v)", ns, idx, err)
	}

	// delete the node
	if err := s.DeleteNode(1, 1); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, n, err := s.GetNode(1); err != nil || n != nil || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %#v)", n, idx, err)
	}

	if idx, ns, err := s.GetNodes(); err != nil || len(ns) != 0 || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %#v)", ns, idx, err)
	}

	// index is updated
	if idx := s.maxIndex("nodes"); idx != 1 {
		t.Fatalf("bad index: %d", idx)
	}

	// deleting should be idempotent
	if err := s.DeleteNode(4, 1); err != nil {
		t.Fatalf("err: %s", err)
	}
	if idx := s.maxIndex("nodes"); idx != 1 {
		t.Fatalf("bad index: %d", idx)
	}
}

func TestStore_RegisterTopic(t *testing.T) {
	s := testStore(t)

	if _, topic, err := s.GetTopic("unknown-topic"); topic != nil && err != nil {
		t.Fatalf("err: %s, topic: %v", err, topic)
	}

	testRegisterTopic(t, s, 0, "topic1")

	if idx, topics, err := s.GetTopics(); err != nil || idx != 0 || !reflect.DeepEqual(topics, []*structs.Topic{{Topic: "topic1"}}) {
		t.Fatalf("err: %s", err)
	}

	// delete the topic
	if err := s.DeleteTopic(1, "topic1"); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, top, err := s.GetTopic("topic1"); err != nil || top != nil || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %s)", top, idx, err)
	}

	// check index is updated
	if idx := s.maxIndex("topics"); idx != 1 {
		t.Fatalf("err: %v", idx)
	}

	// deleting should be idempotent
	if err := s.DeleteTopic(2, "topic1"); err != nil {
		t.Fatalf("err: %s", err)
	}
	if idx := s.maxIndex("topics"); idx != 1 {
		t.Fatalf("err: %v", idx)
	}
}

func testRegisterTopic(t *testing.T, s *Store, idx uint64, id string) {
	if err := s.EnsureTopic(idx, &structs.Topic{Topic: id}); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	top, err := tx.First("topics", "id", id)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := top.(*structs.Topic); !ok || result.Topic != id {
		t.Fatalf("bad topic: %#v", result)
	}
}

func TestStore_RegisterPartition(t *testing.T) {
	s := testStore(t)

	testRegisterPartition(t, s, 0, 1, "test-topic")

	if _, p, err := s.GetPartition("test-topic", 1); err != nil || p == nil {
		t.Fatalf("err: %s, partition: %v", err, p)
	}

	if _, p, err := s.PartitionsByLeader(partitionLeader); err != nil || p == nil || len(p) != 1 {
		t.Fatalf("err: %s, partition: %v", err, p)
	}

	// delete the partition
	if err := s.DeletePartition(1, "test-topic", 1); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, top, err := s.GetPartition("test-topic", 1); err != nil || top != nil || idx != 1 {
		t.Fatalf("bad: %#v %d (err: %s)", top, idx, err)
	}

	// check index is updated
	if idx := s.maxIndex("partitions"); idx != 1 {
		t.Fatalf("err: %d", idx)
	}

	// deleting should be idempotent
	if err := s.DeletePartition(2, "test-topic", 1); err != nil {
		t.Fatalf("err: %d", err)
	}
	if idx := s.maxIndex("partitions"); idx != 1 {
		t.Fatalf("err: %d", idx)
	}
}

const (
	partitionLeader = 1
)

func testRegisterPartition(t *testing.T, s *Store, idx uint64, id int32, topic string) {
	if err := s.EnsurePartition(idx, &structs.Partition{Partition: id, Topic: topic, Leader: partitionLeader}); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	top, err := tx.First("partitions", "id", topic, id)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := top.(*structs.Partition); !ok || result.Partition != id {
		t.Fatalf("bad partition: %#v", result)
	}
}

func TestStore_RegisterGroup(t *testing.T) {
	s := testStore(t)

	testRegisterGroup(t, s, 0, "test-group")

	if _, p, err := s.GetGroup("test-group"); err != nil || p == nil {
		t.Fatalf("err: %s, group: %v", err, p)
	}

	if err := s.EnsureGroup(1, &structs.Group{Group: "test-group", Coordinator: coordinator, Members: map[string]structs.Member{"member": structs.Member{ID: "member"}}}); err != nil {
		t.Fatalf("err: %s", err)
	}

	if _, p, err := s.GetGroup("test-group"); err != nil || p == nil || len(p.Members) != 1 || p.Members["member"].ID != "member" {
		t.Fatalf("err: %s, group: %v", err, p)
	}

	if err := s.EnsureGroup(1, &structs.Group{Group: "test-group", Coordinator: coordinator, LeaderID: "leader"}); err != nil {
		t.Fatalf("err: %s", err)
	}

	if _, p, err := s.GetGroup("test-group"); err != nil || p == nil || p.LeaderID != "leader" {
		t.Fatalf("err: %s, group: %v", err, p)
	}

	// delete the group
	if err := s.DeleteGroup(2, "test-group"); err != nil {
		t.Fatalf("err: %s", err)
	}

	// check it's gone
	if idx, top, err := s.GetGroup("test-group"); err != nil || top != nil || idx != 2 {
		t.Fatalf("bad: %#v %d (err: %s)", top, idx, err)
	}

	// check index is updated
	if idx := s.maxIndex("groups"); idx != 2 {
		t.Fatalf("err: %d", idx)
	}

	// deleting should be idempotent
	if err := s.DeleteGroup(2, "test-group"); err != nil {
		t.Fatalf("err: %d", err)
	}
	if idx := s.maxIndex("groups"); idx != 2 {
		t.Fatalf("err: %d", idx)
	}
}

const (
	coordinator = int32(1)
)

func testRegisterGroup(t *testing.T, s *Store, idx uint64, id string) {
	if err := s.EnsureGroup(idx, &structs.Group{Group: id, Coordinator: coordinator}); err != nil {
		t.Fatalf("err: %s", err)
	}
	tx := s.db.Txn(false)
	defer tx.Abort()
	top, err := tx.First("groups", "id", id)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	if result, ok := top.(*structs.Group); !ok || result.Coordinator != coordinator {
		t.Fatalf("bad group: %#v", result)
	}
}
<|endoftext|>