<commit_before>package resque

import (
	"encoding/json"
	"time"

	"github.com/jazibjohar/go-resque/driver"
)

var drivers = make(map[string]driver.Enqueuer)

type jobArg interface{}

type job struct {
	Queue string   `json:"queue,omitempty"`
	Class string   `json:"class"`
	Args  []jobArg `json:"args"`
}

func Register(name string, driver driver.Enqueuer) {
	if _, d := drivers[name]; d {
		panic("Register called twice for driver " + name)
	}
	drivers[name] = driver
}

func NewRedisEnqueuer(drvName string, client interface{}, nameSpace string) *RedisEnqueuer {
	drv, ok := drivers[drvName]
	if !ok {
		panic("No such driver: " + drvName)
	}

	drv.SetClient(nameSpace, client)
	drv.Poll()
	return &RedisEnqueuer{drv: drv}
}

type RedisEnqueuer struct {
	drv driver.Enqueuer
}

func (enqueuer *RedisEnqueuer) Enqueue(queue, jobClass string, args ...jobArg) (int64, error) {
	// NOTE: Dirty hack to make a [{}] JSON struct
	if len(args) == 0 {
		args = append(make([]jobArg, 0), make(map[string]jobArg, 0))
	}

	jobJSON, err := json.Marshal(&job{Class: jobClass, Args: args})
	if err != nil {
		return -1, err
	}

	return enqueuer.drv.ListPush(queue, string(jobJSON))
}

// EnqueueIn enque a job at a duration
func (enqueuer *RedisEnqueuer) EnqueueIn(delay time.Duration, queue, jobClass string, args ...jobArg) (bool, error) {
	enqueueTime := time.Now().Add(delay)

	if len(args) == 0 {
		args = append(make([]jobArg, 0), make(map[string]jobArg, 0))
	}

	jobJSON, err := json.Marshal(&job{Class: jobClass, Args: args, Queue: queue})
	if err != nil {
		return false, err
	}
	return enqueuer.drv.ListPushDelay(enqueueTime, queue, string(jobJSON))
}
<commit_msg>Adding mock driver<commit_after>package resque

import (
	"encoding/json"
	"time"

	"github.com/jazibjohar/go-resque/driver"
)

var drivers = make(map[string]driver.Enqueuer)

type jobArg interface{}

type MockRedisDriver struct {
	driver.Enqueuer
}

type job struct {
	Queue string   `json:"queue,omitempty"`
	Class string   `json:"class"`
	Args  []jobArg `json:"args"`
}

func Register(name string, driver driver.Enqueuer) {
	if _, d := drivers[name]; d {
		panic("Register called twice for driver " + name)
	}
	drivers[name] = driver
}

func NewRedisEnqueuer(drvName string, client interface{}, nameSpace string) *RedisEnqueuer {
	drv, ok := drivers[drvName]
	if !ok {
		panic("No such driver: " + drvName)
	}

	drv.SetClient(nameSpace, client)
	drv.Poll()
	return &RedisEnqueuer{drv: drv}
}

type RedisEnqueuer struct {
	drv driver.Enqueuer
}

func (enqueuer *RedisEnqueuer) Enqueue(queue, jobClass string, args ...jobArg) (int64, error) {
	// NOTE: Dirty hack to make a [{}] JSON struct
	if len(args) == 0 {
		args = append(make([]jobArg, 0), make(map[string]jobArg, 0))
	}

	jobJSON, err := json.Marshal(&job{Class: jobClass, Args: args})
	if err != nil {
		return -1, err
	}

	return enqueuer.drv.ListPush(queue, string(jobJSON))
}

// EnqueueIn enque a job at a duration
func (enqueuer *RedisEnqueuer) EnqueueIn(delay time.Duration, queue, jobClass string, args ...jobArg) (bool, error) {
	enqueueTime := time.Now().Add(delay)

	if len(args) == 0 {
		args = append(make([]jobArg, 0), make(map[string]jobArg, 0))
	}

	jobJSON, err := json.Marshal(&job{Class: jobClass, Args: args, Queue: queue})
	if err != nil {
		return false, err
	}
	return enqueuer.drv.ListPushDelay(enqueueTime, queue, string(jobJSON))
}
<|endoftext|>


<commit_before>package somaproto

const (
	StatusOK             = 200
	StatusAccepted       = 202
	StatusBadRequest     = 400
	StatusUnauthorized   = 401
	StatusForbidden      = 403
	StatusNotFound       = 404
	StatusError          = 500
	StatusNotImplemented = 501
	StatusGatewayTimeout = 504
)

// Display text for status codes
var DisplayStatus = map[int]string{
	200: "OK",
	202: "Accepted",
	400: "Bad Request",
	401: "Unauthorized",
	403: "Forbidden",
	404: "Not found",
	500: "Server error",
	501: "Not implemented",
	504: "Gateway timeout",
}

type Result struct {
	StatusCode uint16 `json:"statusCode"`
	StatusText string `json:"statusText"`

	// Errors is set for StatusCode >399
	Errors *[]string `json:"errors, omitempty"`
	// JobId is set for StatusCode 202 (async processing)
	JobId string `json:"jobId, omitempty"`

	// Request dependent data
	Attributes       *[]Attribute       `json:"attributes, omitempty"`
	Buckets          *[]Bucket          `json:"buckets, omitempty"`
	Capabilities     *[]Capability      `json:"capability, omitempty"`
	Categories       *[]Category        `json:"categories, omitempty"`
	CheckConfigs     *[]CheckConfig     `json:"checkConfigs, omitempty"`
	Clusters         *[]Cluster         `json:"clusters, omitempty"`
	DatacenterGroups *[]DatacenterGroup `json:"datacenterGroups, omitempty"`
	Datacenters      *[]Datacenter      `json:"datacenter, omitempty"`
	Deployments      *[]Deployment      `json:"deployments, omitempty"`
	Entities         *[]Entity          `json:"entities, omitempty"`
	Environments     *[]Environment     `json:"environment, omitempty"`
	Grants           *[]Grant           `json:"grants, omitempty"`
	Groups           *[]Group           `json:"groups, omitempty"`
	HostDeployments  *[]HostDeployment  `json:"hostDeployments, omitempty"`
	Levels           *[]Level           `json:"levels, omitempty"`
	Metrics          *[]Metric          `json:"metrics, omitempty"`
	Modes            *[]Mode            `json:"modes, omitempty"`
	Monitorings      *[]Monitoring      `json:"monitorings, omitempty"`
	Nodes            *[]Node            `json:"nodes, omitempty"`
	Oncalls          *[]Oncall          `json:"oncall, omitempty"`
	Permissions      *[]Permission      `json:"permissions, omitempty"`
	Predicates       *[]Predicate       `json:"predicates, omitempty"`
	Properties       *[]Property        `json:"properties, omitempty"`
	Providers        *[]Provider        `json:"providers, omitempty"`
	Repositories     *[]Repository      `json:"repositories, omitempty"`
	Servers          *[]Server          `json:"servers, omitempty"`
	States           *[]State           `json:"states, omitempty"`
	Status           *[]Status          `json:"status, omitempty"`
	Teams            *[]Team            `json:"teams, omitempty"`
	Units            *[]Unit            `json:"units, omitempty"`
	Users            *[]User            `json:"users, omitempty"`
	Validities       *[]Validity        `json:"validities, omitempty"`
	Views            *[]View            `json:"views, omitempty"`
}

func (r *Result) Error(err error) bool {
	if err != nil {
		r.StatusCode = StatusError
		r.StatusText = DisplayStatus[StatusError]
		r.Errors = &[]string{err.Error()}
		return true
	}
	return false
}

func (r *Result) NotImplemented() {
	r.StatusCode = StatusNotImplemented
	r.StatusText = DisplayStatus[StatusNotImplemented]
}

func (r *Result) NotFound() {
	r.StatusCode = StatusNotFound
	r.StatusText = DisplayStatus[StatusNotFound]
}

func (r *Result) Accepted() {
	r.StatusCode = StatusAccepted
	r.StatusText = DisplayStatus[StatusAccepted]
}

func (r *Result) OK() {
	r.StatusCode = StatusOK
	r.StatusText = DisplayStatus[StatusOK]
}

func (r *Result) Clean() {
	if len(*r.Errors) == 0 {
		r.Errors = nil
	}
}

