<commit_before>package true_git

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/flant/werf/pkg/path_matcher"
)

func makeDiffParser(out io.Writer, pathMatcher path_matcher.PathMatcher) *diffParser {
	return &diffParser{
		PathMatcher: pathMatcher,
		Out:         out,
		OutLines:    0,
		Paths:       make([]string, 0),
		BinaryPaths: make([]string, 0),
		state:       unrecognized,
		lineBuf:     make([]byte, 0, 4096),
	}
}

type parserState string

const (
	unrecognized   parserState = "unrecognized"
	diffBegin      parserState = "diffBegin"
	diffBody       parserState = "diffBody"
	newFileDiff    parserState = "newFileDiff"
	deleteFileDiff parserState = "deleteFileDiff"
	modifyFileDiff parserState = "modifyFileDiff"
	ignoreDiff     parserState = "ignoreDiff"
)

type diffParser struct {
	PathMatcher path_matcher.PathMatcher

	Out                 io.Writer
	OutLines            uint
	UnrecognizedCapture bytes.Buffer

	Paths         []string
	BinaryPaths   []string
	LastSeenPaths []string

	state   parserState
	lineBuf []byte
}

func appendUnique(list []string, value string) []string {
	for _, oldValue := range list {
		if value == oldValue {
			return list
		}
	}
	return append(list, value)
}

func (p *diffParser) HandleStdout(data []byte) error {
	for _, b := range data {
		if b == '\n' {
			line := string(p.lineBuf)
			p.lineBuf = p.lineBuf[:0]

			err := p.handleDiffLine(line)
			if err != nil {
				return fmt.Errorf("error parsing diff line: %s", err)
			}

			continue
		}
		p.lineBuf = append(p.lineBuf, b)
	}

	return nil
}

func (p *diffParser) HandleStderr(data []byte) error {
	_, err := p.UnrecognizedCapture.Write(data)
	return err
}

func (p *diffParser) writeOutLine(line string) error {
	p.OutLines++

	_, err := p.Out.Write([]byte(line + "\n"))

	return err
}

func (p *diffParser) writeUnrecognizedLine(line string) error {
	_, err := p.UnrecognizedCapture.Write([]byte(line + "\n"))
	return err
}

func debugPatchParser() bool {
	return os.Getenv("WERF_TRUE_GIT_DEBUG_PATCH_PARSER") == "1"
}

func (p *diffParser) handleDiffLine(line string) error {
	if debugPatchParser() {
		oldState := p.state
		fmt.Printf("TRUE_GIT parse diff line: state=%#v line=%#v\n", oldState, line)
		defer func() {
			fmt.Printf("TRUE_GIT parse diff line: state change: %#v => %#v\n", oldState, p.state)
		}()
	}

	switch p.state {
	case unrecognized:
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeUnrecognizedLine(line)

	case ignoreDiff:
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return nil

	case diffBegin:
		if strings.HasPrefix(line, "deleted file mode ") {
			return p.handleDeleteFileDiff(line)
		}
		if strings.HasPrefix(line, "new file mode ") {
			return p.handleNewFileDiff(line)
		}
		if strings.HasPrefix(line, "old mode ") {
			return p.handleModifyFileDiff(line)
		}
		if strings.HasPrefix(line, "index ") {
			return p.handleModifyFileDiff(line)
		}
		return fmt.Errorf("unexpected diff line in state `%s`: %#v", p.state, line)

	case modifyFileDiff:
		if strings.HasPrefix(line, "new mode ") {
			return p.writeOutLine(line)
		}
		if strings.HasPrefix(line, "--- ") {
			return p.handleModifyFilePathA(line)
		}
		if strings.HasPrefix(line, "+++ ") {
			return p.handleModifyFilePathB(line)
		}
		if strings.HasPrefix(line, "GIT binary patch") {
			return p.handleBinaryBeginHeader(line)
		}
		if strings.HasPrefix(line, "Binary files") {
			return p.handleShortBinaryHeader(line)
		}
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)

	case newFileDiff:
		if strings.HasPrefix(line, "+++ ") {
			return p.handleNewFilePath(line)
		}
		if strings.HasPrefix(line, "GIT binary patch") {
			return p.handleBinaryBeginHeader(line)
		}
		if strings.HasPrefix(line, "Binary files") {
			return p.handleShortBinaryHeader(line)
		}
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)

	case deleteFileDiff:
		if strings.HasPrefix(line, "--- ") {
			return p.handleDeleteFilePath(line)
		}
		if strings.HasPrefix(line, "GIT binary patch") {
			return p.handleBinaryBeginHeader(line)
		}
		if strings.HasPrefix(line, "Binary files") {
			return p.handleShortBinaryHeader(line)
		}
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)

	case diffBody:
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)
	}

	return nil
}

