<commit_before>package opts

import (
	"net"
	"testing"
)

func TestIpOptString(t *testing.T) {
	addresses := []string{"", "0.0.0.0"}
	var ip net.IP

	for _, address := range addresses {
		stringAddress := NewIpOpt(&ip, address).String()
		if stringAddress != address {
			t.Fatalf("IpOpt string should be `%s`, not `%s`", address, stringAddress)
		}
	}
}

func TestNewIpOptInvalidDefaultVal(t *testing.T) {
	ip := net.IPv4(127, 0, 0, 1)
	defaultVal := "Not an ip"

	ipOpt := NewIpOpt(&ip, defaultVal)

	expected := "127.0.0.1"
	if ipOpt.String() != expected {
		t.Fatalf("Expected [%v], got [%v]", expected, ipOpt.String())
	}
}

func TestNewIpOptValidDefaultVal(t *testing.T) {
	ip := net.IPv4(127, 0, 0, 1)
	defaultVal := "192.168.1.1"

	ipOpt := NewIpOpt(&ip, defaultVal)

	expected := "192.168.1.1"
	if ipOpt.String() != expected {
		t.Fatalf("Expected [%v], got [%v]", expected, ipOpt.String())
	}
}

func TestIpOptSetInvalidVal(t *testing.T) {
	ip := net.IPv4(127, 0, 0, 1)
	ipOpt := &IpOpt{IP: &ip}

	invalidIP := "invalid ip"
	expectedError := "invalid ip is not an ip address"
	err := ipOpt.Set(invalidIP)
	if err == nil || err.Error() != expectedError {
		t.Fatalf("Expected an Error with [%v], got [%v]", expectedError, err.Error())
	}
}
<commit_msg>golint: trust<commit_after>package opts

import (
	"net"
	"testing"
)

func TestIpOptString(t *testing.T) {
	addresses := []string{"", "0.0.0.0"}
	var ip net.IP

	for _, address := range addresses {
		stringAddress := NewIPOpt(&ip, address).String()
		if stringAddress != address {
			t.Fatalf("IpOpt string should be `%s`, not `%s`", address, stringAddress)
		}
	}
}

func TestNewIpOptInvalidDefaultVal(t *testing.T) {
	ip := net.IPv4(127, 0, 0, 1)
	defaultVal := "Not an ip"

	ipOpt := NewIPOpt(&ip, defaultVal)

	expected := "127.0.0.1"
	if ipOpt.String() != expected {
		t.Fatalf("Expected [%v], got [%v]", expected, ipOpt.String())
	}
}

func TestNewIpOptValidDefaultVal(t *testing.T) {
	ip := net.IPv4(127, 0, 0, 1)
	defaultVal := "192.168.1.1"

	ipOpt := NewIPOpt(&ip, defaultVal)

	expected := "192.168.1.1"
	if ipOpt.String() != expected {
		t.Fatalf("Expected [%v], got [%v]", expected, ipOpt.String())
	}
}

func TestIpOptSetInvalidVal(t *testing.T) {
	ip := net.IPv4(127, 0, 0, 1)
	ipOpt := &IPOpt{IP: &ip}

	invalidIP := "invalid ip"
	expectedError := "invalid ip is not an ip address"
	err := ipOpt.Set(invalidIP)
	if err == nil || err.Error() != expectedError {
		t.Fatalf("Expected an Error with [%v], got [%v]", expectedError, err.Error())
	}
}
<|endoftext|>


<commit_before>package order

import (
	"github.com/cogger/cogger"
	"golang.org/x/net/context"
)

//Series will execute the workers in order.
//It will wait for the previous to finish before starting the next.
func Series(ctx context.Context, cogs ...cogger.Cog) cogger.Cog {
	return cogger.NewCog(func() chan error {
		out := make(chan error, len(cogs))
		go func() {
			defer close(out)
			for _, cog := range cogs {
				select {
				case <-ctx.Done():
					out <- ctx.Err()
				case err := <-cog.Do(ctx):
					if err != nil {
						out <- err
					}
				}
			}
		}()
		return out
	})
}
<commit_msg>updated series to not prematurely return<commit_after>package order

import (
	"github.com/cogger/cogger"
	"golang.org/x/net/context"
)

//Series will execute the workers in order.
//It will wait for the previous to finish before starting the next.
func Series(ctx context.Context, cogs ...cogger.Cog) cogger.Cog {
	return cogger.NewCog(func() chan error {
		out := make(chan error, len(cogs))
		go func() {
			defer close(out)
			for _, cog := range cogs {
				for err := range cog.Do(ctx) {
					if ctx.Err() != nil {
						out <- err
						break
					}
					if err != nil {
						out <- err
					}
				}
			}
		}()
		return out
	})
}
<|endoftext|>


<commit_before>// Copyright 2020 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

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

	"github.com/google/syzkaller/pkg/kcidb"
	"golang.org/x/net/context"
	"google.golang.org/appengine"
	db "google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
)

func initKcidb() {
	http.HandleFunc("/kcidb_poll", handleKcidbPoll)
}

func handleKcidbPoll(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	for ns, cfg := range config.Namespaces {
		if cfg.Kcidb == nil {
			continue
		}
		if err := handleKcidbNamespce(c, ns, cfg.Kcidb); err != nil {
			log.Errorf(c, "kcidb: %v failed: %v", ns, err)
		}
	}
}

func handleKcidbNamespce(c context.Context, ns string, cfg *KcidbConfig) error {
	client, err := kcidb.NewClient(c, cfg.Origin, cfg.Project, cfg.Topic, cfg.Credentials)
	if err != nil {
		return err
	}
	defer client.Close()

	filter := func(query *db.Query) *db.Query {
		return query.Filter("Namespace=", ns).
			Filter("Status=", BugStatusOpen)
	}
	reported := 0
	return foreachBug(c, filter, func(bug *Bug, bugKey *db.Key) error {
		if reported >= 30 ||
			bug.KcidbStatus != 0 ||
			bug.sanitizeAccess(AccessPublic) > AccessPublic ||
			bug.Reporting[len(bug.Reporting)-1].Reported.IsZero() ||
			timeSince(c, bug.LastTime) > 7*24*time.Hour {
			return nil
		}
		reported++
		return publishKcidbBug(c, client, bug, bugKey)
	})
}

func publishKcidbBug(c context.Context, client *kcidb.Client, bug *Bug, bugKey *db.Key) error {
	rep, err := loadBugReport(c, bug)
	if err != nil {
		return err
	}
	if err := client.Publish(rep); err != nil {
		return err
	}
	tx := func(c context.Context) error {
		bug := new(Bug)
		if err := db.Get(c, bugKey, bug); err != nil {
			return err
		}
		bug.KcidbStatus = 1
		if _, err := db.Put(c, bugKey, bug); err != nil {
			return fmt.Errorf("failed to put bug: %v", err)
		}
		return nil
	}
	if err := db.RunInTransaction(c, tx, nil); err != nil {
		return err
	}
	log.Infof(c, "published bug to kcidb: %v:%v '%v'", bug.Namespace, bugKey.StringID(), bug.displayTitle())
	return nil
}
<commit_msg>dashboard/app: export all open bugs to Kcidb<commit_after>// Copyright 2020 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

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

	"github.com/google/syzkaller/pkg/kcidb"
	"golang.org/x/net/context"
	"google.golang.org/appengine"
	db "google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
)

func initKcidb() {
	http.HandleFunc("/kcidb_poll", handleKcidbPoll)
}

func handleKcidbPoll(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	for ns, cfg := range config.Namespaces {
		if cfg.Kcidb == nil {
			continue
		}
		if err := handleKcidbNamespce(c, ns, cfg.Kcidb); err != nil {
			log.Errorf(c, "kcidb: %v failed: %v", ns, err)
		}
	}
}

func handleKcidbNamespce(c context.Context, ns string, cfg *KcidbConfig) error {
	client, err := kcidb.NewClient(c, cfg.Origin, cfg.Project, cfg.Topic, cfg.Credentials)
	if err != nil {
		return err
	}
	defer client.Close()

	filter := func(query *db.Query) *db.Query {
		return query.Filter("Namespace=", ns).
			Filter("Status=", BugStatusOpen)
	}
	reported := 0
	return foreachBug(c, filter, func(bug *Bug, bugKey *db.Key) error {
		if reported >= 30 ||
			bug.KcidbStatus != 0 ||
			bug.sanitizeAccess(AccessPublic) > AccessPublic ||
			bug.Reporting[len(bug.Reporting)-1].Reported.IsZero() ||
			bug.Status != BugStatusOpen && timeSince(c, bug.LastTime) > 7*24*time.Hour {
			return nil
		}
		reported++
		return publishKcidbBug(c, client, bug, bugKey)
	})
}

func publishKcidbBug(c context.Context, client *kcidb.Client, bug *Bug, bugKey *db.Key) error {
	rep, err := loadBugReport(c, bug)
	if err != nil {
		return err
	}
	if err := client.Publish(rep); err != nil {
		return err
	}
	tx := func(c context.Context) error {
		bug := new(Bug)
		if err := db.Get(c, bugKey, bug); err != nil {
			return err
		}
		bug.KcidbStatus = 1
		if _, err := db.Put(c, bugKey, bug); err != nil {
			return fmt.Errorf("failed to put bug: %v", err)
		}
		return nil
	}
	if err := db.RunInTransaction(c, tx, nil); err != nil {
		return err
	}
	log.Infof(c, "published bug to kcidb: %v:%v '%v'", bug.Namespace, bugKey.StringID(), bug.displayTitle())
	return nil
}
<|endoftext|>


<commit_before>package parser

import (
	"io"
	"path/filepath"
	"net"
	"net/mail"
	"os"
	"regexp"
	"strconv"
	"text/scanner"
	"unicode"

	"github.com/yuuki1/gokc/log"
)

var SYMBOL_TABLES = map[string]int{
	"{": LB,
	"}": RB,

	"global_defs": GLOBALDEFS,
	"notification_email": NOTIFICATION_EMAIL,
	"notification_email_from": NOTIFICATION_EMAIL_FROM,
	"smtp_server": SMTP_SERVER,
	"smtp_connect_timeout": SMTP_CONNECT_TIMEOUT,
	"router_id": ROUTER_ID,
	"lvs_id": LVS_ID,

	"vrrp_sync_group": VRRP_SYNC_GROUP,
	"group": GROUP,

	"vrrp_instance": VRRP_INSTANCE,
	"interface": INTERFACE,
	"lvs_sync_daemon_interface": LVS_SYNC_DAEMON_INTERFACE,
	"virtual_router_id": VIRTUAL_ROUTER_ID,
	"nopreempt": NOPREEMPT,
	"priority": PRIORITY,
	"advert_int": ADVERT_INT,
	"virtual_ipaddress": VIRTUAL_IPADDRESS,
	"state": STATE,
	"MASTER": MASTER,
	"BACKUP": BACKUP,
	"garp_master_delay": GARP_MASTER_DELAY,
	"smtp_alert": SMTP_ALERT,
	"authentication": AUTHENTICATION,
	"auth_type": AUTH_TYPE,
	"auth_pass": AUTH_PASS,
	"PASS": PASS,
	"AH": AH,
	"label": LABEL,
	"dev": DEV,
	"brd": BRD,
	"track_interface": TRACK_INTERFACE,
	"track_script": TRACK_SCRIPT,
	"notify_master": NOTIFY_MASTER,
	"notify_backup": NOTIFY_BACKUP,
	"notify_fault": NOTIFY_FAULT,
	"notify_stop": NOTIFY_STOP,
	"notify": NOTIFY,

	"vrrp_script": VRRP_SCRIPT,
	"script": SCRIPT,
	"interval": INTERVAL,
	"fall": FALL,
	"rise": RISE,

	"virtual_server": VIRTUAL_SERVER,
	"delay_loop": DELAY_LOOP,
	"lb_algo": LB_ALGO,
	"lb_kind": LB_KIND,
	"lvs_sched": LVS_SCHED,
	"lvs_method": LVS_METHOD,
	"rr": RR,
	"wrr": WRR,
	"lc": LC,
	"wlc": WLC,
	"lblc": LBLC,
	"sh": SH,
	"dh": DH,
	"NAT": NAT,
	"DR": DR,
	"TUN": TUN,
	"persistence_timeout": PERSISTENCE_TIMEOUT,
	"protocol": PROTOCOL,
	"TCP": TCP,
	"UDP": UDP,
	"sorry_server": SORRY_SERVER,
	"real_server": REAL_SERVER,
	"weight": WEIGHT,
	"inhibit_on_failure": INHIBIT_ON_FAILURE,
	"TCP_CHECK": TCP_CHECK,
	"HTTP_GET": HTTP_GET,
	"url": URL,
	"path": PATH,
	"digest": DIGEST,
	"status_code": STATUS_CODE,
	"connect_timeout": CONNECT_TIMEOUT,
	"connect_port": CONNECT_PORT,
	"nb_get_retry": NB_GET_RETRY,
	"delay_before_retry": DELAY_BEFORE_RETRY,
	"virtualhost": VIRTUALHOST,
}

type Lexer struct {
	ctx *Context
	emitter chan int
	e *Error
}

type Context struct {
	scanner scanner.Scanner
	filename string
}

type Error struct {
	Message string
	Filename string
	Line int
	Column int
}

func (e *Error) Error() string {
	return e.Message
}

func NewLexer(src io.Reader, filename string) *Lexer {
	var lex Lexer
	lex.ctx = NewContext(src, filename)
	lex.emitter = make(chan int)
	return &lex
}

