<commit_before>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

// Eris-RT is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Eris-RT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.

// version provides the current Eris-DB version and a VersionIdentifier
// for the modules to identify their version with.

package version

import (
	"fmt"
)

// IMPORTANT: this version number needs to be manually kept
// in sync at the bottom of this file for the deployment scripts to parse
// the version number.
const (
	// Client identifier to advertise over the network
	erisClientIdentifier = "eris-db"
	// Major version component of the current release
	erisVersionMajor = 0
	// Minor version component of the current release
	erisVersionMinor = 12
	// Patch version component of the current release
	erisVersionPatch = 0
)

var erisVersion *VersionIdentifier

func init() {
	erisVersion = New(erisClientIdentifier, erisVersionMajor,
		erisVersionMinor, erisVersionPatch)
}

//------------------------------------------------------------------------------
// versioning globally for Eris-DB and scoped for modules

type VersionIdentifier struct {
	clientIdentifier string
	versionMajor     uint8
	versionMinor     uint8
	versionPatch     uint8
}

func New(client string, major, minor, patch uint8) *VersionIdentifier {
	v := new(VersionIdentifier)
	v.clientIdentifier = client
	v.versionMajor = major
	v.versionMinor = minor
	v.versionPatch = patch
	return v
}

// GetVersionString returns `client-major.minor.patch` for Eris-DB
// without a receiver, or for the version called on.
// MakeVersionString builds the same version string with provided parameters.
func GetVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetVersionString() string {
	return fmt.Sprintf("%s-%d.%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor, v.versionPatch)
}

// note: the arguments are passed in as int (rather than uint8)
// because on asserting the version constructed from the configuration file
// the casting of an int to uint8 is uglier than expanding the type range here.
// Should the configuration file have an invalid integer (that could not convert)
// then this will equally be reflected in a failed assertion of the version string.
func MakeVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d.%d", client, major, minor, patch)
}

// GetMinorVersionString returns `client-major.minor` for Eris-DB
// without a receiver, or for the version called on.
// MakeMinorVersionString builds the same version string with
// provided parameters.
func GetMinorVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetMinorVersionString() string {
	return fmt.Sprintf("%s-%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor)
}

// note: similar remark applies here on the use of `int` over `uint8`
// for the arguments as above for MakeVersionString()
func MakeMinorVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d", client, major, minor)
}

// GetVersion returns a tuple of client, major, minor, and patch as types,
// either for Eris-DB without a receiver or the called version structure.
func GetVersion() (client string, major, minor, patch uint8) {
	return erisVersion.GetVersion()
}
func (version *VersionIdentifier) GetVersion() (
	client string, major, minor, patch uint8) {
	return version.clientIdentifier, version.versionMajor, version.versionMinor,
		version.versionPatch
}

//------------------------------------------------------------------------------
// Matching functions

// MatchesMinorVersion matches the client identifier, major and minor version
// number of the reference version identifier to be equal with the receivers.
func MatchesMinorVersion(referenceVersion *VersionIdentifier) bool {
	return erisVersion.MatchesMinorVersion(referenceVersion)
}
func (version *VersionIdentifier) MatchesMinorVersion(
	referenceVersion *VersionIdentifier) bool {
	referenceClient, referenceMajor, referenceMinor, _ := referenceVersion.GetVersion()
	return version.clientIdentifier == referenceClient &&
		version.versionMajor == referenceMajor &&
		version.versionMinor == referenceMinor
}

//------------------------------------------------------------------------------
// Version number for tests/build_tool.sh

// IMPORTANT: Eris-DB version must be on the last line of this file for
// the deployment script tests/build_tool.sh to pick up the right label.
const VERSION = "0.16.0"
<commit_msg>version: update eris-db version to 0.16.0<commit_after>// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT

// Eris-RT is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Eris-RT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.

// version provides the current Eris-DB version and a VersionIdentifier
// for the modules to identify their version with.

package version

import (
	"fmt"
)

// IMPORTANT: this version number needs to be manually kept
// in sync at the bottom of this file for the deployment scripts to parse
// the version number.
const (
	// Client identifier to advertise over the network
	erisClientIdentifier = "eris-db"
	// Major version component of the current release
	erisVersionMajor = 0
	// Minor version component of the current release
	erisVersionMinor = 16
	// Patch version component of the current release
	erisVersionPatch = 0
)

var erisVersion *VersionIdentifier

func init() {
	erisVersion = New(erisClientIdentifier, erisVersionMajor,
		erisVersionMinor, erisVersionPatch)
}

//------------------------------------------------------------------------------
// versioning globally for Eris-DB and scoped for modules

type VersionIdentifier struct {
	clientIdentifier string
	versionMajor     uint8
	versionMinor     uint8
	versionPatch     uint8
}

func New(client string, major, minor, patch uint8) *VersionIdentifier {
	v := new(VersionIdentifier)
	v.clientIdentifier = client
	v.versionMajor = major
	v.versionMinor = minor
	v.versionPatch = patch
	return v
}

// GetVersionString returns `client-major.minor.patch` for Eris-DB
// without a receiver, or for the version called on.
// MakeVersionString builds the same version string with provided parameters.
func GetVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetVersionString() string {
	return fmt.Sprintf("%s-%d.%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor, v.versionPatch)
}

// note: the arguments are passed in as int (rather than uint8)
// because on asserting the version constructed from the configuration file
// the casting of an int to uint8 is uglier than expanding the type range here.
// Should the configuration file have an invalid integer (that could not convert)
// then this will equally be reflected in a failed assertion of the version string.
func MakeVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d.%d", client, major, minor, patch)
}

// GetMinorVersionString returns `client-major.minor` for Eris-DB
// without a receiver, or for the version called on.
// MakeMinorVersionString builds the same version string with
// provided parameters.
func GetMinorVersionString() string { return erisVersion.GetVersionString() }
func (v *VersionIdentifier) GetMinorVersionString() string {
	return fmt.Sprintf("%s-%d.%d", v.clientIdentifier, v.versionMajor,
		v.versionMinor)
}

// note: similar remark applies here on the use of `int` over `uint8`
// for the arguments as above for MakeVersionString()
func MakeMinorVersionString(client string, major, minor, patch int) string {
	return fmt.Sprintf("%s-%d.%d", client, major, minor)
}

// GetVersion returns a tuple of client, major, minor, and patch as types,
// either for Eris-DB without a receiver or the called version structure.
func GetVersion() (client string, major, minor, patch uint8) {
	return erisVersion.GetVersion()
}
func (version *VersionIdentifier) GetVersion() (
	client string, major, minor, patch uint8) {
	return version.clientIdentifier, version.versionMajor, version.versionMinor,
		version.versionPatch
}

//------------------------------------------------------------------------------
// Matching functions

// MatchesMinorVersion matches the client identifier, major and minor version
// number of the reference version identifier to be equal with the receivers.
func MatchesMinorVersion(referenceVersion *VersionIdentifier) bool {
	return erisVersion.MatchesMinorVersion(referenceVersion)
}
func (version *VersionIdentifier) MatchesMinorVersion(
	referenceVersion *VersionIdentifier) bool {
	referenceClient, referenceMajor, referenceMinor, _ := referenceVersion.GetVersion()
	return version.clientIdentifier == referenceClient &&
		version.versionMajor == referenceMajor &&
		version.versionMinor == referenceMinor
}

//------------------------------------------------------------------------------
// Version number for tests/build_tool.sh

// IMPORTANT: Eris-DB version must be on the last line of this file for
// the deployment script tests/build_tool.sh to pick up the right label.
const VERSION = "0.16.0"
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package server

import (
	"context"
	"math"
	"time"

	"github.com/shirou/gopsutil/net"

	"github.com/admpub/log"
)

var (
	realTimeStatus                 *RealTimeStatus
	CancelRealTimeStatusCollection func()
)

func RealTimeStatusIsListening() bool {
	return realTimeStatus != nil
}

func ListenRealTimeStatus() {
	if !RealTimeStatusIsListening() {
		realTimeStatus = NewRealTimeStatus(time.Second*2, 80)
	}
	ctx, cancel := context.WithCancel(context.Background())
	go realTimeStatus.Listen(ctx)
	CancelRealTimeStatusCollection = func() {
		cancel()
		realTimeStatus = nil
	}
}

func NewRealTimeStatus(interval time.Duration, maxSize int) *RealTimeStatus {
	return &RealTimeStatus{
		max:      maxSize,
		interval: interval,
		CPU:      TimeSeries{},
		Mem:      TimeSeries{},
		Net:      NewNetIOTimeSeries(),
	}
}

func NewNetIOTimeSeries() NetIOTimeSeries {
	return NetIOTimeSeries{
		lastBytesSent:   LastTimeValue{},
		lastBytesRecv:   LastTimeValue{},
		lastPacketsSent: LastTimeValue{},
		lastPacketsRecv: LastTimeValue{},
		BytesSent:       TimeSeries{},
		BytesRecv:       TimeSeries{},
		PacketsSent:     TimeSeries{},
		PacketsRecv:     TimeSeries{},
	}
}

type LastTimeValue struct {
	Time  time.Time
	Value float64
}

type NetIOTimeSeries struct {
	lastBytesSent   LastTimeValue
	lastBytesRecv   LastTimeValue
	lastPacketsSent LastTimeValue
	lastPacketsRecv LastTimeValue

	BytesSent   TimeSeries
	BytesRecv   TimeSeries
	PacketsSent TimeSeries
	PacketsRecv TimeSeries
}

type RealTimeStatus struct {
	max      int
	interval time.Duration
	CPU      TimeSeries
	Mem      TimeSeries
	Net      NetIOTimeSeries
}

func (r *RealTimeStatus) Listen(ctx context.Context) *RealTimeStatus {
	info := &DynamicInformation{}
	t := time.NewTicker(r.interval)
	defer t.Stop()
	for {
		select {
		case <-ctx.Done():
			log.Info(`Exit server real-time status collection`)
			return r
		case <-t.C:
			info.NetMemoryCPU()
			if len(info.CPUPercent) > 0 {
				r.CPUAdd(info.CPUPercent[0])
			} else {
				r.CPUAdd(0)
			}
			r.MemAdd(info.Memory.Virtual.UsedPercent)
			if len(info.NetIO) > 0 {
				r.NetAdd(info.NetIO[0])
			}
			//log.Info(`Collect server status`)
		}
	}
	return r
}

func (r *RealTimeStatus) CPUAdd(y float64) *RealTimeStatus {
	if r.max <= 0 {
		return r
	}
	l := len(r.CPU)
	if l >= r.max {
		r.CPU = r.CPU[1+l-r.max:]
	}
	r.CPU = append(r.CPU, NewXY(y))
	return r
}

func (r *RealTimeStatus) MemAdd(y float64) *RealTimeStatus {
	if r.max <= 0 {
		return r
	}
	l := len(r.Mem)
	if l >= r.max {
		r.Mem = r.Mem[1+l-r.max:]
	}
	r.Mem = append(r.Mem, NewXY(y))
	return r
}