// Legacy interface
func (r *Result) ErrorMark(err error, imp bool, found bool,
	length int, jobid string) bool {

	if r.Error(err) {
		return true
	}
	if imp {
		r.NotImplemented()
		return true
	}
	if found || length == 0 {
		r.NotFound()
		return true
	}
	if jobid != "" {
		r.JobId = jobid
		r.Accepted()
		return true
	}
	r.OK()
	return false
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Re-add DeploymentsList<commit_after>package somaproto

const (
	StatusOK             = 200
	StatusAccepted       = 202
	StatusBadRequest     = 400
	StatusUnauthorized   = 401
	StatusForbidden      = 403
	StatusNotFound       = 404
	StatusError          = 500
	StatusNotImplemented = 501
	StatusGatewayTimeout = 504
)

// Display text for status codes
var DisplayStatus = map[int]string{
	200: "OK",
	202: "Accepted",
	400: "Bad Request",
	401: "Unauthorized",
	403: "Forbidden",
	404: "Not found",
	500: "Server error",
	501: "Not implemented",
	504: "Gateway timeout",
}

type Result struct {
	StatusCode uint16 `json:"statusCode"`
	StatusText string `json:"statusText"`

	// Errors is set for StatusCode >399
	Errors *[]string `json:"errors, omitempty"`
	// JobId is set for StatusCode 202 (async processing)
	JobId string `json:"jobId, omitempty"`
	// List of (outstanding) deployment IDs
	DeploymentsList *[]string `json:"deploymentsList, omitempty"`

	// Request dependent data
	Attributes       *[]Attribute       `json:"attributes, omitempty"`
	Buckets          *[]Bucket          `json:"buckets, omitempty"`
	Capabilities     *[]Capability      `json:"capability, omitempty"`
	Categories       *[]Category        `json:"categories, omitempty"`
	CheckConfigs     *[]CheckConfig     `json:"checkConfigs, omitempty"`
	Clusters         *[]Cluster         `json:"clusters, omitempty"`
	DatacenterGroups *[]DatacenterGroup `json:"datacenterGroups, omitempty"`
	Datacenters      *[]Datacenter      `json:"datacenter, omitempty"`
	Deployments      *[]Deployment      `json:"deployments, omitempty"`
	Entities         *[]Entity          `json:"entities, omitempty"`
	Environments     *[]Environment     `json:"environment, omitempty"`
	Grants           *[]Grant           `json:"grants, omitempty"`
	Groups           *[]Group           `json:"groups, omitempty"`
	HostDeployments  *[]HostDeployment  `json:"hostDeployments, omitempty"`
	Levels           *[]Level           `json:"levels, omitempty"`
	Metrics          *[]Metric          `json:"metrics, omitempty"`
	Modes            *[]Mode            `json:"modes, omitempty"`
	Monitorings      *[]Monitoring      `json:"monitorings, omitempty"`
	Nodes            *[]Node            `json:"nodes, omitempty"`
	Oncalls          *[]Oncall          `json:"oncall, omitempty"`
	Permissions      *[]Permission      `json:"permissions, omitempty"`
	Predicates       *[]Predicate       `json:"predicates, omitempty"`
	Properties       *[]Property        `json:"properties, omitempty"`
	Providers        *[]Provider        `json:"providers, omitempty"`
	Repositories     *[]Repository      `json:"repositories, omitempty"`
	Servers          *[]Server          `json:"servers, omitempty"`
	States           *[]State           `json:"states, omitempty"`
	Status           *[]Status          `json:"status, omitempty"`
	Teams            *[]Team            `json:"teams, omitempty"`
	Units            *[]Unit            `json:"units, omitempty"`
	Users            *[]User            `json:"users, omitempty"`
	Validities       *[]Validity        `json:"validities, omitempty"`
	Views            *[]View            `json:"views, omitempty"`
}

func (r *Result) Error(err error) bool {
	if err != nil {
		r.StatusCode = StatusError
		r.StatusText = DisplayStatus[StatusError]
		r.Errors = &[]string{err.Error()}
		return true
	}
	return false
}

func (r *Result) NotImplemented() {
	r.StatusCode = StatusNotImplemented
	r.StatusText = DisplayStatus[StatusNotImplemented]
}

func (r *Result) NotFound() {
	r.StatusCode = StatusNotFound
	r.StatusText = DisplayStatus[StatusNotFound]
}

func (r *Result) Accepted() {
	r.StatusCode = StatusAccepted
	r.StatusText = DisplayStatus[StatusAccepted]
}

func (r *Result) OK() {
	r.StatusCode = StatusOK
	r.StatusText = DisplayStatus[StatusOK]
}

func (r *Result) Clean() {
	if len(*r.Errors) == 0 {
		r.Errors = nil
	}
}

// Legacy interface
func (r *Result) ErrorMark(err error, imp bool, found bool,
	length int, jobid string) bool {

	if r.Error(err) {
		return true
	}
	if imp {
		r.NotImplemented()
		return true
	}
	if found || length == 0 {
		r.NotFound()
		return true
	}
	if jobid != "" {
		r.JobId = jobid
		r.Accepted()
		return true
	}
	r.OK()
	return false
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package parse

import (
	"os"

	"github.com/rthornton128/calc/ast"
	"github.com/rthornton128/calc/scan"
	"github.com/rthornton128/calc/token"
)

func ParseFile(filename, src string) *ast.File {
	var p parser
	p.init(filename, src)
	f := p.parseFile()
	if p.errors.Count() > 0 {
		p.errors.Print()
		return nil
	}
	return f
}

type parser struct {
	file    *token.File
	errors  scan.ErrorList
	scanner scan.Scanner

	pos token.Pos
	tok token.Token
	lit string
}

func (p *parser) addError(msg string) {
	p.errors.Add(p.file.Position(p.pos), msg)
	if p.errors.Count() >= 10 {
		p.errors.Print()
		os.Exit(1)
	}
}

func (p *parser) expect(tok token.Token) token.Pos {
	pos := p.pos
	if p.tok != tok {
		p.addError("Expected '" + tok.String() + "' got '" + p.lit + "'")
	}
	p.next()
	return pos
}

func (p *parser) init(fname, src string) {
	p.file = token.NewFile(fname, 1, len(src))
	p.scanner.Init(p.file, src)
	p.next()
}

func (p *parser) next() {
	p.lit, p.tok, p.pos = p.scanner.Scan()
}

func (p *parser) parseBasicLit() *ast.BasicLit {
	return &ast.BasicLit{LitPos: p.pos, Kind: p.tok, Lit: p.lit}
}

func (p *parser) parseBinaryExpr(open token.Pos) *ast.BinaryExpr {
	pos := p.pos
	op := p.tok
	p.next()

	var list []ast.Expr
	for p.tok != token.RPAREN && p.tok != token.EOF {
		list = append(list, p.parseGenExpr())
	}
	if len(list) < 2 {
		p.addError("binary expression must have at least two operands")
	}
	end := p.expect(token.RPAREN)
	return &ast.BinaryExpr{
		Expression: ast.Expression{
			Opening: open,
			Closing: end,
		},
		Op:    op,
		OpPos: pos,
		List:  list,
	}
}

func (p *parser) parseGenExpr() ast.Expr {
	var expr ast.Expr

	switch p.tok {
	case token.LPAREN:
		expr = p.parseExpr()
	case token.INTEGER:
		expr = p.parseBasicLit()
		p.next()
	default:
		p.addError("Expected '" + token.LPAREN.String() + "' or '" +
			token.INTEGER.String() + "' got '" + p.lit + "'")
		p.next()
	}

	return expr
}

func (p *parser) parseExpr() ast.Expr {
	var expr ast.Expr

	pos := p.expect(token.LPAREN)
	switch p.tok {
	case token.ADD, token.SUB, token.MUL, token.QUO, token.REM:
		expr = p.parseBinaryExpr(pos)
	default:
		p.addError("Expected binary operator but got '" + p.lit + "'")
	}

	return expr
}

func (p *parser) parseFile() *ast.File {
	var expr ast.Expr
	expr = p.parseGenExpr()
	if p.tok != token.EOF {
		p.addError("Expected EOF, got '" + p.lit + "'")
	}
	scope := ast.NewScope(nil)
	scope.Insert(&ast.Ident{NamePos: token.NoPos, Name: "main", Value: nil},
		expr)
	return &ast.File{Scope: scope}
}
<commit_msg>Tweak parser to work with changes<commit_after>// Copyright (c) 2014, Rob Thornton
// All rights reserved.
// This source code is governed by a Simplied BSD-License. Please see the
// LICENSE included in this distribution for a copy of the full license
// or, if one is not included, you may also find a copy at
// http://opensource.org/licenses/BSD-2-Clause

package parse

import (
	"os"

	"github.com/rthornton128/calc/ast"
	"github.com/rthornton128/calc/scan"
	"github.com/rthornton128/calc/token"
)

func ParseFile(filename, src string) *ast.File {
	var p parser
	p.init(filename, src)
	f := p.parseFile()
	if p.errors.Count() > 0 {
		p.errors.Print()
		return nil
	}
	return f
}

type parser struct {
	file    *token.File
	errors  scan.ErrorList
	scanner scan.Scanner

	pos token.Pos
	tok token.Token
	lit string
}

func (p *parser) addError(msg string) {
	p.errors.Add(p.file.Position(p.pos), msg)
	if p.errors.Count() >= 10 {
		p.errors.Print()
		os.Exit(1)
	}
}

func (p *parser) expect(tok token.Token) token.Pos {
	pos := p.pos
	if p.tok != tok {
		p.addError("Expected '" + tok.String() + "' got '" + p.lit + "'")
	}
	p.next()
	return pos
}

func (p *parser) init(fname, src string) {
	p.file = token.NewFile(fname, 1, len(src))
	p.scanner.Init(p.file, src)
	p.next()
}

func (p *parser) next() {
	p.lit, p.tok, p.pos = p.scanner.Scan()
}

func (p *parser) parseBasicLit() *ast.BasicLit {
	return &ast.BasicLit{LitPos: p.pos, Kind: p.tok, Lit: p.lit}
}

func (p *parser) parseBinaryExpr(open token.Pos) *ast.BinaryExpr {
	pos := p.pos
	op := p.tok
	p.next()

	var list []ast.Expr
	for p.tok != token.RPAREN && p.tok != token.EOF {
		list = append(list, p.parseGenExpr())
	}
	if len(list) < 2 {
		p.addError("binary expression must have at least two operands")
	}
	end := p.expect(token.RPAREN)
	return &ast.BinaryExpr{
		Expression: ast.Expression{
			Opening: open,
			Closing: end,
		},
		Op:    op,
		OpPos: pos,
		List:  list,
	}
}

func (p *parser) parseGenExpr() ast.Expr {
	var expr ast.Expr

	switch p.tok {
	case token.LPAREN:
		expr = p.parseExpr()
	case token.INTEGER:
		expr = p.parseBasicLit()
		p.next()
	default:
		p.addError("Expected '" + token.LPAREN.String() + "' or '" +
			token.INTEGER.String() + "' got '" + p.lit + "'")
		p.next()
	}

	return expr
}

func (p *parser) parseExpr() ast.Expr {
	var expr ast.Expr

	pos := p.expect(token.LPAREN)
	switch p.tok {
	case token.ADD, token.SUB, token.MUL, token.QUO, token.REM:
		expr = p.parseBinaryExpr(pos)
	default:
		p.addError("Expected binary operator but got '" + p.lit + "'")
	}

	return expr
}

func (p *parser) parseFile() *ast.File {
	var expr ast.Expr
	expr = p.parseGenExpr()
	if p.tok != token.EOF {
		p.addError("Expected EOF, got '" + p.lit + "'")
	}
	scope := ast.NewScope(nil)
	scope.Insert(&ast.Ident{NamePos: token.NoPos, Name: "main",
		Type: &ast.Ident{NamePos: token.NoPos, Name: "int", Type: nil}},
		expr)
	return &ast.File{Scope: scope}
}
<|endoftext|>


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

import (
	"bytes"
	"fmt"
	"github.com/snowplow/sql-runner/run"
	"text/template"
)

var (
	failureTemplate *template.Template
)

func init() {
	failureTemplate = template.Must(template.New("failure").Parse(`
TARGET INITIALIZATION FAILURES:{{range $status := .}}{{if $status.Errors}}
* {{$status.Name}}{{range $error := $status.Errors}}, ERRORS:
  - {{$error}}{{end}}{{end}}{{end}}
QUERY FAILURES:{{range $status := .}}{{range $step := $status.Steps}}{{range $query := $step.Queries}}{{if $query.Error}}
* Query {{$query.Query.Name}} {{$query.Path}} (in step {{$step.Name}} @ target {{$status.Name}}), ERROR:
  - {{$query.Error}}{{end}}{{end}}{{end}}{{end}}
`))
}

func review(statuses []run.TargetStatus) (int, string) {
	exitCode, queryCount := getExitCodeAndQueryCount(statuses)

	if exitCode == 0 {
		return exitCode, getSuccessMessage(queryCount, len(statuses))
	} else {
		return exitCode, getFailureMessage(statuses)
	}
}

// Don't use a template here as executing it could fail
func getSuccessMessage(queryCount int, targetCount int) string {
	return fmt.Sprintf("SUCCESS: %d queries executed againt %d targets", queryCount, targetCount)
}

// TODO: maybe would be cleaner to bubble up error from this function
func getFailureMessage(statuses []run.TargetStatus) string {

	var message bytes.Buffer
	if err := failureTemplate.Execute(&message, statuses); err != nil {
		return fmt.Sprintf("ERROR: executing failure message template itself failed: %s", err.Error())
	}

	return message.String()
}

// Exit codes:
// - 0 for no errors
// - 5 for target initialization errors
// - 6 for query errors
// - 7 for both types of error
// Also return the total count of query statuses we have
func getExitCodeAndQueryCount(statuses []run.TargetStatus) (int, int) {

	initErrors := false
	queryErrors := false
	queryCount := 0

	for _, targetStatus := range statuses {
		if targetStatus.Errors != nil {
			initErrors = true
		}
	CheckQueries:
		for _, stepStatus := range targetStatus.Steps {
			for _, queryStatus := range stepStatus.Queries {
				if queryStatus.Error != nil {
					queryErrors = true
					queryCount = 0 // Reset
					break CheckQueries
				}
				queryCount++
			}
		}
	}

	var exitCode int
	switch {
	case initErrors && queryErrors:
		exitCode = 7
	case initErrors:
		exitCode = 5
	case queryErrors:
		exitCode = 6
	default:
		exitCode = 0
	}
	return exitCode, queryCount
}
<commit_msg>Fixed typo of "queries executed againt targets" (closes #20)<commit_after>//
// Copyright (c) 2015 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License Version 2.0.
// You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
//
package main

import (
	"bytes"
	"fmt"
	"github.com/snowplow/sql-runner/run"
	"text/template"
)

var (
	failureTemplate *template.Template
)

func init() {
	failureTemplate = template.Must(template.New("failure").Parse(`
TARGET INITIALIZATION FAILURES:{{range $status := .}}{{if $status.Errors}}
* {{$status.Name}}{{range $error := $status.Errors}}, ERRORS:
  - {{$error}}{{end}}{{end}}{{end}}
QUERY FAILURES:{{range $status := .}}{{range $step := $status.Steps}}{{range $query := $step.Queries}}{{if $query.Error}}
* Query {{$query.Query.Name}} {{$query.Path}} (in step {{$step.Name}} @ target {{$status.Name}}), ERROR:
  - {{$query.Error}}{{end}}{{end}}{{end}}{{end}}
`))
}

func review(statuses []run.TargetStatus) (int, string) {
	exitCode, queryCount := getExitCodeAndQueryCount(statuses)

	if exitCode == 0 {
		return exitCode, getSuccessMessage(queryCount, len(statuses))
	} else {
		return exitCode, getFailureMessage(statuses)
	}
}

// Don't use a template here as executing it could fail
func getSuccessMessage(queryCount int, targetCount int) string {
	return fmt.Sprintf("SUCCESS: %d queries executed against %d targets", queryCount, targetCount)
}

// TODO: maybe would be cleaner to bubble up error from this function
func getFailureMessage(statuses []run.TargetStatus) string {

	var message bytes.Buffer
	if err := failureTemplate.Execute(&message, statuses); err != nil {
		return fmt.Sprintf("ERROR: executing failure message template itself failed: %s", err.Error())
	}

	return message.String()
}

// Exit codes:
// - 0 for no errors
// - 5 for target initialization errors
// - 6 for query errors
// - 7 for both types of error
// Also return the total count of query statuses we have
func getExitCodeAndQueryCount(statuses []run.TargetStatus) (int, int) {

	initErrors := false
	queryErrors := false
	queryCount := 0

	for _, targetStatus := range statuses {
		if targetStatus.Errors != nil {
			initErrors = true
		}
	CheckQueries:
		for _, stepStatus := range targetStatus.Steps {
			for _, queryStatus := range stepStatus.Queries {
				if queryStatus.Error != nil {
					queryErrors = true
					queryCount = 0 // Reset
					break CheckQueries
				}
				queryCount++
			}
		}
	}

	var exitCode int
	switch {
	case initErrors && queryErrors:
		exitCode = 7
	case initErrors:
		exitCode = 5
	case queryErrors:
		exitCode = 6
	default:
		exitCode = 0
	}
	return exitCode, queryCount
}
<|endoftext|>


<commit_before>package revmgo

import (
	"errors"
	"fmt"
	"github.com/robfig/revel"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"reflect"
)

var (
	Session *mgo.Session // Global mgo Session
	Dial    string       // http://godoc.org/labix.org/v2/mgo#Dial
	Method  string       // clone, copy, new http://godoc.org/labix.org/v2/mgo#Session.New
)

func AppInit() {
	// Read configuration.
	var found bool
	if Dial, found = revel.Config.String("revmgo.dial"); !found {
		// Default to 'localhost'
		Dial = "localhost"
	}
	if Method, found = revel.Config.String("db.spec"); !found {
		Method = "clone"
	} else if err := MethodError(Method); err != nil {
		revel.ERROR.Panic(err)
	}

	var err error
	if Session == nil {
		// Read configuration.
		if Session, err = mgo.Dial(Dial); err != nil {
			revel.ERROR.Panic(err)
		}
	}

	// register the custom bson.ObjectId binder
	revel.TypeBinders[reflect.TypeOf(bson.ObjectId{})] = ObjectIdBinder
}

func ControllerInit() {
	revel.InterceptMethod((*MongoController).Begin, revel.BEFORE)
	revel.InterceptMethod((*MongoController).End, revel.FINALLY)
}

type MongoController struct {
	*revel.Controller
	MongoSession *mgo.Session // named MongoSession to avoid collision with revel.Session
}

// Connect to mgo if we haven't already and return a copy/new/clone of the session
func (c *MongoController) Begin() revel.Result {
	switch Method {
	case "clone":
		c.MongoSession = Session.Clone()
	case "copy":
		c.MongoSession = Session.Copy()
	case "new":
		c.MongoSession = Session.New()
	}
	return nil
}

// Close the controller session if we have an active one.
func (c *MongoController) End() revel.Result {
	c.MongoSession.Close()
	return nil
}

func MethodError(m string) error {
	switch m {
	case "clone", "copy", "new":
		return nil
	}
	return errors.New("revmgo: Invalid session instantiation method '%s'")
}

// Custom TypeBinder for bson.ObjectId
// Makes additional Id parameters in actions obsolete
var ObjectIdBinder = revel.Binder{
	// Make a ObjectId from a request containing it in string format.
	Bind: revel.ValueBinder(func(val string, typ reflect.Type) reflect.Value {
		if len(val) == 0 {
			return reflect.Zero(typ)
		}
		if bson.IsObjectIdHex(val) {
			objId := bson.ObjectIdHex(val)
			return reflect.ValueOf(objId)
		} else {
			revel.ERROR.Print("ObjectIdBinder.Bind - invalid ObjectId!")
			return reflect.Zero(typ)
		}
	}),
	// Turns ObjectId back to hexString for reverse routing
	Unbind: func(output map[string]string, name string, val interface{}) {
		var hexStr string
		hexStr = fmt.Sprintf("%s", val.(bson.ObjectId).Hex())
		// not sure if this is too carefull but i wouldn't want invalid ObjectIds in my App
		if bson.IsObjectIdHex(hexStr) {
			output[name] = hexStr
		} else {
			revel.ERROR.Print("ObjectIdBinder.Unbind - invalid ObjectId!")
			output[name] = ""
		}
	},
}
<commit_msg>fix for "revmgo.go:40: invalid type for composite literal: bson.ObjectId"<commit_after>package revmgo

import (
	"errors"
	"fmt"
	"github.com/robfig/revel"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"reflect"
)

var (
	Session *mgo.Session // Global mgo Session
	Dial    string       // http://godoc.org/labix.org/v2/mgo#Dial
	Method  string       // clone, copy, new http://godoc.org/labix.org/v2/mgo#Session.New
)

func AppInit() {
	// Read configuration.
	var found bool
	if Dial, found = revel.Config.String("revmgo.dial"); !found {
		// Default to 'localhost'
		Dial = "localhost"
	}
	if Method, found = revel.Config.String("db.spec"); !found {
		Method = "clone"
	} else if err := MethodError(Method); err != nil {
		revel.ERROR.Panic(err)
	}

	var err error
	if Session == nil {
		// Read configuration.
		if Session, err = mgo.Dial(Dial); err != nil {
			revel.ERROR.Panic(err)
		}
	}

	// register the custom bson.ObjectId binder
	objId := bson.NewObjectId()
	revel.TypeBinders[reflect.TypeOf(objId)] = ObjectIdBinder
}

func ControllerInit() {
	revel.InterceptMethod((*MongoController).Begin, revel.BEFORE)
	revel.InterceptMethod((*MongoController).End, revel.FINALLY)
}

type MongoController struct {
	*revel.Controller
	MongoSession *mgo.Session // named MongoSession to avoid collision with revel.Session
}

// Connect to mgo if we haven't already and return a copy/new/clone of the session
func (c *MongoController) Begin() revel.Result {
	switch Method {
	case "clone":
		c.MongoSession = Session.Clone()
	case "copy":
		c.MongoSession = Session.Copy()
	case "new":
		c.MongoSession = Session.New()
	}
	return nil
}

// Close the controller session if we have an active one.
func (c *MongoController) End() revel.Result {
	c.MongoSession.Close()
	return nil
}

func MethodError(m string) error {
	switch m {
	case "clone", "copy", "new":
		return nil
	}
	return errors.New("revmgo: Invalid session instantiation method '%s'")
}

// Custom TypeBinder for bson.ObjectId
// Makes additional Id parameters in actions obsolete
var ObjectIdBinder = revel.Binder{
	// Make a ObjectId from a request containing it in string format.
	Bind: revel.ValueBinder(func(val string, typ reflect.Type) reflect.Value {
		if len(val) == 0 {
			return reflect.Zero(typ)
		}
		if bson.IsObjectIdHex(val) {
			objId := bson.ObjectIdHex(val)
			return reflect.ValueOf(objId)
		} else {
			revel.ERROR.Print("ObjectIdBinder.Bind - invalid ObjectId!")
			return reflect.Zero(typ)
		}
	}),
	// Turns ObjectId back to hexString for reverse routing
	Unbind: func(output map[string]string, name string, val interface{}) {
		var hexStr string
		hexStr = fmt.Sprintf("%s", val.(bson.ObjectId).Hex())
		// not sure if this is too carefull but i wouldn't want invalid ObjectIds in my App
		if bson.IsObjectIdHex(hexStr) {
			output[name] = hexStr
		} else {
			revel.ERROR.Print("ObjectIdBinder.Unbind - invalid ObjectId!")
			output[name] = ""
		}
	},
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package git

import (
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"sync"

	"github.com/sirupsen/logrus"
	utilpointer "k8s.io/utils/pointer"
)

// ClientFactory knows how to create clientFactory for repos
type ClientFactory interface {
	// ClientFromDir creates a client that operates on a repo that has already
	// been cloned to the given directory.
	ClientFromDir(org, repo, dir string) (RepoClient, error)
	// ClientFor creates a client that operates on a new clone of the repo.
	ClientFor(org, repo string) (RepoClient, error)

	// Clean removes the caches used to generate clients
	Clean() error
}

// RepoClient exposes interactions with a git repo
type RepoClient interface {
	Publisher
	Interactor
}

type repoClient struct {
	publisher
	interactor
}

type ClientFactoryOpts struct {
	// Host, defaults to "github.com" if unset
	Host string
	// UseSSH, defaults to false
	UseSSH *bool
	// The directory in which the cache should be
	// created. Defaults to the "/var/tmp" on
	// Linux and os.TempDir otherwise
	CacheDirBase *string
	// If unset, publishing action will error
	Username LoginGetter
	// If unset, publishing action will error
	Token TokenGetter
	// The git user to use.
	GitUser GitUserGetter
	// The censor to use. Not needed for anonymous
	// actions.
	Censor Censor
}

// Apply allows to use a ClientFactoryOpts as Opt
func (cfo *ClientFactoryOpts) Apply(target *ClientFactoryOpts) {
	if cfo.Host != "" {
		target.Host = cfo.Host
	}
	if cfo.UseSSH != nil {
		target.UseSSH = cfo.UseSSH
	}
	if cfo.CacheDirBase != nil {
		target.CacheDirBase = cfo.CacheDirBase
	}
	if cfo.Token != nil {
		target.Token = cfo.Token
	}
	if cfo.GitUser != nil {
		target.Token = cfo.Token
	}
	if cfo.Censor != nil {
		target.Censor = cfo.Censor
	}
}

// ClientFactoryOpts allows to manipulate the options for a ClientFactory
type ClientFactoryOpt func(*ClientFactoryOpts)

func defaultClientFactoryOpts(cfo *ClientFactoryOpts) {
	if cfo.Host == "" {
		cfo.Host = "github.com"
	}
	if cfo.CacheDirBase == nil {
		switch runtime.GOOS {
		case "linux":
			cfo.CacheDirBase = utilpointer.StringPtr("/var/tmp")
		default:
			cfo.CacheDirBase = utilpointer.StringPtr("")
		}
	}
	if cfo.Censor == nil {
		cfo.Censor = func(in []byte) []byte { return in }
	}
}

// NewClientFactory allows for the creation of repository clients. It uses github.com
// without authentication by default.
func NewClientFactory(opts ...ClientFactoryOpt) (ClientFactory, error) {
	o := ClientFactoryOpts{}
	defaultClientFactoryOpts(&o)
	for _, opt := range opts {
		opt(&o)
	}

	cacheDir, err := ioutil.TempDir(*o.CacheDirBase, "gitcache")
	if err != nil {
		return nil, err
	}
	var remotes RemoteResolverFactory
	if o.UseSSH != nil && *o.UseSSH {
		remotes = &sshRemoteResolverFactory{
			host:     o.Host,
			username: o.Username,
		}
	} else {
		remotes = &httpResolverFactory{
			host:     o.Host,
			username: o.Username,
			token:    o.Token,
		}
	}
	return &clientFactory{
		cacheDir:     cacheDir,
		cacheDirBase: *o.CacheDirBase,
		remotes:      remotes,
		gitUser:      o.GitUser,
		censor:       o.Censor,
		masterLock:   &sync.Mutex{},
		repoLocks:    map[string]*sync.Mutex{},
		logger:       logrus.WithField("client", "git"),
	}, nil
}

// NewLocalClientFactory allows for the creation of repository clients
// based on a local filepath remote for testing
func NewLocalClientFactory(baseDir string, gitUser GitUserGetter, censor Censor) (ClientFactory, error) {
	cacheDir, err := ioutil.TempDir("", "gitcache")
	if err != nil {
		return nil, err
	}
	return &clientFactory{
		cacheDir:   cacheDir,
		remotes:    &pathResolverFactory{baseDir: baseDir},
		gitUser:    gitUser,
		censor:     censor,
		masterLock: &sync.Mutex{},
		repoLocks:  map[string]*sync.Mutex{},
		logger:     logrus.WithField("client", "git"),
	}, nil
}

type clientFactory struct {
	remotes RemoteResolverFactory
	gitUser GitUserGetter
	censor  Censor
	logger  *logrus.Entry

	// cacheDir is the root under which cached clones of repos are created
	cacheDir string
	// cacheDirBase is the basedir under which create tempdirs
	cacheDirBase string
	// masterLock guards mutations to the repoLocks records
	masterLock *sync.Mutex
	// repoLocks guard mutating access to subdirectories under the cacheDir
	repoLocks map[string]*sync.Mutex
}

// bootstrapClients returns a repository client and cloner for a dir.
func (c *clientFactory) bootstrapClients(org, repo, dir string) (cacher, cloner, RepoClient, error) {
	if dir == "" {
		workdir, err := os.Getwd()
		if err != nil {
			return nil, nil, nil, err
		}
		dir = workdir
	}
	logger := c.logger.WithFields(logrus.Fields{"org": org, "repo": repo})
	logger.WithField("dir", dir).Debug("Creating a pre-initialized client.")
	executor, err := NewCensoringExecutor(dir, c.censor, logger)
	if err != nil {
		return nil, nil, nil, err
	}
	client := &repoClient{
		publisher: publisher{
			remote:   c.remotes.PublishRemote(org, repo),
			executor: executor,
			info:     c.gitUser,
			logger:   logger,
		},
		interactor: interactor{
			dir:      dir,
			remote:   c.remotes.CentralRemote(org, repo),
			executor: executor,
			logger:   logger,
		},
	}
	return client, client, client, nil
}

// ClientFromDir returns a repository client for a directory that's already initialized with content.
// If the directory isn't specified, the current working directory is used.
func (c *clientFactory) ClientFromDir(org, repo, dir string) (RepoClient, error) {
	_, _, client, err := c.bootstrapClients(org, repo, dir)
	return client, err
}

// ClientFor returns a repository client for the specified repository.
// This function may take a long time if it is the first time cloning the repo.
// In that case, it must do a full git mirror clone. For large repos, this can
// take a while. Once that is done, it will do a git fetch instead of a clone,
// which will usually take at most a few seconds.
func (c *clientFactory) ClientFor(org, repo string) (RepoClient, error) {
	cacheDir := path.Join(c.cacheDir, org, repo)
	c.logger.WithFields(logrus.Fields{"org": org, "repo": repo, "dir": cacheDir}).Debug("Creating a client from the cache.")
	cacheClientCacher, _, _, err := c.bootstrapClients(org, repo, cacheDir)
	if err != nil {
		return nil, err
	}

	repoDir, err := ioutil.TempDir(c.cacheDirBase, "gitrepo")
	if err != nil {
		return nil, err
	}
	_, repoClientCloner, repoClient, err := c.bootstrapClients(org, repo, repoDir)
	if err != nil {
		return nil, err
	}
	c.masterLock.Lock()
	if _, exists := c.repoLocks[cacheDir]; !exists {
		c.repoLocks[cacheDir] = &sync.Mutex{}
	}
	c.masterLock.Unlock()
	c.repoLocks[cacheDir].Lock()
	defer c.repoLocks[cacheDir].Unlock()
	if _, err := os.Stat(path.Join(cacheDir, "HEAD")); os.IsNotExist(err) {
		// we have not yet cloned this repo, we need to do a full clone
		if err := os.MkdirAll(cacheDir, os.ModePerm); err != nil && !os.IsExist(err) {
			return nil, err
		}
		if err := cacheClientCacher.MirrorClone(); err != nil {
			return nil, err
		}
	} else if err != nil {
		// something unexpected happened
		return nil, err
	} else {
		// we have cloned the repo previously, but will refresh it
		if err := cacheClientCacher.RemoteUpdate(); err != nil {
			return nil, err
		}
	}

	// initialize the new derivative repo from the cache
	if err := repoClientCloner.Clone(cacheDir); err != nil {
		return nil, err
	}

	return repoClient, nil
}

// Clean removes the caches used to generate clients
func (c *clientFactory) Clean() error {
	return os.RemoveAll(c.cacheDir)
}
<commit_msg>apply the LoginGetter in ClientFactoryOpts<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package git

import (
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"sync"

	"github.com/sirupsen/logrus"
	utilpointer "k8s.io/utils/pointer"
)

// ClientFactory knows how to create clientFactory for repos
type ClientFactory interface {
	// ClientFromDir creates a client that operates on a repo that has already
	// been cloned to the given directory.
	ClientFromDir(org, repo, dir string) (RepoClient, error)
	// ClientFor creates a client that operates on a new clone of the repo.
	ClientFor(org, repo string) (RepoClient, error)

	// Clean removes the caches used to generate clients
	Clean() error
}

// RepoClient exposes interactions with a git repo
type RepoClient interface {
	Publisher
	Interactor
}

type repoClient struct {
	publisher
	interactor
}

type ClientFactoryOpts struct {
	// Host, defaults to "github.com" if unset
	Host string
	// UseSSH, defaults to false
	UseSSH *bool
	// The directory in which the cache should be
	// created. Defaults to the "/var/tmp" on
	// Linux and os.TempDir otherwise
	CacheDirBase *string
	// If unset, publishing action will error
	Username LoginGetter
	// If unset, publishing action will error
	Token TokenGetter
	// The git user to use.
	GitUser GitUserGetter
	// The censor to use. Not needed for anonymous
	// actions.
	Censor Censor
}

// Apply allows to use a ClientFactoryOpts as Opt
func (cfo *ClientFactoryOpts) Apply(target *ClientFactoryOpts) {
	if cfo.Host != "" {
		target.Host = cfo.Host
	}
	if cfo.UseSSH != nil {
		target.UseSSH = cfo.UseSSH
	}
	if cfo.CacheDirBase != nil {
		target.CacheDirBase = cfo.CacheDirBase
	}
	if cfo.Token != nil {
		target.Token = cfo.Token
	}
	if cfo.GitUser != nil {
		target.Token = cfo.Token
	}
	if cfo.Censor != nil {
		target.Censor = cfo.Censor
	}
	if cfo.Username != nil {
		target.Username = cfo.Username
	}
}

// ClientFactoryOpts allows to manipulate the options for a ClientFactory
type ClientFactoryOpt func(*ClientFactoryOpts)

func defaultClientFactoryOpts(cfo *ClientFactoryOpts) {
	if cfo.Host == "" {
		cfo.Host = "github.com"
	}
	if cfo.CacheDirBase == nil {
		switch runtime.GOOS {
		case "linux":
			cfo.CacheDirBase = utilpointer.StringPtr("/var/tmp")
		default:
			cfo.CacheDirBase = utilpointer.StringPtr("")
		}
	}
	if cfo.Censor == nil {
		cfo.Censor = func(in []byte) []byte { return in }
	}
}

// NewClientFactory allows for the creation of repository clients. It uses github.com
// without authentication by default.
func NewClientFactory(opts ...ClientFactoryOpt) (ClientFactory, error) {
	o := ClientFactoryOpts{}
	defaultClientFactoryOpts(&o)
	for _, opt := range opts {
		opt(&o)
	}

	cacheDir, err := ioutil.TempDir(*o.CacheDirBase, "gitcache")
	if err != nil {
		return nil, err
	}
	var remotes RemoteResolverFactory
	if o.UseSSH != nil && *o.UseSSH {
		remotes = &sshRemoteResolverFactory{
			host:     o.Host,
			username: o.Username,
		}
	} else {
		remotes = &httpResolverFactory{
			host:     o.Host,
			username: o.Username,
			token:    o.Token,
		}
	}
	return &clientFactory{
		cacheDir:     cacheDir,
		cacheDirBase: *o.CacheDirBase,
		remotes:      remotes,
		gitUser:      o.GitUser,
		censor:       o.Censor,
		masterLock:   &sync.Mutex{},
		repoLocks:    map[string]*sync.Mutex{},
		logger:       logrus.WithField("client", "git"),
	}, nil
}

// NewLocalClientFactory allows for the creation of repository clients
// based on a local filepath remote for testing
func NewLocalClientFactory(baseDir string, gitUser GitUserGetter, censor Censor) (ClientFactory, error) {
	cacheDir, err := ioutil.TempDir("", "gitcache")
	if err != nil {
		return nil, err
	}
	return &clientFactory{
		cacheDir:   cacheDir,
		remotes:    &pathResolverFactory{baseDir: baseDir},
		gitUser:    gitUser,
		censor:     censor,
		masterLock: &sync.Mutex{},
		repoLocks:  map[string]*sync.Mutex{},
		logger:     logrus.WithField("client", "git"),
	}, nil
}

type clientFactory struct {
	remotes RemoteResolverFactory
	gitUser GitUserGetter
	censor  Censor
	logger  *logrus.Entry

	// cacheDir is the root under which cached clones of repos are created
	cacheDir string
	// cacheDirBase is the basedir under which create tempdirs
	cacheDirBase string
	// masterLock guards mutations to the repoLocks records
	masterLock *sync.Mutex
	// repoLocks guard mutating access to subdirectories under the cacheDir
	repoLocks map[string]*sync.Mutex
}

// bootstrapClients returns a repository client and cloner for a dir.
func (c *clientFactory) bootstrapClients(org, repo, dir string) (cacher, cloner, RepoClient, error) {
	if dir == "" {
		workdir, err := os.Getwd()
		if err != nil {
			return nil, nil, nil, err
		}
		dir = workdir
	}
	logger := c.logger.WithFields(logrus.Fields{"org": org, "repo": repo})
	logger.WithField("dir", dir).Debug("Creating a pre-initialized client.")
	executor, err := NewCensoringExecutor(dir, c.censor, logger)
	if err != nil {
		return nil, nil, nil, err
	}
	client := &repoClient{
		publisher: publisher{
			remote:   c.remotes.PublishRemote(org, repo),
			executor: executor,
			info:     c.gitUser,
			logger:   logger,
		},
		interactor: interactor{
			dir:      dir,
			remote:   c.remotes.CentralRemote(org, repo),
			executor: executor,
			logger:   logger,
		},
	}
	return client, client, client, nil
}

// ClientFromDir returns a repository client for a directory that's already initialized with content.
// If the directory isn't specified, the current working directory is used.
func (c *clientFactory) ClientFromDir(org, repo, dir string) (RepoClient, error) {
	_, _, client, err := c.bootstrapClients(org, repo, dir)
	return client, err
}

// ClientFor returns a repository client for the specified repository.
// This function may take a long time if it is the first time cloning the repo.
// In that case, it must do a full git mirror clone. For large repos, this can
// take a while. Once that is done, it will do a git fetch instead of a clone,
// which will usually take at most a few seconds.
func (c *clientFactory) ClientFor(org, repo string) (RepoClient, error) {
	cacheDir := path.Join(c.cacheDir, org, repo)
	c.logger.WithFields(logrus.Fields{"org": org, "repo": repo, "dir": cacheDir}).Debug("Creating a client from the cache.")
	cacheClientCacher, _, _, err := c.bootstrapClients(org, repo, cacheDir)
	if err != nil {
		return nil, err
	}

	repoDir, err := ioutil.TempDir(c.cacheDirBase, "gitrepo")
	if err != nil {
		return nil, err
	}
	_, repoClientCloner, repoClient, err := c.bootstrapClients(org, repo, repoDir)
	if err != nil {
		return nil, err
	}
	c.masterLock.Lock()
	if _, exists := c.repoLocks[cacheDir]; !exists {
		c.repoLocks[cacheDir] = &sync.Mutex{}
	}
	c.masterLock.Unlock()
	c.repoLocks[cacheDir].Lock()
	defer c.repoLocks[cacheDir].Unlock()
	if _, err := os.Stat(path.Join(cacheDir, "HEAD")); os.IsNotExist(err) {
		// we have not yet cloned this repo, we need to do a full clone
		if err := os.MkdirAll(cacheDir, os.ModePerm); err != nil && !os.IsExist(err) {
			return nil, err
		}
		if err := cacheClientCacher.MirrorClone(); err != nil {
			return nil, err
		}
	} else if err != nil {
		// something unexpected happened
		return nil, err
	} else {
		// we have cloned the repo previously, but will refresh it
		if err := cacheClientCacher.RemoteUpdate(); err != nil {
			return nil, err
		}
	}

	// initialize the new derivative repo from the cache
	if err := repoClientCloner.Clone(cacheDir); err != nil {
		return nil, err
	}

	return repoClient, nil
}

// Clean removes the caches used to generate clients
func (c *clientFactory) Clean() error {
	return os.RemoveAll(c.cacheDir)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/ahl5esoft/golang-underscore"
	"github.com/cfpb/rhobot/config"
	"github.com/cfpb/rhobot/database"
	"github.com/cfpb/rhobot/gocd"
	"github.com/cfpb/rhobot/healthcheck"
	"github.com/cfpb/rhobot/report"
	"github.com/codegangsta/cli"
	"github.com/davecgh/go-spew/spew"
)

func main() {

	cli.VersionFlag = cli.BoolFlag{
		Name:  "print-version, V",
		Usage: "print only the version",
	}

	app := cli.NewApp()
	app.Name = "Rhobot"
	app.Usage = "Rhobot is a database development tool that uses DevOps best practices."
	app.Version = Version
	app.EnableBashCompletion = true

	conf := config.NewConfig()
	gocdServer := gocd.NewServerConfig(conf.GOCDHost, conf.GOCDPort, conf.GOCDUser, conf.GOCDPassword, conf.GOCDTimeout)

	logLevelFlag := cli.StringFlag{
		Name:  "loglevel, lvl",
		Value: "",
		Usage: "sets the log level for Rhobot",
	}
	gocdHostFlag := cli.StringFlag{
		Name:  "host",
		Value: "",
		Usage: "host of the GoCD server",
	}
	reportFileFlag := cli.StringFlag{
		Name:  "report",
		Value: "",
		Usage: "path to the healthcheck report",
	}
	dburiFlag := cli.StringFlag{
		Name:  "dburi",
		Value: "",
		Usage: "database uri postgres://user:password@host:port/database",
	}
	emailListFlag := cli.StringFlag{
		Name:  "email",
		Value: "",
		Usage: "yaml file containing email distribution list",
	}

	app.Flags = []cli.Flag{logLevelFlag}
	app.Commands = []cli.Command{
		{
			Name:  "healthchecks",
			Usage: "HEALTHCHECK_FILE [--dburi DATABASE_URI] [--report REPORT_FILE] [--email DISTRIBUTION_FILE]",
			Flags: []cli.Flag{
				reportFileFlag,
				dburiFlag,
				emailListFlag,
			},
			Action: func(c *cli.Context) {
				updateLogLevel(c, conf)

				// variables to be populated by cli args
				var healthcheckPath string
				var reportPath string
				var emailListPath string

				if c.Args().Get(0) != "" {
					healthcheckPath = c.Args().Get(0)
				} else {
					log.Error("You must provide the path to the healthcheck file.")
					return
				}
				log.Info("Running health checks from ", healthcheckPath)

				if c.String("dburi") != "" {
					conf.SetDBURI(c.String("dburi"))
				}
				log.Debug("DB_URI: ", conf.DBURI())

				if c.String("report") != "" {
					reportPath = c.String("report")
					log.Debugf("Generating report at %v", reportPath)
				}

				if c.String("email") != "" {
					emailListPath = c.String("email")
					log.Debugf("Emailing report to %v", emailListPath)
				}

				healthcheckRunner(conf, healthcheckPath, reportPath, emailListPath)
				log.Info("Success!")
			},
		},
		{
			Name:    "pipeline",
			Aliases: []string{},
			Usage:   "Interact with GoCD pipeline",
			Subcommands: []cli.Command{
				{
					Name:  "push",
					Usage: "PATH [PIPELINE_GROUP]",
					Flags: []cli.Flag{
						gocdHostFlag,
					},
					Action: func(c *cli.Context) {
						updateLogLevel(c, conf)
						updateGOCDHost(c, conf, gocdServer)

						if len(c.Args()) > 0 {
							path := c.Args()[0]
							group := c.Args().Get(1)
							log.Infof("Pushing config from %v to pipeline group %v...", path, group)
							if err := gocd.Push(gocdServer, path, group); err != nil {
								log.Fatal("Failed to push pipeline config: ", err)
							}
							log.Info("Success!")
						} else {
							log.Fatal("A path to the pipeline config to push is required.")
						}
					},
				},
				{
					Name:  "pull",
					Usage: "PATH",
					Flags: []cli.Flag{
						gocdHostFlag,
					},
					Action: func(c *cli.Context) {
						updateLogLevel(c, conf)
						updateGOCDHost(c, conf, gocdServer)

						if len(c.Args()) > 0 {
							path := c.Args()[0]
							log.Infof("Pulling config from %v to %v...", gocdServer.URL(), path)
							if err := gocd.Pull(gocdServer, path); err != nil {
								log.Fatal("Failed to pull pipeline config: ", err)
							}
							log.Info("Success!")
						} else {
							log.Fatal("A path to pull the pipeline config to is required.")
						}
					},
				},
				{
					Name:  "clone",
					Usage: "PIPELINE_NAME PATH",
					Flags: []cli.Flag{
						gocdHostFlag,
					},
					Action: func(c *cli.Context) {
						updateLogLevel(c, conf)
						updateGOCDHost(c, conf, gocdServer)

						if len(c.Args()) > 1 {
							name := c.Args()[0]
							path := c.Args()[1]
							log.Infof("Cloning pipeline %v to %v...", name, path)
							if _, err := gocd.Clone(gocdServer, path, name); err != nil {
								log.Fatal("Failed to clone pipeline config: ", err)
							}
							log.Info("Success!")
						} else {
							log.Fatal("A pipeline name and a path to clone to are required.")
						}
					},
				},
			},
		},
	}

	app.Run(os.Args)
}

func updateLogLevel(c *cli.Context, config *config.Config) {
	if c.GlobalString("loglevel") != "" {
		config.SetLogLevel(c.GlobalString("loglevel"))
	}
}

func updateGOCDHost(c *cli.Context, config *config.Config, gocdServer *gocd.Server) {
	if c.String("host") != "" {
		config.SetGoCDHost(c.String("host"))
	}
	gocdServer = gocd.NewServerConfig(config.GOCDHost, config.GOCDPort, config.GOCDUser, config.GOCDPassword, config.GOCDTimeout)
}

func healthcheckRunner(config *config.Config, healthcheckPath string, reportPath string, emailListPath string) {
	healthChecks, err := healthcheck.ReadHealthCheckYAMLFromFile(healthcheckPath)
	if err != nil {
		log.Fatal("Failed to read healthchecks: ", err)
	}
	cxn := database.GetPGConnection(config.DBURI())

	// TODO the error returned from PreformHealthChecks determis a bad exit
	results, HCerrs := healthChecks.PreformHealthChecks(cxn)

	numErrors := 0
	fatal := false
	underscore.Each(HCerrs, func(n healthcheck.HCError, i int) {
		if strings.Contains(strings.ToUpper(n.Err), "FATAL") {
			fatal = true
		}
		if strings.Contains(strings.ToUpper(n.Err), "ERROR") {
			numErrors = numErrors + 1
		}
	})

	var elements []report.Element
	for _, val := range results {
		elements = append(elements, val)
	}

	// Make Templated report
	metadata := map[string]interface{}{
		"name":      healthChecks.Name,
		"db_name":   config.PgDatabase,
		"footer":    healthcheck.FooterHealthcheck,
		"timestamp": time.Now().Format(time.ANSIC),
		"status":    healthcheck.StatusHealthchecks(numErrors, fatal),
	}
	rs := report.Set{Elements: elements, Metadata: metadata}

	// Write report to file
	if reportPath != "" {
		prr := report.NewPongo2ReportRunnerFromString(healthcheck.TemplateHealthcheckHTML)
		reader, _ := prr.ReportReader(rs)
		fhr := report.FileHandler{Filename: reportPath}
		_ = fhr.HandleReport(reader)
	}

	// Email report
	if emailListPath != "" {
		prr := report.NewPongo2ReportRunnerFromString(healthcheck.TemplateHealthcheckHTML)
		df, err := report.ReadDistributionFormatYAMLFromFile(emailListPath)
		if err != nil {
			log.Fatal("Failed to read distribution format: ", err)
		}

		for _, level := range report.LogLevelArray {

			subjectStr := healthcheck.SubjectHealthcheck(healthChecks.Name, config.PgDatabase, config.PgHost, level, numErrors, fatal)

			logFilteredSet := report.FilterReportSet(rs, level)
			reader, _ := prr.ReportReader(logFilteredSet)
			recipients := df.GetEmails(level)

			if recipients != nil && len(recipients) != 0 && len(logFilteredSet.Elements) != 0 {
				log.Infof("Send %s to: %v", subjectStr, recipients)
				ehr := report.EmailHandler{
					SMTPHost:    config.SMTPHost,
					SMTPPort:    config.SMTPPort,
					SenderEmail: config.SMTPEmail,
					SenderName:  config.SMTPName,
					Subject:     subjectStr,
					Recipients:  recipients,
					HTML:        true,
				}
				err = ehr.HandleReport(reader)
				if err != nil {
					log.Warn("Failed to email report: ", err)
				}
			}
		}
	}

	// Bad Exit
	if HCerrs != nil {
		log.Fatal("Healthchecks Failed:\n", spew.Sdump(HCerrs))
	}
}
<commit_msg>better log messages<commit_after>package main

import (
	"os"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/ahl5esoft/golang-underscore"
	"github.com/cfpb/rhobot/config"
	"github.com/cfpb/rhobot/database"
	"github.com/cfpb/rhobot/gocd"
	"github.com/cfpb/rhobot/healthcheck"
	"github.com/cfpb/rhobot/report"
	"github.com/codegangsta/cli"
	"github.com/davecgh/go-spew/spew"
)

func main() {

	cli.VersionFlag = cli.BoolFlag{
		Name:  "print-version, V",
		Usage: "print only the version",
	}

	app := cli.NewApp()
	app.Name = "Rhobot"
	app.Usage = "Rhobot is a database development tool that uses DevOps best practices."
	app.Version = Version
	app.EnableBashCompletion = true

	conf := config.NewConfig()
	gocdServer := gocd.NewServerConfig(conf.GOCDHost, conf.GOCDPort, conf.GOCDUser, conf.GOCDPassword, conf.GOCDTimeout)

	logLevelFlag := cli.StringFlag{
		Name:  "loglevel, lvl",
		Value: "",
		Usage: "sets the log level for Rhobot",
	}
	gocdHostFlag := cli.StringFlag{
		Name:  "host",
		Value: "",
		Usage: "host of the GoCD server",
	}
	reportFileFlag := cli.StringFlag{
		Name:  "report",
		Value: "",
		Usage: "path to the healthcheck report",
	}
	dburiFlag := cli.StringFlag{
		Name:  "dburi",
		Value: "",
		Usage: "database uri postgres://user:password@host:port/database",
	}
	emailListFlag := cli.StringFlag{
		Name:  "email",
		Value: "",
		Usage: "yaml file containing email distribution list",
	}

	app.Flags = []cli.Flag{logLevelFlag}
	app.Commands = []cli.Command{
		{
			Name:  "healthchecks",
			Usage: "HEALTHCHECK_FILE [--dburi DATABASE_URI] [--report REPORT_FILE] [--email DISTRIBUTION_FILE]",
			Flags: []cli.Flag{
				reportFileFlag,
				dburiFlag,
				emailListFlag,
			},
			Action: func(c *cli.Context) {
				updateLogLevel(c, conf)

				// variables to be populated by cli args
				var healthcheckPath string
				var reportPath string
				var emailListPath string

				if c.Args().Get(0) != "" {
					healthcheckPath = c.Args().Get(0)
				} else {
					log.Error("You must provide the path to the healthcheck file.")
					return
				}
				log.Info("Running health checks from ", healthcheckPath)

				if c.String("dburi") != "" {
					conf.SetDBURI(c.String("dburi"))
				}
				log.Debug("DB_URI: ", conf.DBURI())

				if c.String("report") != "" {
					reportPath = c.String("report")
					log.Infof("Generating report at %v", reportPath)
				}

				if c.String("email") != "" {
					emailListPath = c.String("email")
					log.Infof("Emailing report to %v", emailListPath)
				}

				healthcheckRunner(conf, healthcheckPath, reportPath, emailListPath)
				log.Info("Success!")
			},
		},
		{
			Name:    "pipeline",
			Aliases: []string{},
			Usage:   "Interact with GoCD pipeline",
			Subcommands: []cli.Command{
				{
					Name:  "push",
					Usage: "PATH [PIPELINE_GROUP]",
					Flags: []cli.Flag{
						gocdHostFlag,
					},
					Action: func(c *cli.Context) {
						updateLogLevel(c, conf)
						updateGOCDHost(c, conf, gocdServer)

						if len(c.Args()) > 0 {
							path := c.Args()[0]
							group := c.Args().Get(1)
							log.Infof("Pushing config from %v to pipeline group %v...", path, group)
							if err := gocd.Push(gocdServer, path, group); err != nil {
								log.Fatal("Failed to push pipeline config: ", err)
							}
							log.Info("Success!")
						} else {
							log.Fatal("A path to the pipeline config to push is required.")
						}
					},
				},
				{
					Name:  "pull",
					Usage: "PATH",
					Flags: []cli.Flag{
						gocdHostFlag,
					},
					Action: func(c *cli.Context) {
						updateLogLevel(c, conf)
						updateGOCDHost(c, conf, gocdServer)

						if len(c.Args()) > 0 {
							path := c.Args()[0]
							log.Infof("Pulling config from %v to %v...", gocdServer.URL(), path)
							if err := gocd.Pull(gocdServer, path); err != nil {
								log.Fatal("Failed to pull pipeline config: ", err)
							}
							log.Info("Success!")
						} else {
							log.Fatal("A path to pull the pipeline config to is required.")
						}
					},
				},
				{
					Name:  "clone",
					Usage: "PIPELINE_NAME PATH",
					Flags: []cli.Flag{
						gocdHostFlag,
					},
					Action: func(c *cli.Context) {
						updateLogLevel(c, conf)
						updateGOCDHost(c, conf, gocdServer)

						if len(c.Args()) > 1 {
							name := c.Args()[0]
							path := c.Args()[1]
							log.Infof("Cloning pipeline %v to %v...", name, path)
							if _, err := gocd.Clone(gocdServer, path, name); err != nil {
								log.Fatal("Failed to clone pipeline config: ", err)
							}
							log.Info("Success!")
						} else {
							log.Fatal("A pipeline name and a path to clone to are required.")
						}
					},
				},
			},
		},
	}

	app.Run(os.Args)
}

func updateLogLevel(c *cli.Context, config *config.Config) {
	if c.GlobalString("loglevel") != "" {
		config.SetLogLevel(c.GlobalString("loglevel"))
	}
}

func updateGOCDHost(c *cli.Context, config *config.Config, gocdServer *gocd.Server) {
	if c.String("host") != "" {
		config.SetGoCDHost(c.String("host"))
	}
	gocdServer = gocd.NewServerConfig(config.GOCDHost, config.GOCDPort, config.GOCDUser, config.GOCDPassword, config.GOCDTimeout)
}

func healthcheckRunner(config *config.Config, healthcheckPath string, reportPath string, emailListPath string) {
	healthChecks, err := healthcheck.ReadHealthCheckYAMLFromFile(healthcheckPath)
	if err != nil {
		log.Fatal("Failed to read healthchecks: ", err)
	}
	cxn := database.GetPGConnection(config.DBURI())

	// TODO the error returned from PreformHealthChecks determis a bad exit
	results, HCerrs := healthChecks.PreformHealthChecks(cxn)

	numErrors := 0
	fatal := false
	underscore.Each(HCerrs, func(n healthcheck.HCError, i int) {
		if strings.Contains(strings.ToUpper(n.Err), "FATAL") {
			fatal = true
		}
		if strings.Contains(strings.ToUpper(n.Err), "ERROR") {
			numErrors = numErrors + 1
		}
	})

	var elements []report.Element
	for _, val := range results {
		elements = append(elements, val)
	}

	// Make Templated report
	metadata := map[string]interface{}{
		"name":      healthChecks.Name,
		"db_name":   config.PgDatabase,
		"footer":    healthcheck.FooterHealthcheck,
		"timestamp": time.Now().Format(time.ANSIC),
		"status":    healthcheck.StatusHealthchecks(numErrors, fatal),
	}
	rs := report.Set{Elements: elements, Metadata: metadata}

	// Write report to file
	if reportPath != "" {
		prr := report.NewPongo2ReportRunnerFromString(healthcheck.TemplateHealthcheckHTML)
		reader, _ := prr.ReportReader(rs)
		fhr := report.FileHandler{Filename: reportPath}
		err = fhr.HandleReport(reader)
		if err != nil {
			log.Error("error writing report to PG database: ", err)
		}
	}

	// Email report
	if emailListPath != "" {
		prr := report.NewPongo2ReportRunnerFromString(healthcheck.TemplateHealthcheckHTML)
		df, err := report.ReadDistributionFormatYAMLFromFile(emailListPath)
		if err != nil {
			log.Fatal("Failed to read distribution format: ", err)
		}

		for _, level := range report.LogLevelArray {

			subjectStr := healthcheck.SubjectHealthcheck(healthChecks.Name, config.PgDatabase, config.PgHost, level, numErrors, fatal)

			logFilteredSet := report.FilterReportSet(rs, level)
			reader, _ := prr.ReportReader(logFilteredSet)
			recipients := df.GetEmails(level)

			if recipients != nil && len(recipients) != 0 && len(logFilteredSet.Elements) != 0 {
				log.Infof("Send %s to: %v", subjectStr, recipients)
				ehr := report.EmailHandler{
					SMTPHost:    config.SMTPHost,
					SMTPPort:    config.SMTPPort,
					SenderEmail: config.SMTPEmail,
					SenderName:  config.SMTPName,
					Subject:     subjectStr,
					Recipients:  recipients,
					HTML:        true,
				}
				err = ehr.HandleReport(reader)
				if err != nil {
					log.Error("Failed to email report: ", err)
				}
			}
		}
	}

	// Bad Exit
	if HCerrs != nil {
		log.Fatal("Healthchecks Failed:\n", spew.Sdump(HCerrs))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"os"
	"os/exec"
	"time"
)

type ExportedImage struct {
	Path         string
	JsonPath     string
	VersionPath  string
	LayerTarPath string
	LayerDirPath string
	LayerConfig  *LayerConfig
}

func newLayerConfig(id, parent, comment string) *LayerConfig {
	return &LayerConfig{
		Id:            id,
		Parent:        parent,
		Comment:       comment,
		Created:       time.Now().UTC(),
		DockerVersion: "0.1.2",
		Architecture:  "x86_64",
	}
}

func (e *ExportedImage) WriteVersion() error {
	fp := e.VersionPath
	f, err := os.Create(fp)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = f.WriteString("1.0")
	if err != nil {
		return err
	}

	return err
}

func (e *ExportedImage) WriteJson() error {
	fp := e.JsonPath
	f, err := os.Create(fp)
	if err != nil {
		return err
	}
	defer f.Close()

	jb, err := json.Marshal(e.LayerConfig)
	if err != nil {
		return err
	}

	_, err = f.WriteString(string(jb))
	if err != nil {
		return err
	}

	return err
}

func (e *ExportedImage) CreateDirs() error {
	return os.MkdirAll(e.Path, 0755)
}

func (e *ExportedImage) TarLayer() error {
	cwd, err := os.Getwd()
	if err != nil {
		return err
	}

	err = os.Chdir(e.LayerDirPath)
	if err != nil {
		return err
	}
	defer os.Chdir(cwd)

	cmd := exec.Command("sudo", "/bin/bash", "-c", "tar cvf ../layer.tar *")
	out, err := cmd.CombinedOutput()
	if err != nil {
		println(string(out))
		return err
	}
	return nil
}

func (e *ExportedImage) RemoveLayerDir() error {
	return os.RemoveAll(e.LayerDirPath)
}

func (e *ExportedImage) ExtractLayerDir() error {
	err := os.MkdirAll(e.LayerDirPath, 0755)
	if err != nil {
		return err
	}

	out, err := extractTar(e.LayerTarPath, e.LayerDirPath)
	if err != nil {
		println(string(out))
		return err
	}
	return nil
}
<commit_msg>tar up dotfiles too<commit_after>package main

import (
	"encoding/json"
	"os"
	"os/exec"
	"time"
)

type ExportedImage struct {
	Path         string
	JsonPath     string
	VersionPath  string
	LayerTarPath string
	LayerDirPath string
	LayerConfig  *LayerConfig
}

func newLayerConfig(id, parent, comment string) *LayerConfig {
	return &LayerConfig{
		Id:            id,
		Parent:        parent,
		Comment:       comment,
		Created:       time.Now().UTC(),
		DockerVersion: "0.1.2",
		Architecture:  "x86_64",
	}
}

func (e *ExportedImage) WriteVersion() error {
	fp := e.VersionPath
	f, err := os.Create(fp)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = f.WriteString("1.0")
	if err != nil {
		return err
	}

	return err
}

func (e *ExportedImage) WriteJson() error {
	fp := e.JsonPath
	f, err := os.Create(fp)
	if err != nil {
		return err
	}
	defer f.Close()

	jb, err := json.Marshal(e.LayerConfig)
	if err != nil {
		return err
	}

	_, err = f.WriteString(string(jb))
	if err != nil {
		return err
	}

	return err
}

func (e *ExportedImage) CreateDirs() error {
	return os.MkdirAll(e.Path, 0755)
}

func (e *ExportedImage) TarLayer() error {
	cwd, err := os.Getwd()
	if err != nil {
		return err
	}

	err = os.Chdir(e.LayerDirPath)
	if err != nil {
		return err
	}
	defer os.Chdir(cwd)

	cmd := exec.Command("sudo", "/bin/bash", "-c", "tar cvf ../layer.tar ./")
	out, err := cmd.CombinedOutput()
	if err != nil {
		println(string(out))
		return err
	}
	return nil
}

func (e *ExportedImage) RemoveLayerDir() error {
	return os.RemoveAll(e.LayerDirPath)
}

func (e *ExportedImage) ExtractLayerDir() error {
	err := os.MkdirAll(e.LayerDirPath, 0755)
	if err != nil {
		return err
	}

	out, err := extractTar(e.LayerTarPath, e.LayerDirPath)
	if err != nil {
		println(string(out))
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tiff

import (
	"image"
	"image/color"
	"reflect"
)

type Image struct {
	Rect     image.Rectangle
	Channels int
	Kind     reflect.Kind // bool/uint*/int*/float*/Complex*/string
	Pix      interface{}  // At(x,y): (Pix.([]T))[y*Stride+x:][:Channels]
	Stride   int
}

func NewImage(r image.Rectangle, channels int, kind reflect.Kind) *Image {
	var pix interface{}
	var stride = r.Dx() * channels
	switch kind {
	case reflect.Bool:
		pix = make([]bool, stride*r.Dy())
	case reflect.Int:
		pix = make([]int, stride*r.Dy())
	case reflect.Int8:
		pix = make([]int8, stride*r.Dy())
	case reflect.Int16:
		pix = make([]int16, stride*r.Dy())
	case reflect.Int32:
		pix = make([]int32, stride*r.Dy())
	case reflect.Int64:
		pix = make([]int64, stride*r.Dy())
	case reflect.Uint:
		pix = make([]uint, stride*r.Dy())
	case reflect.Uint8:
		pix = make([]uint8, stride*r.Dy())
	case reflect.Uint16:
		pix = make([]uint16, stride*r.Dy())
	case reflect.Uint32:
		pix = make([]uint32, stride*r.Dy())
	case reflect.Uint64:
		pix = make([]uint64, stride*r.Dy())
	case reflect.Complex64:
		pix = make([]complex64, stride*r.Dy())
	case reflect.Complex128:
		pix = make([]complex128, stride*r.Dy())
	case reflect.String:
		pix = make([]string, stride*r.Dy())
	default:
		panic("tiff: NewImage, unknown kind = " + kind.String())
	}
	return &Image{
		Rect:     r,
		Channels: channels,
		Kind:     kind,
		Pix:      pix,
		Stride:   r.Dx() * channels,
	}
}

func (p *Image) Bounds() image.Rectangle {
	return p.Rect
}

func (p *Image) ColorModel() color.Model {
	return nil
}

func (p *Image) At(x, y int) color.Color {
	return nil
}

func (p *Image) Set(x, y int, c color.Color) {
	//
}

func (p *Image) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
}

func (p *Image) Slice(low_high_max ...int) interface{} {
	return nil
}

func (p *Image) SubImage(r image.Rectangle) image.Image {
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &Image{}
	}
	i := p.PixOffset(r.Min.X, r.Min.Y)
	return &Image{
		Rect:     r,
		Channels: p.Channels,
		Kind:     p.Kind,
		Pix:      p.Slice(i),
		Stride:   p.Stride,
	}
}

func (p *Image) StdImage() image.Image {
	return nil
}

func (p *Image) Opaque() bool {
	return true
}
<commit_msg>redesign Image format<commit_after>// Copyright 2015 <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tiff

import (
	"image"
	"image/color"
	"reflect"
)

type Image struct {
	// Pix holds the image's pixels, as pixel values in big-endian order format. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*PixelSize].
	Pix []byte
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
	Stride int
	// Rect is the image's bounds.
	Rect image.Rectangle

	// 1:Gray, 2:GrayA, 3:RGB, 4:RGBA
	Channels int
	// Uint8/Uint16/Int32/Int64/Float32/Float64
	DataType reflect.Kind
}

func NewImage(r image.Rectangle, channels int, kind reflect.Kind) *Image {
	return nil
}

func (p *Image) Bounds() image.Rectangle {
	return p.Rect
}

func (p *Image) ColorModel() color.Model {
	return nil
}

func (p *Image) At(x, y int) color.Color {
	return nil
}

func (p *Image) Set(x, y int, c color.Color) {
	//
}

func (p *Image) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
}

func (p *Image) Slice(low_high_max ...int) interface{} {
	return nil
}

func (p *Image) SubImage(r image.Rectangle) image.Image {
	return nil
}

func (p *Image) StdImage() image.Image {
	return nil
}

func (p *Image) Opaque() bool {
	return true
}
<|endoftext|>


<commit_before>package captcha

import (
	"image"
	"image/png"
	"io"
	"os"
	"rand"
)

const (
	maxSkew = 3
)

type CaptchaImage struct {
	*image.NRGBA
	primaryColor image.NRGBAColor
	numberWidth  int
	numberHeight int
	dotSize    int
}

func (img *CaptchaImage) calculateSizes(width, height, ncount int) {
	// Goal: fit all numbers into the image.
	// Convert everything to floats for calculations.
	w := float64(width)
	h := float64(height)
	// fontWidth includes 1-dot spacing between numbers
	fw := float64(fontWidth) + 1
	fh := float64(fontHeight)
	nc := float64(ncount)
	// Calculate width of a sigle number if we only take into
	// account the width
	nw := w / nc
	// Calculate the number height from this width
	nh := nw * fh / fw
	// Number height too large?
	if nh > h {
		// Fit numbers based on height
		nh = h
		nw = fw/fh * nh
	}
	// Calculate dot size
	img.dotSize = int(nh / fh)
	// Save everything, making actual width smaller by 1 dot,
	// to account for spacing between numbers
	img.numberWidth = int(nw)
	img.numberHeight = int(nh) - img.dotSize
}

func NewImage(numbers []byte, width, height int) *CaptchaImage {
	img := new(CaptchaImage)
	img.NRGBA = image.NewNRGBA(width, height)
	img.primaryColor = image.NRGBAColor{uint8(rand.Intn(50)), uint8(rand.Intn(50)), uint8(rand.Intn(128)), 0xFF}
	// We need some space, so calculate border
	var border int
	if width > height {
		border = height/5
	} else {
		border = width/5
	}
	bwidth := width-border*2
	bheight := height-border*2
	img.calculateSizes(bwidth, bheight, len(numbers))
	// Center numbers in image
	x := width/2 - (img.numberWidth*len(numbers))/2 - img.dotSize
	y := height/2 - img.numberHeight/2 + img.dotSize/2
	setRandomBrightness(&img.primaryColor, 180)
	for _, n := range numbers {
		//y = rand.Intn(dotSize * 4)
		img.drawNumber(font[n], x, y)
		x += img.numberWidth + img.dotSize
	}
	//img.strikeThrough(img.primaryColor)
	return img
}

func NewRandomImage(width, height int) (img *CaptchaImage, numbers []byte) {
	numbers = randomNumbers()
	img = NewImage(numbers, width, height)
	return
}

func (img *CaptchaImage) PNGEncode(w io.Writer) os.Error {
	return png.Encode(w, img)
}

func (img *CaptchaImage) drawHorizLine(color image.Color, fromX, toX, y int) {
	for x := fromX; x <= toX; x++ {
		img.Set(x, y, color)
	}
}

func (img *CaptchaImage) drawCircle(color image.Color, x, y, radius int) {
	f := 1 - radius
	dfx := 1
	dfy := -2 * radius
	xx := 0
	yy := radius

	img.Set(x, y+radius, color)
	img.Set(x, y-radius, color)
	img.drawHorizLine(color, x-radius, x+radius, y)

	for xx < yy {
		if f >= 0 {
			yy--
			dfy += 2
			f += dfy
		}
		xx++
		dfx += 2
		f += dfx
		img.drawHorizLine(color, x-xx, x+xx, y+yy)
		img.drawHorizLine(color, x-xx, x+xx, y-yy)
		img.drawHorizLine(color, x-yy, x+yy, y+xx)
		img.drawHorizLine(color, x-yy, x+yy, y-xx)
	}
}

func min3(x, y, z uint8) (o uint8) {
	o = x
	if y < o {
		o = y
	}
	if z < o {
		o = z
	}
	return
}

func max3(x, y, z uint8) (o uint8) {
	o = x
	if y > o {
		o = y
	}
	if z > o {
		o = z
	}
	return
}

func setRandomBrightness(c *image.NRGBAColor, max uint8) {
	minc := min3(c.R, c.G, c.B)
	maxc := max3(c.R, c.G, c.B)
	if maxc > max {
		return
	}
	n := rand.Intn(int(max-maxc)) - int(minc)
	c.R = uint8(int(c.R) + n)
	c.G = uint8(int(c.G) + n)
	c.B = uint8(int(c.B) + n)
}

func rnd(from, to int) int {
	return rand.Intn(to+1-from) + from
}

func (img *CaptchaImage) fillWithCircles(color image.NRGBAColor, n, maxradius int) {
	maxx := img.Bounds().Max.X
	maxy := img.Bounds().Max.Y
	for i := 0; i < n; i++ {
		setRandomBrightness(&color, 255)
		r := rnd(1, maxradius)
		img.drawCircle(color, rnd(r, maxx), rnd(r, maxy), r)
	}
}

// func (img *CaptchaImage) strikeThrough(color image.Color) {
// 	r := 0
// 	maxx := img.Bounds().Max.X
// 	maxy := img.Bounds().Max.Y
// 	y := rnd(maxy/3, maxy-maxy/3)
// 	for x := 0; x < maxx; x += r {
// 		r = rnd(1, dotSize/2-1)
// 		y += rnd(-2, 2)
// 		if y <= 0 || y >= maxy {
// 			y = rnd(maxy/3, maxy-maxy/3)
// 		}
// 		img.drawCircle(color, x, y, r)
// 	}
// }

func (img *CaptchaImage) drawNumber(number []byte, x, y int) {
	//skf := rand.Intn(maxSkew) - maxSkew/2
	//if skf < 0 {
	//	x -= skf * numberHeight
	//}
	//d := img.numberWidth / fontWidth // number height is ignored
	//println(img.numberWidth)
	minr := img.dotSize/2 // minumum radius
	maxr := img.dotSize // maximum radius
	// x += srad
	// y += srad
	for yy := 0; yy < fontHeight; yy++ {
		for xx := 0; xx < fontWidth; xx++ {
			if number[yy*fontWidth+xx] != 1 {
				continue
			}
			// introduce random variations
			or := rnd(minr, maxr)
			ox := x + (xx * maxr) //+ rnd(0, or/2)
			oy := y + (yy * maxr) //+ rnd(0, or/2)
			img.drawCircle(img.primaryColor, ox, oy, or)
		}
		//x += skf
	}
}
<commit_msg>Refactored image captcha ready, and documented.<commit_after>package captcha

import (
	"image"
	"image/png"
	"io"
	"os"
	"rand"
)

const (
	maxSkew = 2
	// Standard width and height for captcha image
	StdWidth  = 300
	StdHeight = 80
)

type CaptchaImage struct {
	*image.NRGBA
	primaryColor image.NRGBAColor
	numberWidth  int
	numberHeight int
	dotSize      int
}

// NewImage returns a new captcha image of the given width and height with the
// given slice of numbers, where each number is 0-9.
func NewImage(numbers []byte, width, height int) *CaptchaImage {
	img := new(CaptchaImage)
	img.NRGBA = image.NewNRGBA(width, height)
	img.primaryColor = image.NRGBAColor{uint8(rand.Intn(50)), uint8(rand.Intn(50)), uint8(rand.Intn(128)), 0xFF}
	// We need some space, so calculate border
	var border int
	if width > height {
		border = height / 5
	} else {
		border = width / 5
	}
	bwidth := width - border*2
	bheight := height - border*2
	img.calculateSizes(bwidth, bheight, len(numbers))
	// Background
	img.fillWithCircles(10, img.dotSize)
	maxx := width - (img.numberWidth+img.dotSize)*len(numbers) - img.dotSize
	maxy := height - img.numberHeight - img.dotSize*2
	x := rnd(img.dotSize*2, maxx)
	y := rnd(img.dotSize*2, maxy)
	setRandomBrightness(&img.primaryColor, 180)
	for _, n := range numbers {
		img.drawNumber(font[n], x, y)
		x += img.numberWidth + img.dotSize
	}
	img.strikeThrough()
	return img
}

// NewRandomImage generates random numbers and returns a new captcha image of
// the given width and height with those numbers printed on it, and the numbers
// themselves.
func NewRandomImage(width, height int) (img *CaptchaImage, numbers []byte) {
	numbers = randomNumbers()
	img = NewImage(numbers, width, height)
	return
}

// PNGEncode writes captcha image in PNG format into the given writer.
func (img *CaptchaImage) PNGEncode(w io.Writer) os.Error {
	return png.Encode(w, img)
}

func (img *CaptchaImage) calculateSizes(width, height, ncount int) {
	// Goal: fit all numbers into the image.
	// Convert everything to floats for calculations.
	w := float64(width)
	h := float64(height)
	// fontWidth includes 1-dot spacing between numbers
	fw := float64(fontWidth) + 1
	fh := float64(fontHeight)
	nc := float64(ncount)
	// Calculate width of a sigle number if we only take into
	// account the width
	nw := w / nc
	// Calculate the number height from this width
	nh := nw * fh / fw
	// Number height too large?
	if nh > h {
		// Fit numbers based on height
		nh = h
		nw = fw / fh * nh
	}
	// Calculate dot size
	img.dotSize = int(nh / fh)
	// Save everything, making actual width smaller by 1 dot,
	// to account for spacing between numbers
	img.numberWidth = int(nw)
	img.numberHeight = int(nh) - img.dotSize
}

func (img *CaptchaImage) drawHorizLine(color image.Color, fromX, toX, y int) {
	for x := fromX; x <= toX; x++ {
		img.Set(x, y, color)
	}
}

func (img *CaptchaImage) drawCircle(color image.Color, x, y, radius int) {
	f := 1 - radius
	dfx := 1
	dfy := -2 * radius
	xx := 0
	yy := radius

	img.Set(x, y+radius, color)
	img.Set(x, y-radius, color)
	img.drawHorizLine(color, x-radius, x+radius, y)

	for xx < yy {
		if f >= 0 {
			yy--
			dfy += 2
			f += dfy
		}
		xx++
		dfx += 2
		f += dfx
		img.drawHorizLine(color, x-xx, x+xx, y+yy)
		img.drawHorizLine(color, x-xx, x+xx, y-yy)
		img.drawHorizLine(color, x-yy, x+yy, y+xx)
		img.drawHorizLine(color, x-yy, x+yy, y-xx)
	}
}

func min3(x, y, z uint8) (o uint8) {
	o = x
	if y < o {
		o = y
	}
	if z < o {
		o = z
	}
	return
}

func max3(x, y, z uint8) (o uint8) {
	o = x
	if y > o {
		o = y
	}
	if z > o {
		o = z
	}
	return
}

func setRandomBrightness(c *image.NRGBAColor, max uint8) {
	minc := min3(c.R, c.G, c.B)
	maxc := max3(c.R, c.G, c.B)
	if maxc > max {
		return
	}
	n := rand.Intn(int(max-maxc)) - int(minc)
	c.R = uint8(int(c.R) + n)
	c.G = uint8(int(c.G) + n)
	c.B = uint8(int(c.B) + n)
}

func rnd(from, to int) int {
	return rand.Intn(to+1-from) + from
}

func (img *CaptchaImage) fillWithCircles(n, maxradius int) {
	color := img.primaryColor
	maxx := img.Bounds().Max.X
	maxy := img.Bounds().Max.Y
	for i := 0; i < n; i++ {
		setRandomBrightness(&color, 255)
		r := rnd(1, maxradius)
		img.drawCircle(color, rnd(r, maxx-r), rnd(r, maxy-r), r)
	}
}

func (img *CaptchaImage) strikeThrough() {
	r := 0
	maxx := img.Bounds().Max.X
	maxy := img.Bounds().Max.Y
	y := rnd(maxy/3, maxy-maxy/3)
	for x := 0; x < maxx; x += r {
		r = rnd(1, img.dotSize/2-1)
		y += rnd(-img.dotSize/2, img.dotSize/2)
		if y <= 0 || y >= maxy {
			y = rnd(maxy/3, maxy-maxy/3)
		}
		img.drawCircle(img.primaryColor, x, y, r)
	}
}

func (img *CaptchaImage) drawNumber(number []byte, x, y int) {
	skf := rand.Float64() * float64(rnd(-maxSkew, maxSkew))
	xs := float64(x)
	minr := img.dotSize / 2               // minumum radius
	maxr := img.dotSize/2 + img.dotSize/4 // maximum radius
	y += rnd(-minr, minr)
	for yy := 0; yy < fontHeight; yy++ {
		for xx := 0; xx < fontWidth; xx++ {
			if number[yy*fontWidth+xx] != 1 {
				continue
			}
			// introduce random variations
			or := rnd(minr, maxr)
			ox := x + (xx * img.dotSize) + rnd(0, or/2)
			oy := y + (yy * img.dotSize) + rnd(0, or/2)
			img.drawCircle(img.primaryColor, ox, oy, or)
		}
		xs += skf
		x = int(xs)
	}
}
<|endoftext|>


<commit_before>package rhymer

import (
    "fmt"
    "os"
    "bufio"
    "strings"
)

type Pronounce struct {
    phonemes []string
}

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func main() {
    // Read the file
    file, err := os.Open("cmudict/cmudict")
    check(err)
    scanner := bufio.NewScanner(file)
    defer file.Close()
    check(err)

    dictionary := make(map[string][]Pronounce)

    // Scan the file line by line
    for scanner.Scan() {
        // Split the line by whitespace
        f := strings.Fields(scanner.Text())
        // f[0] is the string, and f[2:] is the pronounciation

        dictionary[f[0]] = []Pronounce{Pronounce{f[2:]}}
    }

    // fmt.Println(dictionary)
    fmt.Println(dictionary["HELLO"][0].phonemes[2])
}<commit_msg>rhymer pronounce and rhymes<commit_after>package rhymer

import (
    "os"
    "bufio"
    "strings"
    "runtime"
    "path"
)

type rhymer struct {
    dictionary map[string][][]string
}

func (r *rhymer) Pronounce(s string) [][]string {
    return r.dictionary[strings.ToUpper(s)]
}

func (r *rhymer) Rhymes(s1, s2 string) int {
    s1 = strings.ToUpper(s1)
    s2 = strings.ToUpper(s2)
    if len(r.Pronounce(s1)) == 0 || len(r.Pronounce(s2)) == 0 {
        return -1
    }

    rhymes := 0

    for _, v := range r.Pronounce(s1) {
        for _, w := range r.Pronounce(s2) {
            if pronounceRhymes(v, w) {
                rhymes = 1
            }
        }
    }
    return rhymes
}

func vowelSound(s string) bool {
    switch s[0] {
    case 'A', 'E', 'I', 'O', 'U':
        return true
    default:
        return false
    }
}

func pronounceRhymes(a1, a2 []string) bool {
    // Find the shorter word
    var longer []string
    var shorter []string
    if len(a1) > len(a2) {
        longer = a1
        shorter = a2
    } else {
        longer = a2
        shorter = a1
    }

    diff := len(longer) - len(shorter)
    full := true

    offset := 1

    // We need to match the entire shorter word if it starts with a vowel
    if vowelSound(shorter[0]) {
        offset = 0
    }

    // Check if the words sound the same, ignoring the first constanant sound of the shorter word
    for i, v := range shorter[offset:] {
        if longer[diff+i+offset] != v {
            full = false
        }
    }

    return full
}

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func NewRhymer() *rhymer {
    r := new(rhymer)

    // Read the file
    _, filename, _, _ := runtime.Caller(0)
    file, err := os.Open(path.Join(path.Dir(filename), "cmudict", "cmudict"))
    check(err)
    scanner := bufio.NewScanner(file)
    defer file.Close()
    check(err)

    r.dictionary = make(map[string][][]string)

    // Scan the file line by line
    for scanner.Scan() {
        // Split the line by whitespace
        f := strings.Fields(scanner.Text())
        // Trim the stress numbers
        for i, v := range f[2:] {
            f[i+2] = strings.TrimRight(v, "012")
        }
        // f[0] is the string, and f[2:] is the pronounciation
        r.dictionary[f[0]] = append(r.dictionary[f[0]], f[2:])
    }

    return r
}<|endoftext|>


<commit_before>package ripple

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"math/big"
	"strconv"
)

type Amount struct {
	Currency string
	Issuer   string
	Value    big.Rat
}

func (a *Amount) UnmarshalJSON(b []byte) (err error) {

	// Try interpret as IOU
	var m map[string]string
	err = json.Unmarshal(b, &m)
	if err == nil {
		a.Currency = m["currency"]
		_, success := a.Value.SetString(m["value"])
		if !success {
			return fmt.Errorf("Could not interpret value: %s", m["value"])
		}
		a.Issuer = m["issuer"]
		return
	}

	// Try interpret as XRP in drips
	var s string
	err = json.Unmarshal(b, &s)
	if err == nil {
		dripValue, success := a.Value.SetString(s)
		if !success {
			return fmt.Errorf("Could not interpret value: %s", s)
		}
		a.Value.Quo(dripValue, big.NewRat(1000000, 1))
		a.Currency = "XRP"
		return
	}

	return fmt.Errorf("Could not unmarshal amount: %s", b)
}

type Transaction struct {
	Account         string
	Amount          Amount
	Date            int
	Destination     string
	DestinationTag  int
	Fee             string
	Flags           int
	Hash            string
	SendMax         *Amount
	Sequence        int
	SingingPubKey   string
	TransactionType string
	TxnSignature    string
}

type Message struct {
	LedgerHash  string `json:"ledger_hash"`
	LedgerIndex int    `json:"ledger_index"`
	Status      string
	Transaction *Transaction
	Type        string
}

func (m *Message) String() string {
	if m.Type == "transaction" {
		t := m.Transaction

		if t.TransactionType == "Payment" {
			return ("Payment " + t.Hash +
				" from " + t.Account + " to " +
				t.Destination + " " +
				strconv.Itoa(t.DestinationTag) + " " +
				t.Amount.Value.FloatString(5) + " " +
				t.Amount.Currency)
		}

		return t.TransactionType + " " + t.Hash
	}

	return m.Type
}

type Connection struct {
	Messages chan *Message

	conn *websocket.Conn
}

func (r *Connection) Connect(uri string) (err error) {

	// Connect to websocket server
	r.conn, err = websocket.Dial(uri, "", "http://localhost")
	if err != nil {
		return err
	}

	// Subscribe to all transactions
	msg := "{\"command\":\"subscribe\",\"id\":1,\"streams\":[\"transactions\"]}"
	err = websocket.Message.Send(r.conn, msg)
	if err != nil {
		return err
	}

	// Wait for ack
	var m Message
	err = websocket.JSON.Receive(r.conn, &m)
	if err != nil {
		return err
	}

	if m.Type != "response" || m.Status != "success" {
		return errors.New("Failed to subscribe")
	}

	return
}

func (r *Connection) Monitor() {
	for {
		var err error
		var m Message
		err = websocket.JSON.Receive(r.conn, &m)
		if err != nil {
			if err == io.EOF {
				// graceful shutdown by server
				break
			}
			fmt.Println("Could not receive: " + err.Error())
			break
		}
		r.Messages <- &m
	}
}
<commit_msg>Support monitoring transactions from an aribtrary past ledger<commit_after>package ripple

import (
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"math/big"
	"strconv"
	"time"
)

type Amount struct {
	Currency string
	Issuer   string
	Value    big.Rat
}

func (a *Amount) UnmarshalJSON(b []byte) (err error) {

	// Try interpret as IOU
	var m map[string]string
	err = json.Unmarshal(b, &m)
	if err == nil {
		a.Currency = m["currency"]
		_, success := a.Value.SetString(m["value"])
		if !success {
			return fmt.Errorf("Could not interpret value: %s", m["value"])
		}
		a.Issuer = m["issuer"]
		return
	}

	// Try interpret as XRP in drips
	var s string
	err = json.Unmarshal(b, &s)
	if err == nil {
		dripValue, success := a.Value.SetString(s)
		if !success {
			return fmt.Errorf("Could not interpret value: %s", s)
		}
		a.Value.Quo(dripValue, big.NewRat(1000000, 1))
		a.Currency = "XRP"
		return
	}

	return fmt.Errorf("Could not unmarshal amount: %s", b)
}

type Transaction struct {
	Account         string
	Amount          Amount
	Date            int
	Destination     string
	DestinationTag  int
	Fee             string
	Flags           int
	Hash            string
	SendMax         *Amount
	Sequence        int
	SingingPubKey   string
	TransactionType string
	TxnSignature    string
}

func (t *Transaction) String() string {
	if t.TransactionType == "Payment" {
		return ("Payment " + t.Hash +
			" from " + t.Account + " to " +
			t.Destination + " " +
			strconv.Itoa(t.DestinationTag) + " " +
			t.Amount.Value.FloatString(5) + " " +
			t.Amount.Currency)
	}

	return t.TransactionType + " " + t.Hash
}

type Ledger struct {
	Accepted     bool
	CloseTime    uint64 `json:"close_time"`
	Closed       bool
	Hash         string
	Index        string `json:"ledger_index"`
	ParentHash   string
	Transactions []Transaction
}

type Result struct {
	Ledger *Ledger
}

type Message struct {
	Id           int
	Type         string
	Result       *Result
	Status       string
	Error        string
	LedgerHash   string `json:"ledger_hash"`
	LedgerIndex  uint64 `json:"ledger_index"`
	LedgerTime   uint64 `json:"ledger_time"`
	Transaction  *Transaction
	TxnCount     int    `json:"txn_count"`
	ServerStatus string `json:"server_status"`
}

type Connection struct {
	Transactions chan *Transaction

	conn *websocket.Conn
}

func (r *Connection) Connect(uri string) (err error) {

	// Connect to websocket server
	r.conn, err = websocket.Dial(uri, "", "http://localhost")
	if err != nil {
		return err
	}

	// Subscribe to all transactions
	msg := "{\"command\":\"subscribe\",\"id\":1,\"streams\":[\"server\", \"ledger\", \"transactions\"]}"
	err = websocket.Message.Send(r.conn, msg)
	if err != nil {
		return err
	}

	// Wait for ack
	var m Message
	err = websocket.JSON.Receive(r.conn, &m)
	if err != nil {
		return err
	}

	if m.Type != "response" || m.Status != "success" {
		return errors.New("Failed to subscribe")
	}

	return
}

func (r *Connection) getPastLedgers(startLedger uint64, endLedger uint64) {
	// Asks the server for each ledger between start and end, inclusive

	if startLedger > endLedger {
		panic("Invalid ledger range")
	}
	log.Printf("Getting past ledgers [%d, %d]\n", startLedger, endLedger)

	for i := startLedger; i <= endLedger; i++ {
		msg := fmt.Sprintf("{\"command\":\"ledger\",\"id\":2,\"ledger_index\":%d,\"transactions\":1,\"expand\":1}", i)
		err := websocket.Message.Send(r.conn, msg)
		if err != nil {
			panic("Could not get ledger: " + err.Error())
		}

		time.Sleep(time.Second)
	}

	log.Printf("Completed ledgers [%d, %d]\n", startLedger, endLedger)
}

func (r *Connection) MonitorTransactionsFrom(startLedger uint64) {
	currentLedger := startLedger - 1
	currentLedgerTxnsLeft := 0

	for {
		var err error
		var m Message
		err = websocket.JSON.Receive(r.conn, &m)
		if err != nil {
			if err == io.EOF {
				// graceful shutdown by server
				break
			}
			fmt.Println("Could not receive: " + err.Error())
			break
		}

		switch m.Type {
		case "ledgerClosed":
			if m.LedgerIndex > currentLedger+1 {
				//fmt.Printf("Missing ledgers between %d and %d\n", currentLedger, m.LedgerIndex)
				//panic("")
				go r.getPastLedgers(currentLedger+1, m.LedgerIndex-1)
			}
			if currentLedgerTxnsLeft != 0 {
				log.Printf("Missing %d transactions from ledger %d\n", currentLedgerTxnsLeft, currentLedger)
				panic("")
			}
			fmt.Println(m.LedgerIndex)
			currentLedger = m.LedgerIndex
			currentLedgerTxnsLeft = m.TxnCount

		case "transaction":
			if m.LedgerIndex != currentLedger {
				log.Printf("Received out-of-order transaction from ledger %d\n", m.LedgerIndex)
				panic("")
			}
			currentLedgerTxnsLeft--
			r.Transactions <- m.Transaction

		case "serverStatus":
			log.Printf("SERVER: %s\n", m.ServerStatus)

		case "response":
			if m.Id == 2 && m.Status == "success" {
				fmt.Println(m.Result.Ledger.Index)
				for _, t := range m.Result.Ledger.Transactions {
					r.Transactions <- &t
				}
			} else {
				log.Printf("Unknown response ID: %d, status: %s\n", m.Id, m.Status)
			}

		case "error":
			log.Printf("Error: %s\n", m.Error)

		default:
			log.Printf("Unknown message type: %s\n", m.Type)
		}
	}
}
<|endoftext|>


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

// +build darwin freebsd linux netbsd openbsd

package syscall

import (
	"runtime"
	"sync"
	"unsafe"
)

var (
	Stdin  = 0
	Stdout = 1
	Stderr = 2
)

//extern syscall
func c_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32

//extern syscall
func c_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64

const darwinAMD64 = runtime.GOOS == "darwin" && runtime.GOARCH == "amd64"

// Do a system call.  We look at the size of uintptr to see how to pass
// the arguments, so that we don't pass a 64-bit value when the function
// expects a 32-bit one.
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	Entersyscall()
	var r uintptr
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3), 0, 0, 0)
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0)
		r = uintptr(r1)
	}
	err = GetErrno()
	Exitsyscall()
	return r, 0, err
}

