<commit_before>//Package trakerr gives the client access to client side constructors for initializing
//and using trakerr.
package trakerr

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"
)

//TrakerrClient ...
type TrakerrClient struct {
	apiKey                  string
	url                     string
	contextAppVersion       string
	contextEnvName          string
	contextEnvVersion       string
	contextEnvHostname      string
	contextAppOS            string
	contextAppOSVersion     string
	contextDataCenter       string
	contextDataCenterRegion string
	eventsAPI               EventsAPI
	eventTraceBuilder       EventTraceBuilder
}

//NewTrakerrClientWithDefaults creates a new TrakerrClient and return it with the data.
// Most parameters are optional i.e. empty (pass "" to use defaults) with the exception of apiKey which is required.
func NewTrakerrClientWithDefaults(
	apiKey string,
	contextAppVersion string,
	contextEnvName string) *TrakerrClient {
	return NewTrakerrClient(apiKey, "", contextAppVersion, contextEnvName, "", "", "", "", "", "")
}

// NewTrakerrClient creates a new TrakerrClient and return it with the data.
// Most parameters are optional i.e. empty (pass "" to use defaults) with the exception of apiKey which is required.
// url is the location of the serverr service, if "" is passed it defaults to https://trakerr.io/api/v1
func NewTrakerrClient(
	apiKey string,
	url string,
	contextAppVersion string,
	contextEnvName string,
	contextEnvVersion string,
	contextEnvHostname string,
	contextAppOS string,
	contextAppOSVersion string,
	contextDataCenter string,
	contextDataCenterRegion string) *TrakerrClient {

	if contextEnvName == "" {
		contextEnvName = "development"
	}
	if contextAppVersion == "" {
		contextAppVersion = "1.0"
	}
	if contextEnvHostname == "" {
		contextEnvHostname, _ = os.Hostname()
	}

	if contextAppOS == "" {
		contextAppOS = runtime.GOOS
		switch contextAppOS {
		case "windows": // Keep an eye out for OS's using carrage returns
			//cmd1 := exec.Command("systeminfo")
			cmd := exec.Command("cmd", "/C", "systeminfo") //exec.Command("findstr", "/C:\"OS Name\"")
			var out bytes.Buffer
			cmd.Stdout = &out

			err1 := cmd.Run()
			if err1 != nil {
				contextAppOS = runtime.GOOS
				contextAppOSVersion = "N/A (arch:" + runtime.GOARCH + ")"
			} else {
				var output = out.String()
				contextAppOS = getTextFromLine(output, "OS Name:", "\n")
				version := getTextFromLine(output, "OS Version:", "\n")
				versionstringsplit := strings.Split(version, " ")

				if len(versionstringsplit) >= 1 {
					contextAppOSVersion = versionstringsplit[0]
				} else {
					contextAppOSVersion = version
				}
			}

		case "darwin": // ...
			cmd := exec.Command("bash", "-c", "system_profiler SPSoftwareDataType") //exec.Command("findstr", "/C:\"OS Name\"")
			var out bytes.Buffer
			cmd.Stdout = &out

			err1 := cmd.Run()
			if err1 != nil {
				contextAppOS = runtime.GOOS
				contextAppOSVersion = "N/A (arch:" + runtime.GOARCH + ")"
			} else {
				var output = out.String()

				contextAppOS = getTextFromLine(output, "System Version:", "(")
				contextAppOSVersion = getTextFromLine(output, "Kernel Version:", "\n")
			}

		default:
			cmd := exec.Command("bash", "-c", "uname -s") //Uname -r and -s
			var out bytes.Buffer
			cmd.Stdout = &out

			err1 := cmd.Run()
			var output string
			if err1 != nil {
				contextAppOS = runtime.GOOS
			} else {
				output = out.String()

				contextAppOS = strings.Trim(output, " \r\n")
			}

			cmd = exec.Command("bash", "-c", "uname -r") //Uname -r and -s
			err1 = cmd.Run()
			if err1 != nil {
				contextAppOSVersion = "N/A (arch:" + runtime.GOARCH + ")"
			} else {
				output = out.String()

				contextAppOSVersion = strings.Trim(output, " \r\n")
			}

		}

	}
	var eventsAPI EventsAPI

	if url != "" {
		eventsAPI = *NewEventsAPIWithBasePath(url)
	} else {
		eventsAPI = *NewEventsAPI()
	}

	return &TrakerrClient{
		apiKey:                  apiKey,
		url:                     url,
		contextAppVersion:       contextAppVersion,
		contextEnvName:          contextEnvName,
		contextEnvVersion:       contextEnvVersion,
		contextEnvHostname:      contextEnvHostname,
		contextAppOS:            contextAppOS,
		contextAppOSVersion:     contextAppOSVersion,
		contextDataCenter:       contextDataCenter,
		contextDataCenterRegion: contextDataCenterRegion,
		eventsAPI:               eventsAPI,
		eventTraceBuilder:       EventTraceBuilder{}}
}

func getTextFromLine(text string, prefix string, suffix string) string {
	var startindex = strings.Index(text, prefix)
	if startindex == -1 {
		return ""
	}
	var newstringfromprefix = text[startindex+len(prefix):]
	var endindex = strings.Index(newstringfromprefix, suffix)
	if endindex == -1 {
		return ""
	}

	return strings.Trim(newstringfromprefix[0:endindex], " \n\r")
}

//NewAppEvent ...
func (trakerrClient *TrakerrClient) NewAppEvent(classification string, eventType string, eventMessage string) *AppEvent {
	if classification == "" {
		classification = "Error"
	}
	if eventType == "" {
		eventType = "unknown"
	}
	if eventMessage == "" {
		eventMessage = "unknown "
	}
	return trakerrClient.FillDefaults(&AppEvent{Classification: classification, EventType: eventType, EventMessage: eventMessage})
}

//SendEvent ...
func (trakerrClient *TrakerrClient) SendEvent(appEvent *AppEvent) (*APIResponse, error) {
	return trakerrClient.eventsAPI.EventsPost(*trakerrClient.FillDefaults(appEvent))
}

//SendError ...
func (trakerrClient *TrakerrClient) SendError(err interface{}, skip int) (*APIResponse, error) {
	appEvent := trakerrClient.CreateAppEventFromErrorWithSkip(err, skip+1)

	return trakerrClient.eventsAPI.EventsPost(*appEvent)
}

//CreateAppEventFromError ...
func (trakerrClient *TrakerrClient) CreateAppEventFromError(err interface{}) *AppEvent {
	return trakerrClient.CreateAppEventFromErrorWithSkip(err, 1)

}

//CreateAppEventFromErrorWithSkip ...
func (trakerrClient *TrakerrClient) CreateAppEventFromErrorWithSkip(err interface{}, skip int) *AppEvent {
	stacktrace := trakerrClient.eventTraceBuilder.GetEventTraces(err, 50, skip+1)
	event := AppEvent{}
	event.EventType = fmt.Sprintf("%T", err)
	event.EventMessage = fmt.Sprint(err)
	event.Classification = "Error"

	result := trakerrClient.FillDefaults(&event)
	event.EventStacktrace = stacktrace
	return result
}

//AddStackTraceToAppEvent ...
func (trakerrClient *TrakerrClient) AddStackTraceToAppEvent(appEvent *AppEvent, err interface{}, skip int) {
	stacktrace := trakerrClient.eventTraceBuilder.GetEventTraces(err, 50, skip+1)
	var event = appEvent
	event.EventType = fmt.Sprintf("%T", err)
	event.EventMessage = fmt.Sprint(err)
	event.Classification = "Error"

	event.EventStacktrace = stacktrace
}

//Recover recovers from a panic and sends the error to Trakerr.
//Use in a Defer statement.
func (trakerrClient *TrakerrClient) Recover() {
	if err := recover(); err != nil {
		trakerrClient.SendError(err, 1)
	}
}

//RecoverWithAppEvent ...
func (trakerrClient *TrakerrClient) RecoverWithAppEvent(appEvent *AppEvent) {
	if err := recover(); err != nil {
		trakerrClient.AddStackTraceToAppEvent(appEvent, err, 1)
		trakerrClient.SendEvent(appEvent)
	}
}

//Notify recovers from an error and then repanics after sending the error to Trakerr,
//so that the panic can be picked up by the program error handler.
//Use in a Defer statement.
func (trakerrClient *TrakerrClient) Notify() {
	if err := recover(); err != nil {
		trakerrClient.SendError(err, 1)
		panic(err)
	}
}

//FillDefaults ...
func (trakerrClient *TrakerrClient) FillDefaults(appEvent *AppEvent) *AppEvent {
	if appEvent.ApiKey == "" {
		appEvent.ApiKey = trakerrClient.apiKey
	}

	if appEvent.ContextAppVersion == "" {
		appEvent.ContextAppVersion = trakerrClient.contextAppVersion
	}

	if appEvent.ContextEnvName == "" {
		appEvent.ContextEnvName = trakerrClient.contextEnvName
	}
	if appEvent.ContextEnvVersion == "" {
		appEvent.ContextEnvVersion = trakerrClient.contextEnvVersion
	}
	if appEvent.ContextEnvHostname == "" {
		appEvent.ContextEnvHostname = trakerrClient.contextEnvHostname
	}

	if appEvent.ContextAppOS == "" {
		appEvent.ContextAppOS = trakerrClient.contextAppOS
		appEvent.ContextAppOSVersion = trakerrClient.contextAppOSVersion
	}

	if appEvent.ContextDataCenter == "" {
		appEvent.ContextDataCenter = trakerrClient.contextDataCenter
	}
	if appEvent.ContextDataCenterRegion == "" {
		appEvent.ContextDataCenterRegion = trakerrClient.contextDataCenterRegion
	}

	if appEvent.EventTime <= 0 {
		appEvent.EventTime = makeTimestamp()
	}
	return appEvent
}

func makeTimestamp() int64 {
	return time.Now().UnixNano() / int64(time.Millisecond)
}
<commit_msg>changed method signatures to add space for classification.<commit_after>//Package trakerr gives the client access to client side constructors for initializing
//and using trakerr.
package trakerr

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"
)

//TrakerrClient ...
type TrakerrClient struct {
	apiKey                  string
	url                     string
	contextAppVersion       string
	contextEnvName          string
	contextEnvVersion       string
	contextEnvHostname      string
	contextAppOS            string
	contextAppOSVersion     string
	contextDataCenter       string
	contextDataCenterRegion string
	eventsAPI               EventsAPI
	eventTraceBuilder       EventTraceBuilder
}

//NewTrakerrClientWithDefaults creates a new TrakerrClient and return it with the data.
// Most parameters are optional i.e. empty (pass "" to use defaults) with the exception of apiKey which is required.
func NewTrakerrClientWithDefaults(
	apiKey string,
	contextAppVersion string,
	contextEnvName string) *TrakerrClient {
	return NewTrakerrClient(apiKey, "", contextAppVersion, contextEnvName, "", "", "", "", "", "")
}

// NewTrakerrClient creates a new TrakerrClient and return it with the data.
// Most parameters are optional i.e. empty (pass "" to use defaults) with the exception of apiKey which is required.
// url is the location of the serverr service, if "" is passed it defaults to https://trakerr.io/api/v1
func NewTrakerrClient(
	apiKey string,
	url string,
	contextAppVersion string,
	contextEnvName string,
	contextEnvVersion string,
	contextEnvHostname string,
	contextAppOS string,
	contextAppOSVersion string,
	contextDataCenter string,
	contextDataCenterRegion string) *TrakerrClient {

	if contextEnvName == "" {
		contextEnvName = "development"
	}
	if contextAppVersion == "" {
		contextAppVersion = "1.0"
	}
	if contextEnvHostname == "" {
		contextEnvHostname, _ = os.Hostname()
	}

	if contextAppOS == "" {
		contextAppOS = runtime.GOOS
		switch contextAppOS {
		case "windows": // Keep an eye out for OS's using carrage returns
			//cmd1 := exec.Command("systeminfo")
			cmd := exec.Command("cmd", "/C", "systeminfo") //exec.Command("findstr", "/C:\"OS Name\"")
			var out bytes.Buffer
			cmd.Stdout = &out

			err1 := cmd.Run()
			if err1 != nil {
				contextAppOS = runtime.GOOS
				contextAppOSVersion = "N/A (arch:" + runtime.GOARCH + ")"
			} else {
				var output = out.String()
				contextAppOS = getTextFromLine(output, "OS Name:", "\n")
				version := getTextFromLine(output, "OS Version:", "\n")
				versionstringsplit := strings.Split(version, " ")

				if len(versionstringsplit) >= 1 {
					contextAppOSVersion = versionstringsplit[0]
				} else {
					contextAppOSVersion = version
				}
			}

		case "darwin": // ...
			cmd := exec.Command("bash", "-c", "system_profiler SPSoftwareDataType") //exec.Command("findstr", "/C:\"OS Name\"")
			var out bytes.Buffer
			cmd.Stdout = &out

			err1 := cmd.Run()
			if err1 != nil {
				contextAppOS = runtime.GOOS
				contextAppOSVersion = "N/A (arch:" + runtime.GOARCH + ")"
			} else {
				var output = out.String()

				contextAppOS = getTextFromLine(output, "System Version:", "(")
				contextAppOSVersion = getTextFromLine(output, "Kernel Version:", "\n")
			}

		default:
			cmd := exec.Command("bash", "-c", "uname -s") //Uname -r and -s
			var out bytes.Buffer
			cmd.Stdout = &out

			err1 := cmd.Run()
			var output string
			if err1 != nil {
				contextAppOS = runtime.GOOS
			} else {
				output = out.String()

				contextAppOS = strings.Trim(output, " \r\n")
			}

			cmd = exec.Command("bash", "-c", "uname -r") //Uname -r and -s
			err1 = cmd.Run()
			if err1 != nil {
				contextAppOSVersion = "N/A (arch:" + runtime.GOARCH + ")"
			} else {
				output = out.String()

				contextAppOSVersion = strings.Trim(output, " \r\n")
			}

		}

	}
	var eventsAPI EventsAPI

	if url != "" {
		eventsAPI = *NewEventsAPIWithBasePath(url)
	} else {
		eventsAPI = *NewEventsAPI()
	}

	return &TrakerrClient{
		apiKey:                  apiKey,
		url:                     url,
		contextAppVersion:       contextAppVersion,
		contextEnvName:          contextEnvName,
		contextEnvVersion:       contextEnvVersion,
		contextEnvHostname:      contextEnvHostname,
		contextAppOS:            contextAppOS,
		contextAppOSVersion:     contextAppOSVersion,
		contextDataCenter:       contextDataCenter,
		contextDataCenterRegion: contextDataCenterRegion,
		eventsAPI:               eventsAPI,
		eventTraceBuilder:       EventTraceBuilder{}}
}

