<commit_before>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rnd

import (
	"math"

	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/la"
)

// StatAve computes the average of x values
//  Input:
//   x -- sample
//  Output:
//   xave -- average
func StatAve(x []float64) (xave float64) {
	n := len(x)
	if n < 1 {
		return
	}
	for i := 0; i < n; i++ {
		xave += x[i]
	}
	xave /= float64(n)
	return
}

// StatDevFirst computes the average deviation or standard deviation (σ)
// for given value of average/mean/first moment
//  Input:
//   x    -- sample
//   xave -- bar(x) == average/mean/first moment
//   std  -- compute standard deviation (σ) instead of average deviation (adev)
//  Output:
//   xdev -- average deviation; if std==true, computes standard deviation (σ) instead
func StatDevFirst(x []float64, xave float64, std bool) (xdev float64) {

	// check
	n := len(x)
	if n < 2 {
		return
	}
	N := float64(n)

	// standard deviation
	if std {
		var d, c, vari float64
		for i := 0; i < n; i++ {
			d = x[i] - xave // d ← xi - bar(x)
			c += d          // c ← Σ d  (corrector)
			vari += d * d   // vari ← Σ d²
		}
		vari = (vari - c*c/N) / (N - 1.0)
		xdev = math.Sqrt(vari)
		return
	}

	// average deviation
	var sum, d float64
	for i := 0; i < n; i++ {
		d = x[i] - xave    // d ← xi - bar(x)
		sum += math.Abs(d) // sum ← Σ |d|
	}
	xdev = sum / N
	return
}

// StatDev computes the average deviation or standard deviation (σ)
//  Input:
//   x   -- sample
//   std -- compute standard deviation (σ) instead of average deviation (adev)
//  Output:
//   xdev -- average deviation; if std==true, computes standard deviation (σ) instead
func StatDev(x []float64, std bool) (xdev float64) {

	// check
	n := len(x)
	if n < 2 {
		return
	}

	// average
	var xave float64
	for i := 0; i < n; i++ {
		xave += x[i]
	}
	xave /= float64(n)
	xdev = StatDevFirst(x, xave, std)
	return
}

// StatBasic performs some basic statistics
//  Input:
//   x   -- sample
//   std -- compute standard deviation (σ) instead of average deviation (adev)
//  Output:
//   xmin -- minimum value
//   xave -- mean average (first moment)
//   xmax -- maximum value
//   xdev -- average deviation; if std==true, computes standard deviation (σ) instead
func StatBasic(x []float64, std bool) (xmin, xave, xmax, xdev float64) {

	// check
	n := len(x)
	if n < 2 {
		return
	}

	// average, min and max
	xmin, xmax = x[0], x[0]
	for i := 0; i < n; i++ {
		xave += x[i]
		xmin = min(xmin, x[i])
		xmax = max(xmax, x[i])
	}
	xave /= float64(n)
	xdev = StatDevFirst(x, xave, std)
	return
}

// StatMoments computes the 4th moments of a data set
//  Input:
//   x -- sample
//  Output:
//   sum  -- sum of values
//   mean -- mean average (first moment)
//   adev -- average deviation
//   sdev -- standrad deviation
//   vari -- variance (second moment)
//   skew -- skewness (third moment)
//   kurt -- kurtosis (fourth moment)
//  Based on:
//     Press WH, Teukolsky SA, Vetterling WT and Flannery BP (2007)
//       Numerical Recipes in C++ 2007 (3rd Edition), page 725.
func StatMoments(x []float64) (sum, mean, adev, sdev, vari, skew, kurt float64, err error) {

	// check
	n := len(x)
	if n < 2 {
		err = chk.Err("x set must have at least 2 items")
		return
	}

	// first pass to get the mean
	for i := 0; i < n; i++ {
		sum += x[i]
	}
	N := float64(n)
	mean = sum / N

	// second pass to get the first (absolute), second, third, and fourth moments of the deviation from the mean.
	var d, c, p float64
	for i := 0; i < n; i++ {
		d = x[i] - mean     // d ← xi - bar(x)
		adev += math.Abs(d) // adev ← Σ |d|
		c += d              // c ← Σ d  // corrector
		p = d * d           // p ← d²
		vari += p           // vari ← Σ d²
		p *= d              // p  ← d³
		skew += p           // skew ← Σ d³
		kurt += p * d       // kurt ← Σ d⁴
	}

	// put the pieces together according to the conventional definitions
	adev /= N
	vari = (vari - c*c/N) / (N - 1.0)
	sdev = math.Sqrt(vari)
	TOL := 1e-15
	if math.Abs(vari) < 1e-15 {
		err = chk.Err("cannot compute skew and kurtosis because variance is zero. vari=%g (tol=%g)", vari, TOL)
		return
	}
	skew /= (N * vari * sdev)
	kurt = kurt/(N*vari*vari) - 3.0
	return
}

// StatTable computes the min, ave, max, and dev of values organised in a table
//  Input:
//   x     -- sample
//   std   -- compute standard deviation (σ) instead of average deviation (adev)
//   withZ -- computes z-matrix as well
//  Convention of indices:
//   0=min  1=ave  2=max  3=dev
//  Output:                        min          ave          max          dev
//                                  ↓            ↓            ↓            ↓
//   x00 x01 x02 x03 x04 x05 → y00=min(x0?) y10=ave(x0?) y20=max(x0?) y30=dev(x0?)
//   x10 x11 x12 x13 x14 x15 → y01=min(x1?) y11=ave(x1?) y21=max(x1?) y31=dev(x1?)
//   x20 x21 x22 x23 x24 x25 → y02=min(x2?) y12=ave(x2?) y22=max(x2?) y32=dev(x2?)
//                                  ↓            ↓            ↓            ↓
//                       min → z00=min(y0?) z01=min(y1?) z02=min(y2?) z03=min(y3?)
//                       ave → z10=ave(y0?) z11=ave(y1?) z12=ave(y2?) z13=ave(y3?)
//                       max → z20=max(y0?) z21=max(y1?) z22=max(y2?) z23=max(y3?)
//                       dev → z30=dev(y0?) z31=dev(y1?) z32=dev(y2?) z33=dev(y3?)
//                                  =            =            =            =
//                       min → z00=min(min) z01=min(ave) z02=min(max) z03=min(dev)
//                       ave → z10=ave(min) z11=ave(ave) z12=ave(max) z13=ave(dev)
//                       max → z20=max(min) z21=max(ave) z22=max(max) z23=max(dev)
//                       dev → z30=dev(min) z31=dev(ave) z32=dev(max) z33=dev(dev)
func StatTable(x [][]float64, std, withZ bool) (y, z [][]float64) {

	// dimensions
	m := len(x)
	if m < 1 {
		return
	}
	n := len(x[0])
	if n < 2 {
		return
	}

	// compute y
	y = la.MatAlloc(4, m)
	for i := 0; i < m; i++ {
		y[0][i], y[1][i], y[2][i], y[3][i] = StatBasic(x[i], std)
	}

	// compute z
	if withZ {
		z = la.MatAlloc(4, 4)
		for i := 0; i < 4; i++ {
			z[0][i], z[1][i], z[2][i], z[3][i] = StatBasic(y[i], std)
		}
	}
	return
}
<commit_msg>stat dur added<commit_after>// Copyright 2012 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rnd

import (
	"math"
	"time"

	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/la"
)

// StatAve computes the average of x values
//  Input:
//   x -- sample
//  Output:
//   xave -- average
func StatAve(x []float64) (xave float64) {
	n := len(x)
	if n < 1 {
		return
	}
	for i := 0; i < n; i++ {
		xave += x[i]
	}
	xave /= float64(n)
	return
}

// StatDevFirst computes the average deviation or standard deviation (σ)
// for given value of average/mean/first moment
//  Input:
//   x    -- sample
//   xave -- bar(x) == average/mean/first moment
//   std  -- compute standard deviation (σ) instead of average deviation (adev)
//  Output:
//   xdev -- average deviation; if std==true, computes standard deviation (σ) instead
func StatDevFirst(x []float64, xave float64, std bool) (xdev float64) {

	// check
	n := len(x)
	if n < 2 {
		return
	}
	N := float64(n)

	// standard deviation
	if std {
		var d, c, vari float64
		for i := 0; i < n; i++ {
			d = x[i] - xave // d ← xi - bar(x)
			c += d          // c ← Σ d  (corrector)
			vari += d * d   // vari ← Σ d²
		}
		vari = (vari - c*c/N) / (N - 1.0)
		xdev = math.Sqrt(vari)
		return
	}

	// average deviation
	var sum, d float64
	for i := 0; i < n; i++ {
		d = x[i] - xave    // d ← xi - bar(x)
		sum += math.Abs(d) // sum ← Σ |d|
	}
	xdev = sum / N
	return
}

// StatDev computes the average deviation or standard deviation (σ)
//  Input:
//   x   -- sample
//   std -- compute standard deviation (σ) instead of average deviation (adev)
//  Output:
//   xdev -- average deviation; if std==true, computes standard deviation (σ) instead
func StatDev(x []float64, std bool) (xdev float64) {

	// check
	n := len(x)
	if n < 2 {
		return
	}

	// average
	var xave float64
	for i := 0; i < n; i++ {
		xave += x[i]
	}
	xave /= float64(n)
	xdev = StatDevFirst(x, xave, std)
	return
}

// StatBasic performs some basic statistics
//  Input:
//   x   -- sample
//   std -- compute standard deviation (σ) instead of average deviation (adev)
//  Output:
//   xmin -- minimum value
//   xave -- mean average (first moment)
//   xmax -- maximum value
//   xdev -- average deviation; if std==true, computes standard deviation (σ) instead
func StatBasic(x []float64, std bool) (xmin, xave, xmax, xdev float64) {

	// check
	n := len(x)
	if n < 2 {
		return
	}

	// average, min and max
	xmin, xmax = x[0], x[0]
	for i := 0; i < n; i++ {
		xave += x[i]
		xmin = min(xmin, x[i])
		xmax = max(xmax, x[i])
	}
	xave /= float64(n)
	xdev = StatDevFirst(x, xave, std)
	return
}

// StatMoments computes the 4th moments of a data set
//  Input:
//   x -- sample
//  Output:
//   sum  -- sum of values
//   mean -- mean average (first moment)
//   adev -- average deviation
//   sdev -- standrad deviation
//   vari -- variance (second moment)
//   skew -- skewness (third moment)
//   kurt -- kurtosis (fourth moment)
//  Based on:
//     Press WH, Teukolsky SA, Vetterling WT and Flannery BP (2007)
//       Numerical Recipes in C++ 2007 (3rd Edition), page 725.
func StatMoments(x []float64) (sum, mean, adev, sdev, vari, skew, kurt float64, err error) {

	// check
	n := len(x)
	if n < 2 {
		err = chk.Err("x set must have at least 2 items")
		return
	}

	// first pass to get the mean
	for i := 0; i < n; i++ {
		sum += x[i]
	}
	N := float64(n)
	mean = sum / N

	// second pass to get the first (absolute), second, third, and fourth moments of the deviation from the mean.
	var d, c, p float64
	for i := 0; i < n; i++ {
		d = x[i] - mean     // d ← xi - bar(x)
		adev += math.Abs(d) // adev ← Σ |d|
		c += d              // c ← Σ d  // corrector
		p = d * d           // p ← d²
		vari += p           // vari ← Σ d²
		p *= d              // p  ← d³
		skew += p           // skew ← Σ d³
		kurt += p * d       // kurt ← Σ d⁴
	}

	// put the pieces together according to the conventional definitions
	adev /= N
	vari = (vari - c*c/N) / (N - 1.0)
	sdev = math.Sqrt(vari)
	TOL := 1e-15
	if math.Abs(vari) < 1e-15 {
		err = chk.Err("cannot compute skew and kurtosis because variance is zero. vari=%g (tol=%g)", vari, TOL)
		return
	}
	skew /= (N * vari * sdev)
	kurt = kurt/(N*vari*vari) - 3.0
	return
}

