<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"math/rand"

	"github.com/github/git-lfs/lfs"
)

// "download" - all present
func downloadAllExist(oidsExist, oidsMissing []TestObject) error {
	retobjs, err := callBatchApi("download", oidsExist)

	if err != nil {
		return err
	}

	if len(retobjs) != len(oidsExist) {
		return fmt.Errorf("Incorrect number of returned objects, expected %d, got %d", len(oidsExist), len(retobjs))
	}

	var errbuf bytes.Buffer
	for _, o := range retobjs {
		_, ok := o.Rel("download")
		if !ok {
			errbuf.WriteString(fmt.Sprintf("Missing download link for %s\n", o.Oid))
		}
	}

	if errbuf.Len() > 0 {
		return errors.New(errbuf.String())
	}

	return nil
}

// "download" - all missing (test includes 404 error entry)
func downloadAllMissing(oidsExist, oidsMissing []TestObject) error {
	retobjs, err := callBatchApi("download", oidsMissing)

	if err != nil {
		return err
	}

	if len(retobjs) != len(oidsExist) {
		return fmt.Errorf("Incorrect number of returned objects, expected %d, got %d", len(oidsExist), len(retobjs))
	}

	var errbuf bytes.Buffer
	for _, o := range retobjs {
		link, ok := o.Rel("download")
		if ok {
			errbuf.WriteString(fmt.Sprintf("Download link should not exist for %s, was %s\n", o.Oid, link))
		}
		if o.Error == nil {
			errbuf.WriteString(fmt.Sprintf("Download should include an error for missing object %s, was %s\n", o.Oid))
		} else if o.Error.Code != 404 {
			errbuf.WriteString(fmt.Sprintf("Download error code for missing object %s should be 404, got %d\n", o.Oid, o.Error.Code))
		}
	}

	if errbuf.Len() > 0 {
		return errors.New(errbuf.String())
	}

	return nil
}

// "download" - mixture
func downloadMixed(oidsExist, oidsMissing []TestObject) error {

	existSet := lfs.NewStringSetWithCapacity(len(oidsExist))
	missingSet := lfs.NewStringSetWithCapacity(len(oidsMissing))

	// Predictable sequence, mixin existing & missing semi-randomly
	rand.Seed(21)
	count := len(oidsExist) + len(oidsMissing)
	calloids := make([]TestObject, 0, count)
	existIdx := 0
	missingIdx := 0
	for left := count; left > 0; {
		for i := rand.Intn(3) + 1; existIdx < len(oidsExist) && i > 0; i-- {
			obj := oidsExist[existIdx]
			existSet.Add(obj.Oid)
			calloids = append(calloids, obj)
			existIdx++
			left--
		}
		for i := rand.Intn(3) + 1; missingIdx < len(oidsMissing) && i > 0; i-- {
			obj := oidsMissing[missingIdx]
			missingSet.Add(obj.Oid)
			calloids = append(calloids, obj)
			missingIdx++
			left--
		}
	}

	retobjs, err := callBatchApi("download", calloids)

	if err != nil {
		return err
	}

	if len(retobjs) != count {
		return fmt.Errorf("Incorrect number of returned objects, expected %d, got %d", count, len(retobjs))
	}

	var errbuf bytes.Buffer
	for _, o := range retobjs {
		link, ok := o.Rel("download")
		if missingSet.Contains(o.Oid) {
			if ok {
				errbuf.WriteString(fmt.Sprintf("Download link should not exist for %s, was %s\n", o.Oid, link))
			}
			if o.Error == nil {
				errbuf.WriteString(fmt.Sprintf("Download should include an error for missing object %s", o.Oid))
			} else if o.Error.Code != 404 {
				errbuf.WriteString(fmt.Sprintf("Download error code for missing object %s should be 404, got %d\n", o.Oid, o.Error.Code))
			}
		}
		if existSet.Contains(o.Oid) && !ok {
			errbuf.WriteString(fmt.Sprintf("Missing download link for %s\n", o.Oid))
		}

	}

	if errbuf.Len() > 0 {
		return errors.New(errbuf.String())
	}

	return nil

}

func init() {
	addTest("Test download: all existing", downloadAllExist)
	addTest("Test download: all missing", downloadAllMissing)
	addTest("Test download: mixed", downloadMixed)
}
<commit_msg>Fixed test mistake when exist/missing lists are different lengths<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"math/rand"

	"github.com/github/git-lfs/lfs"
)

// "download" - all present
func downloadAllExist(oidsExist, oidsMissing []TestObject) error {
	retobjs, err := callBatchApi("download", oidsExist)

	if err != nil {
		return err
	}

	if len(retobjs) != len(oidsExist) {
		return fmt.Errorf("Incorrect number of returned objects, expected %d, got %d", len(oidsExist), len(retobjs))
	}

	var errbuf bytes.Buffer
	for _, o := range retobjs {
		_, ok := o.Rel("download")
		if !ok {
			errbuf.WriteString(fmt.Sprintf("Missing download link for %s\n", o.Oid))
		}
	}

	if errbuf.Len() > 0 {
		return errors.New(errbuf.String())
	}

	return nil
}

// "download" - all missing (test includes 404 error entry)
func downloadAllMissing(oidsExist, oidsMissing []TestObject) error {
	retobjs, err := callBatchApi("download", oidsMissing)

	if err != nil {
		return err
	}

	if len(retobjs) != len(oidsMissing) {
		return fmt.Errorf("Incorrect number of returned objects, expected %d, got %d", len(oidsMissing), len(retobjs))
	}

	var errbuf bytes.Buffer
	for _, o := range retobjs {
		link, ok := o.Rel("download")
		if ok {
			errbuf.WriteString(fmt.Sprintf("Download link should not exist for %s, was %s\n", o.Oid, link))
		}
		if o.Error == nil {
			errbuf.WriteString(fmt.Sprintf("Download should include an error for missing object %s, was %s\n", o.Oid))
		} else if o.Error.Code != 404 {
			errbuf.WriteString(fmt.Sprintf("Download error code for missing object %s should be 404, got %d\n", o.Oid, o.Error.Code))
		}
	}

	if errbuf.Len() > 0 {
		return errors.New(errbuf.String())
	}

	return nil
}

// "download" - mixture
func downloadMixed(oidsExist, oidsMissing []TestObject) error {

	existSet := lfs.NewStringSetWithCapacity(len(oidsExist))
	missingSet := lfs.NewStringSetWithCapacity(len(oidsMissing))

	// Predictable sequence, mixin existing & missing semi-randomly
	rand.Seed(21)
	count := len(oidsExist) + len(oidsMissing)
	calloids := make([]TestObject, 0, count)
	existIdx := 0
	missingIdx := 0
	for left := count; left > 0; {
		for i := rand.Intn(3) + 1; existIdx < len(oidsExist) && i > 0; i-- {
			obj := oidsExist[existIdx]
			existSet.Add(obj.Oid)
			calloids = append(calloids, obj)
			existIdx++
			left--
		}
		for i := rand.Intn(3) + 1; missingIdx < len(oidsMissing) && i > 0; i-- {
			obj := oidsMissing[missingIdx]
			missingSet.Add(obj.Oid)
			calloids = append(calloids, obj)
			missingIdx++
			left--
		}
	}

	retobjs, err := callBatchApi("download", calloids)

	if err != nil {
		return err
	}

	if len(retobjs) != count {
		return fmt.Errorf("Incorrect number of returned objects, expected %d, got %d", count, len(retobjs))
	}

	var errbuf bytes.Buffer
	for _, o := range retobjs {
		link, ok := o.Rel("download")
		if missingSet.Contains(o.Oid) {
			if ok {
				errbuf.WriteString(fmt.Sprintf("Download link should not exist for %s, was %s\n", o.Oid, link))
			}
			if o.Error == nil {
				errbuf.WriteString(fmt.Sprintf("Download should include an error for missing object %s", o.Oid))
			} else if o.Error.Code != 404 {
				errbuf.WriteString(fmt.Sprintf("Download error code for missing object %s should be 404, got %d\n", o.Oid, o.Error.Code))
			}
		}
		if existSet.Contains(o.Oid) && !ok {
			errbuf.WriteString(fmt.Sprintf("Missing download link for %s\n", o.Oid))
		}

	}

	if errbuf.Len() > 0 {
		return errors.New(errbuf.String())
	}

	return nil

}

func init() {
	addTest("Test download: all existing", downloadAllExist)
	addTest("Test download: all missing", downloadAllMissing)
	addTest("Test download: mixed", downloadMixed)
}
<|endoftext|>


<commit_before>package pods

import (
	"k8s.io/api/core/v1"
	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func VPPDataplanePod(name string, node *v1.Node) *v1.Pod {
	return createVPPDataplanePod(name, node, nil, nil, nil)
}

func VPPDataplanePodConfig(name string, node *v1.Node, variables map[string]string) *v1.Pod {
	return createVPPDataplanePod(name, node, nil, nil, variables)
}

func VPPDataplanePodLiveCheck(name string, node *v1.Node) *v1.Pod {
	return createVPPDataplanePod(name, node, createProbe("/liveness"), createProbe("/readiness"), nil)
}

func createVPPDataplanePod(name string, node *v1.Node, liveness, readiness *v1.Probe, variables map[string]string) *v1.Pod {
	ht := new(v1.HostPathType)
	*ht = v1.HostPathDirectoryOrCreate

	priv := true

	mode := v1.MountPropagationBidirectional
	pod := &v1.Pod{
		ObjectMeta: v12.ObjectMeta{
			Name: name,
		},
		TypeMeta: v12.TypeMeta{
			Kind: "Deployment",
		},
		Spec: v1.PodSpec{
			HostPID: true,
			Volumes: []v1.Volume{
				{
					Name: "workspace",
					VolumeSource: v1.VolumeSource{
						HostPath: &v1.HostPathVolumeSource{
							Type: ht,
							Path: "/var/lib/networkservicemesh",
						},
					},
				},
				{
					Name: "postmortem",
					VolumeSource: v1.VolumeSource{
						HostPath: &v1.HostPathVolumeSource{
							Type: ht,
							Path: "/var/tmp/nsm-postmortem",
						},
					},
				},
			},
			Containers: []v1.Container{
				containerMod(&v1.Container{
					Name:            "vppagent-dataplane",
					Image:           "networkservicemesh/vppagent-dataplane-dev:latest",
					ImagePullPolicy: v1.PullIfNotPresent,
					VolumeMounts: []v1.VolumeMount{
						{
							Name:             "workspace",
							MountPath:        "/var/lib/networkservicemesh/",
							MountPropagation: &mode,
						},
						{
							Name:             "postmortem",
							MountPath:        "/var/tmp/nsm-postmortem/",
							MountPropagation: &mode,
						},
					},
					Env: []v1.EnvVar{
						v1.EnvVar{
							Name: "NSM_DATAPLANE_SRC_IP",
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "status.podIP",
								},
							},
						},
					},
					SecurityContext: &v1.SecurityContext{
						Privileged: &priv,
					},
					LivenessProbe:  liveness,
					ReadinessProbe: readiness,
				}),
			},
		},
	}
	if len(variables) > 0 {
		for k, v := range (variables) {
			pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, v1.EnvVar{
				Name:  k,
				Value: v,
			})
		}
	}
	if node != nil {
		pod.Spec.NodeSelector = map[string]string{
			"kubernetes.io/hostname": node.Labels["kubernetes.io/hostname"],
		}
	}
	return pod
}
<commit_msg>Raise vpp-agent log level (#882)<commit_after>package pods

import (
	"k8s.io/api/core/v1"
	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func VPPDataplanePod(name string, node *v1.Node) *v1.Pod {
	return createVPPDataplanePod(name, node, nil, nil, nil)
}

func VPPDataplanePodConfig(name string, node *v1.Node, variables map[string]string) *v1.Pod {
	return createVPPDataplanePod(name, node, nil, nil, variables)
}

func VPPDataplanePodLiveCheck(name string, node *v1.Node) *v1.Pod {
	return createVPPDataplanePod(name, node, createProbe("/liveness"), createProbe("/readiness"), nil)
}

func createVPPDataplanePod(name string, node *v1.Node, liveness, readiness *v1.Probe, variables map[string]string) *v1.Pod {
	ht := new(v1.HostPathType)
	*ht = v1.HostPathDirectoryOrCreate

	priv := true

	mode := v1.MountPropagationBidirectional
	pod := &v1.Pod{
		ObjectMeta: v12.ObjectMeta{
			Name: name,
		},
		TypeMeta: v12.TypeMeta{
			Kind: "Deployment",
		},
		Spec: v1.PodSpec{
			HostPID: true,
			Volumes: []v1.Volume{
				{
					Name: "workspace",
					VolumeSource: v1.VolumeSource{
						HostPath: &v1.HostPathVolumeSource{
							Type: ht,
							Path: "/var/lib/networkservicemesh",
						},
					},
				},
				{
					Name: "postmortem",
					VolumeSource: v1.VolumeSource{
						HostPath: &v1.HostPathVolumeSource{
							Type: ht,
							Path: "/var/tmp/nsm-postmortem",
						},
					},
				},
			},
			Containers: []v1.Container{
				containerMod(&v1.Container{
					Name:            "vppagent-dataplane",
					Image:           "networkservicemesh/vppagent-dataplane-dev:latest",
					ImagePullPolicy: v1.PullIfNotPresent,
					VolumeMounts: []v1.VolumeMount{
						{
							Name:             "workspace",
							MountPath:        "/var/lib/networkservicemesh/",
							MountPropagation: &mode,
						},
						{
							Name:             "postmortem",
							MountPath:        "/var/tmp/nsm-postmortem/",
							MountPropagation: &mode,
						},
					},
					Env: []v1.EnvVar{
						{
							Name: "NSM_DATAPLANE_SRC_IP",
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "status.podIP",
								},
							},
						},
						{
							Name:  "INITIAL_LOGLVL",
							Value: "debug",
						},
					},
					SecurityContext: &v1.SecurityContext{
						Privileged: &priv,
					},
					LivenessProbe:  liveness,
					ReadinessProbe: readiness,
				}),
			},
		},
	}
	if len(variables) > 0 {
		for k, v := range (variables) {
			pod.Spec.Containers[0].Env = append(pod.Spec.Containers[0].Env, v1.EnvVar{
				Name:  k,
				Value: v,
			})
		}
	}
	if node != nil {
		pod.Spec.NodeSelector = map[string]string{
			"kubernetes.io/hostname": node.Labels["kubernetes.io/hostname"],
		}
	}
	return pod
}
<|endoftext|>