func getTextFromLine(text string, prefix string, suffix string) string {
	var startindex = strings.Index(text, prefix)
	if startindex == -1 {
		return ""
	}
	var newstringfromprefix = text[startindex+len(prefix):]
	var endindex = strings.Index(newstringfromprefix, suffix)
	if endindex == -1 {
		return ""
	}

	return strings.Trim(newstringfromprefix[0:endindex], " \n\r")
}

//NewAppEvent ...
func (trakerrClient *TrakerrClient) NewAppEvent(classification string, eventType string, eventMessage string) *AppEvent {
	if classification == "" {
		classification = "Error"
	}
	if eventType == "" {
		eventType = "unknown"
	}
	if eventMessage == "" {
		eventMessage = "unknown "
	}
	return trakerrClient.FillDefaults(&AppEvent{Classification: classification, EventType: eventType, EventMessage: eventMessage})
}

//SendEvent ...
func (trakerrClient *TrakerrClient) SendEvent(appEvent *AppEvent) (*APIResponse, error) {
	return trakerrClient.eventsAPI.EventsPost(*trakerrClient.FillDefaults(appEvent))
}

//SendError ...
func (trakerrClient *TrakerrClient) SendError(err interface{}, classification string) {
	trakerrClient.SendErrorWithSkip(err, classification, 1)
}

//SendErrorWithSkip ...
func (trakerrClient *TrakerrClient) SendErrorWithSkip(err interface{}, classification string, skip int) (*APIResponse, error) {
	appEvent := trakerrClient.CreateAppEventFromErrorWithSkip(err, classification, skip+1)

	return trakerrClient.eventsAPI.EventsPost(*appEvent)
}

//CreateAppEventFromError ...
func (trakerrClient *TrakerrClient) CreateAppEventFromError(err interface{}, classification string) *AppEvent {
	return trakerrClient.CreateAppEventFromErrorWithSkip(err, classification, 1)

}

//CreateAppEventFromErrorWithSkip ...
func (trakerrClient *TrakerrClient) CreateAppEventFromErrorWithSkip(err interface{}, classification string, skip int) *AppEvent {
	stacktrace := trakerrClient.eventTraceBuilder.GetEventTraces(err, 50, skip+1)
	event := AppEvent{}
	event.EventType = fmt.Sprintf("%T", err)
	event.EventMessage = fmt.Sprint(err)
	event.Classification = classification

	result := trakerrClient.FillDefaults(&event)
	event.EventStacktrace = stacktrace
	return result
}

//AddStackTraceToAppEvent ...
func (trakerrClient *TrakerrClient) AddStackTraceToAppEvent(appEvent *AppEvent, err interface{}, skip int) {
	stacktrace := trakerrClient.eventTraceBuilder.GetEventTraces(err, 50, skip+1)
	var event = appEvent
	if event.EventType == "" {
		event.EventType = fmt.Sprintf("%T", err)
	}
	if event.EventMessage == "" {
		event.EventMessage = fmt.Sprint(err)
	}

	event.EventStacktrace = stacktrace
}

//Recover recovers from a panic and sends the error to Trakerr.
//Use in a Defer statement.
func (trakerrClient *TrakerrClient) Recover(classification string) {
	if err := recover(); err != nil {
		trakerrClient.SendErrorWithSkip(err, classification, 1)
	}
}

//RecoverWithAppEvent ...
func (trakerrClient *TrakerrClient) RecoverWithAppEvent(appEvent *AppEvent) {
	if err := recover(); err != nil {
		trakerrClient.AddStackTraceToAppEvent(appEvent, err, 1)
		trakerrClient.SendEvent(appEvent)
	}
}

//Notify recovers from an error and then repanics after sending the error to Trakerr,
//so that the panic can be picked up by the program error handler.
//Use in a Defer statement.
func (trakerrClient *TrakerrClient) Notify(classification string) {
	if err := recover(); err != nil {
		trakerrClient.SendErrorWithSkip(err, classification, 1)
		panic(err)
	}
}

//FillDefaults ...
func (trakerrClient *TrakerrClient) FillDefaults(appEvent *AppEvent) *AppEvent {
	if appEvent.ApiKey == "" {
		appEvent.ApiKey = trakerrClient.apiKey
	}

	if appEvent.ContextAppVersion == "" {
		appEvent.ContextAppVersion = trakerrClient.contextAppVersion
	}

	if appEvent.ContextEnvName == "" {
		appEvent.ContextEnvName = trakerrClient.contextEnvName
	}
	if appEvent.ContextEnvVersion == "" {
		appEvent.ContextEnvVersion = trakerrClient.contextEnvVersion
	}
	if appEvent.ContextEnvHostname == "" {
		appEvent.ContextEnvHostname = trakerrClient.contextEnvHostname
	}

	if appEvent.ContextAppOS == "" {
		appEvent.ContextAppOS = trakerrClient.contextAppOS
		appEvent.ContextAppOSVersion = trakerrClient.contextAppOSVersion
	}

	if appEvent.ContextDataCenter == "" {
		appEvent.ContextDataCenter = trakerrClient.contextDataCenter
	}
	if appEvent.ContextDataCenterRegion == "" {
		appEvent.ContextDataCenterRegion = trakerrClient.contextDataCenterRegion
	}

	if appEvent.EventTime <= 0 {
		appEvent.EventTime = makeTimestamp()
	}
	return appEvent
}

func makeTimestamp() int64 {
	return time.Now().UnixNano() / int64(time.Millisecond)
}
<|endoftext|>


<commit_before>package library

import (
	"errors"
	"github.com/nytlabs/streamtools/st/blocks" // blocks
	"math"
)

type KullbackLeibler struct {
	blocks.Block
	inA   chan interface{}
	inB   chan interface{}
	clear chan interface{}
	out   chan interface{}
	quit  chan interface{}
}

func NewKullbackLeibler() blocks.BlockInterface {
	return &KullbackLeibler{}
}

func (b *KullbackLeibler) Setup() {
	b.Kind = "KullbackLeibler"
	b.inA = b.InRoute("inA")
	b.inB = b.InRoute("inB")
	b.clear = b.InRoute("clear")
	b.quit = b.Quit()
	b.out = b.Broadcast()
}

func assertHistogram(hI interface{}) (map[string]float64, bool) {
	h, ok := hI.(map[string]interface{})
	if !ok {
		return nil, ok
	}
	valuesI, ok := h["Histogram"]
	if !ok {
		return nil, ok
	}
	values, ok := valuesI.([]interface{})
	if !ok {
		return nil, ok
	}
	out := make(map[string]float64)
	for _, valueI := range values {
		value, ok := valueI.(map[string]interface{})
		if !ok {
			return nil, ok
		}
		kI, ok := value["Label"]
		if !ok {
			return nil, ok
		}
		vI, ok := value["Count"]
		if !ok {
			return nil, ok
		}
		k, ok := kI.(string)
		if !ok {
			return nil, ok
		}
		v, ok := vI.(int)
		if !ok {
			return nil, ok
		}
		out[k] = float64(v)
	}
	return out, ok
}

func (b *KullbackLeibler) Run() {
	A := make(chan interface{}, 1000)
	B := make(chan interface{}, 1000)
	for {
		select {
		case <-b.quit:
			return
		case msg := <-b.inA:
			select {
			case A <- msg:
			default:
				b.Error("the A queue is overflowing")
			}
		case msg := <-b.inB:
			select {
			case B <- msg:
			default:
				b.Error("the B queue is overflowing")
			}
		case <-b.clear:
		Clear:
			for {
				select {
				case <-A:
				case <-B:
				default:
					break Clear
				}
			}
		}
		for len(A) > 0 && len(B) > 0 {
			pI := <-A
			qI := <-B
			p, ok := assertHistogram(pI)
			if !ok {
				b.Error(errors.New("p is not a Histogram"))
				continue
			}
			q, ok := assertHistogram(qI)
			if !ok {
				b.Error(errors.New("q is not a Histogram"))
				continue
			}
			outcomes := make([]string, 0, len(p)+len(q))
			for k := range p {
				outcomes = append(outcomes, k)
			}
			for k := range q {
				outcomes = append(outcomes, k)
			}
			pfull := make([]float64, len(outcomes))
			qfull := make([]float64, len(outcomes))
			for i, k := range outcomes {
				v, ok := p[k]
				if !ok {
					v = 0
				}
				pfull[i] = v
			}
			for i, k := range outcomes {
				v, ok := q[k]
				if !ok {
					v = 0
				}
				qfull[i] = v
			}
			kl := 0.0
			for i := range outcomes {
				kl += math.Log(pfull[i]/qfull[i]) * pfull[i]
			}
			b.out <- map[string]interface{}{
				"KL": kl,
			}
		}
	}
}
<commit_msg>still not working<commit_after>package library

import (
	"errors"
	"github.com/nytlabs/streamtools/st/blocks" // blocks
	"log"
	"math"
)

type KullbackLeibler struct {
	blocks.Block
	inA   chan interface{}
	inB   chan interface{}
	clear chan interface{}
	out   chan interface{}
	quit  chan interface{}
}

func NewKullbackLeibler() blocks.BlockInterface {
	return &KullbackLeibler{}
}

func (b *KullbackLeibler) Setup() {
	b.Kind = "KullbackLeibler"
	b.inA = b.InRoute("p")
	b.inB = b.InRoute("q")
	b.clear = b.InRoute("clear")
	b.quit = b.Quit()
	b.out = b.Broadcast()
}

var eps = 0.0

type histogram map[string]float64

func newHistogram(hI interface{}) (histogram, bool) {
	h, ok := hI.(map[string]interface{})
	if !ok {
		return nil, ok
	}
	valuesI, ok := h["Histogram"]
	if !ok {
		return nil, ok
	}
	values, ok := valuesI.([]interface{})
	if !ok {
		return nil, ok
	}
	var out histogram
	out = make(map[string]float64)
	for _, valueI := range values {
		value, ok := valueI.(map[string]interface{})
		if !ok {
			return nil, ok
		}
		kI, ok := value["Label"]
		if !ok {
			return nil, ok
		}
		vI, ok := value["Count"]
		if !ok {
			return nil, ok
		}
		k, ok := kI.(string)
		if !ok {
			return nil, ok
		}
		v, ok := vI.(int)
		if !ok {
			return nil, ok
		}
		if v == 0 {
			out[k] = eps
		} else {
			out[k] = float64(v)
		}
	}
	z := 0.0
	for _, v := range out {
		z += float64(v)
	}
	for k, _ := range out {
		out[k] /= z
	}
	return out, ok
}

func (h histogram) normalise(p histogram) {
	for k, _ := range p {
		if _, ok := h[k]; !ok {
			h[k] = eps
		}
	}
	z := 0.0
	for _, v := range h {
		z += v
	}
	for k, v := range h {
		h[k] = v / z
		log.Println(v, z, v/z)
	}
}