// StatTable computes the min, ave, max, and dev of values organised in a table
//  Input:
//   x     -- sample
//   std   -- compute standard deviation (σ) instead of average deviation (adev)
//   withZ -- computes z-matrix as well
//  Convention of indices:
//   0=min  1=ave  2=max  3=dev
//  Output:                        min          ave          max          dev
//                                  ↓            ↓            ↓            ↓
//   x00 x01 x02 x03 x04 x05 → y00=min(x0?) y10=ave(x0?) y20=max(x0?) y30=dev(x0?)
//   x10 x11 x12 x13 x14 x15 → y01=min(x1?) y11=ave(x1?) y21=max(x1?) y31=dev(x1?)
//   x20 x21 x22 x23 x24 x25 → y02=min(x2?) y12=ave(x2?) y22=max(x2?) y32=dev(x2?)
//                                  ↓            ↓            ↓            ↓
//                       min → z00=min(y0?) z01=min(y1?) z02=min(y2?) z03=min(y3?)
//                       ave → z10=ave(y0?) z11=ave(y1?) z12=ave(y2?) z13=ave(y3?)
//                       max → z20=max(y0?) z21=max(y1?) z22=max(y2?) z23=max(y3?)
//                       dev → z30=dev(y0?) z31=dev(y1?) z32=dev(y2?) z33=dev(y3?)
//                                  =            =            =            =
//                       min → z00=min(min) z01=min(ave) z02=min(max) z03=min(dev)
//                       ave → z10=ave(min) z11=ave(ave) z12=ave(max) z13=ave(dev)
//                       max → z20=max(min) z21=max(ave) z22=max(max) z23=max(dev)
//                       dev → z30=dev(min) z31=dev(ave) z32=dev(max) z33=dev(dev)
func StatTable(x [][]float64, std, withZ bool) (y, z [][]float64) {

	// dimensions
	m := len(x)
	if m < 1 {
		return
	}
	n := len(x[0])
	if n < 2 {
		return
	}

	// compute y
	y = la.MatAlloc(4, m)
	for i := 0; i < m; i++ {
		y[0][i], y[1][i], y[2][i], y[3][i] = StatBasic(x[i], std)
	}

	// compute z
	if withZ {
		z = la.MatAlloc(4, 4)
		for i := 0; i < 4; i++ {
			z[0][i], z[1][i], z[2][i], z[3][i] = StatBasic(y[i], std)
		}
	}
	return
}

// StatDur generates stat about duration
func StatDur(durs []time.Duration) (min, ave, max, sum time.Duration) {
	if len(durs) == 0 {
		return
	}
	min, max = durs[0], durs[0]
	for _, d := range durs {
		if d < min {
			min = d
		}
		if d > max {
			max = d
		}
		sum += d
	}
	ave = sum / time.Duration(int64(len(durs)))
	return
}
<|endoftext|>


<commit_before>// Copyright 2016 IBM Corporation
//
//   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 commands

import (
	"bytes"
	"fmt"
	"sort"
	"strings"

	"github.com/amalgam8/amalgam8/cli/common"
	"github.com/amalgam8/amalgam8/cli/terminal"
	"github.com/amalgam8/amalgam8/cli/utils"
	ctrl "github.com/amalgam8/amalgam8/controller/client"
	"github.com/amalgam8/amalgam8/pkg/api"
	reg "github.com/amalgam8/amalgam8/registry/client"
	"github.com/urfave/cli"
)

// prettyRouteList is used to cover the table data into JSON or YAML
type prettyRouteList struct {
	Service   string   `json:"service" yaml:"service"`
	Default   string   `json:"default,omitempty" yaml:"default,omitempty"`
	Selectors []string `json:"selectors,omitempty" yaml:"selectors,omitempty"`
}

// RouteListCommand is used for the route-list command.
type RouteListCommand struct {
	ctx        *cli.Context
	registry   *reg.Client
	controller *ctrl.Client
	term       terminal.UI
}

// NewRouteListCommand constructs a new Route List.
func NewRouteListCommand(term terminal.UI) (cmd *RouteListCommand) {
	return &RouteListCommand{
		term: term,
	}
}

// GetMetadata returns the metadata.
func (cmd *RouteListCommand) GetMetadata() cli.Command {
	T := utils.Language(common.DefaultLanguage)
	return cli.Command{
		Name:        "route-list",
		Description: T("route_list_description"),
		Usage:       T("route_list_usage"),
		// TODO: Complete UsageText
		UsageText: T("route_list_usage"),
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "output, o",
				Usage: T("route_list_output_usage"),
				Value: TABLE,
			},
			cli.StringSliceFlag{
				Name:  "service, s",
				Usage: T("route_list_service_usage"),
			},
		},
		Before:       cmd.Before,
		OnUsageError: cmd.OnUsageError,
		Action:       cmd.Action,
	}
}

// Before runs before the Action
// https://godoc.org/github.com/urfave/cli#BeforeFunc
func (cmd *RouteListCommand) Before(ctx *cli.Context) error {
	// Update the context
	cmd.ctx = ctx
	return nil
}

// OnUsageError is executed if an usage error occurs.
func (cmd *RouteListCommand) OnUsageError(ctx *cli.Context, err error, isSubcommand bool) error {
	cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
	return nil
}

// Action runs when no subcommands are specified
// https://godoc.org/github.com/urfave/cli#ActionFunc
func (cmd *RouteListCommand) Action(ctx *cli.Context) error {
	registry, err := NewRegistry(ctx)
	if err != nil {
		// Exit if the registry returned an error
		return nil
	}
	// Update the registry
	cmd.registry = registry

	controller, err := NewController(ctx)
	if err != nil {
		// Exit if the controller returned an error
		return nil
	}
	// Update the controller
	cmd.controller = controller

	if ctx.NArg() > 0 {
		cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
		return nil
	}

	filter := &api.RuleFilter{}
	if ctx.IsSet("service") || ctx.IsSet("s") {
		filter = &api.RuleFilter{
			Destinations: ctx.StringSlice("service"),
		}
	}

	format := ctx.String("output")
	switch format {
	case JSON, YAML:
		return cmd.PrettyPrint(filter, format)
	case TABLE:
		return cmd.RouteTable(filter)
	}

	return cmd.DefaultAction(ctx)
}

// DefaultAction runs the default action.
func (cmd *RouteListCommand) DefaultAction(ctx *cli.Context) error {
	return cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
}

// PrettyPrint prints the list of services in the given format (json or yaml).
func (cmd *RouteListCommand) PrettyPrint(filter *api.RuleFilter, format string) error {
	routeList := []prettyRouteList{}

	routes, err := cmd.controller.ListRoutes(filter)
	if err != nil {
		return err
	}

	// add services that have routing rules
	for serviceName, routingRules := range routes.Services {
		defaultVersion, selectors := routeSelectors(routingRules)
		routeList = append(
			routeList,
			prettyRouteList{
				Service:   serviceName,
				Default:   defaultVersion,
				Selectors: selectors,
			},
		)
	}

	services, err := cmd.registry.ListServices()
	if err != nil {
		return err
	}

	// add services that don't have routing rules
	for _, service := range services {
		if _, ok := routes.Services[service]; !ok {
			routeList = append(
				routeList,
				prettyRouteList{
					Service: service,
				},
			)
		}
	}

	return utils.MarshallReader(cmd.ctx.App.Writer, routeList, format)
}

// RouteTable prints the a list of routes as a table.
// +------------------+-----------------+----------------------+
// | Service          | Default Version | Version Selectors    |
// +------------------+-----------------+----------------------+
// | json_destination | v21,v22,json    | v2(user="test")      |
// | productpage      | v2              | v2(header="Foo:bar") |
// | details          | v1              |                      |
// | reviews          | v2              |                      |
// | ratings          |                 |                      |
// +------------------+-----------------+----------------------+
func (cmd *RouteListCommand) RouteTable(filter *api.RuleFilter) error {
	table := cmd.term.NewTable()
	table.SetHeader([]string{
		"Service",
		"Default Version",
		"Version Selectors",
	})

	routes, err := cmd.controller.ListRoutes(filter)
	if err != nil {
		return err
	}

	// add services that have routing rules
	for serviceName, routingRules := range routes.Services {
		defaultVersion, selectors := routeSelectors(routingRules)
		table.AddRow(
			[]string{
				serviceName,
				defaultVersion,
				strings.Join(selectors, ", "),
			},
		)
	}

	services, err := cmd.registry.ListServices()
	if err != nil {
		return err
	}

	// add services that don't have routing rules
	for _, service := range services {
		if _, ok := routes.Services[service]; !ok {
			table.AddRow([]string{service, "", ""})
		}
	}

	table.SortByColumnIndex(0)
	table.PrintTable()
	return nil
}

func routeSelectors(routingRules []api.Rule) (string, sort.StringSlice) {
	var selectors sort.StringSlice
	var defaultVersion string
	for _, route := range routingRules {
		for _, backend := range route.Route.Backends {
			version := strings.Join(backend.Tags, ",")
			if route.Match != nil {
				selectors = append(selectors, formatMatchSelector(version, route.Match, backend.Weight))
			} else {
				if backend.Weight > 0 {
					selectors = append(selectors, fmt.Sprintf("%s(weight=%g)", version, backend.Weight))
				} else {
					defaultVersion = version
				}
			}
		}
	}
	selectors.Sort()
	return defaultVersion, selectors
}

func formatMatchSelector(version string, match *api.Match, weight float64) string {
	buf := bytes.Buffer{}
	buf.WriteString(version + "(")
	if match.Source != nil {
		fmt.Fprintf(&buf, " source=%s:%s,", match.Source.Name, strings.Join(match.Source.Tags, ","))
	}

	for key, value := range match.Headers {
		if key == "Cookie" && strings.HasPrefix(value, ".*?user=") {
			fmt.Fprintf(&buf, "user=%q", value[len(".*?user="):])
		} else {
			buf.WriteString("header=")
			fmt.Fprintf(&buf, "\"%s:%s\"", key, value)
		}
	}

	if weight > 0 {
		fmt.Fprintf(&buf, ",weight=%g", weight)
	}

	buf.WriteString(")")
	return buf.String()
}
<commit_msg>Removed registry logic from route-list cmd<commit_after>// Copyright 2016 IBM Corporation
//
//   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 commands

import (
	"bytes"
	"fmt"
	"sort"
	"strings"

	"github.com/amalgam8/amalgam8/cli/common"
	"github.com/amalgam8/amalgam8/cli/terminal"
	"github.com/amalgam8/amalgam8/cli/utils"
	ctrl "github.com/amalgam8/amalgam8/controller/client"
	"github.com/amalgam8/amalgam8/pkg/api"
	reg "github.com/amalgam8/amalgam8/registry/client"
	"github.com/urfave/cli"
)

