<commit_before>package goConfig

import (
	"fmt"
	"testing"
)

type testSub struct {
	S1 int        `cfg:"S1" cfgDefault:"1"`
	S2 int        `cfg:"S2"`
	S3 string     `cfg:"S3"`
	S4 testSubSub `cfg:"S4"`
}
type testSubSub struct {
	SS1 int    `cfg:"SS1" cfgDefault:"2"`
	SS2 int    `cfg:"SS2"`
	SS3 string `cfg:"SS3"`
}
type testAux struct {
	A int     `cfg:"A"`
	B string  `cfg:"B"`
	S testSub `cfg:"S"`
}

func TestParseTags(t *testing.T) {
	s := &testAux{A: 1, S: testSub{S1: 1, S2: 2, S3: "test"}}
	err := parseTags(s, "")
	if err != nil {
		t.Fatal(err)
	}

	fmt.Printf("%#v\n", s)

	s1 := "test"
	err = parseTags(s1, "")
	if err == nil {
		t.Fatal("Error expected")
	}

	err = parseTags(&s1, "")
	if err == nil {
		t.Fatal("Error expected")
	}
}

/*
{
  "domain": "www.example.com",
  "mongodb": {
    "host": "localhost",
    "port": 27017
  }
*/

type mongoDB struct {
	Host string
	Port int
}

type configTest struct {
	Domain  string
	MongoDB mongoDB
}

func TestLoad(t *testing.T) {

	Setup.Path = "./examples/"
	//config := configTest{Domain: "test", MongoDB: mongoDB{}}
	config := configTest{}
	err := Load(&config)
	if err != nil {
		t.Fatal(err)
	}

	fmt.Printf("\n\nTestLoad: %#v\n\n", config)

}
<commit_msg>update test printf<commit_after>package goConfig

import (
	"fmt"
	"testing"
)

type testSub struct {
	S1 int        `cfg:"S1" cfgDefault:"1"`
	S2 int        `cfg:"S2"`
	S3 string     `cfg:"S3"`
	S4 testSubSub `cfg:"S4"`
}
type testSubSub struct {
	SS1 int    `cfg:"SS1" cfgDefault:"2"`
	SS2 int    `cfg:"SS2"`
	SS3 string `cfg:"SS3"`
}
type testAux struct {
	A int     `cfg:"A"`
	B string  `cfg:"B"`
	S testSub `cfg:"S"`
}

func TestParseTags(t *testing.T) {
	s := &testAux{A: 1, S: testSub{S1: 1, S2: 2, S3: "test"}}
	err := parseTags(s, "")
	if err != nil {
		t.Fatal(err)
	}

	fmt.Printf("\n\nTestParseTags: %#v\n\n", s)

	s1 := "test"
	err = parseTags(s1, "")
	if err == nil {
		t.Fatal("Error expected")
	}

	err = parseTags(&s1, "")
	if err == nil {
		t.Fatal("Error expected")
	}
}

/*
{
  "domain": "www.example.com",
  "mongodb": {
    "host": "localhost",
    "port": 27017
  }
*/

type mongoDB struct {
	Host string
	Port int
}

type configTest struct {
	Domain  string
	MongoDB mongoDB
}

func TestLoad(t *testing.T) {

	Setup.Path = "./examples/"
	//config := configTest{Domain: "test", MongoDB: mongoDB{}}
	config := configTest{}
	err := Load(&config)
	if err != nil {
		t.Fatal(err)
	}

	fmt.Printf("\n\nTestLoad: %#v\n\n", config)

}
<|endoftext|>


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

// +build go1.7

// Package v1 provides bindings to the Prometheus HTTP API v1:
// http://prometheus.io/docs/querying/api/
package v1

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/prometheus/client_golang/api"
	"github.com/prometheus/common/model"
)

const (
	statusAPIError = 422

	apiPrefix = "/api/v1"

	epQuery       = apiPrefix + "/query"
	epQueryRange  = apiPrefix + "/query_range"
	epLabelValues = apiPrefix + "/label/:name/values"
	epSeries      = apiPrefix + "/series"
)

// ErrorType models the different API error types.
type ErrorType string

// Possible values for ErrorType.
const (
	ErrBadData     ErrorType = "bad_data"
	ErrTimeout               = "timeout"
	ErrCanceled              = "canceled"
	ErrExec                  = "execution"
	ErrBadResponse           = "bad_response"
)

// Error is an error returned by the API.
type Error struct {
	Type ErrorType
	Msg  string
}

func (e *Error) Error() string {
	return fmt.Sprintf("%s: %s", e.Type, e.Msg)
}

// Range represents a sliced time range.
type Range struct {
	// The boundaries of the time range.
	Start, End time.Time
	// The maximum time between two slices within the boundaries.
	Step time.Duration
}

// API provides bindings for Prometheus's v1 API.
type API interface {
	// Query performs a query for the given time.
	Query(ctx context.Context, query string, ts time.Time) (model.Value, error)
	// QueryRange performs a query for the given range.
	QueryRange(ctx context.Context, query string, r Range) (model.Value, error)
	// LabelValues performs a query for the values of the given label.
	LabelValues(ctx context.Context, label string) (model.LabelValues, error)
}

// queryResult contains result data for a query.
type queryResult struct {
	Type   model.ValueType `json:"resultType"`
	Result interface{}     `json:"result"`

	// The decoded value.
	v model.Value
}

func (qr *queryResult) UnmarshalJSON(b []byte) error {
	v := struct {
		Type   model.ValueType `json:"resultType"`
		Result json.RawMessage `json:"result"`
	}{}

	err := json.Unmarshal(b, &v)
	if err != nil {
		return err
	}

	switch v.Type {
	case model.ValScalar:
		var sv model.Scalar
		err = json.Unmarshal(v.Result, &sv)
		qr.v = &sv

	case model.ValVector:
		var vv model.Vector
		err = json.Unmarshal(v.Result, &vv)
		qr.v = vv

	case model.ValMatrix:
		var mv model.Matrix
		err = json.Unmarshal(v.Result, &mv)
		qr.v = mv

	default:
		err = fmt.Errorf("unexpected value type %q", v.Type)
	}
	return err
}

// NewAPI returns a new API for the client.
//
// It is safe to use the returned API from multiple goroutines.
func NewAPI(c api.Client) API {
	return &httpAPI{client: apiClient{c}}
}

type httpAPI struct {
	client api.Client
}

func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
	u := h.client.URL(epQuery, nil)
	q := u.Query()

	q.Set("query", query)
	q.Set("time", ts.Format(time.RFC3339Nano))

	u.RawQuery = q.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}

	_, body, err := h.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	var qres queryResult
	err = json.Unmarshal(body, &qres)

	return model.Value(qres.v), err
}

func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.Value, error) {
	u := h.client.URL(epQueryRange, nil)
	q := u.Query()

	var (
		start = r.Start.Format(time.RFC3339Nano)
		end   = r.End.Format(time.RFC3339Nano)
		step  = strconv.FormatFloat(r.Step.Seconds(), 'f', 3, 64)
	)

	q.Set("query", query)
	q.Set("start", start)
	q.Set("end", end)
	q.Set("step", step)

	u.RawQuery = q.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}

	_, body, err := h.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	var qres queryResult
	err = json.Unmarshal(body, &qres)

	return model.Value(qres.v), err
}

func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
	u := h.client.URL(epLabelValues, map[string]string{"name": label})
	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return nil, err
	}
	_, body, err := h.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}
	var labelValues model.LabelValues
	err = json.Unmarshal(body, &labelValues)
	return labelValues, err
}

// apiClient wraps a regular client and processes successful API responses.
// Successful also includes responses that errored at the API level.
type apiClient struct {
	api.Client
}

type apiResponse struct {
	Status    string          `json:"status"`
	Data      json.RawMessage `json:"data"`
	ErrorType ErrorType       `json:"errorType"`
	Error     string          `json:"error"`
}

func (c apiClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
	resp, body, err := c.Client.Do(ctx, req)
	if err != nil {
		return resp, body, err
	}

	code := resp.StatusCode

	if code/100 != 2 && code != statusAPIError {
		return resp, body, &Error{
			Type: ErrBadResponse,
			Msg:  fmt.Sprintf("bad response code %d", resp.StatusCode),
		}
	}

	var result apiResponse

	if err = json.Unmarshal(body, &result); err != nil {
		return resp, body, &Error{
			Type: ErrBadResponse,
			Msg:  err.Error(),
		}
	}

	if (code == statusAPIError) != (result.Status == "error") {
		err = &Error{
			Type: ErrBadResponse,
			Msg:  "inconsistent body for response code",
		}
	}

	if code == statusAPIError && result.Status == "error" {
		err = &Error{
			Type: result.ErrorType,
			Msg:  result.Error,
		}
	}

	return resp, []byte(result.Data), err
}
<commit_msg>Omit zero value query time<commit_after>// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build go1.7

// Package v1 provides bindings to the Prometheus HTTP API v1:
// http://prometheus.io/docs/querying/api/
package v1

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/prometheus/client_golang/api"
	"github.com/prometheus/common/model"
)

const (
	statusAPIError = 422

	apiPrefix = "/api/v1"

	epQuery       = apiPrefix + "/query"
	epQueryRange  = apiPrefix + "/query_range"
	epLabelValues = apiPrefix + "/label/:name/values"
	epSeries      = apiPrefix + "/series"
)

// ErrorType models the different API error types.
type ErrorType string

// Possible values for ErrorType.
const (
	ErrBadData     ErrorType = "bad_data"
	ErrTimeout               = "timeout"
	ErrCanceled              = "canceled"
	ErrExec                  = "execution"
	ErrBadResponse           = "bad_response"
)

// Error is an error returned by the API.
type Error struct {
	Type ErrorType
	Msg  string
}

func (e *Error) Error() string {
	return fmt.Sprintf("%s: %s", e.Type, e.Msg)
}

// Range represents a sliced time range.
type Range struct {
	// The boundaries of the time range.
	Start, End time.Time
	// The maximum time between two slices within the boundaries.
	Step time.Duration
}

// API provides bindings for Prometheus's v1 API.
type API interface {
	// Query performs a query for the given time.
	Query(ctx context.Context, query string, ts time.Time) (model.Value, error)
	// QueryRange performs a query for the given range.
	QueryRange(ctx context.Context, query string, r Range) (model.Value, error)
	// LabelValues performs a query for the values of the given label.
	LabelValues(ctx context.Context, label string) (model.LabelValues, error)
}

// queryResult contains result data for a query.
type queryResult struct {
	Type   model.ValueType `json:"resultType"`
	Result interface{}     `json:"result"`

	// The decoded value.
	v model.Value
}

func (qr *queryResult) UnmarshalJSON(b []byte) error {
	v := struct {
		Type   model.ValueType `json:"resultType"`
		Result json.RawMessage `json:"result"`
	}{}

	err := json.Unmarshal(b, &v)
	if err != nil {
		return err
	}

	switch v.Type {
	case model.ValScalar:
		var sv model.Scalar
		err = json.Unmarshal(v.Result, &sv)
		qr.v = &sv

	case model.ValVector:
		var vv model.Vector
		err = json.Unmarshal(v.Result, &vv)
		qr.v = vv

	case model.ValMatrix:
		var mv model.Matrix
		err = json.Unmarshal(v.Result, &mv)
		qr.v = mv

	default:
		err = fmt.Errorf("unexpected value type %q", v.Type)
	}
	return err
}

// NewAPI returns a new API for the client.
//
// It is safe to use the returned API from multiple goroutines.
func NewAPI(c api.Client) API {
	return &httpAPI{client: apiClient{c}}
}

type httpAPI struct {
	client api.Client
}

func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
	u := h.client.URL(epQuery, nil)
	q := u.Query()

	q.Set("query", query)
	if !ts.IsZero() {
		q.Set("time", ts.Format(time.RFC3339Nano))
	}

	u.RawQuery = q.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}

	_, body, err := h.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	var qres queryResult
	err = json.Unmarshal(body, &qres)

	return model.Value(qres.v), err
}

func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.Value, error) {
	u := h.client.URL(epQueryRange, nil)
	q := u.Query()

	var (
		start = r.Start.Format(time.RFC3339Nano)
		end   = r.End.Format(time.RFC3339Nano)
		step  = strconv.FormatFloat(r.Step.Seconds(), 'f', 3, 64)
	)

	q.Set("query", query)
	q.Set("start", start)
	q.Set("end", end)
	q.Set("step", step)

	u.RawQuery = q.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}

	_, body, err := h.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}

	var qres queryResult
	err = json.Unmarshal(body, &qres)

	return model.Value(qres.v), err
}