func NewContext(src io.Reader, filename string) *Context {
	c := &Context{filename: filename}
	c.scanner.Init(src)
	c.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats | scanner.ScanChars | scanner.ScanRawStrings | scanner.ScanComments | scanner.SkipComments
	c.scanner.IsIdentRune = isIdentRune
	return c
}

func isIdentRune(ch rune, i int) bool {
	return ch == '_' || ch == '.' || ch == '/' || ch == ':' || ch == '-' || ch == '+' || ch == '*' || ch == '@' || unicode.IsLetter(ch) || unicode.IsDigit(ch)
}

func (c *Context) scanNextToken() (int, string) {
	token := int(c.scanner.Scan())
	s := c.scanner.TokenText()

	for s == "!" || s == "#" {
		c.skipComments()

		token = int(c.scanner.Scan())
		s = c.scanner.TokenText()
	}

	log.Debugf("token text: %s\n", s)

	return token, s
}

func (c *Context) skipComments() {
	ch := c.scanner.Next()
	for ch != '\n' && ch >= 0 {
		ch = c.scanner.Next()
	}
}

func (l *Lexer) scanInclude(filename string) error {
	curDir, err := filepath.Abs(".")
	if err != nil {
		return err
	}

	baseDir := filepath.Dir(l.ctx.filename)
	os.Chdir(baseDir)
	defer os.Chdir(curDir)

	paths, err := filepath.Glob(filename)
	if err != nil {
		return err
	}

	prevctx := l.ctx
	defer func() { l.ctx = prevctx }()

	for _, p := range paths {
		path := filepath.Join(baseDir, p)
		log.Debug(path)

		f, err := os.Open(path)
		if err != nil {
			return err
		}

		l.ctx = NewContext(f, path)
		l.run()

		f.Close()
	}

	return nil
}

func (l *Lexer) Lex(lval *yySymType) int {
	return <-l.emitter
}

func (l *Lexer) mainRun() {
	l.run()
	// XXX
	l.emitter <- scanner.EOF
	l.emitter <- scanner.EOF
}

func (l *Lexer) run() {
	for {
		token, s := l.ctx.scanNextToken()

		if s == "include" {
			token, s = l.ctx.scanNextToken()

			if err := l.scanInclude(s); err != nil {
				l.Error(err.Error())
			}

			token, s = l.ctx.scanNextToken()
		}

		if token == scanner.EOF {
			break
		}

		if token == scanner.Ident || token == scanner.String {
			token = STRING
		}

		if _, err := strconv.Atoi(s); err == nil {
			token = NUMBER
		}

		if net.ParseIP(s) != nil {
			token = IPADDR
		}

		if _, _, err := net.ParseCIDR(s); err == nil {
			token = IP_CIDR
		}

		if ok, _ := regexp.MatchString("[[:xdigit:]]{32}", s); ok {
			token = HEX32
		}

		if ok, _ := regexp.MatchString("/^([[:alnum:]./-_])*", s); ok {
			token = PATHSTR
		}

		if _, err := mail.ParseAddress(s); err == nil {
			token = EMAIL
		}

		if _, ok := SYMBOL_TABLES[s]; ok {
			token = SYMBOL_TABLES[s]
		}

		l.emitter <- token
	}
}

func (l *Lexer) Error(msg string) {
	l.e = &Error{
		Filename: l.ctx.filename,
		Line: l.ctx.scanner.Line,
		Column: l.ctx.scanner.Column,
		Message: msg,
	}
}

func Parse(src io.Reader, filename string) error {
	yyErrorVerbose = true
	l := NewLexer(src, filename)
	go l.mainRun()
	if ret := yyParse(l); ret != 0 {
		return l.e
	}
	return nil
}

<commit_msg>Add safe close emitter<commit_after>package parser

import (
	"io"
	"path/filepath"
	"net"
	"net/mail"
	"os"
	"regexp"
	"strconv"
	"text/scanner"
	"unicode"

	"github.com/yuuki1/gokc/log"
)

var SYMBOL_TABLES = map[string]int{
	"{": LB,
	"}": RB,

	"global_defs": GLOBALDEFS,
	"notification_email": NOTIFICATION_EMAIL,
	"notification_email_from": NOTIFICATION_EMAIL_FROM,
	"smtp_server": SMTP_SERVER,
	"smtp_connect_timeout": SMTP_CONNECT_TIMEOUT,
	"router_id": ROUTER_ID,
	"lvs_id": LVS_ID,

	"vrrp_sync_group": VRRP_SYNC_GROUP,
	"group": GROUP,

	"vrrp_instance": VRRP_INSTANCE,
	"interface": INTERFACE,
	"lvs_sync_daemon_interface": LVS_SYNC_DAEMON_INTERFACE,
	"virtual_router_id": VIRTUAL_ROUTER_ID,
	"nopreempt": NOPREEMPT,
	"priority": PRIORITY,
	"advert_int": ADVERT_INT,
	"virtual_ipaddress": VIRTUAL_IPADDRESS,
	"state": STATE,
	"MASTER": MASTER,
	"BACKUP": BACKUP,
	"garp_master_delay": GARP_MASTER_DELAY,
	"smtp_alert": SMTP_ALERT,
	"authentication": AUTHENTICATION,
	"auth_type": AUTH_TYPE,
	"auth_pass": AUTH_PASS,
	"PASS": PASS,
	"AH": AH,
	"label": LABEL,
	"dev": DEV,
	"brd": BRD,
	"track_interface": TRACK_INTERFACE,
	"track_script": TRACK_SCRIPT,
	"notify_master": NOTIFY_MASTER,
	"notify_backup": NOTIFY_BACKUP,
	"notify_fault": NOTIFY_FAULT,
	"notify_stop": NOTIFY_STOP,
	"notify": NOTIFY,

	"vrrp_script": VRRP_SCRIPT,
	"script": SCRIPT,
	"interval": INTERVAL,
	"fall": FALL,
	"rise": RISE,

	"virtual_server": VIRTUAL_SERVER,
	"delay_loop": DELAY_LOOP,
	"lb_algo": LB_ALGO,
	"lb_kind": LB_KIND,
	"lvs_sched": LVS_SCHED,
	"lvs_method": LVS_METHOD,
	"rr": RR,
	"wrr": WRR,
	"lc": LC,
	"wlc": WLC,
	"lblc": LBLC,
	"sh": SH,
	"dh": DH,
	"NAT": NAT,
	"DR": DR,
	"TUN": TUN,
	"persistence_timeout": PERSISTENCE_TIMEOUT,
	"protocol": PROTOCOL,
	"TCP": TCP,
	"UDP": UDP,
	"sorry_server": SORRY_SERVER,
	"real_server": REAL_SERVER,
	"weight": WEIGHT,
	"inhibit_on_failure": INHIBIT_ON_FAILURE,
	"TCP_CHECK": TCP_CHECK,
	"HTTP_GET": HTTP_GET,
	"url": URL,
	"path": PATH,
	"digest": DIGEST,
	"status_code": STATUS_CODE,
	"connect_timeout": CONNECT_TIMEOUT,
	"connect_port": CONNECT_PORT,
	"nb_get_retry": NB_GET_RETRY,
	"delay_before_retry": DELAY_BEFORE_RETRY,
	"virtualhost": VIRTUALHOST,
}

type Lexer struct {
	ctx *Context
	emitter chan int
	e *Error
}

type Context struct {
	scanner scanner.Scanner
	filename string
}

type Error struct {
	Message string
	Filename string
	Line int
	Column int
}

func (e *Error) Error() string {
	return e.Message
}

func NewLexer(src io.Reader, filename string) *Lexer {
	var lex Lexer
	lex.ctx = NewContext(src, filename)
	lex.emitter = make(chan int)
	return &lex
}

func NewContext(src io.Reader, filename string) *Context {
	c := &Context{filename: filename}
	c.scanner.Init(src)
	c.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats | scanner.ScanChars | scanner.ScanRawStrings | scanner.ScanComments | scanner.SkipComments
	c.scanner.IsIdentRune = isIdentRune
	return c
}

func isIdentRune(ch rune, i int) bool {
	return ch == '_' || ch == '.' || ch == '/' || ch == ':' || ch == '-' || ch == '+' || ch == '*' || ch == '@' || unicode.IsLetter(ch) || unicode.IsDigit(ch)
}

func (c *Context) scanNextToken() (int, string) {
	token := int(c.scanner.Scan())
	s := c.scanner.TokenText()

	for s == "!" || s == "#" {
		c.skipComments()

		token = int(c.scanner.Scan())
		s = c.scanner.TokenText()
	}

	log.Debugf("token text: %s\n", s)

	return token, s
}

func (c *Context) skipComments() {
	ch := c.scanner.Next()
	for ch != '\n' && ch >= 0 {
		ch = c.scanner.Next()
	}
}

func (l *Lexer) scanInclude(filename string) error {
	curDir, err := filepath.Abs(".")
	if err != nil {
		return err
	}

	baseDir := filepath.Dir(l.ctx.filename)
	os.Chdir(baseDir)
	defer os.Chdir(curDir)

	paths, err := filepath.Glob(filename)
	if err != nil {
		return err
	}

	prevctx := l.ctx
	defer func() { l.ctx = prevctx }()

	for _, p := range paths {
		path := filepath.Join(baseDir, p)
		log.Debug(path)

		f, err := os.Open(path)
		if err != nil {
			return err
		}

		l.ctx = NewContext(f, path)
		l.run()

		f.Close()
	}

	return nil
}

func (l *Lexer) Lex(lval *yySymType) int {
	return <-l.emitter
}

func (l *Lexer) mainRun() {
	l.run()
	// XXX
	l.emitter <- scanner.EOF
	l.emitter <- scanner.EOF
	close(l.emitter)
}

func (l *Lexer) run() {
	for {
		token, s := l.ctx.scanNextToken()

		if s == "include" {
			token, s = l.ctx.scanNextToken()

			if err := l.scanInclude(s); err != nil {
				l.Error(err.Error())
			}

			token, s = l.ctx.scanNextToken()
		}

		if token == scanner.EOF {
			break
		}

		if token == scanner.Ident || token == scanner.String {
			token = STRING
		}

		if _, err := strconv.Atoi(s); err == nil {
			token = NUMBER
		}

		if net.ParseIP(s) != nil {
			token = IPADDR
		}

		if _, _, err := net.ParseCIDR(s); err == nil {
			token = IP_CIDR
		}

		if ok, _ := regexp.MatchString("[[:xdigit:]]{32}", s); ok {
			token = HEX32
		}

		if ok, _ := regexp.MatchString("/^([[:alnum:]./-_])*", s); ok {
			token = PATHSTR
		}

		if _, err := mail.ParseAddress(s); err == nil {
			token = EMAIL
		}

		if _, ok := SYMBOL_TABLES[s]; ok {
			token = SYMBOL_TABLES[s]
		}

		l.emitter <- token
	}
}

func (l *Lexer) Error(msg string) {
	l.e = &Error{
		Filename: l.ctx.filename,
		Line: l.ctx.scanner.Line,
		Column: l.ctx.scanner.Column,
		Message: msg,
	}
}

func Parse(src io.Reader, filename string) error {
	yyErrorVerbose = true
	l := NewLexer(src, filename)
	go l.mainRun()
	if ret := yyParse(l); ret != 0 {
		return l.e
	}
	return nil
}

<|endoftext|>


<commit_before>/*
Package common holds code shared between other bounded contexts
*/
package proxy
<commit_msg>Update auth package comment<commit_after>/*
Package auth holds authentication service
*/
package auth
<|endoftext|>


<commit_before>package render

import (
	"fmt"
	"html/template"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/gobuffalo/buffalo/internal/takeon/github.com/gobuffalo/syncx"
	"github.com/gobuffalo/buffalo/internal/takeon/github.com/markbates/errx"
	"github.com/gobuffalo/packd"
	"github.com/sirupsen/logrus"
)

type templateRenderer struct {
	*Engine
	contentType string
	names       []string
	aliases     syncx.StringMap
}

func (s templateRenderer) ContentType() string {
	return s.contentType
}

func (s templateRenderer) resolve(name string) ([]byte, error) {
	if s.TemplatesBox == nil {
		return nil, fmt.Errorf("no templates box is defined")
	}

	if s.TemplatesBox.Has(name) {
		return s.TemplatesBox.Find(name)
	}

	v, ok := s.aliases.Load(name)
	if !ok {
		return nil, fmt.Errorf("could not find template %s", name)
	}

	return s.TemplatesBox.Find(v)
}

func (s *templateRenderer) Render(w io.Writer, data Data) error {
	if s.TemplatesBox != nil {
		err := s.TemplatesBox.Walk(func(p string, f packd.File) error {
			base := filepath.Base(p)

			dir := filepath.Dir(p)

			var exts []string
			sep := strings.Split(base, ".")
			if len(sep) >= 1 {
				base = sep[0]
			}
			if len(sep) > 1 {
				exts = sep[1:]
			}

			for _, ext := range exts {
				pn := filepath.Join(dir, base+"."+ext)
				s.aliases.Store(pn, p)
			}

			return nil
		})
		if err != nil {
			return err
		}
	}

	var body template.HTML
	var err error
	for _, name := range s.names {
		body, err = s.exec(name, data)
		if err != nil {
			return errx.Wrap(err, name)
		}
		data["yield"] = body
	}
	w.Write([]byte(body))
	return nil
}

func fixExtension(name string, ct string) string {
	if filepath.Ext(name) == "" {
		switch {
		case strings.Contains(ct, "html"):
			name += ".html"
		case strings.Contains(ct, "javascript"):
			name += ".js"
		case strings.Contains(ct, "markdown"):
			name += ".md"
		}
	}
	return name
}