func (p *diffParser) handleDiffBegin(line string) error {
	var lineParts []string
	var aAndBParts []string
	var a, b string

	lineParts = strings.SplitN(line, " \"a/", 2)
	if len(lineParts) == 2 {
		aAndBParts = strings.SplitN(lineParts[1], " \"b/", 2)
		a, b = fmt.Sprintf("\"a/%s", aAndBParts[0]), fmt.Sprintf("\"b/%s", aAndBParts[1])
	} else {
		lineParts = strings.SplitN(line, " a/", 2)
		if len(lineParts) == 2 {
			aAndBParts = strings.SplitN(lineParts[1], " b/", 2)
			a, b = fmt.Sprintf("a/%s", aAndBParts[0]), fmt.Sprintf("b/%s", aAndBParts[1])
		} else {
			return fmt.Errorf("unexpected diff begin line: %#v", line)
		}
	}

	trimmedPaths := make(map[string]string)

	p.LastSeenPaths = nil

	for _, data := range []struct{ PathWithPrefix, Prefix string }{{a, "a/"}, {b, "b/"}} {
		if strings.HasPrefix(data.PathWithPrefix, "\"") && strings.HasSuffix(data.PathWithPrefix, "\"") {
			pathWithPrefix, err := strconv.Unquote(data.PathWithPrefix)
			if err != nil {
				return fmt.Errorf("unable to unqoute diff path %#v: %s", data.PathWithPrefix, err)
			}

			path := strings.TrimPrefix(pathWithPrefix, data.Prefix)
			if !p.PathMatcher.MatchPath(path) {
				p.state = ignoreDiff
				return nil
			}

			newPath := p.PathMatcher.TrimFileBaseFilepath(path)
			p.Paths = appendUnique(p.Paths, newPath)
			p.LastSeenPaths = appendUnique(p.LastSeenPaths, newPath)

			newPathWithPrefix := data.Prefix + newPath
			trimmedPaths[data.PathWithPrefix] = strconv.Quote(newPathWithPrefix)
		} else {
			path := strings.TrimPrefix(data.PathWithPrefix, data.Prefix)
			if !p.PathMatcher.MatchPath(path) {
				p.state = ignoreDiff
				return nil
			}

			newPath := p.PathMatcher.TrimFileBaseFilepath(path)
			p.Paths = appendUnique(p.Paths, newPath)
			p.LastSeenPaths = appendUnique(p.LastSeenPaths, newPath)

			trimmedPaths[data.PathWithPrefix] = data.Prefix + newPath
		}
	}

	newLine := fmt.Sprintf("diff --git %s %s", trimmedPaths[a], trimmedPaths[b])

	p.state = diffBegin

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleDeleteFileDiff(line string) error {
	p.state = deleteFileDiff
	return p.writeOutLine(line)
}

func (p *diffParser) handleNewFileDiff(line string) error {
	p.state = newFileDiff
	return p.writeOutLine(line)
}

func (p *diffParser) handleModifyFileDiff(line string) error {
	p.state = modifyFileDiff
	return p.writeOutLine(line)
}

func (p *diffParser) handleModifyFilePathA(line string) error {
	path := strings.TrimPrefix(line, "--- a/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("--- a/%s", newPath)

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleModifyFilePathB(line string) error {
	path := strings.TrimPrefix(line, "+++ b/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("+++ b/%s", newPath)

	p.state = diffBody

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleSubmoduleLine(line string) error {
	p.state = unrecognized
	return nil
}

func (p *diffParser) handleNewFilePath(line string) error {
	path := strings.TrimPrefix(line, "+++ b/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("+++ b/%s", newPath)

	p.state = diffBody

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleDeleteFilePath(line string) error {
	path := strings.TrimPrefix(line, "--- a/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("--- a/%s", newPath)

	p.state = diffBody

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleBinaryBeginHeader(line string) error {
	for _, path := range p.LastSeenPaths {
		p.BinaryPaths = appendUnique(p.BinaryPaths, path)
	}

	p.state = diffBody

	return p.writeOutLine(line)
}

func (p *diffParser) handleShortBinaryHeader(line string) error {
	for _, path := range p.LastSeenPaths {
		p.BinaryPaths = appendUnique(p.BinaryPaths, path)
	}

	p.state = unrecognized

	return p.writeOutLine(line)
}
<commit_msg>Fix gitLatestPatch signature differs in different worktrees<commit_after>package true_git

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/flant/werf/pkg/path_matcher"
)

func makeDiffParser(out io.Writer, pathMatcher path_matcher.PathMatcher) *diffParser {
	return &diffParser{
		PathMatcher: pathMatcher,
		Out:         out,
		OutLines:    0,
		Paths:       make([]string, 0),
		BinaryPaths: make([]string, 0),
		state:       unrecognized,
		lineBuf:     make([]byte, 0, 4096),
	}
}

type parserState string

const (
	unrecognized   parserState = "unrecognized"
	diffBegin      parserState = "diffBegin"
	diffBody       parserState = "diffBody"
	newFileDiff    parserState = "newFileDiff"
	deleteFileDiff parserState = "deleteFileDiff"
	modifyFileDiff parserState = "modifyFileDiff"
	ignoreDiff     parserState = "ignoreDiff"
)

type diffParser struct {
	PathMatcher path_matcher.PathMatcher

	Out                 io.Writer
	OutLines            uint
	UnrecognizedCapture bytes.Buffer

	Paths         []string
	BinaryPaths   []string
	LastSeenPaths []string

	state   parserState
	lineBuf []byte
}

func appendUnique(list []string, value string) []string {
	for _, oldValue := range list {
		if value == oldValue {
			return list
		}
	}
	return append(list, value)
}

func (p *diffParser) HandleStdout(data []byte) error {
	for _, b := range data {
		if b == '\n' {
			line := string(p.lineBuf)
			p.lineBuf = p.lineBuf[:0]

			err := p.handleDiffLine(line)
			if err != nil {
				return fmt.Errorf("error parsing diff line: %s", err)
			}

			continue
		}
		p.lineBuf = append(p.lineBuf, b)
	}

	return nil
}

func (p *diffParser) HandleStderr(data []byte) error {
	_, err := p.UnrecognizedCapture.Write(data)
	return err
}

func (p *diffParser) writeOutLine(line string) error {
	p.OutLines++

	_, err := p.Out.Write([]byte(line + "\n"))

	return err
}

func (p *diffParser) writeUnrecognizedLine(line string) error {
	_, err := p.UnrecognizedCapture.Write([]byte(line + "\n"))
	return err
}

func debugPatchParser() bool {
	return os.Getenv("WERF_TRUE_GIT_DEBUG_PATCH_PARSER") == "1"
}

func (p *diffParser) handleDiffLine(line string) error {
	if debugPatchParser() {
		oldState := p.state
		fmt.Printf("TRUE_GIT parse diff line: state=%#v line=%#v\n", oldState, line)
		defer func() {
			fmt.Printf("TRUE_GIT parse diff line: state change: %#v => %#v\n", oldState, p.state)
		}()
	}

	switch p.state {
	case unrecognized:
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeUnrecognizedLine(line)

	case ignoreDiff:
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return nil

	case diffBegin:
		if strings.HasPrefix(line, "deleted file mode ") {
			return p.handleDeleteFileDiff(line)
		}
		if strings.HasPrefix(line, "new file mode ") {
			return p.handleNewFileDiff(line)
		}
		if strings.HasPrefix(line, "old mode ") {
			return p.handleModifyFileDiff(line)
		}
		if strings.HasPrefix(line, "index ") {
			return p.handleIndexDiffLine(line)
		}
		return fmt.Errorf("unexpected diff line in state `%s`: %#v", p.state, line)

	case modifyFileDiff:
		if strings.HasPrefix(line, "new mode ") {
			return p.writeOutLine(line)
		}
		if strings.HasPrefix(line, "--- ") {
			return p.handleModifyFilePathA(line)
		}
		if strings.HasPrefix(line, "+++ ") {
			return p.handleModifyFilePathB(line)
		}
		if strings.HasPrefix(line, "GIT binary patch") {
			return p.handleBinaryBeginHeader(line)
		}
		if strings.HasPrefix(line, "Binary files") {
			return p.handleShortBinaryHeader(line)
		}
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)

	case newFileDiff:
		if strings.HasPrefix(line, "+++ ") {
			return p.handleNewFilePath(line)
		}
		if strings.HasPrefix(line, "GIT binary patch") {
			return p.handleBinaryBeginHeader(line)
		}
		if strings.HasPrefix(line, "Binary files") {
			return p.handleShortBinaryHeader(line)
		}
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)

	case deleteFileDiff:
		if strings.HasPrefix(line, "--- ") {
			return p.handleDeleteFilePath(line)
		}
		if strings.HasPrefix(line, "GIT binary patch") {
			return p.handleBinaryBeginHeader(line)
		}
		if strings.HasPrefix(line, "Binary files") {
			return p.handleShortBinaryHeader(line)
		}
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)

	case diffBody:
		if strings.HasPrefix(line, "diff --git ") {
			return p.handleDiffBegin(line)
		}
		if strings.HasPrefix(line, "Submodule ") {
			return p.handleSubmoduleLine(line)
		}
		return p.writeOutLine(line)
	}

	return nil
}

func (p *diffParser) handleDiffBegin(line string) error {
	var lineParts []string
	var aAndBParts []string
	var a, b string

	lineParts = strings.SplitN(line, " \"a/", 2)
	if len(lineParts) == 2 {
		aAndBParts = strings.SplitN(lineParts[1], " \"b/", 2)
		a, b = fmt.Sprintf("\"a/%s", aAndBParts[0]), fmt.Sprintf("\"b/%s", aAndBParts[1])
	} else {
		lineParts = strings.SplitN(line, " a/", 2)
		if len(lineParts) == 2 {
			aAndBParts = strings.SplitN(lineParts[1], " b/", 2)
			a, b = fmt.Sprintf("a/%s", aAndBParts[0]), fmt.Sprintf("b/%s", aAndBParts[1])
		} else {
			return fmt.Errorf("unexpected diff begin line: %#v", line)
		}
	}

	trimmedPaths := make(map[string]string)

	p.LastSeenPaths = nil

	for _, data := range []struct{ PathWithPrefix, Prefix string }{{a, "a/"}, {b, "b/"}} {
		if strings.HasPrefix(data.PathWithPrefix, "\"") && strings.HasSuffix(data.PathWithPrefix, "\"") {
			pathWithPrefix, err := strconv.Unquote(data.PathWithPrefix)
			if err != nil {
				return fmt.Errorf("unable to unqoute diff path %#v: %s", data.PathWithPrefix, err)
			}

			path := strings.TrimPrefix(pathWithPrefix, data.Prefix)
			if !p.PathMatcher.MatchPath(path) {
				p.state = ignoreDiff
				return nil
			}

			newPath := p.PathMatcher.TrimFileBaseFilepath(path)
			p.Paths = appendUnique(p.Paths, newPath)
			p.LastSeenPaths = appendUnique(p.LastSeenPaths, newPath)

			newPathWithPrefix := data.Prefix + newPath
			trimmedPaths[data.PathWithPrefix] = strconv.Quote(newPathWithPrefix)
		} else {
			path := strings.TrimPrefix(data.PathWithPrefix, data.Prefix)
			if !p.PathMatcher.MatchPath(path) {
				p.state = ignoreDiff
				return nil
			}

			newPath := p.PathMatcher.TrimFileBaseFilepath(path)
			p.Paths = appendUnique(p.Paths, newPath)
			p.LastSeenPaths = appendUnique(p.LastSeenPaths, newPath)

			trimmedPaths[data.PathWithPrefix] = data.Prefix + newPath
		}
	}

	newLine := fmt.Sprintf("diff --git %s %s", trimmedPaths[a], trimmedPaths[b])

	p.state = diffBegin

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleDeleteFileDiff(line string) error {
	p.state = deleteFileDiff
	return p.writeOutLine(line)
}

func (p *diffParser) handleNewFileDiff(line string) error {
	p.state = newFileDiff
	return p.writeOutLine(line)
}

func (p *diffParser) handleModifyFileDiff(line string) error {
	p.state = modifyFileDiff
	return p.writeOutLine(line)
}

// TODO: remove index line from resulting patch completely in v1.2
func (p *diffParser) handleIndexDiffLine(line string) error {
	p.state = modifyFileDiff

	parts := strings.SplitN(line, " ", 3)
	if len(parts) != 3 {
		// unexpected format
		return p.writeOutLine(line)
	}

	prefix, hashes, suffix := parts[0], parts[1], parts[2]

	hashesParts := strings.SplitN(hashes, "..", 2)
	if len(hashesParts) != 2 {
		// unexpected format
		return p.writeOutLine(line)
	}

	stripHashFunc := func(h string) string {
		if len(h) < 8 {
			return h
		}
		return h[:8]
	}

	var leftHashes []string
	for _, h := range strings.Split(hashesParts[0], ",") {
		leftHashes = append(leftHashes, stripHashFunc(h))
	}

	var rightHashes []string
	for _, h := range strings.Split(hashesParts[1], ",") {
		rightHashes = append(rightHashes, stripHashFunc(h))
	}

	newLine := fmt.Sprintf("%s %s..%s %s", prefix, strings.Join(leftHashes, ","), strings.Join(rightHashes, ","), suffix)

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleModifyFilePathA(line string) error {
	path := strings.TrimPrefix(line, "--- a/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("--- a/%s", newPath)

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleModifyFilePathB(line string) error {
	path := strings.TrimPrefix(line, "+++ b/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("+++ b/%s", newPath)

	p.state = diffBody

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleSubmoduleLine(line string) error {
	p.state = unrecognized
	return nil
}

func (p *diffParser) handleNewFilePath(line string) error {
	path := strings.TrimPrefix(line, "+++ b/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("+++ b/%s", newPath)

	p.state = diffBody

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleDeleteFilePath(line string) error {
	path := strings.TrimPrefix(line, "--- a/")
	newPath := p.PathMatcher.TrimFileBaseFilepath(path)
	newLine := fmt.Sprintf("--- a/%s", newPath)

	p.state = diffBody

	return p.writeOutLine(newLine)
}

func (p *diffParser) handleBinaryBeginHeader(line string) error {
	for _, path := range p.LastSeenPaths {
		p.BinaryPaths = appendUnique(p.BinaryPaths, path)
	}

	p.state = diffBody

	return p.writeOutLine(line)
}

func (p *diffParser) handleShortBinaryHeader(line string) error {
	for _, path := range p.LastSeenPaths {
		p.BinaryPaths = appendUnique(p.BinaryPaths, path)
	}

	p.state = unrecognized

	return p.writeOutLine(line)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"flag"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/replaygaming/consumer"
	"github.com/replaygaming/eventsource"
)

var (
	topicName = flag.String("topic",
		fromEnvWithDefault("ES_TOPIC", "eventsource"),
		"Topic name")

	subscriptionName = flag.String("subscription",
		fromEnvWithDefault("ES_SUBSCRIPTION", "eventsource_"+generateSubId()),
		"Subscription name")

	port = flag.String("port",
		fromEnvWithDefault("ES_PORT", "80"),
		"Eventsource port")

	useMetrics = flag.Bool("metrics", os.Getenv("ES_METRICS") == "true", "Enable metrics")

	metricsPrefix = flag.String("metrics-prefix",
		fromEnvWithDefault("ES_METRICS_PREFIX", "eventsource"),
		"Metrics prefix")

	compress = flag.Bool("compression", os.Getenv("ES_COMPRESSION") == "true", "Enable zlib compression of data")

	verbose = flag.Bool("verbose", os.Getenv("ES_VERBOSE") == "true", "Enable verbose output")
)

func init() {
	flag.Parse()
}

// Create a new eventsource server, optionally with metrics
func newServerWithMetrics() *eventsource.Eventsource {
	server := &eventsource.Eventsource{
		ChannelSubscriber: eventsource.QueryStringChannels{Name: "channels"},
	}

	if *useMetrics {
		metrics, err := NewMetrics(*metricsPrefix)
		if err != nil {
			Fatal("Could not instantiate metrics", err)
		}
		server.Metrics = metrics
	}
	server.Start()
	return server
}

// Create new message consumer
func newConsumer() *consumer.Consumer {
	return consumer.NewConsumer(*topicName, *subscriptionName)
}

// Create the channel that we'll receive messages
func consume(c *consumer.Consumer) <-chan consumer.Message {
	messages, err := c.Consume()
	if err != nil {
		Fatal("Failed to consume messages", err)
	}
	return messages
}

// Pulls out messages from the channel
func messageLoop(messages <-chan consumer.Message, server *eventsource.Eventsource, c *consumer.Consumer) {
	for m := range messages {
		messageData := m.Data()
		if *verbose {
			Debug("Got message: %s", string(messageData))
		}
		data, channels, err := parseMessage(messageData)
		if err != nil {
			Warn("json conversion failed %s", err)
		} else {
			e := eventsource.DefaultEvent{
				Message:  data,
				Channels: channels,
				Compress: *compress,
			}
			server.Send(e)
		}
		m.Done(true)
	}
}

// Handle GET /
func heartbeat(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
}

// Start HTTP server
func startServing(server *eventsource.Eventsource) {
	http.HandleFunc("/", heartbeat)
	http.Handle("/subscribe", server)

	Info("EventSource server started")
	Info("Configuration: port=%s subscription=%s topic=%s"+
		" compression=%t metrics=%t", *port, *subscriptionName,
		*topicName, *compress, *useMetrics)
	if *useMetrics {
		Info("Metrics configuration: metrics-prefix=%s", *metricsPrefix)
	}
	err := http.ListenAndServe(":"+*port, nil)
	if err != nil {
		Fatal("Error starting HTTP server: %v", err)
	}
}

func main() {
	server := newServerWithMetrics()
	c := newConsumer()
	messages := consume(c)

	setupSignalHandlers(c)

	go messageLoop(messages, server, c)

	startServing(server)
}

var shuttingDown = false

// Catch signals to perform a graceful shutdown
func setupSignalHandlers(consumer *consumer.Consumer) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		if shuttingDown {
			os.Exit(1)
		}
		Info("Shutting down gracefully. Repeat signal to force shutdown")
		shuttingDown = true
		consumer.Remove()
		os.Exit(0)
	}()
}

// Generates a random hexadecimal string
func generateSubId() string {
	id := make([]byte, 4)
	todo := len(id)
	offset := 0
	source := rand.NewSource(time.Now().UnixNano())
	for {
		val := int64(source.Int63())
		for i := 0; i < 8; i++ {
			id[offset] = byte(val & 0xff)
			todo--
			if todo == 0 {
				return hex.EncodeToString(id)
			}
			offset++
			val >>= 8
		}
	}
}

// Attempts to get a value from the environment with a default
func fromEnvWithDefault(varName string, defaultValue string) string {
	value := os.Getenv(varName)
	if value != "" {
		return value
	} else {
		return defaultValue
	}
}
<commit_msg>Fixing consumer interface usage<commit_after>package main

import (
	"encoding/hex"
	"flag"
	"math/rand"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/replaygaming/consumer"
	"github.com/replaygaming/eventsource"
)

var (
	topicName = flag.String("topic",
		fromEnvWithDefault("ES_TOPIC", "eventsource"),
		"Topic name")

	subscriptionName = flag.String("subscription",
		fromEnvWithDefault("ES_SUBSCRIPTION", "eventsource_"+generateSubId()),
		"Subscription name")

	port = flag.String("port",
		fromEnvWithDefault("ES_PORT", "80"),
		"Eventsource port")

	useMetrics = flag.Bool("metrics", os.Getenv("ES_METRICS") == "true", "Enable metrics")

	metricsPrefix = flag.String("metrics-prefix",
		fromEnvWithDefault("ES_METRICS_PREFIX", "eventsource"),
		"Metrics prefix")

	compress = flag.Bool("compression", os.Getenv("ES_COMPRESSION") == "true", "Enable zlib compression of data")

	verbose = flag.Bool("verbose", os.Getenv("ES_VERBOSE") == "true", "Enable verbose output")
)

func init() {
	flag.Parse()
}

// Create a new eventsource server, optionally with metrics
func newServerWithMetrics() *eventsource.Eventsource {
	server := &eventsource.Eventsource{
		ChannelSubscriber: eventsource.QueryStringChannels{Name: "channels"},
	}

	if *useMetrics {
		metrics, err := NewMetrics(*metricsPrefix)
		if err != nil {
			Fatal("Could not instantiate metrics", err)
		}
		server.Metrics = metrics
	}
	server.Start()
	return server
}

// Create new message consumer
func newConsumer() consumer.Consumer {
	return consumer.NewConsumer(*topicName, *subscriptionName)
}

// Create the channel that we'll receive messages
func consume(c consumer.Consumer) <-chan consumer.Message {
	messages, err := c.Consume()
	if err != nil {
		Fatal("Failed to consume messages", err)
	}
	return messages
}

// Pulls out messages from the channel
func messageLoop(messages <-chan consumer.Message, server *eventsource.Eventsource, c consumer.Consumer) {
	for m := range messages {
		messageData := m.Data()
		if *verbose {
			Debug("Got message: %s", string(messageData))
		}
		data, channels, err := parseMessage(messageData)
		if err != nil {
			Warn("json conversion failed %s", err)
		} else {
			e := eventsource.DefaultEvent{
				Message:  data,
				Channels: channels,
				Compress: *compress,
			}
			server.Send(e)
		}
		m.Done(true)
	}
}

// Handle GET /
func heartbeat(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
}

// Start HTTP server
func startServing(server *eventsource.Eventsource) {
	http.HandleFunc("/", heartbeat)
	http.Handle("/subscribe", server)

	Info("EventSource server started")
	Info("Configuration: port=%s subscription=%s topic=%s"+
		" compression=%t metrics=%t", *port, *subscriptionName,
		*topicName, *compress, *useMetrics)
	if *useMetrics {
		Info("Metrics configuration: metrics-prefix=%s", *metricsPrefix)
	}
	err := http.ListenAndServe(":"+*port, nil)
	if err != nil {
		Fatal("Error starting HTTP server: %v", err)
	}
}

func main() {
	server := newServerWithMetrics()
	c := newConsumer()
	messages := consume(c)

	setupSignalHandlers(c)

	go messageLoop(messages, server, c)

	startServing(server)
}

var shuttingDown = false

// Catch signals to perform a graceful shutdown
func setupSignalHandlers(consumer consumer.Consumer) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		if shuttingDown {
			os.Exit(1)
		}
		Info("Shutting down gracefully. Repeat signal to force shutdown")
		shuttingDown = true
		consumer.Remove()
		os.Exit(0)
	}()
}

// Generates a random hexadecimal string
func generateSubId() string {
	id := make([]byte, 4)
	todo := len(id)
	offset := 0
	source := rand.NewSource(time.Now().UnixNano())
	for {
		val := int64(source.Int63())
		for i := 0; i < 8; i++ {
			id[offset] = byte(val & 0xff)
			todo--
			if todo == 0 {
				return hex.EncodeToString(id)
			}
			offset++
			val >>= 8
		}
	}
}

// Attempts to get a value from the environment with a default
func fromEnvWithDefault(varName string, defaultValue string) string {
	value := os.Getenv(varName)
	if value != "" {
		return value
	} else {
		return defaultValue
	}
}
<|endoftext|>


<commit_before>package reference

import (
	"regexp"

	// "opencontainers/go-digest" requires us to load the algorithms that we
	// want to use into the binary (it calls .Available).
	_ "crypto/sha256"

	distreference "github.com/docker/distribution/reference"
	"github.com/opencontainers/go-digest"
	"github.com/pkg/errors"
)

const (
	// XDefaultTag defines the default tag used when performing images related actions and no tag or digest is specified
	XDefaultTag = "latest"
	// XDefaultHostname is the default built-in hostname
	XDefaultHostname = "docker.io"
	// XLegacyDefaultHostname is automatically converted to DefaultHostname
	XLegacyDefaultHostname = "index.docker.io"
	// XDefaultRepoPrefix is the prefix used for default repositories in default host
	XDefaultRepoPrefix = "library/"
)

// XCanonical reference is an object with a fully unique
// name including a name with hostname and digest
type XCanonical interface {
	distreference.Canonical
	XDigest() digest.Digest
}

// XParseNamed parses s and returns a syntactically valid reference implementing
// the Named interface. The reference must have a name, otherwise an error is
// returned.
// If an error was encountered it is returned, along with a nil Reference.
func XParseNamed(s string) (distreference.Named, error) {
	named, err := distreference.ParseNormalizedNamed(s)
	if err != nil {
		return nil, errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", s)
	}
	r, err := XWithName(named.Name())
	if err != nil {
		return nil, err
	}
	if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
		r, err := distreference.WithDigest(r, canonical.Digest())
		if err != nil {
			return nil, err
		}
		return &canonicalRef{Canonical: r, namedRef: namedRef{r}}, nil
	}
	if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
		return distreference.WithTag(r, tagged.Tag())
	}
	return r, nil
}

// XWithName returns a named object representing the given string. If the input
// is invalid ErrReferenceInvalidFormat will be returned.
// FIXME: returns *namedRef to expose the distreference.Named implementation. Should revert to distreference.Named.
func XWithName(name string) (*namedRef, error) {
	r, err := distreference.ParseNormalizedNamed(name)
	if err != nil {
		return nil, err
	}
	return &namedRef{r}, nil
}

type namedRef struct {
	distreference.Named // FIXME: must implement private distreference.NamedRepository
}
type canonicalRef struct {
	distreference.Canonical
	namedRef
}

// TEMPORARY: distreference.WithDigest and distreference.WithTag can work with any distreference.Named,
// but if so, they break the values of distreference.Domain() and distreference.Path(),
// and hence also distreference.FamiliarName()/distreference.FamiliarString().  To preserve this,
// we need to implement a PRIVATE distreference.namedRepository.
// Similarly, we need to implement a PRIVATE distreference.normalizedNamed so that distreference.Familiar*()
// knows how to compute the minimal form.
// Right now that happens by these REALLY UGLY methods; eventually we will eliminate namedRef entirely in favor of
// distreference.Named, and distreference can keep its implementation games to itself.
type drPRIVATEInterfaces interface {
	distreference.Named
	Domain() string
	Path() string
	Familiar() distreference.Named
}

func (r *namedRef) Domain() string {
	return r.Named.(drPRIVATEInterfaces).Domain()
}
func (r *namedRef) Path() string {
	return r.Named.(drPRIVATEInterfaces).Path()
}
func (r *namedRef) Familiar() distreference.Named {
	return r.Named.(drPRIVATEInterfaces).Familiar()
}

func (r *canonicalRef) XDigest() digest.Digest {
	return digest.Digest(r.namedRef.Named.(distreference.Canonical).Digest())
}

// XWithDefaultTag adds a default tag to a reference if it only has a repo name.
func XWithDefaultTag(ref distreference.Named) distreference.Named {
	if XIsNameOnly(ref) {
		ref, _ = distreference.WithTag(ref, XDefaultTag)
	}
	return ref
}

// XIsNameOnly returns true if reference only contains a repo name.
func XIsNameOnly(ref distreference.Named) bool {
	if _, ok := ref.(distreference.NamedTagged); ok {
		return false
	}
	if _, ok := ref.(XCanonical); ok {
		return false
	}
	return true
}

// XParseIDOrReference parses string for an image ID or a reference. ID can be
// without a default prefix.
func XParseIDOrReference(idOrRef string) (digest.Digest, distreference.Named, error) {
	if err := validateID(idOrRef); err == nil {
		idOrRef = "sha256:" + idOrRef
	}
	if dgst, err := digest.Parse(idOrRef); err == nil {
		return dgst, nil, nil
	}
	ref, err := XParseNamed(idOrRef)
	return "", ref, err
}

var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)

func validateID(id string) error {
	if ok := validHex.MatchString(id); !ok {
		return errors.Errorf("image ID %q is invalid", id)
	}
	return nil
}
<commit_msg>Implementation transition: Use the Canonical in XDigest instead of namedRef<commit_after>package reference

import (
	"regexp"

	// "opencontainers/go-digest" requires us to load the algorithms that we
	// want to use into the binary (it calls .Available).
	_ "crypto/sha256"

	distreference "github.com/docker/distribution/reference"
	"github.com/opencontainers/go-digest"
	"github.com/pkg/errors"
)

const (
	// XDefaultTag defines the default tag used when performing images related actions and no tag or digest is specified
	XDefaultTag = "latest"
	// XDefaultHostname is the default built-in hostname
	XDefaultHostname = "docker.io"
	// XLegacyDefaultHostname is automatically converted to DefaultHostname
	XLegacyDefaultHostname = "index.docker.io"
	// XDefaultRepoPrefix is the prefix used for default repositories in default host
	XDefaultRepoPrefix = "library/"
)

// XCanonical reference is an object with a fully unique
// name including a name with hostname and digest
type XCanonical interface {
	distreference.Canonical
	XDigest() digest.Digest
}

// XParseNamed parses s and returns a syntactically valid reference implementing
// the Named interface. The reference must have a name, otherwise an error is
// returned.
// If an error was encountered it is returned, along with a nil Reference.
func XParseNamed(s string) (distreference.Named, error) {
	named, err := distreference.ParseNormalizedNamed(s)
	if err != nil {
		return nil, errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", s)
	}
	r, err := XWithName(named.Name())
	if err != nil {
		return nil, err
	}
	if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
		r, err := distreference.WithDigest(r, canonical.Digest())
		if err != nil {
			return nil, err
		}
		return &canonicalRef{Canonical: r, namedRef: namedRef{r}}, nil
	}
	if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
		return distreference.WithTag(r, tagged.Tag())
	}
	return r, nil
}

// XWithName returns a named object representing the given string. If the input
// is invalid ErrReferenceInvalidFormat will be returned.
// FIXME: returns *namedRef to expose the distreference.Named implementation. Should revert to distreference.Named.
func XWithName(name string) (*namedRef, error) {
	r, err := distreference.ParseNormalizedNamed(name)
	if err != nil {
		return nil, err
	}
	return &namedRef{r}, nil
}

type namedRef struct {
	distreference.Named // FIXME: must implement private distreference.NamedRepository
}
type canonicalRef struct {
	distreference.Canonical
	namedRef
}

// TEMPORARY: distreference.WithDigest and distreference.WithTag can work with any distreference.Named,
// but if so, they break the values of distreference.Domain() and distreference.Path(),
// and hence also distreference.FamiliarName()/distreference.FamiliarString().  To preserve this,
// we need to implement a PRIVATE distreference.namedRepository.
// Similarly, we need to implement a PRIVATE distreference.normalizedNamed so that distreference.Familiar*()
// knows how to compute the minimal form.
// Right now that happens by these REALLY UGLY methods; eventually we will eliminate namedRef entirely in favor of
// distreference.Named, and distreference can keep its implementation games to itself.
type drPRIVATEInterfaces interface {
	distreference.Named
	Domain() string
	Path() string
	Familiar() distreference.Named
}

func (r *namedRef) Domain() string {
	return r.Named.(drPRIVATEInterfaces).Domain()
}
func (r *namedRef) Path() string {
	return r.Named.(drPRIVATEInterfaces).Path()
}
func (r *namedRef) Familiar() distreference.Named {
	return r.Named.(drPRIVATEInterfaces).Familiar()
}

func (r *canonicalRef) XDigest() digest.Digest {
	return digest.Digest(r.Canonical.Digest())
}

// XWithDefaultTag adds a default tag to a reference if it only has a repo name.
func XWithDefaultTag(ref distreference.Named) distreference.Named {
	if XIsNameOnly(ref) {
		ref, _ = distreference.WithTag(ref, XDefaultTag)
	}
	return ref
}

// XIsNameOnly returns true if reference only contains a repo name.
func XIsNameOnly(ref distreference.Named) bool {
	if _, ok := ref.(distreference.NamedTagged); ok {
		return false
	}
	if _, ok := ref.(XCanonical); ok {
		return false
	}
	return true
}

// XParseIDOrReference parses string for an image ID or a reference. ID can be
// without a default prefix.
func XParseIDOrReference(idOrRef string) (digest.Digest, distreference.Named, error) {
	if err := validateID(idOrRef); err == nil {
		idOrRef = "sha256:" + idOrRef
	}
	if dgst, err := digest.Parse(idOrRef); err == nil {
		return dgst, nil, nil
	}
	ref, err := XParseNamed(idOrRef)
	return "", ref, err
}

var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)

func validateID(id string) error {
	if ok := validHex.MatchString(id); !ok {
		return errors.Errorf("image ID %q is invalid", id)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"github.com/jacobsa/oglematchers"
	"path"
	"reflect"
	"runtime"
)

// ExpectationResult is an interface returned by ExpectThat that allows callers
// to get information about the result of the expectation and set their own
// custom information. This is not useful to the average consumer, but may be
// helpful if you're writing widely used test utility functions.
type ExpectationResult interface {
	// SetCaller updates the file name and line number associated with the
	// expectation. This allows, for example, a utility function to express that
	// *its* caller should have its line number printed if the expectation fails,
	// instead of the line number of the ExpectThat call within the utility
	// function.
	SetCaller(fileName string, lineNumber int)

	// MatchResult returns the result returned by the expectation's matcher for
	// the supplied candidate.
	MatchResult() (bool, error)
}

// ExpectThat confirms that the supplied matcher matches the value x, adding a
// failure record to the currently running test if it does not. If additional
// parameters are supplied, the first will be used as a format string for the
// later ones, and the user-supplied error message will be added to the test
// output in the event of a failure.
//
// For example:
//
//     ExpectThat(userName, Equals("jacobsa"))
//     ExpectThat(users[i], Equals("jacobsa"), "while processing user %d", i)
//
func ExpectThat(
	x interface{},
	m oglematchers.Matcher,
	errorParts ...interface{}) ExpectationResult {
  res := &expectationResultImpl{}

	// Get information about the call site.
	_, file, lineNumber, ok := runtime.Caller(1)
	if !ok {
		panic("ExpectThat: runtime.Caller")
	}

	// Assemble the user error, if any.
	userError := ""
	if len(errorParts) != 0 {
		v := reflect.ValueOf(errorParts[0])
		if v.Kind() != reflect.String {
			panic(fmt.Sprintf("ExpectThat: invalid format string type %v", v.Kind()))
		}

		userError = fmt.Sprintf(v.String(), errorParts[1:]...)
	}

	// Grab the current test info.
	info := currentlyRunningTest
	if info == nil {
		panic("ExpectThat: no test info.")
	}

	// Check whether the value matches.
	matcherRes, matcherErr := m.Matches(x)
	res.matchResult = matcherRes
	res.matchError = matcherErr

	// Return immediately on success.
	if matcherRes {
		return res
	}

	// Form an appropriate failure message. Make sure that the expected and
	// actual values align properly.
	var record failureRecord
	relativeClause := ""
	if matcherErr != nil {
		relativeClause = fmt.Sprintf(", %s", matcherErr.Error())
	}

	record.GeneratedError = fmt.Sprintf(
		"Expected: %s\nActual:   %v%s",
		m.Description(),
		x,
		relativeClause)

	// Record additional failure info.
	record.FileName = path.Base(file)
	record.LineNumber = lineNumber
	record.UserError = userError

	// Store the failure.
	info.failureRecords = append(info.failureRecords, &record)
	res.failureRecord = &record

	return res
}

type expectationResultImpl struct {
	// The failure record created by the expectation, or nil if none.
	failureRecord *failureRecord

	// The result of the matcher.
	matchResult bool
	matchError error
}

func (r *expectationResultImpl) SetCaller(fileName string, lineNumber int) {
	if r.failureRecord == nil {
		return
	}

	r.failureRecord.FileName = fileName
	r.failureRecord.LineNumber = lineNumber
}

func (r *expectationResultImpl) MatchResult() (bool, error) {
	return r.matchResult, r.matchError
}
<commit_msg>Fixed a bug in ExpectThat.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"github.com/jacobsa/oglematchers"
	"path"
	"reflect"
	"runtime"
)

// ExpectationResult is an interface returned by ExpectThat that allows callers
// to get information about the result of the expectation and set their own
// custom information. This is not useful to the average consumer, but may be
// helpful if you're writing widely used test utility functions.
type ExpectationResult interface {
	// SetCaller updates the file name and line number associated with the
	// expectation. This allows, for example, a utility function to express that
	// *its* caller should have its line number printed if the expectation fails,
	// instead of the line number of the ExpectThat call within the utility
	// function.
	SetCaller(fileName string, lineNumber int)

	// MatchResult returns the result returned by the expectation's matcher for
	// the supplied candidate.
	MatchResult() (bool, error)
}

// ExpectThat confirms that the supplied matcher matches the value x, adding a
// failure record to the currently running test if it does not. If additional
// parameters are supplied, the first will be used as a format string for the
// later ones, and the user-supplied error message will be added to the test
// output in the event of a failure.
//
// For example:
//
//     ExpectThat(userName, Equals("jacobsa"))
//     ExpectThat(users[i], Equals("jacobsa"), "while processing user %d", i)
//
func ExpectThat(
	x interface{},
	m oglematchers.Matcher,
	errorParts ...interface{}) ExpectationResult {
  res := &expectationResultImpl{}

	// Get information about the call site.
	_, file, lineNumber, ok := runtime.Caller(1)
	if !ok {
		panic("ExpectThat: runtime.Caller")
	}

	// Assemble the user error, if any.
	userError := ""
	if len(errorParts) != 0 {
		v := reflect.ValueOf(errorParts[0])
		if v.Kind() != reflect.String {
			panic(fmt.Sprintf("ExpectThat: invalid format string type %v", v.Kind()))
		}

		userError = fmt.Sprintf(v.String(), errorParts[1:]...)
	}

	// Grab the current test info.
	info := currentlyRunningTest
	if info == nil {
		panic("ExpectThat: no test info.")
	}

	// Check whether the value matches.
	matcherRes, matcherErr := m.Matches(x)
	res.matchResult = matcherRes
	res.matchError = matcherErr

	// Return immediately on success.
	if matcherRes {
		return res
	}

	// Form an appropriate failure message. Make sure that the expected and
	// actual values align properly.
	var record failureRecord
	relativeClause := ""
	if matcherErr.Error() != "" {
		relativeClause = fmt.Sprintf(", %s", matcherErr.Error())
	}

	record.GeneratedError = fmt.Sprintf(
		"Expected: %s\nActual:   %v%s",
		m.Description(),
		x,
		relativeClause)

	// Record additional failure info.
	record.FileName = path.Base(file)
	record.LineNumber = lineNumber
	record.UserError = userError

	// Store the failure.
	info.failureRecords = append(info.failureRecords, &record)
	res.failureRecord = &record

	return res
}

type expectationResultImpl struct {
	// The failure record created by the expectation, or nil if none.
	failureRecord *failureRecord

	// The result of the matcher.
	matchResult bool
	matchError error
}

func (r *expectationResultImpl) SetCaller(fileName string, lineNumber int) {
	if r.failureRecord == nil {
		return
	}

	r.failureRecord.FileName = fileName
	r.failureRecord.LineNumber = lineNumber
}

func (r *expectationResultImpl) MatchResult() (bool, error) {
	return r.matchResult, r.matchError
}
<|endoftext|>


<commit_before>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"fmt"
	"io"
)

const (
	HeaderSize = 10
)

type Tag struct {
	Header
	Frames map[string][]Framer
}

func NewTag(reader io.Reader) *Tag {
	t := &Tag{NewHeader(reader), make(map[string][]Framer)}
	if t.Header == nil {
		return nil
	}

	var frame Framer
	for size := t.Header.Size(); size > 0; {
		switch t.Header.Version() {
		case "2.3.0":
			frame = NewV3Frame(reader)
		default:
			frame = NewV3Frame(reader)
		}

		if frame == nil {
			break
		}

		id := frame.Id()
		t.Frames[id] = append(t.Frames[id], frame)

		size -= FrameHeaderSize + frame.Size()
	}

	return t
}

func (t Tag) Bytes() []byte {
	data := make([]byte, t.Size())

	index := 0
	for _, v := range t.Frames {
		for _, f := range v {
			size := FrameHeaderSize + f.Size()

			switch t.Header.Version() {
			case "2.3":
				copy(data[index:index+size], V3Bytes(f))
			default:
				copy(data[index:index+size], V3Bytes(f))
			}

			index += size
		}
	}

	return append(t.Header.Bytes(), data...)
}

type Header interface {
	Version() string
	Size() int
	Bytes() []byte
}

func NewHeader(reader io.Reader) Header {
	data := make([]byte, HeaderSize)
	n, err := io.ReadFull(reader, data)
	if n < HeaderSize || err != nil || string(data[:3]) != "ID3" {
		return nil
	}

	size, err := synchint(data[6:])
	if err != nil {
		return nil
	}

	return Head{
		version:  data[3],
		revision: data[4],
		flags:    data[5],
		size:     size,
	}
}

type Head struct {
	version, revision byte
	flags             byte
	size              int32
}

func (h Head) Version() string {
	return fmt.Sprintf("2.%d.%d", h.version, h.revision)
}

func (h Head) Size() int {
	return int(h.size)
}

func (h Head) Bytes() []byte {
	data := make([]byte, HeaderSize)

	copy(data[:3], []byte("ID3"))
	copy(data[6:], synchbytes(h.size))
	data[3] = h.version
	data[4] = h.revision
	data[5] = h.flags

	return data
}
<commit_msg>Add padding field to tag<commit_after>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"fmt"
	"io"
)

const (
	HeaderSize = 10
)

type Tag struct {
	Header
	Frames  map[string][]Framer
	padding uint
}

func NewTag(reader io.Reader) *Tag {
	t := &Tag{NewHeader(reader), make(map[string][]Framer), 0}
	if t.Header == nil {
		return nil
	}

	var frame Framer
	size := t.Header.Size()
	for size > 0 {
		switch t.Header.Version() {
		case "2.3.0":
			frame = NewV3Frame(reader)
		default:
			frame = NewV3Frame(reader)
		}

		if frame == nil {
			break
		}

		id := frame.Id()
		t.Frames[id] = append(t.Frames[id], frame)

		size -= FrameHeaderSize + frame.Size()
	}

	t.padding = uint(size)
	nAdvance := int(t.padding - FrameHeaderSize)
	if n, err := io.ReadFull(reader, make([]byte, nAdvance)); n != nAdvance || err != nil {
		return nil
	}

	return t
}

func (t Tag) Bytes() []byte {
	data := make([]byte, t.Size())

	index := 0
	for _, v := range t.Frames {
		for _, f := range v {
			size := FrameHeaderSize + f.Size()

			switch t.Header.Version() {
			case "2.3":
				copy(data[index:index+size], V3Bytes(f))
			default:
				copy(data[index:index+size], V3Bytes(f))
			}

			index += size
		}
	}

	return append(t.Header.Bytes(), data...)
}

type Header interface {
	Version() string
	Size() int
	Bytes() []byte
}

func NewHeader(reader io.Reader) Header {
	data := make([]byte, HeaderSize)
	n, err := io.ReadFull(reader, data)
	if n < HeaderSize || err != nil || string(data[:3]) != "ID3" {
		return nil
	}

	size, err := synchint(data[6:])
	if err != nil {
		return nil
	}

	return Head{
		version:  data[3],
		revision: data[4],
		flags:    data[5],
		size:     size,
	}
}

type Head struct {
	version, revision byte
	flags             byte
	size              int32
}

func (h Head) Version() string {
	return fmt.Sprintf("2.%d.%d", h.version, h.revision)
}

func (h Head) Size() int {
	return int(h.size)
}

func (h Head) Bytes() []byte {
	data := make([]byte, HeaderSize)

	copy(data[:3], []byte("ID3"))
	copy(data[6:], synchbytes(h.size))
	data[3] = h.version
	data[4] = h.revision
	data[5] = h.flags

	return data
}
<|endoftext|>


<commit_before>package docker

import (
	"bytes"
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"time"
)

type Image struct {
	Id              string    `json:"id"`
	Parent          string    `json:"parent,omitempty"`
	Comment         string    `json:"comment,omitempty"`
	Created         time.Time `json:"created"`
	Container       string    `json:"container,omitempty"`
	ContainerConfig Config    `json:"container_config,omitempty"`
	DockerVersion   string    `json:"docker_version,omitempty"`
	Author          string    `json:"author,omitempty"`
	Config          *Config   `json:"config,omitempty"`
	graph           *Graph
}

func LoadImage(root string) (*Image, error) {
	// Load the json data
	jsonData, err := ioutil.ReadFile(jsonPath(root))
	if err != nil {
		return nil, err
	}
	var img Image
	if err := json.Unmarshal(jsonData, &img); err != nil {
		return nil, err
	}
	if err := ValidateId(img.Id); err != nil {
		return nil, err
	}
	// Check that the filesystem layer exists
	if stat, err := os.Stat(layerPath(root)); err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("Couldn't load image %s: no filesystem layer", img.Id)
		} else {
			return nil, err
		}
	} else if !stat.IsDir() {
		return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.Id, layerPath(root))
	}

	return &img, nil
}