func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	Entersyscall()
	var r uintptr
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
			int32(a4), int32(a5), int32(a6))
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),
			int64(a4), int64(a5), int64(a6))
		r = uintptr(r1)
	}
	err = GetErrno()
	Exitsyscall()
	return r, 0, err
}

func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	var r uintptr
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3), 0, 0, 0)
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0)
		r = uintptr(r1)
	}
	err = GetErrno()
	return r, 0, err
}

func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	var r uintptr
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
			int32(a4), int32(a5), int32(a6))
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),
			int64(a4), int64(a5), int64(a6))
		r = uintptr(r1)
	}
	err = GetErrno()
	return r, 0, err
}

// Mmap manager, for use by operating system-specific implementations.
// Gccgo only has one implementation but we do this to correspond to gc.

type mmapper struct {
	sync.Mutex
	active map[*byte][]byte // active mappings; key is last byte in mapping
	mmap   func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
	munmap func(addr uintptr, length uintptr) error
}

func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
	if length <= 0 {
		return nil, EINVAL
	}

	// Map the requested memory.
	addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
	if errno != nil {
		return nil, errno
	}

	// Slice memory layout
	var sl = struct {
		addr uintptr
		len  int
		cap  int
	}{addr, length, length}

	// Use unsafe to turn sl into a []byte.
	b := *(*[]byte)(unsafe.Pointer(&sl))

	// Register mapping in m and return it.
	p := &b[cap(b)-1]
	m.Lock()
	defer m.Unlock()
	m.active[p] = b
	return b, nil
}