// partialFeeder returns template string for the name from `TemplateBox`.
// It should be registered as helper named `partialFeeder` so plush can
// find it with the name.
func (s templateRenderer) partialFeeder(name string) (string, error) {
	ct := strings.ToLower(s.contentType)

	d, f := filepath.Split(name)
	name = filepath.Join(d, "_"+f)
	name = fixExtension(name, ct)

	b, err := s.resolve(name)
	return string(b), err
}

func (s templateRenderer) exec(name string, data Data) (template.HTML, error) {
	ct := strings.ToLower(s.contentType)
	data["contentType"] = ct

	name = fixExtension(name, ct)

	// Try to use localized version
	templateName := name
	if languages, ok := data["languages"].([]string); ok {
		ll := len(languages)
		if ll > 0 {
			// Default language is the last in the list
			defaultLanguage := languages[ll-1]
			ext := filepath.Ext(name)
			rawName := strings.TrimSuffix(name, ext)

			for _, l := range languages {
				var candidateName string
				if l == defaultLanguage {
					break
				}
				candidateName = rawName + "." + strings.ToLower(l) + ext
				if _, err := s.resolve(candidateName); err == nil {
					// Replace name with the existing suffixed version
					templateName = candidateName
					break
				}
			}
		}
	}

	// Set current_template to context
	if _, ok := data["current_template"]; !ok {
		data["current_template"] = templateName
	}

	source, err := s.resolve(templateName)
	if err != nil {
		return "", err
	}

	helpers := map[string]interface{}{}

	for k, v := range s.Helpers {
		helpers[k] = v
	}

	// Allows to specify custom partialFeeder
	if helpers["partialFeeder"] == nil {
		helpers["partialFeeder"] = s.partialFeeder
	}

	helpers = s.addAssetsHelpers(helpers)

	body := string(source)
	for _, ext := range s.exts(name) {
		te, ok := s.TemplateEngines[ext]
		if !ok {
			logrus.Errorf("could not find a template engine for %s", ext)
			continue
		}
		body, err = te(body, data, helpers)
		if err != nil {
			return "", err
		}
	}

	return template.HTML(body), nil
}

func (s templateRenderer) exts(name string) []string {
	exts := []string{}
	for {
		ext := filepath.Ext(name)
		if ext == "" {
			break
		}
		name = strings.TrimSuffix(name, ext)
		exts = append(exts, strings.ToLower(ext[1:]))
	}
	if len(exts) == 0 {
		return []string{"html"}
	}
	sort.Sort(sort.Reverse(sort.StringSlice(exts)))
	return exts
}

func (s templateRenderer) assetPath(file string) (string, error) {

	if len(assetMap.Keys()) == 0 || os.Getenv("GO_ENV") != "production" {
		manifest, err := s.AssetsBox.FindString("manifest.json")

		if err != nil {
			manifest, err = s.AssetsBox.FindString("assets/manifest.json")
			if err != nil {
				return assetPathFor(file), nil
			}
		}

		err = loadManifest(manifest)
		if err != nil {
			return assetPathFor(file), fmt.Errorf("your manifest.json is not correct: %s", err)
		}
	}

	return assetPathFor(file), nil
}

// Template renders the named files using the specified
// content type and the github.com/gobuffalo/plush
// package for templating. If more than 1 file is provided
// the second file will be considered a "layout" file
// and the first file will be the "content" file which will
// be placed into the "layout" using "{{yield}}".
func Template(c string, names ...string) Renderer {
	e := New(Options{})
	return e.Template(c, names...)
}

// Template renders the named files using the specified
// content type and the github.com/gobuffalo/plush
// package for templating. If more than 1 file is provided
// the second file will be considered a "layout" file
// and the first file will be the "content" file which will
// be placed into the "layout" using "{{yield}}".
func (e *Engine) Template(c string, names ...string) Renderer {
	return &templateRenderer{
		Engine:      e,
		contentType: c,
		names:       names,
		aliases:     syncx.StringMap{},
	}
}
<commit_msg>cleaning up a bit for codeclimate<commit_after>package render

import (
	"fmt"
	"html/template"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/gobuffalo/buffalo/internal/takeon/github.com/gobuffalo/syncx"
	"github.com/gobuffalo/buffalo/internal/takeon/github.com/markbates/errx"
	"github.com/gobuffalo/packd"
	"github.com/sirupsen/logrus"
)

type templateRenderer struct {
	*Engine
	contentType string
	names       []string
	aliases     syncx.StringMap
}

func (s templateRenderer) ContentType() string {
	return s.contentType
}

func (s templateRenderer) resolve(name string) ([]byte, error) {
	if s.TemplatesBox == nil {
		return nil, fmt.Errorf("no templates box is defined")
	}

	if s.TemplatesBox.Has(name) {
		return s.TemplatesBox.Find(name)
	}

	v, ok := s.aliases.Load(name)
	if !ok {
		return nil, fmt.Errorf("could not find template %s", name)
	}

	return s.TemplatesBox.Find(v)
}

func (s *templateRenderer) Render(w io.Writer, data Data) error {
	if s.TemplatesBox != nil {
		err := s.TemplatesBox.Walk(func(p string, f packd.File) error {
			base := filepath.Base(p)

			dir := filepath.Dir(p)

			var exts []string
			sep := strings.Split(base, ".")
			if len(sep) >= 1 {
				base = sep[0]
			}
			if len(sep) > 1 {
				exts = sep[1:]
			}

			for _, ext := range exts {
				pn := filepath.Join(dir, base+"."+ext)
				s.aliases.Store(pn, p)
			}

			return nil
		})
		if err != nil {
			return err
		}
	}

	var body template.HTML
	var err error
	for _, name := range s.names {
		body, err = s.exec(name, data)
		if err != nil {
			return errx.Wrap(err, name)
		}
		data["yield"] = body
	}
	w.Write([]byte(body))
	return nil
}

func fixExtension(name string, ct string) string {
	if filepath.Ext(name) == "" {
		switch {
		case strings.Contains(ct, "html"):
			name += ".html"
		case strings.Contains(ct, "javascript"):
			name += ".js"
		case strings.Contains(ct, "markdown"):
			name += ".md"
		}
	}
	return name
}

// partialFeeder returns template string for the name from `TemplateBox`.
// It should be registered as helper named `partialFeeder` so plush can
// find it with the name.
func (s templateRenderer) partialFeeder(name string) (string, error) {
	ct := strings.ToLower(s.contentType)

	d, f := filepath.Split(name)
	name = filepath.Join(d, "_"+f)
	name = fixExtension(name, ct)

	b, err := s.resolve(name)
	return string(b), err
}

func (s templateRenderer) exec(name string, data Data) (template.HTML, error) {
	ct := strings.ToLower(s.contentType)
	data["contentType"] = ct

	name = fixExtension(name, ct)

	// Try to use localized version
	templateName := s.localizedName(name, data)

	// Set current_template to context
	if _, ok := data["current_template"]; !ok {
		data["current_template"] = templateName
	}

	source, err := s.resolve(templateName)
	if err != nil {
		return "", err
	}

	helpers := map[string]interface{}{}

	for k, v := range s.Helpers {
		helpers[k] = v
	}

	// Allows to specify custom partialFeeder
	if helpers["partialFeeder"] == nil {
		helpers["partialFeeder"] = s.partialFeeder
	}

	helpers = s.addAssetsHelpers(helpers)

	body := string(source)
	for _, ext := range s.exts(name) {
		te, ok := s.TemplateEngines[ext]
		if !ok {
			logrus.Errorf("could not find a template engine for %s", ext)
			continue
		}
		body, err = te(body, data, helpers)
		if err != nil {
			return "", err
		}
	}

	return template.HTML(body), nil
}

func (s templateRenderer) localizedName(name string, data Data) string {
	templateName := name

	languages, ok := data["languages"].([]string)
	if !ok || len(languages) == 0 {
		return templateName
	}

	ll := len(languages)
	// Default language is the last in the list
	defaultLanguage := languages[ll-1]
	ext := filepath.Ext(name)
	rawName := strings.TrimSuffix(name, ext)

	for _, l := range languages {
		var candidateName string
		if l == defaultLanguage {
			break
		}

		candidateName = rawName + "." + strings.ToLower(l) + ext
		if _, err := s.resolve(candidateName); err == nil {
			// Replace name with the existing suffixed version
			templateName = candidateName
			break
		}
	}

	return templateName
}

func (s templateRenderer) exts(name string) []string {
	exts := []string{}
	for {
		ext := filepath.Ext(name)
		if ext == "" {
			break
		}
		name = strings.TrimSuffix(name, ext)
		exts = append(exts, strings.ToLower(ext[1:]))
	}
	if len(exts) == 0 {
		return []string{"html"}
	}
	sort.Sort(sort.Reverse(sort.StringSlice(exts)))
	return exts
}

func (s templateRenderer) assetPath(file string) (string, error) {

	if len(assetMap.Keys()) == 0 || os.Getenv("GO_ENV") != "production" {
		manifest, err := s.AssetsBox.FindString("manifest.json")

		if err != nil {
			manifest, err = s.AssetsBox.FindString("assets/manifest.json")
			if err != nil {
				return assetPathFor(file), nil
			}
		}

		err = loadManifest(manifest)
		if err != nil {
			return assetPathFor(file), fmt.Errorf("your manifest.json is not correct: %s", err)
		}
	}

	return assetPathFor(file), nil
}

// Template renders the named files using the specified
// content type and the github.com/gobuffalo/plush
// package for templating. If more than 1 file is provided
// the second file will be considered a "layout" file
// and the first file will be the "content" file which will
// be placed into the "layout" using "{{yield}}".
func Template(c string, names ...string) Renderer {
	e := New(Options{})
	return e.Template(c, names...)
}

// Template renders the named files using the specified
// content type and the github.com/gobuffalo/plush
// package for templating. If more than 1 file is provided
// the second file will be considered a "layout" file
// and the first file will be the "content" file which will
// be placed into the "layout" using "{{yield}}".
func (e *Engine) Template(c string, names ...string) Renderer {
	return &templateRenderer{
		Engine:      e,
		contentType: c,
		names:       names,
		aliases:     syncx.StringMap{},
	}
}
<|endoftext|>


<commit_before>package renderer

import (
	"fmt"
	"math/rand"
	"sync"

	"github.com/achilleasa/polaris/asset/scene"
	"github.com/achilleasa/polaris/tracer"
	"github.com/achilleasa/polaris/tracer/opencl"
	"github.com/achilleasa/polaris/types"
	"github.com/go-gl/gl/v2.1/gl"
	"github.com/go-gl/glfw/v3.1/glfw"
)

const (
	// Coefficients for converting delta cursor movements to yaw/pitch camera angles.
	mouseSensitivityX float32 = 0.005
	mouseSensitivityY float32 = 0.005

	// Camera movement speed
	cameraMoveSpeed float32 = 0.05

	// Height in pixels for stacked series widgets
	stackedSeriesHeight uint32 = 20
)

const (
	leftMouseButton  = 0
	rightMouseButton = 1
)

// An interactive opengl-based renderer.
type interactiveGLRenderer struct {
	*defaultRenderer

	accumulatedSamples uint32

	// opengl handles
	window *glfw.Window
	texFbo uint32

	// state
	lastCursorPos types.Vec2
	mousePressed  [2]bool
	camera        *scene.Camera

	// mutex for synchronizing updates
	sync.Mutex

	// Display options
	showUI                bool
	blockAssignmentSeries *stackedSeries
}

// Create a new interactive opengl renderer using the specified block scheduler and tracing pipeline.
func NewInteractive(sc *scene.Scene, scheduler tracer.BlockScheduler, pipeline *opencl.Pipeline, opts Options) (Renderer, error) {
	// Add an extra pipeline step to copy framebuffer data to an opengl texture
	pipeline.PostProcess = append(pipeline.PostProcess, opencl.CopyFrameBufferToOpenGLTexture())

	base, err := NewDefault(sc, scheduler, pipeline, opts)
	if err != nil {
		return nil, err
	}

	r := &interactiveGLRenderer{
		defaultRenderer: base.(*defaultRenderer),
		camera:          sc.Camera,
	}

	err = r.initGL(opts)
	if err != nil {
		r.Close()
		return nil, err
	}

	err = r.initUI()
	if err != nil {
		r.Close()
		return nil, err
	}

	return r, nil
}

func (r *interactiveGLRenderer) Close() {
	if r.window != nil {
		r.window.SetShouldClose(true)
	}
	if r != nil {
		r.defaultRenderer.Close()
	}
}

func (r *interactiveGLRenderer) initGL(opts Options) error {
	var err error
	if err = glfw.Init(); err != nil {
		return fmt.Errorf("failed to initialize glfw: %s", err.Error())
	}

	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 2)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)
	r.window, err = glfw.CreateWindow(int(opts.FrameW), int(opts.FrameH), "polaris", nil, nil)
	if err != nil {
		return fmt.Errorf("could not create opengl window: %s", err.Error())
	}
	r.window.MakeContextCurrent()

	if err = gl.Init(); err != nil {
		return fmt.Errorf("could not init opengl: %s", err.Error())
	}

	// Setup texture for image data
	var fbTexture uint32
	gl.GenTextures(1, &fbTexture)
	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, fbTexture)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(opts.FrameW), int32(opts.FrameH), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)

	// Attach texture to FBO
	gl.GenFramebuffers(1, &r.texFbo)
	gl.BindFramebuffer(gl.READ_FRAMEBUFFER, r.texFbo)
	gl.FramebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbTexture, 0)
	gl.BindFramebuffer(gl.READ_FRAMEBUFFER, 0)

	// Bind event callbacks
	r.window.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
	r.window.SetKeyCallback(r.onKeyEvent)
	r.window.SetMouseButtonCallback(r.onMouseEvent)
	r.window.SetCursorPosCallback(r.onCursorPosEvent)

	return nil
}