func StoreImage(img *Image, layerData Archive, root string) error {
	// Check that root doesn't already exist
	if _, err := os.Stat(root); err == nil {
		return fmt.Errorf("Image %s already exists", img.Id)
	} else if !os.IsNotExist(err) {
		return err
	}
	// Store the layer
	layer := layerPath(root)
	if err := os.MkdirAll(layer, 0700); err != nil {
		return err
	}
	if err := Untar(layerData, layer); err != nil {
		return err
	}
	// Store the json ball
	jsonData, err := json.Marshal(img)
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil {
		return err
	}
	return nil
}

func layerPath(root string) string {
	return path.Join(root, "layer")
}

func jsonPath(root string) string {
	return path.Join(root, "json")
}

func MountAUFS(ro []string, rw string, target string) error {
	// FIXME: Now mount the layers
	rwBranch := fmt.Sprintf("%v=rw", rw)
	roBranches := ""
	for _, layer := range ro {
		roBranches += fmt.Sprintf("%v=ro+wh:", layer)
	}
	branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)

	//if error, try to load aufs kernel module
	if err := mount("none", target, "aufs", 0, branches); err != nil {
		log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
		if err := exec.Command("modprobe", "aufs").Run(); err != nil {
			return fmt.Errorf("Unable to load the AUFS module")
		}
		log.Printf("...module loaded.")
		if err := mount("none", target, "aufs", 0, branches); err != nil {
			return fmt.Errorf("Unable to mount using aufs")
		}
	}
	return nil
}