// prettyRouteList is used to cover the table data into JSON or YAML
type prettyRouteList struct {
	Service   string   `json:"service" yaml:"service"`
	Default   string   `json:"default,omitempty" yaml:"default,omitempty"`
	Selectors []string `json:"selectors,omitempty" yaml:"selectors,omitempty"`
}

// RouteListCommand is used for the route-list command.
type RouteListCommand struct {
	ctx        *cli.Context
	controller *ctrl.Client
	term       terminal.UI
}

// NewRouteListCommand constructs a new Route List.
func NewRouteListCommand(term terminal.UI) (cmd *RouteListCommand) {
	return &RouteListCommand{
		term: term,
	}
}

// GetMetadata returns the metadata.
func (cmd *RouteListCommand) GetMetadata() cli.Command {
	T := utils.Language(common.DefaultLanguage)
	return cli.Command{
		Name:        "route-list",
		Description: T("route_list_description"),
		Usage:       T("route_list_usage"),
		// TODO: Complete UsageText
		UsageText: T("route_list_usage"),
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "output, o",
				Usage: T("route_list_output_usage"),
				Value: TABLE,
			},
			cli.StringSliceFlag{
				Name:  "service, s",
				Usage: T("route_list_service_usage"),
			},
		},
		Before:       cmd.Before,
		OnUsageError: cmd.OnUsageError,
		Action:       cmd.Action,
	}
}

// Before runs before the Action
// https://godoc.org/github.com/urfave/cli#BeforeFunc
func (cmd *RouteListCommand) Before(ctx *cli.Context) error {
	// Update the context
	cmd.ctx = ctx
	return nil
}

// OnUsageError is executed if an usage error occurs.
func (cmd *RouteListCommand) OnUsageError(ctx *cli.Context, err error, isSubcommand bool) error {
	cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
	return nil
}

// Action runs when no subcommands are specified
// https://godoc.org/github.com/urfave/cli#ActionFunc
func (cmd *RouteListCommand) Action(ctx *cli.Context) error {
	controller, err := NewController(ctx)
	if err != nil {
		// Exit if the controller returned an error
		return nil
	}
	// Update the controller
	cmd.controller = controller

	if ctx.NArg() > 0 {
		cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
		return nil
	}

	filter := &api.RuleFilter{}
	if ctx.IsSet("service") || ctx.IsSet("s") {
		filter = &api.RuleFilter{
			Destinations: ctx.StringSlice("service"),
		}
	}

	format := ctx.String("output")
	switch format {
	case JSON, YAML:
		return cmd.PrettyPrint(filter, format)
	case TABLE:
		return cmd.RouteTable(filter)
	}

	return cmd.DefaultAction(ctx)
}

// DefaultAction runs the default action.
func (cmd *RouteListCommand) DefaultAction(ctx *cli.Context) error {
	return cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
}

// PrettyPrint prints the list of services in the given format (json or yaml).
func (cmd *RouteListCommand) PrettyPrint(filter *api.RuleFilter, format string) error {
	routeList := []prettyRouteList{}

	routes, err := cmd.controller.ListRoutes(filter)
	if err != nil {
		return err
	}

	// add services that have routing rules
	for serviceName, routingRules := range routes.Services {
		defaultVersion, selectors := routeSelectors(routingRules)
		routeList = append(
			routeList,
			prettyRouteList{
				Service:   serviceName,
				Default:   defaultVersion,
				Selectors: selectors,
			},
		)
	}

	return utils.MarshallReader(cmd.ctx.App.Writer, routeList, format)
}

// RouteTable prints the a list of routes as a table.
// +------------------+-----------------+----------------------+
// | Service          | Default Version | Version Selectors    |
// +------------------+-----------------+----------------------+
// | json_destination | v21,v22,json    | v2(user="test")      |
// | productpage      | v2              | v2(header="Foo:bar") |
// | details          | v1              |                      |
// | reviews          | v2              |                      |
// | ratings          |                 |                      |
// +------------------+-----------------+----------------------+
func (cmd *RouteListCommand) RouteTable(filter *api.RuleFilter) error {
	table := cmd.term.NewTable()
	table.SetHeader([]string{
		"Service",
		"Default Version",
		"Version Selectors",
	})

	routes, err := cmd.controller.ListRoutes(filter)
	if err != nil {
		return err
	}

	// add services that have routing rules
	for serviceName, routingRules := range routes.Services {
		defaultVersion, selectors := routeSelectors(routingRules)
		table.AddRow(
			[]string{
				serviceName,
				defaultVersion,
				strings.Join(selectors, ", "),
			},
		)
	}

	table.SortByColumnIndex(0)
	table.PrintTable()
	return nil
}

func routeSelectors(routingRules []api.Rule) (string, sort.StringSlice) {
	var selectors sort.StringSlice
	var defaultVersion string
	for _, route := range routingRules {
		for _, backend := range route.Route.Backends {
			version := strings.Join(backend.Tags, ",")
			if route.Match != nil {
				selectors = append(selectors, formatMatchSelector(version, route.Match, backend.Weight))
			} else {
				if backend.Weight > 0 {
					selectors = append(selectors, fmt.Sprintf("%s(weight=%g)", version, backend.Weight))
				} else {
					defaultVersion = version
				}
			}
		}
	}
	selectors.Sort()
	return defaultVersion, selectors
}

func formatMatchSelector(version string, match *api.Match, weight float64) string {
	buf := bytes.Buffer{}
	buf.WriteString(version + "(")
	if match.Source != nil {
		fmt.Fprintf(&buf, " source=%s:%s,", match.Source.Name, strings.Join(match.Source.Tags, ","))
	}

	for key, value := range match.Headers {
		if key == "Cookie" && strings.HasPrefix(value, ".*?user=") {
			fmt.Fprintf(&buf, "user=%q", value[len(".*?user="):])
		} else {
			buf.WriteString("header=")
			fmt.Fprintf(&buf, "\"%s:%s\"", key, value)
		}
	}

	if weight > 0 {
		fmt.Fprintf(&buf, ",weight=%g", weight)
	}

	buf.WriteString(")")
	return buf.String()
}
<|endoftext|>


<commit_before>package facade

import (
	"fmt"
	"io"
	"os"
	"runtime"

	"github.com/spf13/cobra"
	"github.com/spiegel-im-spiegel/gocli"
	"github.com/spiegel-im-spiegel/gpgpdump"
)

const (
	//Name is applicatin name
	Name = "gpgpdump"
	//Version is version for applicatin
	Version = "v0.2.0dev"
)

//ExitCode is OS exit code enumeration class
type ExitCode int

const (
	//Normal is OS exit code "normal"
	Normal ExitCode = iota
	//Abnormal is OS exit code "abnormal"
	Abnormal
)

//Int convert integer value
func (c ExitCode) Int() int {
	return int(c)
}

//Stringer method
func (c ExitCode) String() string {
	switch c {
	case Normal:
		return "normal end"
	case Abnormal:
		return "abnormal end"
	default:
		return "unknown"
	}
}

var (
	versionFlag bool      //version flag
	reader      io.Reader //input file reader (maybe os.Stdin)
	result      string    //result by parsing OpenPGP packets
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use: Name + " [flags] [PGPfile]",
	RunE: func(cmd *cobra.Command, args []string) error {
		//parse options
		if versionFlag {
			return nil
		}
		opts := parseOpt(cmd)
		//fmt.Println("Options: ", opts)

		//open PGP file
		if len(args) > 0 {
			file, err := os.Open(args[0])
			if err != nil { //maybe file path
				return err
			}
			defer file.Close()
			reader = file
		}

		//parse OpenPGP packets
		p := gpgpdump.NewParse(opts, reader)
		info, err := p.Run()
		if err != nil {
			return err
		}

		//marshaling
		var res string
		if opts.JSON() {
			res, err = info.JSON()
		} else {
			res, err = info.TOML()
		}
		if err != nil {
			return err
		}
		result = res //result
		return nil
	},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute(cui *gocli.UI) (exit ExitCode) {
	defer func() {
		//panic hundling
		if r := recover(); r != nil {
			cui.OutputErrln("Panic:", r)
			for depth := 0; ; depth++ {
				pc, _, line, ok := runtime.Caller(depth)
				if !ok {
					break
				}
				cui.OutputErrln(" ->", depth, ":", runtime.FuncForPC(pc).Name(), ": line", line)
			}
			exit = 1
		}
	}()

	//execution
	reader = cui.Reader() //default reader
	if err := RootCmd.Execute(); err != nil {
		//cui.OutputErrln(err) //no need to output error
		exit = 1
		return
	}
	if versionFlag {
		cui.OutputErrln(version())
		return
	}
	cui.Outputln(result)
	return
}

func init() {
	RootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "version for "+Name)
	RootCmd.Flags().BoolP(gpgpdump.ArmorOpt, "a", false, "accepts ASCII input only")
	//RootCmd.Flags().BoolP(gpgpdump.DebugOpt, "d", false, "for debug") //not use
	//RootCmd.Flags().BoolP(gpgpdump.GDumpOpt, "g", false, "selects alternate (GnuPG type) dump format") //not use
	RootCmd.Flags().BoolP(gpgpdump.IntegerOpt, "i", false, "dumps multi-precision integers")
	RootCmd.Flags().BoolP(gpgpdump.JSONOpt, "j", false, "output with JSON format")
	RootCmd.Flags().BoolP(gpgpdump.LiteralOpt, "l", false, "dumps literal packets (tag 11)")
	RootCmd.Flags().BoolP(gpgpdump.MarkerOpt, "m", false, "dumps marker packets (tag 10)")
	RootCmd.Flags().BoolP(gpgpdump.PrivateOpt, "p", false, "dumps private packets (tag 60-63)")
	RootCmd.Flags().BoolP(gpgpdump.UTCOpt, "u", false, "output UTC time")
}

func getBool(cmd *cobra.Command, name string) bool {
	f, err := cmd.Flags().GetBool(name)
	if err != nil {
		panic("invalid option: " + name)
	}
	return f
}

func parseOpt(cmd *cobra.Command) *gpgpdump.Options {
	return gpgpdump.NewOptions(
		gpgpdump.Set(gpgpdump.ArmorOpt, getBool(cmd, gpgpdump.ArmorOpt)),
		//gpgpdump.Set(gpgpdump.DebugOpt, getBool(cmd, gpgpdump.DebugOpt)), //not use
		//gpgpdump.Set(gpgpdump.GDumpOpt, getBool(cmd, gpgpdump.GDumpOpt)), //not use
		gpgpdump.Set(gpgpdump.IntegerOpt, getBool(cmd, gpgpdump.IntegerOpt)),
		gpgpdump.Set(gpgpdump.JSONOpt, getBool(cmd, gpgpdump.JSONOpt)),
		gpgpdump.Set(gpgpdump.LiteralOpt, getBool(cmd, gpgpdump.LiteralOpt)),
		gpgpdump.Set(gpgpdump.MarkerOpt, getBool(cmd, gpgpdump.MarkerOpt)),
		gpgpdump.Set(gpgpdump.PrivateOpt, getBool(cmd, gpgpdump.PrivateOpt)),
		gpgpdump.Set(gpgpdump.UTCOpt, getBool(cmd, gpgpdump.UTCOpt)),
	)
}