func (r *RealTimeStatus) NetAdd(stat net.IOCountersStat) *RealTimeStatus {
	if r.max <= 0 {
		return r
	}
	now := time.Now()
	l := len(r.Net.BytesRecv)
	if l >= r.max {
		r.Net.BytesRecv = r.Net.BytesRecv[1+l-r.max:]
	}
	n := float64(stat.BytesRecv)
	var speed float64
	if !r.Net.lastBytesRecv.Time.IsZero() {
		speed = (n - r.Net.lastBytesRecv.Value) / now.Sub(r.Net.lastBytesRecv.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.BytesRecv = append(r.Net.BytesRecv, NewXY(speed))
	r.Net.lastBytesRecv.Time = now
	r.Net.lastBytesRecv.Value = n

	l = len(r.Net.BytesSent)
	if l >= r.max {
		r.Net.BytesSent = r.Net.BytesSent[1+l-r.max:]
	}
	n = float64(stat.BytesSent)
	if !r.Net.lastBytesSent.Time.IsZero() {
		speed = (n - r.Net.lastBytesSent.Value) / now.Sub(r.Net.lastBytesSent.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.BytesSent = append(r.Net.BytesSent, NewXY(speed))
	r.Net.lastBytesSent.Time = now
	r.Net.lastBytesSent.Value = n

	l = len(r.Net.PacketsRecv)
	if l >= r.max {
		r.Net.PacketsRecv = r.Net.PacketsRecv[1+l-r.max:]
	}
	n = float64(stat.PacketsRecv)
	if !r.Net.lastPacketsRecv.Time.IsZero() {
		speed = (n - r.Net.lastPacketsRecv.Value) / now.Sub(r.Net.lastPacketsRecv.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.PacketsRecv = append(r.Net.PacketsRecv, NewXY(speed))
	r.Net.lastPacketsRecv.Time = now
	r.Net.lastPacketsRecv.Value = n

	l = len(r.Net.PacketsSent)
	if l >= r.max {
		r.Net.PacketsSent = r.Net.PacketsSent[1+l-r.max:]
	}
	n = float64(stat.PacketsSent)
	if !r.Net.lastPacketsSent.Time.IsZero() {
		speed = (n - r.Net.lastPacketsSent.Value) / now.Sub(r.Net.lastPacketsSent.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.PacketsSent = append(r.Net.PacketsSent, NewXY(speed))
	r.Net.lastPacketsSent.Time = now
	r.Net.lastPacketsSent.Value = n
	return r
}

type (
	TimeSeries []XY
	XY         [2]interface{}
)

func NewXY(y float64) XY {
	x := time.Now().UnixNano() / 1e6 //毫秒
	return XY{x, y}
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package server

import (
	"context"
	"math"
	"time"

	"github.com/shirou/gopsutil/net"

	"github.com/admpub/log"
)

var (
	realTimeStatus                 *RealTimeStatus
	CancelRealTimeStatusCollection func()
)

func RealTimeStatusIsListening() bool {
	return realTimeStatus != nil
}

func ListenRealTimeStatus() {
	if !RealTimeStatusIsListening() {
		realTimeStatus = NewRealTimeStatus(time.Second*2, 80)
	}
	ctx, cancel := context.WithCancel(context.Background())
	go realTimeStatus.Listen(ctx)
	CancelRealTimeStatusCollection = func() {
		if RealTimeStatusIsListening() {
			realTimeStatus = nil
			cancel()
		}
	}
}

func NewRealTimeStatus(interval time.Duration, maxSize int) *RealTimeStatus {
	return &RealTimeStatus{
		max:      maxSize,
		interval: interval,
		CPU:      TimeSeries{},
		Mem:      TimeSeries{},
		Net:      NewNetIOTimeSeries(),
	}
}

func NewNetIOTimeSeries() NetIOTimeSeries {
	return NetIOTimeSeries{
		lastBytesSent:   LastTimeValue{},
		lastBytesRecv:   LastTimeValue{},
		lastPacketsSent: LastTimeValue{},
		lastPacketsRecv: LastTimeValue{},
		BytesSent:       TimeSeries{},
		BytesRecv:       TimeSeries{},
		PacketsSent:     TimeSeries{},
		PacketsRecv:     TimeSeries{},
	}
}

type LastTimeValue struct {
	Time  time.Time
	Value float64
}

type NetIOTimeSeries struct {
	lastBytesSent   LastTimeValue
	lastBytesRecv   LastTimeValue
	lastPacketsSent LastTimeValue
	lastPacketsRecv LastTimeValue

	BytesSent   TimeSeries
	BytesRecv   TimeSeries
	PacketsSent TimeSeries
	PacketsRecv TimeSeries
}

type RealTimeStatus struct {
	max      int
	interval time.Duration
	CPU      TimeSeries
	Mem      TimeSeries
	Net      NetIOTimeSeries
}

func (r *RealTimeStatus) Listen(ctx context.Context) *RealTimeStatus {
	info := &DynamicInformation{}
	t := time.NewTicker(r.interval)
	defer t.Stop()
	for {
		select {
		case <-ctx.Done():
			log.Info(`Exit server real-time status collection`)
			return r
		case <-t.C:
			info.NetMemoryCPU()
			if len(info.CPUPercent) > 0 {
				r.CPUAdd(info.CPUPercent[0])
			} else {
				r.CPUAdd(0)
			}
			r.MemAdd(info.Memory.Virtual.UsedPercent)
			if len(info.NetIO) > 0 {
				r.NetAdd(info.NetIO[0])
			}
			//log.Info(`Collect server status`)
		}
	}
	return r
}

func (r *RealTimeStatus) CPUAdd(y float64) *RealTimeStatus {
	if r.max <= 0 {
		return r
	}
	l := len(r.CPU)
	if l >= r.max {
		r.CPU = r.CPU[1+l-r.max:]
	}
	r.CPU = append(r.CPU, NewXY(y))
	return r
}

func (r *RealTimeStatus) MemAdd(y float64) *RealTimeStatus {
	if r.max <= 0 {
		return r
	}
	l := len(r.Mem)
	if l >= r.max {
		r.Mem = r.Mem[1+l-r.max:]
	}
	r.Mem = append(r.Mem, NewXY(y))
	return r
}

func (r *RealTimeStatus) NetAdd(stat net.IOCountersStat) *RealTimeStatus {
	if r.max <= 0 {
		return r
	}
	now := time.Now()
	l := len(r.Net.BytesRecv)
	if l >= r.max {
		r.Net.BytesRecv = r.Net.BytesRecv[1+l-r.max:]
	}
	n := float64(stat.BytesRecv)
	var speed float64
	if !r.Net.lastBytesRecv.Time.IsZero() {
		speed = (n - r.Net.lastBytesRecv.Value) / now.Sub(r.Net.lastBytesRecv.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.BytesRecv = append(r.Net.BytesRecv, NewXY(speed))
	r.Net.lastBytesRecv.Time = now
	r.Net.lastBytesRecv.Value = n

	l = len(r.Net.BytesSent)
	if l >= r.max {
		r.Net.BytesSent = r.Net.BytesSent[1+l-r.max:]
	}
	n = float64(stat.BytesSent)
	if !r.Net.lastBytesSent.Time.IsZero() {
		speed = (n - r.Net.lastBytesSent.Value) / now.Sub(r.Net.lastBytesSent.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.BytesSent = append(r.Net.BytesSent, NewXY(speed))
	r.Net.lastBytesSent.Time = now
	r.Net.lastBytesSent.Value = n

	l = len(r.Net.PacketsRecv)
	if l >= r.max {
		r.Net.PacketsRecv = r.Net.PacketsRecv[1+l-r.max:]
	}
	n = float64(stat.PacketsRecv)
	if !r.Net.lastPacketsRecv.Time.IsZero() {
		speed = (n - r.Net.lastPacketsRecv.Value) / now.Sub(r.Net.lastPacketsRecv.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.PacketsRecv = append(r.Net.PacketsRecv, NewXY(speed))
	r.Net.lastPacketsRecv.Time = now
	r.Net.lastPacketsRecv.Value = n

	l = len(r.Net.PacketsSent)
	if l >= r.max {
		r.Net.PacketsSent = r.Net.PacketsSent[1+l-r.max:]
	}
	n = float64(stat.PacketsSent)
	if !r.Net.lastPacketsSent.Time.IsZero() {
		speed = (n - r.Net.lastPacketsSent.Value) / now.Sub(r.Net.lastPacketsSent.Time).Seconds()
		speed = math.Ceil(speed)
	} else {
		speed = 0
	}
	r.Net.PacketsSent = append(r.Net.PacketsSent, NewXY(speed))
	r.Net.lastPacketsSent.Time = now
	r.Net.lastPacketsSent.Value = n
	return r
}

type (
	TimeSeries []XY
	XY         [2]interface{}
)

func NewXY(y float64) XY {
	x := time.Now().UnixNano() / 1e6 //毫秒
	return XY{x, y}
}
<|endoftext|>


<commit_before>package builtin

import (
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/drone/drone/common"
	"github.com/drone/drone/queue"
	"github.com/samalba/dockerclient"

	log "github.com/Sirupsen/logrus"
)

var (
	// Defult docker host address
	DefaultHost = "unix:///var/run/docker.sock"

	// Docker host address from environment variable
	DockerHost = os.Getenv("DOCKER_HOST")
)

func init() {
	// if the environment doesn't specify a DOCKER_HOST
	// we should use the default Docker socket.
	if len(DockerHost) == 0 {
		DockerHost = DefaultHost
	}
}

type Runner struct {
	Updater
}

func (r *Runner) Run(w *queue.Work) error {
	var workers []*worker
	var client dockerclient.Client

	defer func() {
		recover()

		// ensures that all containers have been removed
		// from the host machine.
		for _, worker := range workers {
			worker.Remove()
		}

		// if any part of the build fails and leaves
		// behind orphan sub-builds we need to cleanup
		// after ourselves.
		if w.Build.State == common.StateRunning {
			// if any tasks are running or pending
			// we should mark them as complete.
			for _, t := range w.Build.Tasks {
				if t.State == common.StateRunning {
					t.State = common.StateError
					t.Finished = time.Now().UTC().Unix()
					t.Duration = t.Finished - t.Started
				}
				if t.State == common.StatePending {
					t.State = common.StateError
					t.Started = time.Now().UTC().Unix()
					t.Finished = time.Now().UTC().Unix()
					t.Duration = 0
				}
				r.SetTask(w.Repo, w.Build, t)
			}
			// must populate build start
			if w.Build.Started == 0 {
				w.Build.Started = time.Now().UTC().Unix()
			}
			// mark the build as complete (with error)
			w.Build.State = common.StateError
			w.Build.Finished = time.Now().UTC().Unix()
			w.Build.Duration = w.Build.Finished - w.Build.Started
			r.SetBuild(w.Repo, w.Build)
		}
	}()

	// marks the build as running
	w.Build.Started = time.Now().UTC().Unix()
	w.Build.State = common.StateRunning
	err := r.SetBuild(w.Repo, w.Build)
	if err != nil {
		return err
	}

	// create the Docker client. In this version of Drone (alpha)
	// we do not spread builds across clients, but this can and
	// (probably) will change in the future.
	client, err = dockerclient.NewDockerClient(DockerHost, nil)
	if err != nil {
		return err
	}

	// loop through and execute the build and
	// clone steps for each build task.
	for _, task := range w.Build.Tasks {

		// marks the task as running
		task.State = common.StateRunning
		task.Started = time.Now().UTC().Unix()
		err = r.SetTask(w.Repo, w.Build, task)
		if err != nil {
			return err
		}

		work := &work{
			Repo:  w.Repo,
			Build: w.Build,
			Keys:  w.Keys,
			Yaml:  w.Yaml,
			Task:  task,
		}
		in, err := json.Marshal(work)
		if err != nil {
			return err
		}
		worker := newWorkerTimeout(client, w.Repo.Timeout+10) // 10 minute buffer
		workers = append(workers, worker)
		cname := cname(w.Repo.FullName, w.Build.Number, task.Number)
		state, builderr := worker.Build(cname, in)

		switch {
		case builderr == ErrTimeout:
			task.State = common.StateKilled
		case builderr != nil:
			task.State = common.StateError
		case state != 0:
			task.ExitCode = state
			task.State = common.StateFailure
		default:
			task.State = common.StateSuccess
		}

		// send the logs to the datastore
		var buf bytes.Buffer
		rc, err := worker.Logs()
		if err != nil && builderr != nil {
			buf.WriteString(builderr.Error())
		} else if err != nil {
			buf.WriteString(err.Error())
			return err
		} else {
			defer rc.Close()
			StdCopy(&buf, &buf, rc)
		}
		err = r.SetLogs(w.Repo, w.Build, task, ioutil.NopCloser(&buf))
		if err != nil {
			return err
		}

		// update the task in the datastore
		task.Finished = time.Now().UTC().Unix()
		task.Duration = task.Finished - task.Started
		err = r.SetTask(w.Repo, w.Build, task)
		if err != nil {
			return err
		}
	}

	// update the build state if any of the sub-tasks
	// had a non-success status
	w.Build.State = common.StateSuccess
	for _, task := range w.Build.Tasks {
		if task.State != common.StateSuccess {
			w.Build.State = task.State
			break
		}
	}
	err = r.SetBuild(w.Repo, w.Build)
	if err != nil {
		return err
	}

	// loop through and execute the notifications and
	// the destroy all containers afterward.
	for i, task := range w.Build.Tasks {
		work := &work{
			Repo:  w.Repo,
			Build: w.Build,
			Keys:  w.Keys,
			Yaml:  w.Yaml,
			Task:  task,
		}
		in, err := json.Marshal(work)
		if err != nil {
			return err
		}
		workers[i].Notify(in)
		break
	}

	return nil
}

func (r *Runner) Cancel(repo string, build, task int) error {
	client, err := dockerclient.NewDockerClient(DockerHost, nil)
	if err != nil {
		return err
	}
	return client.StopContainer(cname(repo, build, task), 30)
}

func (r *Runner) Logs(repo string, build, task int) (io.ReadCloser, error) {
	client, err := dockerclient.NewDockerClient(DockerHost, nil)
	if err != nil {
		return nil, err
	}
	// make sure this container actually exists
	info, err := client.InspectContainer(cname(repo, build, task))
	if err != nil {
		return nil, err
	}
	// verify the container is running. if not we'll
	// do an exponential backoff and attempt to wait
	if !info.State.Running {
		for i := 0; ; i++ {
			time.Sleep(1 * time.Second)
			info, err = client.InspectContainer(info.Id)
			if err != nil {
				return nil, err
			}
			if info.State.Running {
				break
			}
			if i == 5 {
				return nil, dockerclient.ErrNotFound
			}
		}
	}

	rc, err := client.ContainerLogs(info.Id, logOptsTail)
	if err != nil {
		return nil, err
	}
	pr, pw := io.Pipe()
	go func() {
		defer rc.Close()
		StdCopy(pw, pw, rc)
	}()
	return pr, nil
}

func cname(repo string, number, task int) string {
	s := fmt.Sprintf("%s/%d/%d", repo, number, task)
	h := sha1.New()
	h.Write([]byte(s))
	hash := hex.EncodeToString(h.Sum(nil))[:10]
	return fmt.Sprintf("drone-%s", hash)
}

func (r *Runner) Poll(q queue.Queue) {
	for {
		w := q.Pull()
		q.Ack(w)
		err := r.Run(w)
		if err != nil {
			log.Error(err)
		}
	}
}
<commit_msg>passing netrc data to build<commit_after>package builtin

import (
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/drone/drone/common"
	"github.com/drone/drone/queue"
	"github.com/samalba/dockerclient"

	log "github.com/Sirupsen/logrus"
)

var (
	// Defult docker host address
	DefaultHost = "unix:///var/run/docker.sock"

	// Docker host address from environment variable
	DockerHost = os.Getenv("DOCKER_HOST")
)

func init() {
	// if the environment doesn't specify a DOCKER_HOST
	// we should use the default Docker socket.
	if len(DockerHost) == 0 {
		DockerHost = DefaultHost
	}
}

type Runner struct {
	Updater
}

func (r *Runner) Run(w *queue.Work) error {
	var workers []*worker
	var client dockerclient.Client

	defer func() {
		recover()

		// ensures that all containers have been removed
		// from the host machine.
		for _, worker := range workers {
			worker.Remove()
		}

		// if any part of the build fails and leaves
		// behind orphan sub-builds we need to cleanup
		// after ourselves.
		if w.Build.State == common.StateRunning {
			// if any tasks are running or pending
			// we should mark them as complete.
			for _, t := range w.Build.Tasks {
				if t.State == common.StateRunning {
					t.State = common.StateError
					t.Finished = time.Now().UTC().Unix()
					t.Duration = t.Finished - t.Started
				}
				if t.State == common.StatePending {
					t.State = common.StateError
					t.Started = time.Now().UTC().Unix()
					t.Finished = time.Now().UTC().Unix()
					t.Duration = 0
				}
				r.SetTask(w.Repo, w.Build, t)
			}
			// must populate build start
			if w.Build.Started == 0 {
				w.Build.Started = time.Now().UTC().Unix()
			}
			// mark the build as complete (with error)
			w.Build.State = common.StateError
			w.Build.Finished = time.Now().UTC().Unix()
			w.Build.Duration = w.Build.Finished - w.Build.Started
			r.SetBuild(w.Repo, w.Build)
		}
	}()

	// marks the build as running
	w.Build.Started = time.Now().UTC().Unix()
	w.Build.State = common.StateRunning
	err := r.SetBuild(w.Repo, w.Build)
	if err != nil {
		return err
	}

	// create the Docker client. In this version of Drone (alpha)
	// we do not spread builds across clients, but this can and
	// (probably) will change in the future.
	client, err = dockerclient.NewDockerClient(DockerHost, nil)
	if err != nil {
		return err
	}

	// loop through and execute the build and
	// clone steps for each build task.
	for _, task := range w.Build.Tasks {

		// marks the task as running
		task.State = common.StateRunning
		task.Started = time.Now().UTC().Unix()
		err = r.SetTask(w.Repo, w.Build, task)
		if err != nil {
			return err
		}

		work := &work{
			Repo:  w.Repo,
			Build: w.Build,
			Keys:  w.Keys,
			Netrc: w.Netrc,
			Yaml:  w.Yaml,
			Task:  task,
		}
		in, err := json.Marshal(work)
		if err != nil {
			return err
		}
		worker := newWorkerTimeout(client, w.Repo.Timeout+10) // 10 minute buffer
		workers = append(workers, worker)
		cname := cname(w.Repo.FullName, w.Build.Number, task.Number)
		state, builderr := worker.Build(cname, in)

		switch {
		case builderr == ErrTimeout:
			task.State = common.StateKilled
		case builderr != nil:
			task.State = common.StateError
		case state != 0:
			task.ExitCode = state
			task.State = common.StateFailure
		default:
			task.State = common.StateSuccess
		}

		// send the logs to the datastore
		var buf bytes.Buffer
		rc, err := worker.Logs()
		if err != nil && builderr != nil {
			buf.WriteString(builderr.Error())
		} else if err != nil {
			buf.WriteString(err.Error())
			return err
		} else {
			defer rc.Close()
			StdCopy(&buf, &buf, rc)
		}
		err = r.SetLogs(w.Repo, w.Build, task, ioutil.NopCloser(&buf))
		if err != nil {
			return err
		}

		// update the task in the datastore
		task.Finished = time.Now().UTC().Unix()
		task.Duration = task.Finished - task.Started
		err = r.SetTask(w.Repo, w.Build, task)
		if err != nil {
			return err
		}
	}

	// update the build state if any of the sub-tasks
	// had a non-success status
	w.Build.State = common.StateSuccess
	for _, task := range w.Build.Tasks {
		if task.State != common.StateSuccess {
			w.Build.State = task.State
			break
		}
	}
	err = r.SetBuild(w.Repo, w.Build)
	if err != nil {
		return err
	}

	// loop through and execute the notifications and
	// the destroy all containers afterward.
	for i, task := range w.Build.Tasks {
		work := &work{
			Repo:  w.Repo,
			Build: w.Build,
			Keys:  w.Keys,
			Netrc: w.Netrc,
			Yaml:  w.Yaml,
			Task:  task,
		}
		in, err := json.Marshal(work)
		if err != nil {
			return err
		}
		workers[i].Notify(in)
		break
	}

	return nil
}

func (r *Runner) Cancel(repo string, build, task int) error {
	client, err := dockerclient.NewDockerClient(DockerHost, nil)
	if err != nil {
		return err
	}
	return client.StopContainer(cname(repo, build, task), 30)
}

func (r *Runner) Logs(repo string, build, task int) (io.ReadCloser, error) {
	client, err := dockerclient.NewDockerClient(DockerHost, nil)
	if err != nil {
		return nil, err
	}
	// make sure this container actually exists
	info, err := client.InspectContainer(cname(repo, build, task))
	if err != nil {
		return nil, err
	}
	// verify the container is running. if not we'll
	// do an exponential backoff and attempt to wait
	if !info.State.Running {
		for i := 0; ; i++ {
			time.Sleep(1 * time.Second)
			info, err = client.InspectContainer(info.Id)
			if err != nil {
				return nil, err
			}
			if info.State.Running {
				break
			}
			if i == 5 {
				return nil, dockerclient.ErrNotFound
			}
		}
	}

	rc, err := client.ContainerLogs(info.Id, logOptsTail)
	if err != nil {
		return nil, err
	}
	pr, pw := io.Pipe()
	go func() {
		defer rc.Close()
		StdCopy(pw, pw, rc)
	}()
	return pr, nil
}

func cname(repo string, number, task int) string {
	s := fmt.Sprintf("%s/%d/%d", repo, number, task)
	h := sha1.New()
	h.Write([]byte(s))
	hash := hex.EncodeToString(h.Sum(nil))[:10]
	return fmt.Sprintf("drone-%s", hash)
}

func (r *Runner) Poll(q queue.Queue) {
	for {
		w := q.Pull()
		q.Ack(w)
		err := r.Run(w)
		if err != nil {
			log.Error(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/gob"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"text/template"

	"github.com/Masterminds/sprig"
	rt "github.com/kyma-project/test-infra/development/tools/pkg/rendertemplates"
	"gopkg.in/yaml.v2"
	"k8s.io/apimachinery/pkg/util/sets"
)

const (
	// autogenerationMessage is message added at the beginning of each autogenerated file.
	autogenerationMessage = "Code generated by rendertemplates. DO NOT EDIT."
)

var (
	configFilePath  = flag.String("config", "", "Path of the config file")
	additionalFuncs = map[string]interface{}{
		"matchingReleases": rt.MatchingReleases,
		"releaseMatches":   rt.ReleaseMatches,
		"hasPresubmit":     hasPresubmit,
		"hasPostsubmit":    hasPostsubmit,
		"hasPeriodic":      hasPeriodic,
		"getRunId":         getRunID,
	}
	commentSignByFileExt = map[string]sets.String{
		"//": sets.NewString(".go"),
		"#":  sets.NewString(".yaml", ".yml"),
	}
)

func init() {
	gob.Register(map[string]interface{}{})
	gob.Register(map[interface{}]interface{}{})
	gob.Register([]interface{}{})
}

func main() {
	flag.Parse()

	if *configFilePath == "" {
		log.Fatal("Provide path to config file with --config")
	}

	configFile, err := ioutil.ReadFile(*configFilePath)
	if err != nil {
		log.Fatalf("Cannot read config file: %s", err)
	}

	config := new(rt.Config)
	err = yaml.Unmarshal(configFile, config)
	if err != nil {
		log.Fatalf("Cannot parse config yaml: %s\n", err)
	}

	dataFilesDir := filepath.Join(filepath.Dir(*configFilePath), "data")
	// read all template configs from data files
	dataFiles, err := ioutil.ReadDir(dataFilesDir)
	var dataFilesTemplates []rt.TemplateConfig
	for _, dataFile := range dataFiles {
		if !dataFile.IsDir() {
			var dataFileConfig rt.Config
			var cfg bytes.Buffer
			// load datafile as template
			t, err := loadTemplate(dataFilesDir, dataFile.Name())
			if err != nil {
				log.Fatalf("Could not load data file %s: %v", dataFile.Name(), err)
			}
			// execute rendering the datafile from template and store it in-memory
			// at this point the config has all the global values from config.yaml file
			if err := t.Execute(&cfg, config); err != nil {
				log.Fatalf("Cannot render data template: %v", err)
			}
			if err := yaml.Unmarshal(cfg.Bytes(), &dataFileConfig); err != nil {
				log.Fatalf("Cannot parse data file yaml: %s\n", err)
			}
			dataFilesTemplates = append(dataFilesTemplates, dataFileConfig.Templates...)
		}

	}

	config.Templates = append(config.Templates, dataFilesTemplates...)

	for _, templateConfig := range config.Templates {
		err = renderTemplate(path.Dir(*configFilePath), templateConfig, config)
		if err != nil {
			log.Fatalf("Cannot render template %s: %s", templateConfig.From, err)
		}
	}
}

func renderTemplate(basePath string, templateConfig rt.TemplateConfig, config *rt.Config) error {
	templateInstance, err := loadTemplate(basePath, templateConfig.From)
	if err != nil {
		return err
	}
	for _, render := range templateConfig.Render {

		render.MergeConfigs(config)

		// check if there are any component jobs in merged config and generate config for such jobs for each supported release
		render.GenerateComponentJobs(config.Global)

		err = renderFileFromTemplate(basePath, templateInstance, render, config)
		if err != nil {
			log.Printf("Failed render %s file", render.To)
			return err
		}
	}

	return nil
}

func renderFileFromTemplate(basePath string, templateInstance *template.Template, renderConfig rt.RenderConfig, config *rt.Config) error {
	relativeDestPath := path.Join(basePath, renderConfig.To)

	destDir := path.Dir(relativeDestPath)
	err := os.MkdirAll(destDir, os.ModePerm)
	if err != nil {
		return err
	}

	destFile, err := os.Create(relativeDestPath)
	if err != nil {
		return err
	}

	if err := addAutogeneratedHeader(destFile); err != nil {
		return err
	}

	values := map[string]interface{}{"Values": renderConfig.Values, "Global": config.Global}

	return templateInstance.Execute(destFile, values)
}

func loadTemplate(basePath, templatePath string) (*template.Template, error) {
	relativeTemplatePath := path.Join(basePath, templatePath)
	return template.
		New(path.Base(templatePath)).
		Funcs(sprig.TxtFuncMap()).
		Funcs(additionalFuncs).
		ParseFiles(relativeTemplatePath)
}

func addAutogeneratedHeader(destFile *os.File) error {
	outputExt := filepath.Ext(destFile.Name())
	sign, err := commentSign(outputExt)
	if err != nil {
		return err
	}

	header := fmt.Sprintf("%s %s\n\n", sign, autogenerationMessage)
	if _, err := destFile.WriteString(header); err != nil {
		return err
	}

	return nil
}

func commentSign(extension string) (string, error) {
	for sign, extFile := range commentSignByFileExt {
		if extFile.Has(extension) {
			return sign, nil
		}
	}
	return "", fmt.Errorf("cannot add autogenerated header comment: unknow comment sign for %q file extension", extension)
}

// hasProwjobType check if prowjobtype value is present in prowjob configs.
func hasProwjobType(r []rt.Repo, prowjobtype string) bool {
	for _, repo := range r {
		for _, job := range repo.Jobs {
			if _, ok := job.JobConfig[prowjobtype]; ok {
				return ok
			}
		}
	}
	return false
}

// hasPresubmit check if any prowjob is type_presubmit
func hasPresubmit(r []rt.Repo) bool {
	return hasProwjobType(r, "type_presubmit")
}

// hasPresubmit check if any prowjob is type_postsubmit
func hasPostsubmit(r []rt.Repo) bool {
	return hasProwjobType(r, "type_postsubmit")
}

// hasPresubmit check if any prowjob is type_periodic
func hasPeriodic(r []rt.Repo) bool {
	return hasProwjobType(r, "type_periodic")
}

// getRunID trims the prowjob name to 63 characters and makes sure it doesn't end with dash to match pubsub requirements.
func getRunID(name interface{}) string {
	jobName := name.(string)
	if len(jobName) > 63 {
		jobName = jobName[0:63]
		for jobName[len(jobName)-1:] == "-" {
			jobName = jobName[:len(jobName)-1]
		}
	}
	return "\"" + jobName + "\""
}
<commit_msg>Add `show-output-dir` flag to rendertemplates (#3815)<commit_after>package main

import (
	"bytes"
	"encoding/gob"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"text/template"

	"github.com/Masterminds/sprig"
	rt "github.com/kyma-project/test-infra/development/tools/pkg/rendertemplates"
	"gopkg.in/yaml.v2"
	"k8s.io/apimachinery/pkg/util/sets"
)

const (
	// autogenerationMessage is message added at the beginning of each autogenerated file.
	autogenerationMessage = "Code generated by rendertemplates. DO NOT EDIT."
)

var (
	configFilePath = flag.String("config", "", "Path of the config file")
	showOutputDir  = flag.Bool("show-output-dir", false, "Print generated output file paths to stdout")

	additionalFuncs = map[string]interface{}{
		"matchingReleases": rt.MatchingReleases,
		"releaseMatches":   rt.ReleaseMatches,
		"hasPresubmit":     hasPresubmit,
		"hasPostsubmit":    hasPostsubmit,
		"hasPeriodic":      hasPeriodic,
		"getRunId":         getRunID,
	}
	commentSignByFileExt = map[string]sets.String{
		"//": sets.NewString(".go"),
		"#":  sets.NewString(".yaml", ".yml"),
	}
)

func init() {
	gob.Register(map[string]interface{}{})
	gob.Register(map[interface{}]interface{}{})
	gob.Register([]interface{}{})
}

func main() {
	flag.Parse()

	if *configFilePath == "" {
		log.Fatal("Provide path to config file with --config")
	}

	configFile, err := ioutil.ReadFile(*configFilePath)
	if err != nil {
		log.Fatalf("Cannot read config file: %s", err)
	}

	config := new(rt.Config)
	err = yaml.Unmarshal(configFile, config)
	if err != nil {
		log.Fatalf("Cannot parse config yaml: %s\n", err)
	}

	dataFilesDir := filepath.Join(filepath.Dir(*configFilePath), "data")
	// read all template configs from data files
	dataFiles, err := ioutil.ReadDir(dataFilesDir)
	var dataFilesTemplates []rt.TemplateConfig
	for _, dataFile := range dataFiles {
		if !dataFile.IsDir() {
			var dataFileConfig rt.Config
			var cfg bytes.Buffer
			// load datafile as template
			t, err := loadTemplate(dataFilesDir, dataFile.Name())
			if err != nil {
				log.Fatalf("Could not load data file %s: %v", dataFile.Name(), err)
			}
			// execute rendering the datafile from template and store it in-memory
			// at this point the config has all the global values from config.yaml file
			if err := t.Execute(&cfg, config); err != nil {
				log.Fatalf("Cannot render data template: %v", err)
			}
			if err := yaml.Unmarshal(cfg.Bytes(), &dataFileConfig); err != nil {
				log.Fatalf("Cannot parse data file yaml: %s\n", err)
			}
			dataFilesTemplates = append(dataFilesTemplates, dataFileConfig.Templates...)
		}

	}

	config.Templates = append(config.Templates, dataFilesTemplates...)

	for _, templateConfig := range config.Templates {
		err = renderTemplate(path.Dir(*configFilePath), templateConfig, config)
		if err != nil {
			log.Fatalf("Cannot render template %s: %s", templateConfig.From, err)
		}
	}
}

func renderTemplate(basePath string, templateConfig rt.TemplateConfig, config *rt.Config) error {
	templateInstance, err := loadTemplate(basePath, templateConfig.From)
	if err != nil {
		return err
	}
	for _, render := range templateConfig.Render {

		render.MergeConfigs(config)

		// check if there are any component jobs in merged config and generate config for such jobs for each supported release
		render.GenerateComponentJobs(config.Global)

		err = renderFileFromTemplate(basePath, templateInstance, render, config)
		if err != nil {
			log.Printf("Failed render %s file", render.To)
			return err
		}
	}

	return nil
}

func renderFileFromTemplate(basePath string, templateInstance *template.Template, renderConfig rt.RenderConfig, config *rt.Config) error {
	relativeDestPath := path.Join(basePath, renderConfig.To)

	destDir := path.Dir(relativeDestPath)
	err := os.MkdirAll(destDir, os.ModePerm)
	if err != nil {
		return err
	}

	destFile, err := os.Create(relativeDestPath)
	if err != nil {
		return err
	}

	if err := addAutogeneratedHeader(destFile); err != nil {
		return err
	}

	values := map[string]interface{}{"Values": renderConfig.Values, "Global": config.Global}

	if *showOutputDir {
		fmt.Println(destFile.Name())
	}
	return templateInstance.Execute(destFile, values)
}

func loadTemplate(basePath, templatePath string) (*template.Template, error) {
	relativeTemplatePath := path.Join(basePath, templatePath)
	return template.
		New(path.Base(templatePath)).
		Funcs(sprig.TxtFuncMap()).
		Funcs(additionalFuncs).
		ParseFiles(relativeTemplatePath)
}

func addAutogeneratedHeader(destFile *os.File) error {
	outputExt := filepath.Ext(destFile.Name())
	sign, err := commentSign(outputExt)
	if err != nil {
		return err
	}

	header := fmt.Sprintf("%s %s\n\n", sign, autogenerationMessage)
	if _, err := destFile.WriteString(header); err != nil {
		return err
	}

	return nil
}

func commentSign(extension string) (string, error) {
	for sign, extFile := range commentSignByFileExt {
		if extFile.Has(extension) {
			return sign, nil
		}
	}
	return "", fmt.Errorf("cannot add autogenerated header comment: unknow comment sign for %q file extension", extension)
}

// hasProwjobType check if prowjobtype value is present in prowjob configs.
func hasProwjobType(r []rt.Repo, prowjobtype string) bool {
	for _, repo := range r {
		for _, job := range repo.Jobs {
			if _, ok := job.JobConfig[prowjobtype]; ok {
				return ok
			}
		}
	}
	return false
}

// hasPresubmit check if any prowjob is type_presubmit
func hasPresubmit(r []rt.Repo) bool {
	return hasProwjobType(r, "type_presubmit")
}

// hasPresubmit check if any prowjob is type_postsubmit
func hasPostsubmit(r []rt.Repo) bool {
	return hasProwjobType(r, "type_postsubmit")
}

// hasPresubmit check if any prowjob is type_periodic
func hasPeriodic(r []rt.Repo) bool {
	return hasProwjobType(r, "type_periodic")
}

// getRunID trims the prowjob name to 63 characters and makes sure it doesn't end with dash to match pubsub requirements.
func getRunID(name interface{}) string {
	jobName := name.(string)
	if len(jobName) > 63 {
		jobName = jobName[0:63]
		for jobName[len(jobName)-1:] == "-" {
			jobName = jobName[:len(jobName)-1]
		}
	}
	return "\"" + jobName + "\""
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2014 Jeremy Latt
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package irc

import (
	"fmt"
	"strings"

	"github.com/goshuirc/irc-go/ircfmt"
	"github.com/goshuirc/irc-go/ircmsg"
	"github.com/oragono/oragono/irc/sno"
)

var (
	restrictedNicknames = map[string]bool{
		"=scene=":  true, // used for rp commands
		"chanserv": true,
		"nickserv": true,
	}
)

// NICK <nickname>
func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	if !client.authorized {
		client.Quit("Bad password")
		return true
	}

	return performNickChange(server, client, client, msg.Params[0])
}

func performNickChange(server *Server, client *Client, target *Client, newnick string) bool {
	nicknameRaw := strings.TrimSpace(newnick)
	nickname, err := CasefoldName(nicknameRaw)

	if len(nicknameRaw) < 1 {
		client.Send(nil, server.name, ERR_NONICKNAMEGIVEN, client.nick, "No nickname given")
		return false
	}

	if err != nil || len(nicknameRaw) > server.Limits().NickLen || restrictedNicknames[nickname] {
		client.Send(nil, server.name, ERR_ERRONEUSNICKNAME, client.nick, nicknameRaw, "Erroneous nickname")
		return false
	}

	if target.Nick() == nicknameRaw {
		return false
	}

	hadNick := target.HasNick()
	origNick := target.Nick()
	origNickMask := target.NickMaskString()
	err = client.server.clients.SetNick(target, nickname)
	if err == ErrNicknameInUse {
		client.Send(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nicknameRaw, "Nickname is already in use")
		return false
	} else if err != nil {
		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf("Could not set or change nickname: %s", err.Error()))
		return false
	}

	client.server.logger.Debug("nick", fmt.Sprintf("%s changed nickname to %s [%s]", origNickMask, nicknameRaw, nickname))
	if hadNick {
		target.server.snomasks.Send(sno.LocalNicks, fmt.Sprintf(ircfmt.Unescape("$%s$r changed nickname to %s"), origNick, nicknameRaw))
		target.server.whoWas.Append(client)
		for friend := range target.Friends() {
			friend.Send(nil, origNickMask, "NICK", nicknameRaw)
		}
	}

	if target.registered {
		client.server.monitorManager.AlertAbout(target, true)
	} else {
		server.tryRegister(target)
	}
	return false
}

// SANICK <oldnick> <nickname>
func sanickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	targetNick := strings.TrimSpace(msg.Params[0])
	target := server.clients.Get(targetNick)
	if target == nil {
		client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], "No such nick")
		return false
	}
	return performNickChange(server, client, target, msg.Params[1])
}
<commit_msg>fix a bug where the uncasefolded nickname wasn't being recorded<commit_after>// Copyright (c) 2012-2014 Jeremy Latt
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license

package irc

import (
	"fmt"
	"strings"

	"github.com/goshuirc/irc-go/ircfmt"
	"github.com/goshuirc/irc-go/ircmsg"
	"github.com/oragono/oragono/irc/sno"
)

var (
	restrictedNicknames = map[string]bool{
		"=scene=":  true, // used for rp commands
		"chanserv": true,
		"nickserv": true,
	}
)

// NICK <nickname>
func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	if !client.authorized {
		client.Quit("Bad password")
		return true
	}

	return performNickChange(server, client, client, msg.Params[0])
}

func performNickChange(server *Server, client *Client, target *Client, newnick string) bool {
	nickname := strings.TrimSpace(newnick)
	cfnick, err := CasefoldName(nickname)

	if len(nickname) < 1 {
		client.Send(nil, server.name, ERR_NONICKNAMEGIVEN, client.nick, "No nickname given")
		return false
	}

	if err != nil || len(nickname) > server.Limits().NickLen || restrictedNicknames[cfnick] {
		client.Send(nil, server.name, ERR_ERRONEUSNICKNAME, client.nick, nickname, "Erroneous nickname")
		return false
	}

	if target.Nick() == nickname {
		return false
	}

	hadNick := target.HasNick()
	origNick := target.Nick()
	origNickMask := target.NickMaskString()
	err = client.server.clients.SetNick(target, nickname)
	if err == ErrNicknameInUse {
		client.Send(nil, server.name, ERR_NICKNAMEINUSE, client.nick, nickname, "Nickname is already in use")
		return false
	} else if err != nil {
		client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "NICK", fmt.Sprintf("Could not set or change nickname: %s", err.Error()))
		return false
	}

	client.server.logger.Debug("nick", fmt.Sprintf("%s changed nickname to %s [%s]", origNickMask, nickname, cfnick))
	if hadNick {
		target.server.snomasks.Send(sno.LocalNicks, fmt.Sprintf(ircfmt.Unescape("$%s$r changed nickname to %s"), origNick, nickname))
		target.server.whoWas.Append(client)
		for friend := range target.Friends() {
			friend.Send(nil, origNickMask, "NICK", nickname)
		}
	}

	if target.registered {
		client.server.monitorManager.AlertAbout(target, true)
	} else {
		server.tryRegister(target)
	}
	return false
}

// SANICK <oldnick> <nickname>
func sanickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
	targetNick := strings.TrimSpace(msg.Params[0])
	target := server.clients.Get(targetNick)
	if target == nil {
		client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], "No such nick")
		return false
	}
	return performNickChange(server, client, target, msg.Params[1])
}
<|endoftext|>


<commit_before>// Package match provides functionality to find matching times.
// This is the core logic of sleepto.
package match

import "time"

// Condition are used to match a time.
// All fields are optional and can be used in any combination.
// For each field one value of the list has
// to match to find a match for the condition.
type Condition struct {
	Month   []time.Month
	Day     []int // 1 to 31
	Weekday []time.Weekday
	Hour    []int // 0 to 23
	Minute  []int // 0 to 59
	Second  []int // 0 to 59
}

// Next finds the next time the passed condition matches.
func Next(start time.Time, c Condition) time.Time {
	t := setBase(start, c)
	// Stop when when no condition
	if t.Equal(start) {
		return t
	}

	// Walk until all units match.
	// Adjust biggest unit first.
	for {
		switch {
		case wrongMonth(c.Month, t.Month()):
			t = t.AddDate(0, 1, 1-t.Day()).Truncate(time.Hour * 24)
		case wrong(c.Day, t.Day()) || wrongWeekday(c.Weekday, t.Weekday()):
			t = t.AddDate(0, 0, 1).Truncate(time.Hour * 24)
		case wrong(c.Hour, t.Hour()):
			t = t.Add(time.Hour).Truncate(time.Hour)
		case wrong(c.Minute, t.Minute()):
			t = t.Add(time.Minute).Truncate(time.Minute)
		case wrong(c.Second, t.Second()):
			t = t.Add(time.Second).Truncate(time.Second)
		default:
			// Found matching time.
			return t
		}
	}
}

// Find smallest unit and start counting from there.
// At least have to increment by one.
func setBase(t time.Time, c Condition) time.Time {
	switch {
	case len(c.Second) > 0:
		return t.Add(time.Second).Truncate(time.Second)
	case len(c.Minute) > 0:
		return t.Add(time.Minute).Truncate(time.Minute)
	case len(c.Hour) > 0:
		return t.Add(time.Hour).Truncate(time.Hour)
	case len(c.Day) > 0 || len(c.Weekday) > 0:
		return t.AddDate(0, 0, 1).Truncate(time.Hour * 24)
	case len(c.Month) > 0:
		return t.AddDate(0, 1, 1-t.Day()).Truncate(time.Hour * 24)
	default:
		return t
	}
}

func wrong(xs []int, x int) bool {
	if len(xs) == 0 {
		return false
	}
	for _, y := range xs {
		if x == y {
			return false
		}
	}
	return true
}

func wrongMonth(ms []time.Month, m time.Month) bool {
	xs := make([]int, len(ms))
	for i := range ms {
		xs[i] = int(ms[i])
	}
	return wrong(xs, int(m))
}

func wrongWeekday(ds []time.Weekday, d time.Weekday) bool {
	xs := make([]int, len(ds))
	for i := range ds {
		xs[i] = int(ds[i])
	}
	return wrong(xs, int(d))
}
<commit_msg>Fixed typo in comment.<commit_after>// Package match provides functionality to find matching times.
// This is the core logic of sleepto.
package match

import "time"

// Condition is used to match a time.
// All fields are optional and can be used in any combination.
// For each field one value of the list has
// to match to find a match for the condition.
type Condition struct {
	Month   []time.Month
	Day     []int // 1 to 31
	Weekday []time.Weekday
	Hour    []int // 0 to 23
	Minute  []int // 0 to 59
	Second  []int // 0 to 59
}

// Next finds the next time the passed condition matches.
func Next(start time.Time, c Condition) time.Time {
	t := setBase(start, c)
	// Stop when when no condition
	if t.Equal(start) {
		return t
	}

	// Walk until all units match.
	// Adjust biggest unit first.
	for {
		switch {
		case wrongMonth(c.Month, t.Month()):
			t = t.AddDate(0, 1, 1-t.Day()).Truncate(time.Hour * 24)
		case wrong(c.Day, t.Day()) || wrongWeekday(c.Weekday, t.Weekday()):
			t = t.AddDate(0, 0, 1).Truncate(time.Hour * 24)
		case wrong(c.Hour, t.Hour()):
			t = t.Add(time.Hour).Truncate(time.Hour)
		case wrong(c.Minute, t.Minute()):
			t = t.Add(time.Minute).Truncate(time.Minute)
		case wrong(c.Second, t.Second()):
			t = t.Add(time.Second).Truncate(time.Second)
		default:
			// Found matching time.
			return t
		}
	}
}

// Find smallest unit and start counting from there.
// At least have to increment by one.
func setBase(t time.Time, c Condition) time.Time {
	switch {
	case len(c.Second) > 0:
		return t.Add(time.Second).Truncate(time.Second)
	case len(c.Minute) > 0:
		return t.Add(time.Minute).Truncate(time.Minute)
	case len(c.Hour) > 0:
		return t.Add(time.Hour).Truncate(time.Hour)
	case len(c.Day) > 0 || len(c.Weekday) > 0:
		return t.AddDate(0, 0, 1).Truncate(time.Hour * 24)
	case len(c.Month) > 0:
		return t.AddDate(0, 1, 1-t.Day()).Truncate(time.Hour * 24)
	default:
		return t
	}
}

func wrong(xs []int, x int) bool {
	if len(xs) == 0 {
		return false
	}
	for _, y := range xs {
		if x == y {
			return false
		}
	}
	return true
}

func wrongMonth(ms []time.Month, m time.Month) bool {
	xs := make([]int, len(ms))
	for i := range ms {
		xs[i] = int(ms[i])
	}
	return wrong(xs, int(m))
}

func wrongWeekday(ds []time.Weekday, d time.Weekday) bool {
	xs := make([]int, len(ds))
	for i := range ds {
		xs[i] = int(ds[i])
	}
	return wrong(xs, int(d))
}
<|endoftext|>


<commit_before>// +build gomq

package boomer

import (
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/zeromq/gomq"
	"github.com/zeromq/gomq/zmtp"
)

type zmqClient interface {
	recv()
	send()
}

type gomqSocketClient struct {
	pushSocket *gomq.Socket
	pullSocket *gomq.Socket
}

func newGomqSocket(socketType zmtp.SocketType) *gomq.Socket {
	socket := gomq.NewSocket(false, socketType, zmtp.NewSecurityNull())
	return socket
}

func getNetConn(addr string) net.Conn {
	parts := strings.Split(addr, "://")
	netConn, err := net.Dial(parts[0], parts[1])
	if err != nil {
		log.Fatal(err)
	}
	return netConn
}

func connectSock(socket *gomq.Socket, addr string) {
	netConn := getNetConn(addr)
	zmtpConn := zmtp.NewConnection(netConn)
	_, err := zmtpConn.Prepare(socket.SecurityMechanism(), socket.SocketType(), false, nil)
	if err != nil {
		log.Fatal(err)
	}
	conn := gomq.NewConnection(netConn, zmtpConn)
	socket.AddConnection(conn)
	zmtpConn.Recv(socket.RecvChannel())
}

func newZmqClient(masterHost string, masterPort int) *gomqSocketClient {
	pushAddr := fmt.Sprintf("tcp://%s:%d", masterHost, masterPort)
	pullAddr := fmt.Sprintf("tcp://%s:%d", masterHost, masterPort+1)

	pushSocket := newGomqSocket(zmtp.PushSocketType)
	connectSock(pushSocket, pushAddr)

	pullSocket := newGomqSocket(zmtp.PullSocketType)
	connectSock(pullSocket, pullAddr)

	log.Println("ZMQ sockets connected")

	newClient := &gomqSocketClient{
		pushSocket: pushSocket,
		pullSocket: pullSocket,
	}
	go newClient.recv()
	go newClient.send()
	return newClient
}

func (c *gomqSocketClient) recv() {
	for {
		msg, err := c.pullSocket.Recv()
		if err != nil {
			log.Println("Error reading: %v", err)
		} else {
			msgFromMaster := newMessageFromBytes(msg)
			fromServer <- msgFromMaster
		}
	}

}

func (c *gomqSocketClient) send() {
	for {
		select {
		case msg := <-toServer:
			c.sendMessage(msg)
			if msg.Type == "quit" {
				disconnectedFromServer <- true
			}
		}
	}
}

func (c *gomqSocketClient) sendMessage(msg *message) {
	err := c.pushSocket.Send(msg.serialize())
	if err != nil {
		log.Println("Error sending: %v", err)
	}
}
<commit_msg>FIX: log format<commit_after>// +build gomq

package boomer

import (
	"fmt"
	"log"
	"net"
	"strings"

	"github.com/zeromq/gomq"
	"github.com/zeromq/gomq/zmtp"
)

type zmqClient interface {
	recv()
	send()
}

type gomqSocketClient struct {
	pushSocket *gomq.Socket
	pullSocket *gomq.Socket
}

func newGomqSocket(socketType zmtp.SocketType) *gomq.Socket {
	socket := gomq.NewSocket(false, socketType, zmtp.NewSecurityNull())
	return socket
}

func getNetConn(addr string) net.Conn {
	parts := strings.Split(addr, "://")
	netConn, err := net.Dial(parts[0], parts[1])
	if err != nil {
		log.Fatal(err)
	}
	return netConn
}

func connectSock(socket *gomq.Socket, addr string) {
	netConn := getNetConn(addr)
	zmtpConn := zmtp.NewConnection(netConn)
	_, err := zmtpConn.Prepare(socket.SecurityMechanism(), socket.SocketType(), false, nil)
	if err != nil {
		log.Fatal(err)
	}
	conn := gomq.NewConnection(netConn, zmtpConn)
	socket.AddConnection(conn)
	zmtpConn.Recv(socket.RecvChannel())
}

func newZmqClient(masterHost string, masterPort int) *gomqSocketClient {
	pushAddr := fmt.Sprintf("tcp://%s:%d", masterHost, masterPort)
	pullAddr := fmt.Sprintf("tcp://%s:%d", masterHost, masterPort+1)

	pushSocket := newGomqSocket(zmtp.PushSocketType)
	connectSock(pushSocket, pushAddr)

	pullSocket := newGomqSocket(zmtp.PullSocketType)
	connectSock(pullSocket, pullAddr)

	log.Println("ZMQ sockets connected")

	newClient := &gomqSocketClient{
		pushSocket: pushSocket,
		pullSocket: pullSocket,
	}
	go newClient.recv()
	go newClient.send()
	return newClient
}

func (c *gomqSocketClient) recv() {
	for {
		msg, err := c.pullSocket.Recv()
		if err != nil {
			log.Printf("Error reading: %v\n", err)
		} else {
			msgFromMaster := newMessageFromBytes(msg)
			fromServer <- msgFromMaster
		}
	}

}

func (c *gomqSocketClient) send() {
	for {
		select {
		case msg := <-toServer:
			c.sendMessage(msg)
			if msg.Type == "quit" {
				disconnectedFromServer <- true
			}
		}
	}
}

func (c *gomqSocketClient) sendMessage(msg *message) {
	err := c.pushSocket.Send(msg.serialize())
	if err != nil {
		log.Printf("Error sending: %v\n", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package cmd

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/open-policy-agent/opa/ast"
	pr "github.com/open-policy-agent/opa/internal/presentation"
	"github.com/open-policy-agent/opa/loader"
	"github.com/open-policy-agent/opa/metrics"
	"github.com/open-policy-agent/opa/profiler"
	"github.com/open-policy-agent/opa/rego"
	"github.com/open-policy-agent/opa/storage/inmem"
	"github.com/open-policy-agent/opa/topdown"
	"github.com/open-policy-agent/opa/util"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type evalCommandParams struct {
	dataPaths         repeatedStringFlag
	inputPath         string
	imports           repeatedStringFlag
	pkg               string
	stdin             bool
	stdinInput        bool
	explain           *util.EnumFlag
	metrics           bool
	ignore            []string
	outputFormat      *util.EnumFlag
	profile           bool
	profileTopResults bool
	profileCriteria   repeatedStringFlag
	profileLimit      intFlag
	prettyLimit       intFlag
}

const (
	explainModeOff     = ""
	explainModeFull    = "full"
	evalJSONOutput     = "json"
	evalValuesOutput   = "values"
	evalBindingsOutput = "bindings"
	evalPrettyOutput   = "pretty"

	// number of profile results to return by default
	defaultProfileLimit = 10

	defaultPrettyLimit = 80
)

// default sorting order for profiler results
var defaultSortOrder = []string{"total_time_ns", "num_eval", "num_redo", "file", "line"}

func init() {

	var params evalCommandParams

	params.outputFormat = util.NewEnumFlag(evalJSONOutput, []string{
		evalJSONOutput,
		evalValuesOutput,
		evalBindingsOutput,
		evalPrettyOutput,
	})
	params.explain = util.NewEnumFlag(explainModeOff, []string{explainModeFull})

	params.profileCriteria = newrepeatedStringFlag([]string{})
	params.profileLimit = newIntFlag(defaultProfileLimit)
	params.prettyLimit = newIntFlag(defaultPrettyLimit)

	evalCommand := &cobra.Command{
		Use:   "eval <query>",
		Short: "Evaluate a Rego query",
		Long: `Evaluate a Rego query and print the result.

Examples
--------

To evaluate a simple query:

	$ opa eval 'x = 1; y = 2; x < y'

To evaluate a query against JSON data:

	$ opa eval --data data.json 'data.names[_] = name'

File Loading
------------

The --data flag will recursively load data files and Rego files contained in
sub-directories under the path. For example, given /some/path:

	$ opa eval --data /some/path 'data'

Where /some/path contains:

	foo/
	  |
	  +-- bar/
	  |     |
	  |     +-- data.json
	  |
	  +-- baz.rego

The JSON file 'foo/bar/data.json' would be loaded and rooted under
'data.foo.bar' and the 'foo/baz.rego' would be loaded and rooted under the
package path contained inside the file.

Output Formats
--------------

Set the output format with the --format flag.

	--format=json      : output raw query results as JSON
	--format=values    : output line separated JSON arrays containing expression values
	--format=bindings  : output line separated JSON objects containing variable bindings
	--format=pretty    : output query results in a human-readable format
`,

		PreRunE: func(cmd *cobra.Command, args []string) error {
			if len(args) > 0 && params.stdin {
				return errors.New("specify query argument or --stdin but not both")
			} else if len(args) == 0 && !params.stdin {
				return errors.New("specify query argument or --stdin")
			} else if len(args) > 1 {
				return errors.New("specify at most one query argument")
			}
			if params.stdin && params.stdinInput {
				return errors.New("specify --stdin or --stdin-input but not both")
			}
			if params.stdinInput && params.inputPath != "" {
				return errors.New("specify --stdin-input or --input but not both")
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			if err := eval(args, params); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
		},
	}

	evalCommand.Flags().VarP(&params.dataPaths, "data", "d", "set data file(s) or directory path(s)")
	evalCommand.Flags().StringVarP(&params.inputPath, "input", "i", "", "set input file path")
	evalCommand.Flags().VarP(&params.imports, "import", "", "set query import(s)")
	evalCommand.Flags().StringVarP(&params.pkg, "package", "", "", "set query package")
	evalCommand.Flags().BoolVarP(&params.stdin, "stdin", "", false, "read query from stdin")
	evalCommand.Flags().BoolVarP(&params.stdinInput, "stdin-input", "I", false, "read input document from stdin")
	evalCommand.Flags().BoolVarP(&params.metrics, "metrics", "", false, "report query performance metrics")
	evalCommand.Flags().VarP(params.explain, "explain", "", "enable query explainations")
	evalCommand.Flags().VarP(params.outputFormat, "format", "f", "set output format")
	evalCommand.Flags().BoolVarP(&params.profile, "profile", "", false, "perform expression profiling")
	evalCommand.Flags().VarP(&params.profileCriteria, "profile-sort", "", "set sort order of expression profiler results")
	evalCommand.Flags().VarP(&params.profileLimit, "profile-limit", "", "set number of profiling results to show")
	evalCommand.Flags().VarP(&params.prettyLimit, "pretty-limit", "", "set limit after which pretty output gets truncated")
	setIgnore(evalCommand.Flags(), &params.ignore)

	RootCommand.AddCommand(evalCommand)
}

func eval(args []string, params evalCommandParams) (err error) {

	var query string

	if params.stdin {
		bs, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return err
		}
		query = string(bs)
	} else {
		query = args[0]
	}

	regoArgs := []func(*rego.Rego){rego.Query(query)}

	if len(params.imports.v) > 0 {
		regoArgs = append(regoArgs, rego.Imports(params.imports.v))
	}

	if params.pkg != "" {
		regoArgs = append(regoArgs, rego.Package(params.pkg))
	}

	// include metrics as part of the profiler result
	if isProfilingEnabled(params) {
		params.metrics = true
	}

	if len(params.dataPaths.v) > 0 {

		f := loaderFilter{
			Ignore: checkParams.ignore,
		}

		loadResult, err := loader.Filtered(params.dataPaths.v, f.Apply)
		if err != nil {
			return err
		}
		regoArgs = append(regoArgs, rego.Store(inmem.NewFromObject(loadResult.Documents)))
		for _, file := range loadResult.Modules {
			regoArgs = append(regoArgs, rego.Module(file.Name, string(file.Raw)))
		}
	}

	bs, err := readInputBytes(params)
	if err != nil {
		return err
	} else if bs != nil {
		term, err := ast.ParseTerm(string(bs))
		if err != nil {
			return err
		}
		regoArgs = append(regoArgs, rego.ParsedInput(term.Value))
	}

	var tracer *topdown.BufferTracer

	switch params.explain.String() {
	case explainModeFull:
		tracer = topdown.NewBufferTracer()
		regoArgs = append(regoArgs, rego.Tracer(tracer))
	}

	var m metrics.Metrics

	if params.metrics {
		m = metrics.New()
		regoArgs = append(regoArgs, rego.Metrics(m))
	}

	var p *profiler.Profiler
	if isProfilingEnabled(params) {
		p = profiler.New()
		regoArgs = append(regoArgs, rego.Tracer(p))
	}

	eval := rego.New(regoArgs...)
	ctx := context.Background()
	rs, err := eval.Eval(ctx)

	result := pr.Output{
		Error:  err,
		Result: rs,
	}

	if tracer != nil {
		result.Explanation = *tracer
	}

	if m != nil {
		result.Metrics = m
	}

	if isProfilingEnabled(params) {
		var sortOrder = defaultSortOrder

		if len(params.profileCriteria.v) != 0 {
			sortOrder = getProfileSortOrder(strings.Split(params.profileCriteria.String(), ","))
		}

		result.Profile = p.ReportTopNResults(params.profileLimit.v, sortOrder)
	}

	switch params.outputFormat.String() {
	case evalBindingsOutput:
		return pr.Bindings(os.Stdout, result)
	case evalValuesOutput:
		return pr.Values(os.Stdout, result)
	case evalPrettyOutput:
		return pr.Pretty(os.Stdout, result)
	default:
		return pr.JSON(os.Stdout, result)
	}
}

func getProfileSortOrder(sortOrder []string) []string {

	// convert the sort order slice to a map for faster lookups
	sortOrderMap := make(map[string]bool)
	for _, cr := range sortOrder {
		sortOrderMap[cr] = true
	}

	// compare the given sort order and the default
	for _, cr := range defaultSortOrder {
		if _, ok := sortOrderMap[cr]; !ok {
			sortOrder = append(sortOrder, cr)
		}
	}
	return sortOrder
}

func isProfilingEnabled(params evalCommandParams) bool {
	if params.profile || params.profileCriteria.isFlagSet() || params.profileLimit.isFlagSet() {
		return true
	}
	return false
}

func readInputBytes(params evalCommandParams) ([]byte, error) {
	if params.stdinInput {
		return ioutil.ReadAll(os.Stdin)
	} else if params.inputPath != "" {
		return ioutil.ReadFile(params.inputPath)
	}
	return nil, nil
}

type repeatedStringFlag struct {
	v     []string
	isSet bool
}

func newrepeatedStringFlag(val []string) repeatedStringFlag {
	return repeatedStringFlag{
		v:     val,
		isSet: false,
	}
}

func (f *repeatedStringFlag) Type() string {
	return "string"
}

func (f *repeatedStringFlag) String() string {
	return strings.Join(f.v, ",")
}

func (f *repeatedStringFlag) Set(s string) error {
	f.v = append(f.v, s)
	f.isSet = true
	return nil
}

func (f *repeatedStringFlag) isFlagSet() bool {
	return f.isSet
}

type intFlag struct {
	v     int
	isSet bool
}

func newIntFlag(val int) intFlag {
	return intFlag{
		v:     val,
		isSet: false,
	}
}

func (f *intFlag) Type() string {
	return "int"
}

func (f *intFlag) String() string {
	return strconv.Itoa(f.v)
}

func (f *intFlag) Set(s string) error {
	v, err := strconv.ParseInt(s, 0, 64)
	f.v = int(v)
	f.isSet = true
	return err
}

func (f *intFlag) isFlagSet() bool {
	return f.isSet
}
<commit_msg>Refactor eval subcommand flag handling<commit_after>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package cmd

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/open-policy-agent/opa/ast"
	pr "github.com/open-policy-agent/opa/internal/presentation"
	"github.com/open-policy-agent/opa/loader"
	"github.com/open-policy-agent/opa/metrics"
	"github.com/open-policy-agent/opa/profiler"
	"github.com/open-policy-agent/opa/rego"
	"github.com/open-policy-agent/opa/storage/inmem"
	"github.com/open-policy-agent/opa/topdown"
	"github.com/open-policy-agent/opa/util"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type evalCommandParams struct {
	dataPaths         repeatedStringFlag
	inputPath         string
	imports           repeatedStringFlag
	pkg               string
	stdin             bool
	stdinInput        bool
	explain           *util.EnumFlag
	metrics           bool
	ignore            []string
	outputFormat      *util.EnumFlag
	profile           bool
	profileTopResults bool
	profileCriteria   repeatedStringFlag
	profileLimit      intFlag
	prettyLimit       intFlag
}

const (
	explainModeOff     = ""
	explainModeFull    = "full"
	evalJSONOutput     = "json"
	evalValuesOutput   = "values"
	evalBindingsOutput = "bindings"
	evalPrettyOutput   = "pretty"

	// number of profile results to return by default
	defaultProfileLimit = 10

	defaultPrettyLimit = 80
)

// default sorting order for profiler results
var defaultSortOrder = []string{"total_time_ns", "num_eval", "num_redo", "file", "line"}

func init() {

	var params evalCommandParams

	params.outputFormat = util.NewEnumFlag(evalJSONOutput, []string{
		evalJSONOutput,
		evalValuesOutput,
		evalBindingsOutput,
		evalPrettyOutput,
	})
	params.explain = util.NewEnumFlag(explainModeOff, []string{explainModeFull})

	params.profileCriteria = newrepeatedStringFlag([]string{})
	params.profileLimit = newIntFlag(defaultProfileLimit)
	params.prettyLimit = newIntFlag(defaultPrettyLimit)

	evalCommand := &cobra.Command{
		Use:   "eval <query>",
		Short: "Evaluate a Rego query",
		Long: `Evaluate a Rego query and print the result.

Examples
--------

To evaluate a simple query:

	$ opa eval 'x = 1; y = 2; x < y'

To evaluate a query against JSON data:

	$ opa eval --data data.json 'data.names[_] = name'

File Loading
------------

The --data flag will recursively load data files and Rego files contained in
sub-directories under the path. For example, given /some/path:

	$ opa eval --data /some/path 'data'

Where /some/path contains:

	foo/
	  |
	  +-- bar/
	  |     |
	  |     +-- data.json
	  |
	  +-- baz.rego

The JSON file 'foo/bar/data.json' would be loaded and rooted under
'data.foo.bar' and the 'foo/baz.rego' would be loaded and rooted under the
package path contained inside the file.

Output Formats
--------------

Set the output format with the --format flag.

	--format=json      : output raw query results as JSON
	--format=values    : output line separated JSON arrays containing expression values
	--format=bindings  : output line separated JSON objects containing variable bindings
	--format=pretty    : output query results in a human-readable format
`,

		PreRunE: func(cmd *cobra.Command, args []string) error {
			if len(args) > 0 && params.stdin {
				return errors.New("specify query argument or --stdin but not both")
			} else if len(args) == 0 && !params.stdin {
				return errors.New("specify query argument or --stdin")
			} else if len(args) > 1 {
				return errors.New("specify at most one query argument")
			}
			if params.stdin && params.stdinInput {
				return errors.New("specify --stdin or --stdin-input but not both")
			}
			if params.stdinInput && params.inputPath != "" {
				return errors.New("specify --stdin-input or --input but not both")
			}
			if params.profileLimit.isFlagSet() || params.profileCriteria.isFlagSet() {
				params.profile = true
			}
			if params.profile {
				params.metrics = true
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			if err := eval(args, params); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
		},
	}

	evalCommand.Flags().VarP(&params.dataPaths, "data", "d", "set data file(s) or directory path(s)")
	evalCommand.Flags().StringVarP(&params.inputPath, "input", "i", "", "set input file path")
	evalCommand.Flags().VarP(&params.imports, "import", "", "set query import(s)")
	evalCommand.Flags().StringVarP(&params.pkg, "package", "", "", "set query package")
	evalCommand.Flags().BoolVarP(&params.stdin, "stdin", "", false, "read query from stdin")
	evalCommand.Flags().BoolVarP(&params.stdinInput, "stdin-input", "I", false, "read input document from stdin")
	evalCommand.Flags().BoolVarP(&params.metrics, "metrics", "", false, "report query performance metrics")
	evalCommand.Flags().VarP(params.explain, "explain", "", "enable query explainations")
	evalCommand.Flags().VarP(params.outputFormat, "format", "f", "set output format")
	evalCommand.Flags().BoolVarP(&params.profile, "profile", "", false, "perform expression profiling")
	evalCommand.Flags().VarP(&params.profileCriteria, "profile-sort", "", "set sort order of expression profiler results")
	evalCommand.Flags().VarP(&params.profileLimit, "profile-limit", "", "set number of profiling results to show")
	evalCommand.Flags().VarP(&params.prettyLimit, "pretty-limit", "", "set limit after which pretty output gets truncated")
	setIgnore(evalCommand.Flags(), &params.ignore)

	RootCommand.AddCommand(evalCommand)
}

func eval(args []string, params evalCommandParams) (err error) {

	var query string

	if params.stdin {
		bs, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return err
		}
		query = string(bs)
	} else {
		query = args[0]
	}

	regoArgs := []func(*rego.Rego){rego.Query(query)}

	if len(params.imports.v) > 0 {
		regoArgs = append(regoArgs, rego.Imports(params.imports.v))
	}

	if params.pkg != "" {
		regoArgs = append(regoArgs, rego.Package(params.pkg))
	}

	if len(params.dataPaths.v) > 0 {

		f := loaderFilter{
			Ignore: checkParams.ignore,
		}

		loadResult, err := loader.Filtered(params.dataPaths.v, f.Apply)
		if err != nil {
			return err
		}
		regoArgs = append(regoArgs, rego.Store(inmem.NewFromObject(loadResult.Documents)))
		for _, file := range loadResult.Modules {
			regoArgs = append(regoArgs, rego.Module(file.Name, string(file.Raw)))
		}
	}

	bs, err := readInputBytes(params)
	if err != nil {
		return err
	} else if bs != nil {
		term, err := ast.ParseTerm(string(bs))
		if err != nil {
			return err
		}
		regoArgs = append(regoArgs, rego.ParsedInput(term.Value))
	}

	var tracer *topdown.BufferTracer

	switch params.explain.String() {
	case explainModeFull:
		tracer = topdown.NewBufferTracer()
		regoArgs = append(regoArgs, rego.Tracer(tracer))
	}

	var m metrics.Metrics

	if params.metrics {
		m = metrics.New()
		regoArgs = append(regoArgs, rego.Metrics(m))
	}

	var p *profiler.Profiler
	if params.profile {
		p = profiler.New()
		regoArgs = append(regoArgs, rego.Tracer(p))
	}

	eval := rego.New(regoArgs...)
	ctx := context.Background()
	rs, err := eval.Eval(ctx)

	result := pr.Output{
		Error:  err,
		Result: rs,
	}

	if tracer != nil {
		result.Explanation = *tracer
	}

	if m != nil {
		result.Metrics = m
	}

	if params.profile {
		var sortOrder = defaultSortOrder

		if len(params.profileCriteria.v) != 0 {
			sortOrder = getProfileSortOrder(strings.Split(params.profileCriteria.String(), ","))
		}

		result.Profile = p.ReportTopNResults(params.profileLimit.v, sortOrder)
	}

	switch params.outputFormat.String() {
	case evalBindingsOutput:
		return pr.Bindings(os.Stdout, result)
	case evalValuesOutput:
		return pr.Values(os.Stdout, result)
	case evalPrettyOutput:
		return pr.Pretty(os.Stdout, result)
	default:
		return pr.JSON(os.Stdout, result)
	}
}

func getProfileSortOrder(sortOrder []string) []string {

	// convert the sort order slice to a map for faster lookups
	sortOrderMap := make(map[string]bool)
	for _, cr := range sortOrder {
		sortOrderMap[cr] = true
	}

	// compare the given sort order and the default
	for _, cr := range defaultSortOrder {
		if _, ok := sortOrderMap[cr]; !ok {
			sortOrder = append(sortOrder, cr)
		}
	}
	return sortOrder
}

func readInputBytes(params evalCommandParams) ([]byte, error) {
	if params.stdinInput {
		return ioutil.ReadAll(os.Stdin)
	} else if params.inputPath != "" {
		return ioutil.ReadFile(params.inputPath)
	}
	return nil, nil
}

type repeatedStringFlag struct {
	v     []string
	isSet bool
}

func newrepeatedStringFlag(val []string) repeatedStringFlag {
	return repeatedStringFlag{
		v:     val,
		isSet: false,
	}
}

func (f *repeatedStringFlag) Type() string {
	return "string"
}

func (f *repeatedStringFlag) String() string {
	return strings.Join(f.v, ",")
}

func (f *repeatedStringFlag) Set(s string) error {
	f.v = append(f.v, s)
	f.isSet = true
	return nil
}

func (f *repeatedStringFlag) isFlagSet() bool {
	return f.isSet
}

type intFlag struct {
	v     int
	isSet bool
}

func newIntFlag(val int) intFlag {
	return intFlag{
		v:     val,
		isSet: false,
	}
}

func (f *intFlag) Type() string {
	return "int"
}

func (f *intFlag) String() string {
	return strconv.Itoa(f.v)
}

func (f *intFlag) Set(s string) error {
	v, err := strconv.ParseInt(s, 0, 64)
	f.v = int(v)
	f.isSet = true
	return err
}

func (f *intFlag) isFlagSet() bool {
	return f.isSet
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/BurntSushi/toml"
	"github.com/c4milo/gitd"
	"github.com/c4milo/handlers/logger"
	"github.com/hashicorp/logutils"
	"gopkg.in/tylerb/graceful.v1"
)

// Version is injected in build time and defined in the Makefile
var Version string

// Name is injected in build time and defined in the Makefile
var Name string

// Config defines the configurable options for this service.
type Config struct {
	Bind            string `toml:"bind"`
	Port            uint   `toml:"port"`
	ReposPath       string `toml:"repos_path"`
	LogLevel        string `toml:"log_level"`
	LogFilePath     string `toml:"log_file"`
	ShutdownTimeout string `toml:"shutdown_timeout"`
}

// Default configuration
var config = Config{
	Bind:            "localhost",
	Port:            12345,
	LogLevel:        "WARN",
	ShutdownTimeout: "15s",
}

// Configuration file path
var configFile string

func init() {
	reposPath, err := ioutil.TempDir(os.TempDir(), Name)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	config.ReposPath = reposPath

	flag.StringVar(&configFile, "f", "", "config file path")
	flag.Parse()

	if _, err := toml.DecodeFile(configFile, &config); err != nil {
		log.Printf("[ERROR] %v", err)
		log.Print("[ERROR] Parsing config file, using default configuration.")
	}
}

func main() {
	var logWriter io.Writer
	if config.LogFilePath != "" {
		var err error
		logWriter, err = os.OpenFile(config.LogFilePath, os.O_RDWR|os.O_APPEND, 0660)
		if err != nil {
			log.Printf("[WARN] %v", err)
		}
	}

	if logWriter == nil {
		logWriter = os.Stderr
	}

	filter := &logutils.LevelFilter{
		Levels:   []logutils.LogLevel{"DEBUG", "WARN", "ERROR"},
		MinLevel: logutils.LogLevel(config.LogLevel),
		Writer:   logWriter,
	}

	log.SetOutput(filter)

	mux := http.DefaultServeMux
	rack := gitd.Handler(mux, gitd.ReposPath(config.ReposPath))
	rack = logger.Handler(rack, logger.AppName(Name))

	address := fmt.Sprintf("%s:%d", config.Bind, config.Port)
	timeout, err := time.ParseDuration(config.ShutdownTimeout)
	if err != nil {
		log.Fatalf("[ERROR] %v", err)
	}

	log.Printf("[INFO] Listening on %s...", address)
	log.Printf("[INFO] Serving Git repositories over HTTP from %s", config.ReposPath)

	graceful.Run(address, timeout, rack)
}
<commit_msg>Adds license header.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/BurntSushi/toml"
	"github.com/c4milo/gitd"
	"github.com/c4milo/handlers/logger"
	"github.com/hashicorp/logutils"
	"gopkg.in/tylerb/graceful.v1"
)

// Version is injected in build time and defined in the Makefile
var Version string

// Name is injected in build time and defined in the Makefile
var Name string

// Config defines the configurable options for this service.
type Config struct {
	Bind            string `toml:"bind"`
	Port            uint   `toml:"port"`
	ReposPath       string `toml:"repos_path"`
	LogLevel        string `toml:"log_level"`
	LogFilePath     string `toml:"log_file"`
	ShutdownTimeout string `toml:"shutdown_timeout"`
}

// Default configuration
var config = Config{
	Bind:            "localhost",
	Port:            12345,
	LogLevel:        "WARN",
	ShutdownTimeout: "15s",
}

// Configuration file path
var configFile string

func init() {
	reposPath, err := ioutil.TempDir(os.TempDir(), Name)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	config.ReposPath = reposPath

	flag.StringVar(&configFile, "f", "", "config file path")
	flag.Parse()

	if _, err := toml.DecodeFile(configFile, &config); err != nil {
		log.Printf("[ERROR] %v", err)
		log.Print("[ERROR] Parsing config file, using default configuration.")
	}
}

func main() {
	var logWriter io.Writer
	if config.LogFilePath != "" {
		var err error
		logWriter, err = os.OpenFile(config.LogFilePath, os.O_RDWR|os.O_APPEND, 0660)
		if err != nil {
			log.Printf("[WARN] %v", err)
		}
	}

	if logWriter == nil {
		logWriter = os.Stderr
	}

	filter := &logutils.LevelFilter{
		Levels:   []logutils.LogLevel{"DEBUG", "WARN", "ERROR"},
		MinLevel: logutils.LogLevel(config.LogLevel),
		Writer:   logWriter,
	}

	log.SetOutput(filter)

	mux := http.DefaultServeMux
	rack := gitd.Handler(mux, gitd.ReposPath(config.ReposPath))
	rack = logger.Handler(rack, logger.AppName(Name))

	address := fmt.Sprintf("%s:%d", config.Bind, config.Port)
	timeout, err := time.ParseDuration(config.ShutdownTimeout)
	if err != nil {
		log.Fatalf("[ERROR] %v", err)
	}

	log.Printf("[INFO] Listening on %s...", address)
	log.Printf("[INFO] Serving Git repositories over HTTP from %s", config.ReposPath)

	graceful.Run(address, timeout, rack)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	"github.com/minio/cli"
	"github.com/minio/minio/internal/color"
	"github.com/minio/pkg/console"
	"github.com/minio/pkg/trie"
	"github.com/minio/pkg/words"
)

// GlobalFlags - global flags for minio.
var GlobalFlags = []cli.Flag{
	// Deprecated flag, so its hidden now - existing deployments will keep working.
	cli.StringFlag{
		Name:   "config-dir, C",
		Value:  defaultConfigDir.Get(),
		Usage:  "[DEPRECATED] path to legacy configuration directory",
		Hidden: true,
	},
	cli.StringFlag{
		Name:  "certs-dir, S",
		Value: defaultCertsDir.Get(),
		Usage: "path to certs directory",
	},
	cli.BoolFlag{
		Name:  "quiet",
		Usage: "disable startup and info messages",
	},
	cli.BoolFlag{
		Name:  "anonymous",
		Usage: "hide sensitive information from logging",
	},
	cli.BoolFlag{
		Name:  "json",
		Usage: "output logs in JSON format",
	},
	// Deprecated flag, so its hidden now, existing deployments will keep working.
	cli.BoolFlag{
		Name:   "compat",
		Usage:  "enable strict S3 compatibility by turning off certain performance optimizations",
		Hidden: true,
	},
	// This flag is hidden and to be used only during certain performance testing.
	cli.BoolFlag{
		Name:   "no-compat",
		Usage:  "disable strict S3 compatibility by turning on certain performance optimizations",
		Hidden: true,
	},
}

// Help template for minio.
var minioHelpTemplate = `NAME:
  {{.Name}} - {{.Usage}}

DESCRIPTION:
  {{.Description}}

USAGE:
  {{.HelpName}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}}{{end}} [ARGS...]

COMMANDS:
  {{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
  {{end}}{{if .VisibleFlags}}
FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}{{end}}
VERSION:
  {{.Version}}
`

func newApp(name string) *cli.App {
	// Collection of minio commands currently supported are.
	commands := []cli.Command{}

	// Collection of minio commands currently supported in a trie tree.
	commandsTree := trie.NewTrie()

	// registerCommand registers a cli command.
	registerCommand := func(command cli.Command) {
		commands = append(commands, command)
		commandsTree.Insert(command.Name)
	}

	findClosestCommands := func(command string) []string {
		var closestCommands []string
		closestCommands = append(closestCommands, commandsTree.PrefixMatch(command)...)

		sort.Strings(closestCommands)
		// Suggest other close commands - allow missed, wrongly added and
		// even transposed characters
		for _, value := range commandsTree.Walk(commandsTree.Root()) {
			if sort.SearchStrings(closestCommands, value) < len(closestCommands) {
				continue
			}
			// 2 is arbitrary and represents the max
			// allowed number of typed errors
			if words.DamerauLevenshteinDistance(command, value) < 2 {
				closestCommands = append(closestCommands, value)
			}
		}

		return closestCommands
	}

	// Register all commands.
	registerCommand(serverCmd)
	registerCommand(gatewayCmd)

	// Set up app.
	cli.HelpFlag = cli.BoolFlag{
		Name:  "help, h",
		Usage: "show help",
	}
	cli.VersionPrinter = printMinIOVersion

	app := cli.NewApp()
	app.Name = name
	app.Author = "MinIO, Inc."
	app.Version = ReleaseTag
	app.Usage = "High Performance Object Storage"
	app.Description = `Build high performance data infrastructure for machine learning, analytics and application data workloads with MinIO`
	app.Flags = GlobalFlags
	app.HideHelpCommand = true // Hide `help, h` command, we already have `minio --help`.
	app.Commands = commands
	app.CustomAppHelpTemplate = minioHelpTemplate
	app.CommandNotFound = func(ctx *cli.Context, command string) {
		console.Printf("‘%s’ is not a minio sub-command. See ‘minio --help’.\n", command)
		closestCommands := findClosestCommands(command)
		if len(closestCommands) > 0 {
			console.Println()
			console.Println("Did you mean one of these?")
			for _, cmd := range closestCommands {
				console.Printf("\t‘%s’\n", cmd)
			}
		}

		os.Exit(1)
	}

	return app
}

func startupBanner(banner io.Writer) {
	fmt.Fprintln(banner, color.Blue("Runtime:")+color.Bold(" %s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH))
	fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>"))
	fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear))
}

func versionBanner(c *cli.Context) io.Reader {
	banner := &strings.Builder{}
	fmt.Fprintln(banner, color.Bold("%s version %s (commit-id=%s)", c.App.Name, c.App.Version, CommitID))
	startupBanner(banner)
	return strings.NewReader(banner.String())
}

func printMinIOVersion(c *cli.Context) {
	io.Copy(c.App.Writer, versionBanner(c))
}

// Main main for minio server.
func Main(args []string) {
	// Set the minio app name.
	appName := filepath.Base(args[0])

	// Run the app - exit on error.
	if err := newApp(appName).Run(args); err != nil {
		os.Exit(1)
	}
}
<commit_msg>update banner with version+runtime (#15206)<commit_after>// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"

	"github.com/minio/cli"
	"github.com/minio/minio/internal/color"
	"github.com/minio/pkg/console"
	"github.com/minio/pkg/trie"
	"github.com/minio/pkg/words"
)

// GlobalFlags - global flags for minio.
var GlobalFlags = []cli.Flag{
	// Deprecated flag, so its hidden now - existing deployments will keep working.
	cli.StringFlag{
		Name:   "config-dir, C",
		Value:  defaultConfigDir.Get(),
		Usage:  "[DEPRECATED] path to legacy configuration directory",
		Hidden: true,
	},
	cli.StringFlag{
		Name:  "certs-dir, S",
		Value: defaultCertsDir.Get(),
		Usage: "path to certs directory",
	},
	cli.BoolFlag{
		Name:  "quiet",
		Usage: "disable startup and info messages",
	},
	cli.BoolFlag{
		Name:  "anonymous",
		Usage: "hide sensitive information from logging",
	},
	cli.BoolFlag{
		Name:  "json",
		Usage: "output logs in JSON format",
	},
	// Deprecated flag, so its hidden now, existing deployments will keep working.
	cli.BoolFlag{
		Name:   "compat",
		Usage:  "enable strict S3 compatibility by turning off certain performance optimizations",
		Hidden: true,
	},
	// This flag is hidden and to be used only during certain performance testing.
	cli.BoolFlag{
		Name:   "no-compat",
		Usage:  "disable strict S3 compatibility by turning on certain performance optimizations",
		Hidden: true,
	},
}

// Help template for minio.
var minioHelpTemplate = `NAME:
  {{.Name}} - {{.Usage}}

DESCRIPTION:
  {{.Description}}

USAGE:
  {{.HelpName}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}}{{end}} [ARGS...]

COMMANDS:
  {{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
  {{end}}{{if .VisibleFlags}}
FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}{{end}}
VERSION:
  {{.Version}}
`

func newApp(name string) *cli.App {
	// Collection of minio commands currently supported are.
	commands := []cli.Command{}

	// Collection of minio commands currently supported in a trie tree.
	commandsTree := trie.NewTrie()

	// registerCommand registers a cli command.
	registerCommand := func(command cli.Command) {
		commands = append(commands, command)
		commandsTree.Insert(command.Name)
	}

	findClosestCommands := func(command string) []string {
		var closestCommands []string
		closestCommands = append(closestCommands, commandsTree.PrefixMatch(command)...)

		sort.Strings(closestCommands)
		// Suggest other close commands - allow missed, wrongly added and
		// even transposed characters
		for _, value := range commandsTree.Walk(commandsTree.Root()) {
			if sort.SearchStrings(closestCommands, value) < len(closestCommands) {
				continue
			}
			// 2 is arbitrary and represents the max
			// allowed number of typed errors
			if words.DamerauLevenshteinDistance(command, value) < 2 {
				closestCommands = append(closestCommands, value)
			}
		}

		return closestCommands
	}

	// Register all commands.
	registerCommand(serverCmd)
	registerCommand(gatewayCmd)

	// Set up app.
	cli.HelpFlag = cli.BoolFlag{
		Name:  "help, h",
		Usage: "show help",
	}
	cli.VersionPrinter = printMinIOVersion

	app := cli.NewApp()
	app.Name = name
	app.Author = "MinIO, Inc."
	app.Version = ReleaseTag
	app.Usage = "High Performance Object Storage"
	app.Description = `Build high performance data infrastructure for machine learning, analytics and application data workloads with MinIO`
	app.Flags = GlobalFlags
	app.HideHelpCommand = true // Hide `help, h` command, we already have `minio --help`.
	app.Commands = commands
	app.CustomAppHelpTemplate = minioHelpTemplate
	app.CommandNotFound = func(ctx *cli.Context, command string) {
		console.Printf("‘%s’ is not a minio sub-command. See ‘minio --help’.\n", command)
		closestCommands := findClosestCommands(command)
		if len(closestCommands) > 0 {
			console.Println()
			console.Println("Did you mean one of these?")
			for _, cmd := range closestCommands {
				console.Printf("\t‘%s’\n", cmd)
			}
		}

		os.Exit(1)
	}

	return app
}

func startupBanner(banner io.Writer) {
	fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear))
	fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>"))
	fmt.Fprintln(banner, color.Blue("Version:")+color.Bold(" %s (%s %s/%s)", ReleaseTag, runtime.Version(), runtime.GOOS, runtime.GOARCH))
}

func versionBanner(c *cli.Context) io.Reader {
	banner := &strings.Builder{}
	fmt.Fprintln(banner, color.Bold("%s version %s (commit-id=%s)", c.App.Name, c.App.Version, CommitID))
	fmt.Fprintln(banner, color.Blue("Runtime:")+color.Bold(" %s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH))
	fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>"))
	fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear))
	return strings.NewReader(banner.String())
}

func printMinIOVersion(c *cli.Context) {
	io.Copy(c.App.Writer, versionBanner(c))
}

// Main main for minio server.
func Main(args []string) {
	// Set the minio app name.
	appName := filepath.Base(args[0])

	// Run the app - exit on error.
	if err := newApp(appName).Run(args); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>