func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
	u := h.client.URL(epLabelValues, map[string]string{"name": label})
	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
	if err != nil {
		return nil, err
	}
	_, body, err := h.client.Do(ctx, req)
	if err != nil {
		return nil, err
	}
	var labelValues model.LabelValues
	err = json.Unmarshal(body, &labelValues)
	return labelValues, err
}

// apiClient wraps a regular client and processes successful API responses.
// Successful also includes responses that errored at the API level.
type apiClient struct {
	api.Client
}

type apiResponse struct {
	Status    string          `json:"status"`
	Data      json.RawMessage `json:"data"`
	ErrorType ErrorType       `json:"errorType"`
	Error     string          `json:"error"`
}

func (c apiClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
	resp, body, err := c.Client.Do(ctx, req)
	if err != nil {
		return resp, body, err
	}

	code := resp.StatusCode

	if code/100 != 2 && code != statusAPIError {
		return resp, body, &Error{
			Type: ErrBadResponse,
			Msg:  fmt.Sprintf("bad response code %d", resp.StatusCode),
		}
	}

	var result apiResponse

	if err = json.Unmarshal(body, &result); err != nil {
		return resp, body, &Error{
			Type: ErrBadResponse,
			Msg:  err.Error(),
		}
	}

	if (code == statusAPIError) != (result.Status == "error") {
		err = &Error{
			Type: ErrBadResponse,
			Msg:  "inconsistent body for response code",
		}
	}

	if code == statusAPIError && result.Status == "error" {
		err = &Error{
			Type: result.ErrorType,
			Msg:  result.Error,
		}
	}

	return resp, []byte(result.Data), err
}
<|endoftext|>


<commit_before>package spec

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/pkg/units"
)

// SpecHandler provides conversion function from what gets passed in over the
// plugin API to an api.VolumeSpec object.
type SpecHandler interface {
	// SpecFromString parses options from the name.
	// If the scheduler was unable to pass in the volume spec via the API,
	// the spec can be passed in via the name in the format:
	// "key=value;key=value;name=volname"
	// source is populated if key parent=<volume_id> is specified.
	// If the spec was parsed, it returns:
	//  	(true, parsed_spec, locator, source, parsed_name)
	// If the input string didn't contain the string, it returns:
	// 	(false, DefaultSpec(), nil, nil, inputString)
	SpecFromString(inputString string) (
		bool,
		*api.VolumeSpec,
		*api.VolumeLocator,
		*api.Source,
		string,
	)

	// SpecFromOpts parses in docker options passed in the the docker run
	// command of the form --opt name=value
	// source is populated if --opt parent=<volume_id> is specified.
	// If the options are validated then it returns:
	// 	(resultant_VolumeSpec, source, locator, nil)
	// If the options have invalid values then it returns:
	//	(nil, nil, nil, error)

	SpecFromOpts(opts map[string]string) (
		*api.VolumeSpec,
		*api.VolumeLocator,
		*api.Source,
		error,
	)
	// Returns a default VolumeSpec if no docker options or string encoding
	// was provided.
	DefaultSpec() *api.VolumeSpec
}

var (
	nameRegex       = regexp.MustCompile(api.Name + "=([0-9A-Za-z_-]+),?")
	nodesRegex      = regexp.MustCompile(api.SpecNodes + "=([0-9A-Za-z_-]+),?")
	sizeRegex       = regexp.MustCompile(api.SpecSize + "=([0-9A-Za-z]+),?")
	scaleRegex      = regexp.MustCompile(api.SpecScale + "=([0-9]+),?")
	fsRegex         = regexp.MustCompile(api.SpecFilesystem + "=([0-9A-Za-z]+),?")
	bsRegex         = regexp.MustCompile(api.SpecBlockSize + "=([0-9]+),?")
	haRegex         = regexp.MustCompile(api.SpecHaLevel + "=([0-9]+),?")
	cosRegex        = regexp.MustCompile(api.SpecPriority + "=([A-Za-z]+),?")
	sharedRegex     = regexp.MustCompile(api.SpecShared + "=([A-Za-z]+),?")
	passphraseRegex = regexp.MustCompile(api.SpecPassphrase + "=([0-9A-Za-z_@./#&+-]+),?")
	stickyRegex     = regexp.MustCompile(api.SpecSticky + "=([A-Za-z]+),?")
	secureRegex     = regexp.MustCompile(api.SpecSecure + "=([A-Za-z]+),?")
	zonesRegex      = regexp.MustCompile(api.SpecZones + "=([A-Za-z]+),?")
	racksRegex      = regexp.MustCompile(api.SpecRacks + "=([A-Za-z]+),?")
	aggrRegex       = regexp.MustCompile(api.SpecAggregationLevel + "=([0-9]+|" +
		api.SpecAutoAggregationValue + "),?")
	compressedRegex   = regexp.MustCompile(api.SpecCompressed + "=([A-Za-z]+),?")
	snapScheduleRegex = regexp.MustCompile(api.SpecSnapshotSchedule +
		`=\-([A-Za-z0-9,:;@=]+)\-,?`)
)

type specHandler struct {
}

// NewSpecHandler returns a new SpecHandler interface
func NewSpecHandler() SpecHandler {
	return &specHandler{}
}

func (d *specHandler) cosLevel(cos string) (api.CosType, error) {
	cos = strings.ToLower(cos)
	switch cos {
	case "high", "3":
		return api.CosType_HIGH, nil
	case "medium", "2":
		return api.CosType_MEDIUM, nil
	case "low", "1", "":
		return api.CosType_LOW, nil
	}
	return api.CosType_NONE,
		fmt.Errorf("Cos must be one of %q | %q | %q", "high", "medium", "low")
}

func (d *specHandler) getVal(r *regexp.Regexp, str string) (bool, string) {
	found := r.FindString(str)
	if found == "" {
		return false, ""
	}

	submatches := r.FindStringSubmatch(str)
	if len(submatches) < 2 {
		return false, ""
	}

	val := submatches[1]

	return true, val
}

func (d *specHandler) DefaultSpec() *api.VolumeSpec {
	return &api.VolumeSpec{
		VolumeLabels: make(map[string]string),
		Format:       api.FSType_FS_TYPE_EXT4,
		HaLevel:      1,
	}
}

func (d *specHandler) SpecFromOpts(
	opts map[string]string,
) (*api.VolumeSpec, *api.VolumeLocator, *api.Source, error) {
	var source *api.Source
	var locator *api.VolumeLocator
	spec := d.DefaultSpec()

	nodeList := make([]string, 0)

	for k, v := range opts {
		switch k {
		case api.SpecNodes:
			inputNodes := strings.Split(v, ",")
			for _, node := range inputNodes {
				if len(node) != 0 {
					nodeList = append(nodeList, node)
				}
			}
			spec.ReplicaSet = &api.ReplicaSet{Nodes: nodeList}
		case api.SpecParent:
			source = &api.Source{Parent: v}
		case api.SpecEphemeral:
			spec.Ephemeral, _ = strconv.ParseBool(v)
		case api.SpecSize:
			if size, err := units.Parse(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Size = uint64(size)
			}
		case api.SpecScale:
			if scale, err := strconv.ParseUint(v, 10, 64); err == nil {
				spec.Scale = uint32(scale)
			}

		case api.SpecFilesystem:
			if value, err := api.FSTypeSimpleValueOf(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Format = value
			}
		case api.SpecBlockSize:
			if blockSize, err := units.Parse(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.BlockSize = blockSize
			}
		case api.SpecHaLevel:
			haLevel, _ := strconv.ParseInt(v, 10, 64)
			spec.HaLevel = haLevel
		case api.SpecPriority:
			cos, err := d.cosLevel(v)
			if err != nil {
				return nil, nil, nil, err
			}
			spec.Cos = cos
		case api.SpecDedupe:
			spec.Dedupe, _ = strconv.ParseBool(v)
		case api.SpecSnapshotInterval:
			snapshotInterval, _ := strconv.ParseUint(v, 10, 32)
			spec.SnapshotInterval = uint32(snapshotInterval)
		case api.SpecSnapshotSchedule:
			spec.SnapshotSchedule = v
		case api.SpecAggregationLevel:
			if v == api.SpecAutoAggregationValue {
				spec.AggregationLevel = api.AutoAggregation
			} else {
				aggregationLevel, _ := strconv.ParseUint(v, 10, 32)
				spec.AggregationLevel = uint32(aggregationLevel)
			}
		case api.SpecShared:
			if shared, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Shared = shared
			}
		case api.SpecSticky:
			if sticky, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Sticky = sticky
			}
		case api.SpecSecure:
			if secure, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Encrypted = secure
			}
		case api.SpecPassphrase:
			spec.Encrypted = true
			spec.Passphrase = v
		case api.SpecGroup:
			spec.Group = &api.Group{Id: v}
		case api.SpecGroupEnforce:
			if groupEnforced, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.GroupEnforced = groupEnforced
			}
		case api.SpecZones, api.SpecRacks:
			if locator == nil {
				locator = &api.VolumeLocator{
					VolumeLabels: make(map[string]string),
				}
			}
			locator.VolumeLabels[k] = v
		case api.SpecCompressed:
			if compressed, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Compressed = compressed
			}
		default:
			spec.VolumeLabels[k] = v
		}
	}
	return spec, locator, source, nil
}

func (d *specHandler) SpecFromString(
	str string,
) (bool, *api.VolumeSpec, *api.VolumeLocator, *api.Source, string) {
	// If we can't parse the name, the rest of the spec is invalid.
	ok, name := d.getVal(nameRegex, str)
	if !ok {
		return false, d.DefaultSpec(), nil, nil, str
	}

	opts := make(map[string]string)

	if ok, sz := d.getVal(sizeRegex, str); ok {
		opts[api.SpecSize] = sz
	}
	if ok, nodes := d.getVal(nodesRegex, str); ok {
		opts[api.SpecNodes] = nodes
	}
	if ok, scale := d.getVal(scaleRegex, str); ok {
		opts[api.SpecScale] = scale
	}
	if ok, fs := d.getVal(fsRegex, str); ok {
		opts[api.SpecFilesystem] = fs
	}
	if ok, bs := d.getVal(bsRegex, str); ok {
		opts[api.SpecBlockSize] = bs
	}
	if ok, ha := d.getVal(haRegex, str); ok {
		opts[api.SpecHaLevel] = ha
	}
	if ok, priority := d.getVal(cosRegex, str); ok {
		opts[api.SpecPriority] = priority
	}
	if ok, shared := d.getVal(sharedRegex, str); ok {
		opts[api.SpecShared] = shared
	}
	if ok, sticky := d.getVal(stickyRegex, str); ok {
		opts[api.SpecSticky] = sticky
	}
	if ok, secure := d.getVal(secureRegex, str); ok {
		opts[api.SpecSecure] = secure
	}
	if ok, passphrase := d.getVal(passphraseRegex, str); ok {
		opts[api.SpecPassphrase] = passphrase
	}
	if ok, zones := d.getVal(zonesRegex, str); ok {
		opts[api.SpecZones] = zones
	}
	if ok, racks := d.getVal(racksRegex, str); ok {
		opts[api.SpecRacks] = racks
	}
	if ok, aggregationLvl := d.getVal(aggrRegex, str); ok {
		opts[api.SpecAggregationLevel] = aggregationLvl
	}
	if ok, compressed := d.getVal(compressedRegex, str); ok {
		opts[api.SpecCompressed] = compressed
	}
	if ok, sched := d.getVal(snapScheduleRegex, str); ok {
		opts[api.SpecSnapshotSchedule] = sched
	}

	spec, locator, source, err := d.SpecFromOpts(opts)
	if err != nil {
		return false, d.DefaultSpec(), nil, nil, name
	}
	return true, spec, locator, source, name
}
<commit_msg>Snap schedule cannot have comma<commit_after>package spec

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/libopenstorage/openstorage/api"
	"github.com/libopenstorage/openstorage/pkg/units"
)

// SpecHandler provides conversion function from what gets passed in over the
// plugin API to an api.VolumeSpec object.
type SpecHandler interface {
	// SpecFromString parses options from the name.
	// If the scheduler was unable to pass in the volume spec via the API,
	// the spec can be passed in via the name in the format:
	// "key=value;key=value;name=volname"
	// source is populated if key parent=<volume_id> is specified.
	// If the spec was parsed, it returns:
	//  	(true, parsed_spec, locator, source, parsed_name)
	// If the input string didn't contain the string, it returns:
	// 	(false, DefaultSpec(), nil, nil, inputString)
	SpecFromString(inputString string) (
		bool,
		*api.VolumeSpec,
		*api.VolumeLocator,
		*api.Source,
		string,
	)

	// SpecFromOpts parses in docker options passed in the the docker run
	// command of the form --opt name=value
	// source is populated if --opt parent=<volume_id> is specified.
	// If the options are validated then it returns:
	// 	(resultant_VolumeSpec, source, locator, nil)
	// If the options have invalid values then it returns:
	//	(nil, nil, nil, error)

	SpecFromOpts(opts map[string]string) (
		*api.VolumeSpec,
		*api.VolumeLocator,
		*api.Source,
		error,
	)
	// Returns a default VolumeSpec if no docker options or string encoding
	// was provided.
	DefaultSpec() *api.VolumeSpec
}