<commit_before><commit_msg>print item after deleting it, in case of misdeleteing<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpc

import (
	"github.com/bitmark-inc/bitmarkd/merkle"
	"github.com/bitmark-inc/bitmarkd/reservoir"
	"github.com/bitmark-inc/logger"
	"time"
)

// Transaction is a rpc entry for transaction related functions
type Transaction struct {
	log   *logger.L
	start time.Time
}

// TransactionArguments is the arguments for statuc rpc request
type TransactionArguments struct {
	Id string `json:"txId"`
}

// TransactionStatus is a struct for an rpc reply
type TransactionStatus struct {
	Status string `json:"status"`
}

// Status is an rpc api for query transaction status
func (t *Transaction) Status(arguments *TransactionArguments, reply *TransactionStatus) error {
	var txId merkle.Digest
	err := txId.UnmarshalText([]byte(arguments.Id))
	if err != nil {
		return err
	}
	reply.Status = reservoir.TransactionStatus(txId).String()
	return nil
}
<commit_msg>[rpc] fix tx id decoding<commit_after>// Copyright (c) 2014-2017 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpc

import (
	"github.com/bitmark-inc/bitmarkd/merkle"
	"github.com/bitmark-inc/bitmarkd/reservoir"
	"github.com/bitmark-inc/logger"
	"time"
)

// Transaction is a rpc entry for transaction related functions
type Transaction struct {
	log   *logger.L
	start time.Time
}

// TransactionArguments is the arguments for statuc rpc request
type TransactionArguments struct {
	TxId merkle.Digest `json:"txId"`
}

// TransactionStatus is a struct for an rpc reply
type TransactionStatusReply struct {
	Status string `json:"status"`
}

// Status is an rpc api for query transaction status
func (t *Transaction) Status(arguments *TransactionArguments, reply *TransactionStatusReply) error {
	reply.Status = reservoir.TransactionStatus(arguments.TxId).String()
	return nil
}
<|endoftext|>


<commit_before>// Package rpcutil provides various methods for working with gorilla's JSON RPC
// 2 interface (http://www.gorillatoolkit.org/pkg/rpc/v2/json2)
package rpcutil

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

	"gopkg.in/validator.v2"

	"github.com/gorilla/rpc/v2"
	"github.com/gorilla/rpc/v2/json2"
	"github.com/levenlabs/go-applicator"
	"github.com/levenlabs/go-llog"
)

// A QuietError is a json2.Error except that it will not cause a warn log when
// returned from a handler
type QuietError json2.Error

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

// RequestKV returns a basic KV for passing into llog, filled with entries
// related to the passed in http.Request
func RequestKV(r *http.Request) llog.KV {
	kv := llog.KV{
		"ip": RequestIP(r),
	}
	// first try Referer, but fallback to Origin
	if ref := r.Header.Get("Referer"); ref != "" {
		kv["referer"] = ref
	} else if o := r.Header.Get("Origin"); o != "" {
		kv["origin"] = o
	}
	if via := r.Header.Get("Via"); via != "" {
		kv["via"] = via
	}
	return kv
}

// we don't ever really pass this into encoding/json, so having it implement
// json.Marshaler isn't really necessary, but it's helpful to think of it in
// this way
type jsonInliner struct {
	orig  interface{}
	extra map[string]interface{}
}

func (j jsonInliner) MarshalJSON() ([]byte, error) {
	bOrig, err := json.Marshal(j.orig)
	if err != nil {
		return nil, err
	}
	if len(bOrig) < 2 || bOrig[len(bOrig)-1] != '}' {
		return nil, errors.New("jsonInliner original value not an object")
	}
	if len(j.extra) == 0 {
		return bOrig, nil
	}

	bExtra, err := json.Marshal(j.extra)
	if err != nil {
		return nil, err
	}

	bOrig = bOrig[:len(bOrig)-1]
	bOrig = append(bOrig, ',')
	bOrig = append(bOrig, bExtra[1:]...)
	return bOrig, nil
}

// LLCodec wraps around gorilla's json2.Codec, adding logging to all requests
type LLCodec struct {
	c rpc.Codec

	// If true any errors which are not user caused (error code < 1) will not
	// actually be returned to the client, only a generic error message in their
	// place
	HideServerErrors bool

	// If true the gopkg.in/validator.v2 package will be used to automatically
	// validate inputs to calls
	ValidateInput bool

	// If true the github.com/levenlabs/go-applicator package will be used to
	// apply functions to your input fields
	RunInputApplicators bool

	// If set, once a non-error response is returned by an rpc endpoint this
	// will be called and the result (if non-nil) will be inlined with the
	// original response. The original response must encode to a json object for
	// this to work.
	//
	// For example, if the original response encodes to `{"success":true}`, and
	// ResponseInliner returns `{"currentTime":123456}`, the final response sent
	// to the client will be `{"success":true,"currentTime":123456}`
	ResponseInliner func(*http.Request) map[string]interface{}

	// All endpoints (fullname, i.e. "Service.Method") set as keys in this map
	// will not have an INFO log printed out when they are hit
	ExcludeRequestLog map[string]bool
}

// NewLLCodec returns an LLCodec, which is an implementation of rpc.Codec around
// json2.Codec. All public fields on LLCodec can be modified up intil passing
// this into rpc.RegisterCodec
func NewLLCodec() LLCodec {
	return LLCodec{c: json2.NewCodec(), ExcludeRequestLog: map[string]bool{}}
}

// NewRequest implements the NewRequest method for the rpc.Codec interface
func (c LLCodec) NewRequest(r *http.Request) rpc.CodecRequest {
	return llCodecRequest{
		c:            &c,
		CodecRequest: c.c.NewRequest(r),
		r:            r,
		kv:           RequestKV(r),
	}
}

type llCodecRequest struct {
	c *LLCodec
	rpc.CodecRequest
	r  *http.Request
	kv llog.KV
}

func stringifyInterface(args interface{}) string {
	if rm, ok := args.(*json.RawMessage); ok {
		return string(*rm)
	}
	if by, ok := args.([]byte); ok {
		return string(by)
	}
	return fmt.Sprintf("%+v", args)
}

func (cr llCodecRequest) ReadRequest(args interface{}) error {
	// After calling the underlying ReadRequest the args will be filled in
	if err := cr.CodecRequest.ReadRequest(args); err != nil {
		// err will already be a json2.Error in this specific case, we don't
		// have to wrap it again
		return err
	}

	method, _ := cr.CodecRequest.Method()
	cr.kv["method"] = method
	var fn llog.LogFunc
	if cr.c.ExcludeRequestLog[method] {
		// don't log anything
	} else if llog.GetLevel() == llog.DebugLevel {
		cr.kv["args"] = stringifyInterface(args)
		cr.kv["argsType"] = fmt.Sprintf("%T", args)
		fn = llog.Debug
	} else {
		fn = llog.Info
		if argsKVer, ok := args.(interface {
			KV() llog.KV
		}); ok {
			cr.kv = llog.Merge(cr.kv, argsKVer.KV())
		}
	}

	if cr.c.RunInputApplicators {
		if err := applicator.Apply(args); err != nil {
			// presumably the error is an internal one, but leave the option
			// for the function to return a json2.Error if they want
			return err
		}
	}

	if cr.c.ValidateInput {
		if err := validator.Validate(args); err != nil {
			return &json2.Error{
				Code:    json2.E_BAD_PARAMS,
				Message: err.Error(),
			}
		}
	}

	if fn != nil {
		fn("jsonrpc incoming request", cr.kv)
	}

	return nil
}

func (cr llCodecRequest) maybeInlineExtra(r interface{}) (interface{}, error) {
	if cr.c.ResponseInliner == nil {
		return r, nil
	}
	extra := cr.c.ResponseInliner(cr.r)
	if extra == nil {
		return r, nil
	}

	j := jsonInliner{orig: r, extra: extra}
	b, err := j.MarshalJSON()
	if err != nil {
		return nil, err
	}
	jr := json.RawMessage(b)
	return &jr, nil
}

func (cr llCodecRequest) WriteResponse(w http.ResponseWriter, r interface{}) {
	llog.Debug("jsonrpc responding", cr.kv)
	newR, err := cr.maybeInlineExtra(r)
	if err != nil {
		kv := llog.KV{
			"err": err,
		}
		kv["orig"], _ = json.Marshal(r)
		llog.Error("jsonrpc could not inline extra", cr.kv, kv)
	} else {
		r = newR
	}

	cr.CodecRequest.WriteResponse(w, r)
}

func (cr llCodecRequest) WriteError(w http.ResponseWriter, status int, err error) {
	// status is ignored by gorilla

	cr.kv["err"] = err

	var quietErr *QuietError
	var jsonErr *json2.Error
	switch terr := err.(type) {
	case *QuietError:
		quietErr = terr
		jsonErr = (*json2.Error)(terr)
	case *json2.Error:
		jsonErr = terr
	default:
		jsonErr = &json2.Error{
			Code:    json2.E_SERVER,
			Message: fmt.Sprintf("unexpected internal server error: %s", err),
		}
	}
	if kv, ok := jsonErr.Data.(llog.KV); ok {
		for k, v := range kv {
			cr.kv[k] = v
		}
	}

	// The only predefined error that is considered a server error really is
	// E_SERVER, all the others which are less than it are basically client
	// errors. So all within this range are considered internal server errors,
	// and need to be possibly hidden and definitely output as errors
	if jsonErr.Code < 0 && jsonErr.Code >= json2.E_SERVER {
		if cr.c.HideServerErrors {
			jsonErr = &json2.Error{
				Code:    json2.E_SERVER,
				Message: "internal server error",
			}
		}
		llog.Warn("jsonrpc internal server error", cr.kv)
	} else if quietErr == nil {
		llog.Warn("jsonrpc client error", cr.kv)
	}

	// its okay to always return jsonErr since quietErr is a jsonErr
	cr.CodecRequest.WriteError(w, status, jsonErr)
}
<commit_msg>add rpcutil.IsInternalErr<commit_after>// Package rpcutil provides various methods for working with gorilla's JSON RPC
// 2 interface (http://www.gorillatoolkit.org/pkg/rpc/v2/json2)
package rpcutil

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

	"gopkg.in/validator.v2"

	"github.com/gorilla/rpc/v2"
	"github.com/gorilla/rpc/v2/json2"
	"github.com/levenlabs/go-applicator"
	"github.com/levenlabs/go-llog"
)