// TarLayer returns a tar archive of the image's filesystem layer.
func (image *Image) TarLayer(compression Compression) (Archive, error) {
	layerPath, err := image.layer()
	if err != nil {
		return nil, err
	}
	return Tar(layerPath, compression)
}

func (image *Image) Mount(root, rw string) error {
	if mounted, err := Mounted(root); err != nil {
		return err
	} else if mounted {
		return fmt.Errorf("%s is already mounted", root)
	}
	layers, err := image.layers()
	if err != nil {
		return err
	}
	// Create the target directories if they don't exist
	if err := os.Mkdir(root, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	if err := os.Mkdir(rw, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	if err := MountAUFS(layers, rw, root); err != nil {
		return err
	}
	return nil
}

func (image *Image) Changes(rw string) ([]Change, error) {
	layers, err := image.layers()
	if err != nil {
		return nil, err
	}
	return Changes(layers, rw)
}

func (image *Image) ShortId() string {
	return TruncateId(image.Id)
}

func ValidateId(id string) error {
	if id == "" {
		return fmt.Errorf("Image id can't be empty")
	}
	if strings.Contains(id, ":") {
		return fmt.Errorf("Invalid character in image id: ':'")
	}
	return nil
}

func GenerateId() string {
	id := make([]byte, 32)
	_, err := io.ReadFull(rand.Reader, id)
	if err != nil {
		panic(err) // This shouldn't happen
	}
	return hex.EncodeToString(id)
}

// Image includes convenience proxy functions to its graph
// These functions will return an error if the image is not registered
// (ie. if image.graph == nil)
func (img *Image) History() ([]*Image, error) {
	var parents []*Image
	if err := img.WalkHistory(
		func(img *Image) error {
			parents = append(parents, img)
			return nil
		},
	); err != nil {
		return nil, err
	}
	return parents, nil
}

// layers returns all the filesystem layers needed to mount an image
// FIXME: @shykes refactor this function with the new error handling
//        (I'll do it if I have time tonight, I focus on the rest)
func (img *Image) layers() ([]string, error) {
	var list []string
	var e error
	if err := img.WalkHistory(
		func(img *Image) (err error) {
			if layer, err := img.layer(); err != nil {
				e = err
			} else if layer != "" {
				list = append(list, layer)
			}
			return err
		},
	); err != nil {
		return nil, err
	} else if e != nil { // Did an error occur inside the handler?
		return nil, e
	}
	if len(list) == 0 {
		return nil, fmt.Errorf("No layer found for image %s\n", img.Id)
	}
	return list, nil
}

func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
	currentImg := img
	for currentImg != nil {
		if handler != nil {
			if err := handler(currentImg); err != nil {
				return err
			}
		}
		currentImg, err = currentImg.GetParent()
		if err != nil {
			return fmt.Errorf("Error while getting parent image: %v", err)
		}
	}
	return nil
}

func (img *Image) GetParent() (*Image, error) {
	if img.Parent == "" {
		return nil, nil
	}
	if img.graph == nil {
		return nil, fmt.Errorf("Can't lookup parent of unregistered image")
	}
	return img.graph.Get(img.Parent)
}

func (img *Image) root() (string, error) {
	if img.graph == nil {
		return "", fmt.Errorf("Can't lookup root of unregistered image")
	}
	return img.graph.imageRoot(img.Id), nil
}

// Return the path of an image's layer
func (img *Image) layer() (string, error) {
	root, err := img.root()
	if err != nil {
		return "", err
	}
	return layerPath(root), nil
}

func (img *Image) Checksum() (string, error) {
	root, err := img.root()
	if err != nil {
		return "", err
	}

	checksumDictPth := path.Join(root, "..", "..", "checksums")
	checksums := new(map[string]string)

	if checksumDict, err := ioutil.ReadFile(checksumDictPth); err == nil {
		if err := json.Unmarshal(checksumDict, checksums); err != nil {
			return "", err
		}
		if checksum, ok := (*checksums)[img.Id]; ok {
			return checksum, nil
		}
	}

	layer, err := img.layer()
	if err != nil {
		return "", err
	}
	jsonData, err := ioutil.ReadFile(jsonPath(root))
	if err != nil {
		return "", err
	}

	layerData, err := Tar(layer, Xz)
	if err != nil {
		return "", err
	}

	h := sha256.New()
	if _, err := io.Copy(h, bytes.NewBuffer(jsonData)); err != nil {
		return "", err
	}
	if _, err := io.Copy(h, strings.NewReader("\n")); err != nil {
		return "", err
	}
	if _, err := io.Copy(h, layerData); err != nil {
		return "", err
	}

	hash := "sha256:"+hex.EncodeToString(h.Sum(nil))
	if *checksums == nil {
		*checksums = map[string]string{}
	}
	(*checksums)[img.Id] = hash
	checksumJson, err := json.Marshal(checksums)
	if err != nil {
		return hash, err
	}

	if err := ioutil.WriteFile(checksumDictPth, checksumJson, 0600); err != nil {
		return hash, err
	}
	return hash, nil
}
<commit_msg>simplify image.Checksum<commit_after>package docker

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"time"
)