func (r *interactiveGLRenderer) Render() error {
	for !r.window.ShouldClose() {
		glfw.PollEvents()

		// Render next frame
		r.Lock()

		// Render frame unless we have reached our target SPP
		if r.options.SamplesPerPixel == 0 || (r.options.SamplesPerPixel != 0 && r.accumulatedSamples < r.defaultRenderer.options.SamplesPerPixel) {
			err := r.renderFrame(r.accumulatedSamples)
			if err != nil {
				r.Unlock()
				return err
			}
		}

		// Copy texture data to framebuffer
		gl.BindFramebuffer(gl.READ_FRAMEBUFFER, r.texFbo)
		gl.BlitFramebuffer(0, 0, int32(r.options.FrameW), int32(r.options.FrameH), 0, 0, int32(r.options.FrameW), int32(r.options.FrameH), gl.COLOR_BUFFER_BIT, gl.LINEAR)
		gl.BindFramebuffer(gl.READ_FRAMEBUFFER, 0)

		// Display tracer stats
		if r.showUI {
			r.renderUI()
		}

		r.window.SwapBuffers()
		r.Unlock()
	}
	return nil
}

func (r *interactiveGLRenderer) initUI() error {
	// Setup ortho projection for UI bits
	gl.Disable(gl.DEPTH_TEST)
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.Ortho(0, float64(r.options.FrameW), float64(r.options.FrameH), 0, -1, 1)
	gl.Viewport(0, 0, int32(r.options.FrameW), int32(r.options.FrameH))
	gl.MatrixMode(gl.MODELVIEW)
	gl.LoadIdentity()

	// Setup series
	r.blockAssignmentSeries = makeStackedSeries(len(r.tracers), int(r.options.FrameW))

	return nil
}

func (r *interactiveGLRenderer) onBeforeShowUI() {
	r.blockAssignmentSeries.Clear()
}

func (r *interactiveGLRenderer) renderUI() {
	var y int32 = 1
	var frameW int32 = int32(r.options.FrameW) - 1
	gl.LineWidth(2.0)
	for seriesIndex, blockH := range r.blockAssignments {
		gl.Color3fv(&r.blockAssignmentSeries.colors[seriesIndex][0])
		gl.Begin(gl.LINE_LOOP)
		gl.Vertex2i(0, y)
		gl.Vertex2i(frameW, y)
		gl.Vertex2i(frameW, y+int32(blockH))
		gl.Vertex2i(0, y+int32(blockH))
		gl.End()

		y += int32(blockH)
	}

	for seriesIndex, blockH := range r.blockAssignments {
		r.blockAssignmentSeries.Append(seriesIndex, float32(blockH))
	}
	r.blockAssignmentSeries.Render(r.options.FrameH-stackedSeriesHeight, stackedSeriesHeight)
}

func (r *interactiveGLRenderer) onKeyEvent(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if action != glfw.Press && action != glfw.Repeat {
		return
	}

	var moveDir scene.CameraDirection
	switch key {
	case glfw.KeyEscape:
		r.window.SetShouldClose(true)
	case glfw.KeyUp:
		moveDir = scene.Forward
	case glfw.KeyDown:
		moveDir = scene.Backward
	case glfw.KeyLeft:
		moveDir = scene.Left
	case glfw.KeyRight:
		moveDir = scene.Right
	case glfw.KeyTab:
		r.showUI = !r.showUI
		if r.showUI {
			r.onBeforeShowUI()
		}
		return
	default:
		return

	}

	// Double speed if shift is pressed
	var speedScaler float32 = 1.0
	if (mods & glfw.ModShift) == glfw.ModShift {
		speedScaler = 2.0
	}
	r.camera.Move(moveDir, speedScaler*cameraMoveSpeed)
	r.updateCamera()
}

func (r *interactiveGLRenderer) onMouseEvent(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
	if button != glfw.MouseButtonLeft && button != glfw.MouseButtonRight {
		return
	}

	r.mousePressed[leftMouseButton] = false
	r.mousePressed[rightMouseButton] = false

	if action == glfw.Press {
		xPos, yPos := w.GetCursorPos()
		r.lastCursorPos[0], r.lastCursorPos[1] = float32(xPos), float32(yPos)

		buttonIndex := leftMouseButton
		if button == glfw.MouseButtonRight {
			buttonIndex = rightMouseButton
		}

		r.mousePressed[buttonIndex] = true
	}
}

func (r *interactiveGLRenderer) onCursorPosEvent(w *glfw.Window, xPos, yPos float64) {
	if !r.mousePressed[leftMouseButton] && !r.mousePressed[rightMouseButton] {
		return
	}

	// Calculate delta movement and apply mouse sensitivity
	newPos := types.Vec2{float32(xPos), float32(yPos)}
	delta := r.lastCursorPos.Sub(newPos)
	delta[0] *= mouseSensitivityX
	delta[1] *= mouseSensitivityY
	r.lastCursorPos = newPos

	if r.mousePressed[leftMouseButton] {
		// The left mouse button rotates lookat around eye
		r.camera.Pitch = delta[1]
		r.camera.Yaw = delta[0]
		r.camera.Update()
		r.updateCamera()
	}
}

func (r *interactiveGLRenderer) updateCamera() {
	r.Lock()
	defer r.Unlock()

	for _, tr := range r.tracers {
		tr.UpdateState(tracer.Asynchronous, tracer.CameraData, r.camera)
	}

	r.accumulatedSamples = 0
}

type stackedSeries struct {
	series [][]float32
	colors []types.Vec3
}

func makeStackedSeries(numSeries, histCount int) *stackedSeries {
	s := &stackedSeries{
		series: make([][]float32, numSeries),
		colors: make([]types.Vec3, numSeries),
	}

	for sIndex := 0; sIndex < numSeries; sIndex++ {
		s.series[sIndex] = make([]float32, histCount)
		s.colors[sIndex] = types.Vec3{rand.Float32(), rand.Float32(), 1.0}
	}

	return s
}

// Clear series
func (s *stackedSeries) Clear() {
	histCount := len(s.series[0])
	for sIndex := 0; sIndex < len(s.series); sIndex++ {
		s.series[sIndex] = make([]float32, histCount)
	}
}

// Shift series values and append new value at the end.
func (s *stackedSeries) Append(seriesIndex int, val float32) {
	s.series[seriesIndex] = append(s.series[seriesIndex][1:], val)
}

func (s *stackedSeries) Render(rY, rHeight uint32) {
	gl.Begin(gl.LINES)
	for x := 0; x < len(s.series[0]); x++ {
		var sum float32 = 0
		var scale float32 = 1.0
		for seriesIndex := 0; seriesIndex < len(s.series); seriesIndex++ {
			sum += s.series[seriesIndex][x]
		}
		if sum > 0.0 {
			scale = float32(rHeight) / sum
		}

		var y float32 = float32(rY)
		gl.LineWidth(1.0)
		for seriesIndex := 0; seriesIndex < len(s.series); seriesIndex++ {
			sH := s.series[seriesIndex][x] * scale
			gl.Color3fv(&s.colors[seriesIndex][0])
			gl.Vertex2f(float32(x), y)
			gl.Vertex2f(float32(x), y+sH)
			y += sH
		}

	}
	gl.End()
}
<commit_msg>Fix interactive rendering accumulator bug introduced by previous commit<commit_after>package renderer

import (
	"fmt"
	"math/rand"
	"sync"

	"github.com/achilleasa/polaris/asset/scene"
	"github.com/achilleasa/polaris/tracer"
	"github.com/achilleasa/polaris/tracer/opencl"
	"github.com/achilleasa/polaris/types"
	"github.com/go-gl/gl/v2.1/gl"
	"github.com/go-gl/glfw/v3.1/glfw"
)

const (
	// Coefficients for converting delta cursor movements to yaw/pitch camera angles.
	mouseSensitivityX float32 = 0.005
	mouseSensitivityY float32 = 0.005

	// Camera movement speed
	cameraMoveSpeed float32 = 0.05

	// Height in pixels for stacked series widgets
	stackedSeriesHeight uint32 = 20
)

const (
	leftMouseButton  = 0
	rightMouseButton = 1
)

// An interactive opengl-based renderer.
type interactiveGLRenderer struct {
	*defaultRenderer

	accumulatedSamples uint32

	// opengl handles
	window *glfw.Window
	texFbo uint32

	// state
	lastCursorPos types.Vec2
	mousePressed  [2]bool
	camera        *scene.Camera

	// mutex for synchronizing updates
	sync.Mutex

	// Display options
	showUI                bool
	blockAssignmentSeries *stackedSeries
}

// Create a new interactive opengl renderer using the specified block scheduler and tracing pipeline.
func NewInteractive(sc *scene.Scene, scheduler tracer.BlockScheduler, pipeline *opencl.Pipeline, opts Options) (Renderer, error) {
	// Add an extra pipeline step to copy framebuffer data to an opengl texture
	pipeline.PostProcess = append(pipeline.PostProcess, opencl.CopyFrameBufferToOpenGLTexture())

	base, err := NewDefault(sc, scheduler, pipeline, opts)
	if err != nil {
		return nil, err
	}

	r := &interactiveGLRenderer{
		defaultRenderer: base.(*defaultRenderer),
		camera:          sc.Camera,
	}

	err = r.initGL(opts)
	if err != nil {
		r.Close()
		return nil, err
	}

	err = r.initUI()
	if err != nil {
		r.Close()
		return nil, err
	}

	return r, nil
}

func (r *interactiveGLRenderer) Close() {
	if r.window != nil {
		r.window.SetShouldClose(true)
	}
	if r != nil {
		r.defaultRenderer.Close()
	}
}

func (r *interactiveGLRenderer) initGL(opts Options) error {
	var err error
	if err = glfw.Init(); err != nil {
		return fmt.Errorf("failed to initialize glfw: %s", err.Error())
	}

	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 2)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)
	r.window, err = glfw.CreateWindow(int(opts.FrameW), int(opts.FrameH), "polaris", nil, nil)
	if err != nil {
		return fmt.Errorf("could not create opengl window: %s", err.Error())
	}
	r.window.MakeContextCurrent()

	if err = gl.Init(); err != nil {
		return fmt.Errorf("could not init opengl: %s", err.Error())
	}

	// Setup texture for image data
	var fbTexture uint32
	gl.GenTextures(1, &fbTexture)
	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, fbTexture)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(opts.FrameW), int32(opts.FrameH), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)

	// Attach texture to FBO
	gl.GenFramebuffers(1, &r.texFbo)
	gl.BindFramebuffer(gl.READ_FRAMEBUFFER, r.texFbo)
	gl.FramebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbTexture, 0)
	gl.BindFramebuffer(gl.READ_FRAMEBUFFER, 0)

	// Bind event callbacks
	r.window.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
	r.window.SetKeyCallback(r.onKeyEvent)
	r.window.SetMouseButtonCallback(r.onMouseEvent)
	r.window.SetCursorPosCallback(r.onCursorPosEvent)

	return nil
}

func (r *interactiveGLRenderer) Render() error {
	for !r.window.ShouldClose() {
		glfw.PollEvents()

		// Render next frame
		r.Lock()

		// Render frame unless we have reached our target SPP
		if r.options.SamplesPerPixel == 0 || (r.options.SamplesPerPixel != 0 && r.accumulatedSamples < r.defaultRenderer.options.SamplesPerPixel) {
			err := r.renderFrame(r.accumulatedSamples)
			if r.options.SamplesPerPixel == 0 {
				r.accumulatedSamples++
			} else {
				r.accumulatedSamples += r.options.SamplesPerPixel
			}
			if err != nil {
				r.Unlock()
				return err
			}
		}

		// Copy texture data to framebuffer
		gl.BindFramebuffer(gl.READ_FRAMEBUFFER, r.texFbo)
		gl.BlitFramebuffer(0, 0, int32(r.options.FrameW), int32(r.options.FrameH), 0, 0, int32(r.options.FrameW), int32(r.options.FrameH), gl.COLOR_BUFFER_BIT, gl.LINEAR)
		gl.BindFramebuffer(gl.READ_FRAMEBUFFER, 0)

		// Display tracer stats
		if r.showUI {
			r.renderUI()
		}

		r.window.SwapBuffers()
		r.Unlock()
	}
	return nil
}

func (r *interactiveGLRenderer) initUI() error {
	// Setup ortho projection for UI bits
	gl.Disable(gl.DEPTH_TEST)
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.Ortho(0, float64(r.options.FrameW), float64(r.options.FrameH), 0, -1, 1)
	gl.Viewport(0, 0, int32(r.options.FrameW), int32(r.options.FrameH))
	gl.MatrixMode(gl.MODELVIEW)
	gl.LoadIdentity()

	// Setup series
	r.blockAssignmentSeries = makeStackedSeries(len(r.tracers), int(r.options.FrameW))

	return nil
}

func (r *interactiveGLRenderer) onBeforeShowUI() {
	r.blockAssignmentSeries.Clear()
}