var (
	nameRegex       = regexp.MustCompile(api.Name + "=([0-9A-Za-z_-]+),?")
	nodesRegex      = regexp.MustCompile(api.SpecNodes + "=([0-9A-Za-z_-]+),?")
	sizeRegex       = regexp.MustCompile(api.SpecSize + "=([0-9A-Za-z]+),?")
	scaleRegex      = regexp.MustCompile(api.SpecScale + "=([0-9]+),?")
	fsRegex         = regexp.MustCompile(api.SpecFilesystem + "=([0-9A-Za-z]+),?")
	bsRegex         = regexp.MustCompile(api.SpecBlockSize + "=([0-9]+),?")
	haRegex         = regexp.MustCompile(api.SpecHaLevel + "=([0-9]+),?")
	cosRegex        = regexp.MustCompile(api.SpecPriority + "=([A-Za-z]+),?")
	sharedRegex     = regexp.MustCompile(api.SpecShared + "=([A-Za-z]+),?")
	passphraseRegex = regexp.MustCompile(api.SpecPassphrase + "=([0-9A-Za-z_@./#&+-]+),?")
	stickyRegex     = regexp.MustCompile(api.SpecSticky + "=([A-Za-z]+),?")
	secureRegex     = regexp.MustCompile(api.SpecSecure + "=([A-Za-z]+),?")
	zonesRegex      = regexp.MustCompile(api.SpecZones + "=([A-Za-z]+),?")
	racksRegex      = regexp.MustCompile(api.SpecRacks + "=([A-Za-z]+),?")
	aggrRegex       = regexp.MustCompile(api.SpecAggregationLevel + "=([0-9]+|" +
		api.SpecAutoAggregationValue + "),?")
	compressedRegex   = regexp.MustCompile(api.SpecCompressed + "=([A-Za-z]+),?")
	snapScheduleRegex = regexp.MustCompile(api.SpecSnapshotSchedule +
		`=([A-Za-z0-9:;@=#]+),?`)
)

type specHandler struct {
}

// NewSpecHandler returns a new SpecHandler interface
func NewSpecHandler() SpecHandler {
	return &specHandler{}
}

func (d *specHandler) cosLevel(cos string) (api.CosType, error) {
	cos = strings.ToLower(cos)
	switch cos {
	case "high", "3":
		return api.CosType_HIGH, nil
	case "medium", "2":
		return api.CosType_MEDIUM, nil
	case "low", "1", "":
		return api.CosType_LOW, nil
	}
	return api.CosType_NONE,
		fmt.Errorf("Cos must be one of %q | %q | %q", "high", "medium", "low")
}

func (d *specHandler) getVal(r *regexp.Regexp, str string) (bool, string) {
	found := r.FindString(str)
	if found == "" {
		return false, ""
	}

	submatches := r.FindStringSubmatch(str)
	if len(submatches) < 2 {
		return false, ""
	}

	val := submatches[1]

	return true, val
}

func (d *specHandler) DefaultSpec() *api.VolumeSpec {
	return &api.VolumeSpec{
		VolumeLabels: make(map[string]string),
		Format:       api.FSType_FS_TYPE_EXT4,
		HaLevel:      1,
	}
}

func (d *specHandler) SpecFromOpts(
	opts map[string]string,
) (*api.VolumeSpec, *api.VolumeLocator, *api.Source, error) {
	var source *api.Source
	var locator *api.VolumeLocator
	spec := d.DefaultSpec()

	nodeList := make([]string, 0)

	for k, v := range opts {
		switch k {
		case api.SpecNodes:
			inputNodes := strings.Split(v, ",")
			for _, node := range inputNodes {
				if len(node) != 0 {
					nodeList = append(nodeList, node)
				}
			}
			spec.ReplicaSet = &api.ReplicaSet{Nodes: nodeList}
		case api.SpecParent:
			source = &api.Source{Parent: v}
		case api.SpecEphemeral:
			spec.Ephemeral, _ = strconv.ParseBool(v)
		case api.SpecSize:
			if size, err := units.Parse(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Size = uint64(size)
			}
		case api.SpecScale:
			if scale, err := strconv.ParseUint(v, 10, 64); err == nil {
				spec.Scale = uint32(scale)
			}

		case api.SpecFilesystem:
			if value, err := api.FSTypeSimpleValueOf(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Format = value
			}
		case api.SpecBlockSize:
			if blockSize, err := units.Parse(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.BlockSize = blockSize
			}
		case api.SpecHaLevel:
			haLevel, _ := strconv.ParseInt(v, 10, 64)
			spec.HaLevel = haLevel
		case api.SpecPriority:
			cos, err := d.cosLevel(v)
			if err != nil {
				return nil, nil, nil, err
			}
			spec.Cos = cos
		case api.SpecDedupe:
			spec.Dedupe, _ = strconv.ParseBool(v)
		case api.SpecSnapshotInterval:
			snapshotInterval, _ := strconv.ParseUint(v, 10, 32)
			spec.SnapshotInterval = uint32(snapshotInterval)
		case api.SpecSnapshotSchedule:
			spec.SnapshotSchedule = v
		case api.SpecAggregationLevel:
			if v == api.SpecAutoAggregationValue {
				spec.AggregationLevel = api.AutoAggregation
			} else {
				aggregationLevel, _ := strconv.ParseUint(v, 10, 32)
				spec.AggregationLevel = uint32(aggregationLevel)
			}
		case api.SpecShared:
			if shared, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Shared = shared
			}
		case api.SpecSticky:
			if sticky, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Sticky = sticky
			}
		case api.SpecSecure:
			if secure, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Encrypted = secure
			}
		case api.SpecPassphrase:
			spec.Encrypted = true
			spec.Passphrase = v
		case api.SpecGroup:
			spec.Group = &api.Group{Id: v}
		case api.SpecGroupEnforce:
			if groupEnforced, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.GroupEnforced = groupEnforced
			}
		case api.SpecZones, api.SpecRacks:
			if locator == nil {
				locator = &api.VolumeLocator{
					VolumeLabels: make(map[string]string),
				}
			}
			locator.VolumeLabels[k] = v
		case api.SpecCompressed:
			if compressed, err := strconv.ParseBool(v); err != nil {
				return nil, nil, nil, err
			} else {
				spec.Compressed = compressed
			}
		default:
			spec.VolumeLabels[k] = v
		}
	}
	return spec, locator, source, nil
}

func (d *specHandler) SpecFromString(
	str string,
) (bool, *api.VolumeSpec, *api.VolumeLocator, *api.Source, string) {
	// If we can't parse the name, the rest of the spec is invalid.
	ok, name := d.getVal(nameRegex, str)
	if !ok {
		return false, d.DefaultSpec(), nil, nil, str
	}

	opts := make(map[string]string)

	if ok, sz := d.getVal(sizeRegex, str); ok {
		opts[api.SpecSize] = sz
	}
	if ok, nodes := d.getVal(nodesRegex, str); ok {
		opts[api.SpecNodes] = nodes
	}
	if ok, scale := d.getVal(scaleRegex, str); ok {
		opts[api.SpecScale] = scale
	}
	if ok, fs := d.getVal(fsRegex, str); ok {
		opts[api.SpecFilesystem] = fs
	}
	if ok, bs := d.getVal(bsRegex, str); ok {
		opts[api.SpecBlockSize] = bs
	}
	if ok, ha := d.getVal(haRegex, str); ok {
		opts[api.SpecHaLevel] = ha
	}
	if ok, priority := d.getVal(cosRegex, str); ok {
		opts[api.SpecPriority] = priority
	}
	if ok, shared := d.getVal(sharedRegex, str); ok {
		opts[api.SpecShared] = shared
	}
	if ok, sticky := d.getVal(stickyRegex, str); ok {
		opts[api.SpecSticky] = sticky
	}
	if ok, secure := d.getVal(secureRegex, str); ok {
		opts[api.SpecSecure] = secure
	}
	if ok, passphrase := d.getVal(passphraseRegex, str); ok {
		opts[api.SpecPassphrase] = passphrase
	}
	if ok, zones := d.getVal(zonesRegex, str); ok {
		opts[api.SpecZones] = zones
	}
	if ok, racks := d.getVal(racksRegex, str); ok {
		opts[api.SpecRacks] = racks
	}
	if ok, aggregationLvl := d.getVal(aggrRegex, str); ok {
		opts[api.SpecAggregationLevel] = aggregationLvl
	}
	if ok, compressed := d.getVal(compressedRegex, str); ok {
		opts[api.SpecCompressed] = compressed
	}
	if ok, sched := d.getVal(snapScheduleRegex, str); ok {
		opts[api.SpecSnapshotSchedule] = strings.Replace(sched, "#", ",", -1)
	}

	spec, locator, source, err := d.SpecFromOpts(opts)
	if err != nil {
		return false, d.DefaultSpec(), nil, nil, name
	}
	return true, spec, locator, source, name
}
<|endoftext|>


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

package gcsproxy

import (
	"fmt"
	"math"
	"time"

	"github.com/googlecloudplatform/gcsfuse/lease"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/gcloud/gcs"
	"golang.org/x/net/context"
)

// A view on a particular generation of an object in GCS that allows random
// access reads and writes.
//
// Reads may involve reading from a local cache. Writes are buffered locally
// until the Sync method is called, at which time a new generation of the
// object is created.
//
// This type is not safe for concurrent access. The user must provide external
// synchronization around the methods where it is not otherwise noted.
type MutableObject struct {
	/////////////////////////
	// Constant data
	/////////////////////////

	chunkSize uint64

	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket
	leaser lease.FileLeaser
	clock  timeutil.Clock

	/////////////////////////
	// Mutable state
	/////////////////////////

	destroyed bool

	// A record for the specific generation of the object from which our local
	// state is branched.
	src gcs.Object

	// When clean, a read proxy around src. When dirty, nil.
	//
	// INVARIANT: When non-nil, readProxy.CheckInvariants() does not panic.
	readProxy lease.ReadProxy

	// When dirty, a read/write lease containing our current contents. When
	// clean, nil.
	//
	// INVARIANT: (readProxy == nil) != (readWriteLease == nil)
	readWriteLease lease.ReadWriteLease

	// The time at which a method that modifies our contents was last called, or
	// nil if never.
	//
	// INVARIANT: If dirty(), then mtime != nil
	mtime *time.Time
}