type Image struct {
	Id              string    `json:"id"`
	Parent          string    `json:"parent,omitempty"`
	Comment         string    `json:"comment,omitempty"`
	Created         time.Time `json:"created"`
	Container       string    `json:"container,omitempty"`
	ContainerConfig Config    `json:"container_config,omitempty"`
	DockerVersion   string    `json:"docker_version,omitempty"`
	Author          string    `json:"author,omitempty"`
	Config          *Config   `json:"config,omitempty"`
	graph           *Graph
}

func LoadImage(root string) (*Image, error) {
	// Load the json data
	jsonData, err := ioutil.ReadFile(jsonPath(root))
	if err != nil {
		return nil, err
	}
	var img Image
	if err := json.Unmarshal(jsonData, &img); err != nil {
		return nil, err
	}
	if err := ValidateId(img.Id); err != nil {
		return nil, err
	}
	// Check that the filesystem layer exists
	if stat, err := os.Stat(layerPath(root)); err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("Couldn't load image %s: no filesystem layer", img.Id)
		} else {
			return nil, err
		}
	} else if !stat.IsDir() {
		return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.Id, layerPath(root))
	}

	return &img, nil
}

func StoreImage(img *Image, layerData Archive, root string) error {
	// Check that root doesn't already exist
	if _, err := os.Stat(root); err == nil {
		return fmt.Errorf("Image %s already exists", img.Id)
	} else if !os.IsNotExist(err) {
		return err
	}
	// Store the layer
	layer := layerPath(root)
	if err := os.MkdirAll(layer, 0700); err != nil {
		return err
	}
	if err := Untar(layerData, layer); err != nil {
		return err
	}
	// Store the json ball
	jsonData, err := json.Marshal(img)
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil {
		return err
	}
	return nil
}

func layerPath(root string) string {
	return path.Join(root, "layer")
}

func jsonPath(root string) string {
	return path.Join(root, "json")
}