func (r *interactiveGLRenderer) renderUI() {
	var y int32 = 1
	var frameW int32 = int32(r.options.FrameW) - 1
	gl.LineWidth(2.0)
	for seriesIndex, blockH := range r.blockAssignments {
		gl.Color3fv(&r.blockAssignmentSeries.colors[seriesIndex][0])
		gl.Begin(gl.LINE_LOOP)
		gl.Vertex2i(0, y)
		gl.Vertex2i(frameW, y)
		gl.Vertex2i(frameW, y+int32(blockH))
		gl.Vertex2i(0, y+int32(blockH))
		gl.End()

		y += int32(blockH)
	}

	for seriesIndex, blockH := range r.blockAssignments {
		r.blockAssignmentSeries.Append(seriesIndex, float32(blockH))
	}
	r.blockAssignmentSeries.Render(r.options.FrameH-stackedSeriesHeight, stackedSeriesHeight)
}

func (r *interactiveGLRenderer) onKeyEvent(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if action != glfw.Press && action != glfw.Repeat {
		return
	}

	var moveDir scene.CameraDirection
	switch key {
	case glfw.KeyEscape:
		r.window.SetShouldClose(true)
	case glfw.KeyUp:
		moveDir = scene.Forward
	case glfw.KeyDown:
		moveDir = scene.Backward
	case glfw.KeyLeft:
		moveDir = scene.Left
	case glfw.KeyRight:
		moveDir = scene.Right
	case glfw.KeyTab:
		r.showUI = !r.showUI
		if r.showUI {
			r.onBeforeShowUI()
		}
		return
	default:
		return

	}

	// Double speed if shift is pressed
	var speedScaler float32 = 1.0
	if (mods & glfw.ModShift) == glfw.ModShift {
		speedScaler = 2.0
	}
	r.camera.Move(moveDir, speedScaler*cameraMoveSpeed)
	r.updateCamera()
}

func (r *interactiveGLRenderer) onMouseEvent(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
	if button != glfw.MouseButtonLeft && button != glfw.MouseButtonRight {
		return
	}

	r.mousePressed[leftMouseButton] = false
	r.mousePressed[rightMouseButton] = false

	if action == glfw.Press {
		xPos, yPos := w.GetCursorPos()
		r.lastCursorPos[0], r.lastCursorPos[1] = float32(xPos), float32(yPos)

		buttonIndex := leftMouseButton
		if button == glfw.MouseButtonRight {
			buttonIndex = rightMouseButton
		}

		r.mousePressed[buttonIndex] = true
	}
}

func (r *interactiveGLRenderer) onCursorPosEvent(w *glfw.Window, xPos, yPos float64) {
	if !r.mousePressed[leftMouseButton] && !r.mousePressed[rightMouseButton] {
		return
	}

	// Calculate delta movement and apply mouse sensitivity
	newPos := types.Vec2{float32(xPos), float32(yPos)}
	delta := r.lastCursorPos.Sub(newPos)
	delta[0] *= mouseSensitivityX
	delta[1] *= mouseSensitivityY
	r.lastCursorPos = newPos

	if r.mousePressed[leftMouseButton] {
		// The left mouse button rotates lookat around eye
		r.camera.Pitch = delta[1]
		r.camera.Yaw = delta[0]
		r.camera.Update()
		r.updateCamera()
	}
}

func (r *interactiveGLRenderer) updateCamera() {
	r.Lock()
	defer r.Unlock()

	for _, tr := range r.tracers {
		tr.UpdateState(tracer.Asynchronous, tracer.CameraData, r.camera)
	}

	r.accumulatedSamples = 0
}

type stackedSeries struct {
	series [][]float32
	colors []types.Vec3
}

func makeStackedSeries(numSeries, histCount int) *stackedSeries {
	s := &stackedSeries{
		series: make([][]float32, numSeries),
		colors: make([]types.Vec3, numSeries),
	}

	for sIndex := 0; sIndex < numSeries; sIndex++ {
		s.series[sIndex] = make([]float32, histCount)
		s.colors[sIndex] = types.Vec3{rand.Float32(), rand.Float32(), 1.0}
	}

	return s
}

// Clear series
func (s *stackedSeries) Clear() {
	histCount := len(s.series[0])
	for sIndex := 0; sIndex < len(s.series); sIndex++ {
		s.series[sIndex] = make([]float32, histCount)
	}
}

// Shift series values and append new value at the end.
func (s *stackedSeries) Append(seriesIndex int, val float32) {
	s.series[seriesIndex] = append(s.series[seriesIndex][1:], val)
}

func (s *stackedSeries) Render(rY, rHeight uint32) {
	gl.Begin(gl.LINES)
	for x := 0; x < len(s.series[0]); x++ {
		var sum float32 = 0
		var scale float32 = 1.0
		for seriesIndex := 0; seriesIndex < len(s.series); seriesIndex++ {
			sum += s.series[seriesIndex][x]
		}
		if sum > 0.0 {
			scale = float32(rHeight) / sum
		}

		var y float32 = float32(rY)
		gl.LineWidth(1.0)
		for seriesIndex := 0; seriesIndex < len(s.series); seriesIndex++ {
			sH := s.series[seriesIndex][x] * scale
			gl.Color3fv(&s.colors[seriesIndex][0])
			gl.Vertex2f(float32(x), y)
			gl.Vertex2f(float32(x), y+sH)
			y += sH
		}

	}
	gl.End()
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

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

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

package main

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

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

// This chaincode implements a simple map that is stored in the state.
// The following operations are available.

// Invoke operations
// put - requires two arguments, a key and value
// remove - requires a key

// Query operations
// get - requires one argument, a key, and returns a value
// keys - requires no arguments, returns all keys

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	return nil, nil
}

// Run callback representing the invocation of a chaincode
func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {

	switch function {

	case "put":
		if len(args) < 2 {
			return nil, errors.New("put operation must include two arguments, a key and value")
		}
		key := args[0]
		value := args[1]

		err := stub.PutState(key, []byte(value))
		if err != nil {
			fmt.Printf("Error putting state %s", err)
			return nil, fmt.Errorf("put operation failed. Error updating state: %s", err)
		}
		return nil, nil

	case "remove":
		if len(args) < 1 {
			return nil, errors.New("remove operation must include one argument, a key")
		}
		key := args[0]

		err := stub.DelState(key)
		if err != nil {
			return nil, fmt.Errorf("remove operation failed. Error updating state: %s", err)
		}
		return nil, nil

	default:
		return nil, errors.New("Unsupported operation")
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {

	switch function {

	case "get":
		if len(args) < 1 {
			return nil, errors.New("get operation must include one argument, a key")
		}
		key := args[0]
		value, err := stub.GetState(key)
		if err != nil {
			return nil, fmt.Errorf("get operation failed. Error accessing state: %s", err)
		}
		return value, nil

	case "keys":

		keysIter, err := stub.RangeQueryState("", "")
		if err != nil {
			return nil, fmt.Errorf("keys operation failed. Error accessing state: %s", err)
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			key, _, err := keysIter.Next()
			if err != nil {
				return nil, fmt.Errorf("keys operation failed. Error accessing state: %s", err)
			}
			keys = append(keys, key)
		}

		jsonKeys, err := json.Marshal(keys)
		if err != nil {
			return nil, fmt.Errorf("keys operation failed. Error marshaling JSON: %s", err)
		}

		return jsonKeys, nil

	default:
		return nil, errors.New("Unsupported operation")
	}
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting chaincode: %s", err)
	}
}
<commit_msg>revert map changes so prior PR with the same change can be accepted<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

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

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

package main

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

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

// This chaincode implements a simple map that is stored in the state.
// The following operations are available.

// Invoke operations
// put - requires two arguments, a key and value
// remove - requires a key

// Query operations
// get - requires one argument, a key, and returns a value
// keys - requires no arguments, returns all keys

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

// Run callback representing the invocation of a chaincode
func (t *SimpleChaincode) Run(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {

	switch function {

	case "init":
		// Do nothing

	case "put":
		if len(args) < 2 {
			return nil, errors.New("put operation must include two arguments, a key and value")
		}
		key := args[0]
		value := args[1]

		err := stub.PutState(key, []byte(value))
		if err != nil {
			fmt.Printf("Error putting state %s", err)
			return nil, fmt.Errorf("put operation failed. Error updating state: %s", err)
		}
		return nil, nil

	case "remove":
		if len(args) < 1 {
			return nil, errors.New("remove operation must include one argument, a key")
		}
		key := args[0]

		err := stub.DelState(key)
		if err != nil {
			return nil, fmt.Errorf("remove operation failed. Error updating state: %s", err)
		}
		return nil, nil

	default:
		return nil, errors.New("Unsupported operation")
	}

	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {

	switch function {

	case "get":
		if len(args) < 1 {
			return nil, errors.New("get operation must include one argument, a key")
		}
		key := args[0]
		value, err := stub.GetState(key)
		if err != nil {
			return nil, fmt.Errorf("get operation failed. Error accessing state: %s", err)
		}
		return value, nil

	case "keys":

		keysIter, err := stub.RangeQueryState("", "")
		if err != nil {
			return nil, fmt.Errorf("keys operation failed. Error accessing state: %s", err)
		}
		defer keysIter.Close()

		var keys []string
		for keysIter.HasNext() {
			key, _, err := keysIter.Next()
			if err != nil {
				return nil, fmt.Errorf("keys operation failed. Error accessing state: %s", err)
			}
			keys = append(keys, key)
		}

		jsonKeys, err := json.Marshal(keys)
		if err != nil {
			return nil, fmt.Errorf("keys operation failed. Error marshaling JSON: %s", err)
		}

		return jsonKeys, nil

	default:
		return nil, errors.New("Unsupported operation")
	}
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting chaincode: %s", err)
	}
}
<|endoftext|>


<commit_before>package agents

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/shirou/gopsutil/disk"

	"github.com/AstromechZA/spoon/conf"
	"github.com/AstromechZA/spoon/sink"
)

type diskAgent struct {
	config   conf.SpoonConfigAgent
	settings map[string]string
}

func NewDiskAgent(config *conf.SpoonConfigAgent) (Agent, error) {

	settings := make(map[string]string, 0)
	for k, v := range config.Settings {
		vs, ok := v.(string)
		if ok == false {
			return nil, fmt.Errorf("Error casting settings value %v to string", v)
		}
		settings[k] = vs
	}

	return &diskAgent{
		config:   (*config),
		settings: settings,
	}, nil
}

func (a *diskAgent) GetConfig() conf.SpoonConfigAgent {
	return a.config
}

func (a *diskAgent) Tick(s sink.Sink) error {

	devre := a.settings["device_regex"]

	// fetch all the physical disk partitions. the boolean indicates whether
	// non-physical partitions should be returned too.
	parts, err := disk.Partitions(false)
	if err == nil {
		// loop through all the partitions returned
		for _, p := range parts {

			// check against regex if provided
			if devre != "" {
				m, _ := regexp.MatchString(devre, p.Device)
				if m == false {
					log.Printf("Skipping usage for %v because it didn't match device_regex", p)
					continue
				}
			}

			usage, uerr := disk.Usage(p.Mountpoint)
			if uerr == nil {
				log.Printf("Outputting Usage for %v because it matched device_regex", p)
				prefixPath := fmt.Sprintf("%s.%s", a.config.Path, a.formatDeviceName(p.Device))

				s.Gauge(fmt.Sprintf("%s.total", prefixPath), float64(usage.Total))
				s.Gauge(fmt.Sprintf("%s.free", prefixPath), float64(usage.Free))
				s.Gauge(fmt.Sprintf("%s.used", prefixPath), float64(usage.Used))
				s.Gauge(fmt.Sprintf("%s.used_percent", prefixPath), float64(usage.UsedPercent))
				s.Gauge(fmt.Sprintf("%s.inode_free", prefixPath), float64(usage.InodesFree))
				s.Gauge(fmt.Sprintf("%s.inode_used", prefixPath), float64(usage.InodesUsed))
				s.Gauge(fmt.Sprintf("%s.inode_used_percent", prefixPath), float64(usage.InodesUsedPercent))

			} else {
				log.Printf("Fetching usage for disk %v failed: %v", p.Mountpoint, uerr.Error())
			}
		}
	} else {
		// just log this error, we can continue
		log.Printf("Fetching list of physical disk partitions failed: %v", err.Error())
	}

	iocounters, err := disk.IOCounters()
	if err == nil {

		for path, iostat := range iocounters {
			deviceName := "/dev/" + path

			// check against regex if provided
			if devre != "" {
				m, _ := regexp.MatchString(devre, deviceName)
				if m == false {
					continue
				}
			}

			log.Printf("Outputting IO Counters for %v because it matched device_regex", iostat)
			prefixPath := fmt.Sprintf("%s.%s", a.config.Path, a.formatDeviceName(deviceName))

			s.Gauge(fmt.Sprintf("%s.read_count", prefixPath), float64(iostat.ReadCount))
			s.Gauge(fmt.Sprintf("%s.write_count", prefixPath), float64(iostat.WriteCount))
			s.Gauge(fmt.Sprintf("%s.read_bytes", prefixPath), float64(iostat.ReadBytes))
			s.Gauge(fmt.Sprintf("%s.write_bytes", prefixPath), float64(iostat.WriteBytes))
			s.Gauge(fmt.Sprintf("%s.read_count", prefixPath), float64(iostat.ReadCount))
		}

	} else {
		log.Printf("Fetching iocounters for system failed: %v", err.Error())
	}
	return nil
}

func (a *diskAgent) formatDeviceName(device string) string {
	// first replace all forward slashes with -
	device = strings.Replace(device, "/", "_", -1)
	// then trim them off
	return strings.Trim(device, "_")
}
<commit_msg>tweak<commit_after>package agents

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/shirou/gopsutil/disk"

	"github.com/AstromechZA/spoon/conf"
	"github.com/AstromechZA/spoon/sink"
)