// A QuietError is a json2.Error except that it will not cause a warn log when
// returned from a handler
type QuietError json2.Error

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

// RequestKV returns a basic KV for passing into llog, filled with entries
// related to the passed in http.Request
func RequestKV(r *http.Request) llog.KV {
	kv := llog.KV{
		"ip": RequestIP(r),
	}
	// first try Referer, but fallback to Origin
	if ref := r.Header.Get("Referer"); ref != "" {
		kv["referer"] = ref
	} else if o := r.Header.Get("Origin"); o != "" {
		kv["origin"] = o
	}
	if via := r.Header.Get("Via"); via != "" {
		kv["via"] = via
	}
	return kv
}

// we don't ever really pass this into encoding/json, so having it implement
// json.Marshaler isn't really necessary, but it's helpful to think of it in
// this way
type jsonInliner struct {
	orig  interface{}
	extra map[string]interface{}
}

func (j jsonInliner) MarshalJSON() ([]byte, error) {
	bOrig, err := json.Marshal(j.orig)
	if err != nil {
		return nil, err
	}
	if len(bOrig) < 2 || bOrig[len(bOrig)-1] != '}' {
		return nil, errors.New("jsonInliner original value not an object")
	}
	if len(j.extra) == 0 {
		return bOrig, nil
	}

	bExtra, err := json.Marshal(j.extra)
	if err != nil {
		return nil, err
	}

	bOrig = bOrig[:len(bOrig)-1]
	bOrig = append(bOrig, ',')
	bOrig = append(bOrig, bExtra[1:]...)
	return bOrig, nil
}

// LLCodec wraps around gorilla's json2.Codec, adding logging to all requests
type LLCodec struct {
	c rpc.Codec

	// If true any errors which are not user caused (error code < 1) will not
	// actually be returned to the client, only a generic error message in their
	// place
	HideServerErrors bool

	// If true the gopkg.in/validator.v2 package will be used to automatically
	// validate inputs to calls
	ValidateInput bool

	// If true the github.com/levenlabs/go-applicator package will be used to
	// apply functions to your input fields
	RunInputApplicators bool

	// If set, once a non-error response is returned by an rpc endpoint this
	// will be called and the result (if non-nil) will be inlined with the
	// original response. The original response must encode to a json object for
	// this to work.
	//
	// For example, if the original response encodes to `{"success":true}`, and
	// ResponseInliner returns `{"currentTime":123456}`, the final response sent
	// to the client will be `{"success":true,"currentTime":123456}`
	ResponseInliner func(*http.Request) map[string]interface{}

	// All endpoints (fullname, i.e. "Service.Method") set as keys in this map
	// will not have an INFO log printed out when they are hit
	ExcludeRequestLog map[string]bool
}

// NewLLCodec returns an LLCodec, which is an implementation of rpc.Codec around
// json2.Codec. All public fields on LLCodec can be modified up intil passing
// this into rpc.RegisterCodec
func NewLLCodec() LLCodec {
	return LLCodec{c: json2.NewCodec(), ExcludeRequestLog: map[string]bool{}}
}

// NewRequest implements the NewRequest method for the rpc.Codec interface
func (c LLCodec) NewRequest(r *http.Request) rpc.CodecRequest {
	return llCodecRequest{
		c:            &c,
		CodecRequest: c.c.NewRequest(r),
		r:            r,
		kv:           RequestKV(r),
	}
}

type llCodecRequest struct {
	c *LLCodec
	rpc.CodecRequest
	r  *http.Request
	kv llog.KV
}

func stringifyInterface(args interface{}) string {
	if rm, ok := args.(*json.RawMessage); ok {
		return string(*rm)
	}
	if by, ok := args.([]byte); ok {
		return string(by)
	}
	return fmt.Sprintf("%+v", args)
}

func (cr llCodecRequest) ReadRequest(args interface{}) error {
	// After calling the underlying ReadRequest the args will be filled in
	if err := cr.CodecRequest.ReadRequest(args); err != nil {
		// err will already be a json2.Error in this specific case, we don't
		// have to wrap it again
		return err
	}

	method, _ := cr.CodecRequest.Method()
	cr.kv["method"] = method
	var fn llog.LogFunc
	if cr.c.ExcludeRequestLog[method] {
		// don't log anything
	} else if llog.GetLevel() == llog.DebugLevel {
		cr.kv["args"] = stringifyInterface(args)
		cr.kv["argsType"] = fmt.Sprintf("%T", args)
		fn = llog.Debug
	} else {
		fn = llog.Info
		if argsKVer, ok := args.(interface {
			KV() llog.KV
		}); ok {
			cr.kv = llog.Merge(cr.kv, argsKVer.KV())
		}
	}

	if cr.c.RunInputApplicators {
		if err := applicator.Apply(args); err != nil {
			// presumably the error is an internal one, but leave the option
			// for the function to return a json2.Error if they want
			return err
		}
	}

	if cr.c.ValidateInput {
		if err := validator.Validate(args); err != nil {
			return &json2.Error{
				Code:    json2.E_BAD_PARAMS,
				Message: err.Error(),
			}
		}
	}

	if fn != nil {
		fn("jsonrpc incoming request", cr.kv)
	}

	return nil
}

func (cr llCodecRequest) maybeInlineExtra(r interface{}) (interface{}, error) {
	if cr.c.ResponseInliner == nil {
		return r, nil
	}
	extra := cr.c.ResponseInliner(cr.r)
	if extra == nil {
		return r, nil
	}

	j := jsonInliner{orig: r, extra: extra}
	b, err := j.MarshalJSON()
	if err != nil {
		return nil, err
	}
	jr := json.RawMessage(b)
	return &jr, nil
}

func (cr llCodecRequest) WriteResponse(w http.ResponseWriter, r interface{}) {
	llog.Debug("jsonrpc responding", cr.kv)
	newR, err := cr.maybeInlineExtra(r)
	if err != nil {
		kv := llog.KV{
			"err": err,
		}
		kv["orig"], _ = json.Marshal(r)
		llog.Error("jsonrpc could not inline extra", cr.kv, kv)
	} else {
		r = newR
	}

	cr.CodecRequest.WriteResponse(w, r)
}

// IsInternalErr returns whether or not this error is due to an internal server
// error (vs bad request data on the client's part). Returns false if nil,
// returns true if a non *json2.Error is passed in.
func IsInternalErr(err error) bool {
	if err == nil {
		return false
	}
	jerr, ok := err.(*json2.Error)
	if !ok {
		return true
	}
	return jerr.Code < 0 && jerr.Code >= json2.E_SERVER
}

func (cr llCodecRequest) WriteError(w http.ResponseWriter, status int, err error) {
	// status is ignored by gorilla

	cr.kv["err"] = err

	var quietErr *QuietError
	var jsonErr *json2.Error
	switch terr := err.(type) {
	case *QuietError:
		quietErr = terr
		jsonErr = (*json2.Error)(terr)
	case *json2.Error:
		jsonErr = terr
	default:
		jsonErr = &json2.Error{
			Code:    json2.E_SERVER,
			Message: fmt.Sprintf("unexpected internal server error: %s", err),
		}
	}
	if kv, ok := jsonErr.Data.(llog.KV); ok {
		for k, v := range kv {
			cr.kv[k] = v
		}
	}

	// The only predefined error that is considered a server error really is
	// E_SERVER, all the others which are less than it are basically client
	// errors. So all within this range are considered internal server errors,
	// and need to be possibly hidden and definitely output as errors
	if IsInternalErr(jsonErr) {
		if cr.c.HideServerErrors {
			jsonErr = &json2.Error{
				Code:    json2.E_SERVER,
				Message: "internal server error",
			}
		}
		llog.Warn("jsonrpc internal server error", cr.kv)
	} else if quietErr == nil {
		llog.Warn("jsonrpc client error", cr.kv)
	}

	// its okay to always return jsonErr since quietErr is a jsonErr
	cr.CodecRequest.WriteError(w, status, jsonErr)
}
<|endoftext|>


<commit_before><commit_msg>Quick err if statement not always better<commit_after><|endoftext|>


<commit_before>package runtime

import (
	"errors"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/micro/go-micro/runtime/package"
	"github.com/micro/go-micro/runtime/process"
	proc "github.com/micro/go-micro/runtime/process/os"
	"github.com/micro/go-micro/util/log"
)

type runtime struct {
	sync.RWMutex
	closed   chan bool
	running  bool
	services map[string]*service
}

type service struct {
	sync.RWMutex

	running bool
	closed  chan bool
	err     error

	// service to manage
	*Service
	// process creator
	Process *proc.Process
	// Exec
	Exec *process.Executable
	// process pid
	PID *process.PID
}

func newRuntime() *runtime {
	return &runtime{
		closed:   make(chan bool),
		services: make(map[string]*service),
	}
}

func newService(s *Service) *service {
	parts := strings.Split(s.Exec, " ")
	exec := parts[0]
	args := []string{}

	if len(parts) > 1 {
		args = parts[1:]
	}

	return &service{
		Service: s,
		Process: new(proc.Process),
		Exec: &process.Executable{
			Binary: &packager.Binary{
				Name: s.Name,
				Path: exec,
			},
			Env:  os.Environ(),
			Args: args,
		},
	}
}

func (s *service) Running() bool {
	s.RLock()
	defer s.RUnlock()
	return s.running
}

func (s *service) Start() error {
	s.Lock()
	defer s.Unlock()

	if s.running {
		return nil
	}

	// reset
	s.err = nil
	s.closed = make(chan bool)

	// TODO: pull source & build binary

	p, err := s.Process.Fork(s.Exec)
	if err != nil {
		return err
	}

	// set the pid
	s.PID = p
	// set to running
	s.running = true

	// wait and watch
	go s.Wait()

	return nil
}

func (s *service) Stop() error {
	s.Lock()
	defer s.Unlock()

	select {
	case <-s.closed:
		return nil
	default:
		close(s.closed)
		s.running = false
		return s.Process.Kill(s.PID)
	}

	return nil
}

func (s *service) Error() error {
	s.RLock()
	defer s.RUnlock()
	return s.err
}

func (s *service) Wait() {
	// wait for process to exit
	err := s.Process.Wait(s.PID)

	s.Lock()
	defer s.Unlock()

	// save the error
	if err != nil {
		s.err = err
	}

	// no longer running
	s.running = false
}

func (r *runtime) Create(s *Service) error {
	r.Lock()
	defer r.Unlock()

	if _, ok := r.services[s.Name]; ok {
		return errors.New("service already registered")
	}

	// save service
	r.services[s.Name] = newService(s)

	return nil
}

func (r *runtime) Delete(s *Service) error {
	r.Lock()
	defer r.Unlock()

	if s, ok := r.services[s.Name]; ok {
		delete(r.services, s.Name)
		return s.Stop()
	}

	return nil
}

func (r *runtime) Start() error {
	r.Lock()

	// already running
	if r.running {
		r.Unlock()
		return nil
	}

	// set running
	r.running = true
	r.closed = make(chan bool)
	closed := r.closed

	r.Unlock()

	t := time.NewTicker(time.Second * 5)
	defer t.Stop()

	for {
		select {
		case <-t.C:
			// check running services
			r.RLock()
			for _, service := range r.services {
				if service.Running() {
					continue
				}

				// TODO: check service error
				log.Debugf("Starting %s", service.Name)
				if err := service.Start(); err != nil {
					log.Debugf("Error starting %s: %v", service.Name, err)
				}
			}
			r.RUnlock()
		case <-closed:
			// TODO: stop all the things
			return nil
		}
	}

	return nil
}