func MountAUFS(ro []string, rw string, target string) error {
	// FIXME: Now mount the layers
	rwBranch := fmt.Sprintf("%v=rw", rw)
	roBranches := ""
	for _, layer := range ro {
		roBranches += fmt.Sprintf("%v=ro+wh:", layer)
	}
	branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)

	//if error, try to load aufs kernel module
	if err := mount("none", target, "aufs", 0, branches); err != nil {
		log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
		if err := exec.Command("modprobe", "aufs").Run(); err != nil {
			return fmt.Errorf("Unable to load the AUFS module")
		}
		log.Printf("...module loaded.")
		if err := mount("none", target, "aufs", 0, branches); err != nil {
			return fmt.Errorf("Unable to mount using aufs")
		}
	}
	return nil
}

// TarLayer returns a tar archive of the image's filesystem layer.
func (image *Image) TarLayer(compression Compression) (Archive, error) {
	layerPath, err := image.layer()
	if err != nil {
		return nil, err
	}
	return Tar(layerPath, compression)
}

func (image *Image) Mount(root, rw string) error {
	if mounted, err := Mounted(root); err != nil {
		return err
	} else if mounted {
		return fmt.Errorf("%s is already mounted", root)
	}
	layers, err := image.layers()
	if err != nil {
		return err
	}
	// Create the target directories if they don't exist
	if err := os.Mkdir(root, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	if err := os.Mkdir(rw, 0755); err != nil && !os.IsExist(err) {
		return err
	}
	if err := MountAUFS(layers, rw, root); err != nil {
		return err
	}
	return nil
}

func (image *Image) Changes(rw string) ([]Change, error) {
	layers, err := image.layers()
	if err != nil {
		return nil, err
	}
	return Changes(layers, rw)
}

func (image *Image) ShortId() string {
	return TruncateId(image.Id)
}

func ValidateId(id string) error {
	if id == "" {
		return fmt.Errorf("Image id can't be empty")
	}
	if strings.Contains(id, ":") {
		return fmt.Errorf("Invalid character in image id: ':'")
	}
	return nil
}

func GenerateId() string {
	id := make([]byte, 32)
	_, err := io.ReadFull(rand.Reader, id)
	if err != nil {
		panic(err) // This shouldn't happen
	}
	return hex.EncodeToString(id)
}

// Image includes convenience proxy functions to its graph
// These functions will return an error if the image is not registered
// (ie. if image.graph == nil)
func (img *Image) History() ([]*Image, error) {
	var parents []*Image
	if err := img.WalkHistory(
		func(img *Image) error {
			parents = append(parents, img)
			return nil
		},
	); err != nil {
		return nil, err
	}
	return parents, nil
}

// layers returns all the filesystem layers needed to mount an image
// FIXME: @shykes refactor this function with the new error handling
//        (I'll do it if I have time tonight, I focus on the rest)
func (img *Image) layers() ([]string, error) {
	var list []string
	var e error
	if err := img.WalkHistory(
		func(img *Image) (err error) {
			if layer, err := img.layer(); err != nil {
				e = err
			} else if layer != "" {
				list = append(list, layer)
			}
			return err
		},
	); err != nil {
		return nil, err
	} else if e != nil { // Did an error occur inside the handler?
		return nil, e
	}
	if len(list) == 0 {
		return nil, fmt.Errorf("No layer found for image %s\n", img.Id)
	}
	return list, nil
}

func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
	currentImg := img
	for currentImg != nil {
		if handler != nil {
			if err := handler(currentImg); err != nil {
				return err
			}
		}
		currentImg, err = currentImg.GetParent()
		if err != nil {
			return fmt.Errorf("Error while getting parent image: %v", err)
		}
	}
	return nil
}

func (img *Image) GetParent() (*Image, error) {
	if img.Parent == "" {
		return nil, nil
	}
	if img.graph == nil {
		return nil, fmt.Errorf("Can't lookup parent of unregistered image")
	}
	return img.graph.Get(img.Parent)
}

func (img *Image) root() (string, error) {
	if img.graph == nil {
		return "", fmt.Errorf("Can't lookup root of unregistered image")
	}
	return img.graph.imageRoot(img.Id), nil
}

// Return the path of an image's layer
func (img *Image) layer() (string, error) {
	root, err := img.root()
	if err != nil {
		return "", err
	}
	return layerPath(root), nil
}

func (img *Image) Checksum() (string, error) {
	root, err := img.root()
	if err != nil {
		return "", err
	}

	checksumDictPth := path.Join(root, "..", "..", "checksums")
	checksums := new(map[string]string)

	if checksumDict, err := ioutil.ReadFile(checksumDictPth); err == nil {
		if err := json.Unmarshal(checksumDict, checksums); err != nil {
			return "", err
		}
		if checksum, ok := (*checksums)[img.Id]; ok {
			return checksum, nil
		}
	}

	layer, err := img.layer()
	if err != nil {
		return "", err
	}
	jsonData, err := ioutil.ReadFile(jsonPath(root))
	if err != nil {
		return "", err
	}

	layerData, err := Tar(layer, Xz)
	if err != nil {
		return "", err
	}

	h := sha256.New()
	if _, err := h.Write(jsonData); err != nil {
		return "", err
	}
	if _, err := h.Write([]byte("\n")); err != nil {
		return "", err
	}
	if _, err := io.Copy(h, layerData); err != nil {
		return "", err
	}

	hash := "sha256:"+hex.EncodeToString(h.Sum(nil))
	if *checksums == nil {
		*checksums = map[string]string{}
	}
	(*checksums)[img.Id] = hash
	checksumJson, err := json.Marshal(checksums)
	if err != nil {
		return hash, err
	}

	if err := ioutil.WriteFile(checksumDictPth, checksumJson, 0600); err != nil {
		return hash, err
	}
	return hash, nil
}
<|endoftext|>


<commit_before>package imgio

import (
	"errors"
	"image/draw"
	"io"
	"sync"
)

type Image struct {
	img draw.Image
	gen PointsSequenceGenerator
	prw PointReadWriter
	mux sync.RWMutex

	pointCursor uint64
	byteCursor  int
}

func NewImage(img draw.Image, gen PointsSequenceGenerator, prw PointReadWriter) *Image {
	return &Image{
		img: img,
		gen: gen,
		prw: prw,
	}
}

// Read implements io.Reader interface
func (f *Image) Read(p []byte) (n int, err error) {
	f.mux.RLock()
	defer f.mux.RUnlock()

	f.gen.Seek(f.pointCursor)

	if !f.gen.Valid() {
		return 0, io.EOF
	}
	if len(p) == 0 {
		return 0, nil
	}

	for {
		if !f.gen.Valid() {
			return n, io.EOF
		}
		if n >= len(p) {
			return
		}

		point := f.gen.Current()
		color := f.img.At(point.X, point.Y)
		buff, nBytesRead := f.prw.Read(f.byteCursor, color, point)

		if len(p)-n > nBytesRead {
			copy(p[n:], buff[:nBytesRead])
			n += nBytesRead
			f.gen.Next()
			f.pointCursor++
			f.byteCursor = 0
		} else {
			end := nBytesRead - len(p) + n
			copy(p[n:], buff[:end])
			n += end
			f.byteCursor = end + 1
			return
		}
	}

	return
}

// Write implements io.Writer interface
func (f *Image) Write(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}

	f.mux.Lock()
	defer f.mux.Unlock()

	f.gen.Seek(f.pointCursor)

	for {
		if !f.gen.Valid() {
			return n, errors.New("overflow")
		}
		if len(p) == 0 {
			return n, nil
		}

		point := f.gen.Current()
		srcColor := f.img.At(point.X, point.Y)
		color, writtenBytes := f.prw.Write(p, f.byteCursor, srcColor, point)
		f.img.Set(point.X, point.Y, color)
		f.gen.Next()
		f.pointCursor++
		n += writtenBytes
		p = p[writtenBytes:]
		if f.prw.Size(point) > int64(writtenBytes) {
			f.byteCursor = writtenBytes + 1
		}
	}

	return
}

func (i *Image) Seek(offset int64, whence int) (int64, error) {
	return 0, nil
}

func (s *Image) Size() (size int64) {
	s.gen.Rewind()
	for s.gen.Valid() {
		point := s.gen.Current()
		size += s.prw.Size(point)
		s.gen.Next()
	}
	return
}
<commit_msg>Small fix image<commit_after>package imgio

import (
	"errors"
	"image/draw"
	"io"
	"sync"
)

type Image struct {
	img draw.Image
	gen PointsSequenceGenerator
	prw PointReadWriter
	mux sync.RWMutex

	pointCursor uint64
	byteCursor  int
}

func NewImage(img draw.Image, gen PointsSequenceGenerator, prw PointReadWriter) *Image {
	return &Image{
		img: img,
		gen: gen,
		prw: prw,
	}
}

// Read implements io.Reader interface
func (i *Image) Read(p []byte) (n int, err error) {
	i.mux.RLock()
	defer i.mux.RUnlock()

	i.gen.Seek(i.pointCursor)

	if !i.gen.Valid() {
		return 0, io.EOF
	}
	if len(p) == 0 {
		return 0, nil
	}

	for {
		if !i.gen.Valid() {
			return n, io.EOF
		}
		if n >= len(p) {
			return
		}

		point := i.gen.Current()
		color := i.img.At(point.X, point.Y)
		buff, nBytesRead := i.prw.Read(i.byteCursor, color, point)

		if len(p)-n > nBytesRead {
			copy(p[n:], buff[:nBytesRead])
			n += nBytesRead
			i.gen.Next()
			i.pointCursor++
			i.byteCursor = 0
		} else {
			end := nBytesRead - len(p) + n
			copy(p[n:], buff[:end])
			n += end
			i.byteCursor = end + 1
			return
		}
	}

	return
}

// Write implements io.Writer interface
func (i *Image) Write(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}

	i.mux.Lock()
	defer i.mux.Unlock()

	i.gen.Seek(i.pointCursor)

	for {
		if !i.gen.Valid() {
			return n, errors.New("overflow")
		}
		if len(p) == 0 {
			return n, nil
		}

		point := i.gen.Current()
		srcColor := i.img.At(point.X, point.Y)
		color, writtenBytes := i.prw.Write(p, i.byteCursor, srcColor, point)
		i.img.Set(point.X, point.Y, color)
		i.gen.Next()
		i.pointCursor++
		n += writtenBytes
		p = p[writtenBytes:]
		if i.prw.Size(point) > int64(writtenBytes) {
			i.byteCursor = writtenBytes + 1
		}
	}

	return
}

func (i *Image) Seek(offset int64, whence int) (int64, error) {
	return 0, nil
}

func (i *Image) Size() (size int64) {
	i.gen.Rewind()
	for i.gen.Valid() {
		point := i.gen.Current()
		size += i.prw.Size(point)
		i.gen.Next()
	}
	return
}
<|endoftext|>


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

package main

import (
	"code.google.com/p/gordon-go/go/types"
	. "code.google.com/p/gordon-go/gui"
)

type indexNode struct {
	*nodeBase
	set, addressable bool
	x, key, elem, ok *port
}

func newIndexNode(set bool) *indexNode {
	n := &indexNode{set: set}
	n.nodeBase = newNodeBase(n)
	n.x = n.newInput(nil)
	n.x.connsChanged = n.connsChanged
	n.key = n.newInput(nil)
	n.key.connsChanged = n.connsChanged
	if set {
		n.elem = n.newInput(nil)
		n.elem.connsChanged = n.connsChanged
	} else {
		n.elem = n.newOutput(nil)
	}
	n.text.SetText("[]")
	n.text.SetTextColor(color(&types.Func{}, true, false))
	n.addSeqPorts()
	n.connsChanged()
	return n
}

func (n *indexNode) connectable(t types.Type, dst *port) bool {
	if dst == n.x {
		ok := false
		switch t := underlying(t).(type) {
		case *types.Array, *types.Slice, *types.Map:
			ok = true
		case *types.Pointer:
			_, ok = underlying(t.Elem).(*types.Array)
		}
		return ok
	}
	if inputType(n.x) == nil {
		// A connection whose destination is being edited may currently be connected to n.x.  It is temporarily disconnected during the call to connectable, but inputs (such as n.elem) with dependent types are not updated, so we have to specifically check for this case here.
		return false
	}
	return assignable(t, dst.obj.Type)
}