type diskAgent struct {
	config   conf.SpoonConfigAgent
	settings map[string]string
}

func NewDiskAgent(config *conf.SpoonConfigAgent) (Agent, error) {

	settings := make(map[string]string, 0)
	for k, v := range config.Settings {
		vs, ok := v.(string)
		if ok == false {
			return nil, fmt.Errorf("Error casting settings value %v to string", v)
		}
		settings[k] = vs
	}

	return &diskAgent{
		config:   (*config),
		settings: settings,
	}, nil
}

func (a *diskAgent) GetConfig() conf.SpoonConfigAgent {
	return a.config
}

func (a *diskAgent) Tick(s sink.Sink) error {

	devre := a.settings["device_regex"]

	// fetch all the physical disk partitions. the boolean indicates whether
	// non-physical partitions should be returned too.
	parts, err := disk.Partitions(false)
	if err == nil {
		// loop through all the partitions returned
		for _, p := range parts {

			// check against regex if provided
			if devre != "" {
				m, _ := regexp.MatchString(devre, p.Device)
				if m == false {
					log.Printf("Skipping usage for %v because it didn't match device_regex", p)
					continue
				}
			}

			usage, uerr := disk.Usage(p.Mountpoint)
			if uerr == nil {
				log.Printf("Outputting Usage for %v because it matched device_regex", p)
				prefixPath := fmt.Sprintf("%s.%s", a.config.Path, a.formatDeviceName(p.Device))

				s.Gauge(fmt.Sprintf("%s.total", prefixPath), float64(usage.Total))
				s.Gauge(fmt.Sprintf("%s.free", prefixPath), float64(usage.Free))
				s.Gauge(fmt.Sprintf("%s.used", prefixPath), float64(usage.Used))
				s.Gauge(fmt.Sprintf("%s.used_percent", prefixPath), float64(usage.UsedPercent))
				s.Gauge(fmt.Sprintf("%s.inode_free", prefixPath), float64(usage.InodesFree))
				s.Gauge(fmt.Sprintf("%s.inode_used", prefixPath), float64(usage.InodesUsed))
				s.Gauge(fmt.Sprintf("%s.inode_used_percent", prefixPath), float64(usage.InodesUsedPercent))

			} else {
				log.Printf("Fetching usage for disk %v failed: %v", p.Mountpoint, uerr.Error())
			}
		}
	} else {
		// just log this error, we can continue
		log.Printf("Fetching list of physical disk partitions failed: %v", err.Error())
	}

	iocounters, err := disk.IOCounters()
	if err == nil {

		for path, iostat := range iocounters {
			deviceName := "/dev/" + path

			// check against regex if provided
			if devre != "" {
				m, _ := regexp.MatchString(devre, deviceName)
				if m == false {
					continue
				}
			}

			log.Printf("Outputting IO Counters for %v because it matched device_regex", iostat)
			prefixPath := fmt.Sprintf("%s.%s", a.config.Path, a.formatDeviceName(deviceName))

			s.Gauge(fmt.Sprintf("%s.read_count", prefixPath), float64(iostat.ReadCount))
			s.Gauge(fmt.Sprintf("%s.write_count", prefixPath), float64(iostat.WriteCount))
			s.Gauge(fmt.Sprintf("%s.read_bytes", prefixPath), float64(iostat.ReadBytes))
			s.Gauge(fmt.Sprintf("%s.write_bytes", prefixPath), float64(iostat.WriteBytes))
			s.Gauge(fmt.Sprintf("%s.read_count", prefixPath), float64(iostat.ReadCount))
		}

	} else {
		log.Printf("Fetching iocounters for system failed: %v", err.Error())
	}

	return nil
}

func (a *diskAgent) formatDeviceName(device string) string {
	// first replace all forward slashes with -
	device = strings.Replace(device, "/", "_", -1)
	// then trim them off
	return strings.Trim(device, "_")
}
<|endoftext|>


<commit_before>// brightness provides a library for adjusting intel_backlight light levels.
//
// Set the SUID bit (allowing any user to run the script with root
// permissions, with associated risks) as follows:
// $ go build tools/dec_brightness.go
// # mv dec_brightness /usr/bin/inc_intel_backlight
// # chown root:root /usr/bin/inc_intel_backlight
// # chmod 4755 /usr/bin/inc_intel_backlight
package brightness

import (
	"io/ioutil"
	"log"
	"strconv"
	"strings"
)

var (
	brightness_path = "/sys/class/backlight/intel_backlight/brightness"
	max_path        = "/sys/class/backlight/intel_backlight/max_brightness"
	levels          = []int{
		1, 5, 8, 12, 18, 27, 40, 60, 90, 135, 202, 303, 454, 852,
	}
)

// getMax gets the maximum light value.
func getMax() (int, error) {
	bytes, err := ioutil.ReadFile(max_path)
	if err != nil {
		return -1, err
	}
	parts := strings.Split(string(bytes), "\n")
	// Remove trailing \n.
	max, err := strconv.Atoi(parts[0])
	if err != nil {
		return -1, err
	}
	log.Printf("Max brightness = %v\n", max)
	return max, nil
}

// Set sets brightness to value.
func Set(value int) error {
	max, err := getMax()
	if err != nil {
		return err
	}

	if value > max {
		log.Println("Value > max value (%v > %v); using %v instead\n", value, max, max)
		value = max
	}
	if value < 0 {
		log.Println("Value < min value (%v < 0); using 0 instead\n", value)
		value = 0
	}

	new_string := strconv.FormatInt(int64(value), 10) + "\n"
	out_bytes := []byte(new_string)

	err = ioutil.WriteFile(brightness_path, out_bytes, 0600)
	if err != nil {
		return err
	}
	log.Printf("Wrote %v to %v.\n", value, brightness_path)
	return nil
}

// Inc increases the light level to the nearest higher bucket.
func Inc() error {
	log.Printf("Inc()\n")
	current, err := Get()
	if err != nil {
		return err
	}
	for _, v := range levels {
		if v > current {
			log.Printf("Next highest value is %d; setting it\n", v)
			return Set(v)
		}
	}
	highest := levels[len(levels)-1]
	log.Printf("No higher bucket, resetting to highest value %d\n", highest)
	return Set(highest)
}

// Dec decreases the light level to the nearest lower bucket.
func Dec() error {
	log.Printf("Dec()\n")
	current, err := Get()
	if err != nil {
		return err
	}
	for i, v := range levels {
		if v >= current {
			if i == 0 {
				log.Printf("First value is higher/equal to than current; resetting to %d\n", v, levels[0])
				return Set(levels[0])
			} else {
				log.Printf("First value lower than current is %d; setting it\n", levels[i-1])
				return Set(levels[i-1])
			}
		}
	}
	value := levels[len(levels)-2]
	log.Printf("No higher bucket, resetting to next highest value %d\n", value)
	return Set(value)

}

// Get retrieves the current light level.
func Get() (int, error) {
	log.Printf("Get()\n")
	bytes, err := ioutil.ReadFile(brightness_path)
	if err != nil {
		return -1, err
	}

	// Remove trailing \n.
	parts := strings.Split(string(bytes), "\n")
	current, err := strconv.Atoi(parts[0])
	if err != nil {
		return -1, err
	}
	log.Printf("Current brightness = %v\n", current)
	return current, nil
}

// Adjust adjusts the brightness by delta.
func Adjust(delta int) error {
	log.Printf("Set(%v)\n", delta)
	current, err := Get()
	if err != nil {
		return err
	}
	return Set(int(current + delta))
}
<commit_msg>tweaks brightness values<commit_after>// brightness provides a library for adjusting intel_backlight light levels.
//
// Set the SUID bit (allowing any user to run the script with root
// permissions, with associated risks) as follows:
// $ go build tools/dec_brightness.go
// # mv dec_brightness /usr/bin/inc_intel_backlight
// # chown root:root /usr/bin/inc_intel_backlight
// # chmod 4755 /usr/bin/inc_intel_backlight
package brightness

import (
	"io/ioutil"
	"log"
	"strconv"
	"strings"
)

var (
	brightness_path = "/sys/class/backlight/intel_backlight/brightness"
	max_path        = "/sys/class/backlight/intel_backlight/max_brightness"
	levels          = []int{
		1, 3, 5, 8, 12, 18, 27, 40, 60, 90, 135, 202, 303, 454, 852,
	}
)

// getMax gets the maximum light value.
func getMax() (int, error) {
	bytes, err := ioutil.ReadFile(max_path)
	if err != nil {
		return -1, err
	}
	parts := strings.Split(string(bytes), "\n")
	// Remove trailing \n.
	max, err := strconv.Atoi(parts[0])
	if err != nil {
		return -1, err
	}
	log.Printf("Max brightness = %v\n", max)
	return max, nil
}

// Set sets brightness to value.
func Set(value int) error {
	max, err := getMax()
	if err != nil {
		return err
	}

	if value > max {
		log.Println("Value > max value (%v > %v); using %v instead\n", value, max, max)
		value = max
	}
	if value < 0 {
		log.Println("Value < min value (%v < 0); using 0 instead\n", value)
		value = 0
	}

	new_string := strconv.FormatInt(int64(value), 10) + "\n"
	out_bytes := []byte(new_string)

	err = ioutil.WriteFile(brightness_path, out_bytes, 0600)
	if err != nil {
		return err
	}
	log.Printf("Wrote %v to %v.\n", value, brightness_path)
	return nil
}

// Inc increases the light level to the nearest higher bucket.
func Inc() error {
	log.Printf("Inc()\n")
	current, err := Get()
	if err != nil {
		return err
	}
	for _, v := range levels {
		if v > current {
			log.Printf("Next highest value is %d; setting it\n", v)
			return Set(v)
		}
	}
	highest := levels[len(levels)-1]
	log.Printf("No higher bucket, resetting to highest value %d\n", highest)
	return Set(highest)
}

// Dec decreases the light level to the nearest lower bucket.
func Dec() error {
	log.Printf("Dec()\n")
	current, err := Get()
	if err != nil {
		return err
	}
	for i, v := range levels {
		if v >= current {
			if i == 0 {
				log.Printf("First value is higher/equal to than current; resetting to %d\n", v, levels[0])
				return Set(levels[0])
			} else {
				log.Printf("First value lower than current is %d; setting it\n", levels[i-1])
				return Set(levels[i-1])
			}
		}
	}
	value := levels[len(levels)-2]
	log.Printf("No higher bucket, resetting to next highest value %d\n", value)
	return Set(value)

}

// Get retrieves the current light level.
func Get() (int, error) {
	log.Printf("Get()\n")
	bytes, err := ioutil.ReadFile(brightness_path)
	if err != nil {
		return -1, err
	}

	// Remove trailing \n.
	parts := strings.Split(string(bytes), "\n")
	current, err := strconv.Atoi(parts[0])
	if err != nil {
		return -1, err
	}
	log.Printf("Current brightness = %v\n", current)
	return current, nil
}

// Adjust adjusts the brightness by delta.
func Adjust(delta int) error {
	log.Printf("Set(%v)\n", delta)
	current, err := Get()
	if err != nil {
		return err
	}
	return Set(int(current + delta))
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	restful "github.com/emicklei/go-restful"
	"github.com/emicklei/go-restful/swagger"
	"github.com/garyburd/redigo/redis"
	"github.com/the42/ogdat/database"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"
)

const AppID = "5bcbfc24-8e7e-4105-99c4-dd47e7e5094a"
const watcherappid = "a6545f8f-e0c9-4917-83c7-3e47bd1e0247"

var logger *log.Logger

type analyser struct {
	dbcon analyserdb
	pool  *redis.Pool
}

func NewAnalyser(dbcon *sql.DB, pool *redis.Pool) *analyser {
	analyser := &analyser{dbcon: analyserdb{DBConn: database.DBConn{Appid: AppID, DBer: dbcon}}, pool: pool}
	return analyser
}

func isonlyweb() bool {
	boolval, err := strconv.ParseBool(os.Getenv("ONLYWEB"))
	if err != nil {
		return false
	}
	return boolval
}

func getredisconnect() string {
	const redisurl = "REDISCLOUD_URL"
	const redisdb = "ANALYSER_REDISDB"

	return os.Getenv(redisurl) + "/" + os.Getenv(redisdb)
}

func portbinding() string {
	if port := os.Getenv("ANALYSER_PORT"); port != "" {
		return port
	}
	if port := os.Getenv("PORT"); port != "" {
		return port
	}
	return "8080"
}

func hostname() string {
	return "http://localhost" + ":" + portbinding()
}

func getheartbeatinterval() int {

	if i, err := strconv.Atoi(os.Getenv("HEARTBEAT_INTERVAL")); err == nil {
		return i
	}
	return 60 // Minutes
}

func heartbeat(interval int) chan bool {
	retchan := make(chan bool)
	go func() {
		for {
			dbconn, err := database.GetDatabaseConnection()
			if err != nil {
				logger.Panicln(err)
			}
			db := &database.DBConn{DBer: dbconn, Appid: AppID}
			if err := db.HeartBeat(); err != nil {
				logger.Panicln(err)
			}
			dbconn.Close()
			logger.Printf("Watchdog beating every %d minute\n", interval)
			retchan <- true
			time.Sleep(time.Duration(interval) * time.Minute)
		}
	}()
	return retchan
}