func (r *runtime) Stop() error {
	r.Lock()
	defer r.Unlock()

	if !r.running {
		return nil
	}

	select {
	case <-r.closed:
		return nil
	default:
		close(r.closed)

		// set not running
		r.running = false

		// stop all the services
		for _, service := range r.services {
			service.Stop()
		}
	}

	return nil
}
<commit_msg>Immediately start services<commit_after>package runtime

import (
	"errors"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/micro/go-micro/runtime/package"
	"github.com/micro/go-micro/runtime/process"
	proc "github.com/micro/go-micro/runtime/process/os"
	"github.com/micro/go-micro/util/log"
)

type runtime struct {
	sync.RWMutex
	// used to stop the runtime
	closed chan bool
	// used to start new services
	start chan *service
	// indicates if we're running
	running bool
	// the service map
	services map[string]*service
}

type service struct {
	sync.RWMutex

	running bool
	closed  chan bool
	err     error

	// service to manage
	*Service
	// process creator
	Process *proc.Process
	// Exec
	Exec *process.Executable
	// process pid
	PID *process.PID
}

func newRuntime() *runtime {
	return &runtime{
		closed:   make(chan bool),
		start:    make(chan *service, 128),
		services: make(map[string]*service),
	}
}

func newService(s *Service) *service {
	parts := strings.Split(s.Exec, " ")
	exec := parts[0]
	args := []string{}

	if len(parts) > 1 {
		args = parts[1:]
	}

	return &service{
		Service: s,
		Process: new(proc.Process),
		Exec: &process.Executable{
			Binary: &packager.Binary{
				Name: s.Name,
				Path: exec,
			},
			Env:  os.Environ(),
			Args: args,
		},
	}
}

func (s *service) Running() bool {
	s.RLock()
	defer s.RUnlock()
	return s.running
}

func (s *service) Start() error {
	s.Lock()
	defer s.Unlock()

	if s.running {
		return nil
	}

	// reset
	s.err = nil
	s.closed = make(chan bool)

	// TODO: pull source & build binary

	p, err := s.Process.Fork(s.Exec)
	if err != nil {
		return err
	}

	// set the pid
	s.PID = p
	// set to running
	s.running = true

	// wait and watch
	go s.Wait()

	return nil
}

func (s *service) Stop() error {
	s.Lock()
	defer s.Unlock()

	select {
	case <-s.closed:
		return nil
	default:
		close(s.closed)
		s.running = false
		return s.Process.Kill(s.PID)
	}

	return nil
}

func (s *service) Error() error {
	s.RLock()
	defer s.RUnlock()
	return s.err
}

func (s *service) Wait() {
	// wait for process to exit
	err := s.Process.Wait(s.PID)

	s.Lock()
	defer s.Unlock()

	// save the error
	if err != nil {
		s.err = err
	}

	// no longer running
	s.running = false
}

func (r *runtime) Create(s *Service) error {
	r.Lock()
	defer r.Unlock()

	if _, ok := r.services[s.Name]; ok {
		return errors.New("service already registered")
	}

	// save service
	r.services[s.Name] = newService(s)

	// push into start queue
	r.start <- r.services[s.Name]

	return nil
}

func (r *runtime) Delete(s *Service) error {
	r.Lock()
	defer r.Unlock()

	if s, ok := r.services[s.Name]; ok {
		delete(r.services, s.Name)
		return s.Stop()
	}

	return nil
}

func (r *runtime) Start() error {
	r.Lock()

	// already running
	if r.running {
		r.Unlock()
		return nil
	}

	// set running
	r.running = true
	r.closed = make(chan bool)
	closed := r.closed

	r.Unlock()

	t := time.NewTicker(time.Second * 5)
	defer t.Stop()

	for {
		select {
		case <-t.C:
			// check running services
			r.RLock()
			for _, service := range r.services {
				if service.Running() {
					continue
				}

				// TODO: check service error
				log.Debugf("Starting %s", service.Name)
				if err := service.Start(); err != nil {
					log.Debugf("Error starting %s: %v", service.Name, err)
				}
			}
			r.RUnlock()
		case service := <-r.start:
			if service.Running() {
				continue
			}

			// TODO: check service error
			log.Debugf("Starting %s", service.Name)
			if err := service.Start(); err != nil {
				log.Debugf("Error starting %s: %v", service.Name, err)
			}
		case <-closed:
			// TODO: stop all the things
			return nil
		}
	}

	return nil
}

func (r *runtime) Stop() error {
	r.Lock()
	defer r.Unlock()

	if !r.running {
		return nil
	}

	select {
	case <-r.closed:
		return nil
	default:
		close(r.closed)

		// set not running
		r.running = false

		// stop all the services
		for _, service := range r.services {
			service.Stop()
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/native"
	"os"
	"strings"
	"time"
)

type cmdOpts struct {
	Host    string `short:"H" long:"host" default:"localhost" description:"Hostname"`
	Port    string `short:"p" long:"port" default:"3306" description:"Port"`
	User    string `short:"u" long:"user" default:"root" description:"Username"`
	Pass    string `short:"P" long:"password" default:"" description:"Password"`
	Channel string `short:"c" long:"channel" default:"" description:"Channel name for Multi source replication"`
}

func fetchSlaveStatus(db mysql.Conn, status map[string]string, channel string) error {
	query := fmt.Sprintf("SHOW SLAVE STATUS")
	if channel != "" {
		query = fmt.Sprintf("SHOW SLAVE STATUS FOR CHANNEL '%s'", db.Escape(channel))
	}
	rows, res, err := db.Query(query)
	if err != nil {
		return err
	}
	if len(rows) < 1 {
		return fmt.Errorf("No slave status retrieved")
	}

	for _, field := range res.Fields() {
		status[strings.ToLower(field.Name)] = rows[0].Str(res.Map(field.Name))
	}
	return nil
}

func waitMasterPosition(db mysql.Conn, master_log_file string, read_master_log_pos string, timeout int32, channel string) (int, error) {
	// SELECT MASTER_POS_WAIT('$file', $pos, $timeout, 'main-db')
	query := fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %s, %d)", master_log_file, read_master_log_pos, timeout)
	if channel != "" {
		query = fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %s, %d, '%s')", master_log_file, read_master_log_pos, timeout, db.Escape(channel))
	}
	rows, _, err := db.Query(query)
	if err != nil {
		return -1, err
	}
	if len(rows) < 1 || rows[0][0] == nil {
		return -1, fmt.Errorf("No result retrieved for master_pos_wait")
	}
	result := rows[0].Int(0)
	return result, nil
}

func main() {
	os.Exit(_main())
}

func _main() (st int) {
	st = 1
	opts := cmdOpts{}
	psr := flags.NewParser(&opts, flags.Default)
	_, err := psr.Parse()
	if err != nil {
		os.Exit(1)
	}

	db := mysql.New("tcp", "", fmt.Sprintf("%s:%s", opts.Host, opts.Port), opts.User, opts.Pass, "")
	err = db.Connect()
	if err != nil {
		fmt.Fprintf(os.Stderr, "couldn't connect DB: %s\n", err)
		return
	}
	defer db.Close()

	fmt.Fprintf(os.Stdout, "Wait slave catchup master..\n")
	for {
		status := make(map[string]string)
		err = fetchSlaveStatus(db, status, opts.Channel)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't fetch slave status: %s\n", err)
			return
		}
		if status["seconds_behind_master"] != "0" {
			time.Sleep(time.Duration(1) * time.Second)
			continue
		}
		break
	}

	fmt.Fprintf(os.Stdout, "Stop slave io_thread and Check master_post_wait\n")
	for {
		stop_query := fmt.Sprintf("STOP SLAVE IO_THREAD")
		start_query := fmt.Sprintf("START SLAVE IO_THREAD")
		if opts.Channel != "" {
			stop_query = fmt.Sprintf("STOP SLAVE IO_THREAD FOR CHANNEL '%s'", db.Escape(opts.Channel))
			start_query = fmt.Sprintf("START SLAVE IO_THREAD FOR CHANNEL '%s'", db.Escape(opts.Channel))
		}
		_, _, err := db.Query(stop_query)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Could not stop slave io_thread: %s", err)
			return
		}

		status := make(map[string]string)
		err = fetchSlaveStatus(db, status, opts.Channel)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't fetch slave status... restart slave io_thread: %s\n", err)
			_, _, _ = db.Query(start_query)
			return
		}

		fmt.Fprintf(os.Stdout, "master_pos_wait..\n")
		master_pos_wait, err := waitMasterPosition(db, status["master_log_file"], status["read_master_log_pos"], 10, opts.Channel)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed exec master_pos_wait... restart slave io_thread: %s\n", err)
			_, _, _ = db.Query(start_query)
			return
		}

		if master_pos_wait == -1 {
			fmt.Fprintf(os.Stderr, "master_pos_wait returns -1... restart slave io_thread\n")
			_, _, _ = db.Query(start_query)
			time.Sleep(time.Duration(3) * time.Second)
			continue
		}
		break
	}
	fmt.Fprintf(os.Stdout, "io_thread stopped safety. Do stop slave\n")
	query := fmt.Sprintf("STOP SLAVE")
	if opts.Channel != "" {
		query = fmt.Sprintf("STOP SLAVE FOR CHANNEL '%s'", db.Escape(opts.Channel))
	}
	_, _, err = db.Query(query)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not stop slave: %s", err)
		return
	}
	fmt.Fprintf(os.Stdout, "Slave just stopped safety\n")
	st = 0
	return
}
<commit_msg>implement timeout<commit_after>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/ziutek/mymysql/mysql"
	_ "github.com/ziutek/mymysql/native"
	"os"
	"strings"
	"time"
)

type cmdOpts struct {
	Host    string `short:"H" long:"host" default:"localhost" description:"Hostname"`
	Port    string `short:"p" long:"port" default:"3306" description:"Port"`
	User    string `short:"u" long:"user" default:"root" description:"Username"`
	Pass    string `short:"P" long:"password" default:"" description:"Password"`
	Channel string `short:"c" long:"channel" default:"" description:"Channel name for Multi source replication"`
	Timeout uint   `short:"t" long:"timeout" default:"180" description:"Timeout second"`
}

func fetchSlaveStatus(db mysql.Conn, status map[string]string, channel string) error {
	query := fmt.Sprintf("SHOW SLAVE STATUS")
	if channel != "" {
		query = fmt.Sprintf("SHOW SLAVE STATUS FOR CHANNEL '%s'", db.Escape(channel))
	}
	rows, res, err := db.Query(query)
	if err != nil {
		return err
	}
	if len(rows) < 1 {
		return fmt.Errorf("No slave status retrieved")
	}

	for _, field := range res.Fields() {
		status[strings.ToLower(field.Name)] = rows[0].Str(res.Map(field.Name))
	}
	return nil
}

func waitMasterPosition(db mysql.Conn, master_log_file string, read_master_log_pos string, timeout int32, channel string) (int, error) {
	// SELECT MASTER_POS_WAIT('$file', $pos, $timeout, 'main-db')
	query := fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %s, %d)", master_log_file, read_master_log_pos, timeout)
	if channel != "" {
		query = fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %s, %d, '%s')", master_log_file, read_master_log_pos, timeout, db.Escape(channel))
	}
	rows, _, err := db.Query(query)
	if err != nil {
		return -1, err
	}
	if len(rows) < 1 || rows[0][0] == nil {
		return -1, fmt.Errorf("No result retrieved for master_pos_wait")
	}
	result := rows[0].Int(0)
	return result, nil
}

func main() {
	os.Exit(_main())
}