func (m *mmapper) Munmap(data []byte) (err error) {
	if len(data) == 0 || len(data) != cap(data) {
		return EINVAL
	}

	// Find the base of the mapping.
	p := &data[cap(data)-1]
	m.Lock()
	defer m.Unlock()
	b := m.active[p]
	if b == nil || &b[0] != &data[0] {
		return EINVAL
	}

	// Unmap the memory and update m.
	if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
		return errno
	}
	m.active[p] = nil, false
	return nil
}

var mapper = &mmapper{
	active: make(map[*byte][]byte),
	mmap:   mmap,
	munmap: munmap,
}

func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
	return mapper.Mmap(fd, offset, length, prot, flags)
}

func Munmap(b []byte) (err error) {
	return mapper.Munmap(b)
}

// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int

func (s Signal) Signal() {}

func Signame(s Signal) string

func (s Signal) String() string {
	return Signame(s)
}
<commit_msg>syscall: Fix errno handling in syscall.Syscall and friends.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin freebsd linux netbsd openbsd

package syscall

import (
	"runtime"
	"sync"
	"unsafe"
)

var (
	Stdin  = 0
	Stdout = 1
	Stderr = 2
)

//extern syscall
func c_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32

//extern syscall
func c_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64

const darwinAMD64 = runtime.GOOS == "darwin" && runtime.GOARCH == "amd64"

