<commit_before>// +build cgo,linux

/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cadvisor

import (
	"flag"
	"fmt"
	"net/http"
	"regexp"
	"time"

	"github.com/golang/glog"
	"github.com/google/cadvisor/cache/memory"
	cadvisorMetrics "github.com/google/cadvisor/container"
	"github.com/google/cadvisor/events"
	cadvisorfs "github.com/google/cadvisor/fs"
	cadvisorhttp "github.com/google/cadvisor/http"
	cadvisorapi "github.com/google/cadvisor/info/v1"
	cadvisorapiv2 "github.com/google/cadvisor/info/v2"
	"github.com/google/cadvisor/manager"
	"github.com/google/cadvisor/utils/sysfs"
	"k8s.io/kubernetes/pkg/util/runtime"
)

type cadvisorClient struct {
	runtime string
	manager.Manager
}

var _ Interface = new(cadvisorClient)

// TODO(vmarmol): Make configurable.
// The amount of time for which to keep stats in memory.
const statsCacheDuration = 2 * time.Minute
const maxHousekeepingInterval = 15 * time.Second
const defaultHousekeepingInterval = 10 * time.Second
const allowDynamicHousekeeping = true

func init() {
	// Override cAdvisor flag defaults.
	flagOverrides := map[string]string{
		// Override the default cAdvisor housekeeping interval.
		"housekeeping_interval": defaultHousekeepingInterval.String(),
		// Disable event storage by default.
		"event_storage_event_limit": "default=0",
		"event_storage_age_limit":   "default=0",
	}
	for name, defaultValue := range flagOverrides {
		if f := flag.Lookup(name); f != nil {
			f.DefValue = defaultValue
			f.Value.Set(defaultValue)
		} else {
			glog.Errorf("Expected cAdvisor flag %q not found", name)
		}
	}
}

// Creates a cAdvisor and exports its API on the specified port if port > 0.
func New(port uint, runtime string) (Interface, error) {
	sysFs, err := sysfs.NewRealSysFs()
	if err != nil {
		return nil, err
	}

	// Create and start the cAdvisor container manager.
	m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, maxHousekeepingInterval, allowDynamicHousekeeping, cadvisorMetrics.MetricSet{cadvisorMetrics.NetworkTcpUsageMetrics: struct{}{}})
	if err != nil {
		return nil, err
	}

	cadvisorClient := &cadvisorClient{
		runtime: runtime,
		Manager: m,
	}

	err = cadvisorClient.exportHTTP(port)
	if err != nil {
		return nil, err
	}
	return cadvisorClient, nil
}

func (cc *cadvisorClient) Start() error {
	return cc.Manager.Start()
}

func (cc *cadvisorClient) exportHTTP(port uint) error {
	// Register the handlers regardless as this registers the prometheus
	// collector properly.
	mux := http.NewServeMux()
	err := cadvisorhttp.RegisterHandlers(mux, cc, "", "", "", "")
	if err != nil {
		return err
	}

	re := regexp.MustCompile(`^k8s_(?P<kubernetes_container_name>[^_\.]+)[^_]+_(?P<kubernetes_pod_name>[^_]+)_(?P<kubernetes_namespace>[^_]+)`)
	reCaptureNames := re.SubexpNames()
	cadvisorhttp.RegisterPrometheusHandler(mux, cc, "/metrics", func(name string) map[string]string {
		extraLabels := map[string]string{}
		matches := re.FindStringSubmatch(name)
		for i, match := range matches {
			if len(reCaptureNames[i]) > 0 {
				extraLabels[re.SubexpNames()[i]] = match
			}
		}
		return extraLabels
	})

	// Only start the http server if port > 0
	if port > 0 {
		serv := &http.Server{
			Addr:    fmt.Sprintf(":%d", port),
			Handler: mux,
		}

		// TODO(vmarmol): Remove this when the cAdvisor port is once again free.
		// If export failed, retry in the background until we are able to bind.
		// This allows an existing cAdvisor to be killed before this one registers.
		go func() {
			defer runtime.HandleCrash()

			err := serv.ListenAndServe()
			for err != nil {
				glog.Infof("Failed to register cAdvisor on port %d, retrying. Error: %v", port, err)
				time.Sleep(time.Minute)
				err = serv.ListenAndServe()
			}
		}()
	}

	return nil
}

func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
	return cc.GetContainerInfo(name, req)
}

func (cc *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
	return cc.GetContainerInfoV2(name, options)
}

func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) {
	return cc.GetVersionInfo()
}

func (cc *cadvisorClient) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
	infos, err := cc.SubcontainersInfo(name, req)
	if err != nil && len(infos) == 0 {
		return nil, err
	}

	result := make(map[string]*cadvisorapi.ContainerInfo, len(infos))
	for _, info := range infos {
		result[info.Name] = info
	}
	return result, err
}

func (cc *cadvisorClient) MachineInfo() (*cadvisorapi.MachineInfo, error) {
	return cc.GetMachineInfo()
}

func (cc *cadvisorClient) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
	var label string

	switch cc.runtime {
	case "docker":
		label = cadvisorfs.LabelDockerImages
	case "rkt":
		label = cadvisorfs.LabelRktImages
	default:
		return cadvisorapiv2.FsInfo{}, fmt.Errorf("ImagesFsInfo: unknown runtime: %v", cc.runtime)
	}

	return cc.getFsInfo(label)
}

func (cc *cadvisorClient) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
	return cc.getFsInfo(cadvisorfs.LabelSystemRoot)
}

func (cc *cadvisorClient) getFsInfo(label string) (cadvisorapiv2.FsInfo, error) {
	res, err := cc.GetFsInfo(label)
	if err != nil {
		return cadvisorapiv2.FsInfo{}, err
	}
	if len(res) == 0 {
		return cadvisorapiv2.FsInfo{}, fmt.Errorf("failed to find information for the filesystem labeled %q", label)
	}
	// TODO(vmarmol): Handle this better when a label has more than one image filesystem.
	if len(res) > 1 {
		glog.Warningf("More than one filesystem labeled %q: %#v. Only using the first one", label, res)
	}

	return res[0], nil
}

func (cc *cadvisorClient) WatchEvents(request *events.Request) (*events.EventChannel, error) {
	return cc.WatchForEvents(request)
}
<commit_msg>Remove duplicate prometheus metrics<commit_after>// +build cgo,linux

/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cadvisor

import (
	"flag"
	"fmt"
	"net/http"
	"time"

	"github.com/golang/glog"
	"github.com/google/cadvisor/cache/memory"
	cadvisorMetrics "github.com/google/cadvisor/container"
	"github.com/google/cadvisor/events"
	cadvisorfs "github.com/google/cadvisor/fs"
	cadvisorhttp "github.com/google/cadvisor/http"
	cadvisorapi "github.com/google/cadvisor/info/v1"
	cadvisorapiv2 "github.com/google/cadvisor/info/v2"
	"github.com/google/cadvisor/manager"
	"github.com/google/cadvisor/utils/sysfs"
	"k8s.io/kubernetes/pkg/util/runtime"
)

type cadvisorClient struct {
	runtime string
	manager.Manager
}

var _ Interface = new(cadvisorClient)

// TODO(vmarmol): Make configurable.
// The amount of time for which to keep stats in memory.
const statsCacheDuration = 2 * time.Minute
const maxHousekeepingInterval = 15 * time.Second
const defaultHousekeepingInterval = 10 * time.Second
const allowDynamicHousekeeping = true

func init() {
	// Override cAdvisor flag defaults.
	flagOverrides := map[string]string{
		// Override the default cAdvisor housekeeping interval.
		"housekeeping_interval": defaultHousekeepingInterval.String(),
		// Disable event storage by default.
		"event_storage_event_limit": "default=0",
		"event_storage_age_limit":   "default=0",
	}
	for name, defaultValue := range flagOverrides {
		if f := flag.Lookup(name); f != nil {
			f.DefValue = defaultValue
			f.Value.Set(defaultValue)
		} else {
			glog.Errorf("Expected cAdvisor flag %q not found", name)
		}
	}
}

// Creates a cAdvisor and exports its API on the specified port if port > 0.
func New(port uint, runtime string) (Interface, error) {
	sysFs, err := sysfs.NewRealSysFs()
	if err != nil {
		return nil, err
	}

	// Create and start the cAdvisor container manager.
	m, err := manager.New(memory.New(statsCacheDuration, nil), sysFs, maxHousekeepingInterval, allowDynamicHousekeeping, cadvisorMetrics.MetricSet{cadvisorMetrics.NetworkTcpUsageMetrics: struct{}{}})
	if err != nil {
		return nil, err
	}

	cadvisorClient := &cadvisorClient{
		runtime: runtime,
		Manager: m,
	}

	err = cadvisorClient.exportHTTP(port)
	if err != nil {
		return nil, err
	}
	return cadvisorClient, nil
}

func (cc *cadvisorClient) Start() error {
	return cc.Manager.Start()
}

func (cc *cadvisorClient) exportHTTP(port uint) error {
	// Register the handlers regardless as this registers the prometheus
	// collector properly.
	mux := http.NewServeMux()
	err := cadvisorhttp.RegisterHandlers(mux, cc, "", "", "", "")
	if err != nil {
		return err
	}

	cadvisorhttp.RegisterPrometheusHandler(mux, cc, "/metrics", nil)

	// Only start the http server if port > 0
	if port > 0 {
		serv := &http.Server{
			Addr:    fmt.Sprintf(":%d", port),
			Handler: mux,
		}

		// TODO(vmarmol): Remove this when the cAdvisor port is once again free.
		// If export failed, retry in the background until we are able to bind.
		// This allows an existing cAdvisor to be killed before this one registers.
		go func() {
			defer runtime.HandleCrash()

			err := serv.ListenAndServe()
			for err != nil {
				glog.Infof("Failed to register cAdvisor on port %d, retrying. Error: %v", port, err)
				time.Sleep(time.Minute)
				err = serv.ListenAndServe()
			}
		}()
	}

	return nil
}

func (cc *cadvisorClient) ContainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (*cadvisorapi.ContainerInfo, error) {
	return cc.GetContainerInfo(name, req)
}

func (cc *cadvisorClient) ContainerInfoV2(name string, options cadvisorapiv2.RequestOptions) (map[string]cadvisorapiv2.ContainerInfo, error) {
	return cc.GetContainerInfoV2(name, options)
}

func (cc *cadvisorClient) VersionInfo() (*cadvisorapi.VersionInfo, error) {
	return cc.GetVersionInfo()
}

func (cc *cadvisorClient) SubcontainerInfo(name string, req *cadvisorapi.ContainerInfoRequest) (map[string]*cadvisorapi.ContainerInfo, error) {
	infos, err := cc.SubcontainersInfo(name, req)
	if err != nil && len(infos) == 0 {
		return nil, err
	}

	result := make(map[string]*cadvisorapi.ContainerInfo, len(infos))
	for _, info := range infos {
		result[info.Name] = info
	}
	return result, err
}

func (cc *cadvisorClient) MachineInfo() (*cadvisorapi.MachineInfo, error) {
	return cc.GetMachineInfo()
}

func (cc *cadvisorClient) ImagesFsInfo() (cadvisorapiv2.FsInfo, error) {
	var label string

	switch cc.runtime {
	case "docker":
		label = cadvisorfs.LabelDockerImages
	case "rkt":
		label = cadvisorfs.LabelRktImages
	default:
		return cadvisorapiv2.FsInfo{}, fmt.Errorf("ImagesFsInfo: unknown runtime: %v", cc.runtime)
	}

	return cc.getFsInfo(label)
}

func (cc *cadvisorClient) RootFsInfo() (cadvisorapiv2.FsInfo, error) {
	return cc.getFsInfo(cadvisorfs.LabelSystemRoot)
}

func (cc *cadvisorClient) getFsInfo(label string) (cadvisorapiv2.FsInfo, error) {
	res, err := cc.GetFsInfo(label)
	if err != nil {
		return cadvisorapiv2.FsInfo{}, err
	}
	if len(res) == 0 {
		return cadvisorapiv2.FsInfo{}, fmt.Errorf("failed to find information for the filesystem labeled %q", label)
	}
	// TODO(vmarmol): Handle this better when a label has more than one image filesystem.
	if len(res) > 1 {
		glog.Warningf("More than one filesystem labeled %q: %#v. Only using the first one", label, res)
	}

	return res[0], nil
}

func (cc *cadvisorClient) WatchEvents(request *events.Request) (*events.EventChannel, error) {
	return cc.WatchForEvents(request)
}
<|endoftext|>


<commit_before>// Copyright 2012 The Plotinum Authors. All rights reserved.
// Use of this source code is governed by an MIT-style license
// that can be found in the LICENSE file.

package plotter

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/vg"
	"sort"
	"math"
)

// BoxPlot implements the Plotter interface, drawing
// a boxplot to represent the distribution of values.
type BoxPlot struct {
	// Values is a copy of the values of the values used to
	// create this box plot.
	Values

	// Location is the location of the box along its axis.
	Location float64

	// Width is the width used to draw the box.
	Width vg.Length

	// CapWidth is the width of the cap used to top
	// off a whisker.
	CapWidth vg.Length

	// Median is the median value of the data.
	Median float64

	// Quartile1 and Quartile3 are the first and
	// third quartiles of the data respectively.
	Quartile1, Quartile3 float64

	// AdjLow and AdjHigh are the `adjacent' values
	// on the low and high ends of the data.  The
	// adjacent values are the points to which the
	// whiskers are drawn.
	AdjLow, AdjHigh float64

	// Min and Max are the extreme values of the data.
	Min, Max float64

	// Outside are the indices of Vs for the outside points.
	Outside []int

	// GlyphStyle is the style of the outside point glyphs.
	plot.GlyphStyle

	// BoxStyle is the line style for the box.
	BoxStyle plot.LineStyle

	// MedianStyle is the line style for the median line.
	MedianStyle plot.LineStyle

	// WhiskerStyle is the line style used to draw the
	// whiskers.
	WhiskerStyle plot.LineStyle
}