func version() string {
	return fmt.Sprintf("%s %s\nCopyright 2016,2017 Spiegel (based on pgpdump by kazu-yamamoto)\nLicensed under Apache License, Version 2.0\n", Name, Version)
}

/* Copyright 2017 Spiegel
 *
 * 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.
 */
<commit_msg>Refactoring facade.go<commit_after>package facade

import (
	"fmt"
	"io"
	"os"
	"runtime"

	"github.com/spf13/cobra"
	"github.com/spiegel-im-spiegel/gocli"
	"github.com/spiegel-im-spiegel/gpgpdump"
)

const (
	//Name is applicatin name
	Name = "gpgpdump"
	//Version is version for applicatin
	Version = "v0.2.0dev"
)

//ExitCode is OS exit code enumeration class
type ExitCode int

const (
	//Normal is OS exit code "normal"
	Normal ExitCode = iota
	//Abnormal is OS exit code "abnormal"
	Abnormal
)

//Int convert integer value
func (c ExitCode) Int() int {
	return int(c)
}

//Stringer method
func (c ExitCode) String() string {
	switch c {
	case Normal:
		return "normal end"
	case Abnormal:
		return "abnormal end"
	default:
		return "unknown"
	}
}

var (
	versionFlag bool      //version flag
	reader      io.Reader //input reader (maybe os.Stdin)
	result      string    //result by parsing OpenPGP packets
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use: Name + " [flags] [PGPfile]",
	RunE: func(cmd *cobra.Command, args []string) error {
		//parse options
		if versionFlag {
			return nil
		}
		opts := parseOpt(cmd)

		//open PGP file
		if len(args) > 0 {
			file, err := os.Open(args[0]) //args[0] is maybe file path
			if err != nil {
				return err
			}
			defer file.Close()
			reader = file
		}

		//parse OpenPGP packets
		p := gpgpdump.NewParse(opts, reader)
		info, err := p.Run()
		if err != nil {
			return err
		}

		//marshal packet info
		if opts.JSON() {
			result, err = info.JSON()
		} else {
			result, err = info.TOML()
		}
		if err != nil {
			return err
		}
		return nil
	},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute(cui *gocli.UI) (exit ExitCode) {
	defer func() {
		//panic hundling
		if r := recover(); r != nil {
			cui.OutputErrln("Panic:", r)
			for depth := 0; ; depth++ {
				pc, _, line, ok := runtime.Caller(depth)
				if !ok {
					break
				}
				cui.OutputErrln(" ->", depth, ":", runtime.FuncForPC(pc).Name(), ": line", line)
			}
			exit = Abnormal
		}
	}()

	//execution
	exit = Normal
	reader = cui.Reader() //default reader; maybe os.Stdin
	result = ""
	if err := RootCmd.Execute(); err != nil {
		//cui.OutputErrln(err) //no need to output error
		exit = Abnormal
		return
	}
	if versionFlag {
		cui.OutputErrln(version())
		return
	}
	cui.Outputln(result)
	return
}

func init() {
	RootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "version for "+Name)
	RootCmd.Flags().BoolP(gpgpdump.ArmorOpt, "a", false, "accepts ASCII input only")
	//RootCmd.Flags().BoolP(gpgpdump.DebugOpt, "d", false, "for debug") //not use
	//RootCmd.Flags().BoolP(gpgpdump.GDumpOpt, "g", false, "selects alternate (GnuPG type) dump format") //not use
	RootCmd.Flags().BoolP(gpgpdump.IntegerOpt, "i", false, "dumps multi-precision integers")
	RootCmd.Flags().BoolP(gpgpdump.JSONOpt, "j", false, "output with JSON format")
	RootCmd.Flags().BoolP(gpgpdump.LiteralOpt, "l", false, "dumps literal packets (tag 11)")
	RootCmd.Flags().BoolP(gpgpdump.MarkerOpt, "m", false, "dumps marker packets (tag 10)")
	RootCmd.Flags().BoolP(gpgpdump.PrivateOpt, "p", false, "dumps private packets (tag 60-63)")
	RootCmd.Flags().BoolP(gpgpdump.UTCOpt, "u", false, "output UTC time")
}

func getBool(cmd *cobra.Command, name string) bool {
	f, err := cmd.Flags().GetBool(name)
	if err != nil {
		panic("invalid option: " + name)
	}
	return f
}

func parseOpt(cmd *cobra.Command) *gpgpdump.Options {
	return gpgpdump.NewOptions(
		gpgpdump.Set(gpgpdump.ArmorOpt, getBool(cmd, gpgpdump.ArmorOpt)),
		//gpgpdump.Set(gpgpdump.DebugOpt, getBool(cmd, gpgpdump.DebugOpt)), //not use
		//gpgpdump.Set(gpgpdump.GDumpOpt, getBool(cmd, gpgpdump.GDumpOpt)), //not use
		gpgpdump.Set(gpgpdump.IntegerOpt, getBool(cmd, gpgpdump.IntegerOpt)),
		gpgpdump.Set(gpgpdump.JSONOpt, getBool(cmd, gpgpdump.JSONOpt)),
		gpgpdump.Set(gpgpdump.LiteralOpt, getBool(cmd, gpgpdump.LiteralOpt)),
		gpgpdump.Set(gpgpdump.MarkerOpt, getBool(cmd, gpgpdump.MarkerOpt)),
		gpgpdump.Set(gpgpdump.PrivateOpt, getBool(cmd, gpgpdump.PrivateOpt)),
		gpgpdump.Set(gpgpdump.UTCOpt, getBool(cmd, gpgpdump.UTCOpt)),
	)
}

func version() string {
	return fmt.Sprintf("%s %s\nCopyright 2016,2017 Spiegel (based on pgpdump by kazu-yamamoto)\nLicensed under Apache License, Version 2.0\n", Name, Version)
}

/* Copyright 2017 Spiegel
 *
 * 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.
 */
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/lomik/carbon-clickhouse/carbon"
	"github.com/lomik/carbon-clickhouse/helper/RowBinary"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"

	_ "net/http/pprof"
)

// Version of carbon-clickhouse
const Version = "0.6"

func httpServe(addr string) (func(), error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return nil, err
	}

	go http.Serve(listener, nil)
	return func() { listener.Close() }, nil
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/carbon-clickhouse/carbon-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	printVersion := flag.Bool("version", false, "Print version")
	cat := flag.String("cat", "", "Print RowBinary file in TabSeparated format")
	bincat := flag.String("recover", "", "Read all good records from corrupted data file. Write binary data to stdout")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *cat != "" {
		reader, err := RowBinary.NewReader(*cat)
		if err != nil {
			log.Fatal(err)
		}

		for {
			metric, err := reader.ReadRecord()
			if err != nil {
				if err == io.EOF {
					return
				}
				log.Fatal(err)
			}

			fmt.Printf("%s\t%#v\t%d\t%s\t%d\n",
				string(metric),
				reader.Value(),
				reader.Timestamp(),
				reader.DaysString(),
				reader.Version(),
			)
		}
	}

	if *bincat != "" {
		reader, err := RowBinary.NewReader(*bincat)
		if err != nil {
			log.Fatal(err)
		}

		io.Copy(os.Stdout, reader)
		return
	}

	if *printDefaultConfig {
		if err = carbon.PrintDefaultConfig(); err != nil {
			log.Fatal(err)
		}
		return
	}

	app := carbon.New(*configFile)

	if err = app.ParseConfig(); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	cfg := app.Config

	if err = zapwriter.ApplyConfig(cfg.Logging); err != nil {
		log.Fatal(err)
	}

	mainLogger := zapwriter.Logger("main")

	/* CONFIG end */

	// pprof
	if cfg.Pprof.Enabled {
		_, err = httpServe(cfg.Pprof.Listen)
		if err != nil {
			mainLogger.Fatal("pprof listen failed", zap.Error(err))
		}
	}

	if err = app.Start(); err != nil {
		mainLogger.Fatal("app start failed", zap.Error(err))
	} else {
		mainLogger.Info("app started")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGUSR1)

		for {
			<-c
			mainLogger.Info("USR1 received. Clear tree cache")
			app.ClearTreeExistsCache()
		}
	}()

	app.Loop()

	mainLogger.Info("app stopped")
}
<commit_msg>version 0.6.1<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/lomik/carbon-clickhouse/carbon"
	"github.com/lomik/carbon-clickhouse/helper/RowBinary"
	"github.com/lomik/zapwriter"
	"go.uber.org/zap"

	_ "net/http/pprof"
)

// Version of carbon-clickhouse
const Version = "0.6.1"

func httpServe(addr string) (func(), error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return nil, err
	}

	go http.Serve(listener, nil)
	return func() { listener.Close() }, nil
}

func main() {
	var err error

	/* CONFIG start */

	configFile := flag.String("config", "/etc/carbon-clickhouse/carbon-clickhouse.conf", "Filename of config")
	printDefaultConfig := flag.Bool("config-print-default", false, "Print default config")
	checkConfig := flag.Bool("check-config", false, "Check config and exit")
	printVersion := flag.Bool("version", false, "Print version")
	cat := flag.String("cat", "", "Print RowBinary file in TabSeparated format")
	bincat := flag.String("recover", "", "Read all good records from corrupted data file. Write binary data to stdout")

	flag.Parse()

	if *printVersion {
		fmt.Print(Version)
		return
	}

	if *cat != "" {
		reader, err := RowBinary.NewReader(*cat)
		if err != nil {
			log.Fatal(err)
		}

		for {
			metric, err := reader.ReadRecord()
			if err != nil {
				if err == io.EOF {
					return
				}
				log.Fatal(err)
			}

			fmt.Printf("%s\t%#v\t%d\t%s\t%d\n",
				string(metric),
				reader.Value(),
				reader.Timestamp(),
				reader.DaysString(),
				reader.Version(),
			)
		}
	}

	if *bincat != "" {
		reader, err := RowBinary.NewReader(*bincat)
		if err != nil {
			log.Fatal(err)
		}

		io.Copy(os.Stdout, reader)
		return
	}

	if *printDefaultConfig {
		if err = carbon.PrintDefaultConfig(); err != nil {
			log.Fatal(err)
		}
		return
	}

	app := carbon.New(*configFile)

	if err = app.ParseConfig(); err != nil {
		log.Fatal(err)
	}

	// config parsed successfully. Exit in check-only mode
	if *checkConfig {
		return
	}

	cfg := app.Config

	if err = zapwriter.ApplyConfig(cfg.Logging); err != nil {
		log.Fatal(err)
	}

	mainLogger := zapwriter.Logger("main")

	/* CONFIG end */

	// pprof
	if cfg.Pprof.Enabled {
		_, err = httpServe(cfg.Pprof.Listen)
		if err != nil {
			mainLogger.Fatal("pprof listen failed", zap.Error(err))
		}
	}

	if err = app.Start(); err != nil {
		mainLogger.Fatal("app start failed", zap.Error(err))
	} else {
		mainLogger.Info("app started")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGUSR1)

		for {
			<-c
			mainLogger.Info("USR1 received. Clear tree cache")
			app.ClearTreeExistsCache()
		}
	}()

	app.Loop()

	mainLogger.Info("app stopped")
}
<|endoftext|>


<commit_before>package admin

import (
	"net"
	"net/http"
	_path "path"
	"time"
)