// Do a system call.  We look at the size of uintptr to see how to pass
// the arguments, so that we don't pass a 64-bit value when the function
// expects a 32-bit one.
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	Entersyscall()
	SetErrno(0)
	var r uintptr
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3), 0, 0, 0)
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0)
		r = uintptr(r1)
	}
	err = GetErrno()
	Exitsyscall()
	return r, 0, err
}

func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	Entersyscall()
	SetErrno(0)
	var r uintptr
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
			int32(a4), int32(a5), int32(a6))
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),
			int64(a4), int64(a5), int64(a6))
		r = uintptr(r1)
	}
	err = GetErrno()
	Exitsyscall()
	return r, 0, err
}

func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	var r uintptr
	SetErrno(0)
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3), 0, 0, 0)
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0)
		r = uintptr(r1)
	}
	err = GetErrno()
	return r, 0, err
}

func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	var r uintptr
	SetErrno(0)
	if unsafe.Sizeof(r) == 4 {
		r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
			int32(a4), int32(a5), int32(a6))
		r = uintptr(r1)
	} else {
		r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),
			int64(a4), int64(a5), int64(a6))
		r = uintptr(r1)
	}
	err = GetErrno()
	return r, 0, err
}

// Mmap manager, for use by operating system-specific implementations.
// Gccgo only has one implementation but we do this to correspond to gc.