func (n *indexNode) connsChanged() {
	if n.set == n.elem.out {
		n.removePortBase(n.elem)
		if n.set {
			n.elem = n.newInput(nil)
			n.elem.connsChanged = n.connsChanged
		} else {
			n.elem = n.newOutput(nil)
		}
	}
	t := inputType(n.x)
	var key, elem types.Type
	n.addressable = false
	if t != nil {
		key = types.Typ[types.Int]
		switch t := underlying(t).(type) {
		case *types.Array:
			elem = t.Elem
		case *types.Pointer:
			elem = underlying(t.Elem).(*types.Array).Elem
			if !n.set {
				elem = &types.Pointer{Elem: elem}
			}
			n.addressable = true
		case *types.Slice:
			elem = t.Elem
			if !n.set {
				elem = &types.Pointer{Elem: elem}
			}
			n.addressable = true
		case *types.Map:
			key, elem = t.Key, t.Elem
		}
	}
	n.x.setType(t)
	n.key.setType(key)
	n.elem.setType(elem)

	_, ok := underlying(t).(*types.Map)
	if !n.set && ok && n.ok == nil {
		n.ok = n.newOutput(newVar("ok", types.Typ[types.Bool]))
	}
	if (n.set || !ok) && n.ok != nil {
		n.removePortBase(n.ok)
		n.ok = nil
	}
}

func (n *indexNode) KeyPress(event KeyEvent) {
	if event.Text == "=" {
		if _, ok := underlying(inputType(n.x)).(*types.Map); ok || n.addressable {
			n.set = !n.set
			n.connsChanged()
			SetKeyFocus(n)
		}
	} else {
		n.nodeBase.KeyPress(event)
	}
}
<commit_msg>Flux:  Removed unnecessary connsChanged callbacks, one of which was leading to infinite recursion.<commit_after>// Copyright 2014 Gordon Klaus. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"code.google.com/p/gordon-go/go/types"
	. "code.google.com/p/gordon-go/gui"
)

type indexNode struct {
	*nodeBase
	set, addressable bool
	x, key, elem, ok *port
}

func newIndexNode(set bool) *indexNode {
	n := &indexNode{set: set}
	n.nodeBase = newNodeBase(n)
	n.x = n.newInput(nil)
	n.x.connsChanged = n.connsChanged
	n.key = n.newInput(nil)
	if set {
		n.elem = n.newInput(nil)
	} else {
		n.elem = n.newOutput(nil)
	}
	n.text.SetText("[]")
	n.text.SetTextColor(color(&types.Func{}, true, false))
	n.addSeqPorts()
	n.connsChanged()
	return n
}

func (n *indexNode) connectable(t types.Type, dst *port) bool {
	if dst == n.x {
		ok := false
		switch t := underlying(t).(type) {
		case *types.Array, *types.Slice, *types.Map:
			ok = true
		case *types.Pointer:
			_, ok = underlying(t.Elem).(*types.Array)
		}
		return ok
	}
	if inputType(n.x) == nil {
		// A connection whose destination is being edited may currently be connected to n.x.  It is temporarily disconnected during the call to connectable, but inputs (such as n.elem) with dependent types are not updated, so we have to specifically check for this case here.
		return false
	}
	return assignable(t, dst.obj.Type)
}

func (n *indexNode) connsChanged() {
	if n.set == n.elem.out {
		n.removePortBase(n.elem)
		if n.set {
			n.elem = n.newInput(nil)
		} else {
			n.elem = n.newOutput(nil)
		}
	}

	t := inputType(n.x)
	var key, elem types.Type
	n.addressable = false
	if t != nil {
		key = types.Typ[types.Int]
		switch t := underlying(t).(type) {
		case *types.Array:
			elem = t.Elem
		case *types.Pointer:
			elem = underlying(t.Elem).(*types.Array).Elem
			if !n.set {
				elem = &types.Pointer{Elem: elem}
			}
			n.addressable = true
		case *types.Slice:
			elem = t.Elem
			if !n.set {
				elem = &types.Pointer{Elem: elem}
			}
			n.addressable = true
		case *types.Map:
			key, elem = t.Key, t.Elem
		}
	}
	n.x.setType(t)
	n.key.setType(key)
	n.elem.setType(elem)

	_, ok := underlying(t).(*types.Map)
	if !n.set && ok && n.ok == nil {
		n.ok = n.newOutput(newVar("ok", types.Typ[types.Bool]))
	}
	if (n.set || !ok) && n.ok != nil {
		n.removePortBase(n.ok)
		n.ok = nil
	}
}

func (n *indexNode) KeyPress(event KeyEvent) {
	if event.Text == "=" {
		if _, ok := underlying(inputType(n.x)).(*types.Map); ok || n.addressable {
			n.set = !n.set
			n.connsChanged()
			SetKeyFocus(n)
		}
	} else {
		n.nodeBase.KeyPress(event)
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package bleve

import (
	"github.com/blevesearch/bleve/document"
	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/index/store"
)

// A Batch groups together multiple Index and Delete
// operations you would like performed at the same
// time.  The Batch structure is NOT thread-safe.
// You should only perform operations on a batch
// from a single thread at a time.  Once batch
// execution has started, you may not modify it.
type Batch struct {
	index    Index
	internal *index.Batch
}

// Index adds the specified index operation to the
// batch.  NOTE: the bleve Index is not updated
// until the batch is executed.
func (b *Batch) Index(id string, data interface{}) error {
	if id == "" {
		return ErrorEmptyID
	}
	doc := document.NewDocument(id)
	err := b.index.Mapping().mapDocument(doc, data)
	if err != nil {
		return err
	}
	b.internal.Update(doc)
	return nil
}

// Delete adds the specified delete operation to the
// batch.  NOTE: the bleve Index is not updated until
// the batch is executed.
func (b *Batch) Delete(id string) {
	if id != "" {
		b.internal.Delete(id)
	}
}

// SetInternal adds the specified set internal
// operation to the batch. NOTE: the bleve Index is
// not updated until the batch is executed.
func (b *Batch) SetInternal(key, val []byte) {
	b.internal.SetInternal(key, val)
}

// SetInternal adds the specified delete internal
// operation to the batch. NOTE: the bleve Index is
// not updated until the batch is executed.
func (b *Batch) DeleteInternal(key []byte) {
	b.internal.DeleteInternal(key)
}

// Size returns the total number of operations inside the batch
// including normal index operations and internal operations.
func (b *Batch) Size() int {
	return len(b.internal.IndexOps) + len(b.internal.InternalOps)
}

// String prints a user friendly string represenation of what
// is inside this batch.
func (b *Batch) String() string {
	return b.internal.String()
}

// Reset returns a Batch to the empty state so that it can
// be re-used in the future.
func (b *Batch) Reset() {
	b.internal.Reset()
}

// An Index implements all the indexing and searching
// capabilities of bleve.  An Index can be created
// using the New() and Open() methods.
//
// Index() takes an input value, deduces a DocumentMapping for its type,
// assigns string paths to its fields or values then applies field mappings on
// them.
//
// If the value is a []byte, the indexer attempts to convert it to something
// else using the ByteArrayConverter registered as
// IndexMapping.ByteArrayConverter. By default, it interprets the value as a
// JSON payload and unmarshals it to map[string]interface{}.
//
// The DocumentMapping used to index a value is deduced by the following rules:
// 1) If value implements Classifier interface, resolve the mapping from Type().
// 2) If value has a string field or value at IndexMapping.TypeField.
// (defaulting to "_type"), use it to resolve the mapping. Fields addressing
// is described below.
// 3) If IndexMapping.DefaultType is registered, return it.
// 4) Return IndexMapping.DefaultMapping.
//
// Each field or nested field of the value is identified by a string path, then
// mapped to one or several FieldMappings which extract the result for analysis.
//
// Struct values fields are identified by their "json:" tag, or by their name.
// Nested fields are identified by prefixing with their parent identifier,
// separated by a dot.
//
// Map values entries are identified by their string key. Entries not indexed
// by strings are ignored. Entry values are identified recursively like struct
// fields.
//
// Slice and array values are identified by their field name. Their elements
// are processed sequentially with the same FieldMapping.
//
// String, float64 and time.Time values are identified by their field name.
// Other types are ignored.
//
// Each value identifier is decomposed in its parts and recursively address
// SubDocumentMappings in the tree starting at the root DocumentMapping.  If a
// mapping is found, all its FieldMappings are applied to the value. If no
// mapping is found and the root DocumentMapping is dynamic, default mappings
// are used based on value type and IndexMapping default configurations.
//
// Finally, mapped values are analyzed, indexed or stored. See
// FieldMapping.Analyzer to know how an analyzer is resolved for a given field.
//
// Examples:
//
//  type Date struct {
//    Day string `json:"day"`
//    Month string
//    Year string
//  }
//
//  type Person struct {
//    FirstName string `json:"first_name"`
//    LastName string
//    BirthDate Date `json:"birth_date"`
//  }
//
// A Person value FirstName is mapped by the SubDocumentMapping at
// "first_name". Its LastName is mapped by the one at "LastName". The day of
// BirthDate is mapped to the SubDocumentMapping "day" of the root
// SubDocumentMapping "birth_date". It will appear as the "birth_date.day"
// field in the index. The month is mapped to "birth_date.Month".
type Index interface {
	// Index analyzes, indexes or stores mapped data fields. Supplied
	// identifier is bound to analyzed data and will be retrieved by search
	// requests. See Index interface documentation for details about mapping
	// rules.
	Index(id string, data interface{}) error
	Delete(id string) error

	NewBatch() *Batch
	Batch(b *Batch) error

	// Document returns specified document or nil if the document is not
	// indexed or stored.
	Document(id string) (*document.Document, error)
	// DocCount returns the number of documents in the index.
	DocCount() (uint64, error)

	Search(req *SearchRequest) (*SearchResult, error)

	Fields() ([]string, error)

	FieldDict(field string) (index.FieldDict, error)
	FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error)
	FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error)

	DumpAll() chan interface{}
	DumpDoc(id string) chan interface{}
	DumpFields() chan interface{}

	Close() error

	Mapping() *IndexMapping

	Stats() *IndexStat

	GetInternal(key []byte) ([]byte, error)
	SetInternal(key, val []byte) error
	DeleteInternal(key []byte) error

	// Advanced returns the indexer and data store, exposing lower level
	// methods to enumerate records and access data.
	Advanced() (index.Index, store.KVStore, error)
}

// A Classifier is an interface describing any object
// which knows how to identify its own type.
type Classifier interface {
	Type() string
}

// New index at the specified path, must not exist.
// The provided mapping will be used for all
// Index/Search operations.
func New(path string, mapping *IndexMapping) (Index, error) {
	return newIndexUsing(path, mapping, Config.DefaultIndexType, Config.DefaultKVStore, nil)
}

// NewUsing creates index at the specified path,
// which must not already exist.
// The provided mapping will be used for all
// Index/Search operations.
// The specified index type will be used
// The specified kvstore implemenation will be used
// and the provided kvconfig will be passed to its
// constructor.
func NewUsing(path string, mapping *IndexMapping, indexType string, kvstore string, kvconfig map[string]interface{}) (Index, error) {
	return newIndexUsing(path, mapping, indexType, kvstore, kvconfig)
}

// Open index at the specified path, must exist.
// The mapping used when it was created will be used for all Index/Search operations.
func Open(path string) (Index, error) {
	return openIndexUsing(path, nil)
}