type StatResult struct {
	// The current size in bytes of the content, including any local
	// modifications that have not been Sync'd.
	Size int64

	// The time at which the contents were last updated, or the creation time of
	// the source object if they never have been.
	Mtime time.Time

	// Has the object changed out from under us in GCS? If so, Sync will fail.
	Clobbered bool
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

// Create a view on the given GCS object generation, using the supplied leaser
// to mediate temporary space usage.
//
// chunkSize is used when reading contents from GCS. See notes on NewReadProxy.
//
// REQUIRES: o != nil
func NewMutableObject(
	chunkSize uint64,
	o *gcs.Object,
	bucket gcs.Bucket,
	leaser lease.FileLeaser,
	clock timeutil.Clock) (mo *MutableObject) {
	// Set up the basic struct.
	mo = &MutableObject{
		chunkSize: chunkSize,
		bucket:    bucket,
		leaser:    leaser,
		clock:     clock,
		src:       *o,
		readProxy: NewReadProxy(o, nil, chunkSize, leaser, bucket),
	}

	return
}

// Return the generation of the object from which the current contents of this
// proxy were branched. If Sync has been successfully called, this is the
// generation most recently returned by Sync. Otherwise it is the generation
// from which the proxy was created.
func (mo *MutableObject) SourceGeneration() int64 {
	return mo.src.Generation
}

// Panic if any internal invariants are violated. Careful users can call this
// at appropriate times to help debug weirdness. Consider using
// syncutil.InvariantMutex to automate the process.
func (mo *MutableObject) CheckInvariants() {
	if mo.destroyed {
		return
	}

	// INVARIANT: When non-nil, readProxy.CheckInvariants() does not panic.
	if mo.readProxy != nil {
		mo.readProxy.CheckInvariants()
	}

	// INVARIANT: (readProxy == nil) != (readWriteLease == nil)
	if mo.readProxy == nil && mo.readWriteLease == nil {
		panic("Both readProxy and readWriteLease are nil")
	}

	if mo.readProxy != nil && mo.readWriteLease != nil {
		panic("Both readProxy and readWriteLease are non-nil")
	}

	// INVARIANT: If dirty(), then mtime != nil
	if mo.dirty() && mo.mtime == nil {
		panic("Expected non-nil mtime.")
	}
}

// Destroy any local file caches, putting the proxy into an indeterminate
// state. The MutableObject must not be used after calling this method,
// regardless of outcome.
func (mo *MutableObject) Destroy() (err error) {
	mo.destroyed = true

	// If we have no read/write lease, there's nothing to do.
	if mo.readWriteLease == nil {
		return
	}

	// Downgrade to a read lease, then revoke it.
	mo.readWriteLease.Downgrade().Revoke()
	mo.readWriteLease = nil

	return
}

// Return the current size in bytes of the content and an indication of whether
// the proxied object has changed out from under us (in which case Sync will
// fail).
//
// sr.Clobbered will be set only if needClobbered is true. Otherwise a round
// trip to GCS can be saved.
func (mo *MutableObject) Stat(
	ctx context.Context,
	needClobbered bool) (sr StatResult, err error) {
	// If we have ever been modified, our mtime field is authoritative (even if
	// we've been Sync'd, because Sync is not supposed to affect the mtime).
	// Otherwise our source object's creation time is our mtime.
	if mo.mtime != nil {
		sr.Mtime = *mo.mtime
	} else {
		sr.Mtime = mo.src.Updated
	}

	// If we have a read/write lease, it is authoritative for our size. Otherwise
	// the read proxy is authoritative.
	if mo.readWriteLease != nil {
		sr.Size, err = mo.readWriteLease.Size()
		if err != nil {
			err = fmt.Errorf("Size: %v", err)
			return
		}
	} else {
		sr.Size = mo.readProxy.Size()
	}

	// Figure out whether we were clobbered iff the user asked us to.
	if needClobbered {
		sr.Clobbered, err = mo.clobbered(ctx)
		if err != nil {
			err = fmt.Errorf("clobbered: %v", err)
			return
		}
	}

	return
}

// Make a random access read into our view of the content. May block for
// network access.
//
// Guarantees that err != nil if n < len(buf)
func (mo *MutableObject) ReadAt(
	ctx context.Context,
	buf []byte,
	offset int64) (n int, err error) {
	// Serve from the read proxy or the read/write lease.
	if mo.dirty() {
		n, err = mo.readWriteLease.ReadAt(buf, offset)
	} else {
		n, err = mo.readProxy.ReadAt(ctx, buf, offset)
	}

	return
}

// Make a random access write into our view of the content. May block for
// network access. Not guaranteed to be reflected remotely until after Sync is
// called successfully.
//
// Guarantees that err != nil if n < len(buf)
func (mo *MutableObject) WriteAt(
	ctx context.Context,
	buf []byte,
	offset int64) (n int, err error) {
	// Make sure we have a read/write lease.
	if err = mo.ensureReadWriteLease(ctx); err != nil {
		err = fmt.Errorf("ensureReadWriteLease: %v", err)
		return
	}

	newMtime := mo.clock.Now()
	mo.mtime = &newMtime
	n, err = mo.readWriteLease.WriteAt(buf, offset)

	return
}

// Truncate our view of the content to the given number of bytes, extending if
// n is greater than the current size. May block for network access. Not
// guaranteed to be reflected remotely until after Sync is called successfully.
func (mo *MutableObject) Truncate(ctx context.Context, n int64) (err error) {
	// Make sure we have a read/write lease.
	if err = mo.ensureReadWriteLease(ctx); err != nil {
		err = fmt.Errorf("ensureReadWriteLease: %v", err)
		return
	}

	// Convert to signed, which is what lease.ReadWriteLease wants.
	if n > math.MaxInt64 {
		err = fmt.Errorf("Illegal offset: %v", n)
		return
	}

	newMtime := mo.clock.Now()
	mo.mtime = &newMtime
	err = mo.readWriteLease.Truncate(int64(n))

	return
}

// If the proxy is dirty due to having been modified, save its current contents
// to GCS, creating a generation with exactly those contents. Do so with a
// precondition such that the creation will fail if the source generation is
// not current. In that case, return an error of type *gcs.PreconditionError.
// If the proxy is not dirty, simply return nil.
//
// After this method successfully returns, SourceGeneration returns the
// generation at which the contents are current.
func (mo *MutableObject) Sync(ctx context.Context) (err error) {
	// Do we need to do anything?
	if !mo.dirty() {
		return
	}

	// Seek the read/write lease to the start so that it can be used as a reader
	// for its full contents below.
	_, err = mo.readWriteLease.Seek(0, 0)
	if err != nil {
		err = fmt.Errorf("Seek: %v", err)
		return
	}

	// Write a new generation of the object with the appropriate contents, using
	// an appropriate precondition.
	req := &gcs.CreateObjectRequest{
		Name:                   mo.src.Name,
		Contents:               mo.readWriteLease,
		GenerationPrecondition: &mo.src.Generation,
	}

	o, err := mo.bucket.CreateObject(ctx, req)

	// Special case: handle precondition errors.
	if _, ok := err.(*gcs.PreconditionError); ok {
		err = &gcs.PreconditionError{
			Err: fmt.Errorf("CreateObject: %v", err),
		}

		return
	}

	// Propagate other errors more directly.
	if err != nil {
		err = fmt.Errorf("CreateObject: %v", err)
		return
	}

	mo.src = *o

	// Downgrade the read/write lease to a read lease, and use that to prime the
	// new read proxy.
	rl := mo.readWriteLease.Downgrade()
	mo.readWriteLease = nil
	mo.readProxy = NewReadProxy(o, rl, mo.chunkSize, mo.leaser, mo.bucket)

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func (mo *MutableObject) dirty() bool {
	return mo.readWriteLease != nil
}

// Ensure that mo.readWriteLease is non-nil with an authoritative view of mo's
// contents.
func (mo *MutableObject) ensureReadWriteLease(ctx context.Context) (err error) {
	// Is there anything to do?
	if mo.readWriteLease != nil {
		return
	}

	// Set up the read/write lease.
	rwl, err := mo.readProxy.Upgrade(ctx)
	if err != nil {
		err = fmt.Errorf("readProxy.Upgrade: %v", err)
		return
	}

	mo.readWriteLease = rwl
	mo.readProxy = nil

	return
}

func (mo *MutableObject) clobbered(
	ctx context.Context) (clobbered bool, err error) {
	// Stat the object in GCS.
	req := &gcs.StatObjectRequest{Name: mo.src.Name}
	o, err := mo.bucket.StatObject(ctx, req)

	// Special case: "not found" means we have been clobbered.
	if _, ok := err.(*gcs.NotFoundError); ok {
		err = nil
		clobbered = true
		return
	}

	// Propagate other errors.
	if err != nil {
		err = fmt.Errorf("StatObject: %v", err)
		return
	}

	// We are clobbered iff the generation doesn't match our source generation.
	clobbered = (o.Generation != mo.src.Generation)

	return
}
<commit_msg>Deleted mutable_object.go.<commit_after><|endoftext|>


<commit_before>package kit

// InterfaceTemplate
var InterfaceTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

const ServiceName = "{{ToLower $title}}"

{{AsComment $schema.Description}} type {{$title}}Service interface { {{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}} {{$funcKey}}(ctx context.Context, req *{{Argumentize $funcValue.Properties.incoming}}) (res *{{Argumentize $funcValue.Properties.outgoing}}, err error)
{{end}}
}
`

// Service Template
var ServiceTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

type {{ToLower $title}} struct{}

func New{{$title}}() {{$title}}Service {
	return &{{ToLower $title}}{}
}

{{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}}func ({{Pointerize $title}} *{{ToLower $title}}) {{$funcKey}}(ctx context.Context, req *{{Argumentize $funcValue.Properties.incoming}}) (*{{Argumentize $funcValue.Properties.outgoing}}, error) {
	return nil, nil
}{{end}}`

// TransportHTTPServerTemplate
var TransportHTTPServerTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

import (
	"golang.org/x/net/context"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/tracing/zipkin"
	httptransport "github.com/go-kit/kit/transport/http"
)

// RegisterHandlers registers handlers of {{$title}}Service to the
// http.DefaultServeMux
func RegisterHandlers(ctx context.Context, svc {{$title}}Service, serverOpts *kitworker.ServerOption, logger log.Logger) { {{range $funcKey, $funcValue := $schema.Functions}}
	http.Handle(New{{$funcKey}}Handler(ctx, svc, serverOpts, logger)){{end}}
}

{{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}}func New{{$funcKey}}Handler(ctx context.Context, svc {{$title}}Service, opts *kitworker.ServerOption, logger log.Logger) (string, *httptransport.Server) {
	return newServer(ctx, svc, opts, logger, semiotics[EndpointName{{$funcKey}}])
}
{{end}}

func newServer(ctx context.Context, svc {{$title}}Service, opts *kitworker.ServerOption, logger log.Logger, s semiotic) (string, *httptransport.Server) {
	transportLogger := log.NewContext(logger).With("transport", "HTTP/JSON")
	middlewares, serverOpts := opts.Configure(ServiceName, s.Name, transportLogger)

	endpoint := s.ServerEndpointFunc(svc)

	for _, middleware := range middlewares {
		endpoint = middleware(endpoint)
	}

	handler := httptransport.NewServer(
		ctx,
		endpoint,
		s.DecodeRequestFunc,
		s.EncodeResponseFunc,
		serverOpts...,
	)

	return s.Route, handler
}
`

// TransportHTTPClientTemplate
var TransportHTTPClientTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

import (
	"io"
	"net/url"
	"strings"

	"github.com/go-kit/kit/circuitbreaker"
	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/loadbalancer"
	"github.com/go-kit/kit/loadbalancer/static"
	"github.com/go-kit/kit/log"
	kitratelimit "github.com/go-kit/kit/ratelimit"
	"github.com/go-kit/kit/tracing/zipkin"
	httptransport "github.com/go-kit/kit/transport/http"
	"github.com/juju/ratelimit"
	jujuratelimit "github.com/juju/ratelimit"
	"github.com/sony/gobreaker"
	"golang.org/x/net/context"
)

// {{$title}}Client holds remote endpoint functions
// Satisfies {{$title}}Service interface
type {{$title}}Client struct {
	{{range $funcKey, $funcValue := $schema.Functions}}// {{$funcKey}}LoadBalancer provides remote call to {{ToLower $funcKey}} endpoints
		{{$funcKey}}LoadBalancer loadbalancer.LoadBalancer

	{{end}}
}

// New{{$title}}Client creates a new client for {{$title}}Service
func  New{{$title}}Client(clientOpts *kitworker.ClientOption, logger log.Logger) *{{$title}}Client {
	if clientOpts.LoadBalancerCreator == nil {
		panic("LoadBalancerCreator must be set")
	}

	return &{{$title}}Client{ {{range $funcKey, $funcValue := $schema.Functions}}
		{{$funcKey}}LoadBalancer : createClientLoadBalancer(semiotics[EndpointName{{$funcKey}}], clientOpts, logger),{{end}}
	}
}

{{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}}func ({{Pointerize $title}} *{{$title}}Client) {{$funcKey}}(ctx context.Context, req *{{Argumentize $funcValue.Properties.incoming}}) (*{{Argumentize $funcValue.Properties.outgoing}}, error) {
	endpoint, err := {{Pointerize $title}}.{{$funcKey}}LoadBalancer.Endpoint()
	if err != nil {
		return nil, err
	}

	res, err := endpoint(ctx, req)
	if err != nil {
		return nil, err
	}

	return res.(*{{Argumentize $funcValue.Properties.outgoing}}), nil
}
{{end}}

func createClientLoadBalancer(
	s semiotic,
	clientOpts *kitworker.ClientOption,
	logger log.Logger,
) loadbalancer.LoadBalancer {
	middlewares, transportOpts := clientOpts.Configure(ServiceName, s.Name)

	loadbalancerFactory := func(instance string) (endpoint.Endpoint, io.Closer, error) {

		e := httptransport.NewClient(
			s.Method,
			kitworker.CreateProxyURL(instance, s.Route),
			s.EncodeRequestFunc,
			s.DecodeResponseFunc,
			transportOpts...,
		).Endpoint()

		for _, middleware := range middlewares {
			e = middleware(e)
		}

		return e, nil, nil
	}

	return clientOpts.LoadBalancerCreator(loadbalancerFactory)
}
`

// TransportHTTPSemioticsTemplate
var TransportHTTPSemioticsTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

import (
    "io"
    "net/url"
    "strings"

    "github.com/cihangir/gene/example/tinder/models"
    "github.com/go-kit/kit/circuitbreaker"
    "github.com/go-kit/kit/endpoint"
    "github.com/go-kit/kit/loadbalancer"
    "github.com/go-kit/kit/loadbalancer/static"
    "github.com/go-kit/kit/log"
    kitratelimit "github.com/go-kit/kit/ratelimit"
    "github.com/go-kit/kit/tracing/zipkin"
    httptransport "github.com/go-kit/kit/transport/http"
    "github.com/juju/ratelimit"
    jujuratelimit "github.com/juju/ratelimit"
    "github.com/sony/gobreaker"
    "golang.org/x/net/context"
)

const (
{{range $funcKey, $funcValue := $schema.Functions}}
 	EndpointName{{$funcKey}} = "{{ToLower $funcKey}}"{{end}}
)

type semiotic struct {
	Name               string
	Method             string
	Route              string
	ServerEndpointFunc func(svc {{$title}}Service) endpoint.Endpoint
	DecodeRequestFunc  httptransport.DecodeRequestFunc
	EncodeRequestFunc  httptransport.EncodeRequestFunc
	EncodeResponseFunc httptransport.EncodeResponseFunc
	DecodeResponseFunc httptransport.DecodeResponseFunc
}

var semiotics = map[string]semiotic{
{{range $funcKey, $funcValue := $schema.Functions}}
    EndpointName{{$funcKey}}: semiotic{
    	Name:               EndpointName{{$funcKey}},
    	Method:             "POST",
    	ServerEndpointFunc: make{{$funcKey}}Endpoint,
		Route:              "/"+EndpointName{{$funcKey}},
		DecodeRequestFunc:  decode{{$funcKey}}Request,
		EncodeRequestFunc:  encodeRequest,
		EncodeResponseFunc: encodeResponse,
		DecodeResponseFunc: decode{{$funcKey}}Response,
    },
    {{end}}
}

// Decode Request functions

{{range $funcKey, $funcValue := $schema.Functions}}
func decode{{$funcKey}}Request(r *http.Request) (interface{}, error) {
	var req {{Argumentize $funcValue.Properties.incoming}}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return nil, err
	}
	return &req, nil
}
{{end}}

// Decode Response functions

{{range $funcKey, $funcValue := $schema.Functions}}
func decode{{$funcKey}}Response(r *http.Response) (interface{}, error) {
	var res {{Argumentize $funcValue.Properties.outgoing}}
	if err := json.NewDecoder(r.Body).Decode(&res); err != nil {
		return nil, err
	}
	return &res, nil
}
{{end}}

// Encode request function

func encodeRequest(r *http.Request, request interface{}) error {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(request); err != nil {
		return err
	}
	r.Body = ioutil.NopCloser(&buf)
	return nil
}

// Encode response function

func encodeResponse(rw http.ResponseWriter, response interface{}) error {
	return json.NewEncoder(rw).Encode(response)
}

// Endpoint functions

{{range $funcKey, $funcValue := $schema.Functions}}
func make{{$funcKey}}Endpoint(svc {{$title}}Service) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (interface{}, error) {
		req := request.(*{{Argumentize $funcValue.Properties.incoming}})
		return svc.{{$funcKey}}(ctx, req)
	}
}
{{end}}
`
<commit_msg>generators/kit: fix templates<commit_after>package kit

// InterfaceTemplate
var InterfaceTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

import (
	"golang.org/x/net/context"
)

const ServiceName = "{{ToLower $title}}"

{{AsComment $schema.Description}} type {{$title}}Service interface { {{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}} {{$funcKey}}(ctx context.Context, req *{{Argumentize $funcValue.Properties.incoming}}) (res *{{Argumentize $funcValue.Properties.outgoing}}, err error)
{{end}}
}
`