func main() {
	dbcon, err := database.GetDatabaseConnection()
	if err != nil {
		logger.Panicln(err)
	}
	defer dbcon.Close()
	analyser := NewAnalyser(dbcon, redis.NewPool(func() (redis.Conn, error) { return database.GetRedisConnection(getredisconnect()) }, 10))

	var datachange, urlchange chan []byte
	var heartbeatchannel chan bool

	if !isonlyweb() {
		heartbeatchannel = heartbeat(getheartbeatinterval())

		<-heartbeatchannel // Wait for the first heartbeat, so the logging in the database is properly set up
		if err := analyser.populatedatasetinfo(); err != nil {
			logger.Panicln(err)
		}
		datachange = analyser.listenredischannel(watcherappid + ":DataChange")
		urlchange = analyser.listenredischannel(watcherappid + ":UrlChange")
	}

	restful.DefaultResponseMimeType = restful.MIME_JSON
	restful.EnableContentEncoding = true
	restful.Add(NewAnalyseOGDATRESTService(analyser))

	config := swagger.Config{
		WebServicesUrl:  hostname(),
		ApiPath:         "/swaggerdoc",
		SwaggerPath:     "/doc/",
		SwaggerFilePath: "swagger-ui/dist/",
		WebServices:     restful.RegisteredWebServices()} // you control what services are visible
	swagger.InstallSwaggerService(config)

	logger.Printf("analyser (%s) listening on port %s\n", AppID, portbinding())
	go logger.Fatal(http.ListenAndServe(":"+portbinding(), nil))

	if !isonlyweb() {
		populatedatasetinfo := func() {
			if err := analyser.populatedatasetinfo(); err != nil {
				logger.Panicln(err)
			}
		}
		for {
			select {
			case <-urlchange:
				populatedatasetinfo()
			case <-datachange:
				populatedatasetinfo()
			case <-heartbeatchannel:
				logger.Println("Idle")
			}
		}
	}
}

func init() {
	logger = log.New(os.Stderr, filepath.Base(os.Args[0])+": ", log.LstdFlags)
}
<commit_msg>there is no need for this code any longer since the UI lives in its own repository<commit_after>package main

import (
	"database/sql"
	restful "github.com/emicklei/go-restful"
	"github.com/emicklei/go-restful/swagger"
	"github.com/garyburd/redigo/redis"
	"github.com/the42/ogdat/database"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"
)

const AppID = "5bcbfc24-8e7e-4105-99c4-dd47e7e5094a"
const watcherappid = "a6545f8f-e0c9-4917-83c7-3e47bd1e0247"

var logger *log.Logger

type analyser struct {
	dbcon analyserdb
	pool  *redis.Pool
}

func NewAnalyser(dbcon *sql.DB, pool *redis.Pool) *analyser {
	analyser := &analyser{dbcon: analyserdb{DBConn: database.DBConn{Appid: AppID, DBer: dbcon}}, pool: pool}
	return analyser
}

func isonlyweb() bool {
	boolval, err := strconv.ParseBool(os.Getenv("ONLYWEB"))
	if err != nil {
		return false
	}
	return boolval
}

func getredisconnect() string {
	const redisurl = "REDISCLOUD_URL"
	const redisdb = "ANALYSER_REDISDB"

	return os.Getenv(redisurl) + "/" + os.Getenv(redisdb)
}

func portbinding() string {
	if port := os.Getenv("PORT"); port != "" {
		return port
	}
	return "8080"
}

func hostname() string {
	return "http://localhost" + ":" + portbinding()
}

func getheartbeatinterval() int {

	if i, err := strconv.Atoi(os.Getenv("HEARTBEAT_INTERVAL")); err == nil {
		return i
	}
	return 60 // Minutes
}

func heartbeat(interval int) chan bool {
	retchan := make(chan bool)
	go func() {
		for {
			dbconn, err := database.GetDatabaseConnection()
			if err != nil {
				logger.Panicln(err)
			}
			db := &database.DBConn{DBer: dbconn, Appid: AppID}
			if err := db.HeartBeat(); err != nil {
				logger.Panicln(err)
			}
			dbconn.Close()
			logger.Printf("Watchdog beating every %d minute\n", interval)
			retchan <- true
			time.Sleep(time.Duration(interval) * time.Minute)
		}
	}()
	return retchan
}

func main() {
	dbcon, err := database.GetDatabaseConnection()
	if err != nil {
		logger.Panicln(err)
	}
	defer dbcon.Close()
	analyser := NewAnalyser(dbcon, redis.NewPool(func() (redis.Conn, error) { return database.GetRedisConnection(getredisconnect()) }, 10))

	var datachange, urlchange chan []byte
	var heartbeatchannel chan bool

	if !isonlyweb() {
		heartbeatchannel = heartbeat(getheartbeatinterval())

		<-heartbeatchannel // Wait for the first heartbeat, so the logging in the database is properly set up
		if err := analyser.populatedatasetinfo(); err != nil {
			logger.Panicln(err)
		}
		datachange = analyser.listenredischannel(watcherappid + ":DataChange")
		urlchange = analyser.listenredischannel(watcherappid + ":UrlChange")
	}

	restful.DefaultResponseMimeType = restful.MIME_JSON
	restful.EnableContentEncoding = true
	restful.Add(NewAnalyseOGDATRESTService(analyser))

	config := swagger.Config{
		WebServicesUrl:  hostname(),
		ApiPath:         "/swaggerdoc",
		SwaggerPath:     "/doc/",
		SwaggerFilePath: "swagger-ui/dist/",
		WebServices:     restful.RegisteredWebServices()} // you control what services are visible
	swagger.InstallSwaggerService(config)

	logger.Printf("analyser (%s) listening on port %s\n", AppID, portbinding())
	go logger.Fatal(http.ListenAndServe(":"+portbinding(), nil))

	if !isonlyweb() {
		populatedatasetinfo := func() {
			if err := analyser.populatedatasetinfo(); err != nil {
				logger.Panicln(err)
			}
		}
		for {
			select {
			case <-urlchange:
				populatedatasetinfo()
			case <-datachange:
				populatedatasetinfo()
			case <-heartbeatchannel:
				logger.Println("Idle")
			}
		}
	}
}

func init() {
	logger = log.New(os.Stderr, filepath.Base(os.Args[0])+": ", log.LstdFlags)
}
<|endoftext|>


<commit_before>/*
Utilities for common regexp patterns

Copyright 2014 Luca Chiricozzi. All rights reserved.
Released under the MIT License.
http://opensource.org/licenses/MIT
*/
package reutils

import "regexp"

// MatchName checks whether a string is a valid name.
func MatchName(s string) bool {
	exp := regexp.MustCompile("^[\\pL\\pN !?'.-]+$")
	return exp.MatchString(s)
}

// MatchEmail checks whether a string is a valid email.
func MatchEmail(s string) bool {
	exp := regexp.MustCompile("^[a-zA-Z0-9+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$")
	return exp.MatchString(s)
}
<commit_msg>Update reutils.go<commit_after>/*
Utilities for common regexp patterns

Copyright 2014 Luca Chiricozzi. All rights reserved.
Released under the MIT License.
http://opensource.org/licenses/MIT
*/
package reutils

import "regexp"

// MatchName checks whether a string is a valid name.
func MatchName(s string) bool {
	exp := regexp.MustCompile("^[\\pL\\pN-]+$")
	return exp.MatchString(s)
}

// MatchEmail checks whether a string is a valid email.
func MatchEmail(s string) bool {
	exp := regexp.MustCompile("^[a-zA-Z0-9+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$")
	return exp.MatchString(s)
}
<|endoftext|>


<commit_before>package riemann

import (
	"flag"
	"strconv"

	"github.com/readmill/metrics"
	"github.com/readmill/raidman"
)

var (
	HttpStatusAttr = "status"
	PersistAttr    = "persist"
)

type Riemann struct {
	addr   *string
	net    *string
	client *raidman.Client
}

func (r *Riemann) Publish(evs ...*metrics.Event) error {
	if r.client == nil {
		client, err := r.open()
		if err != nil {
			return err
		}
		r.client = client
	}

	for _, e := range evs {
		ev := &raidman.Event{
			State:      e.State,
			Service:    e.Service,
			Metric:     e.Metric,
			Ttl:        e.Ttl,
			Tags:       e.Tags,
			Attributes: e.Attributes,
		}
		if ev.Attributes == nil {
			ev.Attributes = map[string]interface{}{}
		}
		if e.HttpStatus != 0 {
			ev.Attributes[HttpStatusAttr] = strconv.Itoa(e.HttpStatus)
		}
		if !e.Transient {
			ev.Attributes[PersistAttr] = "true"
		}
		err := r.client.Send(ev)
		if err != nil {
			return err
		}
	}
	return nil
}

func (r *Riemann) open() (*raidman.Client, error) {
	return raidman.Dial(*r.net, *r.addr)
}

func init() {
	addr := flag.String("riemann.addr", ":5555", "riemann host address")
	netwrk := flag.String("riemann.net", "tcp", "riemann network protocol (tcp, udp)")
	metrics.Register("riemann", &Riemann{addr, netwrk, nil})
}
<commit_msg>Attempt to catch EOF<commit_after>package riemann

import (
	"flag"
	"strconv"

	"github.com/readmill/metrics"
	"github.com/readmill/raidman"
)

var (
	HttpStatusAttr = "status"
	PersistAttr    = "persist"
)

type Riemann struct {
	addr   *string
	net    *string
	client *raidman.Client
}

func (r *Riemann) Publish(evs ...*metrics.Event) error {
	if r.client == nil {
		client, err := r.open()
		if err != nil {
			return err
		}
		r.client = client
	}

	for _, e := range evs {
		ev := &raidman.Event{
			State:      e.State,
			Service:    e.Service,
			Metric:     e.Metric,
			Ttl:        e.Ttl,
			Tags:       e.Tags,
			Attributes: e.Attributes,
		}
		if ev.Attributes == nil {
			ev.Attributes = map[string]interface{}{}
		}
		if e.HttpStatus != 0 {
			ev.Attributes[HttpStatusAttr] = strconv.Itoa(e.HttpStatus)
		}
		if !e.Transient {
			ev.Attributes[PersistAttr] = "true"
		}
		err := r.client.Send(ev)
		if err != nil {
			if err == io.EOF {
				r.client = nil
			}
			return err
		}
	}
	return nil
}

func (r *Riemann) open() (*raidman.Client, error) {
	return raidman.Dial(*r.net, *r.addr)
}

func init() {
	addr := flag.String("riemann.addr", ":5555", "riemann host address")
	netwrk := flag.String("riemann.net", "tcp", "riemann network protocol (tcp, udp)")
	metrics.Register("riemann", &Riemann{addr, netwrk, nil})
}
<|endoftext|>


<commit_before>package git

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	ini "github.com/vaughan0/go-ini"
)

func PrepSubmodules(
	gitDir, checkoutDir, mainRev string,
) error {

	gitModules := filepath.Join(checkoutDir, ".gitmodules")

	submodules, err := ParseSubmodules(gitModules)
	if err != nil {
		if os.IsNotExist(err) {
			// No .gitmodules available.
			return nil
		}
		return err
	}

	log.Printf("Prep %v submodules", len(submodules))

	GetSubmoduleRevs(gitDir, mainRev, submodules)

	errs := make(chan error, len(submodules))

	go func() {
		defer close(errs)

		var wg sync.WaitGroup
		defer wg.Wait()

		// Run only NumCPU in parallel
		semaphore := make(chan struct{}, runtime.NumCPU())

		for _, submodule := range submodules {

			wg.Add(1)
			go func(submodule Submodule) {
				defer wg.Done()
				defer func() { <-semaphore }()
				semaphore <- struct{}{}

				err := prepSubmodule(gitDir, checkoutDir, submodule)
				if err != nil {
					err = fmt.Errorf("processing %v: %v", submodule.Path, err)
				}
				errs <- err
			}(submodule)
		}
	}()

	// errs chan has buffer length len(submodules)
	err = MultipleErrors(errs)
	if err != nil {
		return err
	}
	return nil
}

type ErrMultiple struct {
	errs []error
}

func (em *ErrMultiple) Error() string {
	var s []string
	for _, e := range em.errs {
		s = append(s, e.Error())
	}
	return fmt.Sprint("multiple errors:\n", strings.Join(s, "\n"))
}

// Read errors out of a channel, counting only the non-nil ones.
// If there are zero non-nil errs, nil is returned.
func MultipleErrors(errs <-chan error) error {
	var em ErrMultiple
	for e := range errs {
		if e == nil {
			continue
		}
		em.errs = append(em.errs, e)
	}
	if len(em.errs) == 0 {
		return nil
	}
	return &em
}

// Checkout the working directory of a given submodule.
func prepSubmodule(
	mainGitDir, mainCheckoutDir string,
	submodule Submodule,
) error {

	subGitDir := filepath.Join(mainGitDir, "modules", submodule.Path)

	err := LocalMirror(submodule.URL, subGitDir, submodule.Rev, os.Stderr)
	if err != nil {
		return err
	}

	subCheckoutPath := filepath.Join(mainCheckoutDir, submodule.Path)

	// Note: checkout may recurse onto prepSubmodules.
	err = recursiveCheckout(subGitDir, subCheckoutPath, submodule.Rev)
	if err != nil {
		return err
	}
	return err
}

type Submodule struct {
	Path, URL string
	Rev       string // populated by GetSubmoduleRevs
}

func ParseSubmodules(filename string) (submodules []Submodule, err error) {
	config, err := ini.LoadFile(filename)
	if err != nil {
		return nil, err
	}

	for section := range config {
		if !strings.HasPrefix(section, "submodule") {
			continue
		}
		submodules = append(submodules, Submodule{
			Path: config.Section(section)["path"],
			URL:  config.Section(section)["url"],
		})
	}
	return submodules, nil
}