func _main() (st int) {
	st = 1
	opts := cmdOpts{}
	psr := flags.NewParser(&opts, flags.Default)
	_, err := psr.Parse()
	if err != nil {
		os.Exit(1)
	}

	timeout := time.Now()
	timeout = timeout.Add(time.Duration(opts.Timeout) * time.Second)

	db := mysql.New("tcp", "", fmt.Sprintf("%s:%s", opts.Host, opts.Port), opts.User, opts.Pass, "")
	err = db.Connect()
	if err != nil {
		fmt.Fprintf(os.Stderr, "couldn't connect DB: %s\n", err)
		return
	}
	defer db.Close()

	fmt.Fprintf(os.Stdout, "Wait slave catchup master..\n")
	for {
		if timeout.Before(time.Now()) {
			fmt.Fprintf(os.Stderr, "Timeout: %d second\n", opts.Timeout)
			return
		}
		status := make(map[string]string)
		err = fetchSlaveStatus(db, status, opts.Channel)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't fetch slave status: %s\n", err)
			return
		}
		if status["seconds_behind_master"] != "0" {
			time.Sleep(time.Duration(1) * time.Second)
			continue
		}
		break
	}

	fmt.Fprintf(os.Stdout, "Stop slave io_thread and Check master_post_wait\n")
	for {
		if timeout.Before(time.Now()) {
			fmt.Fprintf(os.Stderr, "Timeout: %d second\n", opts.Timeout)
			return
		}
		stop_query := fmt.Sprintf("STOP SLAVE IO_THREAD")
		start_query := fmt.Sprintf("START SLAVE IO_THREAD")
		if opts.Channel != "" {
			stop_query = fmt.Sprintf("STOP SLAVE IO_THREAD FOR CHANNEL '%s'", db.Escape(opts.Channel))
			start_query = fmt.Sprintf("START SLAVE IO_THREAD FOR CHANNEL '%s'", db.Escape(opts.Channel))
		}
		_, _, err := db.Query(stop_query)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Could not stop slave io_thread: %s", err)
			return
		}

		status := make(map[string]string)
		err = fetchSlaveStatus(db, status, opts.Channel)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't fetch slave status... restart slave io_thread: %s\n", err)
			_, _, _ = db.Query(start_query)
			return
		}

		fmt.Fprintf(os.Stdout, "master_pos_wait..\n")
		master_pos_wait, err := waitMasterPosition(db, status["master_log_file"], status["read_master_log_pos"], 5, opts.Channel)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed exec master_pos_wait... restart slave io_thread: %s\n", err)
			_, _, _ = db.Query(start_query)
			return
		}

		if master_pos_wait == -1 {
			fmt.Fprintf(os.Stderr, "master_pos_wait returns -1... restart slave io_thread\n")
			_, _, _ = db.Query(start_query)
			time.Sleep(time.Duration(3) * time.Second)
			continue
		}
		break
	}
	fmt.Fprintf(os.Stdout, "io_thread stopped safety. Do stop slave\n")
	query := fmt.Sprintf("STOP SLAVE")
	if opts.Channel != "" {
		query = fmt.Sprintf("STOP SLAVE FOR CHANNEL '%s'", db.Escape(opts.Channel))
	}
	_, _, err = db.Query(query)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not stop slave: %s", err)
		return
	}
	fmt.Fprintf(os.Stdout, "Slave just stopped safety\n")
	st = 0
	return
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package processor

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"time"

	"code.google.com/p/gopacket"
	"code.google.com/p/gopacket/layers"

	"my/errs"

	"my/itto/verify/packet"
	"my/itto/verify/packet/bats"
	"my/itto/verify/packet/miax"
)

type reusingProcessor struct {
	obtainer       packet.Obtainer
	handler        packet.Handler
	packetNumLimit int
	flowBufSrc     bytes.Buffer
	flowBufDst     bytes.Buffer
}

// default processor is reusing processor
func NewProcessor() packet.Processor {
	// FIXME unsupported by itto
	return NewReusingProcessor()
}

func NewReusingProcessor() packet.Processor {
	return &reusingProcessor{}
}

func (p *reusingProcessor) SetObtainer(o packet.Obtainer) {
	p.obtainer = o
}

func (p *reusingProcessor) SetHandler(handler packet.Handler) {
	p.handler = handler
}

func (p *reusingProcessor) LimitPacketNumber(limit int) {
	p.packetNumLimit = limit
}

func (p *reusingProcessor) ProcessAll() (err error) {
	errs.PassE(&err)
	pd := NewEndpointPayloadDetector()
	for port := 30100; port < 30200; port++ {
		pd.addDstMap(layers.NewUDPPortEndpoint(layers.UDPPort(port)), bats.LayerTypeBSU)
	}
	for port := 51000; port < 51100; port++ {
		pd.addDstMap(layers.NewUDPPortEndpoint(layers.UDPPort(port)), miax.LayerTypeMachTop)
	}
	pmlf := &payloadMuxLayerFactory{}
	pmlf.AddDetector(pd)

	parser := packet.NewReusingLayerParser(layers.LayerTypeEthernet)
	parser.AddDecodingLayerFactory(EthernetLayerFactory)
	parser.AddDecodingLayerFactory(Dot1QLayerFactory)
	parser.AddDecodingLayerFactory(IPv4LayerFactory)
	parser.AddDecodingLayerFactory(UDPLayerFactory)
	parser.AddDecodingLayerFactory(TcpIgnoreLayerFactory)
	parser.AddDecodingLayerFactory(pmlf)
	parser.AddDecodingLayerFactory(miax.MachTopLayerFactory)
	parser.AddDecodingLayerFactory(miax.MachLayerFactory)
	parser.AddDecodingLayerFactory(miax.TomLayerFactory)
	parser.AddDecodingLayerFactory(bats.BSULayerFactory)
	parser.AddDecodingLayerFactory(bats.PitchLayerFactory)

	packetNumLimit := -1
	if p.packetNumLimit > 0 {
		packetNumLimit = p.packetNumLimit
	}
	var decoded []gopacket.DecodingLayer
	pmlf.SetDecodedLayers(&decoded)
	for packetNum := 0; packetNum != packetNumLimit; packetNum++ {
		//log.Printf("packetNum: %d\n", packetNum)
		data, ci, err := p.obtainer.ZeroCopyReadPacketData()
		if err == io.EOF {
			break
		}
		errs.CheckE(err)
		errs.CheckE(parser.DecodeLayers(data, &decoded))
		errs.CheckE(p.ProcessPacket(data, ci, decoded))
	}
	return
}

func (p *reusingProcessor) ProcessPacket(data []byte, ci gopacket.CaptureInfo, decoded []gopacket.DecodingLayer) (err error) {
	errs.PassE(&err)
	pkt, err := p.CreatePacket(data, ci, decoded)
	errs.CheckE(err)
	p.handler.HandlePacket(pkt)
	p.flowBufSrc.Reset()
	p.flowBufDst.Reset()
	var flow gopacket.Flow
	var seqNum uint64
	for _, layer := range decoded {
		//log.Printf("%#v", layer)
		switch l := layer.(type) {
		case gopacket.NetworkLayer:
			p.flowBufSrc.Write(l.NetworkFlow().Src().Raw())
			p.flowBufDst.Write(l.NetworkFlow().Dst().Raw())
		case *layers.UDP:
			p.flowBufSrc.Write(l.TransportFlow().Src().Raw())
			p.flowBufDst.Write(l.TransportFlow().Dst().Raw())
		case *miax.Mach:
			flow = gopacket.NewFlow(packet.EndpointCombinedSession, p.flowBufSrc.Bytes(), p.flowBufDst.Bytes())
			seqNum = l.SequenceNumber
		case miax.TomMessage:
			m := applicationMessage{
				layer:     l,
				flow:      flow,
				seqNum:    seqNum,
				timestamp: pkt.Timestamp(),
			}
			p.handler.HandleMessage(&m)
		case *bats.BSU:
			flow = gopacket.NewFlow(packet.EndpointCombinedSession, p.flowBufSrc.Bytes(), p.flowBufDst.Bytes())
			seqNum = uint64(l.Sequence)
		case bats.PitchMessage:
			m := applicationMessage{
				layer:     l,
				flow:      flow,
				seqNum:    seqNum,
				timestamp: pkt.Timestamp(),
			}
			p.handler.HandleMessage(&m)
			seqNum++
		}
	}
	return
}

func (p *reusingProcessor) CreatePacket(data []byte, ci gopacket.CaptureInfo, decoded []gopacket.DecodingLayer) (packet packet.Packet, err error) {
	packet = &reusingPacket{
		data:   data,
		ci:     ci,
		layers: decoded,
	}
	return
}

var _ packet.Packet = &reusingPacket{}

type reusingPacket struct {
	data   []byte
	ci     gopacket.CaptureInfo
	layers []gopacket.DecodingLayer
}

func (rp *reusingPacket) String() string {
	var b bytes.Buffer
	fmt.Fprintf(&b, "PACKET: %d bytes", len(rp.Data()))
	if rp.ci.Length > 0 {
		fmt.Fprintf(&b, ", wire length %d cap length %d", rp.ci.Length, rp.ci.CaptureLength)
	}
	if !rp.ci.Timestamp.IsZero() {
		fmt.Fprintf(&b, " @ %v", rp.ci.Timestamp)
	}
	b.WriteByte('\n')
	for i, l := range rp.layers {
		if gl, ok := l.(gopacket.Layer); ok {
			fmt.Fprintf(&b, "- Layer %d (%02d bytes) = %s\n", i+1, len(gl.LayerContents()), gopacket.LayerString(gl))
		} else {
			fmt.Fprintf(&b, "- Layer %d <cannot print>\n", i+1)
		}
	}
	return b.String()
}
func (rp *reusingPacket) Data() []byte {
	return rp.data
}
func (rp *reusingPacket) Timestamp() time.Time {
	return rp.ci.Timestamp
}

/************************************************************************/
var (
	EthernetLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeEthernet,
		func() gopacket.DecodingLayer { return &layers.Ethernet{} },
	)
	Dot1QLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeDot1Q,
		func() gopacket.DecodingLayer { return &layers.Dot1Q{} },
	)
	IPv4LayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeIPv4,
		func() gopacket.DecodingLayer { return &layers.IPv4{} },
	)
	UDPLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeUDP,
		func() gopacket.DecodingLayer { return &layers.UDP{} },
	)
	TcpIgnoreLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeTCP,
		func() gopacket.DecodingLayer { return &gopacket.Payload{} },
	)
)

/************************************************************************/
var _ = log.Ldate
<commit_msg>packet/processor: support moldudp64 & itto<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package processor

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"time"

	"code.google.com/p/gopacket"
	"code.google.com/p/gopacket/layers"

	"my/errs"

	"my/itto/verify/packet"
	"my/itto/verify/packet/bats"
	"my/itto/verify/packet/itto"
	"my/itto/verify/packet/miax"
	"my/itto/verify/packet/moldudp64"
)

type reusingProcessor struct {
	obtainer       packet.Obtainer
	handler        packet.Handler
	packetNumLimit int
	flowBufSrc     bytes.Buffer
	flowBufDst     bytes.Buffer
}

// default processor is reusing processor
func NewProcessor() packet.Processor {
	return NewReusingProcessor()
}

func NewReusingProcessor() packet.Processor {
	return &reusingProcessor{}
}

func (p *reusingProcessor) SetObtainer(o packet.Obtainer) {
	p.obtainer = o
}

func (p *reusingProcessor) SetHandler(handler packet.Handler) {
	p.handler = handler
}

func (p *reusingProcessor) LimitPacketNumber(limit int) {
	p.packetNumLimit = limit
}

func (p *reusingProcessor) ProcessAll() (err error) {
	errs.PassE(&err)
	pd := NewEndpointPayloadDetector()
	for port := 30100; port < 30200; port++ {
		pd.addDstMap(layers.NewUDPPortEndpoint(layers.UDPPort(port)), bats.LayerTypeBSU)
	}
	for port := 51000; port < 51100; port++ {
		pd.addDstMap(layers.NewUDPPortEndpoint(layers.UDPPort(port)), miax.LayerTypeMachTop)
	}
	for port := 18000; port < 18010; port++ {
		pd.addDstMap(layers.NewUDPPortEndpoint(layers.UDPPort(port)), moldudp64.LayerTypeMoldUDP64)
	}
	pmlf := &payloadMuxLayerFactory{}
	pmlf.AddDetector(pd)

	parser := packet.NewReusingLayerParser(layers.LayerTypeEthernet)
	parser.AddDecodingLayerFactory(EthernetLayerFactory)
	parser.AddDecodingLayerFactory(Dot1QLayerFactory)
	parser.AddDecodingLayerFactory(IPv4LayerFactory)
	parser.AddDecodingLayerFactory(UDPLayerFactory)
	parser.AddDecodingLayerFactory(TcpIgnoreLayerFactory)
	parser.AddDecodingLayerFactory(pmlf)
	parser.AddDecodingLayerFactory(miax.MachTopLayerFactory)
	parser.AddDecodingLayerFactory(miax.MachLayerFactory)
	parser.AddDecodingLayerFactory(miax.TomLayerFactory)
	parser.AddDecodingLayerFactory(bats.BSULayerFactory)
	parser.AddDecodingLayerFactory(bats.PitchLayerFactory)
	parser.AddDecodingLayerFactory(moldudp64.MoldUDP64LayerFactory)
	parser.AddDecodingLayerFactory(moldudp64.MoldUDP64MessageBlockLayerFactory)
	parser.AddDecodingLayerFactory(itto.IttoLayerFactory)

	packetNumLimit := -1
	if p.packetNumLimit > 0 {
		packetNumLimit = p.packetNumLimit
	}
	var decoded []gopacket.DecodingLayer
	pmlf.SetDecodedLayers(&decoded)
	for packetNum := 0; packetNum != packetNumLimit; packetNum++ {
		//log.Printf("packetNum: %d\n", packetNum)
		data, ci, err := p.obtainer.ZeroCopyReadPacketData()
		if err == io.EOF {
			break
		}
		errs.CheckE(err)
		errs.CheckE(parser.DecodeLayers(data, &decoded))
		errs.CheckE(p.ProcessPacket(data, ci, decoded))
	}
	return
}