// NewBoxPlot returns a new BoxPlot that represents
// the distribution of the given values.  The style of
// the box plot is that used for Tukey's schematic
// plots is ``Exploratory Data Analysis.''
//
// An error is returned if the boxplot is created with
// no values.
//
// The fence values are 1.5x the interquartile before
// the first quartile and after the third quartile.  Any
// value that is outside of the fences are drawn as
// Outside points.  The adjacent values (to which the
// whiskers stretch) are the minimum and maximum
// values that are not outside the fences.
func NewBoxPlot(w vg.Length, loc float64, values Valuer) *BoxPlot {
	b := new(BoxPlot)
	b.Location = loc
	b.Width = w
	b.CapWidth = 3 * w / 4
	b.GlyphStyle = DefaultGlyphStyle
	b.BoxStyle = DefaultLineStyle
	b.MedianStyle = DefaultLineStyle
	b.WhiskerStyle = plot.LineStyle{
		Width:  vg.Points(0.5),
		Dashes: []vg.Length{vg.Points(4), vg.Points(2)},
	}

	b.Values = CopyValues(values)
	sorted := CopyValues(values)
	sort.Float64s(sorted)
	if len(sorted) == 0 {
		b.Width = 0
		b.GlyphStyle.Radius = 0
		b.BoxStyle.Width = 0
		b.MedianStyle.Width = 0
		b.WhiskerStyle.Width = 0
		return b
	} else if len(sorted) == 1 {
		b.Median = sorted[0]
		b.Quartile1 = sorted[0]
		b.Quartile3 = sorted[0]
	} else {
		b.Median = median(sorted)
		b.Quartile1 = median(sorted[:len(sorted)/2])
		b.Quartile3 = median(sorted[len(sorted)/2:])
	}
	b.Min = sorted[0]
	b.Max = sorted[len(sorted)-1]

	low := b.Quartile1 - 1.5*(b.Quartile3-b.Quartile1)
	high := b.Quartile3 + 1.5*(b.Quartile3-b.Quartile1)
	b.AdjLow = math.Inf(1)
	b.AdjHigh = math.Inf(-1)
	for i, v := range b.Values {
		if v > high || v < low {
			b.Outside = append(b.Outside, i)
			continue
		}
		if v < b.AdjLow {
			b.AdjLow = v
		}
		if v > b.AdjHigh {
			b.AdjHigh = v
		}
	}

	return b
}

// median returns the median value from a
// sorted Values.
func median(vs Values) float64 {
	if len(vs) == 1 {
		return vs[0]
	}
	med := vs[len(vs)/2]
	if len(vs)%2 == 0 {
		med += vs[len(vs)/2-1]
		med /= 2
	}
	return med
}

func (b *BoxPlot) Plot(da plot.DrawArea, plt *plot.Plot) {
	trX, trY := plt.Transforms(&da)
	x := trX(b.Location)

	med := trY(b.Median)
	q1 := trY(b.Quartile1)
	q3 := trY(b.Quartile3)
	aLow := trY(b.AdjLow)
	aHigh := trY(b.AdjHigh)

	box := da.ClipLinesY([]plot.Point{
		{x - b.Width/2, q1},
		{x - b.Width/2, q3},
		{x + b.Width/2, q3},
		{x + b.Width/2, q1},
		{x - b.Width/2 - b.BoxStyle.Width/2, q1},
	})
	da.StrokeLines(b.BoxStyle, box...)

	medLine := da.ClipLinesY([]plot.Point{
		{x - b.Width/2, med},
		{x + b.Width/2, med},
	})
	da.StrokeLines(b.MedianStyle, medLine...)

	cap := b.CapWidth / 2
	whisks := da.ClipLinesY([]plot.Point{{x, q3}, {x, aHigh}},
		[]plot.Point{{x - cap, aHigh}, {x + cap, aHigh}},
		[]plot.Point{{x, q1}, {x, aLow}},
		[]plot.Point{{x - cap, aLow}, {x + cap, aLow}})
	da.StrokeLines(b.WhiskerStyle, whisks...)

	for _, out := range b.Outside {
		y := trY(b.Value(out))
		da.DrawGlyph(b.GlyphStyle, plot.Point{x, y})
	}
}

// DataRange returns the minimum and maximum x
// and y values, implementing the plot.DataRanger
// interface.
func (b *BoxPlot) DataRange() (float64, float64, float64, float64) {
	return b.Location, b.Location, b.Min, b.Max
}

// GlyphBoxes returns a slice of GlyphBoxes for the
// points and for the median line of the boxplot,
// implementing the plot.GlyphBoxer interface
func (b *BoxPlot) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {
	bs := make([]plot.GlyphBox, len(b.Outside)+1)
	for i, out := range b.Outside {
		bs[i].X = plt.X.Norm(b.Location)
		bs[i].Y = plt.Y.Norm(b.Value(out))
		bs[i].Rect = b.GlyphStyle.Rect()
	}
	bs[len(bs)-1].X = plt.X.Norm(b.Location)
	bs[len(bs)-1].Y = plt.Y.Norm(b.Median)
	bs[len(bs)-1].Rect = plot.Rect{
		Min:  plot.Point{X: -(b.Width/2 + b.BoxStyle.Width/2)},
		Size: plot.Point{X: b.Width + b.BoxStyle.Width},
	}
	return bs
}

// OutsideLabels returns a *Labels that will plot
// a label for each of the outside points.  The
// labels are assumed to correspond to the
// points used to create the box plot.
func (b *BoxPlot) OutsideLabels(labels Labeller) (*Labels, error) {
	strs := make([]string, len(b.Outside))
	for i, out := range b.Outside {
		strs[i] = labels.Label(out)
	}
	o := boxPlotOutsideLabels{b, strs}
	ls, err := NewLabels(o, o)
	if err != nil {
		return nil, err
	}
	ls.XOffset += b.GlyphStyle.Radius / 2
	ls.YOffset += b.GlyphStyle.Radius / 2
	return ls, nil
}

type boxPlotOutsideLabels struct {
	box    *BoxPlot
	labels []string
}

func (o boxPlotOutsideLabels) Len() int {
	return len(o.box.Outside)
}

func (o boxPlotOutsideLabels) XY(i int) (float64, float64) {
	return o.box.Location, o.box.Value(o.box.Outside[i])
}

func (o boxPlotOutsideLabels) Label(i int) string {
	return o.labels[i]
}

// HorizBoxPlot is like a regular BoxPlot, however,
// it draws horizontally instead of Vertically.
type HorizBoxPlot struct{ *BoxPlot }

func (b HorizBoxPlot) Plot(da plot.DrawArea, plt *plot.Plot) {
	trX, trY := plt.Transforms(&da)
	y := trY(b.Location)

	med := trX(b.Median)
	q1 := trX(b.Quartile1)
	q3 := trX(b.Quartile3)
	aLow := trX(b.AdjLow)
	aHigh := trX(b.AdjHigh)

	box := da.ClipLinesX([]plot.Point{
		{q1, y - b.Width/2},
		{q3, y - b.Width/2},
		{q3, y + b.Width/2},
		{q1, y + b.Width/2},
		{q1, y - b.Width/2 - b.BoxStyle.Width/2},
	})
	da.StrokeLines(b.BoxStyle, box...)

	medLine := da.ClipLinesX([]plot.Point{
		{med, y - b.Width/2},
		{med, y + b.Width/2},
	})
	da.StrokeLines(b.MedianStyle, medLine...)

	cap := b.CapWidth / 2
	whisks := da.ClipLinesX([]plot.Point{{q3, y}, {aHigh, y}},
		[]plot.Point{{aHigh, y - cap}, {aHigh, y + cap}},
		[]plot.Point{{q1, y}, {aLow, y}},
		[]plot.Point{{aLow, y - cap}, {aLow, y + cap}})
	da.StrokeLines(b.WhiskerStyle, whisks...)

	for _, out := range b.Outside {
		x := trX(b.Value(out))
		da.DrawGlyph(b.GlyphStyle, plot.Point{x, y})
	}
}

// DataRange returns the minimum and maximum x
// and y values, implementing the plot.DataRanger
// interface.
func (b HorizBoxPlot) DataRange() (float64, float64, float64, float64) {
	return b.Min, b.Max, b.Location, b.Location
}

// GlyphBoxes returns a slice of GlyphBoxes for the
// points and for the median line of the boxplot,
// implementing the plot.GlyphBoxer interface
func (b HorizBoxPlot) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {
	bs := make([]plot.GlyphBox, len(b.Outside)+1)
	for i, out := range b.Outside {
		bs[i].X = plt.X.Norm(b.Value(out))
		bs[i].Y = plt.Y.Norm(b.Location)
		bs[i].Rect = b.GlyphStyle.Rect()
	}
	bs[len(bs)-1].X = plt.X.Norm(b.Median)
	bs[len(bs)-1].Y = plt.Y.Norm(b.Location)
	bs[len(bs)-1].Rect = plot.Rect{
		Min:  plot.Point{Y: -(b.Width/2 + b.BoxStyle.Width/2)},
		Size: plot.Point{Y: b.Width + b.BoxStyle.Width},
	}
	return bs
}

// OutsideLabels returns a *Labels that will plot
// a label for each of the outside points.  The
// labels are assumed to correspond to the
// points used to create the box plot.
func (b *HorizBoxPlot) OutsideLabels(labels Labeller) (*Labels, error) {
	strs := make([]string, len(b.Outside))
	for i, out := range b.Outside {
		strs[i] = labels.Label(out)
	}
	o := horizBoxPlotOutsideLabels{
		boxPlotOutsideLabels{b.BoxPlot, strs},
	}
	ls, err := NewLabels(o, o)
	if err != nil {
		return nil, err
	}
	ls.XOffset += b.GlyphStyle.Radius / 2
	ls.YOffset += b.GlyphStyle.Radius / 2
	return ls, nil
}

type horizBoxPlotOutsideLabels struct {
	boxPlotOutsideLabels
}

func (o horizBoxPlotOutsideLabels) XY(i int) (float64, float64) {
	return o.box.Value(o.box.Outside[i]), o.box.Location
}
<commit_msg>Simplify the creation of horizontal box plots. Instead of wrapping a *BoxPlot in HorizBoxPlot{}, one can just use MakeHorizBoxPlot().<commit_after>// Copyright 2012 The Plotinum Authors. All rights reserved.
// Use of this source code is governed by an MIT-style license
// that can be found in the LICENSE file.

package plotter

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/vg"
	"sort"
	"math"
)

// BoxPlot implements the Plotter interface, drawing
// a boxplot to represent the distribution of values.
type BoxPlot struct {
	// Values is a copy of the values of the values used to
	// create this box plot.
	Values

	// Location is the location of the box along its axis.
	Location float64

	// Width is the width used to draw the box.
	Width vg.Length

	// CapWidth is the width of the cap used to top
	// off a whisker.
	CapWidth vg.Length

	// Median is the median value of the data.
	Median float64

	// Quartile1 and Quartile3 are the first and
	// third quartiles of the data respectively.
	Quartile1, Quartile3 float64

	// AdjLow and AdjHigh are the `adjacent' values
	// on the low and high ends of the data.  The
	// adjacent values are the points to which the
	// whiskers are drawn.
	AdjLow, AdjHigh float64

	// Min and Max are the extreme values of the data.
	Min, Max float64

	// Outside are the indices of Vs for the outside points.
	Outside []int

	// GlyphStyle is the style of the outside point glyphs.
	plot.GlyphStyle

	// BoxStyle is the line style for the box.
	BoxStyle plot.LineStyle

	// MedianStyle is the line style for the median line.
	MedianStyle plot.LineStyle

	// WhiskerStyle is the line style used to draw the
	// whiskers.
	WhiskerStyle plot.LineStyle
}

// NewBoxPlot returns a new BoxPlot that represents
// the distribution of the given values.  The style of
// the box plot is that used for Tukey's schematic
// plots is ``Exploratory Data Analysis.''
//
// An error is returned if the boxplot is created with
// no values.
//
// The fence values are 1.5x the interquartile before
// the first quartile and after the third quartile.  Any
// value that is outside of the fences are drawn as
// Outside points.  The adjacent values (to which the
// whiskers stretch) are the minimum and maximum
// values that are not outside the fences.
func NewBoxPlot(w vg.Length, loc float64, values Valuer) *BoxPlot {
	b := new(BoxPlot)
	b.Location = loc
	b.Width = w
	b.CapWidth = 3 * w / 4
	b.GlyphStyle = DefaultGlyphStyle
	b.BoxStyle = DefaultLineStyle
	b.MedianStyle = DefaultLineStyle
	b.WhiskerStyle = plot.LineStyle{
		Width:  vg.Points(0.5),
		Dashes: []vg.Length{vg.Points(4), vg.Points(2)},
	}

	b.Values = CopyValues(values)
	sorted := CopyValues(values)
	sort.Float64s(sorted)
	if len(sorted) == 0 {
		b.Width = 0
		b.GlyphStyle.Radius = 0
		b.BoxStyle.Width = 0
		b.MedianStyle.Width = 0
		b.WhiskerStyle.Width = 0
		return b
	} else if len(sorted) == 1 {
		b.Median = sorted[0]
		b.Quartile1 = sorted[0]
		b.Quartile3 = sorted[0]
	} else {
		b.Median = median(sorted)
		b.Quartile1 = median(sorted[:len(sorted)/2])
		b.Quartile3 = median(sorted[len(sorted)/2:])
	}
	b.Min = sorted[0]
	b.Max = sorted[len(sorted)-1]

	low := b.Quartile1 - 1.5*(b.Quartile3-b.Quartile1)
	high := b.Quartile3 + 1.5*(b.Quartile3-b.Quartile1)
	b.AdjLow = math.Inf(1)
	b.AdjHigh = math.Inf(-1)
	for i, v := range b.Values {
		if v > high || v < low {
			b.Outside = append(b.Outside, i)
			continue
		}
		if v < b.AdjLow {
			b.AdjLow = v
		}
		if v > b.AdjHigh {
			b.AdjHigh = v
		}
	}

	return b
}