// Database type
type Database struct {
	app       *App
	transport *http.Transport
	client    *http.Client
}

// ServerValue
var (
	ServerValueTimestamp interface{} = struct {
		SV string `json:".sv"`
	}{"timestamp"}
)

func newDatabase(app *App) *Database {
	tr := &http.Transport{
		IdleConnTimeout: time.Minute * 5,
		MaxIdleConns:    20,
		Dial: func(network, address string) (net.Conn, error) {
			c, err := net.Dial(network, address)
			return c, err
		},
	}
	return &Database{
		app:       app,
		transport: tr,
		client:    &http.Client{Transport: tr},
	}
}

// Ref returns a Reference for a path
func (database *Database) Ref(path string) *Reference {
	path = _path.Clean(path)
	return &Reference{database: database, path: path}
}
<commit_msg>database: implement RefFromURL<commit_after>package admin

import (
	"fmt"
	"net"
	"net/http"
	_url "net/url"
	_path "path"
	"time"
)

// Database type
type Database struct {
	app       *App
	transport *http.Transport
	client    *http.Client
}

// ServerValue
var (
	ServerValueTimestamp interface{} = struct {
		SV string `json:".sv"`
	}{"timestamp"}
)

func newDatabase(app *App) *Database {
	tr := &http.Transport{
		IdleConnTimeout: time.Minute * 5,
		MaxIdleConns:    20,
		Dial: func(network, address string) (net.Conn, error) {
			c, err := net.Dial(network, address)
			return c, err
		},
	}
	return &Database{
		app:       app,
		transport: tr,
		client:    &http.Client{Transport: tr},
	}
}

// Ref returns a Reference for a path
func (database *Database) Ref(path string) *Reference {
	path = _path.Clean(path)
	return &Reference{database: database, path: path}
}

// RefFromURL returns a Reference from an url
func (database *Database) RefFromURL(url string) (*Reference, error) {
	u, err := _url.Parse(url)
	if err != nil {
		return nil, err
	}
	if u.Host != database.app.databaseURL {
		return nil, fmt.Errorf("firebasedatabase: invalid host %v", u.Host)
	}
	return database.Ref(u.Path), nil
}
<|endoftext|>


<commit_before>package mysql

import (
	"database/sql"
	"github.com/davyxu/cellnet"
	"github.com/davyxu/cellnet/peer"
	"github.com/go-sql-driver/mysql"
	"sync"
)

type mysqlConnector struct {
	peer.CorePeerProperty
	peer.CoreContextSet
	peer.CoreSQLParameter

	db      *sql.DB
	dbGuard sync.RWMutex
}

func (self *mysqlConnector) IsReady() bool {
	return self.Raw() != nil
}

func (self *mysqlConnector) Raw() interface{} {
	self.dbGuard.RLock()
	defer self.dbGuard.RUnlock()
	return self.db
}

func (self *mysqlConnector) TypeName() string {
	return "mysql.Connector"
}

func (self *mysqlConnector) Start() cellnet.Peer {

	go self.tryConnect()

	return self
}

func (self *mysqlConnector) tryConnect() {

	config, err := mysql.ParseDSN(self.Address())

	if err != nil {
		log.Errorf("Invalid mysql DSN: %s, %s\n", self.Address(), err.Error())
		return
	}

	log.Infof("Connect to mysql database: %s/%s...", config.Addr, config.DBName)

	db, err := sql.Open("mysql", self.Address())
	if err != nil {
		log.Errorf("Open mysql database error: %s\n", err)
		return
	}

	db.SetMaxOpenConns(int(self.PoolConnCount))
	db.SetMaxIdleConns(int(self.PoolConnCount / 2))

	err = db.Ping()
	if err != nil {
		log.Errorln(err)
		return
	}

	self.dbGuard.Lock()
	self.db = db
	self.dbGuard.Unlock()

	log.SetColor("blue").Infof("Connected to mysql %s/%s", config.Addr, config.DBName)
}

func (self *mysqlConnector) Stop() {

	self.db.Close()
}

func init() {

	peer.RegisterPeerCreator(func() cellnet.Peer {
		self := &mysqlConnector{}
		self.CoreSQLParameter.Init()

		return self
	})
}
<commit_msg>mysql start改为同步模式<commit_after>package mysql

import (
	"database/sql"
	"github.com/davyxu/cellnet"
	"github.com/davyxu/cellnet/peer"
	"github.com/go-sql-driver/mysql"
	"sync"
)

type mysqlConnector struct {
	peer.CorePeerProperty
	peer.CoreContextSet
	peer.CoreSQLParameter

	db      *sql.DB
	dbGuard sync.RWMutex
}

func (self *mysqlConnector) IsReady() bool {
	return self.Raw() != nil
}

func (self *mysqlConnector) Raw() interface{} {
	self.dbGuard.RLock()
	defer self.dbGuard.RUnlock()
	return self.db
}

func (self *mysqlConnector) TypeName() string {
	return "mysql.Connector"
}

func (self *mysqlConnector) Start() cellnet.Peer {

	self.tryConnect()

	return self
}

func (self *mysqlConnector) tryConnect() {

	config, err := mysql.ParseDSN(self.Address())

	if err != nil {
		log.Errorf("Invalid mysql DSN: %s, %s\n", self.Address(), err.Error())
		return
	}

	log.Infof("Connect to mysql database: %s/%s...", config.Addr, config.DBName)

	db, err := sql.Open("mysql", self.Address())
	if err != nil {
		log.Errorf("Open mysql database error: %s\n", err)
		return
	}

	db.SetMaxOpenConns(int(self.PoolConnCount))
	db.SetMaxIdleConns(int(self.PoolConnCount / 2))

	err = db.Ping()
	if err != nil {
		log.Errorln(err)
		return
	}

	self.dbGuard.Lock()
	self.db = db
	self.dbGuard.Unlock()

	log.SetColor("green").Infof("Connected to mysql %s/%s", config.Addr, config.DBName)
}

func (self *mysqlConnector) Stop() {

	self.db.Close()
}

func init() {

	peer.RegisterPeerCreator(func() cellnet.Peer {
		self := &mysqlConnector{}
		self.CoreSQLParameter.Init()

		return self
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

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.
*/

// +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true
// +k8s:defaulter-gen=TypeMeta

// +groupName=meta.cert-manager.io

package v1
<commit_msg>Add '// +gencrdrefdocs:force' to meta/v1 package<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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.
*/

// +k8s:deepcopy-gen=package
// +k8s:openapi-gen=true
// +k8s:defaulter-gen=TypeMeta
// +gencrdrefdocs:force
// +groupName=meta.cert-manager.io

package v1
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 api

import (
	"fmt"
	"strings"
)

// Rules is a collection of api.Rule.
//
// All rules must be evaluated in order to come to a conclusion. While
// it is sufficient to have a single fromEndpoints rule match, none of
// the fromRequires may be violated at the same time.
type Rules []*Rule

func (rs Rules) String() string {
	strRules := make([]string, 0, len(rs))

	for _, r := range rs {
		strRules = append(strRules, fmt.Sprintf("%+v", r))
	}

	return "[" + strings.Join(strRules, ",") + "]"
}
<commit_msg>policy/api: Improve formatting of rules structures<commit_after>// Copyright 2016-2019 Authors of Cilium
//
// 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 api

import (
	"fmt"
	"strings"
)

// Rules is a collection of api.Rule.
//
// All rules must be evaluated in order to come to a conclusion. While
// it is sufficient to have a single fromEndpoints rule match, none of
// the fromRequires may be violated at the same time.
type Rules []*Rule

func (rs Rules) String() string {
	strRules := make([]string, 0, len(rs))

	for _, r := range rs {
		strRules = append(strRules, fmt.Sprintf("%+v", r))
	}

	return "[" + strings.Join(strRules, ",\n") + "]"
}
<|endoftext|>


<commit_before>package resources

import (
	"errors"
	"net"
	"os"

	"github.com/atlassian/smith"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/rest"
)

func GetBundleTprClient(cfg *rest.Config) (*rest.RESTClient, *runtime.Scheme, error) {
	groupVersion := schema.GroupVersion{
		Group:   smith.SmithResourceGroup,
		Version: smith.BundleResourceVersion,
	}

	schemeBuilder := runtime.NewSchemeBuilder(func(scheme *runtime.Scheme) error {
		scheme.AddKnownTypes(
			groupVersion,
			&smith.Bundle{},
			&smith.BundleList{},
			&metav1.ListOptions{},
			&metav1.DeleteOptions{},
		)
		return nil
	})

	scheme := runtime.NewScheme()
	if err := schemeBuilder.AddToScheme(scheme); err != nil {
		return nil, nil, err
	}

	config := *cfg
	config.GroupVersion = &groupVersion
	config.APIPath = "/apis"
	config.ContentType = runtime.ContentTypeJSON
	config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)}

	client, err := rest.RESTClientFor(&config)

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

	return client, scheme, nil
}

func ConfigFromEnv() (*rest.Config, error) {
	host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
	if host == "" || port == "" {
		return nil, errors.New("Unable to load cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")
	}
	CAFile, CertFile, KeyFile := os.Getenv("KUBERNETES_CA_PATH"), os.Getenv("KUBERNETES_CLIENT_CERT"), os.Getenv("KUBERNETES_CLIENT_KEY")
	if CAFile == "" || CertFile == "" || KeyFile == "" {
		return nil, errors.New("Unable to load TLS configuration, KUBERNETES_CA_PATH, KUBERNETES_CLIENT_CERT and KUBERNETES_CLIENT_KEY must be defined")
	}
	return &rest.Config{
		Host: "https://" + net.JoinHostPort(host, port),
		TLSClientConfig: rest.TLSClientConfig{
			CAFile:   CAFile,
			CertFile: CertFile,
			KeyFile:  KeyFile,
		},
	}, nil
}
<commit_msg>Fix for no kind "Status" is registered for version "v1"<commit_after>package resources

import (
	"errors"
	"net"
	"os"

	"github.com/atlassian/smith"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/rest"
)

func GetBundleTprClient(cfg *rest.Config) (*rest.RESTClient, *runtime.Scheme, error) {
	groupVersion := schema.GroupVersion{
		Group:   smith.SmithResourceGroup,
		Version: smith.BundleResourceVersion,
	}

	schemeBuilder := runtime.NewSchemeBuilder(func(scheme *runtime.Scheme) error {
		scheme.AddKnownTypes(
			groupVersion,
			&smith.Bundle{},
			&smith.BundleList{},
			&metav1.ListOptions{},
			&metav1.DeleteOptions{},
		)
		return nil
	})

	scheme := runtime.NewScheme()
	if err := schemeBuilder.AddToScheme(scheme); err != nil {
		return nil, nil, err
	}
	if err := api.AddToScheme(scheme); err != nil {
		return nil, nil, err
	}

	config := *cfg
	config.GroupVersion = &groupVersion
	config.APIPath = "/apis"
	config.ContentType = runtime.ContentTypeJSON
	config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)}

	client, err := rest.RESTClientFor(&config)

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

	return client, scheme, nil
}