func (b *KullbackLeibler) Run() {
	A := make(chan interface{}, 1000)
	B := make(chan interface{}, 1000)
	for {
		select {
		case <-b.quit:
			return
		case msg := <-b.inA:
			select {
			case A <- msg:
			default:
				b.Error("the A queue is overflowing")
			}
		case msg := <-b.inB:
			select {
			case B <- msg:
			default:
				b.Error("the B queue is overflowing")
			}
		case <-b.clear:
		Clear:
			for {
				select {
				case <-A:
				case <-B:
				default:
					break Clear
				}
			}
		}
		for len(A) > 0 && len(B) > 0 {
			pI := <-A
			qI := <-B
			p, ok := newHistogram(pI)
			if !ok {
				b.Error(errors.New("p is not a Histogram"))
				continue
			}
			q, ok := newHistogram(qI)
			if !ok {
				b.Error(errors.New("q is not a Histogram"))
				continue
			}
			log.Println(p, q)
			q.normalise(p)
			p.normalise(q)
			log.Println(p, q)
			kl := 0.0
			for k, pi := range p {
				kl += math.Log(pi/q[k]) * pi
			}
			b.out <- map[string]interface{}{
				"KL": kl,
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 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.

// The stargzify command converts a remote container image into an equivalent
// image with its layers transformed into stargz files instead of gzipped tar
// files. The image is still a valid container image, but its layers contain
// multiple gzip streams instead of one and have a Table of Contents at the end.
package main

import (
	"crypto/sha256"
	"encoding/hex"
	"flag"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/google/crfs/stargz"
	"github.com/google/go-containerregistry/pkg/authn"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/empty"
	"github.com/google/go-containerregistry/pkg/v1/mutate"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"github.com/google/go-containerregistry/pkg/v1/stream"
	"github.com/google/go-containerregistry/pkg/v1/types"
)

var (
	upgrade = flag.Bool("upgrade", false, "upgrade the image in-place by overwriting the tag")
	flatten = flag.Bool("flatten", false, "flatten the image's layers into a single layer")

	usage = `usage: %[1]s [-upgrade] [-flatten] input [output]

Converting images:
  # converts "ubuntu" from dockerhub and uploads to your GCR project
  %[1]s ubuntu gcr.io/<your-project>/ubuntu:stargz

  # converts and overwrites :latest
  %[1]s -upgrade gcr.io/<your-project>/ubuntu:latest

  # converts and flattens "ubuntu"
  %[1]s -flatten ubuntu gcr.io/<your-project>/ubuntu:flattened

Converting files:
  %[1]s file:/tmp/input.tar.gz file:output.stargz

  # writes to /tmp/input.stargz
  %[1]s file:/tmp/input.tar.gz
`
)

func main() {
	flag.Parse()
	if len(flag.Args()) < 1 {
		printUsage()
	}

	if strings.HasPrefix(flag.Args()[0], "file:") {
		// We'll use "file:" prefix as a signal to convert single files.
		convertFile()
	} else {
		convertImage()
	}
}

func printUsage() {
	log.Fatalf(usage, os.Args[0])
}

func convertFile() {
	var in, out string
	if len(flag.Args()) > 0 {
		in = strings.TrimPrefix(flag.Args()[0], "file:")
	}
	if len(flag.Args()) > 1 {
		out = strings.TrimPrefix(flag.Args()[1], "file:")
	}

	var f, fo *os.File // file in, file out
	var err error
	switch in {
	case "":
		printUsage()
	case "-":
		f = os.Stdin
	default:
		f, err = os.Open(in)
		if err != nil {
			log.Fatal(err)
		}
	}
	defer f.Close()

	if out == "" {
		if in == "-" {
			out = "-"
		} else {
			base := strings.TrimSuffix(in, ".gz")
			base = strings.TrimSuffix(base, ".tgz")
			base = strings.TrimSuffix(base, ".tar")
			out = base + ".stargz"
		}
	}
	if out == "-" {
		fo = os.Stdout
	} else {
		fo, err = os.Create(out)
		if err != nil {
			log.Fatal(err)
		}
	}
	w := stargz.NewWriter(fo)
	if err := w.AppendTar(f); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}
	if err := fo.Close(); err != nil {
		log.Fatal(err)
	}
}

func parseFlags(args []string) (string, string) {
	if len(args) < 1 {
		printUsage()
	}

	var src, dst string
	src = args[0]

	if len(args) < 2 {
		if *upgrade {
			dst = src
		} else {
			printUsage()
		}
	} else if len(args) == 2 {
		if *upgrade {
			log.Println("expected one argument with -upgrade")
			printUsage()
		} else {
			dst = args[1]
		}
	} else {
		log.Println("too many arguments")
		printUsage()
	}

	return src, dst
}

func convertImage() {
	src, dst := parseFlags(flag.Args())
	srcRef, err := name.ParseReference(src)
	if err != nil {
		log.Fatal(err)
	}

	// Pull source image.
	srcImg, err := remote.Image(srcRef, remote.WithAuthFromKeychain(authn.DefaultKeychain))
	if err != nil {
		log.Fatal(err)
	}

	// Grab original config, clear the layer info from the config file. We want to
	// preserve the relevant config.
	srcCfg, err := srcImg.ConfigFile()
	if err != nil {
		log.Fatal(err)
	}
	srcCfg.RootFS.DiffIDs = []v1.Hash{}
	srcCfg.History = []v1.History{}

	// Use an empty image with the rest of src's config file as a base.
	img, err := mutate.ConfigFile(empty.Image, srcCfg)
	if err != nil {
		log.Fatal(err)
	}

	layers, err := convertLayers(srcImg)
	if err != nil {
		log.Fatal(err)
	}

	for _, layer := range layers {
		img, err = mutate.Append(img, mutate.Addendum{
			Layer: layer,
			History: v1.History{
				// Leave our mark.
				CreatedBy: fmt.Sprintf("stargzify %s %s", src, dst),
			},
		})
		if err != nil {
			log.Fatal(err)
		}
	}

	// Push the stargzified image to dst.
	dstRef, err := name.ParseReference(dst)
	if err != nil {
		log.Fatal(err)
	}
	dstAuth, err := authn.DefaultKeychain.Resolve(dstRef.Context().Registry)
	if err != nil {
		log.Fatal(err)
	}

	if err := remote.Write(dstRef, img, dstAuth, http.DefaultTransport); err != nil {
		log.Fatal(err)
	}
}

func convertLayers(img v1.Image) ([]v1.Layer, error) {
	if *flatten {
		r := mutate.Extract(img)
		return []v1.Layer{newLayer(r)}, nil
	}

	layers, err := img.Layers()
	if err != nil {
		return nil, err
	}

	converted := []v1.Layer{}
	for _, layer := range layers {
		r, err := layer.Uncompressed()
		if err != nil {
			return nil, err
		}
		converted = append(converted, newLayer(r))
	}

	return converted, nil
}

type layer struct {
	rc     io.ReadCloser
	d      *digester
	diff   *v1.Hash
	digest *v1.Hash
}

// newLayer converts the given io.ReadCloser to a stargz layer.
func newLayer(rc io.ReadCloser) v1.Layer {
	return &layer{
		rc: rc,
		d: &digester{
			h: sha256.New(),
		},
	}
}

func (l *layer) Digest() (v1.Hash, error) {
	if l.digest == nil {
		return v1.Hash{}, stream.ErrNotComputed
	}
	return *l.digest, nil
}

func (l *layer) Size() (int64, error) {
	if l.digest == nil {
		return -1, stream.ErrNotComputed
	}
	return l.d.n, nil
}

func (l *layer) DiffID() (v1.Hash, error) {
	if l.diff == nil {
		return v1.Hash{}, stream.ErrNotComputed
	}
	return *l.diff, nil
}

func (l *layer) MediaType() (types.MediaType, error) {
	// TODO: We might want to set our own media type to indicate stargz layers,
	// but that has the potential to break registry compatibility.
	return types.DockerLayer, nil
}

func (l *layer) Compressed() (io.ReadCloser, error) {
	pr, pw := io.Pipe()

	// Convert input blob to stargz while computing diffid, digest, and size.
	go func() {
		w := stargz.NewWriter(pw)
		if err := w.AppendTar(l.rc); err != nil {
			pw.CloseWithError(err)
			return
		}
		if err := w.Close(); err != nil {
			pw.CloseWithError(err)
			return
		}
		diffid, err := v1.NewHash(w.DiffID())
		if err != nil {
			pw.CloseWithError(err)
			return
		}
		l.diff = &diffid
		l.digest = &v1.Hash{
			Algorithm: "sha256",
			Hex:       hex.EncodeToString(l.d.h.Sum(nil)),
		}
		pw.Close()
	}()

	return ioutil.NopCloser(io.TeeReader(pr, l.d)), nil
}

func (l *layer) Uncompressed() (io.ReadCloser, error) {
	return l.rc, nil
}

// digester tracks the sha256 and length of what is written to it.
type digester struct {
	h hash.Hash
	n int64
}

func (d *digester) Write(b []byte) (int, error) {
	n, err := d.h.Write(b)
	d.n += int64(n)
	return n, err
}
<commit_msg>Ensure writing to the digester completes before the digest calculation. (#25)<commit_after>// Copyright 2019 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.

// The stargzify command converts a remote container image into an equivalent
// image with its layers transformed into stargz files instead of gzipped tar
// files. The image is still a valid container image, but its layers contain
// multiple gzip streams instead of one and have a Table of Contents at the end.
package main

import (
	"crypto/sha256"
	"encoding/hex"
	"flag"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/google/crfs/stargz"
	"github.com/google/go-containerregistry/pkg/authn"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/empty"
	"github.com/google/go-containerregistry/pkg/v1/mutate"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"github.com/google/go-containerregistry/pkg/v1/stream"
	"github.com/google/go-containerregistry/pkg/v1/types"
)

var (
	upgrade = flag.Bool("upgrade", false, "upgrade the image in-place by overwriting the tag")
	flatten = flag.Bool("flatten", false, "flatten the image's layers into a single layer")

	usage = `usage: %[1]s [-upgrade] [-flatten] input [output]

Converting images:
  # converts "ubuntu" from dockerhub and uploads to your GCR project
  %[1]s ubuntu gcr.io/<your-project>/ubuntu:stargz

  # converts and overwrites :latest
  %[1]s -upgrade gcr.io/<your-project>/ubuntu:latest

  # converts and flattens "ubuntu"
  %[1]s -flatten ubuntu gcr.io/<your-project>/ubuntu:flattened

Converting files:
  %[1]s file:/tmp/input.tar.gz file:output.stargz

  # writes to /tmp/input.stargz
  %[1]s file:/tmp/input.tar.gz
`
)

func main() {
	flag.Parse()
	if len(flag.Args()) < 1 {
		printUsage()
	}

	if strings.HasPrefix(flag.Args()[0], "file:") {
		// We'll use "file:" prefix as a signal to convert single files.
		convertFile()
	} else {
		convertImage()
	}
}

func printUsage() {
	log.Fatalf(usage, os.Args[0])
}

func convertFile() {
	var in, out string
	if len(flag.Args()) > 0 {
		in = strings.TrimPrefix(flag.Args()[0], "file:")
	}
	if len(flag.Args()) > 1 {
		out = strings.TrimPrefix(flag.Args()[1], "file:")
	}

	var f, fo *os.File // file in, file out
	var err error
	switch in {
	case "":
		printUsage()
	case "-":
		f = os.Stdin
	default:
		f, err = os.Open(in)
		if err != nil {
			log.Fatal(err)
		}
	}
	defer f.Close()

	if out == "" {
		if in == "-" {
			out = "-"
		} else {
			base := strings.TrimSuffix(in, ".gz")
			base = strings.TrimSuffix(base, ".tgz")
			base = strings.TrimSuffix(base, ".tar")
			out = base + ".stargz"
		}
	}
	if out == "-" {
		fo = os.Stdout
	} else {
		fo, err = os.Create(out)
		if err != nil {
			log.Fatal(err)
		}
	}
	w := stargz.NewWriter(fo)
	if err := w.AppendTar(f); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}
	if err := fo.Close(); err != nil {
		log.Fatal(err)
	}
}

func parseFlags(args []string) (string, string) {
	if len(args) < 1 {
		printUsage()
	}

	var src, dst string
	src = args[0]

	if len(args) < 2 {
		if *upgrade {
			dst = src
		} else {
			printUsage()
		}
	} else if len(args) == 2 {
		if *upgrade {
			log.Println("expected one argument with -upgrade")
			printUsage()
		} else {
			dst = args[1]
		}
	} else {
		log.Println("too many arguments")
		printUsage()
	}

	return src, dst
}

func convertImage() {
	src, dst := parseFlags(flag.Args())
	srcRef, err := name.ParseReference(src)
	if err != nil {
		log.Fatal(err)
	}

	// Pull source image.
	srcImg, err := remote.Image(srcRef, remote.WithAuthFromKeychain(authn.DefaultKeychain))
	if err != nil {
		log.Fatal(err)
	}

	// Grab original config, clear the layer info from the config file. We want to
	// preserve the relevant config.
	srcCfg, err := srcImg.ConfigFile()
	if err != nil {
		log.Fatal(err)
	}
	srcCfg.RootFS.DiffIDs = []v1.Hash{}
	srcCfg.History = []v1.History{}

	// Use an empty image with the rest of src's config file as a base.
	img, err := mutate.ConfigFile(empty.Image, srcCfg)
	if err != nil {
		log.Fatal(err)
	}

	layers, err := convertLayers(srcImg)
	if err != nil {
		log.Fatal(err)
	}

	for _, layer := range layers {
		img, err = mutate.Append(img, mutate.Addendum{
			Layer: layer,
			History: v1.History{
				// Leave our mark.
				CreatedBy: fmt.Sprintf("stargzify %s %s", src, dst),
			},
		})
		if err != nil {
			log.Fatal(err)
		}
	}

	// Push the stargzified image to dst.
	dstRef, err := name.ParseReference(dst)
	if err != nil {
		log.Fatal(err)
	}
	dstAuth, err := authn.DefaultKeychain.Resolve(dstRef.Context().Registry)
	if err != nil {
		log.Fatal(err)
	}

	if err := remote.Write(dstRef, img, dstAuth, http.DefaultTransport); err != nil {
		log.Fatal(err)
	}
}

func convertLayers(img v1.Image) ([]v1.Layer, error) {
	if *flatten {
		r := mutate.Extract(img)
		return []v1.Layer{newLayer(r)}, nil
	}

	layers, err := img.Layers()
	if err != nil {
		return nil, err
	}

	converted := []v1.Layer{}
	for _, layer := range layers {
		r, err := layer.Uncompressed()
		if err != nil {
			return nil, err
		}
		converted = append(converted, newLayer(r))
	}

	return converted, nil
}

type layer struct {
	rc     io.ReadCloser
	d      *digester
	diff   *v1.Hash
	digest *v1.Hash
}

// newLayer converts the given io.ReadCloser to a stargz layer.
func newLayer(rc io.ReadCloser) v1.Layer {
	return &layer{
		rc: rc,
		d: &digester{
			h: sha256.New(),
		},
	}
}

func (l *layer) Digest() (v1.Hash, error) {
	if l.digest == nil {
		return v1.Hash{}, stream.ErrNotComputed
	}
	return *l.digest, nil
}

func (l *layer) Size() (int64, error) {
	if l.digest == nil {
		return -1, stream.ErrNotComputed
	}
	return l.d.n, nil
}

func (l *layer) DiffID() (v1.Hash, error) {
	if l.diff == nil {
		return v1.Hash{}, stream.ErrNotComputed
	}
	return *l.diff, nil
}

func (l *layer) MediaType() (types.MediaType, error) {
	// TODO: We might want to set our own media type to indicate stargz layers,
	// but that has the potential to break registry compatibility.
	return types.DockerLayer, nil
}

func (l *layer) Compressed() (io.ReadCloser, error) {
	pr, pw := io.Pipe()

	// Convert input blob to stargz while computing diffid, digest, and size.
	go func() {
		w := stargz.NewWriter(io.MultiWriter(pw, l.d))
		if err := w.AppendTar(l.rc); err != nil {
			pw.CloseWithError(err)
			return
		}
		if err := w.Close(); err != nil {
			pw.CloseWithError(err)
			return
		}
		diffid, err := v1.NewHash(w.DiffID())
		if err != nil {
			pw.CloseWithError(err)
			return
		}
		l.diff = &diffid
		l.digest = &v1.Hash{
			Algorithm: "sha256",
			Hex:       hex.EncodeToString(l.d.h.Sum(nil)),
		}
		pw.Close()
	}()

	return ioutil.NopCloser(pr), nil
}

func (l *layer) Uncompressed() (io.ReadCloser, error) {
	return l.rc, nil
}

// digester tracks the sha256 and length of what is written to it.
type digester struct {
	h hash.Hash
	n int64
}

func (d *digester) Write(b []byte) (int, error) {
	n, err := d.h.Write(b)
	d.n += int64(n)
	return n, err
}
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.

package main

import (
	"github.com/ardielle/ardielle-go/rdl"
	"bufio"
	"strings"
	"log"
	"flag"
	"io/ioutil"
	"fmt"
	"encoding/json"
	"os"
	"github.com/yahoo/parsec-rdl-gen/utils"
	"text/template"
)

type javaClientGenerator struct {
	registry rdl.TypeRegistry
	schema   *rdl.Schema
	name     string
	writer   *bufio.Writer
	err      error
	banner   string
	ns       string
	base     string
}

func main() {
	pOutdir := flag.String("o", ".", "Output directory")
	flag.String("s", "", "RDL source file")
	namespace := flag.String("ns", "", "Namespace")
	flag.Parse()
	data, err := ioutil.ReadAll(os.Stdin)
	banner := "parsec-rdl-gen (development version)"

	if err == nil {
		var schema rdl.Schema
		err = json.Unmarshal(data, &schema)
		if err == nil {
			GenerateJavaClient(banner, &schema, *pOutdir, *namespace, "")
			os.Exit(0)
		}
	}
	fmt.Fprintf(os.Stderr, "*** %v\n", err)
	os.Exit(1)
}

// GenerateJavaClient generates the client code to talk to the server
func GenerateJavaClient(banner string, schema *rdl.Schema, outdir string, ns string, base string) error {

	reg := rdl.NewTypeRegistry(schema)

	packageDir, err := utils.JavaGenerationDir(outdir, schema, ns)
	if err != nil {
		return err
	}

	cName := utils.Capitalize(string(schema.Name))

	out, file, _, err := utils.OutputWriter(packageDir, cName, "ClientImpl.java")
	if err != nil {
		return err
	}
	gen := &javaClientGenerator{reg, schema, cName, out, nil, banner, ns, base}
	gen.processTemplate(javaClientTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	out, file, _, err = utils.OutputWriter(packageDir, cName, "Client.java")
	if err != nil {
		return err
	}
	gen = &javaClientGenerator{reg, schema, cName, out, nil, banner, ns, base}
	gen.processTemplate(javaClientInterfaceTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	//ResourceException - the throawable wrapper for alternate return types
	out, file, _, err = utils.OutputWriter(packageDir, "ResourceException", ".java")
	if err != nil {
		return err
	}
	err = utils.JavaGenerateResourceException(schema, out, ns)
	out.Flush()
	file.Close()
	if err != nil {
		return err
	}

	//ResourceError - the default data object for an error
	out, file, _, err = utils.OutputWriter(packageDir, "ResourceError", ".java")
	if err != nil {
		return err
	}
	err = utils.JavaGenerateResourceError(schema, out, ns)
	out.Flush()
	file.Close()
	return err
}

func (gen *javaClientGenerator) processTemplate(templateSource string) error {
	commentFun := func(s string) string {
		return utils.FormatComment(s, 0, 80)
	}
	needExpectFunc := func(r *rdl.Resource) bool {
		if (r.Expected != "OK" || len(r.Alternatives) > 0) {
			return true
		}
		return false
	}
	needImportHashSetFunc := func(rs []*rdl.Resource) bool {
		for _,r := range rs {
			if (needExpectFunc(r)) {
				return true
			}
		}
		return false
	}
	needBodyFunc := func(r *rdl.Resource) bool { return gen.needBody(r) }
	needImportJsonProcessingExceptionFunc := func(rs []*rdl.Resource) bool {
		for _,r := range rs {
			if (needBodyFunc(r)) {
				return true
			}
		}
		return false
	}
	funcMap := template.FuncMap{
		"header":      func() string { return utils.JavaGenerationHeader(gen.banner) },
		"package":     func() string { return utils.JavaGenerationPackage(gen.schema, gen.ns) },
		"comment":     commentFun,
		"methodSig":   func(r *rdl.Resource) string { return "public "+ gen.clientMethodSignature(r) },
		"name":        func() string { return gen.name },
		"cName":       func() string { return utils.Capitalize(gen.name) },
		"lName":       func() string { return utils.Uncapitalize(gen.name) },
		"needBody":    needBodyFunc,
		"bodyObj":     func(r *rdl.Resource) string { return gen.getBodyObj(r) },
		"iMethod":     func(r *rdl.Resource) string { return gen.clientMethodSignature(r) + ";" },
		"builderExt":  func(r *rdl.Resource) string { return gen.builderExt(r) },
		"origPackage": func() string { return utils.JavaGenerationOrigPackage(gen.schema, gen.ns) },
		"origHeader":  func() string { return utils.JavaGenerationOrigHeader(gen.banner) },
		"returnType":  func(r *rdl.Resource) string { return utils.JavaType(gen.registry, r.Type, true, "", "")},
		"needExpect":  needExpectFunc,
		"needImportHashSet":  needImportHashSetFunc,
		"needImportJsonProcessingException": needImportJsonProcessingExceptionFunc,
	}
	t := template.Must(template.New(gen.name).Funcs(funcMap).Parse(templateSource))
	return t.Execute(gen.writer, gen.schema)
}

func (gen* javaClientGenerator) builderExt(r *rdl.Resource) string {
	code := "\n"
	spacePad := "                            "
	for _, input := range r.Inputs {
		iname := javaName(input.Name)
		if input.PathParam {
			code += spacePad + ".resolveTemplate(\"" + iname + "\", " + iname + ")\n"
		} else if input.QueryParam != "" {
			code += spacePad + ".queryParam(\"" + iname + "\", " + iname + ")\n"
		}
	}
	code += spacePad + ".build();"
	return code
}

func (gen* javaClientGenerator) getBodyObj(r *rdl.Resource) string {
	idx, ok := gen.findFirstUserDefType(r.Inputs)
	if ok { return javaName(r.Inputs[idx].Name) }
	return ""
}

func (gen* javaClientGenerator) findFirstUserDefType(resInputs []*rdl.ResourceInput) (int, bool) {
	for idx, input := range resInputs {
		userType := gen.registry.FindBaseType(input.Type)
		// todo: need consider map or array case
		if userType == rdl.BaseTypeStruct {
			return idx, true
		}
	}
	return -1, false
}

func (gen *javaClientGenerator) needBody(r *rdl.Resource) bool {
	// check inputs is user defined type or not
	_, ok := gen.findFirstUserDefType(r.Inputs)
	return ok
}

const javaClientInterfaceTemplate = `{{origHeader}}
package {{origPackage}}.parsec_generated;

import java.util.concurrent.CompletableFuture;
import {{package}}.ResourceException;
{{range .Types}}{{if .StructTypeDef}}{{if .StructTypeDef.Name}}import {{package}}.{{.StructTypeDef.Name}};
{{end}}{{end}}{{end}}

public interface {{cName}}Client {
{{range .Resources}}
    {{iMethod .}}{{end}}
}
`
const javaClientTemplate = `{{origHeader}}
package {{origPackage}}.parsec_generated;

import {{package}}.ResourceException;
{{range .Types}}{{if .StructTypeDef}}{{if .StructTypeDef.Name}}import {{package}}.{{.StructTypeDef.Name}};
{{end}}{{end}}{{end}}
import com.ning.http.client.AsyncHandler;
import com.yahoo.parsec.clients.DefaultAsyncCompletionHandler;
import com.yahoo.parsec.clients.ParsecAsyncHttpClient;
import com.yahoo.parsec.clients.ParsecAsyncHttpRequest;
import com.yahoo.parsec.clients.ParsecAsyncHttpRequest.Builder;
{{if needImportJsonProcessingException .Resources}}
import com.fasterxml.jackson.core.JsonProcessingException;{{end}}
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.UriBuilder;
import java.net.URI;
{{if needImportHashSet .Resources}}import java.util.HashSet;
import java.util.Set;{{end}}
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class {{cName}}ClientImpl implements {{cName}}Client {

    /** Logger. */
    private static final Logger LOGGER = LoggerFactory.getLogger({{cName}}ClientImpl.class);

    /** ParsecAsyncHttpClient. */
    private final ParsecAsyncHttpClient parsecAsyncHttpClient;

    /** Object mapper */
    private final ObjectMapper objectMapper;

    /** URL. */
    private String url;

    /** Headers. */
    private final Map<String, String> headers;

    /**
     * connection timeout.
     */
    private static final int IDLE_CONNECTION_TIMEOUT_IN_MS = 15000;

    /**
     * total connections.
     */
    private static final int MAXIMUM_CONNECTIONS_TOTAL = 50;

    public {{cName}}ClientImpl(
        String url,
        Map<String, String> headers
    ) {

        ParsecAsyncHttpClient client  = null;
        try {
            client = new ParsecAsyncHttpClient.Builder()
                .setAcceptAnyCertificate(true)
                .setAllowPoolingConnections(true)
                .setPooledConnectionIdleTimeout(IDLE_CONNECTION_TIMEOUT_IN_MS)
                .setMaxConnections(MAXIMUM_CONNECTIONS_TOTAL)
                .build();
        } catch (ExecutionException e) {
            LOGGER.error("create ParsecAsyncHttpClient failed. " + e.getMessage());
            throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        this.parsecAsyncHttpClient = client;
        this.objectMapper = new ObjectMapper();
        this.url = url;
        this.headers = headers;
    }

    public {{cName}}ClientImpl(
            ParsecAsyncHttpClient client,
            ObjectMapper objectMapper,
            String url,
            Map<String, String> headers
    ) {
        this.parsecAsyncHttpClient = client;
        this.objectMapper = objectMapper;
        this.url = url;
        this.headers = headers;
    }

    private ParsecAsyncHttpRequest getRequest(String method, URI uri, String body) throws ResourceException {
        Builder builder = new Builder();

        builder.setUri(uri);
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        builder.setMethod(method);

        builder.setBody(body).setBodyEncoding("UTF-8");

        ParsecAsyncHttpRequest request = null;
        try {
            request = builder.build();
        } catch (Exception e) {
            LOGGER.error("builder build failed: " + e.getMessage());
            throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return request;
    }
{{range .Resources}}
    @Override
    {{methodSig .}} {
        String path = "{{.Path}}";
        String body = null;
{{if needBody .}}
        try {
            body = objectMapper.writeValueAsString({{bodyObj .}});
        } catch (JsonProcessingException e) {
            LOGGER.error("JsonProcessingException: " + e.getMessage());
            throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR, e.getMessage());
        }
{{end}}
        URI uri = UriBuilder.fromUri(url).path(path){{builderExt .}}
        ParsecAsyncHttpRequest request = getRequest("{{.Method}}", uri, body);

{{if needExpect .}}
        Set<Integer> expectedStatus = new HashSet<>();
        expectedStatus.add(ResourceException.{{.Expected}});
        {{if .Alternatives}}{{range .Alternatives}}expectedStatus.add(ResourceException.{{.}});
{{end}}{{end}}
        AsyncHandler<{{returnType .}}> asyncHandler = new DefaultAsyncCompletionHandler<>({{returnType .}}.class, expectedStatus);
{{else}}
        AsyncHandler<{{returnType .}}> asyncHandler = new DefaultAsyncCompletionHandler<>({{returnType .}}.class);
{{end}}
        return parsecAsyncHttpClient.criticalExecute(request, asyncHandler);
    }
{{end}}
}
`

// todo: copy from go-schema.go
func safeTypeVarName(rtype rdl.TypeRef) rdl.TypeName {
	tokens := strings.Split(string(rtype), ".")
	return rdl.TypeName(utils.Capitalize(strings.Join(tokens, "")))
}

// todo: duplicate with server code, need integrate
func javaMethodName(reg rdl.TypeRegistry, r *rdl.Resource) (string, []string) {
	var params []string
	bodyType := string(safeTypeVarName(r.Type))
	for _, v := range r.Inputs {
		if v.Context != "" { //ignore these legacy things
			log.Println("Warning: v1 style context param ignored:", v.Name, v.Context)
			continue
		}
		k := v.Name
		if v.QueryParam == "" && !v.PathParam && v.Header == "" {
			bodyType = string(safeTypeVarName(v.Type))
		}
		optional := false // but different with server code, how?
		params = append(params, utils.JavaType(reg, v.Type, optional, "", "")+" "+javaName(k))
	}
	return strings.ToLower(string(r.Method)) + string(bodyType), params
}

// todo: duplicate with java-server.go
func javaName(name rdl.Identifier) string {
	switch name {
	case "type", "default": //other reserved words
		return "_" + string(name)
	default:
		return string(name)
	}
}

func (gen *javaClientGenerator) clientMethodSignature(r *rdl.Resource) string {
	reg := gen.registry
	returnType := utils.JavaType(reg, r.Type, true, "", "")
	methName, params := javaMethodName(reg, r)
	sparams := ""
	if len(params) > 0 {
		sparams = strings.Join(params, ", ")
	}
	if len(r.Outputs) > 0 {
		if sparams == "" {
			sparams = "java.util.Map<String,java.util.List<String>> headers"
		} else {
			sparams = sparams + ", java.util.Map<String,java.util.List<String>> headers"
		}
	}
	return "CompletableFuture<" + returnType + "> " + methName + "(" + sparams + ") throws ResourceException"
}

<commit_msg>modify template, user can set headers on functions of client<commit_after>// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.

package main

import (
	"github.com/ardielle/ardielle-go/rdl"
	"bufio"
	"strings"
	"log"
	"flag"
	"io/ioutil"
	"fmt"
	"encoding/json"
	"os"
	"github.com/yahoo/parsec-rdl-gen/utils"
	"text/template"
)

type javaClientGenerator struct {
	registry rdl.TypeRegistry
	schema   *rdl.Schema
	name     string
	writer   *bufio.Writer
	err      error
	banner   string
	ns       string
	base     string
}

func main() {
	pOutdir := flag.String("o", ".", "Output directory")
	flag.String("s", "", "RDL source file")
	namespace := flag.String("ns", "", "Namespace")
	flag.Parse()
	data, err := ioutil.ReadAll(os.Stdin)
	banner := "parsec-rdl-gen (development version)"

	if err == nil {
		var schema rdl.Schema
		err = json.Unmarshal(data, &schema)
		if err == nil {
			GenerateJavaClient(banner, &schema, *pOutdir, *namespace, "")
			os.Exit(0)
		}
	}
	fmt.Fprintf(os.Stderr, "*** %v\n", err)
	os.Exit(1)
}

// GenerateJavaClient generates the client code to talk to the server
func GenerateJavaClient(banner string, schema *rdl.Schema, outdir string, ns string, base string) error {

	reg := rdl.NewTypeRegistry(schema)

	packageDir, err := utils.JavaGenerationDir(outdir, schema, ns)
	if err != nil {
		return err
	}

	cName := utils.Capitalize(string(schema.Name))

	out, file, _, err := utils.OutputWriter(packageDir, cName, "ClientImpl.java")
	if err != nil {
		return err
	}
	gen := &javaClientGenerator{reg, schema, cName, out, nil, banner, ns, base}
	gen.processTemplate(javaClientTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	out, file, _, err = utils.OutputWriter(packageDir, cName, "Client.java")
	if err != nil {
		return err
	}
	gen = &javaClientGenerator{reg, schema, cName, out, nil, banner, ns, base}
	gen.processTemplate(javaClientInterfaceTemplate)
	out.Flush()
	file.Close()
	if gen.err != nil {
		return gen.err
	}

	//ResourceException - the throawable wrapper for alternate return types
	out, file, _, err = utils.OutputWriter(packageDir, "ResourceException", ".java")
	if err != nil {
		return err
	}
	err = utils.JavaGenerateResourceException(schema, out, ns)
	out.Flush()
	file.Close()
	if err != nil {
		return err
	}

	//ResourceError - the default data object for an error
	out, file, _, err = utils.OutputWriter(packageDir, "ResourceError", ".java")
	if err != nil {
		return err
	}
	err = utils.JavaGenerateResourceError(schema, out, ns)
	out.Flush()
	file.Close()
	return err
}

func (gen *javaClientGenerator) processTemplate(templateSource string) error {
	commentFun := func(s string) string {
		return utils.FormatComment(s, 0, 80)
	}
	needExpectFunc := func(r *rdl.Resource) bool {
		if (r.Expected != "OK" || len(r.Alternatives) > 0) {
			return true
		}
		return false
	}
	needImportHashSetFunc := func(rs []*rdl.Resource) bool {
		for _,r := range rs {
			if (needExpectFunc(r)) {
				return true
			}
		}
		return false
	}
	needBodyFunc := func(r *rdl.Resource) bool { return gen.needBody(r) }
	needImportJsonProcessingExceptionFunc := func(rs []*rdl.Resource) bool {
		for _,r := range rs {
			if (needBodyFunc(r)) {
				return true
			}
		}
		return false
	}
	funcMap := template.FuncMap{
		"header":      func() string { return utils.JavaGenerationHeader(gen.banner) },
		"package":     func() string { return utils.JavaGenerationPackage(gen.schema, gen.ns) },
		"comment":     commentFun,
		"methodSig":   func(r *rdl.Resource) string { return "public "+ gen.clientMethodSignature(r) },
		"name":        func() string { return gen.name },
		"cName":       func() string { return utils.Capitalize(gen.name) },
		"lName":       func() string { return utils.Uncapitalize(gen.name) },
		"needBody":    needBodyFunc,
		"bodyObj":     func(r *rdl.Resource) string { return gen.getBodyObj(r) },
		"iMethod":     func(r *rdl.Resource) string { return gen.clientMethodSignature(r) + ";" },
		"builderExt":  func(r *rdl.Resource) string { return gen.builderExt(r) },
		"origPackage": func() string { return utils.JavaGenerationOrigPackage(gen.schema, gen.ns) },
		"origHeader":  func() string { return utils.JavaGenerationOrigHeader(gen.banner) },
		"returnType":  func(r *rdl.Resource) string { return utils.JavaType(gen.registry, r.Type, true, "", "")},
		"needExpect":  needExpectFunc,
		"needImportHashSet":  needImportHashSetFunc,
		"needImportJsonProcessingException": needImportJsonProcessingExceptionFunc,
	}
	t := template.Must(template.New(gen.name).Funcs(funcMap).Parse(templateSource))
	return t.Execute(gen.writer, gen.schema)
}

func (gen* javaClientGenerator) builderExt(r *rdl.Resource) string {
	code := "\n"
	spacePad := "                            "
	for _, input := range r.Inputs {
		iname := javaName(input.Name)
		if input.PathParam {
			code += spacePad + ".resolveTemplate(\"" + iname + "\", " + iname + ")\n"
		} else if input.QueryParam != "" {
			code += spacePad + ".queryParam(\"" + iname + "\", " + iname + ")\n"
		}
	}
	code += spacePad + ".build();"
	return code
}

func (gen* javaClientGenerator) getBodyObj(r *rdl.Resource) string {
	idx, ok := gen.findFirstUserDefType(r.Inputs)
	if ok { return javaName(r.Inputs[idx].Name) }
	return ""
}

func (gen* javaClientGenerator) findFirstUserDefType(resInputs []*rdl.ResourceInput) (int, bool) {
	for idx, input := range resInputs {
		userType := gen.registry.FindBaseType(input.Type)
		// todo: need consider map or array case
		if userType == rdl.BaseTypeStruct {
			return idx, true
		}
	}
	return -1, false
}

func (gen *javaClientGenerator) needBody(r *rdl.Resource) bool {
	// check inputs is user defined type or not
	_, ok := gen.findFirstUserDefType(r.Inputs)
	return ok
}

const javaClientInterfaceTemplate = `{{origHeader}}
package {{origPackage}}.parsec_generated;

import java.util.Map;
import java.util.concurrent.CompletableFuture;
import {{package}}.ResourceException;
{{range .Types}}{{if .StructTypeDef}}{{if .StructTypeDef.Name}}import {{package}}.{{.StructTypeDef.Name}};
{{end}}{{end}}{{end}}

public interface {{cName}}Client {
{{range .Resources}}
    {{iMethod .}}{{end}}
}
`
const javaClientTemplate = `{{origHeader}}
package {{origPackage}}.parsec_generated;

import {{package}}.ResourceException;
{{range .Types}}{{if .StructTypeDef}}{{if .StructTypeDef.Name}}import {{package}}.{{.StructTypeDef.Name}};
{{end}}{{end}}{{end}}
import com.ning.http.client.AsyncHandler;
import com.yahoo.parsec.clients.DefaultAsyncCompletionHandler;
import com.yahoo.parsec.clients.ParsecAsyncHttpClient;
import com.yahoo.parsec.clients.ParsecAsyncHttpRequest;
import com.yahoo.parsec.clients.ParsecAsyncHttpRequest.Builder;
{{if needImportJsonProcessingException .Resources}}
import com.fasterxml.jackson.core.JsonProcessingException;{{end}}
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.UriBuilder;
import java.net.URI;
{{if needImportHashSet .Resources}}import java.util.HashSet;
import java.util.Set;{{end}}
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class {{cName}}ClientImpl implements {{cName}}Client {

    /** Logger. */
    private static final Logger LOGGER = LoggerFactory.getLogger({{cName}}ClientImpl.class);

    /** ParsecAsyncHttpClient. */
    private final ParsecAsyncHttpClient parsecAsyncHttpClient;

    /** Object mapper */
    private final ObjectMapper objectMapper;

    /** URL. */
    private String url;

    /** Headers. */
    private Map<String, String> defaultHeaders;

    /**
     * connection timeout.
     */
    private static final int IDLE_CONNECTION_TIMEOUT_IN_MS = 15000;

    /**
     * total connections.
     */
    private static final int MAXIMUM_CONNECTIONS_TOTAL = 50;

    public {{cName}}ClientImpl(String url) {
        this(url, null);
    }

    public {{cName}}ClientImpl(
        String url,
        Map<String, String> headers
    ) {

        ParsecAsyncHttpClient client  = null;
        try {
            client = new ParsecAsyncHttpClient.Builder()
                .setAcceptAnyCertificate(true)
                .setAllowPoolingConnections(true)
                .setPooledConnectionIdleTimeout(IDLE_CONNECTION_TIMEOUT_IN_MS)
                .setMaxConnections(MAXIMUM_CONNECTIONS_TOTAL)
                .build();
        } catch (ExecutionException e) {
            LOGGER.error("create ParsecAsyncHttpClient failed. " + e.getMessage());
            throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        this.parsecAsyncHttpClient = client;
        this.objectMapper = new ObjectMapper();
        this.url = url;
        this.defaultHeaders = headers;
    }

    public {{cName}}ClientImpl(
            ParsecAsyncHttpClient client,
            ObjectMapper objectMapper,
            String url,
            Map<String, String> headers
    ) {
        this.parsecAsyncHttpClient = client;
        this.objectMapper = objectMapper;
        this.url = url;
        this.defaultHeaders = headers;
    }

    private ParsecAsyncHttpRequest getRequest(
            String method,
            Map<String, String> headers,
            URI uri,
            String body
    ) throws ResourceException {
        Builder builder = new Builder();

        builder.setUri(uri);
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }

        builder.setMethod(method);

        builder.setBody(body).setBodyEncoding("UTF-8");

        ParsecAsyncHttpRequest request = null;
        try {
            request = builder.build();
        } catch (Exception e) {
            LOGGER.error("builder build failed: " + e.getMessage());
            throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return request;
    }

    public Map<String, String> getDefaultHeaders() {
        return defaultHeaders;
    }

    public void setHeaders(Map<String, String> headers) {
        this.defaultHeaders = headers;
    }
{{range .Resources}}
    @Override
    {{methodSig .}} {
        String path = "{{.Path}}";
        String body = null;
{{if needBody .}}
        try {
            body = objectMapper.writeValueAsString({{bodyObj .}});
        } catch (JsonProcessingException e) {
            LOGGER.error("JsonProcessingException: " + e.getMessage());
            throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR, e.getMessage());
        }
{{end}}
        URI uri = UriBuilder.fromUri(url).path(path){{builderExt .}}
        if (headers == null) {
            headers = getDefaultHeaders();
        }
        ParsecAsyncHttpRequest request = getRequest("{{.Method}}", headers, uri, body);

{{if needExpect .}}
        Set<Integer> expectedStatus = new HashSet<>();
        expectedStatus.add(ResourceException.{{.Expected}});
        {{if .Alternatives}}{{range .Alternatives}}expectedStatus.add(ResourceException.{{.}});
{{end}}{{end}}
        AsyncHandler<{{returnType .}}> asyncHandler = new DefaultAsyncCompletionHandler<>({{returnType .}}.class, expectedStatus);
{{else}}
        AsyncHandler<{{returnType .}}> asyncHandler = new DefaultAsyncCompletionHandler<>({{returnType .}}.class);
{{end}}
        return parsecAsyncHttpClient.criticalExecute(request, asyncHandler);
    }
{{end}}
}
`

// todo: copy from go-schema.go
func safeTypeVarName(rtype rdl.TypeRef) rdl.TypeName {
	tokens := strings.Split(string(rtype), ".")
	return rdl.TypeName(utils.Capitalize(strings.Join(tokens, "")))
}

// todo: duplicate with server code, need integrate
func javaMethodName(reg rdl.TypeRegistry, r *rdl.Resource) (string, []string) {
	var params []string
	bodyType := string(safeTypeVarName(r.Type))
	for _, v := range r.Inputs {
		if v.Context != "" { //ignore these legacy things
			log.Println("Warning: v1 style context param ignored:", v.Name, v.Context)
			continue
		}
		k := v.Name
		if v.QueryParam == "" && !v.PathParam && v.Header == "" {
			bodyType = string(safeTypeVarName(v.Type))
		}
		optional := false // but different with server code, how?
		params = append(params, utils.JavaType(reg, v.Type, optional, "", "")+" "+javaName(k))
	}
	return strings.ToLower(string(r.Method)) + string(bodyType), params
}

// todo: duplicate with java-server.go
func javaName(name rdl.Identifier) string {
	switch name {
	case "type", "default": //other reserved words
		return "_" + string(name)
	default:
		return string(name)
	}
}

func (gen *javaClientGenerator) clientMethodSignature(r *rdl.Resource) string {
	reg := gen.registry
	returnType := utils.JavaType(reg, r.Type, true, "", "")
	methName, params := javaMethodName(reg, r)
	sparams := "Map<String, String> headers"
	if len(params) > 0 {
		sparams = sparams + ", " + strings.Join(params, ", ")
	}
	return "CompletableFuture<" + returnType + "> " + methName + "(" + sparams + ") throws ResourceException"
}

<|endoftext|>


<commit_before>/*Package configurationFile represents Encodable/Decodable Golang structures from/to TOML structures.
 *
 *The global structure is ConfigurationFile, which is the simple way to store accurtely your local informations.
 *
 */
package configurationFile

import (
	"bytes"
	"errors"
	"io/ioutil"
	"path/filepath"

	"fmt"

	"os/user"

	"os"

	"strings"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/gitManip"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
)

/*GetConfigurationFileContent get the content of the local configuration file.
 *If no configuration file has been found, create a default one and set the bytes array.
 */
func GetConfigurationFileContent(filePointer *os.File, bytesArray *[]byte) {
	fileState, err := filePointer.Stat()
	// If the file is empty, get the default structure and save it
	if err != nil || fileState.Size() == 0 {
		traces.WarningTracer.Println("No (or empty) configuration file - creating default one...")
		var fileBuffer bytes.Buffer
		defaultStructure := Default()
		defaultStructure.Encode(&fileBuffer)
		*bytesArray = fileBuffer.Bytes()
	} else {
		b, _ := ioutil.ReadAll(filePointer)
		*bytesArray = b
	}
}

/*ConfigurationFile represents the TOML structure of the Goyave configuration file.
 *
 *The structure of the configuration file is:
 *	Author:
 *		The name of the user.
 *	VisibleRepositories:
 *		A list of local visible git repositories.
 *	HiddenRepositories:
 *		A list of local ignored git repositories.
 *	Groups:
 *		A list of groups.
 */
type ConfigurationFile struct {
	Author              string
	Local               LocalInformations `toml:"local"`
	VisibleRepositories []GitRepository   `toml:"visible"`
	HiddenRepositories  []GitRepository   `toml:"hidden"`
	Groups              []Group           `toml:"group"`
}

/*Default returns a default ConfigurationFile structure.
 */
func Default() *ConfigurationFile {
	usr, _ := user.Current()
	return &ConfigurationFile{
		Author: usr.Username,
		Local: LocalInformations{
			DefaultTarget: consts.VisibleFlag,
			Group:         utils.GetLocalhost(),
		},
	}
}

/*GetDefaultEntry returns the default entry to store a new git repository.
 *This methods returns HiddenFlag, or VisibleFlag
 */
func (c *ConfigurationFile) GetDefaultEntry() (string, error) {
	defaultTarget := c.Local.DefaultTarget
	if defaultTarget != consts.VisibleFlag && defaultTarget != consts.HiddenFlag {
		return consts.VisibleFlag, fmt.Errorf("the default target is not set to %s or %s. Please check your configuration file", consts.HiddenFlag, consts.VisibleFlag)
	}
	return defaultTarget, nil
}

/*AddRepository will add a single path in the TOML's target if the path does not exists.
 *This method uses both methods addVisibleRepository and addHiddenRepository.
 */
func (c *ConfigurationFile) AddRepository(path string, target string) error {
	if target == consts.VisibleFlag {
		return c.addVisibleRepository(path)
	}
	if target == consts.HiddenFlag {
		return c.addHiddenRepository(path)
	}
	return errors.New("the target does not exists")
}

/*addVisibleRepository adds a given git repo path as a visible repository.
 *If the repository already exists in the VisibleRepository field, the method throws an error: RepositoryAlreadyExists.
 *Else, the repository is append to the VisibleRepository field, and the method returns nil.
 */
func (c *ConfigurationFile) addVisibleRepository(path string) error {
	for _, registeredRepository := range c.VisibleRepositories {
		if registeredRepository.Path == path {
			return errors.New(consts.RepositoryAlreadyExists)
		}
	}
	var newVisibleRepository = GitRepository{
		Name: filepath.Base(path),
		Path: path,
	}
	c.VisibleRepositories = append(c.VisibleRepositories, newVisibleRepository)
	return nil
}

/*addHiddenRepository adds a given git repo path as an hidden repository.
 *If the repository already exists in the HiddenRepository field, the method throws an error: RepositoryAlreadyExists.
 *Else, the repository is append to the HiddenRepository field, and the method returns nil.
 */
func (c *ConfigurationFile) addHiddenRepository(path string) error {
	for _, registeredRepository := range c.HiddenRepositories {
		if registeredRepository.Path == path {
			return errors.New(consts.RepositoryAlreadyExists)
		}
	}
	var newHiddenRepository = GitRepository{
		Name: filepath.Base(path),
		Path: path,
	}
	c.HiddenRepositories = append(c.HiddenRepositories, newHiddenRepository)
	return nil
}

/*RemoveRepositoryFromSlice returns a new slice without the corresponding element (here, a string).
 *If the element is not found, this method returns an error.
 */
func (c *ConfigurationFile) RemoveRepositoryFromSlice(path string, slice string) error {
	// The code below is the same for visible and hidden repositories - need to refactor the code later
	if slice == consts.VisibleFlag {
		sliceIndex := utils.SliceIndex(len(c.VisibleRepositories), func(i int) bool { return c.VisibleRepositories[i].Path == path })
		if sliceIndex != -1 {
			c.VisibleRepositories = append(c.VisibleRepositories[:sliceIndex], c.VisibleRepositories[sliceIndex+1:]...)
			return nil
		}
		return errors.New(consts.ItemIsNotInSlice)
	}
	sliceIndex := utils.SliceIndex(len(c.HiddenRepositories), func(i int) bool { return c.HiddenRepositories[i].Path == path })
	if sliceIndex != -1 {
		c.HiddenRepositories = append(c.HiddenRepositories[:sliceIndex], c.HiddenRepositories[sliceIndex+1:]...)
		return nil
	}
	return errors.New(consts.ItemIsNotInSlice)
}

/*GitRepository represents the structure of a local git repository.
 *
 *Properties of this structure are:
 *	GitObject:
 *		A reference to a git structure that represents the repository.
 *	Name:
 * 		The custom name of the repository.
 *	Path:
 *		The path of the repository.
 */
type GitRepository struct {
	GitObject *gitManip.GitObject
	Name      string
	Path      string
}

/*ByName implements sort.Interface for []GitRepository based on the Name field.
 */
type ByName []GitRepository

/*Len returns the length of the ByName type object.
 */
func (g ByName) Len() int { return len(g) }

/*Swap swaps two objects in the same array.
 */
func (g ByName) Swap(i, j int) { g[i], g[j] = g[j], g[i] }

/*Less returns True if the first element is lower than the second one (alphabetic order).
 */
func (g ByName) Less(i, j int) bool { return strings.Compare(g[i].Name, g[j].Name) == -1 }

/*NewGitRepository instantiates the GitRepository struct, based on the path information.
 */
func NewGitRepository(name, path string) *GitRepository {
	return &GitRepository{
		GitObject: gitManip.New(path),
		Name:      name,
		Path:      path,
	}
}

/*Init (re)initializes the GitObject structure
 */
func (g *GitRepository) Init() {
	g.GitObject = gitManip.New(g.Path)
}

/*isExists check if the current path of the git repository is correct or not,
 *and if the current repository exists again or not.
 *This methods returns a boolean value.
 */
func (g *GitRepository) isExists() bool {
	_, err := os.Stat(g.Path)
	return os.IsNotExist(err)
}

/*Group represents a group of git repositories.
 *
 *The structure of a Group type is:
 *
 *	Name:
 *		The group name.
 *	Repositories:
 *		A list of git repositories id, tagged in the group.
 */
type Group struct {
	Name         string
	Repositories []string
}

/*LocalInformations represents your local configuration of Goyave.
 *
 *The structure contains:
 *  DefaultEntry:
 *		The default entry to store a git repository (hidden or visible).
 *	Group:
 *		The current group name.
 */
type LocalInformations struct {
	DefaultTarget string
	Group         string
}

/*DecodeString is a function to decode an entire string (which is the content of a given TOML file) to a ConfigurationFile structure.
 */
func DecodeString(c *ConfigurationFile, data string) error {
	_, err := toml.Decode(data, *c)
	return err
}

/*DecodeBytesArray is a function to decode an entire string (which is the content of a given TOML file) to a ConfigurationFile structure.
 */
func DecodeBytesArray(c *ConfigurationFile, data []byte) error {
	_, err := toml.Decode(string(data[:]), *c)
	return err
}

/*Encode is a function to encode a ConfigurationFile structure to a byffer of bytes.
 */
func (c *ConfigurationFile) Encode(buffer *bytes.Buffer) error {
	return toml.NewEncoder(buffer).Encode(c)
}
<commit_msg>Add a method to get the path of a given repository<commit_after>/*Package configurationFile represents Encodable/Decodable Golang structures from/to TOML structures.
 *
 *The global structure is ConfigurationFile, which is the simple way to store accurtely your local informations.
 *
 */
package configurationFile

import (
	"bytes"
	"errors"
	"io/ioutil"
	"path/filepath"

	"fmt"

	"os/user"

	"os"

	"strings"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/gitManip"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
)

/*GetConfigurationFileContent get the content of the local configuration file.
 *If no configuration file has been found, create a default one and set the bytes array.
 */
func GetConfigurationFileContent(filePointer *os.File, bytesArray *[]byte) {
	fileState, err := filePointer.Stat()
	// If the file is empty, get the default structure and save it
	if err != nil || fileState.Size() == 0 {
		traces.WarningTracer.Println("No (or empty) configuration file - creating default one...")
		var fileBuffer bytes.Buffer
		defaultStructure := Default()
		defaultStructure.Encode(&fileBuffer)
		*bytesArray = fileBuffer.Bytes()
	} else {
		b, _ := ioutil.ReadAll(filePointer)
		*bytesArray = b
	}
}

/*ConfigurationFile represents the TOML structure of the Goyave configuration file.
 *
 *The structure of the configuration file is:
 *	Author:
 *		The name of the user.
 *	VisibleRepositories:
 *		A list of local visible git repositories.
 *	HiddenRepositories:
 *		A list of local ignored git repositories.
 *	Groups:
 *		A list of groups.
 */
type ConfigurationFile struct {
	Author              string
	Local               LocalInformations `toml:"local"`
	VisibleRepositories []GitRepository   `toml:"visible"`
	HiddenRepositories  []GitRepository   `toml:"hidden"`
	Groups              []Group           `toml:"group"`
}

/*Default returns a default ConfigurationFile structure.
 */
func Default() *ConfigurationFile {
	usr, _ := user.Current()
	return &ConfigurationFile{
		Author: usr.Username,
		Local: LocalInformations{
			DefaultTarget: consts.VisibleFlag,
			Group:         utils.GetLocalhost(),
		},
	}
}

/*GetDefaultEntry returns the default entry to store a new git repository.
 *This methods returns HiddenFlag, or VisibleFlag
 */
func (c *ConfigurationFile) GetDefaultEntry() (string, error) {
	defaultTarget := c.Local.DefaultTarget
	if defaultTarget != consts.VisibleFlag && defaultTarget != consts.HiddenFlag {
		return consts.VisibleFlag, fmt.Errorf("the default target is not set to %s or %s. Please check your configuration file", consts.HiddenFlag, consts.VisibleFlag)
	}
	return defaultTarget, nil
}

/*AddRepository will add a single path in the TOML's target if the path does not exists.
 *This method uses both methods addVisibleRepository and addHiddenRepository.
 */
func (c *ConfigurationFile) AddRepository(path string, target string) error {
	if target == consts.VisibleFlag {
		return c.addVisibleRepository(path)
	}
	if target == consts.HiddenFlag {
		return c.addHiddenRepository(path)
	}
	return errors.New("the target does not exists")
}

/*addVisibleRepository adds a given git repo path as a visible repository.
 *If the repository already exists in the VisibleRepository field, the method throws an error: RepositoryAlreadyExists.
 *Else, the repository is append to the VisibleRepository field, and the method returns nil.
 */
func (c *ConfigurationFile) addVisibleRepository(path string) error {
	for _, registeredRepository := range c.VisibleRepositories {
		if registeredRepository.Path == path {
			return errors.New(consts.RepositoryAlreadyExists)
		}
	}
	var newVisibleRepository = GitRepository{
		Name: filepath.Base(path),
		Path: path,
	}
	c.VisibleRepositories = append(c.VisibleRepositories, newVisibleRepository)
	return nil
}

/*addHiddenRepository adds a given git repo path as an hidden repository.
 *If the repository already exists in the HiddenRepository field, the method throws an error: RepositoryAlreadyExists.
 *Else, the repository is append to the HiddenRepository field, and the method returns nil.
 */
func (c *ConfigurationFile) addHiddenRepository(path string) error {
	for _, registeredRepository := range c.HiddenRepositories {
		if registeredRepository.Path == path {
			return errors.New(consts.RepositoryAlreadyExists)
		}
	}
	var newHiddenRepository = GitRepository{
		Name: filepath.Base(path),
		Path: path,
	}
	c.HiddenRepositories = append(c.HiddenRepositories, newHiddenRepository)
	return nil
}

/*GetPathFromRepository returns the path of a given git repository name.
 *If the repository does not exists, it returns an empty string.
 */
func (c *ConfigurationFile) GetPathFromRepository(target string) string {
	for _, registeredRepository := range c.VisibleRepositories {
		if registeredRepository.Name == target {
			return registeredRepository.Path
		}
	}
	return ""
}

/*RemoveRepositoryFromSlice returns a new slice without the corresponding element (here, a string).
 *If the element is not found, this method returns an error.
 */
func (c *ConfigurationFile) RemoveRepositoryFromSlice(path string, slice string) error {
	// The code below is the same for visible and hidden repositories - need to refactor the code later
	if slice == consts.VisibleFlag {
		sliceIndex := utils.SliceIndex(len(c.VisibleRepositories), func(i int) bool { return c.VisibleRepositories[i].Path == path })
		if sliceIndex != -1 {
			c.VisibleRepositories = append(c.VisibleRepositories[:sliceIndex], c.VisibleRepositories[sliceIndex+1:]...)
			return nil
		}
		return errors.New(consts.ItemIsNotInSlice)
	}
	sliceIndex := utils.SliceIndex(len(c.HiddenRepositories), func(i int) bool { return c.HiddenRepositories[i].Path == path })
	if sliceIndex != -1 {
		c.HiddenRepositories = append(c.HiddenRepositories[:sliceIndex], c.HiddenRepositories[sliceIndex+1:]...)
		return nil
	}
	return errors.New(consts.ItemIsNotInSlice)
}

/*GitRepository represents the structure of a local git repository.
 *
 *Properties of this structure are:
 *	GitObject:
 *		A reference to a git structure that represents the repository.
 *	Name:
 * 		The custom name of the repository.
 *	Path:
 *		The path of the repository.
 */
type GitRepository struct {
	GitObject *gitManip.GitObject
	Name      string
	Path      string
}

/*ByName implements sort.Interface for []GitRepository based on the Name field.
 */
type ByName []GitRepository

/*Len returns the length of the ByName type object.
 */
func (g ByName) Len() int { return len(g) }

/*Swap swaps two objects in the same array.
 */
func (g ByName) Swap(i, j int) { g[i], g[j] = g[j], g[i] }

/*Less returns True if the first element is lower than the second one (alphabetic order).
 */
func (g ByName) Less(i, j int) bool { return strings.Compare(g[i].Name, g[j].Name) == -1 }

/*NewGitRepository instantiates the GitRepository struct, based on the path information.
 */
func NewGitRepository(name, path string) *GitRepository {
	return &GitRepository{
		GitObject: gitManip.New(path),
		Name:      name,
		Path:      path,
	}
}

/*Init (re)initializes the GitObject structure
 */
func (g *GitRepository) Init() {
	g.GitObject = gitManip.New(g.Path)
}

/*isExists check if the current path of the git repository is correct or not,
 *and if the current repository exists again or not.
 *This methods returns a boolean value.
 */
func (g *GitRepository) isExists() bool {
	_, err := os.Stat(g.Path)
	return os.IsNotExist(err)
}

/*Group represents a group of git repositories.
 *
 *The structure of a Group type is:
 *
 *	Name:
 *		The group name.
 *	Repositories:
 *		A list of git repositories id, tagged in the group.
 */
type Group struct {
	Name         string
	Repositories []string
}

/*LocalInformations represents your local configuration of Goyave.
 *
 *The structure contains:
 *  DefaultEntry:
 *		The default entry to store a git repository (hidden or visible).
 *	Group:
 *		The current group name.
 */
type LocalInformations struct {
	DefaultTarget string
	Group         string
}

/*DecodeString is a function to decode an entire string (which is the content of a given TOML file) to a ConfigurationFile structure.
 */
func DecodeString(c *ConfigurationFile, data string) error {
	_, err := toml.Decode(data, *c)
	return err
}

/*DecodeBytesArray is a function to decode an entire string (which is the content of a given TOML file) to a ConfigurationFile structure.
 */
func DecodeBytesArray(c *ConfigurationFile, data []byte) error {
	_, err := toml.Decode(string(data[:]), *c)
	return err
}

/*Encode is a function to encode a ConfigurationFile structure to a byffer of bytes.
 */
func (c *ConfigurationFile) Encode(buffer *bytes.Buffer) error {
	return toml.NewEncoder(buffer).Encode(c)
}
<|endoftext|>


<commit_before>package systemd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"syscall"

	"github.com/coreos/fleet/third_party/github.com/coreos/go-systemd/dbus"
	log "github.com/coreos/fleet/third_party/github.com/golang/glog"

	"github.com/coreos/fleet/event"
	"github.com/coreos/fleet/job"
	"github.com/coreos/fleet/machine"
)

const (
	defaultSystemdRuntimePath = "/run/systemd/system/"
)

type SystemdManager struct {
	Systemd		*dbus.Conn
	Machine		*machine.Machine
	UnitPrefix	string
	unitPath	string

	subscriptions	*dbus.SubscriptionSet
	stop		chan bool
}

func NewSystemdManager(machine *machine.Machine, unitPrefix string) *SystemdManager {
	systemd, err := dbus.New()
	if err != nil {
		panic(err)
	}

	return &SystemdManager{systemd, machine, unitPrefix, defaultSystemdRuntimePath, systemd.NewSubscriptionSet(), nil}
}

func (m *SystemdManager) Publish(bus *event.EventBus, stopchan chan bool) {
	m.Systemd.Subscribe()

	changechan, errchan := m.subscriptions.Subscribe()

	stream := NewEventStream()
	stream.Stream(changechan, bus.Channel)

	for true {
		select {
		case <-stopchan:
			break
		case err := <-errchan:
			var errString string
			if err != nil {
				errString = err.Error()
			} else {
				errString = "N/A"
			}
			log.Errorf("Received error from dbus: err=%s", errString)
		}
	}

	stream.Close()
	m.Systemd.Unsubscribe()
}

func (m *SystemdManager) StartJob(job *job.Job) {
	name := m.addUnitNamePrefix(job.Name)
	m.writeUnit(name, job.Payload.Unit.String())
	m.daemonReload()

	m.subscriptions.Add(name)

	m.startUnit(name)
}

func (m *SystemdManager) StopJob(jobName string) {
	unitName := m.addUnitNamePrefix(jobName)

	m.subscriptions.Remove(jobName)

	m.stopUnit(unitName)
	m.removeUnit(unitName)
}

func (m *SystemdManager) getUnitStates(name string) (string, string, string, error) {
	info, err := m.Systemd.GetUnitProperties(name)

	if err != nil {
		return "", "", "", err
	} else {
		loadState := info["LoadState"].(string)
		activeState := info["ActiveState"].(string)
		subState := info["SubState"].(string)
		return loadState, activeState, subState, nil
	}
}

func (m *SystemdManager) startUnit(name string) {
	log.V(1).Infof("Starting systemd unit %s", name)

	files := []string{name}
	if _, _, err := m.Systemd.EnableUnitFiles(files, true, false); err != nil {
		log.Errorf("Failed to enable systemd unit %s: %v", name, err)
		return
	} else {
		log.V(1).Infof("Enabled systemd unit %s", name)
	}

	if stat, err := m.Systemd.StartUnit(name, "replace"); err != nil {
		log.Errorf("Failed to start systemd unit %s: %v", name, err)
	} else {
		log.Infof("Started systemd unit %s(%s)", name, stat)
	}
}

func (m *SystemdManager) stopUnit(name string) {
	log.V(1).Infof("Stopping systemd unit %s", name)

	if stat, err := m.Systemd.StopUnit(name, "replace"); err != nil {
		log.Errorf("Failed to stop systemd unit %s: %v", name, err)
	} else {
		log.Infof("Stopped systemd unit %s(%s)", name, stat)
	}

	// go-systemd does not yet have this implemented
	//files := []string{name}
	//Systemd.DisableUnitFiles(files, true, false)
}

func (m *SystemdManager) removeUnit(name string) {
	file := m.getLocalPath(name)
	log.Infof("Removing systemd unit file %s", file)
	syscall.Unlink(file)
}

func (m *SystemdManager) readUnit(name string) (string, error) {
	path := m.getLocalPath(name)
	contents, err := ioutil.ReadFile(path)
	if err == nil {
		return string(contents), nil
	} else {
		return "", errors.New(fmt.Sprintf("No unit file at local path %s", path))
	}
}

func (m *SystemdManager) daemonReload() error {
	log.Infof("Instructing systemd to reload units")
	return m.Systemd.Reload()
}

func (m *SystemdManager) writeUnit(name string, contents string) error {
	log.Infof("Writing systemd unit file %s", name)

	path := path.Join(m.unitPath, name)
	file, err := os.Create(path)
	defer file.Close()

	if err != nil {
		return err
	}

	file.Write([]byte(contents))
	return nil
}

func (m *SystemdManager) getLocalPath(name string) string {
	return path.Join(m.unitPath, name)
}

func (m *SystemdManager) addUnitNamePrefix(name string) string {
	if len(m.UnitPrefix) > 0 {
		return fmt.Sprintf("%s.%s", m.UnitPrefix, name)
	} else {
		return name
	}
}

func (m *SystemdManager) stripUnitNamePrefix(name string) string {
	if len(m.UnitPrefix) > 0 {
		return strings.TrimPrefix(name, fmt.Sprintf("%s.", m.UnitPrefix))
	} else {
		return name
	}
}
<commit_msg>chore(gofmt): gofmt systemd/manager.go<commit_after>package systemd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"syscall"

	"github.com/coreos/fleet/third_party/github.com/coreos/go-systemd/dbus"
	log "github.com/coreos/fleet/third_party/github.com/golang/glog"

	"github.com/coreos/fleet/event"
	"github.com/coreos/fleet/job"
	"github.com/coreos/fleet/machine"
)

const (
	defaultSystemdRuntimePath = "/run/systemd/system/"
)

type SystemdManager struct {
	Systemd    *dbus.Conn
	Machine    *machine.Machine
	UnitPrefix string
	unitPath   string

	subscriptions *dbus.SubscriptionSet
	stop          chan bool
}

func NewSystemdManager(machine *machine.Machine, unitPrefix string) *SystemdManager {
	systemd, err := dbus.New()
	if err != nil {
		panic(err)
	}

	return &SystemdManager{systemd, machine, unitPrefix, defaultSystemdRuntimePath, systemd.NewSubscriptionSet(), nil}
}

func (m *SystemdManager) Publish(bus *event.EventBus, stopchan chan bool) {
	m.Systemd.Subscribe()

	changechan, errchan := m.subscriptions.Subscribe()

	stream := NewEventStream()
	stream.Stream(changechan, bus.Channel)

	for true {
		select {
		case <-stopchan:
			break
		case err := <-errchan:
			var errString string
			if err != nil {
				errString = err.Error()
			} else {
				errString = "N/A"
			}
			log.Errorf("Received error from dbus: err=%s", errString)
		}
	}

	stream.Close()
	m.Systemd.Unsubscribe()
}

func (m *SystemdManager) StartJob(job *job.Job) {
	name := m.addUnitNamePrefix(job.Name)
	m.writeUnit(name, job.Payload.Unit.String())
	m.daemonReload()

	m.subscriptions.Add(name)

	m.startUnit(name)
}

func (m *SystemdManager) StopJob(jobName string) {
	unitName := m.addUnitNamePrefix(jobName)

	m.subscriptions.Remove(jobName)

	m.stopUnit(unitName)
	m.removeUnit(unitName)
}

func (m *SystemdManager) getUnitStates(name string) (string, string, string, error) {
	info, err := m.Systemd.GetUnitProperties(name)

	if err != nil {
		return "", "", "", err
	} else {
		loadState := info["LoadState"].(string)
		activeState := info["ActiveState"].(string)
		subState := info["SubState"].(string)
		return loadState, activeState, subState, nil
	}
}

func (m *SystemdManager) startUnit(name string) {
	log.V(1).Infof("Starting systemd unit %s", name)

	files := []string{name}
	if _, _, err := m.Systemd.EnableUnitFiles(files, true, false); err != nil {
		log.Errorf("Failed to enable systemd unit %s: %v", name, err)
		return
	} else {
		log.V(1).Infof("Enabled systemd unit %s", name)
	}

	if stat, err := m.Systemd.StartUnit(name, "replace"); err != nil {
		log.Errorf("Failed to start systemd unit %s: %v", name, err)
	} else {
		log.Infof("Started systemd unit %s(%s)", name, stat)
	}
}

func (m *SystemdManager) stopUnit(name string) {
	log.V(1).Infof("Stopping systemd unit %s", name)

	if stat, err := m.Systemd.StopUnit(name, "replace"); err != nil {
		log.Errorf("Failed to stop systemd unit %s: %v", name, err)
	} else {
		log.Infof("Stopped systemd unit %s(%s)", name, stat)
	}

	// go-systemd does not yet have this implemented
	//files := []string{name}
	//Systemd.DisableUnitFiles(files, true, false)
}

func (m *SystemdManager) removeUnit(name string) {
	file := m.getLocalPath(name)
	log.Infof("Removing systemd unit file %s", file)
	syscall.Unlink(file)
}

func (m *SystemdManager) readUnit(name string) (string, error) {
	path := m.getLocalPath(name)
	contents, err := ioutil.ReadFile(path)
	if err == nil {
		return string(contents), nil
	} else {
		return "", errors.New(fmt.Sprintf("No unit file at local path %s", path))
	}
}

func (m *SystemdManager) daemonReload() error {
	log.Infof("Instructing systemd to reload units")
	return m.Systemd.Reload()
}

func (m *SystemdManager) writeUnit(name string, contents string) error {
	log.Infof("Writing systemd unit file %s", name)

	path := path.Join(m.unitPath, name)
	file, err := os.Create(path)
	defer file.Close()

	if err != nil {
		return err
	}

	file.Write([]byte(contents))
	return nil
}

func (m *SystemdManager) getLocalPath(name string) string {
	return path.Join(m.unitPath, name)
}

func (m *SystemdManager) addUnitNamePrefix(name string) string {
	if len(m.UnitPrefix) > 0 {
		return fmt.Sprintf("%s.%s", m.UnitPrefix, name)
	} else {
		return name
	}
}

func (m *SystemdManager) stripUnitNamePrefix(name string) string {
	if len(m.UnitPrefix) > 0 {
		return strings.TrimPrefix(name, fmt.Sprintf("%s.", m.UnitPrefix))
	} else {
		return name
	}
}
<|endoftext|>


<commit_before>package statsd

import (
	"sync"

	backendTypes "github.com/atlassian/gostatsd/backend/types"
	"github.com/atlassian/gostatsd/types"

	log "github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

// dispatchingHandler dispatches events to all configured backends and forwards metrics to a Dispatcher.
type dispatchingHandler struct {
	wg         sync.WaitGroup
	dispatcher Dispatcher
	backends   []backendTypes.Backend
	tags       types.Tags // Tags to add to all metrics and events
}

// NewDispatchingHandler initialises a new dispatching handler.
func NewDispatchingHandler(dispatcher Dispatcher, backends []backendTypes.Backend, tags types.Tags) *dispatchingHandler {
	return &dispatchingHandler{
		dispatcher: dispatcher,
		backends:   backends,
		tags:       tags,
	}
}

func (dh *dispatchingHandler) DispatchMetric(ctx context.Context, m *types.Metric) error {
	if m.Hostname == "" {
		m.Hostname = string(m.SourceIP)
	}
	m.Tags = append(m.Tags, dh.tags...)
	return dh.dispatcher.DispatchMetric(ctx, m)
}

func (dh *dispatchingHandler) DispatchEvent(ctx context.Context, e *types.Event) error {
	if e.Hostname == "" {
		e.Hostname = string(e.SourceIP)
	}
	e.Tags = append(e.Tags, dh.tags...)
	dh.wg.Add(len(dh.backends))
	for _, backend := range dh.backends {
		go func(b backendTypes.Backend) {
			defer dh.wg.Done()
			if err := b.SendEvent(ctx, e); err != nil {
				log.Errorf("Sending event to backend failed: %v", err)
			}
		}(backend)
	}
	return nil
}

// WaitForEvents waits for all event-dispatching goroutines to finish.
func (dh *dispatchingHandler) WaitForEvents() {
	dh.wg.Wait()
}
<commit_msg>Do not log context errors<commit_after>package statsd

import (
	"sync"

	backendTypes "github.com/atlassian/gostatsd/backend/types"
	"github.com/atlassian/gostatsd/types"

	log "github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

// dispatchingHandler dispatches events to all configured backends and forwards metrics to a Dispatcher.
type dispatchingHandler struct {
	wg         sync.WaitGroup
	dispatcher Dispatcher
	backends   []backendTypes.Backend
	tags       types.Tags // Tags to add to all metrics and events
}

// NewDispatchingHandler initialises a new dispatching handler.
func NewDispatchingHandler(dispatcher Dispatcher, backends []backendTypes.Backend, tags types.Tags) *dispatchingHandler {
	return &dispatchingHandler{
		dispatcher: dispatcher,
		backends:   backends,
		tags:       tags,
	}
}

func (dh *dispatchingHandler) DispatchMetric(ctx context.Context, m *types.Metric) error {
	if m.Hostname == "" {
		m.Hostname = string(m.SourceIP)
	}
	m.Tags = append(m.Tags, dh.tags...)
	return dh.dispatcher.DispatchMetric(ctx, m)
}

func (dh *dispatchingHandler) DispatchEvent(ctx context.Context, e *types.Event) error {
	if e.Hostname == "" {
		e.Hostname = string(e.SourceIP)
	}
	e.Tags = append(e.Tags, dh.tags...)
	dh.wg.Add(len(dh.backends))
	for _, backend := range dh.backends {
		go func(b backendTypes.Backend) {
			defer dh.wg.Done()
			if err := b.SendEvent(ctx, e); err != nil && err != context.Canceled && err != context.DeadlineExceeded {
				log.Errorf("Sending event to backend failed: %v", err)
			}
		}(backend)
	}
	return nil
}

// WaitForEvents waits for all event-dispatching goroutines to finish.
func (dh *dispatchingHandler) WaitForEvents() {
	dh.wg.Wait()
}
<|endoftext|>


<commit_before>package controller

import (
	"fmt"
)

type ScanImage struct {
	imageId		string
	taggedName 	string
	digest		string
}

func (image ScanImage) scan () (e error){

	//cmd := fmt.Sprintf ("docker run -ti --rm -v /var/run/docker.sock:/var/run/docker.sock --privileged %s /ose_scanner -h %s -p %s -s %s -u %s -w %s -id %s -tag %s", Hub.Scanner, Hub.Host, Hub.Port, Hub.Scheme, Hub.Username, Hub.Password, image.imageId, image.taggedName)

	fmt.Printf ("Scanning: %s (%s)\n", image.taggedName, image.imageId[:10])

	args := []string {}
	args = append(args, "/oc_scanner")

	args = append(args, "-h")
	args = append(args, Hub.Host)

	args = append(args, "-p")
	args = append(args, Hub.Port)

	args = append(args, "-s")
	args = append(args, Hub.Scheme)

	args = append(args, "-u")
	args = append(args, Hub.Username)

	args = append(args, "-w")
	args = append(args, Hub.Password)

	args = append(args, "-id")
	args = append(args, image.imageId)

	args = append(args, "-tag")
	args = append(args, image.taggedName)

	args = append(args, "-digest")
	args = append(args, image.digest)

	docker := NewDocker ()

	err := docker.launchContainer (Hub.Scanner, args)

	if err != nil {
		fmt.Printf ("Error creating scanning container: %s\n", err)
		return err
	}

	fmt.Printf ("Done Scanning: %s\n", image.taggedName)

	//time.Sleep(10*time.Second)
	return nil
}

<commit_msg>Fixed typo in container exec<commit_after>package controller

import (
	"fmt"
)

type ScanImage struct {
	imageId		string
	taggedName 	string
	digest		string
}

func (image ScanImage) scan () (e error){

	//cmd := fmt.Sprintf ("docker run -ti --rm -v /var/run/docker.sock:/var/run/docker.sock --privileged %s /ose_scanner -h %s -p %s -s %s -u %s -w %s -id %s -tag %s", Hub.Scanner, Hub.Host, Hub.Port, Hub.Scheme, Hub.Username, Hub.Password, image.imageId, image.taggedName)

	fmt.Printf ("Scanning: %s (%s)\n", image.taggedName, image.imageId[:10])

	args := []string {}
	args = append(args, "/ose_scanner")

	args = append(args, "-h")
	args = append(args, Hub.Host)

	args = append(args, "-p")
	args = append(args, Hub.Port)

	args = append(args, "-s")
	args = append(args, Hub.Scheme)

	args = append(args, "-u")
	args = append(args, Hub.Username)

	args = append(args, "-w")
	args = append(args, Hub.Password)

	args = append(args, "-id")
	args = append(args, image.imageId)

	args = append(args, "-tag")
	args = append(args, image.taggedName)

	args = append(args, "-digest")
	args = append(args, image.digest)

	docker := NewDocker ()

	err := docker.launchContainer (Hub.Scanner, args)

	if err != nil {
		fmt.Printf ("Error creating scanning container: %s\n", err)
		return err
	}

	fmt.Printf ("Done Scanning: %s\n", image.taggedName)

	//time.Sleep(10*time.Second)
	return nil
}

<|endoftext|>