// median returns the median value from a
// sorted Values.
func median(vs Values) float64 {
	if len(vs) == 1 {
		return vs[0]
	}
	med := vs[len(vs)/2]
	if len(vs)%2 == 0 {
		med += vs[len(vs)/2-1]
		med /= 2
	}
	return med
}

func (b *BoxPlot) Plot(da plot.DrawArea, plt *plot.Plot) {
	trX, trY := plt.Transforms(&da)
	x := trX(b.Location)

	med := trY(b.Median)
	q1 := trY(b.Quartile1)
	q3 := trY(b.Quartile3)
	aLow := trY(b.AdjLow)
	aHigh := trY(b.AdjHigh)

	box := da.ClipLinesY([]plot.Point{
		{x - b.Width/2, q1},
		{x - b.Width/2, q3},
		{x + b.Width/2, q3},
		{x + b.Width/2, q1},
		{x - b.Width/2 - b.BoxStyle.Width/2, q1},
	})
	da.StrokeLines(b.BoxStyle, box...)

	medLine := da.ClipLinesY([]plot.Point{
		{x - b.Width/2, med},
		{x + b.Width/2, med},
	})
	da.StrokeLines(b.MedianStyle, medLine...)

	cap := b.CapWidth / 2
	whisks := da.ClipLinesY([]plot.Point{{x, q3}, {x, aHigh}},
		[]plot.Point{{x - cap, aHigh}, {x + cap, aHigh}},
		[]plot.Point{{x, q1}, {x, aLow}},
		[]plot.Point{{x - cap, aLow}, {x + cap, aLow}})
	da.StrokeLines(b.WhiskerStyle, whisks...)

	for _, out := range b.Outside {
		y := trY(b.Value(out))
		da.DrawGlyph(b.GlyphStyle, plot.Point{x, y})
	}
}

// DataRange returns the minimum and maximum x
// and y values, implementing the plot.DataRanger
// interface.
func (b *BoxPlot) DataRange() (float64, float64, float64, float64) {
	return b.Location, b.Location, b.Min, b.Max
}

// GlyphBoxes returns a slice of GlyphBoxes for the
// points and for the median line of the boxplot,
// implementing the plot.GlyphBoxer interface
func (b *BoxPlot) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {
	bs := make([]plot.GlyphBox, len(b.Outside)+1)
	for i, out := range b.Outside {
		bs[i].X = plt.X.Norm(b.Location)
		bs[i].Y = plt.Y.Norm(b.Value(out))
		bs[i].Rect = b.GlyphStyle.Rect()
	}
	bs[len(bs)-1].X = plt.X.Norm(b.Location)
	bs[len(bs)-1].Y = plt.Y.Norm(b.Median)
	bs[len(bs)-1].Rect = plot.Rect{
		Min:  plot.Point{X: -(b.Width/2 + b.BoxStyle.Width/2)},
		Size: plot.Point{X: b.Width + b.BoxStyle.Width},
	}
	return bs
}

// OutsideLabels returns a *Labels that will plot
// a label for each of the outside points.  The
// labels are assumed to correspond to the
// points used to create the box plot.
func (b *BoxPlot) OutsideLabels(labels Labeller) (*Labels, error) {
	strs := make([]string, len(b.Outside))
	for i, out := range b.Outside {
		strs[i] = labels.Label(out)
	}
	o := boxPlotOutsideLabels{b, strs}
	ls, err := NewLabels(o, o)
	if err != nil {
		return nil, err
	}
	ls.XOffset += b.GlyphStyle.Radius / 2
	ls.YOffset += b.GlyphStyle.Radius / 2
	return ls, nil
}

type boxPlotOutsideLabels struct {
	box    *BoxPlot
	labels []string
}

func (o boxPlotOutsideLabels) Len() int {
	return len(o.box.Outside)
}

func (o boxPlotOutsideLabels) XY(i int) (float64, float64) {
	return o.box.Location, o.box.Value(o.box.Outside[i])
}

func (o boxPlotOutsideLabels) Label(i int) string {
	return o.labels[i]
}

// HorizBoxPlot is like a regular BoxPlot, however,
// it draws horizontally instead of Vertically.
type HorizBoxPlot struct{ *BoxPlot }

// MakeHorizBoxPlot returns a HorizBoxPlot,
// plotting the values in a horizontal box plot
// centered along a fixed location of the y axis.
func MakeHorizBoxPlot(w vg.Length, loc float64, vs Values) HorizBoxPlot {
	return HorizBoxPlot{ NewBoxPlot(w, loc, vs) }
}

func (b HorizBoxPlot) Plot(da plot.DrawArea, plt *plot.Plot) {
	trX, trY := plt.Transforms(&da)
	y := trY(b.Location)

	med := trX(b.Median)
	q1 := trX(b.Quartile1)
	q3 := trX(b.Quartile3)
	aLow := trX(b.AdjLow)
	aHigh := trX(b.AdjHigh)

	box := da.ClipLinesX([]plot.Point{
		{q1, y - b.Width/2},
		{q3, y - b.Width/2},
		{q3, y + b.Width/2},
		{q1, y + b.Width/2},
		{q1, y - b.Width/2 - b.BoxStyle.Width/2},
	})
	da.StrokeLines(b.BoxStyle, box...)

	medLine := da.ClipLinesX([]plot.Point{
		{med, y - b.Width/2},
		{med, y + b.Width/2},
	})
	da.StrokeLines(b.MedianStyle, medLine...)

	cap := b.CapWidth / 2
	whisks := da.ClipLinesX([]plot.Point{{q3, y}, {aHigh, y}},
		[]plot.Point{{aHigh, y - cap}, {aHigh, y + cap}},
		[]plot.Point{{q1, y}, {aLow, y}},
		[]plot.Point{{aLow, y - cap}, {aLow, y + cap}})
	da.StrokeLines(b.WhiskerStyle, whisks...)

	for _, out := range b.Outside {
		x := trX(b.Value(out))
		da.DrawGlyph(b.GlyphStyle, plot.Point{x, y})
	}
}

// DataRange returns the minimum and maximum x
// and y values, implementing the plot.DataRanger
// interface.
func (b HorizBoxPlot) DataRange() (float64, float64, float64, float64) {
	return b.Min, b.Max, b.Location, b.Location
}

// GlyphBoxes returns a slice of GlyphBoxes for the
// points and for the median line of the boxplot,
// implementing the plot.GlyphBoxer interface
func (b HorizBoxPlot) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {
	bs := make([]plot.GlyphBox, len(b.Outside)+1)
	for i, out := range b.Outside {
		bs[i].X = plt.X.Norm(b.Value(out))
		bs[i].Y = plt.Y.Norm(b.Location)
		bs[i].Rect = b.GlyphStyle.Rect()
	}
	bs[len(bs)-1].X = plt.X.Norm(b.Median)
	bs[len(bs)-1].Y = plt.Y.Norm(b.Location)
	bs[len(bs)-1].Rect = plot.Rect{
		Min:  plot.Point{Y: -(b.Width/2 + b.BoxStyle.Width/2)},
		Size: plot.Point{Y: b.Width + b.BoxStyle.Width},
	}
	return bs
}

// OutsideLabels returns a *Labels that will plot
// a label for each of the outside points.  The
// labels are assumed to correspond to the
// points used to create the box plot.
func (b *HorizBoxPlot) OutsideLabels(labels Labeller) (*Labels, error) {
	strs := make([]string, len(b.Outside))
	for i, out := range b.Outside {
		strs[i] = labels.Label(out)
	}
	o := horizBoxPlotOutsideLabels{
		boxPlotOutsideLabels{b.BoxPlot, strs},
	}
	ls, err := NewLabels(o, o)
	if err != nil {
		return nil, err
	}
	ls.XOffset += b.GlyphStyle.Radius / 2
	ls.YOffset += b.GlyphStyle.Radius / 2
	return ls, nil
}

type horizBoxPlotOutsideLabels struct {
	boxPlotOutsideLabels
}

func (o horizBoxPlotOutsideLabels) XY(i int) (float64, float64) {
	return o.box.Value(o.box.Outside[i]), o.box.Location
}
<|endoftext|>


<commit_before>package core

import (
	"database/sql"
	"errors"
	"time"

	_ "github.com/go-sql-driver/mysql"

	"../utils"
)

/*
	Container info
*/
type Container struct {
	ID         int
	CID        string
	ProbeID    int
	Hostname   string
	Image      string
	IPAddress  string
	MacAddress string
}

/*
	Container's stats
*/
type Stat struct {
	ContainerID int
	Time        int64
	SizeRootFs  uint64
	SizeRw      uint64
	SizeMemory  uint64
	Running     bool
}

/*
	SQL Variables
*/
var (
	// DB
	DB       *sql.DB
	ProbesID map[string]int

	// Prepared queries
	GetProbeIDStmt             *sql.Stmt
	InsertProbeStmt            *sql.Stmt
	InsertContainerStmt        *sql.Stmt
	DeleteContainerStmt        *sql.Stmt
	GetContainerLastStatStmt   *sql.Stmt
	InsertStatStmt             *sql.Stmt
	DeleteStatStmt             *sql.Stmt
	GetContainerByCIDStmt      *sql.Stmt
	GetStatsByContainerIdStmt  *sql.Stmt
	GetStatsByContainerCIDStmt *sql.Stmt
)

func InitSQL() {
	var err error // Error handling

	// Connect DB
	sqlc := DGConfig.DockerGuard.SQLServer // SQL Config
	DB, err = sql.Open("mysql", sqlc.User+":"+sqlc.Pass+"@tcp("+sqlc.IP+":"+utils.I2S(sqlc.Port)+")/"+sqlc.DB)
	if err != nil {
		l.Critical(err)
	}
	err = DB.Ping()
	if err != nil {
		l.Critical(err)
	}
	l.Verbose("Connected to SQL database")

	// Prepare DB queries
	GetProbeIDStmt, err = DB.Prepare("SELECT id FROM probes WHERE name=?")
	if err != nil {
		l.Critical("Can't create InsertContainerStmt:", err)
	}
	InsertProbeStmt, err = DB.Prepare("INSERT INTO probes VALUES (DEFAULT,?)")
	if err != nil {
		l.Critical("Can't create InsertContainerStmt:", err)
	}
	InsertContainerStmt, err = DB.Prepare("INSERT INTO containers VALUES (DEFAULT,?,?,?,?,?,?)")
	if err != nil {
		l.Critical("Can't create InsertContainerStmt:", err)
	}
	DeleteContainerStmt, err = DB.Prepare("DELETE FROM containers WHERE containerid=?")
	if err != nil {
		l.Critical("Can't create DeleteContainerStmt:", err)
	}
	GetContainerLastStatStmt, err = DB.Prepare("SELECT * FROM stats WHERE containerid=? ORDER BY time DESC LIMIT 1")
	if err != nil {
		l.Critical("Can't create DeleteContainerStmt:", err)
	}
	InsertStatStmt, err = DB.Prepare("INSERT INTO stats VALUES (?,?,?,?,?,?)")
	if err != nil {
		l.Critical("Can't create InsertStatStmt:", err)
	}
	DeleteStatStmt, err = DB.Prepare("DELETE FROM stats WHERE containerid=? AND time=?")
	if err != nil {
		l.Critical("Can't create DeleteStatStmt:", err)
	}
	GetContainerByCIDStmt, err = DB.Prepare("SELECT * FROM containers WHERE containerid=?")
	if err != nil {
		l.Critical("Can't create GetContainerByIdStmt:", err)
	}
	GetStatsByContainerIdStmt, err = DB.Prepare("SELECT * FROM containers WHERE id=?")
	if err != nil {
		l.Critical("Can't create GetStatsByContainerIdStmt:", err)
	}
	GetStatsByContainerCIDStmt, err = DB.Prepare("SELECT * FROM containers WHERE containerid=?")
	if err != nil {
		l.Critical("Can't create GetStatsByContainerCIDStmt:", err)
	}

	// Get probes ID
	ProbesID = make(map[string]int)
	for _, probe := range DGConfig.Probes {
		id, err := GetProbeID(probe.Name)
		if err != nil {
			l.Critical("Error GetProbeID ("+probe.Name+"):", err)
		}
		ProbesID[probe.Name] = id
	}
}

/*
	Get a probe ID from sql server
	If does not exist: create it and return the probe ID
*/
func GetProbeID(name string) (int, error) {
	var id int64  // Probe ID to return
	var err error // Error handling

	err = GetProbeIDStmt.QueryRow(name).Scan(&id)
	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			result, err := InsertProbeStmt.Exec(name)
			if err != nil {
				l.Error("GetProbeID:", err)
				return 0, err
			}
			id, err = result.LastInsertId()
			if err != nil {
				l.Error("GetProbeID:", err)
				return 0, err
			}
		} else {
			l.Error("GetProbeID:", err)
			return 0, err
		}
	}

	return int(id), nil
}