func ConfigFromEnv() (*rest.Config, error) {
	host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
	if host == "" || port == "" {
		return nil, errors.New("Unable to load cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")
	}
	CAFile, CertFile, KeyFile := os.Getenv("KUBERNETES_CA_PATH"), os.Getenv("KUBERNETES_CLIENT_CERT"), os.Getenv("KUBERNETES_CLIENT_KEY")
	if CAFile == "" || CertFile == "" || KeyFile == "" {
		return nil, errors.New("Unable to load TLS configuration, KUBERNETES_CA_PATH, KUBERNETES_CLIENT_CERT and KUBERNETES_CLIENT_KEY must be defined")
	}
	return &rest.Config{
		Host: "https://" + net.JoinHostPort(host, port),
		TLSClientConfig: rest.TLSClientConfig{
			CAFile:   CAFile,
			CertFile: CertFile,
			KeyFile:  KeyFile,
		},
	}, nil
}
<|endoftext|>


<commit_before>package cassandra

import (
	"time"

	"github.com/gocql/gocql"
)

// Session is an interface that describes the surface area of interacting with
// a cassandra store.
type Session interface {
	ExecQuery(string) error
	ExecIterQuery(query string) (ScanIter, CloseIter)
	Close()
}

// CQLSession implements a session to cassandra.
type CQLSession struct {
	session *gocql.Session
}

// ScanIter defines the function type returned from ExecIterQuery.
type ScanIter func(...interface{}) bool

// CloseIter is a type returned from ExecIterQuery. When used it wraps the
// close of the underlying iterator.
type CloseIter func() error

// NewCQLSession returns a populated CQLSession struct, or an error using the
// underlying cassandra driver.
func NewCQLSession(ips []string, keyspace string, consistency string, timeout string) (*CQLSession, error) {
	cluster := gocql.NewCluster(ips...)
	cluster.Keyspace = keyspace
	cluster.Consistency = gocql.ParseConsistency(consistency)
	var err error
	cluster.Timeout, err = time.ParseDuration(timeout)
	if err != nil {
		return nil, err
	}

	s, err := cluster.CreateSession()
	if err != nil {
		return nil, err
	}

	return &CQLSession{
		session: s,
	}, nil
}

// ExecQuery executes the provided query against the underlying cassandra
// session.
func (s *CQLSession) ExecQuery(query string) error {
	return s.session.Query(query).Exec()
}

// ExecIterQuery performs an iterated query against the underlying session.
func (s *CQLSession) ExecIterQuery(query string) (ScanIter, CloseIter) {
	iter := s.session.Query(query).Iter()

	return func(dest ...interface{}) bool {
			return iter.Scan(dest...)
		}, func() error {
			return iter.Close()
		}
}

// Close closes the underlying cassandra session.
func (s *CQLSession) Close() {
	s.session.Close()
}

// MockCassSession is used in testing.
type MockCassSession struct {
	query string
}

// ExecQuery implements the interface for testing.
func (s *MockCassSession) ExecQuery(query string) error {
	s.query = query
	return nil
}

// ExecIterQuery implements the interface for testing.
func (s *MockCassSession) ExecIterQuery(query string) (ScanIter, CloseIter) {
	s.query = query
	return func(dest ...interface{}) bool {
			return false
		},
		func() error {
			return nil
		}
}

// Close implements the interface for testing.
func (s *MockCassSession) Close() {}

// LastQuery is used during tests to validate the generated query.
func (s *MockCassSession) LastQuery() string {
	return s.query
}
<commit_msg>Seperate CQL config and session<commit_after>package cassandra

import (
	"time"

	"github.com/gocql/gocql"
)

// Session is an interface that describes the surface area of interacting with
// a cassandra store.
type Session interface {
	ExecQuery(string) error
	ExecIterQuery(query string) (ScanIter, CloseIter)
	Close()
}

// CQLSession implements a session to cassandra.
type CQLSession struct {
	session *gocql.Session
}

// ScanIter defines the function type returned from ExecIterQuery.
type ScanIter func(...interface{}) bool

// CloseIter is a type returned from ExecIterQuery. When used it wraps the
// close of the underlying iterator.
type CloseIter func() error

func NewCQLConfig(ips []string, keyspace string, consistency string, timeout string) (*gocql.ClusterConfig, error) {
	cluster := gocql.NewCluster(ips...)
	cluster.Keyspace = keyspace
	cluster.Consistency = gocql.ParseConsistency(consistency)
	var err error
	cluster.Timeout, err = time.ParseDuration(timeout)
	if err != nil {
		return nil, err
	}
	return cluster, nil
}

func NewCQLSessionFromConfig(cluster *gocql.ClusterConfig) (*CQLSession, error) {
	s, err := cluster.CreateSession()
	if err != nil {
		return nil, err
	}

	return &CQLSession{
		session: s,
	}, nil
}

// NewCQLSession returns a populated CQLSession struct, or an error using the
// underlying cassandra driver.
func NewCQLSession(ips []string, keyspace string, consistency string, timeout string) (*CQLSession, error) {
	cluster, err := NewCQLConfig(ips, keyspace, consistency, timeout)
	if err != nil {
		return nil, err
	}

	return NewCQLSessionFromConfig(cluster)
}

// ExecQuery executes the provided query against the underlying cassandra
// session.
func (s *CQLSession) ExecQuery(query string) error {
	return s.session.Query(query).Exec()
}

// ExecIterQuery performs an iterated query against the underlying session.
func (s *CQLSession) ExecIterQuery(query string) (ScanIter, CloseIter) {
	iter := s.session.Query(query).Iter()

	return func(dest ...interface{}) bool {
			return iter.Scan(dest...)
		}, func() error {
			return iter.Close()
		}
}

// Close closes the underlying cassandra session.
func (s *CQLSession) Close() {
	s.session.Close()
}

// MockCassSession is used in testing.
type MockCassSession struct {
	query string
}

// ExecQuery implements the interface for testing.
func (s *MockCassSession) ExecQuery(query string) error {
	s.query = query
	return nil
}

// ExecIterQuery implements the interface for testing.
func (s *MockCassSession) ExecIterQuery(query string) (ScanIter, CloseIter) {
	s.query = query
	return func(dest ...interface{}) bool {
			return false
		},
		func() error {
			return nil
		}
}

// Close implements the interface for testing.
func (s *MockCassSession) Close() {}

// LastQuery is used during tests to validate the generated query.
func (s *MockCassSession) LastQuery() string {
	return s.query
}
<|endoftext|>


<commit_before>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

import (
	"bytes"
	"errors"
	"net/url"
	"regexp"
	"strconv"
	"time"
)

type Build struct {
	Raw     *BuildResponse
	Job     *Job
	Jenkins *Jenkins
	Base    string
	Depth   int
}

type parameter struct {
	Name  string
	Value string
}

type branch struct {
	SHA1 string
	Name string
}

type BuildRevision struct {
	SHA1   string   `json:"SHA1"`
	Branch []branch `json:"branch"`
}

type Builds struct {
	BuildNumber int64         `json:"buildNumber"`
	BuildResult interface{}   `json:"buildResult"`
	Marked      BuildRevision `json:"marked"`
	Revision    BuildRevision `json:"revision"`
}

type culprit struct {
	AbsoluteUrl string
	FullName    string
}

type generalObj struct {
	Parameters              []parameter              `json:"parameters"`
	Causes                  []map[string]interface{} `json:"causes"`
	BuildsByBranchName      map[string]Builds        `json:"buildsByBranchName"`
	LastBuiltRevision       BuildRevision            `json:"lastBuiltRevision"`
	RemoteUrls              []string                 `json:"remoteUrls"`
	ScmName                 string                   `json:"scmName"`
	MercurialNodeName       string                   `json:"mercurialNodeName"`
	MercurialRevisionNumber string                   `json:"mercurialRevisionNumber"`
	Subdir                  interface{}              `json:"subdir"`
	TotalCount              int64
	UrlName                 string
}

type TestResult struct {
	Duration  int64 `json:"duration"`
	Empty     bool  `json:"empty"`
	FailCount int64 `json:"failCount"`
	PassCount int64 `json:"passCount"`
	SkipCount int64 `json:"skipCount"`
	Suites    []struct {
		Cases []struct {
			Age             int64       `json:"age"`
			ClassName       string      `json:"className"`
			Duration        int64       `json:"duration"`
			ErrorDetails    interface{} `json:"errorDetails"`
			ErrorStackTrace interface{} `json:"errorStackTrace"`
			FailedSince     int64       `json:"failedSince"`
			Name            string      `json:"name"`
			Skipped         bool        `json:"skipped"`
			SkippedMessage  interface{} `json:"skippedMessage"`
			Status          string      `json:"status"`
			Stderr          interface{} `json:"stderr"`
			Stdout          interface{} `json:"stdout"`
		} `json:"cases"`
		Duration  int64       `json:"duration"`
		ID        interface{} `json:"id"`
		Name      string      `json:"name"`
		Stderr    interface{} `json:"stderr"`
		Stdout    interface{} `json:"stdout"`
		Timestamp interface{} `json:"timestamp"`
	} `json:"suites"`
}

type BuildResponse struct {
	Actions   []generalObj
	Artifacts []struct {
		DisplayPath  string `json:"displayPath"`
		FileName     string `json:"fileName"`
		RelativePath string `json:"relativePath"`
	} `json:"artifacts"`
	Building  bool   `json:"building"`
	BuiltOn   string `json:"builtOn"`
	ChangeSet struct {
		Items []struct {
			AffectedPaths []string `json:"affectedPaths"`
			Author        struct {
				AbsoluteUrl string `json:"absoluteUrl"`
				FullName    string `json:"fullName"`
			} `json:"author"`
			Comment  string `json:"comment"`
			CommitID string `json:"commitId"`
			Date     string `json:"date"`
			ID       string `json:"id"`
			Msg      string `json:"msg"`
			Paths    []struct {
				EditType string `json:"editType"`
				File     string `json:"file"`
			} `json:"paths"`
			Timestamp int64 `json:"timestamp"`
		} `json:"items"`
		Kind      string `json:"kind"`
		Revisions []struct {
			Module   string
			Revision int
		} `json:"revision"`
	} `json:"changeSet"`
	Culprits          []culprit   `json:"culprits"`
	Description       interface{} `json:"description"`
	Duration          int64       `json:"duration"`
	EstimatedDuration int64       `json:"estimatedDuration"`
	Executor          interface{} `json:"executor"`
	FullDisplayName   string      `json:"fullDisplayName"`
	ID                string      `json:"id"`
	KeepLog           bool        `json:"keepLog"`
	Number            int64       `json:"number"`
	QueueID           int64       `json:"queueId"`
	Result            string      `json:"result"`
	Timestamp         int64       `json:"timestamp"`
	URL               string      `json:"url"`
	MavenArtifacts    interface{} `json:"mavenArtifacts"`
	MavenVersionUsed  string      `json:"mavenVersionUsed"`
	FingerPrint       []FingerPrintResponse
	Runs              []struct {
		Number int64
		URL    string
	} `json:"runs"`
}

// Builds
func (b *Build) Info() *BuildResponse {
	return b.Raw
}

func (b *Build) GetActions() []generalObj {
	return b.Raw.Actions
}

func (b *Build) GetUrl() string {
	return b.Raw.URL
}

func (b *Build) GetBuildNumber() int64 {
	return b.Raw.Number
}
func (b *Build) GetResult() string {
	return b.Raw.Result
}