// Service Template
var ServiceTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

type {{ToLower $title}} struct{}

func New{{$title}}() {{$title}}Service {
	return &{{ToLower $title}}{}
}

{{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}}func ({{Pointerize $title}} *{{ToLower $title}}) {{$funcKey}}(ctx context.Context, req *{{Argumentize $funcValue.Properties.incoming}}) (*{{Argumentize $funcValue.Properties.outgoing}}, error) {
	return nil, nil
}{{end}}`

// TransportHTTPServerTemplate
var TransportHTTPServerTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

import (
	"golang.org/x/net/context"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/tracing/zipkin"
	httptransport "github.com/go-kit/kit/transport/http"
)

// RegisterHandlers registers handlers of {{$title}}Service to the
// http.DefaultServeMux
func RegisterHandlers(ctx context.Context, svc {{$title}}Service, serverOpts *kitworker.ServerOption, logger log.Logger) { {{range $funcKey, $funcValue := $schema.Functions}}
	http.Handle(New{{$funcKey}}Handler(ctx, svc, serverOpts, logger)){{end}}
}

{{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}}func New{{$funcKey}}Handler(ctx context.Context, svc {{$title}}Service, opts *kitworker.ServerOption, logger log.Logger) (string, *httptransport.Server) {
	return newServer(ctx, svc, opts, logger, semiotics[EndpointName{{$funcKey}}])
}
{{end}}

func newServer(ctx context.Context, svc {{$title}}Service, opts *kitworker.ServerOption, logger log.Logger, s semiotic) (string, *httptransport.Server) {
	transportLogger := log.NewContext(logger).With("transport", "HTTP/JSON")
	middlewares, serverOpts := opts.Configure(ServiceName, s.Name, transportLogger)

	endpoint := s.ServerEndpointFunc(svc)

	for _, middleware := range middlewares {
		endpoint = middleware(endpoint)
	}

	handler := httptransport.NewServer(
		ctx,
		endpoint,
		s.DecodeRequestFunc,
		s.EncodeResponseFunc,
		serverOpts...,
	)

	return s.Route, handler
}
`

// TransportHTTPClientTemplate
var TransportHTTPClientTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

import (
	"io"
	"net/url"
	"strings"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/sd/lb"
	httptransport "github.com/go-kit/kit/transport/http"
	"golang.org/x/net/context"
)

// {{$title}}Client holds remote endpoint functions
// Satisfies {{$title}}Service interface
type {{$title}}Client struct {
	{{range $funcKey, $funcValue := $schema.Functions}}// {{$funcKey}}LoadBalancer provides remote call to {{ToLower $funcKey}} endpoints
		{{$funcKey}}LoadBalancer lb.Balancer

	{{end}}
}

// New{{$title}}Client creates a new client for {{$title}}Service
func  New{{$title}}Client(clientOpts *kitworker.ClientOption, logger log.Logger) *{{$title}}Client {
	if clientOpts.LoadBalancerCreator == nil {
		panic("LoadBalancerCreator must be set")
	}

	return &{{$title}}Client{ {{range $funcKey, $funcValue := $schema.Functions}}
		{{$funcKey}}LoadBalancer : createClientLoadBalancer(semiotics[EndpointName{{$funcKey}}], clientOpts, logger),{{end}}
	}
}

{{range $funcKey, $funcValue := $schema.Functions}}
{{AsComment $funcValue.Description}}func ({{Pointerize $title}} *{{$title}}Client) {{$funcKey}}(ctx context.Context, req *{{Argumentize $funcValue.Properties.incoming}}) (*{{Argumentize $funcValue.Properties.outgoing}}, error) {
	endpoint, err := {{Pointerize $title}}.{{$funcKey}}LoadBalancer.Endpoint()
	if err != nil {
		return nil, err
	}

	res, err := endpoint(ctx, req)
	if err != nil {
		return nil, err
	}

	return res.(*{{Argumentize $funcValue.Properties.outgoing}}), nil
}
{{end}}

func createClientLoadBalancer(
	s semiotic,
	clientOpts *kitworker.ClientOption,
	logger log.Logger,
) lb.Balancer {
	middlewares, transportOpts := clientOpts.Configure(ServiceName, s.Name)

	loadbalancerFactory := func(instance string) (endpoint.Endpoint, io.Closer, error) {

		e := httptransport.NewClient(
			s.Method,
			kitworker.CreateProxyURL(instance, s.Route),
			s.EncodeRequestFunc,
			s.DecodeResponseFunc,
			transportOpts...,
		).Endpoint()

		for _, middleware := range middlewares {
			e = middleware(e)
		}

		return e, nil, nil
	}

	return clientOpts.LoadBalancerCreator(loadbalancerFactory)
}
`

// TransportHTTPSemioticsTemplate
var TransportHTTPSemioticsTemplate = `
{{$schema := .Schema}}
{{$title := ToUpperFirst .Schema.Title}}

package {{ToLower $title}}

import (
    "io"
    "net/url"
    "strings"

	"github.com/go-kit/kit/endpoint"
	httptransport "github.com/go-kit/kit/transport/http"
	"golang.org/x/net/context"
)

const (
{{range $funcKey, $funcValue := $schema.Functions}}
 	EndpointName{{$funcKey}} = "{{ToLower $funcKey}}"{{end}}
)

type semiotic struct {
	Name               string
	Method             string
	Route              string
	ServerEndpointFunc func(svc {{$title}}Service) endpoint.Endpoint
	DecodeRequestFunc  httptransport.DecodeRequestFunc
	EncodeRequestFunc  httptransport.EncodeRequestFunc
	EncodeResponseFunc httptransport.EncodeResponseFunc
	DecodeResponseFunc httptransport.DecodeResponseFunc
}

var semiotics = map[string]semiotic{
{{range $funcKey, $funcValue := $schema.Functions}}
    EndpointName{{$funcKey}}: semiotic{
    	Name:               EndpointName{{$funcKey}},
    	Method:             "POST",
    	ServerEndpointFunc: make{{$funcKey}}Endpoint,
		Route:              "/"+EndpointName{{$funcKey}},
		DecodeRequestFunc:  decode{{$funcKey}}Request,
		EncodeRequestFunc:  encodeRequest,
		EncodeResponseFunc: encodeResponse,
		DecodeResponseFunc: decode{{$funcKey}}Response,
    },
    {{end}}
}

// Decode Request functions

{{range $funcKey, $funcValue := $schema.Functions}}
func decode{{$funcKey}}Request(ctx context.Context, r *http.Request) (interface{}, error) {
	var req {{Argumentize $funcValue.Properties.incoming}}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return nil, err
	}
	return &req, nil
}
{{end}}

// Decode Response functions

{{range $funcKey, $funcValue := $schema.Functions}}
func decode{{$funcKey}}Response(ctx context.Context, r *http.Response) (interface{}, error) {
	var res {{Argumentize $funcValue.Properties.outgoing}}
	if err := json.NewDecoder(r.Body).Decode(&res); err != nil {
		return nil, err
	}
	return &res, nil
}
{{end}}

// Encode request function

func encodeRequest(ctx context.Context, r *http.Request, request interface{}) error {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(request); err != nil {
		return err
	}
	r.Body = ioutil.NopCloser(&buf)
	return nil
}

// Encode response function

func encodeResponse(ctx context.Context, rw http.ResponseWriter, response interface{}) error {
	return json.NewEncoder(rw).Encode(response)
}

// Endpoint functions