func (p *reusingProcessor) ProcessPacket(data []byte, ci gopacket.CaptureInfo, decoded []gopacket.DecodingLayer) (err error) {
	errs.PassE(&err)
	pkt, err := p.CreatePacket(data, ci, decoded)
	errs.CheckE(err)
	p.handler.HandlePacket(pkt)
	p.flowBufSrc.Reset()
	p.flowBufDst.Reset()
	var flow gopacket.Flow
	var seqNum uint64
	for _, layer := range decoded {
		//log.Printf("%#v", layer)
		switch l := layer.(type) {
		case gopacket.NetworkLayer:
			p.flowBufSrc.Write(l.NetworkFlow().Src().Raw())
			p.flowBufDst.Write(l.NetworkFlow().Dst().Raw())
		case *layers.UDP:
			p.flowBufSrc.Write(l.TransportFlow().Src().Raw())
			p.flowBufDst.Write(l.TransportFlow().Dst().Raw())
		case *miax.Mach:
			flow = gopacket.NewFlow(packet.EndpointCombinedSession, p.flowBufSrc.Bytes(), p.flowBufDst.Bytes())
			seqNum = l.SequenceNumber
		case miax.TomMessage:
			m := applicationMessage{
				layer:     l,
				flow:      flow,
				seqNum:    seqNum,
				timestamp: pkt.Timestamp(),
			}
			p.handler.HandleMessage(&m)
		case *bats.BSU:
			flow = gopacket.NewFlow(packet.EndpointCombinedSession, p.flowBufSrc.Bytes(), p.flowBufDst.Bytes())
			seqNum = uint64(l.Sequence)
		case bats.PitchMessage:
			m := applicationMessage{
				layer:     l,
				flow:      flow,
				seqNum:    seqNum,
				timestamp: pkt.Timestamp(),
			}
			p.handler.HandleMessage(&m)
			seqNum++
		case *moldudp64.MoldUDP64:
			flow = gopacket.NewFlow(packet.EndpointCombinedSession, p.flowBufSrc.Bytes(), p.flowBufDst.Bytes())
			seqNum = l.SequenceNumber
		case itto.IttoMessage:
			m := applicationMessage{
				layer:     l,
				flow:      flow,
				seqNum:    seqNum,
				timestamp: pkt.Timestamp(),
			}
			p.handler.HandleMessage(&m)
			seqNum++
		}
	}
	return
}

func (p *reusingProcessor) CreatePacket(data []byte, ci gopacket.CaptureInfo, decoded []gopacket.DecodingLayer) (packet packet.Packet, err error) {
	packet = &reusingPacket{
		data:   data,
		ci:     ci,
		layers: decoded,
	}
	return
}

var _ packet.Packet = &reusingPacket{}

type reusingPacket struct {
	data   []byte
	ci     gopacket.CaptureInfo
	layers []gopacket.DecodingLayer
}

func (rp *reusingPacket) String() string {
	var b bytes.Buffer
	fmt.Fprintf(&b, "PACKET: %d bytes", len(rp.Data()))
	if rp.ci.Length > 0 {
		fmt.Fprintf(&b, ", wire length %d cap length %d", rp.ci.Length, rp.ci.CaptureLength)
	}
	if !rp.ci.Timestamp.IsZero() {
		fmt.Fprintf(&b, " @ %v", rp.ci.Timestamp)
	}
	b.WriteByte('\n')
	for i, l := range rp.layers {
		if gl, ok := l.(gopacket.Layer); ok {
			fmt.Fprintf(&b, "- Layer %d (%02d bytes) = %s\n", i+1, len(gl.LayerContents()), gopacket.LayerString(gl))
		} else {
			fmt.Fprintf(&b, "- Layer %d <cannot print>\n", i+1)
		}
	}
	return b.String()
}
func (rp *reusingPacket) Data() []byte {
	return rp.data
}
func (rp *reusingPacket) Timestamp() time.Time {
	return rp.ci.Timestamp
}

/************************************************************************/
var (
	EthernetLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeEthernet,
		func() gopacket.DecodingLayer { return &layers.Ethernet{} },
	)
	Dot1QLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeDot1Q,
		func() gopacket.DecodingLayer { return &layers.Dot1Q{} },
	)
	IPv4LayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeIPv4,
		func() gopacket.DecodingLayer { return &layers.IPv4{} },
	)
	UDPLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeUDP,
		func() gopacket.DecodingLayer { return &layers.UDP{} },
	)
	TcpIgnoreLayerFactory = packet.NewSingleDecodingLayerFactory(
		layers.LayerTypeTCP,
		func() gopacket.DecodingLayer { return &gopacket.Payload{} },
	)
)

/************************************************************************/
var _ = log.Ldate
<|endoftext|>


<commit_before>package cwl

import (
	"fmt"
	"io/ioutil"
	"sort"
	"strings"
)

// Input represents "CommandInputParameter".
// @see http://www.commonwl.org/v1.0/CommandLineTool.html#CommandInputParameter
type Input struct {
	ID             string          `json:"id"`
	Label          string          `json:"label"`
	Doc            string          `json:"doc"`
	Format         string          `json:"format"`
	Binding        *Binding        `json:"inputBinding"`
	Default        *InputDefault   `json:"default"`
	Types          []Type          `json:"type"`
	SecondaryFiles []SecondaryFile `json:"secondary_files"`
	// Input.Provided is what provided by parameters.(json|yaml)
	Provided interface{} `json:"-"`
	// Requirement ..
	RequiredType *Type
	Requirements Requirements
}

// New constructs "Input" struct from interface{}.
func (_ Input) New(i interface{}) Input {
	dest := Input{}
	switch x := i.(type) {
	case map[string]interface{}:
		for key, v := range x {
			switch key {
			case "id":
				dest.ID = v.(string)
			case "type":
				dest.Types = Type{}.NewList(v)
			case "label":
				dest.Label = v.(string)
			case "doc":
				dest.Doc = v.(string)
			case "inputBinding":
				dest.Binding = Binding{}.New(v)
			case "default":
				dest.Default = InputDefault{}.New(v)
			case "format":
				dest.Format = v.(string)
			case "secondaryFiles":
				dest.SecondaryFiles = SecondaryFile{}.NewList(v)
			}
		}
	case string:
		dest.Types = Type{}.NewList(x)
	case []interface{}:
		for _, v := range x {
			dest.Types = append(dest.Types, Type{}.New(v))
		}
	}
	return dest
}

// flatten
func (input Input) flatten(typ Type, binding *Binding, prov interface{}) []string {
	flattened := []string{}
	switch typ.Type {
	case "int": // Array of Int
		tobejoined := []string{}
		for _, e := range input.Provided.([]interface{}) {
			tobejoined = append(tobejoined, fmt.Sprintf("%v", e))
		}
		flattened = append(flattened, strings.Join(tobejoined, input.Binding.Separator))
	case "File": // Array of Files
		switch arr := input.Provided.(type) {
		case []string:
			// TODO:
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case map[interface{}]interface{}:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v["location"]))
				default:
					// TODO:
				}
			}
			// In case it's Array of Files, unlike array of int,
			// it's NOT gonna be joined with .Binding.Separator.
			flattened = append(flattened, separated...)
		}
	case "string": // Array of string
		switch arr := prov.(type) {
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case string:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v))
				default:
					// TODO
				}
			}
			flattened = append(flattened, separated...)
		default:
			// TODO
		}
	case "array":
		switch arr := prov.(type) {
		case []interface{}:
			flattened = append(flattened, input.flatten(typ.Items[0], typ.Binding, arr[0])...)
		default:
			// TODO
		}
	default:
		if input.RequiredType != nil {
			flattened = append(flattened, input.flattenWithRequiredType()...)
		} else {
			// TODO
		}
	}
	return flattened
}