func GetSubmoduleRevs(gitDir, mainRev string, submodules []Submodule) error {
	for i := range submodules {
		rev, err := GetSubmoduleRev(gitDir, submodules[i].Path, mainRev)
		if err != nil {
			return err
		}
		submodules[i].Rev = rev
	}
	return nil
}

func GetSubmoduleRev(gitDir, submodulePath, mainRev string) (string, error) {
	cmd := Command(gitDir, "git", "ls-tree", mainRev, "--", submodulePath)
	cmd.Stdout = nil

	parts, err := cmd.Output()
	if err != nil {
		return "", err
	}

	return strings.Fields(string(parts))[2], nil
}
<commit_msg>Clean up<commit_after>package git

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	ini "github.com/vaughan0/go-ini"
)

func PrepSubmodules(
	gitDir, checkoutDir, mainRev string,
) error {

	gitModules := filepath.Join(checkoutDir, ".gitmodules")

	submodules, err := ParseSubmodules(gitModules)
	if err != nil {
		if os.IsNotExist(err) {
			// No .gitmodules available.
			return nil
		}
		return err
	}

	log.Printf("Prep %v submodules", len(submodules))

	GetSubmoduleRevs(gitDir, mainRev, submodules)

	errs := make(chan error, len(submodules))

	go func() {
		defer close(errs)

		var wg sync.WaitGroup
		defer wg.Wait()

		// Run only NumCPU in parallel
		semaphore := make(chan struct{}, runtime.NumCPU())

		for _, submodule := range submodules {

			wg.Add(1)
			go func(submodule Submodule) {
				defer wg.Done()
				defer func() { <-semaphore }()
				semaphore <- struct{}{}

				err := prepSubmodule(gitDir, checkoutDir, submodule)
				if err != nil {
					err = fmt.Errorf("processing %v: %v", submodule.Path, err)
				}
				errs <- err
			}(submodule)
		}
	}()

	// errs chan has buffer length len(submodules)
	err = MultipleErrors(errs)
	if err != nil {
		return err
	}
	return nil
}

type ErrMultiple struct {
	errs []error
}

func (em *ErrMultiple) Error() string {
	var s []string
	for _, e := range em.errs {
		s = append(s, e.Error())
	}
	return fmt.Sprint("multiple errors:\n", strings.Join(s, "\n"))
}

// Read errors out of a channel, counting only the non-nil ones.
// If there are zero non-nil errs, nil is returned.
func MultipleErrors(errs <-chan error) error {
	var em ErrMultiple
	for e := range errs {
		if e == nil {
			continue
		}
		em.errs = append(em.errs, e)
	}
	if len(em.errs) == 0 {
		return nil
	}
	return &em
}

// Checkout the working directory of a given submodule.
func prepSubmodule(
	mainGitDir, mainCheckoutDir string,
	submodule Submodule,
) error {

	subGitDir := filepath.Join(mainGitDir, "modules", submodule.Path)

	err := LocalMirror(submodule.URL, subGitDir, submodule.Rev, os.Stderr)
	if err != nil {
		return err
	}

	subCheckoutPath := filepath.Join(mainCheckoutDir, submodule.Path)

	// Note: checkout may recurse onto prepSubmodules.
	err = recursiveCheckout(subGitDir, subCheckoutPath, submodule.Rev)
	if err != nil {
		return err
	}
	return err
}

type Submodule struct {
	Path, URL string
	Rev       string // populated by GetSubmoduleRevs
}

func ParseSubmodules(filename string) (submodules []Submodule, err error) {
	config, err := ini.LoadFile(filename)
	if err != nil {
		return nil, err
	}

	for section := range config {
		if !strings.HasPrefix(section, "submodule") {
			continue
		}
		submodules = append(submodules, Submodule{
			Path: config.Section(section)["path"],
			URL:  config.Section(section)["url"],
		})
	}
	return submodules, nil
}

func GetSubmoduleRevs(gitDir, mainRev string, submodules []Submodule) error {
	for i := range submodules {
		rev, err := GetSubmoduleRev(gitDir, submodules[i].Path, mainRev)
		if err != nil {
			return err
		}
		submodules[i].Rev = rev
	}
	return nil
}

func GetSubmoduleRev(gitDir, submodulePath, mainRev string) (string, error) {
	cmd := Command(gitDir, "git", "ls-tree", mainRev, "--", submodulePath)

	parts, err := cmd.Output()
	if err != nil {
		return "", err
	}

	return strings.Fields(string(parts))[2], nil
}
<|endoftext|>


<commit_before>package moviestore

import (
	"context"
	"os"
	"reflect"
	"testing"

	"github.com/gilcrest/go-api-basic/datastore"
	"github.com/gilcrest/go-api-basic/datastore/datastoretest"
	"github.com/gilcrest/go-api-basic/domain/logger"
	"github.com/gilcrest/go-api-basic/domain/movie"
	"github.com/google/uuid"
)

func TestNewDefaultTransactor(t *testing.T) {
	type args struct {
		ds datastore.Datastorer
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	db, cleanup, err := datastore.NewDB(dsn, lgr)
	defer cleanup()
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	defaultTransactor := DefaultTransactor{defaultDatastore}

	tests := []struct {
		name string
		args args
		want DefaultTransactor
	}{
		{"typical", args{ds: defaultDatastore}, defaultTransactor},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := NewDefaultTransactor(tt.args.ds); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("NewDefaultTransactor() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestDefaultTransactor_Create(t *testing.T) {
	type fields struct {
		datastorer datastore.Datastorer
	}
	type args struct {
		ctx context.Context
		m   *movie.Movie
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	// I am intentionally not using the cleanup function that is
	// returned from NewDB as I need the DB to stay open for the test
	// t.Cleanup function
	db, _, err := datastore.NewDB(dsn, lgr)
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	defaultTransactor := NewDefaultTransactor(defaultDatastore)
	ctx := context.Background()
	m := newMovie(t)
	t.Cleanup(func() {
		err := defaultTransactor.Delete(ctx, m)
		if err != nil {
			t.Fatalf("defaultTransactor.Delete error = %v", err)
		}
	})

	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		{"typical", fields{datastorer: defaultDatastore}, args{ctx, m}, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := DefaultTransactor{
				datastorer: tt.fields.datastorer,
			}
			if err := dt.Create(tt.args.ctx, tt.args.m); (err != nil) != tt.wantErr {
				t.Errorf("DefaultTransactor.Create() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestDefaultTransactor_Update(t *testing.T) {
	type fields struct {
		datastorer datastore.Datastorer
	}
	type args struct {
		ctx context.Context
		m   *movie.Movie
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	// I am intentionally not using the cleanup function that is
	// returned from NewDB as I need the DB to stay open for the test
	// t.Cleanup function
	db, _, err := datastore.NewDB(dsn, lgr)
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	// defaultTransactor := NewDefaultTransactor(defaultDatastore)
	ctx := context.Background()
	// create a movie with the helper to ensure that at least one row
	// is returned
	m := newMovieDBHelper(t, ctx, defaultDatastore, true)
	// The ID would not be set on an update, as only the external ID
	// is known to the client
	m.ID = uuid.Nil
	m.SetDirector("Alex Cox")

	m2 := &movie.Movie{}

	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		{"typical", fields{datastorer: defaultDatastore}, args{ctx, m}, false},
		{"no rows updated", fields{datastorer: defaultDatastore}, args{ctx, m2}, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := DefaultTransactor{
				datastorer: tt.fields.datastorer,
			}
			if err := dt.Update(tt.args.ctx, tt.args.m); (err != nil) != tt.wantErr {
				t.Errorf("DefaultTransactor.Update() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestDefaultTransactor_Delete(t *testing.T) {
	type fields struct {
		datastorer datastore.Datastorer
	}
	type args struct {
		ctx context.Context
		m   *movie.Movie
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	// I am intentionally not using the cleanup function that is
	// returned from NewDB as I need the DB to stay open for the test
	// t.Cleanup function
	db, _, err := datastore.NewDB(dsn, lgr)
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	// defaultTransactor := NewDefaultTransactor(defaultDatastore)
	ctx := context.Background()
	// create a movie with the helper to ensure that at least one row
	// is returned
	m := newMovieDBHelper(t, ctx, defaultDatastore, false)

	m2 := &movie.Movie{}

	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		{"typical", fields{datastorer: defaultDatastore}, args{ctx, m}, false},
		{"no rows deleted", fields{datastorer: defaultDatastore}, args{ctx, m2}, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := DefaultTransactor{
				datastorer: tt.fields.datastorer,
			}
			if err := dt.Delete(tt.args.ctx, tt.args.m); (err != nil) != tt.wantErr {
				t.Logf("%s yieled dt.Delete error = %v", tt.name, err)
				t.Errorf("DefaultTransactor.Delete() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}
<commit_msg>move ctx to first arg<commit_after>package moviestore

import (
	"context"
	"os"
	"reflect"
	"testing"

	"github.com/gilcrest/go-api-basic/datastore"
	"github.com/gilcrest/go-api-basic/datastore/datastoretest"
	"github.com/gilcrest/go-api-basic/domain/logger"
	"github.com/gilcrest/go-api-basic/domain/movie"
	"github.com/google/uuid"
)

func TestNewDefaultTransactor(t *testing.T) {
	type args struct {
		ds datastore.Datastorer
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	db, cleanup, err := datastore.NewDB(dsn, lgr)
	defer cleanup()
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	defaultTransactor := DefaultTransactor{defaultDatastore}

	tests := []struct {
		name string
		args args
		want DefaultTransactor
	}{
		{"typical", args{ds: defaultDatastore}, defaultTransactor},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := NewDefaultTransactor(tt.args.ds); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("NewDefaultTransactor() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestDefaultTransactor_Create(t *testing.T) {
	type fields struct {
		datastorer datastore.Datastorer
	}
	type args struct {
		ctx context.Context
		m   *movie.Movie
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	// I am intentionally not using the cleanup function that is
	// returned from NewDB as I need the DB to stay open for the test
	// t.Cleanup function
	db, _, err := datastore.NewDB(dsn, lgr)
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	defaultTransactor := NewDefaultTransactor(defaultDatastore)
	ctx := context.Background()
	m := newMovie(t)
	t.Cleanup(func() {
		err := defaultTransactor.Delete(ctx, m)
		if err != nil {
			t.Fatalf("defaultTransactor.Delete error = %v", err)
		}
	})

	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		{"typical", fields{datastorer: defaultDatastore}, args{ctx, m}, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := DefaultTransactor{
				datastorer: tt.fields.datastorer,
			}
			if err := dt.Create(tt.args.ctx, tt.args.m); (err != nil) != tt.wantErr {
				t.Errorf("DefaultTransactor.Create() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestDefaultTransactor_Update(t *testing.T) {
	type fields struct {
		datastorer datastore.Datastorer
	}
	type args struct {
		ctx context.Context
		m   *movie.Movie
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	// I am intentionally not using the cleanup function that is
	// returned from NewDB as I need the DB to stay open for the test
	// t.Cleanup function
	db, _, err := datastore.NewDB(dsn, lgr)
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	// defaultTransactor := NewDefaultTransactor(defaultDatastore)
	ctx := context.Background()
	// create a movie with the helper to ensure that at least one row
	// is returned
	m := newMovieDBHelper(ctx, t, defaultDatastore, true)
	// The ID would not be set on an update, as only the external ID
	// is known to the client
	m.ID = uuid.Nil
	m.SetDirector("Alex Cox")

	m2 := &movie.Movie{}

	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		{"typical", fields{datastorer: defaultDatastore}, args{ctx, m}, false},
		{"no rows updated", fields{datastorer: defaultDatastore}, args{ctx, m2}, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := DefaultTransactor{
				datastorer: tt.fields.datastorer,
			}
			if err := dt.Update(tt.args.ctx, tt.args.m); (err != nil) != tt.wantErr {
				t.Errorf("DefaultTransactor.Update() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestDefaultTransactor_Delete(t *testing.T) {
	type fields struct {
		datastorer datastore.Datastorer
	}
	type args struct {
		ctx context.Context
		m   *movie.Movie
	}
	dsn := datastoretest.NewPGDatasourceName(t)
	lgr := logger.NewLogger(os.Stdout, true)

	// I am intentionally not using the cleanup function that is
	// returned from NewDB as I need the DB to stay open for the test
	// t.Cleanup function
	db, _, err := datastore.NewDB(dsn, lgr)
	if err != nil {
		t.Errorf("datastore.NewDB error = %v", err)
	}
	defaultDatastore := datastore.NewDefaultDatastore(db)
	// defaultTransactor := NewDefaultTransactor(defaultDatastore)
	ctx := context.Background()
	// create a movie with the helper to ensure that at least one row
	// is returned
	m := newMovieDBHelper(ctx, t, defaultDatastore, false)

	m2 := &movie.Movie{}

	tests := []struct {
		name    string
		fields  fields
		args    args
		wantErr bool
	}{
		{"typical", fields{datastorer: defaultDatastore}, args{ctx, m}, false},
		{"no rows deleted", fields{datastorer: defaultDatastore}, args{ctx, m2}, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := DefaultTransactor{
				datastorer: tt.fields.datastorer,
			}
			if err := dt.Delete(tt.args.ctx, tt.args.m); (err != nil) != tt.wantErr {
				t.Logf("%s yieled dt.Delete error = %v", tt.name, err)
				t.Errorf("DefaultTransactor.Delete() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}
<|endoftext|>