func (b *Build) GetArtifacts() []Artifact {
	artifacts := make([]Artifact, len(b.Raw.Artifacts))
	for i, artifact := range b.Raw.Artifacts {
		artifacts[i] = Artifact{
			Jenkins:  b.Jenkins,
			Build:    b,
			FileName: artifact.FileName,
			Path:     b.Base + "/artifact/" + artifact.RelativePath,
		}
	}
	return artifacts
}

func (b *Build) GetCulprits() []culprit {
	return b.Raw.Culprits
}

func (b *Build) Stop() (bool, error) {
	if b.IsRunning() {
		response, err := b.Jenkins.Requester.Post(b.Base+"/stop", nil, nil, nil)
		if err != nil {
			return false, err
		}
		return response.StatusCode == 200, nil
	}
	return true, nil
}

func (b *Build) GetConsoleOutput() string {
	url := b.Base + "/consoleText"
	var content string
	b.Jenkins.Requester.GetXML(url, &content, nil)
	return content
}

func (b *Build) GetCauses() ([]map[string]interface{}, error) {
	_, err := b.Poll()
	if err != nil {
		return nil, err
	}
	for _, a := range b.Raw.Actions {
		if a.Causes != nil {
			return a.Causes, nil
		}
	}
	return nil, errors.New("No Causes")
}

func (b *Build) GetParameters() []parameter {
	for _, a := range b.Raw.Actions {
		if a.Parameters != nil {
			return a.Parameters
		}
	}
	return nil
}

func (b *Build) GetInjectedEnvVars() (map[string]string, error) {
	var envVars struct {
		EnvMap map[string]string `json:"envMap"`
	}
	endpoint := b.Base + "/injectedEnvVars"
	_, err := b.Jenkins.Requester.GetJSON(endpoint, &envVars, nil)
	if err != nil {
		return envVars.EnvMap, err
	}
	return envVars.EnvMap, nil
}

func (b *Build) GetDownstreamBuilds() ([]*Build, error) {
	result := make([]*Build, 0)
	downstreamJobs, err := b.Job.GetDownstreamJobs()
	if err != nil {
		return nil, err
	}
	for _, job := range downstreamJobs {
		allBuildIDs, err := job.GetAllBuildIds()
		if err != nil {
			return nil, err
		}
		for _, buildID := range allBuildIDs {
			build, err := job.GetBuild(buildID.Number)
			if err != nil {
				return nil, err
			}
			upstreamBuild, _ := build.GetUpstreamBuild()
			// cannot compare only id, it can be from different job
			if b.GetUrl() == upstreamBuild.GetUrl() {
				result = append(result, build)
				break
			}
		}
	}
	return result, nil
}

func (b *Build) GetDownstreamJobNames() []string {
	result := make([]string, 0)
	downstreamJobs := b.Job.GetDownstreamJobsMetadata()
	fingerprints := b.GetAllFingerPrints()
	for _, fingerprint := range fingerprints {
		for _, usage := range fingerprint.Raw.Usage {
			for _, job := range downstreamJobs {
				if job.Name == usage.Name {
					result = append(result, job.Name)
				}
			}
		}
	}
	return result
}

func (b *Build) GetAllFingerPrints() []*FingerPrint {
	b.Poll(3)
	result := make([]*FingerPrint, len(b.Raw.FingerPrint))
	for i, f := range b.Raw.FingerPrint {
		result[i] = &FingerPrint{Jenkins: b.Jenkins, Base: "/fingerprint/", Id: f.Hash, Raw: &f}
	}
	return result
}

func (b *Build) GetUpstreamJob() (*Job, error) {
	causes, err := b.GetCauses()
	if err != nil {
		return nil, err
	}
	if len(causes) > 0 {
		if job, ok := causes[0]["upstreamProject"]; ok {
			return b.Jenkins.GetJob(job.(string))
		}
	}
	return nil, errors.New("Unable to get Upstream Job")
}

func (b *Build) GetUpstreamBuildNumber() (int64, error) {
	causes, err := b.GetCauses()
	if err != nil {
		return 0, err
	}
	if len(causes) > 0 {
		if build, ok := causes[0]["upstreamBuild"]; ok {
			switch t := build.(type) {
			default:
				return t.(int64), nil
			case float64:
				return int64(t), nil
			}
		}
	}
	return 0, nil
}

func (b *Build) GetUpstreamBuild() (*Build, error) {
	job, err := b.GetUpstreamJob()
	if err != nil {
		return nil, err
	}
	if job != nil {
		buildNumber, err := b.GetUpstreamBuildNumber()
		if err == nil {
			return job.GetBuild(buildNumber)
		}
	}
	return nil, errors.New("Build not found")
}

func (b *Build) GetMatrixRuns() ([]*Build, error) {
	_, err := b.Poll(0)
	if err != nil {
		return nil, err
	}
	runs := b.Raw.Runs
	result := make([]*Build, len(b.Raw.Runs))
	r, _ := regexp.Compile(`job/(.*?)/(.*?)/(\d+)/`)

	for i, run := range runs {
		result[i] = &Build{Jenkins: b.Jenkins, Job: b.Job, Raw: new(BuildResponse), Depth: 1, Base: "/" + r.FindString(run.URL)}
		result[i].Poll()
	}
	return result, nil
}

func (b *Build) GetResultSet() (*TestResult, error) {

	url := b.Base + "/testReport"
	var report TestResult

	_, err := b.Jenkins.Requester.GetJSON(url, &report, nil)
	if err != nil {
		return nil, err
	}

	return &report, nil

}

func (b *Build) GetTimestamp() time.Time {
	msInt := int64(b.Raw.Timestamp)
	return time.Unix(0, msInt*int64(time.Millisecond))
}

func (b *Build) GetDuration() int64 {
	return b.Raw.Duration
}

func (b *Build) GetRevision() string {
	vcs := b.Raw.ChangeSet.Kind

	if vcs == "git" || vcs == "hg" {
		for _, a := range b.Raw.Actions {
			if a.LastBuiltRevision.SHA1 != "" {
				return a.LastBuiltRevision.SHA1
			}
			if a.MercurialRevisionNumber != "" {
				return a.MercurialRevisionNumber
			}
		}
	} else if vcs == "svn" {
		return strconv.Itoa(b.Raw.ChangeSet.Revisions[0].Revision)
	}
	return ""
}

func (b *Build) GetRevisionBranch() string {
	vcs := b.Raw.ChangeSet.Kind
	if vcs == "git" {
		for _, a := range b.Raw.Actions {
			if len(a.LastBuiltRevision.Branch) > 0 && a.LastBuiltRevision.Branch[0].SHA1 != "" {
				return a.LastBuiltRevision.Branch[0].SHA1
			}
		}
	} else {
		panic("Not implemented")
	}
	return ""
}

func (b *Build) IsGood() bool {
	return (!b.IsRunning() && b.Raw.Result == STATUS_SUCCESS)
}

func (b *Build) IsRunning() bool {
	_, err := b.Poll()
	if err != nil {
		return false
	}
	return b.Raw.Building
}

func (b *Build) SetDescription(description string) error {
	data := url.Values{}
	data.Set("description", description)
	_, err := b.Jenkins.Requester.Post(b.Base+"/submitDescription", bytes.NewBufferString(data.Encode()), nil, nil)
	return err
}