func (input Input) flattenWithRequiredType() []string {
	flattened := []string{}
	key, needed := input.Types[0].NeedRequirement()
	if !needed {
		return flattened
	}
	if input.RequiredType.Name != key {
		return flattened
	}
	switch provided := input.Provided.(type) {
	case []interface{}:
		for _, e := range provided {
			switch v := e.(type) {
			case map[interface{}]interface{}:
				for _, field := range input.RequiredType.Fields {
					if val, ok := v[field.Name]; ok {
						if field.Binding == nil {
							// Without thinking anything, just append it!!!
							flattened = append(flattened, fmt.Sprintf("%v", val))
						} else {
							if field.Binding.Prefix != "" {
								if field.Binding.Separate {
									flattened = append(flattened, field.Binding.Prefix, fmt.Sprintf("%v", val))
								} else {
									// TODO: Join if .Separator is given
									flattened = append(flattened, fmt.Sprintf("%s%v", field.Binding.Prefix, val))
								}
							} else {
								switch v2 := val.(type) {
								case []interface{}:
									for _, val2 := range v2 {
										switch v3 := val2.(type) {
										case []interface{}:
										case map[interface{}]interface{}:
											for _, types := range input.Requirements[0].SchemaDefRequirement.Types {
												val3array := []string{}
												var val3count int = 0
												sort.Sort(types.Fields)
												for _, fields := range types.Fields {
													for key3, val3 := range v3 {
														if fields.Name == key3 {
															for _, val3type := range fields.Types {
																if val3type.Type == "" {
																} else {
																	switch val3type.Type {
																	case "enum":
																		for _, symbol := range val3type.Symbols {
																			if symbol == val3 {
																				val3array = append(val3array, fmt.Sprintf("%v", val3))
																				val3count = val3count + 1
																			}
																		}
																	case "int":
																		if fields.Binding.Prefix != "" {
																			val3array = append(val3array, fields.Binding.Prefix, fmt.Sprintf("%v", val3))
																			val3count = val3count + 1
																		} else {
																			val3array = append(val3array, fmt.Sprintf("%v", val3))
																			val3count = val3count + 1
																		}
																	}
																}
															}
														}
													}
												}
												if len(v3) == val3count {
													flattened = append(flattened, val3array...)
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return flattened
}

// Flatten ...
func (input Input) Flatten() []string {
	if input.Provided == nil {
		// In case "input.Default == nil" should be validated by usage layer.
		if input.Default != nil {
			return input.Default.Flatten(input.Binding)
		} else {
			return []string{}
		}
	}
	flattened := []string{}
	if repr := input.Types[0]; len(input.Types) == 1 {
		switch repr.Type {
		case "array":
			flattened = append(flattened, input.flatten(repr.Items[0], repr.Binding, input.Provided)...)
		case "int":
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided.(int)))
		case "File":
			switch provided := input.Provided.(type) {
			case map[interface{}]interface{}:
				// TODO: more strict type casting
				if provided["location"] != nil {
					flattened = append(flattened, fmt.Sprintf("%v", provided["location"]))
				} else {
					fp, _ := ioutil.TempFile("", "ioutil")
					fpath := fp.Name()
					flattened = append(flattened, fpath)
					fp.Write([]byte(fmt.Sprintf("%v", provided["contents"])))
					// TODO: remove after finish program
					defer fp.Close()
				}
			default:
			}
		default:
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided))
		}
	}
	if input.Binding != nil && input.Binding.Prefix != "" {
		flattened = append([]string{input.Binding.Prefix}, flattened...)
	}

	return flattened
}

// Inputs represents "inputs" field in CWL.
type Inputs []Input

// New constructs new "Inputs" struct.
func (_ Inputs) New(i interface{}) Inputs {
	dest := Inputs{}
	switch x := i.(type) {
	case []interface{}:
		for _, v := range x {
			dest = append(dest, Input{}.New(v))
		}
	case map[string]interface{}:
		for key, v := range x {
			input := Input{}.New(v)
			input.ID = key
			dest = append(dest, input)
		}
	}
	return dest
}

// Len for sorting.
func (ins Inputs) Len() int {
	return len(ins)
}

// Less for sorting.
func (ins Inputs) Less(i, j int) bool {
	prev, next := ins[i].Binding, ins[j].Binding
	switch [2]bool{prev == nil, next == nil} {
	case [2]bool{true, true}:
		return true
	case [2]bool{false, true}:
		return prev.Position < 0
	case [2]bool{true, false}:
		return next.Position > 0
	default:
		return prev.Position <= next.Position
	}
}

// Swap for sorting.
func (ins Inputs) Swap(i, j int) {
	ins[i], ins[j] = ins[j], ins[i]
}
<commit_msg>Use reference to "Input" struct<commit_after>package cwl

import (
	"fmt"
	"io/ioutil"
	"sort"
	"strings"
)

// Input represents "CommandInputParameter".
// @see http://www.commonwl.org/v1.0/CommandLineTool.html#CommandInputParameter
type Input struct {
	ID             string          `json:"id"`
	Label          string          `json:"label"`
	Doc            string          `json:"doc"`
	Format         string          `json:"format"`
	Binding        *Binding        `json:"inputBinding"`
	Default        *InputDefault   `json:"default"`
	Types          []Type          `json:"type"`
	SecondaryFiles []SecondaryFile `json:"secondary_files"`
	// Input.Provided is what provided by parameters.(json|yaml)
	Provided interface{} `json:"-"`
	// Requirement ..
	RequiredType *Type
	Requirements Requirements
}

// New constructs "Input" struct from interface{}.
func (input Input) New(i interface{}) *Input {
	dest := &Input{}
	switch x := i.(type) {
	case map[string]interface{}:
		for key, v := range x {
			switch key {
			case "id":
				dest.ID = v.(string)
			case "type":
				dest.Types = Type{}.NewList(v)
			case "label":
				dest.Label = v.(string)
			case "doc":
				dest.Doc = v.(string)
			case "inputBinding":
				dest.Binding = Binding{}.New(v)
			case "default":
				dest.Default = InputDefault{}.New(v)
			case "format":
				dest.Format = v.(string)
			case "secondaryFiles":
				dest.SecondaryFiles = SecondaryFile{}.NewList(v)
			}
		}
	case string:
		dest.Types = Type{}.NewList(x)
	case []interface{}:
		for _, v := range x {
			dest.Types = append(dest.Types, Type{}.New(v))
		}
	}
	return dest
}

// flatten
func (input *Input) flatten(typ Type, binding *Binding, prov interface{}) []string {
	flattened := []string{}
	switch typ.Type {
	case "int": // Array of Int
		tobejoined := []string{}
		for _, e := range input.Provided.([]interface{}) {
			tobejoined = append(tobejoined, fmt.Sprintf("%v", e))
		}
		flattened = append(flattened, strings.Join(tobejoined, input.Binding.Separator))
	case "File": // Array of Files
		switch arr := input.Provided.(type) {
		case []string:
			// TODO:
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case map[interface{}]interface{}:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v["location"]))
				default:
					// TODO:
				}
			}
			// In case it's Array of Files, unlike array of int,
			// it's NOT gonna be joined with .Binding.Separator.
			flattened = append(flattened, separated...)
		}
	case "string": // Array of string
		switch arr := prov.(type) {
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case string:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v))
				default:
					// TODO
				}
			}
			flattened = append(flattened, separated...)
		default:
			// TODO
		}
	case "array":
		switch arr := prov.(type) {
		case []interface{}:
			flattened = append(flattened, input.flatten(typ.Items[0], typ.Binding, arr[0])...)
		default:
			// TODO
		}
	default:
		if input.RequiredType != nil {
			flattened = append(flattened, input.flattenWithRequiredType()...)
		} else {
			// TODO
		}
	}
	return flattened
}

func (input *Input) flattenWithRequiredType() []string {
	flattened := []string{}
	key, needed := input.Types[0].NeedRequirement()
	if !needed {
		return flattened
	}
	if input.RequiredType.Name != key {
		return flattened
	}
	switch provided := input.Provided.(type) {
	case []interface{}:
		for _, e := range provided {
			switch v := e.(type) {
			case map[interface{}]interface{}:
				for _, field := range input.RequiredType.Fields {
					if val, ok := v[field.Name]; ok {
						if field.Binding == nil {
							// Without thinking anything, just append it!!!
							flattened = append(flattened, fmt.Sprintf("%v", val))
						} else {
							if field.Binding.Prefix != "" {
								if field.Binding.Separate {
									flattened = append(flattened, field.Binding.Prefix, fmt.Sprintf("%v", val))
								} else {
									// TODO: Join if .Separator is given
									flattened = append(flattened, fmt.Sprintf("%s%v", field.Binding.Prefix, val))
								}
							} else {
								switch v2 := val.(type) {
								case []interface{}:
									for _, val2 := range v2 {
										switch v3 := val2.(type) {
										case []interface{}:
										case map[interface{}]interface{}:
											for _, types := range input.Requirements[0].SchemaDefRequirement.Types {
												val3array := []string{}
												var val3count int = 0
												sort.Sort(types.Fields)
												for _, fields := range types.Fields {
													for key3, val3 := range v3 {
														if fields.Name == key3 {
															for _, val3type := range fields.Types {
																if val3type.Type == "" {
																} else {
																	switch val3type.Type {
																	case "enum":
																		for _, symbol := range val3type.Symbols {
																			if symbol == val3 {
																				val3array = append(val3array, fmt.Sprintf("%v", val3))
																				val3count = val3count + 1
																			}
																		}
																	case "int":
																		if fields.Binding.Prefix != "" {
																			val3array = append(val3array, fields.Binding.Prefix, fmt.Sprintf("%v", val3))
																			val3count = val3count + 1
																		} else {
																			val3array = append(val3array, fmt.Sprintf("%v", val3))
																			val3count = val3count + 1
																		}
																	}
																}
															}
														}
													}
												}
												if len(v3) == val3count {
													flattened = append(flattened, val3array...)
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return flattened
}

// Flatten ...
func (input *Input) Flatten() []string {
	if input.Provided == nil {
		// In case "input.Default == nil" should be validated by usage layer.
		if input.Default != nil {
			return input.Default.Flatten(input.Binding)
		} else {
			return []string{}
		}
	}
	flattened := []string{}
	if repr := input.Types[0]; len(input.Types) == 1 {
		switch repr.Type {
		case "array":
			flattened = append(flattened, input.flatten(repr.Items[0], repr.Binding, input.Provided)...)
		case "int":
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided.(int)))
		case "File":
			switch provided := input.Provided.(type) {
			case map[interface{}]interface{}:
				// TODO: more strict type casting
				if provided["location"] != nil {
					flattened = append(flattened, fmt.Sprintf("%v", provided["location"]))
				} else {
					fp, _ := ioutil.TempFile("", "ioutil")
					fpath := fp.Name()
					flattened = append(flattened, fpath)
					fp.Write([]byte(fmt.Sprintf("%v", provided["contents"])))
					// TODO: remove after finish program
					defer fp.Close()
				}
			default:
			}
		default:
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided))
		}
	}
	if input.Binding != nil && input.Binding.Prefix != "" {
		flattened = append([]string{input.Binding.Prefix}, flattened...)
	}

	return flattened
}

// Inputs represents "inputs" field in CWL.
type Inputs []*Input

// New constructs new "Inputs" struct.
func (ins Inputs) New(i interface{}) Inputs {
	dest := Inputs{}
	switch x := i.(type) {
	case []interface{}:
		for _, v := range x {
			dest = append(dest, Input{}.New(v))
		}
	case map[string]interface{}:
		for key, v := range x {
			input := Input{}.New(v)
			input.ID = key
			dest = append(dest, input)
		}
	}
	return dest
}

// Len for sorting.
func (ins Inputs) Len() int {
	return len(ins)
}

// Less for sorting.
func (ins Inputs) Less(i, j int) bool {
	prev, next := ins[i].Binding, ins[j].Binding
	switch [2]bool{prev == nil, next == nil} {
	case [2]bool{true, true}:
		return true
	case [2]bool{false, true}:
		return prev.Position < 0
	case [2]bool{true, false}:
		return next.Position > 0
	default:
		return prev.Position <= next.Position
	}
}

// Swap for sorting.
func (ins Inputs) Swap(i, j int) {
	ins[i], ins[j] = ins[j], ins[i]
}
<|endoftext|>


<commit_before>package jason

import (
	"encoding/json"
	"errors"
	"io"
)

// Value represents an arbitrary JSON value.
// It may contain a bool, number, string, object, array or null.
type Value struct {
	data   interface{}
	exists bool // Used to separate nil and non-existing values
}

// Object represents an object JSON value.
// The underlying golang map can be accessed with Map.
// It is needed when iterating through the values of the object.
type Object struct {
	Value
	Map   map[string]*Value // The formatted map with typed values
	valid bool
}

// Create a new Value from a io.reader.
// Useful for parsing the body of a net/http response.
// Returns an error if something went wrong.
// Example: NewFromReader(res.Body)
func NewValueFromReader(reader io.Reader) (*Value, error) {
	j := new(Value)
	d := json.NewDecoder(reader)
	err := d.Decode(&j.data)
	return j, err
}

// Create a new Value from bytes
// Returns an error if the bytes couldn't be parsed.
func NewValueFromBytes(b []byte) (*Value, error) {
	j := new(Value)
	err := json.Unmarshal(b, &j.data)
	return j, err
}

// Create a new Value from a string
// Returns an error if the string couldn't be parsed.
func NewValueFromString(s string) (*Value, error) {
	b := []byte(s)
	return NewValueFromBytes(b)
}

// Marshal into bytes
func (j *Value) Marshal() ([]byte, error) {
	return json.Marshal(j.data)
}

// Private Get
func (j *Value) get(key string) (*Value, error) {

	// Assume this is an object
	obj := j.object()

	// Only continue if it really is an object
	if obj.valid {
		child, ok := obj.Map[key]
		if ok {
			return child, nil
		}
	}

	return nil, errors.New("could not get")

}

// Private get path
func (j *Value) getPath(keys []string) (*Value, error) {
	current := j
	var err error
	for _, key := range keys {
		current, err = current.get(key)

		if err != nil {
			return nil, err
		}
	}
	return current, nil
}

// Get Value at key path. Returns a Value or error.
// Example: Get("address", "street")
func (j *Value) Get(keys ...string) (*Value, error) {
	return j.getPath(keys)
}

// Get Object at key path. Returns an Object, or error.
func (v *Value) GetObject(keys ...string) (*Object, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return nil, err
	} else {

		obj, err := child.AsObject()

		if err != nil {
			return nil, err
		} else {
			return obj, nil
		}

	}

	return nil, nil
}

// Get string at key path. Returns a string primitive, or error.
func (v *Value) GetString(keys ...string) (string, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return "", err
	} else {

		return child.AsString()

	}

	return "", nil
}

// Get number at key path. Returns a float64, or error.
func (v *Value) GetNumber(keys ...string) (float64, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return 0, err
	} else {

		n, err := child.AsNumber()

		if err != nil {
			return 0, err
		} else {
			return n, nil
		}

	}

	return 0, nil
}

// Get number at key path. Returns a bool, or error.
func (v *Value) GetBoolean(keys ...string) (bool, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return false, err
	}

	return child.AsBoolean()
}

// Get array at key path. Returns an array of Values, or error.
func (v *Value) GetArray(keys ...string) ([]*Value, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return nil, err
	} else {

		return child.AsArray()

	}

	return nil, nil
}

// Returns true if the instance is actually a JSON null object.
func (j *Value) IsNull() bool {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case nil:
		valid = j.exists // Valid only if j also exists, since other values could possibly also be nil
		break
	}

	return valid

}

// Returns the current Value as an array of Values.
// Returns an error if the current Value is not an Array.
func (j *Value) AsArray() ([]*Value, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case []interface{}:
		valid = true
		break
	}

	// Unsure if this is a good way to use slices, it's probably not
	var slice []*Value

	if valid {

		for _, element := range j.data.([]interface{}) {
			child := Value{element, true}
			slice = append(slice, &child)
		}

		return slice, nil
	}

	return slice, errors.New("Not an array")

}

// Returns the current Value as a float64.
// Returns an error if the current Value is not a json number.
func (j *Value) AsNumber() (float64, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case float64:
		valid = true
		break
	}

	if valid {
		return j.data.(float64), nil
	}

	return 0, errors.New("not a number")
}