/*
	Insert a container
*/
func (c *Container) Insert() (int64, error) {
	var err error         // Error handling
	var result sql.Result // SQL result

	result, err = InsertContainerStmt.Exec(c.CID, c.ProbeID, c.Hostname, c.Image, c.IPAddress, c.MacAddress)

	if err == nil {
		id, err := result.LastInsertId()
		if err != nil {
			return 0, err
		} else {
			return id, nil
		}
	}

	return 0, err
}

/*
	Delete a container
*/
func (c *Container) Delete() error {
	var err error // Error handling

	_, err = DeleteContainerStmt.Exec(c.CID)

	return err
}

/*
	Get container's last stat
*/
func (c *Container) GetLastStat() (Stat, error) {
	var stat Stat // Returned stat
	var err error // Error handling

	err = GetContainerLastStatStmt.QueryRow(c.ID).Scan(&stat.ContainerID, &stat.Time, &stat.SizeRootFs, &stat.SizeRw, &stat.SizeMemory, &stat.Running)
	if err != nil {
		if err.Error() != "sql: no rows in result set" {
			l.Error("GetLastStat:", err)
		}
		return stat, err
	}

	return stat, err
}

/*
	Get containers by $field
*/
func GetContainersBy(field string, value interface{}) ([]Container, error) {
	var containers []Container // Containers to return
	var rows *sql.Rows         // SQL Rows
	var err error              // Error handling

	// Protection against SQL injection
	var fieldExists bool = false
	for _, i := range []string{"id", "containerid", "probeid", "hostname", "image", "ip", "mac"} {
		if field == i {
			fieldExists = true
		}
	}
	if !fieldExists {
		l.Error("GetContainersBy: Field (" + field + ") does not exist.")
		return containers, errors.New("GetContainersBy: Field (" + field + ") does not exist.")
	}

	// Get containers
	rows, err = DB.Query("SELECT * FROM containers WHERE "+field+"=?", value)
	if err != nil {
		l.Error("GetContainersBy: Can't get rows:", err)
		return containers, err
	}
	defer rows.Close()
	for rows.Next() {
		var tmpContainer Container

		if err = rows.Scan(&tmpContainer.ID,
			&tmpContainer.CID,
			&tmpContainer.ProbeID,
			&tmpContainer.Hostname,
			&tmpContainer.Image,
			&tmpContainer.IPAddress,
			&tmpContainer.MacAddress); err != nil {
			l.Error("GetContainersBy: Can't scan row:", err)
			return containers, err
		}

		containers = append(containers, tmpContainer)
	}
	if err = rows.Err(); err != nil {
		l.Error("GetContainersBy: Rows error:", err)
		return containers, err
	}

	return containers, nil
}

/*
	Get a container by id
*/
func GetContainerByID(id int) (Container, error) {
	var container Container // Container to return
	var err error           // Error handling

	err = GetContainerByCIDStmt.QueryRow(id).Scan(&container.ID, &container.CID, &container.ProbeID, &container.Hostname, &container.Image, &container.IPAddress, &container.MacAddress)
	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			return container, err
		} else {
			l.Error("GetContainerByID:", err)
			return container, err
		}
	}

	return container, nil
}

/*
	Get a container by cid
*/
func GetContainerByCID(cid string) (Container, error) {
	var container Container // Container to return
	var err error           // Error handling

	err = GetContainerByCIDStmt.QueryRow(cid).Scan(&container.ID, &container.CID, &container.ProbeID, &container.Hostname, &container.Image, &container.IPAddress, &container.MacAddress)
	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			return container, err
		} else {
			l.Error("GetContainerByCID:", err)
			return container, err
		}
	}

	return container, nil
}

/*
	Insert a stat
*/
func (s *Stat) Insert() error {
	var err error // Error handling
	var timeInsert int64 = time.Now().Unix()

	_, err = InsertStatStmt.Exec(s.ContainerID, timeInsert, s.SizeRootFs, s.SizeRw, s.SizeMemory, s.Running)

	return err
}

/*
	Delete a stat
*/
func (s *Stat) Delete() error {
	var err error // Error handling

	_, err = DeleteStatStmt.Exec(s.ContainerID, s.Time)

	return err
}

/*
	Get stats by container id
*/
func GetStatsByContainerID(containerID string) ([]Stat, error) {
	var stats []Stat   // List of stats to return
	var err error      // Erro handling
	var tmpStat Stat   // Temporary stat
	var rows *sql.Rows // Temporary sql rows

	rows, err = GetStatsByContainerIdStmt.Query(containerID)
	if err != nil {
		l.Error("GetStatsByContainerID:", err)
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		err = rows.Scan(&tmpStat.ContainerID, &tmpStat.Time, &tmpStat.SizeRootFs, &tmpStat.SizeRw, &tmpStat.SizeMemory, &tmpStat.Running)
		if err != nil {
			l.Error("GetStatsByContainerID:", err)
			return nil, err
		}
		stats = append(stats, tmpStat)
	}
	err = rows.Err()
	if err != nil {
		l.Error("GetStatsByContainerID:", err)
		return nil, err
	}

	return stats, nil
}
<commit_msg>Add: GetBetweenStats<commit_after>package core

import (
	"database/sql"
	"errors"
	"time"

	_ "github.com/go-sql-driver/mysql"

	"../utils"
)

/*
	Container info
*/
type Container struct {
	ID         int
	CID        string
	ProbeID    int
	Hostname   string
	Image      string
	IPAddress  string
	MacAddress string
}

/*
	Container's stats
*/
type Stat struct {
	ContainerID int
	Time        int64
	SizeRootFs  uint64
	SizeRw      uint64
	SizeMemory  uint64
	Running     bool
}

/*
	SQL Variables
*/
var (
	// DB
	DB       *sql.DB
	ProbesID map[string]int

	// Prepared queries
	GetProbeIDStmt             *sql.Stmt
	InsertProbeStmt            *sql.Stmt
	InsertContainerStmt        *sql.Stmt
	DeleteContainerStmt        *sql.Stmt
	GetLastStatStmt            *sql.Stmt
	GetBetweenStatsStmt        *sql.Stmt
	InsertStatStmt             *sql.Stmt
	DeleteStatStmt             *sql.Stmt
	GetContainerByCIDStmt      *sql.Stmt
	GetStatsByContainerIdStmt  *sql.Stmt
	GetStatsByContainerCIDStmt *sql.Stmt
)

func InitSQL() {
	var err error // Error handling

	// Connect DB
	sqlc := DGConfig.DockerGuard.SQLServer // SQL Config
	DB, err = sql.Open("mysql", sqlc.User+":"+sqlc.Pass+"@tcp("+sqlc.IP+":"+utils.I2S(sqlc.Port)+")/"+sqlc.DB)
	if err != nil {
		l.Critical(err)
	}
	err = DB.Ping()
	if err != nil {
		l.Critical(err)
	}
	l.Verbose("Connected to SQL database")

	// Prepare DB queries
	GetProbeIDStmt, err = DB.Prepare("SELECT id FROM probes WHERE name=?")
	if err != nil {
		l.Critical("Can't create InsertContainerStmt:", err)
	}
	InsertProbeStmt, err = DB.Prepare("INSERT INTO probes VALUES (DEFAULT,?)")
	if err != nil {
		l.Critical("Can't create InsertContainerStmt:", err)
	}
	InsertContainerStmt, err = DB.Prepare("INSERT INTO containers VALUES (DEFAULT,?,?,?,?,?,?)")
	if err != nil {
		l.Critical("Can't create InsertContainerStmt:", err)
	}
	DeleteContainerStmt, err = DB.Prepare("DELETE FROM containers WHERE containerid=?")
	if err != nil {
		l.Critical("Can't create DeleteContainerStmt:", err)
	}
	GetLastStatStmt, err = DB.Prepare("SELECT * FROM stats WHERE containerid=? ORDER BY time DESC LIMIT 1")
	if err != nil {
		l.Critical("Can't create DeleteContainerStmt:", err)
	}
	GetBetweenStatsStmt, err = DB.Prepare("SELECT * FROM stats WHERE containerid=? AND time BETWEEN ? AND ? ORDER BY time")
	if err != nil {
		l.Critical("Can't create DeleteContainerStmt:", err)
	}
	InsertStatStmt, err = DB.Prepare("INSERT INTO stats VALUES (?,?,?,?,?,?)")
	if err != nil {
		l.Critical("Can't create InsertStatStmt:", err)
	}
	DeleteStatStmt, err = DB.Prepare("DELETE FROM stats WHERE containerid=? AND time=?")
	if err != nil {
		l.Critical("Can't create DeleteStatStmt:", err)
	}
	GetContainerByCIDStmt, err = DB.Prepare("SELECT * FROM containers WHERE containerid=?")
	if err != nil {
		l.Critical("Can't create GetContainerByIdStmt:", err)
	}
	GetStatsByContainerIdStmt, err = DB.Prepare("SELECT * FROM containers WHERE id=?")
	if err != nil {
		l.Critical("Can't create GetStatsByContainerIdStmt:", err)
	}
	GetStatsByContainerCIDStmt, err = DB.Prepare("SELECT * FROM containers WHERE containerid=?")
	if err != nil {
		l.Critical("Can't create GetStatsByContainerCIDStmt:", err)
	}

	// Get probes ID
	ProbesID = make(map[string]int)
	for _, probe := range DGConfig.Probes {
		id, err := GetProbeID(probe.Name)
		if err != nil {
			l.Critical("Error GetProbeID ("+probe.Name+"):", err)
		}
		ProbesID[probe.Name] = id
	}
}

/*
	Get a probe ID from sql server
	If does not exist: create it and return the probe ID
*/
func GetProbeID(name string) (int, error) {
	var id int64  // Probe ID to return
	var err error // Error handling

	err = GetProbeIDStmt.QueryRow(name).Scan(&id)
	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			result, err := InsertProbeStmt.Exec(name)
			if err != nil {
				l.Error("GetProbeID:", err)
				return 0, err
			}
			id, err = result.LastInsertId()
			if err != nil {
				l.Error("GetProbeID:", err)
				return 0, err
			}
		} else {
			l.Error("GetProbeID:", err)
			return 0, err
		}
	}

	return int(id), nil
}

/*
	Insert a container
*/
func (c *Container) Insert() (int64, error) {
	var err error         // Error handling
	var result sql.Result // SQL result

	result, err = InsertContainerStmt.Exec(c.CID, c.ProbeID, c.Hostname, c.Image, c.IPAddress, c.MacAddress)

	if err == nil {
		id, err := result.LastInsertId()
		if err != nil {
			return 0, err
		} else {
			return id, nil
		}
	}

	return 0, err
}

/*
	Delete a container
*/
func (c *Container) Delete() error {
	var err error // Error handling

	_, err = DeleteContainerStmt.Exec(c.CID)

	return err
}

/*
	Get container's last stat
*/
func (c *Container) GetLastStat() (Stat, error) {
	var stat Stat // Returned stat
	var err error // Error handling

	err = GetLastStatStmt.QueryRow(c.ID).Scan(&stat.ContainerID, &stat.Time, &stat.SizeRootFs, &stat.SizeRw, &stat.SizeMemory, &stat.Running)
	if err != nil {
		if err.Error() != "sql: no rows in result set" {
			l.Error("GetLastStat:", err)
		}
		return stat, err
	}

	return stat, err
}

/*
	Get container's stats between two dates
*/
func (c *Container) GetBetweenStats(begin, end int) ([]Stat, error) {
	var stats []Stat   // Returned stats
	var rows *sql.Rows // SQL Rows
	var err error      // Error handling

	rows, err = GetBetweenStatsStmt.Query(c.ID, begin, end)
	if err != nil {
		if err.Error() != "sql: no rows in result set" {
			l.Error("GetBetweenStats:", err)
		}
		return stats, err
	}

	defer rows.Close()
	for rows.Next() {
		var tmpStat Stat

		if err = rows.Scan(
			&tmpStat.ContainerID,
			&tmpStat.Time,
			&tmpStat.SizeRootFs,
			&tmpStat.SizeRw,
			&tmpStat.SizeMemory,
			&tmpStat.Running); err != nil {
			l.Error("GetBetweenStats: Can't scan row:", err)
			return stats, err
		}

		stats = append(stats, tmpStat)
	}
	if err = rows.Err(); err != nil {
		l.Error("GetBetweenStatStmt: Rows error:", err)
		return stats, err
	}

	return stats, err
}

/*
	Get containers by $field
*/
func GetContainersBy(field string, value interface{}) ([]Container, error) {
	var containers []Container // Containers to return
	var rows *sql.Rows         // SQL Rows
	var err error              // Error handling

	// Protection against SQL injection
	var fieldExists bool = false
	for _, i := range []string{"id", "containerid", "probeid", "hostname", "image", "ip", "mac"} {
		if field == i {
			fieldExists = true
		}
	}
	if !fieldExists {
		l.Error("GetContainersBy: Field (" + field + ") does not exist.")
		return containers, errors.New("GetContainersBy: Field (" + field + ") does not exist.")
	}

	// Get containers
	rows, err = DB.Query("SELECT * FROM containers WHERE "+field+"=?", value)
	if err != nil {
		l.Error("GetContainersBy: Can't get rows:", err)
		return containers, err
	}
	defer rows.Close()
	for rows.Next() {
		var tmpContainer Container

		if err = rows.Scan(&tmpContainer.ID,
			&tmpContainer.CID,
			&tmpContainer.ProbeID,
			&tmpContainer.Hostname,
			&tmpContainer.Image,
			&tmpContainer.IPAddress,
			&tmpContainer.MacAddress); err != nil {
			l.Error("GetContainersBy: Can't scan row:", err)
			return containers, err
		}

		containers = append(containers, tmpContainer)
	}
	if err = rows.Err(); err != nil {
		l.Error("GetContainersBy: Rows error:", err)
		return containers, err
	}

	return containers, nil
}