type mmapper struct {
	sync.Mutex
	active map[*byte][]byte // active mappings; key is last byte in mapping
	mmap   func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
	munmap func(addr uintptr, length uintptr) error
}

func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
	if length <= 0 {
		return nil, EINVAL
	}

	// Map the requested memory.
	addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
	if errno != nil {
		return nil, errno
	}

	// Slice memory layout
	var sl = struct {
		addr uintptr
		len  int
		cap  int
	}{addr, length, length}

	// Use unsafe to turn sl into a []byte.
	b := *(*[]byte)(unsafe.Pointer(&sl))

	// Register mapping in m and return it.
	p := &b[cap(b)-1]
	m.Lock()
	defer m.Unlock()
	m.active[p] = b
	return b, nil
}

func (m *mmapper) Munmap(data []byte) (err error) {
	if len(data) == 0 || len(data) != cap(data) {
		return EINVAL
	}

	// Find the base of the mapping.
	p := &data[cap(data)-1]
	m.Lock()
	defer m.Unlock()
	b := m.active[p]
	if b == nil || &b[0] != &data[0] {
		return EINVAL
	}

	// Unmap the memory and update m.
	if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
		return errno
	}
	m.active[p] = nil, false
	return nil
}

var mapper = &mmapper{
	active: make(map[*byte][]byte),
	mmap:   mmap,
	munmap: munmap,
}

func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
	return mapper.Mmap(fd, offset, length, prot, flags)
}

func Munmap(b []byte) (err error) {
	return mapper.Munmap(b)
}

// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int

func (s Signal) Signal() {}

func Signame(s Signal) string

func (s Signal) String() string {
	return Signame(s)
}
<|endoftext|>