// OpenUsing opens index at the specified path, must exist.
// The mapping used when it was created will be used for all Index/Search operations.
// The provided runtimeConfig can override settings
// persisted when the kvstore was created.
func OpenUsing(path string, runtimeConfig map[string]interface{}) (Index, error) {
	return openIndexUsing(path, runtimeConfig)
}
<commit_msg>index: document DumpAll, DumpDoc and DumpFields methods<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package bleve

import (
	"github.com/blevesearch/bleve/document"
	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/index/store"
)

// A Batch groups together multiple Index and Delete
// operations you would like performed at the same
// time.  The Batch structure is NOT thread-safe.
// You should only perform operations on a batch
// from a single thread at a time.  Once batch
// execution has started, you may not modify it.
type Batch struct {
	index    Index
	internal *index.Batch
}

// Index adds the specified index operation to the
// batch.  NOTE: the bleve Index is not updated
// until the batch is executed.
func (b *Batch) Index(id string, data interface{}) error {
	if id == "" {
		return ErrorEmptyID
	}
	doc := document.NewDocument(id)
	err := b.index.Mapping().mapDocument(doc, data)
	if err != nil {
		return err
	}
	b.internal.Update(doc)
	return nil
}

// Delete adds the specified delete operation to the
// batch.  NOTE: the bleve Index is not updated until
// the batch is executed.
func (b *Batch) Delete(id string) {
	if id != "" {
		b.internal.Delete(id)
	}
}

// SetInternal adds the specified set internal
// operation to the batch. NOTE: the bleve Index is
// not updated until the batch is executed.
func (b *Batch) SetInternal(key, val []byte) {
	b.internal.SetInternal(key, val)
}

// SetInternal adds the specified delete internal
// operation to the batch. NOTE: the bleve Index is
// not updated until the batch is executed.
func (b *Batch) DeleteInternal(key []byte) {
	b.internal.DeleteInternal(key)
}

// Size returns the total number of operations inside the batch
// including normal index operations and internal operations.
func (b *Batch) Size() int {
	return len(b.internal.IndexOps) + len(b.internal.InternalOps)
}

// String prints a user friendly string represenation of what
// is inside this batch.
func (b *Batch) String() string {
	return b.internal.String()
}

// Reset returns a Batch to the empty state so that it can
// be re-used in the future.
func (b *Batch) Reset() {
	b.internal.Reset()
}

// An Index implements all the indexing and searching
// capabilities of bleve.  An Index can be created
// using the New() and Open() methods.
//
// Index() takes an input value, deduces a DocumentMapping for its type,
// assigns string paths to its fields or values then applies field mappings on
// them.
//
// If the value is a []byte, the indexer attempts to convert it to something
// else using the ByteArrayConverter registered as
// IndexMapping.ByteArrayConverter. By default, it interprets the value as a
// JSON payload and unmarshals it to map[string]interface{}.
//
// The DocumentMapping used to index a value is deduced by the following rules:
// 1) If value implements Classifier interface, resolve the mapping from Type().
// 2) If value has a string field or value at IndexMapping.TypeField.
// (defaulting to "_type"), use it to resolve the mapping. Fields addressing
// is described below.
// 3) If IndexMapping.DefaultType is registered, return it.
// 4) Return IndexMapping.DefaultMapping.
//
// Each field or nested field of the value is identified by a string path, then
// mapped to one or several FieldMappings which extract the result for analysis.
//
// Struct values fields are identified by their "json:" tag, or by their name.
// Nested fields are identified by prefixing with their parent identifier,
// separated by a dot.
//
// Map values entries are identified by their string key. Entries not indexed
// by strings are ignored. Entry values are identified recursively like struct
// fields.
//
// Slice and array values are identified by their field name. Their elements
// are processed sequentially with the same FieldMapping.
//
// String, float64 and time.Time values are identified by their field name.
// Other types are ignored.
//
// Each value identifier is decomposed in its parts and recursively address
// SubDocumentMappings in the tree starting at the root DocumentMapping.  If a
// mapping is found, all its FieldMappings are applied to the value. If no
// mapping is found and the root DocumentMapping is dynamic, default mappings
// are used based on value type and IndexMapping default configurations.
//
// Finally, mapped values are analyzed, indexed or stored. See
// FieldMapping.Analyzer to know how an analyzer is resolved for a given field.
//
// Examples:
//
//  type Date struct {
//    Day string `json:"day"`
//    Month string
//    Year string
//  }
//
//  type Person struct {
//    FirstName string `json:"first_name"`
//    LastName string
//    BirthDate Date `json:"birth_date"`
//  }
//
// A Person value FirstName is mapped by the SubDocumentMapping at
// "first_name". Its LastName is mapped by the one at "LastName". The day of
// BirthDate is mapped to the SubDocumentMapping "day" of the root
// SubDocumentMapping "birth_date". It will appear as the "birth_date.day"
// field in the index. The month is mapped to "birth_date.Month".
type Index interface {
	// Index analyzes, indexes or stores mapped data fields. Supplied
	// identifier is bound to analyzed data and will be retrieved by search
	// requests. See Index interface documentation for details about mapping
	// rules.
	Index(id string, data interface{}) error
	Delete(id string) error

	NewBatch() *Batch
	Batch(b *Batch) error

	// Document returns specified document or nil if the document is not
	// indexed or stored.
	Document(id string) (*document.Document, error)
	// DocCount returns the number of documents in the index.
	DocCount() (uint64, error)

	Search(req *SearchRequest) (*SearchResult, error)

	Fields() ([]string, error)

	FieldDict(field string) (index.FieldDict, error)
	FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error)
	FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error)

	// DumpAll returns a channel receiving all index rows as
	// UpsideDownCouchRow, in lexicographic byte order. If the enumeration
	// fails, an error is sent. The channel is closed once the enumeration
	// completes or an error is encountered. A read transaction is maintained
	// for the duration of the enumeration, preventing concurrent write
	// operations to proceed. The caller must consume all channel entries until
	// the channel is closed to ensure the transaction and other resources
	// associated with the enumeration are released.
	//
	// DumpAll exists for debugging and tooling purpose and may change in the
	// future.
	DumpAll() chan interface{}

	// DumpDoc works like DumpAll but returns only StoredRows and
	// TermFrequencyRows related to a document.
	DumpDoc(id string) chan interface{}

	// DumpFields works like DumpAll but returns only FieldRows.
	DumpFields() chan interface{}

	Close() error

	Mapping() *IndexMapping

	Stats() *IndexStat

	GetInternal(key []byte) ([]byte, error)
	SetInternal(key, val []byte) error
	DeleteInternal(key []byte) error

	// Advanced returns the indexer and data store, exposing lower level
	// methods to enumerate records and access data.
	Advanced() (index.Index, store.KVStore, error)
}

// A Classifier is an interface describing any object
// which knows how to identify its own type.
type Classifier interface {
	Type() string
}

// New index at the specified path, must not exist.
// The provided mapping will be used for all
// Index/Search operations.
func New(path string, mapping *IndexMapping) (Index, error) {
	return newIndexUsing(path, mapping, Config.DefaultIndexType, Config.DefaultKVStore, nil)
}

// NewUsing creates index at the specified path,
// which must not already exist.
// The provided mapping will be used for all
// Index/Search operations.
// The specified index type will be used
// The specified kvstore implemenation will be used
// and the provided kvconfig will be passed to its
// constructor.
func NewUsing(path string, mapping *IndexMapping, indexType string, kvstore string, kvconfig map[string]interface{}) (Index, error) {
	return newIndexUsing(path, mapping, indexType, kvstore, kvconfig)
}

// Open index at the specified path, must exist.
// The mapping used when it was created will be used for all Index/Search operations.
func Open(path string) (Index, error) {
	return openIndexUsing(path, nil)
}

// OpenUsing opens index at the specified path, must exist.
// The mapping used when it was created will be used for all Index/Search operations.
// The provided runtimeConfig can override settings
// persisted when the kvstore was created.
func OpenUsing(path string, runtimeConfig map[string]interface{}) (Index, error) {
	return openIndexUsing(path, runtimeConfig)
}
<|endoftext|>


<commit_before>package cmd

import (
	"path/filepath"

	"fmt"

	"github.com/credentials/irmago"
	"github.com/go-errors/errors"
	"github.com/spf13/cobra"
)

// verifyCmd represents the verify command
var verifyCmd = &cobra.Command{
	Use:   "verify irma_configuration_path",
	Short: "Verify irma_configuration folder correctness and authenticity",
	Long:  `The verify command parses the specified irma_configuration folder and checks the signatures of the contained scheme managers.`,
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		path, err := filepath.Abs(args[0])
		if err != nil {
			return err
		}
		if filepath.Base(path) != "irma_configuration" {
			return errors.New("Path is not irma_configuration")
		}

		conf, err := irma.NewConfiguration(path, "")
		if err != nil {
			return err
		}
		if err := conf.ParseFolder(); err != nil {
			return err
		}

		for _, manager := range conf.SchemeManagers {
			for file := range manager.Index {
				// Don't care about the actual bytes
				if _, err := conf.ReadAuthenticatedFile(manager, file); err != nil {
					return err
				}
			}
		}

		fmt.Println()
		fmt.Println("irma_configuration parsed and authenticated successfully.")
		return nil
	},
}

func init() {
	RootCmd.AddCommand(verifyCmd)
}
<commit_msg>schememgr: split verify action into public function<commit_after>package cmd

import (
	"path/filepath"

	"fmt"

	"github.com/credentials/irmago"
	"github.com/go-errors/errors"
	"github.com/spf13/cobra"
)

// verifyCmd represents the verify command
var verifyCmd = &cobra.Command{
	Use:   "verify irma_configuration_path",
	Short: "Verify irma_configuration folder correctness and authenticity",
	Long:  `The verify command parses the specified irma_configuration folder and checks the signatures of the contained scheme managers.`,
	Args:  cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		err := RunVerify(args[0])
		if err == nil {
			fmt.Println()
			fmt.Println("irma_configuration parsed and authenticated successfully.")
		}
		return err
	},
}

func RunVerify(path string) error {
	path, err := filepath.Abs(path)
	if err != nil {
		return err
	}
	if filepath.Base(path) != "irma_configuration" {
		return errors.New("Path is not irma_configuration")
	}

	conf, err := irma.NewConfiguration(path, "")
	if err != nil {
		return err
	}
	if err := conf.ParseFolder(); err != nil {
		return err
	}

	for _, manager := range conf.SchemeManagers {
		for file := range manager.Index {
			// Don't care about the actual bytes
			if _, err := conf.ReadAuthenticatedFile(manager, file); err != nil {
				return err
			}
		}
	}
	return nil
}

func init() {
	RootCmd.AddCommand(verifyCmd)
}
<|endoftext|>


<commit_before>package scoring

import (
	"reflect"
	"sort"
	"testing"
)

func TestEntriesSort(t *testing.T) {
	e1 := Entry{"/foo", &Score{100, Now}}
	e2 := Entry{"/foo/bar", &Score{200, Now}}

	entries := Entries([]Entry{e1, e2})
	expectedEntries := Entries([]Entry{e1, e2})

	sort.Sort(entries)

	if !reflect.DeepEqual(expectedEntries, entries) {
		t.Errorf("Expected entries to be %v, got %v", expectedEntries, entries)
	}
}
<commit_msg>Fix a typo in a test<commit_after>package scoring

import (
	"reflect"
	"testing"
)

func TestEntriesSort(t *testing.T) {
	e1 := Entry{"/foo", &Score{100, Now}}
	e2 := Entry{"/foo/bar", &Score{200, Now}}

	entries := Entries([]Entry{e1, e2})
	expectedEntries := Entries([]Entry{e1, e2})

	entries.Sort()

	if !reflect.DeepEqual(expectedEntries, entries) {
		t.Errorf("Expected entries to be %v, got %v", expectedEntries, entries)
	}
}
<|endoftext|>