/*
	Get a container by id
*/
func GetContainerByID(id int) (Container, error) {
	var container Container // Container to return
	var err error           // Error handling

	err = GetContainerByCIDStmt.QueryRow(id).Scan(&container.ID, &container.CID, &container.ProbeID, &container.Hostname, &container.Image, &container.IPAddress, &container.MacAddress)
	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			return container, err
		} else {
			l.Error("GetContainerByID:", err)
			return container, err
		}
	}

	return container, nil
}

/*
	Get a container by cid
*/
func GetContainerByCID(cid string) (Container, error) {
	var container Container // Container to return
	var err error           // Error handling

	err = GetContainerByCIDStmt.QueryRow(cid).Scan(&container.ID, &container.CID, &container.ProbeID, &container.Hostname, &container.Image, &container.IPAddress, &container.MacAddress)
	if err != nil {
		if err.Error() == "sql: no rows in result set" {
			return container, err
		} else {
			l.Error("GetContainerByCID:", err)
			return container, err
		}
	}

	return container, nil
}

/*
	Insert a stat
*/
func (s *Stat) Insert() error {
	var err error // Error handling
	var timeInsert int64 = time.Now().Unix()

	_, err = InsertStatStmt.Exec(s.ContainerID, timeInsert, s.SizeRootFs, s.SizeRw, s.SizeMemory, s.Running)

	return err
}

/*
	Delete a stat
*/
func (s *Stat) Delete() error {
	var err error // Error handling

	_, err = DeleteStatStmt.Exec(s.ContainerID, s.Time)

	return err
}

/*
	Get stats by container id
*/
func GetStatsByContainerID(containerID string) ([]Stat, error) {
	var stats []Stat   // List of stats to return
	var err error      // Erro handling
	var tmpStat Stat   // Temporary stat
	var rows *sql.Rows // Temporary sql rows

	rows, err = GetStatsByContainerIdStmt.Query(containerID)
	if err != nil {
		l.Error("GetStatsByContainerID:", err)
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		err = rows.Scan(&tmpStat.ContainerID, &tmpStat.Time, &tmpStat.SizeRootFs, &tmpStat.SizeRw, &tmpStat.SizeMemory, &tmpStat.Running)
		if err != nil {
			l.Error("GetStatsByContainerID:", err)
			return nil, err
		}
		stats = append(stats, tmpStat)
	}
	err = rows.Err()
	if err != nil {
		l.Error("GetStatsByContainerID:", err)
		return nil, err
	}

	return stats, nil
}
<|endoftext|>


<commit_before>package client

import (
	"net/http"
	"net/url"
)

type WebClient interface {
	Scrap() (*http.Response, error)
	ScrapWithParameter(path string, method string, values url.Values) (*http.Response, error)
	ScrapWithNoParameter(path string, method string) (*http.Response, error)
	GetUrl() (*url.URL)
}<commit_msg>Expose craft url functions<commit_after>package client

import (
	"net/http"
	"net/url"
)

type WebClient interface {
	Scrap() (*http.Response, error)
	ScrapWithParameter(path string, method string, values url.Values) (*http.Response, error)
	ScrapWithNoParameter(path string, method string) (*http.Response, error)

	GetUrl() (*url.URL)
	CraftUrlGet(path string, values url.Values) (string)
	CraftUrlPost(path string) (string)
}<|endoftext|>


<commit_before>package main

// #cgo CFLAGS: -I${SRCDIR}/../../ceph/src/include
// #cgo LDFLAGS: -L${SRCDIR}/../../ceph/build/lib -lcephd -lstdc++
// #include "cephd/libcephd.h"
import "C"

import (
    "fmt"

    "github.com/quantum/castle/version"
    "github.com/spf13/cobra"
)

func CephVersion() (string) {
    var c_major, c_minor, c_patch C.int
    return C.GoString(C.ceph_version(&c_major,&c_minor,&c_patch))
}

func main() {

    var cmdVersion = &cobra.Command{
        Use:   "version",
        Short: "print castle version",
        Long: `prints the version of castle.`,
        Run: func(cmd *cobra.Command, args []string) {
            fmt.Printf("castled version %v (ceph version %v)\n", version.Version, CephVersion())
        },
    }

    var rootCmd = &cobra.Command{Use: "castled"}
    rootCmd.AddCommand(cmdVersion)
    rootCmd.Execute()
}
<commit_msg>Fixed fmt issues<commit_after>package main

// #cgo CFLAGS: -I${SRCDIR}/../../ceph/src/include
// #cgo LDFLAGS: -L${SRCDIR}/../../ceph/build/lib -lcephd -lstdc++
// #include "cephd/libcephd.h"
import "C"

import (
	"fmt"

	"github.com/quantum/castle/version"
	"github.com/spf13/cobra"
)

func cephVersion() string {
	var cMajor, cMinor, cPatch C.int
	return C.GoString(C.ceph_version(&cMajor, &cMinor, &cPatch))
}