// Returns the current Value as a bool.
// Returns an error if the current Value is not a json boolean.
func (j *Value) AsBoolean() (bool, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case bool:
		valid = true
		break
	}

	if valid {
		return j.data.(bool), nil
	}

	return false, errors.New("no bool")
}

// Private object
func (j *Value) object() *Object {

	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case map[string]interface{}:
		valid = true
		break
	}

	obj := new(Object)
	obj.valid = valid

	m := make(map[string]*Value)

	if valid {
		//obj.Map = j.data.(map[string]interface{})

		for key, element := range j.data.(map[string]interface{}) {
			m[key] = &Value{element, true}

		}
	}

	obj.data = j.data
	obj.Map = m

	return obj
}

// Returns the current data as objects with string keys and Value values.
// Returns an error if the current Value is not a json object
func (j *Value) AsObject() (*Object, error) {
	obj := j.object()

	var err error

	if !obj.valid {
		err = errors.New("Is not an object")
	}

	return obj, err
}

// Returns the current data as a golang string
// Returns an error if the current Value is not a json string
func (j *Value) AsString() (string, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case string:
		valid = true
		break
	}

	if valid {
		return j.data.(string), nil
	}

	return "", errors.New("not a string")
}

// The method named String() is used by golang's log method for logging
// It returns the Value as object
func (j *Value) String() string {
	f, err := json.Marshal(j.data)
	if err != nil {
		return err.Error()
	} else {
		return string(f)
	}
}
<commit_msg>Changed IsNull to AsNull<commit_after>package jason

import (
	"encoding/json"
	"errors"
	"io"
)

// Value represents an arbitrary JSON value.
// It may contain a bool, number, string, object, array or null.
type Value struct {
	data   interface{}
	exists bool // Used to separate nil and non-existing values
}

// Object represents an object JSON value.
// The underlying golang map can be accessed with Map.
// It is needed when iterating through the values of the object.
type Object struct {
	Value
	Map   map[string]*Value // The formatted map with typed values
	valid bool
}

// Create a new Value from a io.reader.
// Useful for parsing the body of a net/http response.
// Returns an error if something went wrong.
// Example: NewFromReader(res.Body)
func NewValueFromReader(reader io.Reader) (*Value, error) {
	j := new(Value)
	d := json.NewDecoder(reader)
	err := d.Decode(&j.data)
	return j, err
}

// Create a new Value from bytes
// Returns an error if the bytes couldn't be parsed.
func NewValueFromBytes(b []byte) (*Value, error) {
	j := new(Value)
	err := json.Unmarshal(b, &j.data)
	return j, err
}

// Create a new Value from a string
// Returns an error if the string couldn't be parsed.
func NewValueFromString(s string) (*Value, error) {
	b := []byte(s)
	return NewValueFromBytes(b)
}

// Marshal into bytes
func (j *Value) Marshal() ([]byte, error) {
	return json.Marshal(j.data)
}

// Private Get
func (j *Value) get(key string) (*Value, error) {

	// Assume this is an object
	obj := j.object()

	// Only continue if it really is an object
	if obj.valid {
		child, ok := obj.Map[key]
		if ok {
			return child, nil
		}
	}

	return nil, errors.New("could not get")

}

// Private get path
func (j *Value) getPath(keys []string) (*Value, error) {
	current := j
	var err error
	for _, key := range keys {
		current, err = current.get(key)

		if err != nil {
			return nil, err
		}
	}
	return current, nil
}

// Get Value at key path. Returns a Value or error.
// Example: Get("address", "street")
func (j *Value) Get(keys ...string) (*Value, error) {
	return j.getPath(keys)
}

// Get Object at key path. Returns an Object, or error.
func (v *Value) GetObject(keys ...string) (*Object, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return nil, err
	} else {

		obj, err := child.AsObject()

		if err != nil {
			return nil, err
		} else {
			return obj, nil
		}

	}

	return nil, nil
}

// Get string at key path. Returns a string primitive, or error.
func (v *Value) GetString(keys ...string) (string, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return "", err
	} else {

		return child.AsString()

	}

	return "", nil
}

// Get number at key path. Returns a float64, or error.
func (v *Value) GetNumber(keys ...string) (float64, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return 0, err
	} else {

		n, err := child.AsNumber()

		if err != nil {
			return 0, err
		} else {
			return n, nil
		}

	}

	return 0, nil
}

// Get number at key path. Returns a bool, or error.
func (v *Value) GetBoolean(keys ...string) (bool, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return false, err
	}

	return child.AsBoolean()
}

// Get array at key path. Returns an array of Values, or error.
func (v *Value) GetArray(keys ...string) ([]*Value, error) {
	child, err := v.getPath(keys)

	if err != nil {
		return nil, err
	} else {

		return child.AsArray()

	}

	return nil, nil
}

// Returns an error if the value is not actually null
func (j *Value) AsNull() error {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case nil:
		valid = j.exists // Valid only if j also exists, since other values could possibly also be nil
		break
	}

	if valid {
		return nil
	}

	return errors.New("is not null")

}

// Returns the current Value as an array of Values.
// Returns an error if the current Value is not an Array.
func (j *Value) AsArray() ([]*Value, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case []interface{}:
		valid = true
		break
	}

	// Unsure if this is a good way to use slices, it's probably not
	var slice []*Value

	if valid {

		for _, element := range j.data.([]interface{}) {
			child := Value{element, true}
			slice = append(slice, &child)
		}

		return slice, nil
	}

	return slice, errors.New("Not an array")

}

// Returns the current Value as a float64.
// Returns an error if the current Value is not a json number.
func (j *Value) AsNumber() (float64, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case float64:
		valid = true
		break
	}

	if valid {
		return j.data.(float64), nil
	}

	return 0, errors.New("not a number")
}

// Returns the current Value as a bool.
// Returns an error if the current Value is not a json boolean.
func (j *Value) AsBoolean() (bool, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case bool:
		valid = true
		break
	}

	if valid {
		return j.data.(bool), nil
	}

	return false, errors.New("no bool")
}

// Private object
func (j *Value) object() *Object {

	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case map[string]interface{}:
		valid = true
		break
	}

	obj := new(Object)
	obj.valid = valid

	m := make(map[string]*Value)

	if valid {
		//obj.Map = j.data.(map[string]interface{})

		for key, element := range j.data.(map[string]interface{}) {
			m[key] = &Value{element, true}

		}
	}

	obj.data = j.data
	obj.Map = m

	return obj
}

// Returns the current data as objects with string keys and Value values.
// Returns an error if the current Value is not a json object
func (j *Value) AsObject() (*Object, error) {
	obj := j.object()

	var err error

	if !obj.valid {
		err = errors.New("Is not an object")
	}

	return obj, err
}

// Returns the current data as a golang string
// Returns an error if the current Value is not a json string
func (j *Value) AsString() (string, error) {
	var valid bool

	// Check the type of this data
	switch j.data.(type) {
	case string:
		valid = true
		break
	}

	if valid {
		return j.data.(string), nil
	}

	return "", errors.New("not a string")
}

// The method named String() is used by golang's log method for logging
// It returns the Value as object
func (j *Value) String() string {
	f, err := json.Marshal(j.data)
	if err != nil {
		return err.Error()
	} else {
		return string(f)
	}
}
<|endoftext|>


<commit_before>package jq

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"

	"github.com/jingweno/jqpipe-go"
)

var Path, Version string

func init() {
	var err error

	Path, err = setupJQPath()
	if err != nil {
		log.Fatal(err)
	}

	Version, err = jqVersion()
	if err != nil {
		log.Fatal(err)
	}
}

func setupJQPath() (string, error) {
	pwd, err := os.Getwd()
	if err != nil {
		return "", err
	}

	jqPath := filepath.Join(pwd, "bin", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
	os.Setenv("PATH", fmt.Sprintf("%s%c%s", jqPath, os.PathListSeparator, os.Getenv("PATH")))

	return filepath.Join(jqPath, "jq"), nil
}

func jqVersion() (string, error) {
	fmt.Println(os.Getenv("PATH"))
	fmt.Println(Path)
	out, err := exec.Command(Path, "--version").Output()
	if err != nil {
		return "", err
	}

	out = bytes.TrimSpace(out)
	r := regexp.MustCompile(`^jq-(.+)$`)
	if r.Match(out) {
		m := r.FindSubmatch(out)[1]
		return string(m), nil
	}

	r = regexp.MustCompile(`^jq version (.+)$`)
	if r.Match(out) {
		m := r.FindSubmatch(out)[1]
		return string(m), nil
	}

	return "", fmt.Errorf("can't find jq version: %s", out)
}

type JQ struct {
	J string `json:"j"`
	Q string `json:"q"`
}

func (j *JQ) Eval() (string, error) {
	seq, err := jq.Eval(j.J, j.Q)
	if err != nil {
		return "", err
	}

	result := []string{}
	for _, s := range seq {
		ss := string(s)
		if ss != "" && ss != "null" {
			result = append(result, ss)
		}
	}

	return strings.Join(result, "\n"), nil
}

func (j *JQ) Valid() bool {
	return j.J != "" && j.Q != ""
}

func (j JQ) String() string {
	return fmt.Sprintf("j=%s, q=%s", j.J, j.Q)
}
<commit_msg>Get jq version from `jq —help`<commit_after>package jq

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"

	"github.com/jingweno/jqpipe-go"
)

var Path, Version string

func init() {
	var err error

	Path, err = setupJQPath()
	if err != nil {
		log.Fatal(err)
	}

	Version, err = jqVersion()
	if err != nil {
		log.Fatal(err)
	}
}

func setupJQPath() (string, error) {
	pwd, err := os.Getwd()
	if err != nil {
		return "", err
	}

	jqPath := filepath.Join(pwd, "bin", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
	os.Setenv("PATH", fmt.Sprintf("%s%c%s", jqPath, os.PathListSeparator, os.Getenv("PATH")))

	return filepath.Join(jqPath, "jq"), nil
}

func jqVersion() (string, error) {
	// get version from `jq --help`
	// since `jq --version` diffs between versions
	// e.g., 1.3 & 1.4
	var b bytes.Buffer
	cmd := exec.Command(Path, "--help")
	cmd.Stdout = &b
	cmd.Stderr = &b
	cmd.Run()

	out := bytes.TrimSpace(b.Bytes())
	r := regexp.MustCompile(`\[version (.+)\]`)
	if r.Match(out) {
		m := r.FindSubmatch(out)[1]
		return string(m), nil
	}

	return "", fmt.Errorf("can't find jq version: %s", out)
}

type JQ struct {
	J string `json:"j"`
	Q string `json:"q"`
}

func (j *JQ) Eval() (string, error) {
	seq, err := jq.Eval(j.J, j.Q)
	if err != nil {
		return "", err
	}

	result := []string{}
	for _, s := range seq {
		ss := string(s)
		if ss != "" && ss != "null" {
			result = append(result, ss)
		}
	}

	return strings.Join(result, "\n"), nil
}

func (j *JQ) Valid() bool {
	return j.J != "" && j.Q != ""
}

func (j JQ) String() string {
	return fmt.Sprintf("j=%s, q=%s", j.J, j.Q)
}
<|endoftext|>