// Poll for current data. Optional parameter - depth.
// More about depth here: https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API
func (b *Build) Poll(options ...interface{}) (int, error) {
	depth := "-1"

	for _, o := range options {
		switch v := o.(type) {
		case string:
			depth = v
		case int:
			depth = strconv.Itoa(v)
		case int64:
			depth = strconv.FormatInt(v, 10)
		}
	}
	if depth == "-1" {
		depth = strconv.Itoa(b.Depth)
	}

	qr := map[string]string{
		"depth": depth,
	}
	response, err := b.Jenkins.Requester.GetJSON(b.Base, b.Raw, qr)
	if err != nil {
		return 0, err
	}
	return response.StatusCode, nil
}
<commit_msg>Change culprit to Culprit (#103)<commit_after>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

import (
	"bytes"
	"errors"
	"net/url"
	"regexp"
	"strconv"
	"time"
)

type Build struct {
	Raw     *BuildResponse
	Job     *Job
	Jenkins *Jenkins
	Base    string
	Depth   int
}

type parameter struct {
	Name  string
	Value string
}

type branch struct {
	SHA1 string
	Name string
}

type BuildRevision struct {
	SHA1   string   `json:"SHA1"`
	Branch []branch `json:"branch"`
}

type Builds struct {
	BuildNumber int64         `json:"buildNumber"`
	BuildResult interface{}   `json:"buildResult"`
	Marked      BuildRevision `json:"marked"`
	Revision    BuildRevision `json:"revision"`
}

type Culprit struct {
	AbsoluteUrl string
	FullName    string
}

type generalObj struct {
	Parameters              []parameter              `json:"parameters"`
	Causes                  []map[string]interface{} `json:"causes"`
	BuildsByBranchName      map[string]Builds        `json:"buildsByBranchName"`
	LastBuiltRevision       BuildRevision            `json:"lastBuiltRevision"`
	RemoteUrls              []string                 `json:"remoteUrls"`
	ScmName                 string                   `json:"scmName"`
	MercurialNodeName       string                   `json:"mercurialNodeName"`
	MercurialRevisionNumber string                   `json:"mercurialRevisionNumber"`
	Subdir                  interface{}              `json:"subdir"`
	TotalCount              int64
	UrlName                 string
}

type TestResult struct {
	Duration  int64 `json:"duration"`
	Empty     bool  `json:"empty"`
	FailCount int64 `json:"failCount"`
	PassCount int64 `json:"passCount"`
	SkipCount int64 `json:"skipCount"`
	Suites    []struct {
		Cases []struct {
			Age             int64       `json:"age"`
			ClassName       string      `json:"className"`
			Duration        int64       `json:"duration"`
			ErrorDetails    interface{} `json:"errorDetails"`
			ErrorStackTrace interface{} `json:"errorStackTrace"`
			FailedSince     int64       `json:"failedSince"`
			Name            string      `json:"name"`
			Skipped         bool        `json:"skipped"`
			SkippedMessage  interface{} `json:"skippedMessage"`
			Status          string      `json:"status"`
			Stderr          interface{} `json:"stderr"`
			Stdout          interface{} `json:"stdout"`
		} `json:"cases"`
		Duration  int64       `json:"duration"`
		ID        interface{} `json:"id"`
		Name      string      `json:"name"`
		Stderr    interface{} `json:"stderr"`
		Stdout    interface{} `json:"stdout"`
		Timestamp interface{} `json:"timestamp"`
	} `json:"suites"`
}

type BuildResponse struct {
	Actions   []generalObj
	Artifacts []struct {
		DisplayPath  string `json:"displayPath"`
		FileName     string `json:"fileName"`
		RelativePath string `json:"relativePath"`
	} `json:"artifacts"`
	Building  bool   `json:"building"`
	BuiltOn   string `json:"builtOn"`
	ChangeSet struct {
		Items []struct {
			AffectedPaths []string `json:"affectedPaths"`
			Author        struct {
				AbsoluteUrl string `json:"absoluteUrl"`
				FullName    string `json:"fullName"`
			} `json:"author"`
			Comment  string `json:"comment"`
			CommitID string `json:"commitId"`
			Date     string `json:"date"`
			ID       string `json:"id"`
			Msg      string `json:"msg"`
			Paths    []struct {
				EditType string `json:"editType"`
				File     string `json:"file"`
			} `json:"paths"`
			Timestamp int64 `json:"timestamp"`
		} `json:"items"`
		Kind      string `json:"kind"`
		Revisions []struct {
			Module   string
			Revision int
		} `json:"revision"`
	} `json:"changeSet"`
	Culprits          []Culprit   `json:"culprits"`
	Description       interface{} `json:"description"`
	Duration          int64       `json:"duration"`
	EstimatedDuration int64       `json:"estimatedDuration"`
	Executor          interface{} `json:"executor"`
	FullDisplayName   string      `json:"fullDisplayName"`
	ID                string      `json:"id"`
	KeepLog           bool        `json:"keepLog"`
	Number            int64       `json:"number"`
	QueueID           int64       `json:"queueId"`
	Result            string      `json:"result"`
	Timestamp         int64       `json:"timestamp"`
	URL               string      `json:"url"`
	MavenArtifacts    interface{} `json:"mavenArtifacts"`
	MavenVersionUsed  string      `json:"mavenVersionUsed"`
	FingerPrint       []FingerPrintResponse
	Runs              []struct {
		Number int64
		URL    string
	} `json:"runs"`
}

// Builds
func (b *Build) Info() *BuildResponse {
	return b.Raw
}

func (b *Build) GetActions() []generalObj {
	return b.Raw.Actions
}

func (b *Build) GetUrl() string {
	return b.Raw.URL
}

func (b *Build) GetBuildNumber() int64 {
	return b.Raw.Number
}
func (b *Build) GetResult() string {
	return b.Raw.Result
}

func (b *Build) GetArtifacts() []Artifact {
	artifacts := make([]Artifact, len(b.Raw.Artifacts))
	for i, artifact := range b.Raw.Artifacts {
		artifacts[i] = Artifact{
			Jenkins:  b.Jenkins,
			Build:    b,
			FileName: artifact.FileName,
			Path:     b.Base + "/artifact/" + artifact.RelativePath,
		}
	}
	return artifacts
}

func (b *Build) GetCulprits() []Culprit {
	return b.Raw.Culprits
}

func (b *Build) Stop() (bool, error) {
	if b.IsRunning() {
		response, err := b.Jenkins.Requester.Post(b.Base+"/stop", nil, nil, nil)
		if err != nil {
			return false, err
		}
		return response.StatusCode == 200, nil
	}
	return true, nil
}

func (b *Build) GetConsoleOutput() string {
	url := b.Base + "/consoleText"
	var content string
	b.Jenkins.Requester.GetXML(url, &content, nil)
	return content
}

func (b *Build) GetCauses() ([]map[string]interface{}, error) {
	_, err := b.Poll()
	if err != nil {
		return nil, err
	}
	for _, a := range b.Raw.Actions {
		if a.Causes != nil {
			return a.Causes, nil
		}
	}
	return nil, errors.New("No Causes")
}

func (b *Build) GetParameters() []parameter {
	for _, a := range b.Raw.Actions {
		if a.Parameters != nil {
			return a.Parameters
		}
	}
	return nil
}

func (b *Build) GetInjectedEnvVars() (map[string]string, error) {
	var envVars struct {
		EnvMap map[string]string `json:"envMap"`
	}
	endpoint := b.Base + "/injectedEnvVars"
	_, err := b.Jenkins.Requester.GetJSON(endpoint, &envVars, nil)
	if err != nil {
		return envVars.EnvMap, err
	}
	return envVars.EnvMap, nil
}

func (b *Build) GetDownstreamBuilds() ([]*Build, error) {
	result := make([]*Build, 0)
	downstreamJobs, err := b.Job.GetDownstreamJobs()
	if err != nil {
		return nil, err
	}
	for _, job := range downstreamJobs {
		allBuildIDs, err := job.GetAllBuildIds()
		if err != nil {
			return nil, err
		}
		for _, buildID := range allBuildIDs {
			build, err := job.GetBuild(buildID.Number)
			if err != nil {
				return nil, err
			}
			upstreamBuild, _ := build.GetUpstreamBuild()
			// cannot compare only id, it can be from different job
			if b.GetUrl() == upstreamBuild.GetUrl() {
				result = append(result, build)
				break
			}
		}
	}
	return result, nil
}

func (b *Build) GetDownstreamJobNames() []string {
	result := make([]string, 0)
	downstreamJobs := b.Job.GetDownstreamJobsMetadata()
	fingerprints := b.GetAllFingerPrints()
	for _, fingerprint := range fingerprints {
		for _, usage := range fingerprint.Raw.Usage {
			for _, job := range downstreamJobs {
				if job.Name == usage.Name {
					result = append(result, job.Name)
				}
			}
		}
	}
	return result
}

func (b *Build) GetAllFingerPrints() []*FingerPrint {
	b.Poll(3)
	result := make([]*FingerPrint, len(b.Raw.FingerPrint))
	for i, f := range b.Raw.FingerPrint {
		result[i] = &FingerPrint{Jenkins: b.Jenkins, Base: "/fingerprint/", Id: f.Hash, Raw: &f}
	}
	return result
}

func (b *Build) GetUpstreamJob() (*Job, error) {
	causes, err := b.GetCauses()
	if err != nil {
		return nil, err
	}
	if len(causes) > 0 {
		if job, ok := causes[0]["upstreamProject"]; ok {
			return b.Jenkins.GetJob(job.(string))
		}
	}
	return nil, errors.New("Unable to get Upstream Job")
}

func (b *Build) GetUpstreamBuildNumber() (int64, error) {
	causes, err := b.GetCauses()
	if err != nil {
		return 0, err
	}
	if len(causes) > 0 {
		if build, ok := causes[0]["upstreamBuild"]; ok {
			switch t := build.(type) {
			default:
				return t.(int64), nil
			case float64:
				return int64(t), nil
			}
		}
	}
	return 0, nil
}

func (b *Build) GetUpstreamBuild() (*Build, error) {
	job, err := b.GetUpstreamJob()
	if err != nil {
		return nil, err
	}
	if job != nil {
		buildNumber, err := b.GetUpstreamBuildNumber()
		if err == nil {
			return job.GetBuild(buildNumber)
		}
	}
	return nil, errors.New("Build not found")
}

func (b *Build) GetMatrixRuns() ([]*Build, error) {
	_, err := b.Poll(0)
	if err != nil {
		return nil, err
	}
	runs := b.Raw.Runs
	result := make([]*Build, len(b.Raw.Runs))
	r, _ := regexp.Compile(`job/(.*?)/(.*?)/(\d+)/`)

	for i, run := range runs {
		result[i] = &Build{Jenkins: b.Jenkins, Job: b.Job, Raw: new(BuildResponse), Depth: 1, Base: "/" + r.FindString(run.URL)}
		result[i].Poll()
	}
	return result, nil
}

func (b *Build) GetResultSet() (*TestResult, error) {

	url := b.Base + "/testReport"
	var report TestResult

	_, err := b.Jenkins.Requester.GetJSON(url, &report, nil)
	if err != nil {
		return nil, err
	}

	return &report, nil

}

func (b *Build) GetTimestamp() time.Time {
	msInt := int64(b.Raw.Timestamp)
	return time.Unix(0, msInt*int64(time.Millisecond))
}

func (b *Build) GetDuration() int64 {
	return b.Raw.Duration
}

func (b *Build) GetRevision() string {
	vcs := b.Raw.ChangeSet.Kind

	if vcs == "git" || vcs == "hg" {
		for _, a := range b.Raw.Actions {
			if a.LastBuiltRevision.SHA1 != "" {
				return a.LastBuiltRevision.SHA1
			}
			if a.MercurialRevisionNumber != "" {
				return a.MercurialRevisionNumber
			}
		}
	} else if vcs == "svn" {
		return strconv.Itoa(b.Raw.ChangeSet.Revisions[0].Revision)
	}
	return ""
}

func (b *Build) GetRevisionBranch() string {
	vcs := b.Raw.ChangeSet.Kind
	if vcs == "git" {
		for _, a := range b.Raw.Actions {
			if len(a.LastBuiltRevision.Branch) > 0 && a.LastBuiltRevision.Branch[0].SHA1 != "" {
				return a.LastBuiltRevision.Branch[0].SHA1
			}
		}
	} else {
		panic("Not implemented")
	}
	return ""
}

func (b *Build) IsGood() bool {
	return (!b.IsRunning() && b.Raw.Result == STATUS_SUCCESS)
}

func (b *Build) IsRunning() bool {
	_, err := b.Poll()
	if err != nil {
		return false
	}
	return b.Raw.Building
}

func (b *Build) SetDescription(description string) error {
	data := url.Values{}
	data.Set("description", description)
	_, err := b.Jenkins.Requester.Post(b.Base+"/submitDescription", bytes.NewBufferString(data.Encode()), nil, nil)
	return err
}

// Poll for current data. Optional parameter - depth.
// More about depth here: https://wiki.jenkins-ci.org/display/JENKINS/Remote+access+API
func (b *Build) Poll(options ...interface{}) (int, error) {
	depth := "-1"

	for _, o := range options {
		switch v := o.(type) {
		case string:
			depth = v
		case int:
			depth = strconv.Itoa(v)
		case int64:
			depth = strconv.FormatInt(v, 10)
		}
	}
	if depth == "-1" {
		depth = strconv.Itoa(b.Depth)
	}

	qr := map[string]string{
		"depth": depth,
	}
	response, err := b.Jenkins.Requester.GetJSON(b.Base, b.Raw, qr)
	if err != nil {
		return 0, err
	}
	return response.StatusCode, nil
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
//
// 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 version

import "fmt"

const MAJOR uint = 2
const MINOR uint = 31
const PATCH uint = 0

var COMMIT string = ""
var IDENTIFIER string = ""
var METADATA string = ""

func Version() string {
	var suffix string = ""
	if len(IDENTIFIER) > 0 {
		suffix = fmt.Sprintf("-%s", IDENTIFIER)
	}

	if len(COMMIT) > 0 || len(METADATA) > 0 {
		suffix = suffix + "+"
	}

	if len(COMMIT) > 0 {
		suffix = fmt.Sprintf("%s"+"commit.%s", suffix, COMMIT)

	}

	if len(METADATA) > 0 {
		if len(COMMIT) > 0 {
			suffix = suffix + "."
		}
		suffix = suffix + METADATA
	}

	return fmt.Sprintf("%d.%d.%d%s", MAJOR, MINOR, PATCH, suffix)
}
<commit_msg>v2.32.0<commit_after>// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
//
// 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 version

import "fmt"

const MAJOR uint = 2
const MINOR uint = 32
const PATCH uint = 0

var COMMIT string = ""
var IDENTIFIER string = ""
var METADATA string = ""

func Version() string {
	var suffix string = ""
	if len(IDENTIFIER) > 0 {
		suffix = fmt.Sprintf("-%s", IDENTIFIER)
	}

	if len(COMMIT) > 0 || len(METADATA) > 0 {
		suffix = suffix + "+"
	}

	if len(COMMIT) > 0 {
		suffix = fmt.Sprintf("%s"+"commit.%s", suffix, COMMIT)

	}

	if len(METADATA) > 0 {
		if len(COMMIT) > 0 {
			suffix = suffix + "."
		}
		suffix = suffix + METADATA
	}

	return fmt.Sprintf("%d.%d.%d%s", MAJOR, MINOR, PATCH, suffix)
}
<|endoftext|>