func main() {

	var cmdVersion = &cobra.Command{
		Use:   "version",
		Short: "print castle version",
		Long:  `prints the version of castle.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("castled version %v (ceph version %v)\n", version.Version, cephVersion())
		},
	}

	var rootCmd = &cobra.Command{Use: "castled"}
	rootCmd.AddCommand(cmdVersion)
	rootCmd.Execute()
}
<|endoftext|>


<commit_before>package main

import (
	"dokugen"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

//TODO: let people pass in a filename to export to.

const STORED_PUZZLES_DIRECTORY = ".puzzles"

type appOptions struct {
	GENERATE            bool
	HELP                bool
	PUZZLE_TO_SOLVE     string
	NUM                 int
	PRINT_STATS         bool
	WALKTHROUGH         bool
	RAW_SYMMETRY        string
	SYMMETRY            sudoku.SymmetryType
	SYMMETRY_PROPORTION float64
	MIN_DIFFICULTY      float64
	MAX_DIFFICULTY      float64
}

func init() {
	//grid.Difficulty can make use of a number of processes simultaneously.
	runtime.GOMAXPROCS(6)
}

func main() {

	//TODO: figure out how to test this.

	var options appOptions

	flag.BoolVar(&options.GENERATE, "g", false, "if true, will generate a puzzle.")
	flag.BoolVar(&options.HELP, "h", false, "If provided, will print help and exit.")
	flag.IntVar(&options.NUM, "n", 1, "Number of things to generate")
	flag.BoolVar(&options.PRINT_STATS, "p", false, "If provided, will print stats.")
	flag.StringVar(&options.PUZZLE_TO_SOLVE, "s", "", "If provided, will solve the puzzle at the given filename and print solution.")
	flag.BoolVar(&options.WALKTHROUGH, "w", false, "If provided, will print out a walkthrough to solve the provided puzzle.")
	flag.StringVar(&options.RAW_SYMMETRY, "y", "vertical", "Valid values: 'none', 'both', 'horizontal', 'vertical")
	flag.Float64Var(&options.SYMMETRY_PROPORTION, "r", 0.7, "What proportion of cells should be filled according to symmetry")
	flag.Float64Var(&options.MIN_DIFFICULTY, "min", 0.0, "Minimum difficulty for generated puzzle")
	flag.Float64Var(&options.MAX_DIFFICULTY, "max", 1.0, "Maximum difficulty for generated puzzle")

	flag.Parse()

	options.RAW_SYMMETRY = strings.ToLower(options.RAW_SYMMETRY)
	switch options.RAW_SYMMETRY {
	case "none":
		options.SYMMETRY = sudoku.SYMMETRY_NONE
	case "both":
		options.SYMMETRY = sudoku.SYMMETRY_BOTH
	case "horizontal":
		options.SYMMETRY = sudoku.SYMMETRY_HORIZONTAL
	case "vertical":
		options.SYMMETRY = sudoku.SYMMETRY_VERTICAL
	default:
		log.Fatal("Unknown symmetry flag: ", options.RAW_SYMMETRY)
	}

	output := os.Stdout

	if options.HELP {
		flag.PrintDefaults()
		return
	}

	var grid *sudoku.Grid

	for i := 0; i < options.NUM; i++ {
		//TODO: allow the type of symmetry to be configured.
		if options.GENERATE {
			grid = generatePuzzle(options.MIN_DIFFICULTY, options.MAX_DIFFICULTY, options.SYMMETRY, options.SYMMETRY_PROPORTION)
			fmt.Fprintln(output, grid.DataString())
		} else if options.PUZZLE_TO_SOLVE != "" {
			//TODO: detect if the load failed.
			grid = sudoku.NewGrid()
			grid.LoadFromFile(options.PUZZLE_TO_SOLVE)
		}

		if grid == nil {
			//No grid to do anything with.
			log.Fatalln("No grid loaded.")
		}

		//TODO: use of this option leads to a busy loop somewhere... Is it related to the generate-multiple-and-difficulty hang?

		var directions sudoku.SolveDirections

		if options.WALKTHROUGH || options.PRINT_STATS {
			directions = grid.HumanSolution()
			if len(directions) == 0 {
				//We couldn't solve it. Let's check and see if the puzzle is well formed.
				if grid.HasMultipleSolutions() {
					//TODO: figure out why guesses wouldn't be used here effectively.
					log.Println("The puzzle had multiple solutions; that means it's not well-formed")
				}
			}
		}

		if options.WALKTHROUGH {
			fmt.Fprintln(output, directions.Walkthrough(grid))
		}
		if options.PRINT_STATS {
			fmt.Fprintln(output, grid.Difficulty())
			//TODO: consider actually printing out the Signals stats (with a Stats method on signals)
			fmt.Fprintln(output, strings.Join(directions.Stats(), "\n"))
		}
		if options.PUZZLE_TO_SOLVE != "" {
			grid.Solve()
			fmt.Fprintln(output, grid.DataString())
			//If we're asked to solve, n could only be 1 anyway.
			return
		}
		grid.Done()
	}

}

func puzzleDirectoryParts(symmetryType sudoku.SymmetryType, symmetryPercentage float64) []string {
	return []string{
		STORED_PUZZLES_DIRECTORY,
		"SYM_TYPE_" + strconv.Itoa(int(symmetryType)),
		"SYM_PERCENTAGE_" + strconv.FormatFloat(symmetryPercentage, 'f', -1, 64),
	}
}

func storePuzzle(grid *sudoku.Grid, difficulty float64, symmetryType sudoku.SymmetryType, symmetryPercentage float64) bool {
	//TODO: we should include a hashed version of our difficulty weights file so we don't cache ones with old weights.
	directoryParts := puzzleDirectoryParts(symmetryType, symmetryPercentage)

	fileNamePart := strconv.FormatFloat(difficulty, 'f', -1, 64) + ".sdk"

	pathSoFar := ""

	for i, part := range directoryParts {
		if i == 0 {
			pathSoFar = part
		} else {
			pathSoFar = filepath.Join(pathSoFar, part)
		}
		if _, err := os.Stat(pathSoFar); os.IsNotExist(err) {
			//need to create it.
			os.Mkdir(pathSoFar, 0700)
		}
	}

	fileName := filepath.Join(pathSoFar, fileNamePart)

	file, err := os.Create(fileName)

	if err != nil {
		log.Println(err)
		return false
	}

	defer file.Close()

	puzzleText := grid.DataString()

	n, err := io.WriteString(file, puzzleText)

	if err != nil {
		log.Println(err)
		return false
	} else {
		if n < len(puzzleText) {
			log.Println("Didn't write full file, only wrote", n, "bytes of", len(puzzleText))
			return false
		}
	}
	return true
}

func vendPuzzle(min float64, max float64, symmetryType sudoku.SymmetryType, symmetryPercentage float64) *sudoku.Grid {
	directory := filepath.Join(puzzleDirectoryParts(symmetryType, symmetryPercentage)...)

	if files, err := ioutil.ReadDir(directory); os.IsNotExist(err) {
		//The directory doesn't exist.
		return nil
	} else {
		//OK, the directory exists, now see which puzzles are there and if any fit. If one does, vend it and delete the file.
		for _, file := range files {
			//See what this actually returns.
			filenameParts := strings.Split(file.Name(), ".")
			//TODO: shouldn't "sdk" be in a constant somewhere?
			if len(filenameParts) != 2 || filenameParts[1] != "sdk" {
				continue
			}
			difficulty, err := strconv.ParseFloat(filenameParts[0], 64)
			if err != nil {
				continue
			}
			if min <= difficulty && difficulty <= max {
				//Found a puzzle!
				grid := sudoku.NewGrid()
				fullFileName := filepath.Join(directory, file.Name())
				grid.LoadFromFile(fullFileName)
				os.Remove(fullFileName)
				return grid
			}
		}
	}
	return nil
}

func generatePuzzle(min float64, max float64, symmetryType sudoku.SymmetryType, symmetryPercentage float64) *sudoku.Grid {
	var result *sudoku.Grid

	result = vendPuzzle(min, max, symmetryType, symmetryPercentage)

	if result != nil {
		log.Println("Vending a puzzle from the cache.")
		return result
	}

	//We'll have to generate one ourselves.
	count := 0
	for {
		log.Println("Attempt", count, "at generating puzzle.")

		result = sudoku.GenerateGrid(symmetryType, symmetryPercentage)

		difficulty := result.Difficulty()

		if difficulty >= min && difficulty <= max {
			return result
		}

		log.Println("Rejecting grid of difficulty", difficulty)
		if storePuzzle(result, difficulty, symmetryType, symmetryPercentage) {
			log.Println("Stored the puzzle for future use.")
		}

		count++
	}
	return nil
}
<commit_msg>vendPuzzle now working.<commit_after>package main

import (
	"dokugen"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

//TODO: let people pass in a filename to export to.

const STORED_PUZZLES_DIRECTORY = ".puzzles"

type appOptions struct {
	GENERATE            bool
	HELP                bool
	PUZZLE_TO_SOLVE     string
	NUM                 int
	PRINT_STATS         bool
	WALKTHROUGH         bool
	RAW_SYMMETRY        string
	SYMMETRY            sudoku.SymmetryType
	SYMMETRY_PROPORTION float64
	MIN_DIFFICULTY      float64
	MAX_DIFFICULTY      float64
}

func init() {
	//grid.Difficulty can make use of a number of processes simultaneously.
	runtime.GOMAXPROCS(6)
}

func main() {

	//TODO: figure out how to test this.

	var options appOptions

	flag.BoolVar(&options.GENERATE, "g", false, "if true, will generate a puzzle.")
	flag.BoolVar(&options.HELP, "h", false, "If provided, will print help and exit.")
	flag.IntVar(&options.NUM, "n", 1, "Number of things to generate")
	flag.BoolVar(&options.PRINT_STATS, "p", false, "If provided, will print stats.")
	flag.StringVar(&options.PUZZLE_TO_SOLVE, "s", "", "If provided, will solve the puzzle at the given filename and print solution.")
	flag.BoolVar(&options.WALKTHROUGH, "w", false, "If provided, will print out a walkthrough to solve the provided puzzle.")
	flag.StringVar(&options.RAW_SYMMETRY, "y", "vertical", "Valid values: 'none', 'both', 'horizontal', 'vertical")
	flag.Float64Var(&options.SYMMETRY_PROPORTION, "r", 0.7, "What proportion of cells should be filled according to symmetry")
	flag.Float64Var(&options.MIN_DIFFICULTY, "min", 0.0, "Minimum difficulty for generated puzzle")
	flag.Float64Var(&options.MAX_DIFFICULTY, "max", 1.0, "Maximum difficulty for generated puzzle")

	flag.Parse()

	options.RAW_SYMMETRY = strings.ToLower(options.RAW_SYMMETRY)
	switch options.RAW_SYMMETRY {
	case "none":
		options.SYMMETRY = sudoku.SYMMETRY_NONE
	case "both":
		options.SYMMETRY = sudoku.SYMMETRY_BOTH
	case "horizontal":
		options.SYMMETRY = sudoku.SYMMETRY_HORIZONTAL
	case "vertical":
		options.SYMMETRY = sudoku.SYMMETRY_VERTICAL
	default:
		log.Fatal("Unknown symmetry flag: ", options.RAW_SYMMETRY)
	}

	output := os.Stdout

	if options.HELP {
		flag.PrintDefaults()
		return
	}

	var grid *sudoku.Grid

	for i := 0; i < options.NUM; i++ {
		//TODO: allow the type of symmetry to be configured.
		if options.GENERATE {
			grid = generatePuzzle(options.MIN_DIFFICULTY, options.MAX_DIFFICULTY, options.SYMMETRY, options.SYMMETRY_PROPORTION)
			fmt.Fprintln(output, grid.DataString())
		} else if options.PUZZLE_TO_SOLVE != "" {
			//TODO: detect if the load failed.
			grid = sudoku.NewGrid()
			grid.LoadFromFile(options.PUZZLE_TO_SOLVE)
		}

		if grid == nil {
			//No grid to do anything with.
			log.Fatalln("No grid loaded.")
		}

		//TODO: use of this option leads to a busy loop somewhere... Is it related to the generate-multiple-and-difficulty hang?

		var directions sudoku.SolveDirections

		if options.WALKTHROUGH || options.PRINT_STATS {
			directions = grid.HumanSolution()
			if len(directions) == 0 {
				//We couldn't solve it. Let's check and see if the puzzle is well formed.
				if grid.HasMultipleSolutions() {
					//TODO: figure out why guesses wouldn't be used here effectively.
					log.Println("The puzzle had multiple solutions; that means it's not well-formed")
				}
			}
		}

		if options.WALKTHROUGH {
			fmt.Fprintln(output, directions.Walkthrough(grid))
		}
		if options.PRINT_STATS {
			fmt.Fprintln(output, grid.Difficulty())
			//TODO: consider actually printing out the Signals stats (with a Stats method on signals)
			fmt.Fprintln(output, strings.Join(directions.Stats(), "\n"))
		}
		if options.PUZZLE_TO_SOLVE != "" {
			grid.Solve()
			fmt.Fprintln(output, grid.DataString())
			//If we're asked to solve, n could only be 1 anyway.
			return
		}
		grid.Done()
	}

}

func puzzleDirectoryParts(symmetryType sudoku.SymmetryType, symmetryPercentage float64) []string {
	return []string{
		STORED_PUZZLES_DIRECTORY,
		"SYM_TYPE_" + strconv.Itoa(int(symmetryType)),
		"SYM_PERCENTAGE_" + strconv.FormatFloat(symmetryPercentage, 'f', -1, 64),
	}
}

func storePuzzle(grid *sudoku.Grid, difficulty float64, symmetryType sudoku.SymmetryType, symmetryPercentage float64) bool {
	//TODO: we should include a hashed version of our difficulty weights file so we don't cache ones with old weights.
	directoryParts := puzzleDirectoryParts(symmetryType, symmetryPercentage)

	fileNamePart := strconv.FormatFloat(difficulty, 'f', -1, 64) + ".sdk"

	pathSoFar := ""

	for i, part := range directoryParts {
		if i == 0 {
			pathSoFar = part
		} else {
			pathSoFar = filepath.Join(pathSoFar, part)
		}
		if _, err := os.Stat(pathSoFar); os.IsNotExist(err) {
			//need to create it.
			os.Mkdir(pathSoFar, 0700)
		}
	}

	fileName := filepath.Join(pathSoFar, fileNamePart)

	file, err := os.Create(fileName)

	if err != nil {
		log.Println(err)
		return false
	}

	defer file.Close()

	puzzleText := grid.DataString()

	n, err := io.WriteString(file, puzzleText)

	if err != nil {
		log.Println(err)
		return false
	} else {
		if n < len(puzzleText) {
			log.Println("Didn't write full file, only wrote", n, "bytes of", len(puzzleText))
			return false
		}
	}
	return true
}

func vendPuzzle(min float64, max float64, symmetryType sudoku.SymmetryType, symmetryPercentage float64) *sudoku.Grid {
	directory := filepath.Join(puzzleDirectoryParts(symmetryType, symmetryPercentage)...)

	if files, err := ioutil.ReadDir(directory); os.IsNotExist(err) {
		//The directory doesn't exist.
		return nil
	} else {
		//OK, the directory exists, now see which puzzles are there and if any fit. If one does, vend it and delete the file.
		for _, file := range files {
			//See what this actually returns.
			filenameParts := strings.Split(file.Name(), ".")

			//Remember: there's a dot in the filename due to the float seperator.
			//TODO: shouldn't "sdk" be in a constant somewhere?
			if len(filenameParts) != 3 || filenameParts[2] != "sdk" {
				continue
			}

			difficulty, err := strconv.ParseFloat(strings.Join(filenameParts[0:2], "."), 64)
			if err != nil {
				continue
			}

			if min <= difficulty && difficulty <= max {
				//Found a puzzle!
				grid := sudoku.NewGrid()
				fullFileName := filepath.Join(directory, file.Name())
				grid.LoadFromFile(fullFileName)
				os.Remove(fullFileName)
				return grid
			}
		}
	}
	return nil
}

func generatePuzzle(min float64, max float64, symmetryType sudoku.SymmetryType, symmetryPercentage float64) *sudoku.Grid {
	var result *sudoku.Grid

	result = vendPuzzle(min, max, symmetryType, symmetryPercentage)

	if result != nil {
		log.Println("Vending a puzzle from the cache.")
		return result
	}

	//We'll have to generate one ourselves.
	count := 0
	for {
		log.Println("Attempt", count, "at generating puzzle.")

		result = sudoku.GenerateGrid(symmetryType, symmetryPercentage)

		difficulty := result.Difficulty()

		if difficulty >= min && difficulty <= max {
			return result
		}

		log.Println("Rejecting grid of difficulty", difficulty)
		if storePuzzle(result, difficulty, symmetryType, symmetryPercentage) {
			log.Println("Stored the puzzle for future use.")
		}

		count++
	}
	return nil
}
<|endoftext|>


<commit_before>/*
	This file is part of go-ethereum

	go-ethereum 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.

	go-ethereum 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 go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors:
 * 	Jeffrey Wilcke <i@jev.io>
 * 	Taylor Gerring <taylor.gerring@gmail.com>
 */

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/tests"
)

var (
	continueOnError = false
	testExtension   = ".json"
	defaultTest     = "all"
	defaultDir      = "."
	allTests        = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests"}
	skipTests       = []string{}

	TestFlag = cli.StringFlag{
		Name:  "test",
		Usage: "Test type (string): VMTests, TransactionTests, StateTests, BlockTests",
		Value: defaultTest,
	}
	FileFlag = cli.StringFlag{
		Name:   "file",
		Usage:  "Test file or directory. Directories are searched for .json files 1 level deep",
		Value:  defaultDir,
		EnvVar: "ETHEREUM_TEST_PATH",
	}
	ContinueOnErrorFlag = cli.BoolFlag{
		Name:  "continue",
		Usage: "Continue running tests on error (true) or [default] exit immediately (false)",
	}
	ReadStdInFlag = cli.BoolFlag{
		Name:  "stdin",
		Usage: "Accept input from stdin instead of reading from file",
	}
	SkipTestsFlag = cli.StringFlag{
		Name:  "skip",
		Usage: "Tests names to skip",
	}
)

func runTestWithReader(test string, r io.Reader) error {
	glog.Infoln("runTest", test)
	var err error
	switch test {
	case "bt", "BlockTest", "BlockTests", "BlockChainTest":
		err = tests.RunBlockTestWithReader(r, skipTests)
	case "st", "state", "StateTest", "StateTests":
		err = tests.RunStateTestWithReader(r, skipTests)
	case "tx", "TransactionTest", "TransactionTests":
		err = tests.RunTransactionTestsWithReader(r, skipTests)
	case "vm", "VMTest", "VMTests":
		err = tests.RunVmTestWithReader(r, skipTests)
	default:
		err = fmt.Errorf("Invalid test type specified: %v", test)
	}

	if err != nil {
		return err
	}

	return nil
}

func getFiles(path string) ([]string, error) {
	glog.Infoln("getFiles", path)
	var files []string
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return nil, err
	}

	switch mode := fi.Mode(); {
	case mode.IsDir():
		fi, _ := ioutil.ReadDir(path)
		files = make([]string, len(fi))
		for i, v := range fi {
			// only go 1 depth and leave directory entires blank
			if !v.IsDir() && v.Name()[len(v.Name())-len(testExtension):len(v.Name())] == testExtension {
				files[i] = filepath.Join(path, v.Name())
				glog.Infoln("Found file", files[i])
			}
		}
	case mode.IsRegular():
		files = make([]string, 1)
		files[0] = path
	}

	return files, nil
}

func runSuite(test, file string) {
	var tests []string

	if test == defaultTest {
		tests = allTests
	} else {
		tests = []string{test}
	}

	for _, curTest := range tests {
		glog.Infoln("runSuite", curTest, file)
		var err error
		var files []string
		if test == defaultTest {
			files, err = getFiles(filepath.Join(file, curTest))

		} else {
			files, err = getFiles(file)
		}
		if err != nil {
			glog.Fatalln(err)
		}

		if len(files) == 0 {
			glog.Warningln("No files matched path")
		}
		for _, curFile := range files {
			// Skip blank entries
			if len(curFile) == 0 {
				continue
			}

			r, err := os.Open(curFile)
			if err != nil {
				glog.Fatalln(err)
			}
			defer r.Close()

			err = runTestWithReader(curTest, r)
			if err != nil {
				if continueOnError {
					glog.Errorln(err)
				} else {
					glog.Fatalln(err)
				}
			}

		}
	}
}

func setupApp(c *cli.Context) {
	flagTest := c.GlobalString(TestFlag.Name)
	flagFile := c.GlobalString(FileFlag.Name)
	continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
	useStdIn := c.GlobalBool(ReadStdInFlag.Name)
	skipTests = strings.Split(c.GlobalString(SkipTestsFlag.Name), " ")

	if !useStdIn {
		runSuite(flagTest, flagFile)
	} else {
		if err := runTestWithReader(flagTest, os.Stdin); err != nil {
			glog.Fatalln(err)
		}

	}
}

func main() {
	glog.SetToStderr(true)

	app := cli.NewApp()
	app.Name = "ethtest"
	app.Usage = "go-ethereum test interface"
	app.Action = setupApp
	app.Version = "0.2.0"
	app.Author = "go-ethereum team"

	app.Flags = []cli.Flag{
		TestFlag,
		FileFlag,
		ContinueOnErrorFlag,
		ReadStdInFlag,
		SkipTestsFlag,
	}

	if err := app.Run(os.Args); err != nil {
		glog.Fatalln(err)
	}

}
<commit_msg>Expand --test switch<commit_after>/*
	This file is part of go-ethereum

	go-ethereum 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.

	go-ethereum 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 go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors:
 * 	Jeffrey Wilcke <i@jev.io>
 * 	Taylor Gerring <taylor.gerring@gmail.com>
 */

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/tests"
)

var (
	continueOnError = false
	testExtension   = ".json"
	defaultTest     = "all"
	defaultDir      = "."
	allTests        = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests"}
	skipTests       = []string{}

	TestFlag = cli.StringFlag{
		Name:  "test",
		Usage: "Test type (string): VMTests, TransactionTests, StateTests, BlockTests",
		Value: defaultTest,
	}
	FileFlag = cli.StringFlag{
		Name:   "file",
		Usage:  "Test file or directory. Directories are searched for .json files 1 level deep",
		Value:  defaultDir,
		EnvVar: "ETHEREUM_TEST_PATH",
	}
	ContinueOnErrorFlag = cli.BoolFlag{
		Name:  "continue",
		Usage: "Continue running tests on error (true) or [default] exit immediately (false)",
	}
	ReadStdInFlag = cli.BoolFlag{
		Name:  "stdin",
		Usage: "Accept input from stdin instead of reading from file",
	}
	SkipTestsFlag = cli.StringFlag{
		Name:  "skip",
		Usage: "Tests names to skip",
	}
)

func runTestWithReader(test string, r io.Reader) error {
	glog.Infoln("runTest", test)
	var err error
	switch strings.ToLower(test) {
	case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
		err = tests.RunBlockTestWithReader(r, skipTests)
	case "st", "state", "statetest", "statetests":
		err = tests.RunStateTestWithReader(r, skipTests)
	case "tx", "transactiontest", "transactiontests":
		err = tests.RunTransactionTestsWithReader(r, skipTests)
	case "vm", "vmtest", "vmtests":
		err = tests.RunVmTestWithReader(r, skipTests)
	default:
		err = fmt.Errorf("Invalid test type specified: %v", test)
	}

	if err != nil {
		return err
	}

	return nil
}

func getFiles(path string) ([]string, error) {
	glog.Infoln("getFiles", path)
	var files []string
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return nil, err
	}

	switch mode := fi.Mode(); {
	case mode.IsDir():
		fi, _ := ioutil.ReadDir(path)
		files = make([]string, len(fi))
		for i, v := range fi {
			// only go 1 depth and leave directory entires blank
			if !v.IsDir() && v.Name()[len(v.Name())-len(testExtension):len(v.Name())] == testExtension {
				files[i] = filepath.Join(path, v.Name())
				glog.Infoln("Found file", files[i])
			}
		}
	case mode.IsRegular():
		files = make([]string, 1)
		files[0] = path
	}

	return files, nil
}

func runSuite(test, file string) {
	var tests []string

	if test == defaultTest {
		tests = allTests
	} else {
		tests = []string{test}
	}

	for _, curTest := range tests {
		glog.Infoln("runSuite", curTest, file)
		var err error
		var files []string
		if test == defaultTest {
			files, err = getFiles(filepath.Join(file, curTest))

		} else {
			files, err = getFiles(file)
		}
		if err != nil {
			glog.Fatalln(err)
		}

		if len(files) == 0 {
			glog.Warningln("No files matched path")
		}
		for _, curFile := range files {
			// Skip blank entries
			if len(curFile) == 0 {
				continue
			}

			r, err := os.Open(curFile)
			if err != nil {
				glog.Fatalln(err)
			}
			defer r.Close()

			err = runTestWithReader(curTest, r)
			if err != nil {
				if continueOnError {
					glog.Errorln(err)
				} else {
					glog.Fatalln(err)
				}
			}

		}
	}
}

func setupApp(c *cli.Context) {
	flagTest := c.GlobalString(TestFlag.Name)
	flagFile := c.GlobalString(FileFlag.Name)
	continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
	useStdIn := c.GlobalBool(ReadStdInFlag.Name)
	skipTests = strings.Split(c.GlobalString(SkipTestsFlag.Name), " ")

	if !useStdIn {
		runSuite(flagTest, flagFile)
	} else {
		if err := runTestWithReader(flagTest, os.Stdin); err != nil {
			glog.Fatalln(err)
		}

	}
}

func main() {
	glog.SetToStderr(true)

	app := cli.NewApp()
	app.Name = "ethtest"
	app.Usage = "go-ethereum test interface"
	app.Action = setupApp
	app.Version = "0.2.0"
	app.Author = "go-ethereum team"

	app.Flags = []cli.Flag{
		TestFlag,
		FileFlag,
		ContinueOnErrorFlag,
		ReadStdInFlag,
		SkipTestsFlag,
	}

	if err := app.Run(os.Args); err != nil {
		glog.Fatalln(err)
	}

}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"

	"code.google.com/p/go.crypto/ssh/terminal"
	eval "github.com/sbinet/go-eval"
)

var fset = token.NewFileSet()
var filename = flag.String("f", "", "file to run")

type shell struct {
	r io.Reader
	w io.Writer
}

func (sh *shell) Read(data []byte) (n int, err error) {
	return sh.r.Read(data)
}
func (sh *shell) Write(data []byte) (n int, err error) {
	return sh.w.Write(data)
}

func main() {
	flag.Parse()
	w := eval.NewWorld()
	if *filename != "" {
		data, err := ioutil.ReadFile(*filename)
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		file, err := parser.ParseFile(fset, *filename, data, 0)
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		files := []*ast.File{file}
		code, err := w.CompilePackage(fset, files, "main")
		if err != nil {
			if list, ok := err.(scanner.ErrorList); ok {
				for _, e := range list {
					fmt.Println(e.Error())
				}
			} else {
				fmt.Println(err.Error())
			}
			os.Exit(1)
		}
		code, err = w.Compile(fset, "main()")
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		_, err = code.Run()
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		os.Exit(0)
	}

	fmt.Println(":: welcome to go-eval...\n(hit ^D to exit)")

	fd := int(os.Stdin.Fd())
	oldState, err := terminal.MakeRaw(fd)
	if err != nil {
		panic(err)
	}
	defer terminal.Restore(fd, oldState)
	term := terminal.NewTerminal(&shell{r: os.Stdin, w: os.Stdout}, "> ")
	if term == nil {
		panic(errors.New("could not create terminal"))
	}

	for {
		line, err := term.ReadLine()
		if err != nil {
			break
		}
		code, err := w.Compile(fset, line)
		if err != nil {
			term.Write([]byte(err.Error() + "\n"))
			continue
		}
		v, err := code.Run()
		if err != nil {
			term.Write([]byte(err.Error() + "\n"))
			continue
		}
		if v != nil {
			term.Write([]byte(v.String() + "\n"))
		}
	}
}
<commit_msg>go-eval/main: add protection against nil Code<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"

	"code.google.com/p/go.crypto/ssh/terminal"
	eval "github.com/sbinet/go-eval"
)

var fset = token.NewFileSet()
var filename = flag.String("f", "", "file to run")

type shell struct {
	r io.Reader
	w io.Writer
}

func (sh *shell) Read(data []byte) (n int, err error) {
	return sh.r.Read(data)
}
func (sh *shell) Write(data []byte) (n int, err error) {
	return sh.w.Write(data)
}

func main() {
	flag.Parse()
	w := eval.NewWorld()
	if *filename != "" {
		data, err := ioutil.ReadFile(*filename)
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		file, err := parser.ParseFile(fset, *filename, data, 0)
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		files := []*ast.File{file}
		code, err := w.CompilePackage(fset, files, "main")
		if err != nil {
			if list, ok := err.(scanner.ErrorList); ok {
				for _, e := range list {
					fmt.Println(e.Error())
				}
			} else {
				fmt.Println(err.Error())
			}
			os.Exit(1)
		}
		code, err = w.Compile(fset, "main()")
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		_, err = code.Run()
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		os.Exit(0)
	}

	fmt.Println(":: welcome to go-eval...\n(hit ^D to exit)")

	fd := int(os.Stdin.Fd())
	oldState, err := terminal.MakeRaw(fd)
	if err != nil {
		panic(err)
	}
	defer terminal.Restore(fd, oldState)
	term := terminal.NewTerminal(&shell{r: os.Stdin, w: os.Stdout}, "> ")
	if term == nil {
		panic(errors.New("could not create terminal"))
	}

	for {
		line, err := term.ReadLine()
		if err != nil {
			break
		}
		code, err := w.Compile(fset, line)
		if err != nil {
			term.Write([]byte(err.Error() + "\n"))
			continue
		}
		if code == nil {
			term.Write([]byte("failed to compile codelet\n"))
			continue
		}
		v, err := code.Run()
		if err != nil {
			term.Write([]byte(err.Error() + "\n"))
			continue
		}
		if v != nil {
			term.Write([]byte(v.String() + "\n"))
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "github.com/keltia/gondole"
    "github.com/urfave/cli"
    "os"
)

var (
    fVerbose bool
)

func init() {
}

func Register(c *cli.Context) error {

    return nil
}

func init() {
    cli.VersionFlag = cli.BoolFlag{Name: "version, V"}

    cli.VersionPrinter = func(c *cli.Context) {
        log.Printf("API wrapper: %s Mastodon CLI: %s\n", c.App.Version, gondole.APIVersion)
    }
}

func main() {
    app := cli.NewApp()
    app.Name = "gondole"
    app.Usage = "Mastodon CLI interface"
    app.Author = "Ollivier Robert <roberto@keltia.net>"
    app.Version = gondole.APIVersion
    //app.HideVersion = true

    app.Before = Register

    app.Flags = []cli.Flag{
        cli.BoolFlag{
            Name:        "verbose,v",
            Usage:       "verbose mode",
            Destination: &fVerbose,
        },
    }
    app.Run(os.Args)
}
<commit_msg>Remove dup func init().<commit_after>package main

import (
    "log"
    "github.com/keltia/gondole"
    "github.com/urfave/cli"
    "os"
)

var (
    fVerbose bool
)

func Register(c *cli.Context) error {

    return nil
}

func init() {
    cli.VersionFlag = cli.BoolFlag{Name: "version, V"}

    cli.VersionPrinter = func(c *cli.Context) {
        log.Printf("API wrapper: %s Mastodon CLI: %s\n", c.App.Version, gondole.APIVersion)
    }
}

func main() {
    app := cli.NewApp()
    app.Name = "gondole"
    app.Usage = "Mastodon CLI interface"
    app.Author = "Ollivier Robert <roberto@keltia.net>"
    app.Version = gondole.APIVersion
    //app.HideVersion = true

    app.Before = Register

    app.Flags = []cli.Flag{
        cli.BoolFlag{
            Name:        "verbose,v",
            Usage:       "verbose mode",
            Destination: &fVerbose,
        },
    }
    app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"

	platform "github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/http"
	"github.com/influxdata/influxdb/kit/signals"
	"github.com/influxdata/influxdb/models"
	"github.com/influxdata/influxdb/write"
	"github.com/spf13/cobra"
)

const (
	inputFormatCsv          = "csv"
	inputFormatLineProtocol = "lp"
)

var writeFlags struct {
	org       organization
	BucketID  string
	Bucket    string
	Precision string
	Format    string
	File      string
	DryRun    bool
}

func cmdWrite(f *globalFlags, opt genericCLIOpts) *cobra.Command {
	cmd := opt.newCmd("write", fluxWriteF, true)
	cmd.Args = cobra.MaximumNArgs(1)
	cmd.Short = "Write points to InfluxDB"
	cmd.Long = `Write data to InfluxDB via stdin, or add an entire file specified with the -f flag`

	writeFlags.org.register(cmd, true)
	opts := flagOpts{
		{
			DestP:      &writeFlags.BucketID,
			Flag:       "bucket-id",
			Desc:       "The ID of destination bucket",
			Persistent: true,
		},
		{
			DestP:      &writeFlags.Bucket,
			Flag:       "bucket",
			Short:      'b',
			EnvVar:     "BUCKET_NAME",
			Desc:       "The name of destination bucket",
			Persistent: true,
		},
		{
			DestP:      &writeFlags.Precision,
			Flag:       "precision",
			Short:      'p',
			Default:    "ns",
			Desc:       "Precision of the timestamps of the lines",
			Persistent: true,
		},
	}
	opts.mustRegister(cmd)
	cmd.PersistentFlags().StringVar(&writeFlags.Format, "format", "", "Input format, either lp (Line Protocol) or csv (Comma Separated Values). Defaults to lp unless '.csv' extension")
	cmd.PersistentFlags().StringVarP(&writeFlags.File, "file", "f", "", "The path to the file to import")

	cmdDryRun := opt.newCmd("dryrun", func(command *cobra.Command, args []string) error {
		writeFlags.DryRun = true
		return fluxWriteF(command, args)
	}, false)
	cmdDryRun.Args = cobra.MaximumNArgs(1)
	cmdDryRun.Short = "Write to stdout instead of InfluxDB"
	cmdDryRun.Long = `Write protocol lines to stdout instead of InfluxDB. Troubleshoot conversion from CSV to line protocol.`
	cmd.AddCommand(cmdDryRun)
	return cmd
}

func fluxWriteF(cmd *cobra.Command, args []string) error {
	ctx := context.Background()
	var bucketID, orgID platform.ID

	// validate flags unless dry-run
	if !writeFlags.DryRun {
		if err := writeFlags.org.validOrgFlags(&flags); err != nil {
			return err
		}

		if writeFlags.Bucket != "" && writeFlags.BucketID != "" {
			return fmt.Errorf("please specify one of bucket or bucket-id")
		}

		if !models.ValidPrecision(writeFlags.Precision) {
			return fmt.Errorf("invalid precision")
		}

		bs, err := newBucketService()
		if err != nil {
			return err
		}

		var filter platform.BucketFilter
		if writeFlags.BucketID != "" {
			filter.ID, err = platform.IDFromString(writeFlags.BucketID)
			if err != nil {
				return fmt.Errorf("failed to decode bucket-id: %v", err)
			}
		}
		if writeFlags.Bucket != "" {
			filter.Name = &writeFlags.Bucket
		}

		if writeFlags.org.id != "" {
			filter.OrganizationID, err = platform.IDFromString(writeFlags.org.id)
			if err != nil {
				return fmt.Errorf("failed to decode org-id id: %v", err)
			}
		}
		if writeFlags.org.name != "" {
			filter.Org = &writeFlags.org.name
		}

		buckets, n, err := bs.FindBuckets(ctx, filter)
		if err != nil {
			return fmt.Errorf("failed to retrieve buckets: %v", err)
		}

		if n == 0 {
			if writeFlags.Bucket != "" {
				return fmt.Errorf("bucket %q was not found", writeFlags.Bucket)
			}

			if writeFlags.BucketID != "" {
				return fmt.Errorf("bucket with id %q does not exist", writeFlags.BucketID)
			}
		}

		bucketID, orgID = buckets[0].ID, buckets[0].OrgID
	}

	var r io.Reader
	if len(args) > 0 && args[0][0] == '@' {
		// backward compatibility: @ in arg denotes a file
		writeFlags.File = args[0][1:]
	}

	if len(writeFlags.File) > 0 {
		f, err := os.Open(writeFlags.File)
		if err != nil {
			return fmt.Errorf("failed to open %q: %v", writeFlags.File, err)
		}
		defer f.Close()
		r = f
		if len(writeFlags.Format) == 0 && strings.HasSuffix(writeFlags.File, ".csv") {
			writeFlags.Format = inputFormatCsv
		}
	} else if len(args) == 0 || args[0] == "-" {
		// backward compatibility: "-" also means stdin
		r = os.Stdin
	} else {
		r = strings.NewReader(args[0])
	}
	// validate input format
	if len(writeFlags.Format) > 0 && writeFlags.Format != inputFormatLineProtocol && writeFlags.Format != inputFormatCsv {
		return fmt.Errorf("unsupported input format: %s", writeFlags.Format)
	}

	if writeFlags.Format == inputFormatCsv {
		r = write.CsvToProtocolLines(r)
	}

	if writeFlags.DryRun {
		// write lines to tdout
		_, err := io.Copy(os.Stdout, r)
		if err != nil {
			return fmt.Errorf("failed: %v", err)
		}
	} else {
		s := write.Batcher{
			Service: &http.WriteService{
				Addr:               flags.Host,
				Token:              flags.Token,
				Precision:          writeFlags.Precision,
				InsecureSkipVerify: flags.skipVerify,
			},
		}

		ctx = signals.WithStandardSignals(ctx)
		if err := s.Write(ctx, orgID, bucketID, r); err != nil && err != context.Canceled {
			return fmt.Errorf("failed to write data: %v", err)
		}
	}

	return nil
}
<commit_msg>chore(cmd/influx/write): q comments<commit_after>package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"

	platform "github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/http"
	"github.com/influxdata/influxdb/kit/signals"
	"github.com/influxdata/influxdb/models"
	"github.com/influxdata/influxdb/write"
	"github.com/spf13/cobra"
)

const (
	inputFormatCsv          = "csv"
	inputFormatLineProtocol = "lp"
)

type writeFlagsType struct {
	org       organization
	BucketID  string
	Bucket    string
	Precision string
	Format    string
	File      string
	DryRun    bool
}

var writeFlags writeFlagsType

func cmdWrite(f *globalFlags, opt genericCLIOpts) *cobra.Command {
	cmd := opt.newCmd("write", fluxWriteF, true)
	cmd.Args = cobra.MaximumNArgs(1)
	cmd.Short = "Write points to InfluxDB"
	cmd.Long = `Write data to InfluxDB via stdin, or add an entire file specified with the -f flag`

	writeFlags.org.register(cmd, true)
	opts := flagOpts{
		{
			DestP:      &writeFlags.BucketID,
			Flag:       "bucket-id",
			Desc:       "The ID of destination bucket",
			Persistent: true,
		},
		{
			DestP:      &writeFlags.Bucket,
			Flag:       "bucket",
			Short:      'b',
			EnvVar:     "BUCKET_NAME",
			Desc:       "The name of destination bucket",
			Persistent: true,
		},
		{
			DestP:      &writeFlags.Precision,
			Flag:       "precision",
			Short:      'p',
			Default:    "ns",
			Desc:       "Precision of the timestamps of the lines",
			Persistent: true,
		},
	}
	opts.mustRegister(cmd)
	cmd.PersistentFlags().StringVar(&writeFlags.Format, "format", "", "Input format, either lp (Line Protocol) or csv (Comma Separated Values). Defaults to lp unless '.csv' extension")
	cmd.PersistentFlags().StringVarP(&writeFlags.File, "file", "f", "", "The path to the file to import")

	cmdDryRun := opt.newCmd("dryrun", fluxWriteDryrunF, false)
	cmdDryRun.Args = cobra.MaximumNArgs(1)
	cmdDryRun.Short = "Write to stdout instead of InfluxDB"
	cmdDryRun.Long = `Write protocol lines to stdout instead of InfluxDB. Troubleshoot conversion from CSV to line protocol.`
	cmd.AddCommand(cmdDryRun)
	return cmd
}

// createLineReader uses writeFlags and cli arguments to create a reader that produces line protocol
func (writeFlags *writeFlagsType) createLineReader(args []string) (r io.Reader, closer io.Closer, err error) {
	if len(args) > 0 && args[0][0] == '@' {
		// backward compatibility: @ in arg denotes a file
		writeFlags.File = args[0][1:]
	}

	if len(writeFlags.File) > 0 {
		f, err := os.Open(writeFlags.File)
		if err != nil {
			return nil, nil, fmt.Errorf("failed to open %q: %v", writeFlags.File, err)
		}
		closer = f
		r = f
		if len(writeFlags.Format) == 0 && strings.HasSuffix(writeFlags.File, ".csv") {
			writeFlags.Format = inputFormatCsv
		}
	} else if len(args) == 0 || args[0] == "-" {
		// backward compatibility: "-" also means stdin
		r = os.Stdin
	} else {
		r = strings.NewReader(args[0])
	}
	// validate input format
	if len(writeFlags.Format) > 0 && writeFlags.Format != inputFormatLineProtocol && writeFlags.Format != inputFormatCsv {
		return nil, nil, fmt.Errorf("unsupported input format: %s", writeFlags.Format)
	}

	if writeFlags.Format == inputFormatCsv {
		r = write.CsvToProtocolLines(r)
	}
	return r, closer, nil
}

func fluxWriteF(cmd *cobra.Command, args []string) error {
	// validate InfluxDB flags
	if err := writeFlags.org.validOrgFlags(&flags); err != nil {
		return err
	}

	if writeFlags.Bucket != "" && writeFlags.BucketID != "" {
		return fmt.Errorf("please specify one of bucket or bucket-id")
	}

	if !models.ValidPrecision(writeFlags.Precision) {
		return fmt.Errorf("invalid precision")
	}

	bs, err := newBucketService()
	if err != nil {
		return err
	}

	var filter platform.BucketFilter
	if writeFlags.BucketID != "" {
		filter.ID, err = platform.IDFromString(writeFlags.BucketID)
		if err != nil {
			return fmt.Errorf("failed to decode bucket-id: %v", err)
		}
	}
	if writeFlags.Bucket != "" {
		filter.Name = &writeFlags.Bucket
	}

	if writeFlags.org.id != "" {
		filter.OrganizationID, err = platform.IDFromString(writeFlags.org.id)
		if err != nil {
			return fmt.Errorf("failed to decode org-id id: %v", err)
		}
	}
	if writeFlags.org.name != "" {
		filter.Org = &writeFlags.org.name
	}

	ctx := context.Background()
	buckets, n, err := bs.FindBuckets(ctx, filter)
	if err != nil {
		return fmt.Errorf("failed to retrieve buckets: %v", err)
	}

	if n == 0 {
		if writeFlags.Bucket != "" {
			return fmt.Errorf("bucket %q was not found", writeFlags.Bucket)
		}

		if writeFlags.BucketID != "" {
			return fmt.Errorf("bucket with id %q does not exist", writeFlags.BucketID)
		}
	}
	bucketID, orgID := buckets[0].ID, buckets[0].OrgID

	// create line reader
	r, closer, err := writeFlags.createLineReader(args)
	if closer != nil {
		defer closer.Close()
	}
	if err != nil {
		return err
	}

	// write to InfluxDB
	s := write.Batcher{
		Service: &http.WriteService{
			Addr:               flags.Host,
			Token:              flags.Token,
			Precision:          writeFlags.Precision,
			InsecureSkipVerify: flags.skipVerify,
		},
	}
	ctx = signals.WithStandardSignals(ctx)
	if err := s.Write(ctx, orgID, bucketID, r); err != nil && err != context.Canceled {
		return fmt.Errorf("failed to write data: %v", err)
	}

	return nil
}

func fluxWriteDryrunF(cmd *cobra.Command, args []string) error {
	// create line reader
	r, closer, err := writeFlags.createLineReader(args)
	if closer != nil {
		defer closer.Close()
	}
	if err != nil {
		return err
	}
	// dry run
	_, err = io.Copy(os.Stdout, r)
	if err != nil {
		return fmt.Errorf("failed: %v", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/fatih/color"
	"github.com/urfave/cli"
	"github.com/xwjdsh/manssh"
)

var (
	messageStyle = color.New(color.FgWhite, color.Bold)
	aliasStyle   = color.New(color.FgYellow, color.Bold)

	globalStyle    = color.New(color.FgMagenta, color.Bold)
	globalKeyStyle = color.New(color.FgCyan, color.Bold)

	successStyle = color.New(color.BgGreen, color.FgWhite)
	errorStyle   = color.New(color.BgRed, color.FgWhite)
)

func printSuccessFlag() {
	successStyle.Printf("%-9s", " success")
}

func printErrorFlag() {
	errorStyle.Printf("%-7s", " error")
}

func printErrorWithHelp(c *cli.Context, err error) error {
	cli.ShowSubcommandHelp(c)
	fmt.Println()
	printErrorFlag()
	return cli.NewExitError(err, 1)
}

func printHosts(hosts []*manssh.HostConfig) {
	var global *manssh.HostConfig
	for _, host := range hosts {
		if host.Aliases == "*" {
			global = host
			continue
		}
		printHost(host)
	}
	if global != nil && global.Config != nil && len(global.Config) > 0 {
		printHost(global)
	}
}

func printMessage(format string, a ...interface{}) {
	messageStyle.Printf(format, a...)
}

func printHost(host *manssh.HostConfig) {
	isGlobal := host.Aliases == "*"
	if isGlobal {
		globalStyle.Printf("\t(*) Global Configs\n")
	} else {
		aliasStyle.Printf("\t%s", host.Aliases)
		fmt.Printf(" -> %s\n", host.Connect)
	}
	for k, v := range host.Config {
		if isGlobal {
			globalKeyStyle.Printf("\t\t%s ", k)
			fmt.Printf("= %s\n", v)
		} else {
			fmt.Printf("\t\t%s = %s\n", k, v)
		}
	}
	fmt.Println()
}
<commit_msg>Update print style<commit_after>package main

import (
	"fmt"

	"github.com/fatih/color"
	"github.com/urfave/cli"
	"github.com/xwjdsh/manssh"
)

var (
	messageStyle = color.New(color.FgWhite, color.Bold)
	aliasStyle   = color.New(color.FgYellow, color.Bold)

	globalStyle    = color.New(color.FgMagenta, color.Bold)
	globalKeyStyle = color.New(color.FgCyan, color.Bold)

	successStyle = color.New(color.FgGreen)
	errorStyle   = color.New(color.FgRed)
)

func printSuccessFlag() {
	successStyle.Printf("%s", "\u2714  ")
}

func printErrorFlag() {
	errorStyle.Printf("%s", "\u2716  ")
}

func printErrorWithHelp(c *cli.Context, err error) error {
	cli.ShowSubcommandHelp(c)
	fmt.Println()
	printErrorFlag()
	return cli.NewExitError(err, 1)
}

func printHosts(hosts []*manssh.HostConfig) {
	var global *manssh.HostConfig
	for _, host := range hosts {
		if host.Aliases == "*" {
			global = host
			continue
		}
		printHost(host)
	}
	if global != nil && global.Config != nil && len(global.Config) > 0 {
		printHost(global)
	}
}

func printMessage(format string, a ...interface{}) {
	messageStyle.Printf(format, a...)
}

func printHost(host *manssh.HostConfig) {
	isGlobal := host.Aliases == "*"
	if isGlobal {
		globalStyle.Printf("\t(*) Global Configs\n")
	} else {
		aliasStyle.Printf("\t%s", host.Aliases)
		fmt.Printf(" -> %s\n", host.Connect)
	}
	for k, v := range host.Config {
		if isGlobal {
			globalKeyStyle.Printf("\t\t%s ", k)
			fmt.Printf("= %s\n", v)
		} else {
			fmt.Printf("\t\t%s = %s\n", k, v)
		}
	}
	fmt.Println()
}
<|endoftext|>