{{range $funcKey, $funcValue := $schema.Functions}}
func make{{$funcKey}}Endpoint(svc {{$title}}Service) endpoint.Endpoint {
	return func(ctx context.Context, request interface{}) (interface{}, error) {
		req := request.(*{{Argumentize $funcValue.Properties.incoming}})
		return svc.{{$funcKey}}(ctx, req)
	}
}
{{end}}
`
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

var r *mux.Router

const ContactsBaseURL string = "http://localhost:3000/contacts/"

func init() {
	r = mux.NewRouter()
	r.HandleFunc("/contacts", getContactsHandler).Methods("GET")
	r.HandleFunc("/contacts", postContactsHandler).Methods("POST")
	r.HandleFunc("/contacts/{slug}", getContactHandler).Methods("GET")
	r.HandleFunc("/contacts/{slug}", patchContactHandler).Methods("PATCH")
	r.HandleFunc("/contacts/{slug}", deleteContactHandler).Methods("DELETE")
}

// getContactsHandler returns a json response containing all
// the contacts.
//
// URL: GET /contacts
//
// For example, If there were only two contacts in total,
// GET /contacts and
// would yield the following response.
//
// Response:
// [
//  {
//    "id": "53a14760e3bdea4286000003",
//    "company": "Encom Inc.",
//    "person": "Sam Flynn",
//    "email": "samflynn@encom.com",
//    "phone": "103-345-456",
//    "skypeid": "sam_flynn",
//    "country": "USA"
//  },
//  {
//    "id": "53a14760e3bdea4286000004",
//    "company": "Encom Inc.",
//    "person": "Kevin Flynn",
//    "email": "kevinflynn@encom.com",
//    "phone": "234-877-988",
//    "skypeid": "kevin_flynn",
//    "country": "USA"
//  }
// ]
func getContactsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	c, err := GetAllContacts()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// postContactsHandler creates a new contact in the database.
//
// URL: POST /contacts
//
// Request:
// {
//   "company": "Encom Inc.",
//   "person": "Sam Flynn",
//   "email": "samflynn@encom.com",
//   "phone": "103-345-456",
//   "skypeid": "sam_flynn",
//   "country": "USA"
// }
//
// Response:
// HTTP/1.1 201 Created
// Location: http://localhost:3000/contacts/sam-flynn
func postContactsHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c contact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	n, err := NewContact(c.Company, c.Person, c.Email, c.Phone, c.SkypeId, c.Country)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	url := ContactsBaseURL + n.Slug
	w.Header().Set("Location", url)
	w.WriteHeader(http.StatusCreated)
}

// getContactHandler returns json data pertaining to a specific contact.
//
// URL: GET /contacts/{slug}
//
// For example,
// GET /contacts/flynn
//
// Response:
// {
//   "id": "53a15a07e3bdea53d0000002",
//   "company": "Encom Inc.",
//   "person": "Flynn",
//   "slug": "flynn"
//   "email": "flynn@encom.com",
//   "country": "USA"
// }
func getContactHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	slug := vars["slug"]
	c, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// patchContactHandler patches a contact in the database.
// URL: PATCH /contacts/{slug}
// Request:
// {
//   "country": "India"
// }
//
// Response:
// HTTP/1.1 200 OK
func patchContactHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c incomingContact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	vars := mux.Vars(r)
	slug := vars["slug"]
	fc, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = fc.copyIncomingFields(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = fc.Update()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// deleteContactHandler deletes a contact from the database.
// URL: DELETE /contacts/{slug}
//
// Response:
// HTTP/1.1 204 No Content
func deleteContactHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	slug := vars["slug"]
	c, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = c.Delete()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
<commit_msg>Declare mux router outside init<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)

var r *mux.Router = mux.NewRouter()

const ContactsBaseURL string = "http://localhost:3000/contacts/"

func init() {
	r.HandleFunc("/contacts", getContactsHandler).Methods("GET")
	r.HandleFunc("/contacts", postContactsHandler).Methods("POST")
	r.HandleFunc("/contacts/{slug}", getContactHandler).Methods("GET")
	r.HandleFunc("/contacts/{slug}", patchContactHandler).Methods("PATCH")
	r.HandleFunc("/contacts/{slug}", deleteContactHandler).Methods("DELETE")
}

// getContactsHandler returns a json response containing all
// the contacts.
//
// URL: GET /contacts
//
// For example, If there were only two contacts in total,
// GET /contacts and
// would yield the following response.
//
// Response:
// [
//  {
//    "id": "53a14760e3bdea4286000003",
//    "company": "Encom Inc.",
//    "person": "Sam Flynn",
//    "email": "samflynn@encom.com",
//    "phone": "103-345-456",
//    "skypeid": "sam_flynn",
//    "country": "USA"
//  },
//  {
//    "id": "53a14760e3bdea4286000004",
//    "company": "Encom Inc.",
//    "person": "Kevin Flynn",
//    "email": "kevinflynn@encom.com",
//    "phone": "234-877-988",
//    "skypeid": "kevin_flynn",
//    "country": "USA"
//  }
// ]
func getContactsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	c, err := GetAllContacts()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// postContactsHandler creates a new contact in the database.
//
// URL: POST /contacts
//
// Request:
// {
//   "company": "Encom Inc.",
//   "person": "Sam Flynn",
//   "email": "samflynn@encom.com",
//   "phone": "103-345-456",
//   "skypeid": "sam_flynn",
//   "country": "USA"
// }
//
// Response:
// HTTP/1.1 201 Created
// Location: http://localhost:3000/contacts/sam-flynn
func postContactsHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c contact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	n, err := NewContact(c.Company, c.Person, c.Email, c.Phone, c.SkypeId, c.Country)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	url := ContactsBaseURL + n.Slug
	w.Header().Set("Location", url)
	w.WriteHeader(http.StatusCreated)
}

// getContactHandler returns json data pertaining to a specific contact.
//
// URL: GET /contacts/{slug}
//
// For example,
// GET /contacts/flynn
//
// Response:
// {
//   "id": "53a15a07e3bdea53d0000002",
//   "company": "Encom Inc.",
//   "person": "Flynn",
//   "slug": "flynn"
//   "email": "flynn@encom.com",
//   "country": "USA"
// }
func getContactHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	slug := vars["slug"]
	c, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	enc := json.NewEncoder(w)
	if err = enc.Encode(c); err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// patchContactHandler patches a contact in the database.
// URL: PATCH /contacts/{slug}
// Request:
// {
//   "country": "India"
// }
//
// Response:
// HTTP/1.1 200 OK
func patchContactHandler(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var c incomingContact
	err := decoder.Decode(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	vars := mux.Vars(r)
	slug := vars["slug"]
	fc, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = fc.copyIncomingFields(&c)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = fc.Update()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

// deleteContactHandler deletes a contact from the database.
// URL: DELETE /contacts/{slug}
//
// Response:
// HTTP/1.1 204 No Content
func deleteContactHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	slug := vars["slug"]
	c, err := GetContactBySlug(slug)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = c.Delete()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
<|endoftext|>


<commit_before>package testlog

import (
	"flag"
	"log"
	"os"

	"github.com/lucas-clemente/quic-go/internal/utils"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var (
	logFileName string // the log file set in the ginkgo flags
	logFile     *os.File
)

// read the logfile command line flag
// to set call ginkgo -- -logfile=log.txt
func init() {
	flag.StringVar(&logFileName, "logfile", "", "log file")
}

var _ = BeforeEach(func() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	if len(logFileName) > 0 {
		var err error
		logFile, err = os.Create("./log.txt")
		Expect(err).ToNot(HaveOccurred())
		log.SetOutput(logFile)
		utils.SetLogLevel(utils.LogLevelDebug)
	}
})

var _ = AfterEach(func() {
	if len(logFileName) > 0 {
		_ = logFile.Close()
	}
})
<commit_msg>actually use the log file set as a flag in the integration tests<commit_after>package testlog

import (
	"flag"
	"log"
	"os"

	"github.com/lucas-clemente/quic-go/internal/utils"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var (
	logFileName string // the log file set in the ginkgo flags
	logFile     *os.File
)

// read the logfile command line flag
// to set call ginkgo -- -logfile=log.txt
func init() {
	flag.StringVar(&logFileName, "logfile", "", "log file")
}

var _ = BeforeEach(func() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	if len(logFileName) > 0 {
		var err error
		logFile, err = os.Create(logFileName)
		Expect(err).ToNot(HaveOccurred())
		log.SetOutput(logFile)
		utils.SetLogLevel(utils.LogLevelDebug)
	}
})

var _ = AfterEach(func() {
	if len(logFileName) > 0 {
		_ = logFile.Close()
	}
})
<|endoftext|>


<commit_before>package beegopro

import (
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/pelletier/go-toml"
	"github.com/spf13/viper"

	"github.com/beego/bee/internal/pkg/git"
	"github.com/beego/bee/internal/pkg/system"
	beeLogger "github.com/beego/bee/logger"
	"github.com/beego/bee/utils"
)

const MDateFormat = "20060102_150405"

var DefaultBeegoPro = &Container{
	BeegoProFile:  system.CurrentDir + "/beegopro.toml",
	TimestampFile: system.CurrentDir + "/.beegopro.timestamp",
	GoModFile:     system.CurrentDir + "/go.mod",
	UserOption: UserOption{
		Debug:         false,
		ContextDebug:  false,
		Dsn:           "",
		Driver:        "mysql",
		ProType:       "default",
		ApiPrefix:     "/api",
		EnableModule:  nil,
		Models:        make(map[string]TextModel),
		GitRemotePath: "https://github.com/beego/beego-pro.git",
		Branch:        "master",
		GitLocalPath:  system.BeegoHome + "/beego-pro",
		EnableFormat:  true,
		SourceGen:     "text",
		EnableGitPull: true,
		Path: map[string]string{
			"beego": ".",
		},
		EnableGomod:    true,
		RefreshGitTime: 24 * 3600,
		Extend:         nil,
	},
	GenerateTime:     time.Now().Format(MDateFormat),
	GenerateTimeUnix: time.Now().Unix(),
	TmplOption:       TmplOption{},
	CurPath:          system.CurrentDir,
	EnableModules:    make(map[string]interface{}), // get the user configuration, get the enable module result
	FunctionOnce:     make(map[string]sync.Once),   // get the tmpl configuration, get the function once result
}

func (c *Container) Run() {
	// init git refresh cache time
	c.initTimestamp()
	c.initUserOption()
	c.initTemplateOption()
	c.initParser()
	c.initRender()
	c.flushTimestamp()
}

func (c *Container) InitToml() {
	if exist := utils.IsExist(c.BeegoProFile); exist {
		beeLogger.Log.Fatalf("file beegopro.toml already exists")
	}
	sourceFile := c.UserOption.GitLocalPath + "/beegopro.toml"
	input, err := ioutil.ReadFile(sourceFile)
	if err != nil {
		beeLogger.Log.Fatalf("read beegopro.toml file err, %s", err.Error())
		return
	}
	err = ioutil.WriteFile(c.BeegoProFile, input, 0644)
	if err != nil {
		beeLogger.Log.Fatalf("create beegopro.toml file err, %s", err.Error())
		return
	}
	beeLogger.Log.Success("Successfully created file beegopro.toml")
}

func (c *Container) initUserOption() {
	if !utils.IsExist(c.BeegoProFile) {
		beeLogger.Log.Fatalf("beego pro config is not exist, beego json path: %s", c.BeegoProFile)
		return
	}
	viper.SetConfigFile(c.BeegoProFile)
	err := viper.ReadInConfig()
	if err != nil {
		beeLogger.Log.Fatalf("read beego pro config content, err: %s", err.Error())
		return
	}

	err = viper.Unmarshal(&c.UserOption)
	if err != nil {
		beeLogger.Log.Fatalf("beego pro config unmarshal error, err: %s", err.Error())
		return
	}
	if c.UserOption.Debug {
		viper.Debug()
	}

	if c.UserOption.EnableGomod {
		if !utils.IsExist(c.GoModFile) {
			beeLogger.Log.Fatalf("go mod not exist, please create go mod file")
			return
		}
	}

	for _, value := range c.UserOption.EnableModule {
		c.EnableModules[value] = struct{}{}
	}

	if len(c.EnableModules) == 0 {
		c.EnableModules["*"] = struct{}{}
	}

	if c.UserOption.Debug {
		fmt.Println("c.modules", c.EnableModules)
	}

}

func (c *Container) initTemplateOption() {
	if c.UserOption.EnableGitPull && (c.GenerateTimeUnix-c.Timestamp.GitCacheLastRefresh > c.UserOption.RefreshGitTime) {
		err := git.CloneORPullRepo(c.UserOption.GitRemotePath, c.UserOption.GitLocalPath)
		if err != nil {
			beeLogger.Log.Fatalf("beego pro git clone or pull repo error, err: %s", err)
			return
		}
		c.Timestamp.GitCacheLastRefresh = c.GenerateTimeUnix
	}

	tree, err := toml.LoadFile(c.UserOption.GitLocalPath + "/" + c.UserOption.ProType + "/bee.toml")

	if err != nil {
		beeLogger.Log.Fatalf("beego tmpl exec error, err: %s", err)
		return
	}
	err = tree.Unmarshal(&c.TmplOption)
	if err != nil {
		beeLogger.Log.Fatalf("beego tmpl parse error, err: %s", err)
		return
	}

	if c.UserOption.Debug {
		spew.Dump("tmpl", c.TmplOption)
	}

	for _, value := range c.TmplOption.Descriptor {
		if value.Once {
			c.FunctionOnce[value.SrcName] = sync.Once{}
		}
	}
}

func (c *Container) initParser() {
	driver, flag := ParserDriver[c.UserOption.SourceGen]
	if !flag {
		beeLogger.Log.Fatalf("parse driver not exit, source gen %s", c.UserOption.SourceGen)
	}
	driver.RegisterOption(c.UserOption, c.TmplOption)
	c.Parser = driver
}

func (c *Container) initRender() {
	for _, desc := range c.TmplOption.Descriptor {
		_, allFlag := c.EnableModules["*"]
		_, moduleFlag := c.EnableModules[desc.Module]
		if !allFlag && !moduleFlag {
			continue
		}

		models := c.Parser.GetRenderInfos(desc)
		// model table name, model table schema
		for _, m := range models {
			// some render exec once
			syncOnce, flag := c.FunctionOnce[desc.SrcName]
			if flag {
				syncOnce.Do(func() {
					c.renderModel(m)
				})
				continue
			}
			c.renderModel(m)
		}
	}
}

func (c *Container) renderModel(m RenderInfo) {
	// todo optimize
	m.GenerateTime = c.GenerateTime
	render := NewRender(m)
	render.Exec(m.Descriptor.SrcName)
	if render.Descriptor.IsExistScript() {
		err := render.Descriptor.ExecScript(c.CurPath)
		if err != nil {
			beeLogger.Log.Fatalf("beego exec shell error, err: %s", err)
		}
	}
}

func (c *Container) initTimestamp() {
	if utils.IsExist(c.TimestampFile) {
		tree, err := toml.LoadFile(c.TimestampFile)
		if err != nil {
			beeLogger.Log.Fatalf("beego timestamp tmpl exec error, err: %s", err)
			return
		}
		err = tree.Unmarshal(&c.Timestamp)
		if err != nil {
			beeLogger.Log.Fatalf("beego timestamp tmpl parse error, err: %s", err)
			return
		}
	}
	c.Timestamp.Generate = c.GenerateTimeUnix
}

func (c *Container) flushTimestamp() {
	tomlByte, err := toml.Marshal(c.Timestamp)
	if err != nil {
		beeLogger.Log.Fatalf("marshal timestamp tmpl parse error, err: %s", err)
	}
	err = ioutil.WriteFile(c.TimestampFile, tomlByte, 0644)
	if err != nil {
		beeLogger.Log.Fatalf("flush timestamp tmpl parse error, err: %s", err)
	}
}
<commit_msg>get template from git when run 'bee pro toml' if template dose not exit<commit_after>package beegopro

import (
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/pelletier/go-toml"
	"github.com/spf13/viper"

	"github.com/beego/bee/internal/pkg/git"
	"github.com/beego/bee/internal/pkg/system"
	beeLogger "github.com/beego/bee/logger"
	"github.com/beego/bee/utils"
)

const MDateFormat = "20060102_150405"

var DefaultBeegoPro = &Container{
	BeegoProFile:  system.CurrentDir + "/beegopro.toml",
	TimestampFile: system.CurrentDir + "/.beegopro.timestamp",
	GoModFile:     system.CurrentDir + "/go.mod",
	UserOption: UserOption{
		Debug:         false,
		ContextDebug:  false,
		Dsn:           "",
		Driver:        "mysql",
		ProType:       "default",
		ApiPrefix:     "/api",
		EnableModule:  nil,
		Models:        make(map[string]TextModel),
		GitRemotePath: "https://github.com/beego/beego-pro.git",
		Branch:        "master",
		GitLocalPath:  system.BeegoHome + "/beego-pro",
		EnableFormat:  true,
		SourceGen:     "text",
		EnableGitPull: true,
		Path: map[string]string{
			"beego": ".",
		},
		EnableGomod:    true,
		RefreshGitTime: 24 * 3600,
		Extend:         nil,
	},
	GenerateTime:     time.Now().Format(MDateFormat),
	GenerateTimeUnix: time.Now().Unix(),
	TmplOption:       TmplOption{},
	CurPath:          system.CurrentDir,
	EnableModules:    make(map[string]interface{}), // get the user configuration, get the enable module result
	FunctionOnce:     make(map[string]sync.Once),   // get the tmpl configuration, get the function once result
}

func (c *Container) Run() {
	// init git refresh cache time
	c.initTimestamp()
	c.initUserOption()
	c.initTemplateOption()
	c.initParser()
	c.initRender()
	c.flushTimestamp()
}

func (c *Container) InitToml() {
	if exist := utils.IsExist(c.BeegoProFile); exist {
		beeLogger.Log.Fatalf("file beegopro.toml already exists")
	}
	sourceFile := c.UserOption.GitLocalPath + "/beegopro.toml"
	if !utils.IsExist(c.UserOption.GitLocalPath) {
		c.getTemplateFromGit()
	}
	input, err := ioutil.ReadFile(sourceFile)
	if err != nil {
		beeLogger.Log.Fatalf("read beegopro.toml file err, %s", err.Error())
		return
	}
	err = ioutil.WriteFile(c.BeegoProFile, input, 0644)
	if err != nil {
		beeLogger.Log.Fatalf("create beegopro.toml file err, %s", err.Error())
		return
	}
	beeLogger.Log.Success("Successfully created file beegopro.toml")
}

func (c *Container) getTemplateFromGit() {
	err := git.CloneORPullRepo(c.UserOption.GitRemotePath, c.UserOption.GitLocalPath)
	if err != nil {
		beeLogger.Log.Fatalf("beego pro git clone or pull repo error, err: %s", err)
		return
	}
	c.Timestamp.GitCacheLastRefresh = c.GenerateTimeUnix
}
func (c *Container) initUserOption() {
	if !utils.IsExist(c.BeegoProFile) {
		beeLogger.Log.Fatalf("beego pro config is not exist, beego json path: %s", c.BeegoProFile)
		return
	}
	viper.SetConfigFile(c.BeegoProFile)
	err := viper.ReadInConfig()
	if err != nil {
		beeLogger.Log.Fatalf("read beego pro config content, err: %s", err.Error())
		return
	}

	err = viper.Unmarshal(&c.UserOption)
	if err != nil {
		beeLogger.Log.Fatalf("beego pro config unmarshal error, err: %s", err.Error())
		return
	}
	if c.UserOption.Debug {
		viper.Debug()
	}

	if c.UserOption.EnableGomod {
		if !utils.IsExist(c.GoModFile) {
			beeLogger.Log.Fatalf("go mod not exist, please create go mod file")
			return
		}
	}

	for _, value := range c.UserOption.EnableModule {
		c.EnableModules[value] = struct{}{}
	}

	if len(c.EnableModules) == 0 {
		c.EnableModules["*"] = struct{}{}
	}

	if c.UserOption.Debug {
		fmt.Println("c.modules", c.EnableModules)
	}

}

func (c *Container) initTemplateOption() {
	if c.UserOption.EnableGitPull && (c.GenerateTimeUnix-c.Timestamp.GitCacheLastRefresh > c.UserOption.RefreshGitTime) {
		c.getTemplateFromGit()
	}

	tree, err := toml.LoadFile(c.UserOption.GitLocalPath + "/" + c.UserOption.ProType + "/bee.toml")

	if err != nil {
		beeLogger.Log.Fatalf("beego tmpl exec error, err: %s", err)
		return
	}
	err = tree.Unmarshal(&c.TmplOption)
	if err != nil {
		beeLogger.Log.Fatalf("beego tmpl parse error, err: %s", err)
		return
	}

	if c.UserOption.Debug {
		spew.Dump("tmpl", c.TmplOption)
	}

	for _, value := range c.TmplOption.Descriptor {
		if value.Once {
			c.FunctionOnce[value.SrcName] = sync.Once{}
		}
	}
}

func (c *Container) initParser() {
	driver, flag := ParserDriver[c.UserOption.SourceGen]
	if !flag {
		beeLogger.Log.Fatalf("parse driver not exit, source gen %s", c.UserOption.SourceGen)
	}
	driver.RegisterOption(c.UserOption, c.TmplOption)
	c.Parser = driver
}

func (c *Container) initRender() {
	for _, desc := range c.TmplOption.Descriptor {
		_, allFlag := c.EnableModules["*"]
		_, moduleFlag := c.EnableModules[desc.Module]
		if !allFlag && !moduleFlag {
			continue
		}

		models := c.Parser.GetRenderInfos(desc)
		// model table name, model table schema
		for _, m := range models {
			// some render exec once
			syncOnce, flag := c.FunctionOnce[desc.SrcName]
			if flag {
				syncOnce.Do(func() {
					c.renderModel(m)
				})
				continue
			}
			c.renderModel(m)
		}
	}
}

func (c *Container) renderModel(m RenderInfo) {
	// todo optimize
	m.GenerateTime = c.GenerateTime
	render := NewRender(m)
	render.Exec(m.Descriptor.SrcName)
	if render.Descriptor.IsExistScript() {
		err := render.Descriptor.ExecScript(c.CurPath)
		if err != nil {
			beeLogger.Log.Fatalf("beego exec shell error, err: %s", err)
		}
	}
}

func (c *Container) initTimestamp() {
	if utils.IsExist(c.TimestampFile) {
		tree, err := toml.LoadFile(c.TimestampFile)
		if err != nil {
			beeLogger.Log.Fatalf("beego timestamp tmpl exec error, err: %s", err)
			return
		}
		err = tree.Unmarshal(&c.Timestamp)
		if err != nil {
			beeLogger.Log.Fatalf("beego timestamp tmpl parse error, err: %s", err)
			return
		}
	}
	c.Timestamp.Generate = c.GenerateTimeUnix
}

func (c *Container) flushTimestamp() {
	tomlByte, err := toml.Marshal(c.Timestamp)
	if err != nil {
		beeLogger.Log.Fatalf("marshal timestamp tmpl parse error, err: %s", err)
	}
	err = ioutil.WriteFile(c.TimestampFile, tomlByte, 0644)
	if err != nil {
		beeLogger.Log.Fatalf("flush timestamp tmpl parse error, err: %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/flynn/go-crypto-ssh"
	"github.com/flynn/go-shlex"
)

const PrereceiveHook = `#!/bin/bash
set -eo pipefail; while read oldrev newrev refname; do
[[ $refname = "refs/heads/master" ]] && git archive $newrev | {{RECEIVER}} "$RECEIVE_USER" "$RECEIVE_REPO" "$RECEIVE_KEYNAME" "$RECEIVE_FINGERPRINT" | sed -$([[ $(uname) == "Darwin" ]] && echo l || echo u) "s/^/"$'\e[1G'"/"
done
`

var port *string = flag.String("p", "22", "port to listen on")
var repoPath *string = flag.String("r", "/tmp/repos", "path to repo cache")
var keyPath *string = flag.String("k", "/tmp/keys", "path to named keys")

var receiver string
var privateKey string
var keyNames = make(map[string]string)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage:  %v [options] <privatekey> <receiver>\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if len(os.Args) < 2 {
		flag.Usage()
		return
	}
	privateKey = flag.Arg(0)
	receiver = flag.Arg(1)

	// An SSH server is represented by a ServerConfig, which holds
	// certificate details and handles authentication of ServerConns.
	config := &ssh.ServerConfig{
		PublicKeyCallback: func(conn *ssh.ServerConn, user, algo string, pubkey []byte) bool {
			clientkey, _, ok := ssh.ParsePublicKey(pubkey)
			if !ok {
				return false
			}
			os.MkdirAll(*keyPath, 0755)
			files, err := ioutil.ReadDir(*keyPath)
			if err != nil {
				panic(err)
			}
			for _, file := range files {
				if !file.IsDir() {
					data, err := ioutil.ReadFile(*keyPath + "/" + file.Name())
					if err != nil {
						panic(err)
					}
					filekey, _, _, _, ok := ssh.ParseAuthorizedKey(data)
					if !ok {
						continue
					}
					if bytes.Equal(clientkey.Marshal(), filekey.Marshal()) {
						keyNames[publicKeyFingerprint(clientkey)] = file.Name()
						return true
					}
				}
			}
			return false
		},
	}

	pemBytes, err := ioutil.ReadFile(privateKey)
	if err != nil {
		log.Fatal("Failed to load private key:", err)
	}
	if err = config.SetRSAPrivateKey(pemBytes); err != nil {
		log.Fatal("Failed to parse private key:", err)
	}

	listener, err := ssh.Listen("tcp", "0.0.0.0:"+*port, config)
	if err != nil {
		log.Fatal("failed to listen for connection")
	}
	for {
		// SSH connections just house multiplexed connections
		conn, err := listener.Accept()
		if err != nil {
			log.Println("failed to accept incoming connection")
			continue
		}
		if err := conn.Handshake(); err != nil {
			log.Println("failed to handshake")
			continue
		}
		go handleConnection(conn)
	}
}

func handleConnection(conn *ssh.ServerConn) {
	defer conn.Close()
	for {
		// Accept reads from the connection, demultiplexes packets
		// to their corresponding channels and returns when a new
		// channel request is seen. Some goroutine must always be
		// calling Accept; otherwise no messages will be forwarded
		// to the channels.
		ch, err := conn.Accept()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("hanndleConnection Accept:", err)
			break
		}
		if ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			break
		}
		go handleChannel(conn, ch)
	}
}

func handleChannel(conn *ssh.ServerConn, ch ssh.Channel) {
	err := ch.Accept()
	if err != nil {
		panic(err)
	}
	defer ch.Close()
	for {
		req, err := ch.ReadRequest()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("handleChannel read request err:", err)
			continue
		}
		switch req.Request {
		case "exec":
			if req.WantReply {
				ch.AckRequest(true)
			}
			cmdline := string(req.Payload[4:])
			cmdargs, err := shlex.Split(cmdline)
			if err != nil {
				panic(err)
			}
			ensureCacheRepo(cmdargs[1])
			cmd := exec.Command(cmdargs[0], cmdargs[1:]...)
			cmd.Dir = *repoPath
			cmd.Env = []string{
				"RECEIVE_USER=" + conn.User,
				"RECEIVE_REPO=" + cmdargs[1],
				"RECEIVE_KEYNAME=" + keyNames[publicKeyFingerprint(conn.PublicKey)],
				"RECEIVE_FINGERPRINT=" + publicKeyFingerprint(conn.PublicKey),
			}
			errCh := attachCmd(cmd, ch, ch.Stderr(), ch)
			err = cmd.Start()
			if err != nil {
				panic(err)
			}
			exitCh := exitStatusCh(cmd)
			if err = <-errCh; err != nil {
				panic(err)
			}
			ch.Exit(<-exitCh)
		case "env":
			if req.WantReply {
				ch.AckRequest(true)
			}
		}
	}
}

func attachCmd(cmd *exec.Cmd, stdout, stderr io.Writer, stdin io.Reader) chan error {
	errCh := make(chan error)

	stdinIn, err := cmd.StdinPipe()
	if err != nil {
		panic(err)
	}
	stdoutOut, err := cmd.StdoutPipe()
	if err != nil {
		panic(err)
	}
	stderrOut, err := cmd.StderrPipe()
	if err != nil {
		panic(err)
	}

	go func() {
		_, e := io.Copy(stdinIn, stdin)
		errCh <- e
	}()
	go func() {
		_, e := io.Copy(stdout, stdoutOut)
		errCh <- e
	}()
	go func() {
		_, e := io.Copy(stderr, stderrOut)
		errCh <- e
	}()

	return errCh
}

func exitStatusCh(cmd *exec.Cmd) chan uint {
	exitCh := make(chan uint)
	go func() {
		err := cmd.Wait()
		if err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// There is no plattform independent way to retrieve
				// the exit code, but the following will work on Unix
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					exitCh <- uint(status.ExitStatus())
				}
			} else {
				panic(err)
			}
			return
		}
		exitCh <- uint(0)
	}()
	return exitCh
}

func ensureCacheRepo(path string) {
	cachePath := *repoPath + "/" + path
	if _, err := os.Stat(cachePath); os.IsNotExist(err) {
		os.MkdirAll(cachePath, 0755)
		cmd := exec.Command("git", "init", "--bare")
		cmd.Dir = cachePath
		err = cmd.Run()
		if err != nil {
			panic(err)
		}
	}
	receiver, err := filepath.Abs(receiver)
	if err != nil {
		panic(err)
	}
	ioutil.WriteFile(
		cachePath+"/hooks/pre-receive",
		[]byte(strings.Replace(PrereceiveHook, "{{RECEIVER}}", receiver, 1)),
		0755)
}

func publicKeyFingerprint(key ssh.PublicKey) string {
	var values []string
	h := md5.New()
	h.Write(ssh.MarshalPublicKey(key))
	for _, value := range h.Sum(nil) {
		values = append(values, fmt.Sprintf("%x", value))
	}
	return strings.Join(values, ":")
}
<commit_msg>adding no auth option<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/flynn/go-crypto-ssh"
	"github.com/flynn/go-shlex"
)

const PrereceiveHook = `#!/bin/bash
set -eo pipefail; while read oldrev newrev refname; do
[[ $refname = "refs/heads/master" ]] && git archive $newrev | {{RECEIVER}} "$RECEIVE_USER" "$RECEIVE_REPO" "$RECEIVE_KEYNAME" "$RECEIVE_FINGERPRINT" | sed -$([[ $(uname) == "Darwin" ]] && echo l || echo u) "s/^/"$'\e[1G'"/"
done
`

var port *string = flag.String("p", "22", "port to listen on")
var repoPath *string = flag.String("r", "/tmp/repos", "path to repo cache")
var keyPath *string = flag.String("k", "/tmp/keys", "path to named keys")
var noAuth *bool = flag.Boolean("n", false, "no client authentication")

var receiver string
var privateKey string
var keyNames = make(map[string]string)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage:  %v [options] <privatekey> <receiver>\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if len(os.Args) < 2 {
		flag.Usage()
		return
	}
	privateKey = flag.Arg(0)
	receiver = flag.Arg(1)

	var config *ssh.ServerConfig
	if *noAuth {
		config = &ssh.ServerConfig{
			NoClientAuth: true,
		}
	} else {
		config = &ssh.ServerConfig{
			PublicKeyCallback: func(conn *ssh.ServerConn, user, algo string, pubkey []byte) bool {
				clientkey, _, ok := ssh.ParsePublicKey(pubkey)
				if !ok {
					return false
				}
				os.MkdirAll(*keyPath, 0755)
				files, err := ioutil.ReadDir(*keyPath)
				if err != nil {
					panic(err)
				}
				for _, file := range files {
					if !file.IsDir() {
						data, err := ioutil.ReadFile(*keyPath + "/" + file.Name())
						if err != nil {
							panic(err)
						}
						filekey, _, _, _, ok := ssh.ParseAuthorizedKey(data)
						if !ok {
							continue
						}
						if bytes.Equal(clientkey.Marshal(), filekey.Marshal()) {
							keyNames[publicKeyFingerprint(clientkey)] = file.Name()
							return true
						}
					}
				}
				return false
			},
		}
	}

	pemBytes, err := ioutil.ReadFile(privateKey)
	if err != nil {
		log.Fatal("Failed to load private key:", err)
	}
	if err = config.SetRSAPrivateKey(pemBytes); err != nil {
		log.Fatal("Failed to parse private key:", err)
	}

	listener, err := ssh.Listen("tcp", "0.0.0.0:"+*port, config)
	if err != nil {
		log.Fatal("failed to listen for connection")
	}
	for {
		// SSH connections just house multiplexed connections
		conn, err := listener.Accept()
		if err != nil {
			log.Println("failed to accept incoming connection")
			continue
		}
		if err := conn.Handshake(); err != nil {
			log.Println("failed to handshake")
			continue
		}
		go handleConnection(conn)
	}
}

func handleConnection(conn *ssh.ServerConn) {
	defer conn.Close()
	for {
		// Accept reads from the connection, demultiplexes packets
		// to their corresponding channels and returns when a new
		// channel request is seen. Some goroutine must always be
		// calling Accept; otherwise no messages will be forwarded
		// to the channels.
		ch, err := conn.Accept()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("hanndleConnection Accept:", err)
			break
		}
		if ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			break
		}
		go handleChannel(conn, ch)
	}
}

func handleChannel(conn *ssh.ServerConn, ch ssh.Channel) {
	err := ch.Accept()
	if err != nil {
		panic(err)
	}
	defer ch.Close()
	for {
		req, err := ch.ReadRequest()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("handleChannel read request err:", err)
			continue
		}
		switch req.Request {
		case "exec":
			if req.WantReply {
				ch.AckRequest(true)
			}
			cmdline := string(req.Payload[4:])
			cmdargs, err := shlex.Split(cmdline)
			if err != nil {
				panic(err)
			}
			ensureCacheRepo(cmdargs[1])
			var keyname, fingerprint string
			if *noAuth {
				fingerprint = ""
				keyname = ""
			} else {
				fingerprint = publicKeyFingerprint(conn.PublicKey)
				keyname = keyNames[fingerprint]
			}
			cmd := exec.Command(cmdargs[0], cmdargs[1:]...)
			cmd.Dir = *repoPath
			cmd.Env = []string{
				"RECEIVE_USER=" + conn.User,
				"RECEIVE_REPO=" + cmdargs[1],
				"RECEIVE_KEYNAME=" + keyname,
				"RECEIVE_FINGERPRINT=" + fingerprint,
			}
			errCh := attachCmd(cmd, ch, ch.Stderr(), ch)
			err = cmd.Start()
			if err != nil {
				panic(err)
			}
			exitCh := exitStatusCh(cmd)
			if err = <-errCh; err != nil {
				panic(err)
			}
			ch.Exit(<-exitCh)
		case "env":
			if req.WantReply {
				ch.AckRequest(true)
			}
		}
	}
}

func attachCmd(cmd *exec.Cmd, stdout, stderr io.Writer, stdin io.Reader) chan error {
	errCh := make(chan error)

	stdinIn, err := cmd.StdinPipe()
	if err != nil {
		panic(err)
	}
	stdoutOut, err := cmd.StdoutPipe()
	if err != nil {
		panic(err)
	}
	stderrOut, err := cmd.StderrPipe()
	if err != nil {
		panic(err)
	}

	go func() {
		_, e := io.Copy(stdinIn, stdin)
		errCh <- e
	}()
	go func() {
		_, e := io.Copy(stdout, stdoutOut)
		errCh <- e
	}()
	go func() {
		_, e := io.Copy(stderr, stderrOut)
		errCh <- e
	}()

	return errCh
}

func exitStatusCh(cmd *exec.Cmd) chan uint {
	exitCh := make(chan uint)
	go func() {
		err := cmd.Wait()
		if err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// There is no plattform independent way to retrieve
				// the exit code, but the following will work on Unix
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					exitCh <- uint(status.ExitStatus())
				}
			} else {
				panic(err)
			}
			return
		}
		exitCh <- uint(0)
	}()
	return exitCh
}

func ensureCacheRepo(path string) {
	cachePath := *repoPath + "/" + path
	if _, err := os.Stat(cachePath); os.IsNotExist(err) {
		os.MkdirAll(cachePath, 0755)
		cmd := exec.Command("git", "init", "--bare")
		cmd.Dir = cachePath
		err = cmd.Run()
		if err != nil {
			panic(err)
		}
	}
	receiver, err := filepath.Abs(receiver)
	if err != nil {
		panic(err)
	}
	ioutil.WriteFile(
		cachePath+"/hooks/pre-receive",
		[]byte(strings.Replace(PrereceiveHook, "{{RECEIVER}}", receiver, 1)),
		0755)
}

func publicKeyFingerprint(key ssh.PublicKey) string {
	var values []string
	h := md5.New()
	h.Write(ssh.MarshalPublicKey(key))
	for _, value := range h.Sum(nil) {
		values = append(values, fmt.Sprintf("%x", value))
	}
	return strings.Join(values, ":")
}
<|endoftext|>


<commit_before>// Package duration provides a duration of audio from file or reader
package duration

import (
	"io"
	"os"

	log "github.com/go-pkgz/lgr"
	"github.com/tcolgate/mp3"
)

// Service provides duration of audio from file or reader
type Service struct{}

// File scans MP3 file from provided file and returns its duration in seconds, ignoring possible errors
func (s *Service) File(fname string) int {
	fh, err := os.Open(fname) //nolint:gosec // this is not an inclusion as file was created by us
	if err != nil {
		log.Printf("[WARN] can't get duration, failed to open file %s: %v", fname, err)
		return 0
	}
	defer fh.Close() // nolint
	return s.Reader(fh)
}

// Reader scans MP3 from provided file and returns its duration in seconds, ignoring possible errors
func (s *Service) Reader(r io.Reader) int {
	d := mp3.NewDecoder(r)

	var f mp3.Frame
	var skipped int
	var duration float64
	var err error

	for err == nil {
		if err = d.Decode(&f, &skipped); err != nil && err != io.EOF {
			return 0
		}
		duration += f.Duration().Seconds()
	}
	return int(duration)
}
<commit_msg>add duration calculation error logging<commit_after>// Package duration provides a duration of audio from file or reader
package duration

import (
	"io"
	"os"

	log "github.com/go-pkgz/lgr"
	"github.com/tcolgate/mp3"
)

// Service provides duration of audio from file or reader
type Service struct{}

// File scans MP3 file from provided file and returns its duration in seconds, ignoring possible errors
func (s *Service) File(fname string) int {
	fh, err := os.Open(fname) //nolint:gosec // this is not an inclusion as file was created by us
	if err != nil {
		log.Printf("[WARN] can't get duration, failed to open file %s: %v", fname, err)
		return 0
	}
	defer fh.Close() // nolint
	return s.Reader(fh)
}

// Reader scans MP3 from provided file and returns its duration in seconds, ignoring possible errors
func (s *Service) Reader(r io.Reader) int {
	d := mp3.NewDecoder(r)

	var f mp3.Frame
	var skipped int
	var duration float64
	var err error

	for err == nil {
		if err = d.Decode(&f, &skipped); err != nil && err != io.EOF {
			log.Printf("[WARN] can't get duration for provided stream: %v", err)
			return 0
		}
		duration += f.Duration().Seconds()
	}
	return int(duration)
}
<|endoftext|>