<commit_before>package captcha

import (
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font"
	"golang.org/x/image/font/gofont/goregular"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"io"
	"math"
	"math/rand"
	"time"
)

const charPreset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

var rng = rand.New(rand.NewSource(time.Now().UnixNano()))
var ttfFont *truetype.Font

type Options struct {
	BackgroundColor color.Color
	CharPreset      string
	TxtLength       int
	width           int
	height          int
}

func newDefaultOption(width, height int) *Options {
	return &Options{
		BackgroundColor: color.Transparent,
		CharPreset:      charPreset,
		TxtLength:       4,
		width:           width,
		height:          height,
	}
}

type SetOption func(*Options)

type Data struct {
	Text string

	img *image.NRGBA
}

func (data *Data) WriteTo(w io.Writer) error {
	return png.Encode(w, data.img)
}

func init() {
	var err error
	ttfFont, err = freetype.ParseFont(goregular.TTF)
	if err != nil {
		panic(err)
	}
}

func New(width int, height int, option ...SetOption) (*Data, error) {
	options := newDefaultOption(width, height)
	for _, setOption := range option {
		setOption(options)
	}

	text := randomText(options)
	img := image.NewNRGBA(image.Rect(0, 0, width, height))
	draw.Draw(img, img.Bounds(), &image.Uniform{options.BackgroundColor}, image.ZP, draw.Src)
	drawNoise(img, options)
	drawLine(img, options)
	err := drawText(text, img, options)
	if err != nil {
		return nil, err
	}

	return &Data{Text: text, img: img}, nil
}

func randomText(opts *Options) (text string) {
	n := len(opts.CharPreset)
	for i := 0; i < opts.TxtLength; i++ {
		text += string(opts.CharPreset[rng.Intn(n)])
	}

	return text
}

func drawNoise(img *image.NRGBA, opts *Options) {
	noiseCount := (opts.width * opts.height) / 18
	for i := 0; i < noiseCount; i++ {
		x := rng.Intn(opts.width)
		y := rng.Intn(opts.height)
		img.Set(x, y, randomColor())
	}
}

func randomColor() color.RGBA {
	red := rng.Intn(255)
	green := rng.Intn(255)
	blue := rng.Intn(255)

	return color.RGBA{R: uint8(red), G: uint8(green), B: uint8(blue), A: uint8(255)}
}

func drawLine(img *image.NRGBA, opts *Options) {
	for i := 0; i < 3; i++ {
		drawSineCurve(img, opts)
	}
}

// Ideally we want to draw bezier curves
// For now sine curves will do the job
func drawSineCurve(img *image.NRGBA, opts *Options) {
	var xStart, xEnd int
	if opts.width <= 40 {
		xStart, xEnd = 1, opts.width-1
	} else {
		xStart = rng.Intn(opts.width/10) + 1
		xEnd = opts.width - rng.Intn(opts.width/10) - 1
	}
	curveHeight := float64(rng.Intn(opts.height/6) + opts.height/6)
	yStart := rng.Intn(opts.height*2/3) + opts.height/6
	angle := 1.0 + rng.Float64()
	flip := rng.Intn(2) == 0
	yFlip := 1.0
	if flip {
		yFlip = -1.0
	}
	curveColor := randomDarkGray()

	for x1 := xStart; x1 <= xEnd; x1++ {
		y := math.Sin(math.Pi*angle*float64(x1)/float64(opts.width)) * curveHeight * yFlip
		img.Set(x1, int(y)+yStart, curveColor)
	}
}

func randomDarkGray() color.Gray {
	gray := rng.Intn(128) + 20

	return color.Gray{Y: uint8(gray)}
}

func drawText(text string, img *image.NRGBA, opts *Options) error {
	ctx := freetype.NewContext()
	ctx.SetDPI(72.0)
	ctx.SetClip(img.Bounds())
	ctx.SetDst(img)
	ctx.SetHinting(font.HintingFull)
	ctx.SetFont(ttfFont)

	fontSpacing := opts.width / len(text)

	for idx, char := range text {
		fontScale := 1 + float64(rng.Intn(7))/float64(9)
		fontSize := float64(opts.height) / fontScale
		ctx.SetFontSize(fontSize)
		ctx.SetSrc(image.NewUniform(randomDarkGray()))
		x := fontSpacing*idx + fontSpacing/int(fontSize)
		y := opts.height/6 + rng.Intn(opts.height/3) + int(fontSize/2)
		pt := freetype.Pt(x, y)
		if _, err := ctx.DrawString(string(char), pt); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>add: godoc comments<commit_after>// Package captcha provides a simple API for captcha generation
package captcha

import (
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font"
	"golang.org/x/image/font/gofont/goregular"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"io"
	"math"
	"math/rand"
	"time"
)

const charPreset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

var rng = rand.New(rand.NewSource(time.Now().UnixNano()))
var ttfFont *truetype.Font

// Options manage captcha generation details.
type Options struct {
	// BackgroundColor is captcha image's background color.
	// It defaults to color.Transparent.
	BackgroundColor color.Color
	// CharPreset decides what text will be on captcha image.
	// It defaults to digit 0-9 and all English alphabet.
	// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
	CharPreset string
	// TextLength is the length of captcha text.
	// It defaults to 4.
	TextLength int
	// CurveNumber is the number of curves to draw on captcha image.
	// It defaults to 3.
	CurveNumber int

	width       int
	height      int
}

func newDefaultOption(width, height int) *Options {
	return &Options{
		BackgroundColor: color.Transparent,
		CharPreset:      charPreset,
		TextLength:      4,
		CurveNumber:     3,
		width:           width,
		height:          height,
	}
}

// SetOption is a function that can be used to modify default options.
type SetOption func(*Options)

// Data is the result of captcha generation.
// It has a `Text` field and a private `img` field that will
// be used in `WriteTo` receiver
type Data struct {
	// Text is captcha solution
	Text string

	img *image.NRGBA
}

// WriteTo encodes image data and writes to an io.Writer.
// It returns possible error from PNG encoding
func (data *Data) WriteTo(w io.Writer) error {
	return png.Encode(w, data.img)
}

func init() {
	var err error
	ttfFont, err = freetype.ParseFont(goregular.TTF)
	if err != nil {
		panic(err)
	}
}

// New creates a new captcha.
// It returns captcha data and any freetype drawing error encountered
func New(width int, height int, option ...SetOption) (*Data, error) {
	options := newDefaultOption(width, height)
	for _, setOption := range option {
		setOption(options)
	}

	text := randomText(options)
	img := image.NewNRGBA(image.Rect(0, 0, width, height))
	draw.Draw(img, img.Bounds(), &image.Uniform{options.BackgroundColor}, image.ZP, draw.Src)
	drawNoise(img, options)
	drawCurves(img, options)
	err := drawText(text, img, options)
	if err != nil {
		return nil, err
	}

	return &Data{Text: text, img: img}, nil
}

func randomText(opts *Options) (text string) {
	n := len(opts.CharPreset)
	for i := 0; i < opts.TextLength; i++ {
		text += string(opts.CharPreset[rng.Intn(n)])
	}

	return text
}

func drawNoise(img *image.NRGBA, opts *Options) {
	noiseCount := (opts.width * opts.height) / 18
	for i := 0; i < noiseCount; i++ {
		x := rng.Intn(opts.width)
		y := rng.Intn(opts.height)
		img.Set(x, y, randomColor())
	}
}

func randomColor() color.RGBA {
	red := rng.Intn(255)
	green := rng.Intn(255)
	blue := rng.Intn(255)

	return color.RGBA{R: uint8(red), G: uint8(green), B: uint8(blue), A: uint8(255)}
}

func drawCurves(img *image.NRGBA, opts *Options) {
	for i := 0; i < opts.CurveNumber; i++ {
		drawSineCurve(img, opts)
	}
}

// Ideally we want to draw bezier curves
// For now sine curves will do the job
func drawSineCurve(img *image.NRGBA, opts *Options) {
	var xStart, xEnd int
	if opts.width <= 40 {
		xStart, xEnd = 1, opts.width-1
	} else {
		xStart = rng.Intn(opts.width/10) + 1
		xEnd = opts.width - rng.Intn(opts.width/10) - 1
	}
	curveHeight := float64(rng.Intn(opts.height/6) + opts.height/6)
	yStart := rng.Intn(opts.height*2/3) + opts.height/6
	angle := 1.0 + rng.Float64()
	flip := rng.Intn(2) == 0
	yFlip := 1.0
	if flip {
		yFlip = -1.0
	}
	curveColor := randomDarkGray()

	for x1 := xStart; x1 <= xEnd; x1++ {
		y := math.Sin(math.Pi*angle*float64(x1)/float64(opts.width)) * curveHeight * yFlip
		img.Set(x1, int(y)+yStart, curveColor)
	}
}

func randomDarkGray() color.Gray {
	gray := rng.Intn(128) + 20

	return color.Gray{Y: uint8(gray)}
}

func drawText(text string, img *image.NRGBA, opts *Options) error {
	ctx := freetype.NewContext()
	ctx.SetDPI(72.0)
	ctx.SetClip(img.Bounds())
	ctx.SetDst(img)
	ctx.SetHinting(font.HintingFull)
	ctx.SetFont(ttfFont)

	fontSpacing := opts.width / len(text)

	for idx, char := range text {
		fontScale := 1 + float64(rng.Intn(7))/float64(9)
		fontSize := float64(opts.height) / fontScale
		ctx.SetFontSize(fontSize)
		ctx.SetSrc(image.NewUniform(randomDarkGray()))
		x := fontSpacing*idx + fontSpacing/int(fontSize)
		y := opts.height/6 + rng.Intn(opts.height/3) + int(fontSize/2)
		pt := freetype.Pt(x, y)
		if _, err := ctx.DrawString(string(char), pt); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 fi

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strings"
	"sync"

	"github.com/golang/glog"
	"k8s.io/kops/pkg/assets"
	"k8s.io/kops/pkg/diff"
	"k8s.io/kops/util/pkg/reflectutils"
)

// DryRunTarget is a special Target that does not execute anything, but instead tracks all changes.
// By running against a DryRunTarget, a list of changes that would be made can be easily collected,
// without any special support from the Tasks.
type DryRunTarget struct {
	mutex sync.Mutex

	changes   []*render
	deletions []Deletion

	// The destination to which the final report will be printed on Finish()
	out io.Writer

	// assetBuilder records all assets used
	assetBuilder *assets.AssetBuilder
}

type render struct {
	a       Task
	aIsNil  bool
	e       Task
	changes Task
}

// ByTaskKey sorts []*render by TaskKey (type/name)
type ByTaskKey []*render

func (a ByTaskKey) Len() int      { return len(a) }
func (a ByTaskKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByTaskKey) Less(i, j int) bool {
	return buildTaskKey(a[i].e) < buildTaskKey(a[j].e)
}

// DeletionByTaskName sorts []Deletion by TaskName
type DeletionByTaskName []Deletion

func (a DeletionByTaskName) Len() int      { return len(a) }
func (a DeletionByTaskName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a DeletionByTaskName) Less(i, j int) bool {
	return a[i].TaskName() < a[i].TaskName()
}

var _ Target = &DryRunTarget{}

func NewDryRunTarget(assetBuilder *assets.AssetBuilder, out io.Writer) *DryRunTarget {
	t := &DryRunTarget{}
	t.out = out
	t.assetBuilder = assetBuilder
	return t
}

func (t *DryRunTarget) ProcessDeletions() bool {
	// We display deletions
	return true
}

func (t *DryRunTarget) Render(a, e, changes Task) error {
	valA := reflect.ValueOf(a)
	aIsNil := valA.IsNil()

	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.changes = append(t.changes, &render{
		a:       a,
		aIsNil:  aIsNil,
		e:       e,
		changes: changes,
	})
	return nil
}

func (t *DryRunTarget) Delete(deletion Deletion) error {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.deletions = append(t.deletions, deletion)

	return nil
}

func idForTask(taskMap map[string]Task, t Task) string {
	for k, v := range taskMap {
		if v == t {
			// Skip task type, if present (taskType/taskName)
			firstSlash := strings.Index(k, "/")
			if firstSlash != -1 {
				k = k[firstSlash+1:]
			}
			return k
		}
	}
	glog.Fatalf("unknown task: %v", t)
	return "?"
}

func (t *DryRunTarget) PrintReport(taskMap map[string]Task, out io.Writer) error {
	b := &bytes.Buffer{}

	if len(t.changes) != 0 {
		var creates []*render
		var updates []*render

		for _, r := range t.changes {
			if r.aIsNil {
				creates = append(creates, r)
			} else {
				updates = append(updates, r)
			}
		}

		// Give everything a consistent ordering
		sort.Sort(ByTaskKey(creates))
		sort.Sort(ByTaskKey(updates))

		if len(creates) != 0 {
			fmt.Fprintf(b, "Will create resources:\n")
			for _, r := range creates {
				taskName := getTaskName(r.changes)
				fmt.Fprintf(b, "  %s/%s\n", taskName, idForTask(taskMap, r.e))

				changes := reflect.ValueOf(r.changes)
				if changes.Kind() == reflect.Ptr && !changes.IsNil() {
					changes = changes.Elem()
				}

				if changes.Kind() == reflect.Struct {
					for i := 0; i < changes.NumField(); i++ {

						field := changes.Field(i)

						fieldName := changes.Type().Field(i).Name
						if changes.Type().Field(i).PkgPath != "" {
							// Not exported
							continue
						}

						fieldValue := reflectutils.ValueAsString(field)

						shouldPrint := true
						if fieldName == "Name" {
							// The field name is already printed above, no need to repeat it.
							shouldPrint = false
						}
						if fieldName == "Lifecycle" {
							// Lifecycle is a "system" field; no need to show it
							shouldPrint = false
						}
						if fieldValue == "<nil>" || fieldValue == "<resource>" {
							// Uninformative
							shouldPrint = false
						}
						if fieldValue == "id:<nil>" {
							// Uninformative, but we can often print the name instead
							name := ""
							if field.CanInterface() {
								hasName, ok := field.Interface().(HasName)
								if ok {
									name = StringValue(hasName.GetName())
								}
							}
							if name != "" {
								fieldValue = "name:" + name
							} else {
								shouldPrint = false
							}
						}
						if shouldPrint {
							fmt.Fprintf(b, "  \t%-20s\t%s\n", fieldName, fieldValue)
						}
					}
				}

				fmt.Fprintf(b, "\n")
			}
		}

		if len(updates) != 0 {
			fmt.Fprintf(b, "Will modify resources:\n")
			// We can't use our reflection helpers here - we want corresponding values from a,e,c
			for _, r := range updates {
				changeList, err := buildChangeList(r.a, r.e, r.changes)
				if err != nil {
					return err
				}
				taskName := getTaskName(r.changes)
				fmt.Fprintf(b, "  %s/%s\n", taskName, idForTask(taskMap, r.e))

				if len(changeList) == 0 {
					fmt.Fprintf(b, "   internal consistency error!\n")
					fmt.Fprintf(b, "    actual: %+v\n", r.a)
					fmt.Fprintf(b, "    expect: %+v\n", r.e)
					continue
				}

				for _, change := range changeList {
					lines := strings.Split(change.Description, "\n")
					if len(lines) == 1 {
						fmt.Fprintf(b, "  \t%-20s\t%s\n", change.FieldName, change.Description)
					} else {
						fmt.Fprintf(b, "  \t%-20s\n", change.FieldName)
						for _, line := range lines {
							fmt.Fprintf(b, "  \t%-20s\t%s\n", "", line)
						}
					}
				}
				fmt.Fprintf(b, "\n")
			}
		}
	}

	if len(t.deletions) != 0 {
		// Give everything a consistent ordering
		sort.Sort(DeletionByTaskName(t.deletions))

		fmt.Fprintf(b, "Will delete items:\n")
		for _, d := range t.deletions {
			fmt.Fprintf(b, "  %-20s %s\n", d.TaskName(), d.Item())
		}
	}

	if len(t.assetBuilder.ContainerAssets) != 0 {
		glog.V(4).Infof("ContainerAssets:")
		for _, a := range t.assetBuilder.ContainerAssets {
			glog.V(4).Infof("  %s %s", a.DockerImage, a.CanonicalLocation)
		}
	}

	if len(t.assetBuilder.FileAssets) != 0 {
		glog.V(4).Infof("FileAssets:")
		for _, a := range t.assetBuilder.FileAssets {
			if a.FileURL != nil && a.CanonicalFileURL != nil {
				glog.V(4).Infof("  %s %s", a.FileURL.String(), a.CanonicalFileURL.String())
			} else if a.FileURL != nil {
				glog.V(4).Infof("  %s", a.FileURL.String())
			}
		}
	}

	_, err := out.Write(b.Bytes())
	return err
}

type change struct {
	FieldName   string
	Description string
}

func buildChangeList(a, e, changes Task) ([]change, error) {
	var changeList []change

	valC := reflect.ValueOf(changes)
	valA := reflect.ValueOf(a)
	valE := reflect.ValueOf(e)
	if valC.Kind() == reflect.Ptr && !valC.IsNil() {
		valC = valC.Elem()
	}
	if valA.Kind() == reflect.Ptr && !valA.IsNil() {
		valA = valA.Elem()
	}
	if valE.Kind() == reflect.Ptr && !valE.IsNil() {
		valE = valE.Elem()
	}
	if valC.Kind() == reflect.Struct {
		for i := 0; i < valC.NumField(); i++ {
			if valC.Type().Field(i).PkgPath != "" {
				// Not exported
				continue
			}

			fieldValC := valC.Field(i)

			changed := true
			switch fieldValC.Kind() {
			case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map:
				changed = !fieldValC.IsNil()

			case reflect.String:
				changed = fieldValC.Interface().(string) != ""
			}
			if !changed {
				continue
			}

			if fieldValC.Kind() == reflect.String && fieldValC.Interface().(string) == "" {
				// No change
				continue
			}

			fieldValE := valE.Field(i)

			description := ""
			ignored := false
			if fieldValE.CanInterface() {
				fieldValA := valA.Field(i)

				switch fieldValE.Interface().(type) {
				//case SimpleUnit:
				//	ignored = true
				case Resource, ResourceHolder:
					resA, okA := tryResourceAsString(fieldValA)
					resE, okE := tryResourceAsString(fieldValE)
					if okA && okE {
						description = diff.FormatDiff(resA, resE)
					}
				}

				if !ignored && description == "" {
					description = fmt.Sprintf(" %v -> %v", reflectutils.ValueAsString(fieldValA), reflectutils.ValueAsString(fieldValE))
				}
			}
			if ignored {
				continue
			}
			changeList = append(changeList, change{FieldName: valC.Type().Field(i).Name, Description: description})
		}
	} else {
		return nil, fmt.Errorf("unhandled change type: %v", valC.Type())
	}

	return changeList, nil
}

func tryResourceAsString(v reflect.Value) (string, bool) {
	if !v.IsValid() {
		return "", false
	}
	if !v.CanInterface() {
		return "", false
	}

	// Guard against nil interface go-tcha
	if v.Kind() == reflect.Interface && v.IsNil() {
		return "", false
	}
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return "", false
	}

	intf := v.Interface()
	if res, ok := intf.(Resource); ok {
		s, err := ResourceAsString(res)
		if err != nil {
			glog.Warningf("error converting to resource: %v", err)
			return "", false
		}
		return s, true
	}
	if res, ok := intf.(*ResourceHolder); ok {
		s, err := res.AsString()
		if err != nil {
			glog.Warningf("error converting to resource: %v", err)
			return "", false
		}
		return s, true
	}
	return "", false
}

func getTaskName(t Task) string {
	s := fmt.Sprintf("%T", t)
	lastDot := strings.LastIndexByte(s, '.')
	if lastDot != -1 {
		s = s[lastDot+1:]
	}
	return s
}

// Finish is called at the end of a run, and prints a list of changes to the configured Writer
func (t *DryRunTarget) Finish(taskMap map[string]Task) error {
	return t.PrintReport(taskMap, t.out)
}

// Deletions returns all task names which is going to be deleted
func (t *DryRunTarget) Deletions() []string {
	var deletions []string
	for _, d := range t.deletions {
		deletions = append(deletions, d.TaskName())
	}
	return deletions
}

// Changes returns all changed task names
func (t *DryRunTarget) Changes() []string {
	var changes []string
	for _, r := range t.changes {
		if r.aIsNil {
			changes = append(changes, getTaskName(r.changes))
		}
	}
	return changes
}

// HasChanges returns true iff any changes would have been made
func (t *DryRunTarget) HasChanges() bool {
	return len(t.changes)+len(t.deletions) != 0
}
<commit_msg>append task as well<commit_after>/*
Copyright 2016 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 fi

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strings"
	"sync"

	"github.com/golang/glog"
	"k8s.io/kops/pkg/assets"
	"k8s.io/kops/pkg/diff"
	"k8s.io/kops/util/pkg/reflectutils"
)

// DryRunTarget is a special Target that does not execute anything, but instead tracks all changes.
// By running against a DryRunTarget, a list of changes that would be made can be easily collected,
// without any special support from the Tasks.
type DryRunTarget struct {
	mutex sync.Mutex

	changes   []*render
	deletions []Deletion

	// The destination to which the final report will be printed on Finish()
	out io.Writer

	// assetBuilder records all assets used
	assetBuilder *assets.AssetBuilder
}

type render struct {
	a       Task
	aIsNil  bool
	e       Task
	changes Task
}

// ByTaskKey sorts []*render by TaskKey (type/name)
type ByTaskKey []*render

func (a ByTaskKey) Len() int      { return len(a) }
func (a ByTaskKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByTaskKey) Less(i, j int) bool {
	return buildTaskKey(a[i].e) < buildTaskKey(a[j].e)
}

// DeletionByTaskName sorts []Deletion by TaskName
type DeletionByTaskName []Deletion

func (a DeletionByTaskName) Len() int      { return len(a) }
func (a DeletionByTaskName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a DeletionByTaskName) Less(i, j int) bool {
	return a[i].TaskName() < a[i].TaskName()
}

var _ Target = &DryRunTarget{}

func NewDryRunTarget(assetBuilder *assets.AssetBuilder, out io.Writer) *DryRunTarget {
	t := &DryRunTarget{}
	t.out = out
	t.assetBuilder = assetBuilder
	return t
}

func (t *DryRunTarget) ProcessDeletions() bool {
	// We display deletions
	return true
}

func (t *DryRunTarget) Render(a, e, changes Task) error {
	valA := reflect.ValueOf(a)
	aIsNil := valA.IsNil()

	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.changes = append(t.changes, &render{
		a:       a,
		aIsNil:  aIsNil,
		e:       e,
		changes: changes,
	})
	return nil
}

func (t *DryRunTarget) Delete(deletion Deletion) error {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.deletions = append(t.deletions, deletion)

	return nil
}

func idForTask(taskMap map[string]Task, t Task) string {
	for k, v := range taskMap {
		if v == t {
			// Skip task type, if present (taskType/taskName)
			firstSlash := strings.Index(k, "/")
			if firstSlash != -1 {
				k = k[firstSlash+1:]
			}
			return k
		}
	}
	glog.Fatalf("unknown task: %v", t)
	return "?"
}

func (t *DryRunTarget) PrintReport(taskMap map[string]Task, out io.Writer) error {
	b := &bytes.Buffer{}

	if len(t.changes) != 0 {
		var creates []*render
		var updates []*render

		for _, r := range t.changes {
			if r.aIsNil {
				creates = append(creates, r)
			} else {
				updates = append(updates, r)
			}
		}

		// Give everything a consistent ordering
		sort.Sort(ByTaskKey(creates))
		sort.Sort(ByTaskKey(updates))

		if len(creates) != 0 {
			fmt.Fprintf(b, "Will create resources:\n")
			for _, r := range creates {
				taskName := getTaskName(r.changes)
				fmt.Fprintf(b, "  %s/%s\n", taskName, idForTask(taskMap, r.e))

				changes := reflect.ValueOf(r.changes)
				if changes.Kind() == reflect.Ptr && !changes.IsNil() {
					changes = changes.Elem()
				}

				if changes.Kind() == reflect.Struct {
					for i := 0; i < changes.NumField(); i++ {

						field := changes.Field(i)

						fieldName := changes.Type().Field(i).Name
						if changes.Type().Field(i).PkgPath != "" {
							// Not exported
							continue
						}

						fieldValue := reflectutils.ValueAsString(field)

						shouldPrint := true
						if fieldName == "Name" {
							// The field name is already printed above, no need to repeat it.
							shouldPrint = false
						}
						if fieldName == "Lifecycle" {
							// Lifecycle is a "system" field; no need to show it
							shouldPrint = false
						}
						if fieldValue == "<nil>" || fieldValue == "<resource>" {
							// Uninformative
							shouldPrint = false
						}
						if fieldValue == "id:<nil>" {
							// Uninformative, but we can often print the name instead
							name := ""
							if field.CanInterface() {
								hasName, ok := field.Interface().(HasName)
								if ok {
									name = StringValue(hasName.GetName())
								}
							}
							if name != "" {
								fieldValue = "name:" + name
							} else {
								shouldPrint = false
							}
						}
						if shouldPrint {
							fmt.Fprintf(b, "  \t%-20s\t%s\n", fieldName, fieldValue)
						}
					}
				}

				fmt.Fprintf(b, "\n")
			}
		}

		if len(updates) != 0 {
			fmt.Fprintf(b, "Will modify resources:\n")
			// We can't use our reflection helpers here - we want corresponding values from a,e,c
			for _, r := range updates {
				changeList, err := buildChangeList(r.a, r.e, r.changes)
				if err != nil {
					return err
				}
				taskName := getTaskName(r.changes)
				fmt.Fprintf(b, "  %s/%s\n", taskName, idForTask(taskMap, r.e))

				if len(changeList) == 0 {
					fmt.Fprintf(b, "   internal consistency error!\n")
					fmt.Fprintf(b, "    actual: %+v\n", r.a)
					fmt.Fprintf(b, "    expect: %+v\n", r.e)
					continue
				}

				for _, change := range changeList {
					lines := strings.Split(change.Description, "\n")
					if len(lines) == 1 {
						fmt.Fprintf(b, "  \t%-20s\t%s\n", change.FieldName, change.Description)
					} else {
						fmt.Fprintf(b, "  \t%-20s\n", change.FieldName)
						for _, line := range lines {
							fmt.Fprintf(b, "  \t%-20s\t%s\n", "", line)
						}
					}
				}
				fmt.Fprintf(b, "\n")
			}
		}
	}

	if len(t.deletions) != 0 {
		// Give everything a consistent ordering
		sort.Sort(DeletionByTaskName(t.deletions))

		fmt.Fprintf(b, "Will delete items:\n")
		for _, d := range t.deletions {
			fmt.Fprintf(b, "  %-20s %s\n", d.TaskName(), d.Item())
		}
	}

	if len(t.assetBuilder.ContainerAssets) != 0 {
		glog.V(4).Infof("ContainerAssets:")
		for _, a := range t.assetBuilder.ContainerAssets {
			glog.V(4).Infof("  %s %s", a.DockerImage, a.CanonicalLocation)
		}
	}

	if len(t.assetBuilder.FileAssets) != 0 {
		glog.V(4).Infof("FileAssets:")
		for _, a := range t.assetBuilder.FileAssets {
			if a.FileURL != nil && a.CanonicalFileURL != nil {
				glog.V(4).Infof("  %s %s", a.FileURL.String(), a.CanonicalFileURL.String())
			} else if a.FileURL != nil {
				glog.V(4).Infof("  %s", a.FileURL.String())
			}
		}
	}

	_, err := out.Write(b.Bytes())
	return err
}

type change struct {
	FieldName   string
	Description string
}

func buildChangeList(a, e, changes Task) ([]change, error) {
	var changeList []change

	valC := reflect.ValueOf(changes)
	valA := reflect.ValueOf(a)
	valE := reflect.ValueOf(e)
	if valC.Kind() == reflect.Ptr && !valC.IsNil() {
		valC = valC.Elem()
	}
	if valA.Kind() == reflect.Ptr && !valA.IsNil() {
		valA = valA.Elem()
	}
	if valE.Kind() == reflect.Ptr && !valE.IsNil() {
		valE = valE.Elem()
	}
	if valC.Kind() == reflect.Struct {
		for i := 0; i < valC.NumField(); i++ {
			if valC.Type().Field(i).PkgPath != "" {
				// Not exported
				continue
			}

			fieldValC := valC.Field(i)

			changed := true
			switch fieldValC.Kind() {
			case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map:
				changed = !fieldValC.IsNil()

			case reflect.String:
				changed = fieldValC.Interface().(string) != ""
			}
			if !changed {
				continue
			}

			if fieldValC.Kind() == reflect.String && fieldValC.Interface().(string) == "" {
				// No change
				continue
			}

			fieldValE := valE.Field(i)

			description := ""
			ignored := false
			if fieldValE.CanInterface() {
				fieldValA := valA.Field(i)

				switch fieldValE.Interface().(type) {
				//case SimpleUnit:
				//	ignored = true
				case Resource, ResourceHolder:
					resA, okA := tryResourceAsString(fieldValA)
					resE, okE := tryResourceAsString(fieldValE)
					if okA && okE {
						description = diff.FormatDiff(resA, resE)
					}
				}

				if !ignored && description == "" {
					description = fmt.Sprintf(" %v -> %v", reflectutils.ValueAsString(fieldValA), reflectutils.ValueAsString(fieldValE))
				}
			}
			if ignored {
				continue
			}
			changeList = append(changeList, change{FieldName: valC.Type().Field(i).Name, Description: description})
		}
	} else {
		return nil, fmt.Errorf("unhandled change type: %v", valC.Type())
	}

	return changeList, nil
}

func tryResourceAsString(v reflect.Value) (string, bool) {
	if !v.IsValid() {
		return "", false
	}
	if !v.CanInterface() {
		return "", false
	}

	// Guard against nil interface go-tcha
	if v.Kind() == reflect.Interface && v.IsNil() {
		return "", false
	}
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return "", false
	}

	intf := v.Interface()
	if res, ok := intf.(Resource); ok {
		s, err := ResourceAsString(res)
		if err != nil {
			glog.Warningf("error converting to resource: %v", err)
			return "", false
		}
		return s, true
	}
	if res, ok := intf.(*ResourceHolder); ok {
		s, err := res.AsString()
		if err != nil {
			glog.Warningf("error converting to resource: %v", err)
			return "", false
		}
		return s, true
	}
	return "", false
}

func getTaskName(t Task) string {
	s := fmt.Sprintf("%T", t)
	lastDot := strings.LastIndexByte(s, '.')
	if lastDot != -1 {
		s = s[lastDot+1:]
	}
	return s
}

// Finish is called at the end of a run, and prints a list of changes to the configured Writer
func (t *DryRunTarget) Finish(taskMap map[string]Task) error {
	return t.PrintReport(taskMap, t.out)
}

// Deletions returns all task names which is going to be deleted
func (t *DryRunTarget) Deletions() []string {
	var deletions []string
	for _, d := range t.deletions {
		deletions = append(deletions, d.TaskName())
	}
	return deletions
}

// Changes returns tasks which is going to be created or updated
func (t *DryRunTarget) Changes() (map[string]Task, map[string]Task) {
	creates := make(map[string]Task)
	updates := make(map[string]Task)
	for _, r := range t.changes {
		if r.aIsNil {
			creates[getTaskName(r.changes)] = r.changes
		} else {
			updates[getTaskName(r.changes)] = r.changes
		}
	}
	return creates, updates
}

// HasChanges returns true iff any changes would have been made
func (t *DryRunTarget) HasChanges() bool {
	return len(t.changes)+len(t.deletions) != 0
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"time"
)

func dial(conn *Connection, timeoutSeconds int) error {
	logDebug("Waiting " + strconv.Itoa(timeoutSeconds) + " seconds")
	if err := pingTCP(conn, timeoutSeconds); err != nil {
		return err
	}

	if conn.Scheme != "http" && conn.Scheme != "https" {
		return nil
	}

	if err := pingHTTP(conn, timeoutSeconds); err != nil {
		return err
	}
	return nil
}

func parallelDial(conn *Connection, timeoutSeconds int, ch chan error) {
	err := dial(conn, timeoutSeconds)
	ch <- err
}

func pingHTTP(conn *Connection, timeoutSeconds int) error {
	timeout := time.Duration(timeoutSeconds) * time.Second
	start := time.Now()
	address := fmt.Sprintf("%s://%s:%d%s", conn.Scheme, conn.Host, conn.Port, conn.Path)
	logDebug("HTTP address: " + address)

	for {
		resp, err := http.Get(address)

		if resp != nil {
			logDebug("ping HTTP " + resp.Status)
		}

		if err == nil && resp.StatusCode < http.StatusInternalServerError {
			return nil
		}

		if time.Since(start) > timeout {
			return errors.New(resp.Status)
		}

		time.Sleep(500 * time.Millisecond)
	}
}

func pingTCP(conn *Connection, timeoutSeconds int) error {
	timeout := time.Duration(timeoutSeconds) * time.Second
	start := time.Now()
	address := fmt.Sprintf("%s:%d", conn.Host, conn.Port)
	logDebug("Dial address: " + address)

	for {
		_, err := net.DialTimeout(conn.Type, address, time.Second)
		logDebug("ping TCP")

		if err == nil {
			logDebug("Up")
			return nil
		}

		logDebug("Down")
		logDebug(err)
		if time.Since(start) > timeout {
			return err
		}

		time.Sleep(500 * time.Millisecond)
	}
}
<commit_msg>Add address to debug to associate address to log (#6)<commit_after>package main

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"time"
)

func dial(conn *Connection, timeoutSeconds int) error {
	logDebug("Waiting " + strconv.Itoa(timeoutSeconds) + " seconds")
	if err := pingTCP(conn, timeoutSeconds); err != nil {
		return err
	}

	if conn.Scheme != "http" && conn.Scheme != "https" {
		return nil
	}

	if err := pingHTTP(conn, timeoutSeconds); err != nil {
		return err
	}
	return nil
}

func parallelDial(conn *Connection, timeoutSeconds int, ch chan error) {
	err := dial(conn, timeoutSeconds)
	ch <- err
}

func pingHTTP(conn *Connection, timeoutSeconds int) error {
	timeout := time.Duration(timeoutSeconds) * time.Second
	start := time.Now()
	address := fmt.Sprintf("%s://%s:%d%s", conn.Scheme, conn.Host, conn.Port, conn.Path)
	logDebug("HTTP address: " + address)

	for {
		resp, err := http.Get(address)

		if resp != nil {
			logDebug("ping HTTP " + address + " " + resp.Status)
		}

		if err == nil && resp.StatusCode < http.StatusInternalServerError {
			return nil
		}

		if time.Since(start) > timeout {
			return errors.New(resp.Status)
		}

		time.Sleep(500 * time.Millisecond)
	}
}

func pingTCP(conn *Connection, timeoutSeconds int) error {
	timeout := time.Duration(timeoutSeconds) * time.Second
	start := time.Now()
	address := fmt.Sprintf("%s:%d", conn.Host, conn.Port)
	logDebug("Dial address: " + address)

	for {
		_, err := net.DialTimeout(conn.Type, address, time.Second)
		logDebug("ping TCP: " + address)

		if err == nil {
			logDebug("Up: " + address)
			return nil
		}

		logDebug("Down: " + address)
		logDebug(err)
		if time.Since(start) > timeout {
			return err
		}

		time.Sleep(500 * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>// Package ddtracer is a DataDog's tracer (https://github.com/DataDog/dd-trace-go) wrapper for the OpenTracing API.
// As this is an OpenAPI wrapper, please refer to the official documentation.
package ddtracer

import (
	"context"
	"fmt"
	"math/rand"
	"os"
	"time"

	"github.com/DataDog/dd-trace-go/tracer"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func defaultHostname() string {
	host, _ := os.Hostname()
	return host
}

var (
	DefaultService  = defaultHostname()
	DefaultResource = "/"
)

var (
	// ServiceTagKey is use to indicate which tag is going to be used to set the service name
	ServiceTagKey = "service"
	// ResourceTagKey is use to indicate which tag is going to be used to set the resource
	ResourceTagKey = "resource"
)

type Tracer struct {
	*tracer.Tracer
	textPropagator *textMapPropagator
}

// NewTracer creates a new Tracer.
func NewTracer() opentracing.Tracer {
	return NewTracerTransport(nil)
}

// NewTracerTransport create a new Tracer with the given transport.
func NewTracerTransport(tr tracer.Transport) opentracing.Tracer {
	var driver *tracer.Tracer
	if tr == nil {
		driver = tracer.NewTracer()
	} else {
		driver = tracer.NewTracerTransport(tr)
	}

	t := &Tracer{Tracer: driver}
	t.textPropagator = &textMapPropagator{t}

	return t
}

func (t *Tracer) StartSpan(op string, opts ...opentracing.StartSpanOption) opentracing.Span {
	sso := &opentracing.StartSpanOptions{}
	for _, o := range opts {
		o.Apply(sso)
	}

	return t.startSpanWithOptions(op, sso)
}

func (t *Tracer) startSpanWithOptions(op string, opts *opentracing.StartSpanOptions) opentracing.Span {
	var span *tracer.Span
	for _, ref := range opts.References {
		if ref.Type == opentracing.ChildOfRef {
			if p, ok := ref.ReferencedContext.(*SpanContext); ok {
				span = tracer.NewChildSpanFromContext(op, p.ctx)
			}
		}
	}

	if span == nil {
		span = t.NewRootSpan(op, DefaultService, DefaultResource)
	}

	s := &Span{span}
	for key, value := range opts.Tags {
		s.SetTag(key, value)
	}

	return s

}

func (t *Tracer) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error {
	sc, ok := sm.(*SpanContext)
	if !ok {
		return opentracing.ErrInvalidSpanContext
	}

	span, ok := tracer.SpanFromContext(sc.ctx)
	if !ok {
		return opentracing.ErrInvalidSpanContext
	}

	switch format {
	case opentracing.HTTPHeaders:
		return t.textPropagator.Inject(span, carrier)
	}

	return opentracing.ErrUnsupportedFormat
}

func (t *Tracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
	switch format {
	case opentracing.HTTPHeaders:
		return t.textPropagator.Extract(carrier)
	}
	return nil, opentracing.ErrUnsupportedFormat
}

type Span struct {
	*tracer.Span
}

func (s *Span) Finish() {
	s.FinishWithOptions(opentracing.FinishOptions{})
}

func (s *Span) FinishWithOptions(opts opentracing.FinishOptions) {
	if !opts.FinishTime.IsZero() {
		s.Duration = opts.FinishTime.UTC().UnixNano() - s.Start
	}
	s.Span.Finish()
}

func (s *Span) Context() opentracing.SpanContext {
	ctx := s.Span.Context(context.Background())
	return &SpanContext{ctx}
}

func (s *Span) SetOperationName(operationName string) opentracing.Span {
	s.Name = operationName
	return s
}

func (s *Span) setMeta(key string, value interface{}) opentracing.Span {
	val := fmt.Sprint(value)
	switch key {
	case ServiceTagKey:
		s.Service = val
	case ResourceTagKey:
		s.Resource = val
	default:
		s.SetMeta(key, val)
	}

	return s
}

func (s *Span) SetTag(key string, value interface{}) opentracing.Span {
	switch t := value.(type) {
	case float64:
		s.SetMetric(key, t)
	default:
		s.setMeta(key, fmt.Sprint(value))
	}

	return s
}

func (s *Span) LogFields(fields ...log.Field) {
	for _, field := range fields {
		s.SetTag(field.Key(), field.Value())
	}
}

func (s *Span) LogKV(alternatingKeyValues ...interface{}) {
	fields, err := log.InterleavedKVToFields(alternatingKeyValues...)
	if err != nil {
		return
	}
	s.LogFields(fields...)
}

// SetBaggageItem  hasn't been implemented
func (s *Span) SetBaggageItem(restrictedKey string, value string) opentracing.Span {
	panic("not implemented")
}

// BaggageItem hasn't been implemented
func (s *Span) BaggageItem(restrictedKey string) string {
	panic("not implemented")
}

func (s *Span) Tracer() opentracing.Tracer {
	return s.Tracer()
}

// LogEvent hasn't been implemented
func (s *Span) LogEvent(event string) {
	panic("not implemented")
}

// LogEventWithPayload hasn't been implemented
func (s *Span) LogEventWithPayload(event string, payload interface{}) {
	panic("not implemented")
}

// Log hasn't been implemented
func (s *Span) Log(data opentracing.LogData) {
	panic("not implemented")
}

type SpanContext struct {
	ctx context.Context
}

// ForeachBaggageItem hasn't been implemented
func (ctx *SpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
	panic("not implemented")
}
<commit_msg>Deprecate Log facily functions<commit_after>// Package ddtracer is a DataDog's tracer (https://github.com/DataDog/dd-trace-go) wrapper for the OpenTracing API.
// As this is an OpenAPI wrapper, please refer to the official documentation.
package ddtracer

import (
	"context"
	"fmt"
	stdlog "log"
	"math/rand"
	"os"
	"time"

	"github.com/DataDog/dd-trace-go/tracer"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func defaultHostname() string {
	host, _ := os.Hostname()
	return host
}

var (
	DefaultService  = defaultHostname()
	DefaultResource = "/"
)

var (
	// ServiceTagKey is use to indicate which tag is going to be used to set the service name
	ServiceTagKey = "service"
	// ResourceTagKey is use to indicate which tag is going to be used to set the resource
	ResourceTagKey = "resource"
)

type Tracer struct {
	*tracer.Tracer
	textPropagator *textMapPropagator
}

// NewTracer creates a new Tracer.
func NewTracer() opentracing.Tracer {
	return NewTracerTransport(nil)
}

// NewTracerTransport create a new Tracer with the given transport.
func NewTracerTransport(tr tracer.Transport) opentracing.Tracer {
	var driver *tracer.Tracer
	if tr == nil {
		driver = tracer.NewTracer()
	} else {
		driver = tracer.NewTracerTransport(tr)
	}

	t := &Tracer{Tracer: driver}
	t.textPropagator = &textMapPropagator{t}

	return t
}

func (t *Tracer) StartSpan(op string, opts ...opentracing.StartSpanOption) opentracing.Span {
	sso := &opentracing.StartSpanOptions{}
	for _, o := range opts {
		o.Apply(sso)
	}

	return t.startSpanWithOptions(op, sso)
}

func (t *Tracer) startSpanWithOptions(op string, opts *opentracing.StartSpanOptions) opentracing.Span {
	var span *tracer.Span
	for _, ref := range opts.References {
		if ref.Type == opentracing.ChildOfRef {
			if p, ok := ref.ReferencedContext.(*SpanContext); ok {
				span = tracer.NewChildSpanFromContext(op, p.ctx)
			}
		}
	}

	if span == nil {
		span = t.NewRootSpan(op, DefaultService, DefaultResource)
	}

	s := &Span{span}
	for key, value := range opts.Tags {
		s.SetTag(key, value)
	}

	return s

}

func (t *Tracer) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error {
	sc, ok := sm.(*SpanContext)
	if !ok {
		return opentracing.ErrInvalidSpanContext
	}

	span, ok := tracer.SpanFromContext(sc.ctx)
	if !ok {
		return opentracing.ErrInvalidSpanContext
	}

	switch format {
	case opentracing.HTTPHeaders:
		return t.textPropagator.Inject(span, carrier)
	}

	return opentracing.ErrUnsupportedFormat
}

func (t *Tracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
	switch format {
	case opentracing.HTTPHeaders:
		return t.textPropagator.Extract(carrier)
	}
	return nil, opentracing.ErrUnsupportedFormat
}

type Span struct {
	*tracer.Span
}

func (s *Span) Finish() {
	s.FinishWithOptions(opentracing.FinishOptions{})
}

func (s *Span) FinishWithOptions(opts opentracing.FinishOptions) {
	if !opts.FinishTime.IsZero() {
		s.Duration = opts.FinishTime.UTC().UnixNano() - s.Start
	}
	s.Span.Finish()
}

func (s *Span) Context() opentracing.SpanContext {
	ctx := s.Span.Context(context.Background())
	return &SpanContext{ctx}
}

func (s *Span) SetOperationName(operationName string) opentracing.Span {
	s.Name = operationName
	return s
}

func (s *Span) setMeta(key string, value interface{}) opentracing.Span {
	val := fmt.Sprint(value)
	switch key {
	case ServiceTagKey:
		s.Service = val
	case ResourceTagKey:
		s.Resource = val
	default:
		s.SetMeta(key, val)
	}

	return s
}

func (s *Span) SetTag(key string, value interface{}) opentracing.Span {
	switch t := value.(type) {
	case float64:
		s.SetMetric(key, t)
	default:
		s.setMeta(key, fmt.Sprint(value))
	}

	return s
}

func (s *Span) LogFields(fields ...log.Field) {
	for _, field := range fields {
		s.SetTag(field.Key(), field.Value())
	}
}

func (s *Span) LogKV(alternatingKeyValues ...interface{}) {
	fields, err := log.InterleavedKVToFields(alternatingKeyValues...)
	if err != nil {
		return
	}
	s.LogFields(fields...)
}

func (s *Span) LogEvent(event string) {
	stdlog.Println("Span.LogEvent() has been deprecated, use LogFields or LogKV")
}

func (s *Span) LogEventWithPayload(event string, payload interface{}) {
	stdlog.Println("Span.LogWithPayload() has been deprecated, use LogFields or LogKV")
}

func (s *Span) Log(data opentracing.LogData) {
	stdlog.Println("Span.Log() has been deprecated, use LogFields or LogKV")
}

// SetBaggageItem  hasn't been implemented
func (s *Span) SetBaggageItem(restrictedKey string, value string) opentracing.Span {
	panic("not implemented")
}

// BaggageItem hasn't been implemented
func (s *Span) BaggageItem(restrictedKey string) string {
	panic("not implemented")
}

func (s *Span) Tracer() opentracing.Tracer {
	return s.Tracer()
}

type SpanContext struct {
	ctx context.Context
}

// ForeachBaggageItem hasn't been implemented
func (ctx *SpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
	panic("not implemented")
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"github.com/streadway/amqp"
	"log"
	"os"
	"os/signal"
	"syscall"
)

type RabbitMQConnector struct {
	Ch   *amqp.Channel
	Q    *amqp.Queue
	Conn *amqp.Connection
}

func BuildRabbitMQConnector(host string, port int, user string, password string) (*RabbitMQConnector, error) {
	var err error
	mq := &RabbitMQConnector{}
	url := fmt.Sprintf("amqp://%s:%s@%s:%v", user, password, host, port)

	if mq.Conn, err = amqp.Dial(url); err != nil {
		return nil, err
	}
	if mq.Ch, err = mq.Conn.Channel(); err != nil {
		return nil, err
	}
	if err = mq.Ch.ExchangeDeclare("logs", "fanout", true, false, false, false, nil); err != nil {
		return nil, err
	}
	if err = mq.Ch.Qos(1, 0, false); err != nil {
		return nil, err
	}
	q, err := mq.Ch.QueueDeclare("distinctName", true, false, false, false, nil)
	if err != nil {
		return nil, err
	}

	mq.Q = &q
	return mq, nil
}

func (m *RabbitMQConnector) Handle(f func([]byte)) {
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		defer m.close()
		msgs, err := m.Ch.Consume(m.Q.Name, "", false, false, false, false, nil)
		if err != nil {
			panic(err)
		}
		for d := range msgs {
			f(d.Body)
			if err := d.Ack(false); err != nil {
				panic(err)
			}
		}
	}()

	<-signalChan
}

func (m *RabbitMQConnector) close() {
	if err := m.Ch.Close(); err != nil {
		log.Println("error clossing ampq channel:", err)
	}
	if err := m.Conn.Close(); err != nil {
		log.Println("error clossing ampq connection:", err)
	}
}
<commit_msg>improve connector<commit_after>package common

import (
	"fmt"
	"github.com/streadway/amqp"
)

type RabbitMQConnector struct {
	conn    *amqp.Connection
	channel *amqp.Channel
	tag     string
	done    chan error
}

func BuildRabbitMQConnector(host string, port int, user string, password string) (*RabbitMQConnector, error) {
	var err error
	mq := &RabbitMQConnector{}
	Info("connecting to RabbitMQ")

	url := fmt.Sprintf("amqp://%s:%s@%s:%v", user, password, host, port)

	if mq.conn, err = amqp.Dial(url); err != nil {
		return nil, err
	}
	if mq.channel, err = mq.conn.Channel(); err != nil {
		return nil, err
	}
	if err = mq.channel.ExchangeDeclare("logs", "fanout", true, false, false, false, nil); err != nil {
		return nil, err
	}
	if err = mq.channel.Qos(1, 0, false); err != nil {
		return nil, err
	}
	return mq, nil
}

func (m *RabbitMQConnector) Handle(tag string, f func([]byte)) error {

	q, err := m.channel.QueueDeclare(tag, true, false, false, false, nil)
	if err != nil {
		return err
	}

	if err = m.channel.QueueBind(q.Name, "", "logs", false, nil); err != nil {
		return err
	}

	msgs, err := m.channel.Consume(tag, tag, false, false, false, false, nil)
	if err != nil {
		return err
	}
	go func() {
		Info("closing: %s", <-m.conn.NotifyClose(make(chan *amqp.Error)))
		//TODO: try to recconect
	}()
	m.tag = tag

	go handle(msgs, f, m.done)
	return nil
}

func handle(deliveries <-chan amqp.Delivery, f func([]byte), done chan error) {
	for d := range deliveries {
		d.Ack(false)
		f(d.Body)
	}
	Info("handle: deliveries channel closed")
	done <- nil
}

func (c *RabbitMQConnector) Close() error {
	// will close() the deliveries channel
	if err := c.channel.Cancel(c.tag, true); err != nil {
		return fmt.Errorf("Consumer cancel failed: %s", err)
	}
	if err := c.conn.Close(); err != nil {
		return fmt.Errorf("AMQP connection close error: %s", err)
	}
	defer Info("AMQP shutdown OK")
	// wait for handle() to exit
	return <-c.done
}
<|endoftext|>


<commit_before>// 10 june 2014

package ndraw

import (
	"fmt"
	"image"
	"testing"
	"github.com/andlabs/ui"
)

type areaHandler struct {
	img		*image.RGBA
}
func (a *areaHandler) Paint(r image.Rectangle) *image.RGBA {
	return a.img.SubImage(r).(*image.RGBA)
}
func (a *areaHandler) Key(ke ui.KeyEvent) bool {
	return false
}
func (a *areaHandler) Mouse(me ui.MouseEvent) {}

var w ui.Window

func myMain() {
	fonts := ListFonts()
	for _, font := range fonts {
		fmt.Printf("%#v\n", font)
	}
	i := NewImage(320, 240)
	defer i.Close()
	b := NewBrush(BrushSpec{
		R:			0,
		G:			128,
		B:			0,
		A:			0xFF,
	})
	f := NewFont(FontSpec{
		Family:	"Helvetica",
		Size:		12,
		Bold:		true,
	})
	i.Text("hello, world", 100, 20, f, nil, b)
	b.Close()
	p := NewPen(PenSpec{
		R:			128,//255, - TODO GDI AlphaBlend() actually produces gray for this invalid combination while cairo and Quartz do not (!!!)
		G:			0,
		B:			0,
		A:			128,
		Line:			Solid,
		Thickness:	3,
	})
	i.Line(4, 4, 316, 236, p)
	i.Line(100, 20, 101, 21, p)
	p.Close()
	p = NewPen(PenSpec{
		R:			0,
		G:			0,
		B:			255,
		A:			255,
		Line:			Solid,
		Thickness:	2,
	})
	wid, ht := i.TextSize("hello, world", f)
	i.Line(100, 20 + ht + 10, 100 + wid, 20 + ht + 10, p)
	i.Line(100 + wid + 10, 20, 100 + wid + 10, 20 + ht, p)
	p = NewPen(PenSpec{
		R:			0,
		G:			0,
		B:			255,
		A:			255,
		Line:			Solid,
		Thickness:	1,
	})
	i.Line(100, 20 + ht, 100 + wid, 20 + ht, p)
	i.Line(100 + wid, 20, 100 + wid, 20 + ht, p)
	i.Line(30, 200, 70, 240, p)
	p.Close()
	f.Close()
	ui.Do(func() {
		w = ui.NewWindow("Test", 320, 240, ui.NewArea(320, 240, &areaHandler{
			img:		i.Image(),
		}))
		w.OnClosing(func() bool {
			ui.Stop()
			return true
		})
		w.Show()
	})
}

func init() {
	go myMain()
	err := ui.Go()
	if err != nil {
		panic(err)
	}
}

func TestDummy(t *testing.T) {
	// do nothing
}
<commit_msg>Stripped the test program down.<commit_after>// 10 june 2014

package ndraw

import (
	"fmt"
	"image"
	"testing"
	"github.com/andlabs/ui"
)

type areaHandler struct {
	img		*image.RGBA
}
func (a *areaHandler) Paint(r image.Rectangle) *image.RGBA {
	return a.img.SubImage(r).(*image.RGBA)
}
func (a *areaHandler) Key(ke ui.KeyEvent) bool {
	return false
}
func (a *areaHandler) Mouse(me ui.MouseEvent) {}

var w ui.Window

func myMain() {
	fonts := ListFonts()
	for _, font := range fonts {
		fmt.Printf("%#v\n", font)
	}
	i := NewImage(320, 240)
	defer i.Close()
	b := NewBrush(BrushSpec{
		R:			0,
		G:			128,
		B:			0,
		A:			0xFF,
	})
	f := NewFont(FontSpec{
		Family:	"Helvetica",
		Size:		12,
		Bold:		true,
	})
	i.Text("hello, world", 100, 20, f, nil, b)
	b.Close()
	f.Close()
	ui.Do(func() {
		w = ui.NewWindow("Test", 320, 240, ui.NewArea(320, 240, &areaHandler{
			img:		i.Image(),
		}))
		w.OnClosing(func() bool {
			ui.Stop()
			return true
		})
		w.Show()
	})
}

func init() {
	go myMain()
	err := ui.Go()
	if err != nil {
		panic(err)
	}
}

func TestDummy(t *testing.T) {
	// do nothing
}
<|endoftext|>


<commit_before>// Package car is a language agnostic rpc proxy
package car

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/micro/cli"
	"github.com/micro/go-api"
	"github.com/micro/go-api/router"
	"github.com/micro/go-log"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/cmd"
	"github.com/micro/go-micro/registry"
	"github.com/micro/micro/internal/handler"
	"github.com/micro/micro/internal/helper"
	"github.com/micro/micro/internal/server"
	"github.com/micro/micro/internal/stats"
	"github.com/micro/micro/plugin"
	"github.com/pborman/uuid"
)

type sidecar struct {
	name    string
	address string
	hcUrl   string
}

type srv struct {
	*mux.Router
}

var (
	Name         = "go.micro.sidecar"
	Address      = ":8081"
	Handler      = "rpc"
	RootPath     = "/"
	ProxyPath    = "/{service:[a-zA-Z0-9]+}"
	BrokerPath   = "/broker"
	HealthPath   = "/health"
	RegistryPath = "/registry"
	RPCPath      = "/rpc"
	CORS         = map[string]bool{"*": true}
	Namespace    = "go.micro.srv"
)

func (s *srv) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get("Origin"); CORS[origin] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	} else if len(origin) > 0 && CORS["*"] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
	w.Header().Set("Access-Control-Allow-Credentials", "true")

	if r.Method == "OPTIONS" {
		return
	}

	s.Router.ServeHTTP(w, r)
}

func newSidecar(name, address, hcUrl string) *sidecar {
	return &sidecar{
		name:    name,
		address: address,
		hcUrl:   hcUrl,
	}
}

func run(ctx *cli.Context, car *sidecar) {
	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("cors")) > 0 {
		origins := make(map[string]bool)
		for _, origin := range strings.Split(ctx.String("cors"), ",") {
			origins[origin] = true
		}
		CORS = origins
	}
	if len(ctx.String("handler")) > 0 {
		Handler = ctx.String("handler")
	}
	if len(ctx.String("namespace")) > 0 {
		Namespace = ctx.String("namespace")
	}

	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	var opts []server.Option

	if ctx.GlobalBool("enable_tls") {
		config, err := helper.TLSConfig(ctx)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		opts = append(opts, server.EnableTLS(true))
		opts = append(opts, server.TLSConfig(config))
	}

	r := mux.NewRouter()
	s := &srv{r}

	// new server
	srv := server.NewServer(Address)
	srv.Init(opts...)

	// register handlers
	if car != nil {
		log.Logf("Registering Health handler at %s", HealthPath)
		r.Handle(HealthPath, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if c, err := car.hc(); err != nil {
				http.Error(w, err.Error(), c)
				return
			}
		}))
	}

	log.Logf("Registering Registry handler at %s", RegistryPath)
	r.Handle(RegistryPath, http.HandlerFunc(handler.Registry))

	log.Logf("Registering RPC handler at %s", RPCPath)
	r.Handle(RPCPath, http.HandlerFunc(handler.RPC))

	log.Logf("Registering Broker handler at %s", BrokerPath)
	r.Handle(BrokerPath, http.HandlerFunc(handler.Broker))

	switch Handler {
	case "proxy":
		log.Logf("Registering Proxy Handler at %s", ProxyPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Proxy))
		r.PathPrefix(ProxyPath).Handler(handler.Proxy(rt, nil, false))
	// rpc
	default:
		log.Logf("Registering Root Handler at %s", RootPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Rpc))
		r.PathPrefix(RootPath).Handler(handler.RPCX(rt, nil))
	}

	var h http.Handler = s

	if ctx.GlobalBool("enable_stats") {
		st := stats.New()
		r.Handle("/stats", http.HandlerFunc(st.StatsHandler))
		h = st.ServeHTTP(r)
		st.Start()
		defer st.Stop()
	}

	// reverse wrap handler
	plugins := append(Plugins(), plugin.Plugins()...)
	for i := len(plugins); i > 0; i-- {
		h = plugins[i-1].Handler()(h)
	}

	srv.Handle("/", h)

	// Initialise Server
	service := micro.NewService(
		micro.Name(Name),
		micro.RegisterTTL(
			time.Duration(ctx.GlobalInt("register_ttl"))*time.Second,
		),
		micro.RegisterInterval(
			time.Duration(ctx.GlobalInt("register_interval"))*time.Second,
		),
	)

	if err := srv.Start(); err != nil {
		log.Fatal(err)
	}

	// Run server
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	if err := srv.Stop(); err != nil {
		log.Fatal(err)
	}
}

func (s *sidecar) hc() (int, error) {
	if len(s.hcUrl) == 0 {
		return 200, nil
	}
	rsp, err := http.Get(s.hcUrl)
	if err != nil {
		return 500, err
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != 200 {
		return rsp.StatusCode, fmt.Errorf("Non 200 response: %d", rsp.StatusCode)
	}
	return 200, nil
}

func (s *sidecar) hcLoop(service *registry.Service, exitCh chan bool) {
	tick := time.NewTicker(time.Second * 30)
	registered := true

	for {
		select {
		case <-tick.C:
			_, err := s.hc()
			if err != nil && registered {
				log.Logf("Healthcheck error. Deregistering %v", service.Nodes[0].Id)
				(*cmd.DefaultOptions().Registry).Deregister(service)
				registered = false
			} else if err == nil && !registered {
				log.Logf("Healthcheck success. Registering %v", service.Nodes[0].Id)
				(*cmd.DefaultOptions().Registry).Register(service)
				registered = true
			}
		case <-exitCh:
			return
		}
	}
}

// run healthchecker
func (s *sidecar) run(exit chan bool) {
	parts := strings.Split(s.address, ":")
	host := strings.Join(parts[:len(parts)-1], ":")
	port, _ := strconv.Atoi(parts[len(parts)-1])

	id := s.name + "-" + uuid.NewUUID().String()
	node := &registry.Node{
		Id:      id,
		Address: host,
		Port:    port,
	}

	service := &registry.Service{
		Name:  s.name,
		Nodes: []*registry.Node{node},
	}

	log.Logf("Registering %s", node.Id)
	(*cmd.DefaultOptions().Registry).Register(service)

	if len(s.hcUrl) == 0 {
		return
	}

	log.Log("Starting sidecar healthchecker")
	go s.hcLoop(service, exit)
	<-exit
}

func Commands() []cli.Command {
	command := cli.Command{
		Name:  "sidecar",
		Usage: "Run the micro sidecar",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the sidecar address e.g 0.0.0.0:8081",
				EnvVar: "MICRO_SIDECAR_ADDRESS",
			},
			cli.StringFlag{
				Name:   "cors",
				Usage:  "Comma separated whitelist of allowed origins for CORS",
				EnvVar: "MICRO_SIDECAR_CORS",
			},
			cli.StringFlag{
				Name:   "handler",
				Usage:  "Specify the request handler to be used for mapping HTTP requests to services; {proxy, rpc}",
				EnvVar: "MICRO_SIDECAR_HANDLER",
			},
			cli.StringFlag{
				Name:   "namespace",
				Usage:  "Set the namespace used by the sidecar e.g. com.example.srv",
				EnvVar: "MICRO_SIDECAR_NAMESPACE",
			},
			cli.StringFlag{
				Name:  "server_name",
				Usage: "Server name of the app",
			},
			cli.StringFlag{
				Name:  "server_address",
				Usage: "Server address and port of the app",
			},
			cli.StringFlag{
				Name:  "healthcheck_url",
				Usage: "URL to check health of the app",
			},
		},
		Action: func(c *cli.Context) {
			name := c.String("server_name")
			address := c.String("server_address")
			hcUrl := c.String("healthcheck_url")

			if len(name) == 0 && len(address) == 0 {
				run(c, nil)
				return
			}

			if len(name) == 0 {
				fmt.Println("Require server name")
				return
			}

			if len(address) == 0 {
				fmt.Println("Require server address")
				return
			}

			// exit chan
			exit := make(chan bool)

			// start the healthchecker
			car := newSidecar(name, address, hcUrl)
			go car.run(exit)

			// run the server
			run(c, car)

			// kill healthchecker
			close(exit)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<commit_msg>Fix stats handler for sidecar<commit_after>// Package car is a language agnostic rpc proxy
package car

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/micro/cli"
	"github.com/micro/go-api"
	"github.com/micro/go-api/router"
	"github.com/micro/go-log"
	"github.com/micro/go-micro"
	"github.com/micro/go-micro/cmd"
	"github.com/micro/go-micro/registry"
	"github.com/micro/micro/internal/handler"
	"github.com/micro/micro/internal/helper"
	"github.com/micro/micro/internal/server"
	"github.com/micro/micro/internal/stats"
	"github.com/micro/micro/plugin"
	"github.com/pborman/uuid"
)

type sidecar struct {
	name    string
	address string
	hcUrl   string
}

type srv struct {
	*mux.Router
}

var (
	Name         = "go.micro.sidecar"
	Address      = ":8081"
	Handler      = "rpc"
	RootPath     = "/"
	ProxyPath    = "/{service:[a-zA-Z0-9]+}"
	BrokerPath   = "/broker"
	HealthPath   = "/health"
	RegistryPath = "/registry"
	RPCPath      = "/rpc"
	CORS         = map[string]bool{"*": true}
	Namespace    = "go.micro.srv"
)

func (s *srv) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if origin := r.Header.Get("Origin"); CORS[origin] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	} else if len(origin) > 0 && CORS["*"] {
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
	w.Header().Set("Access-Control-Allow-Credentials", "true")

	if r.Method == "OPTIONS" {
		return
	}

	s.Router.ServeHTTP(w, r)
}

func newSidecar(name, address, hcUrl string) *sidecar {
	return &sidecar{
		name:    name,
		address: address,
		hcUrl:   hcUrl,
	}
}

func run(ctx *cli.Context, car *sidecar) {
	if len(ctx.GlobalString("server_name")) > 0 {
		Name = ctx.GlobalString("server_name")
	}
	if len(ctx.String("address")) > 0 {
		Address = ctx.String("address")
	}
	if len(ctx.String("cors")) > 0 {
		origins := make(map[string]bool)
		for _, origin := range strings.Split(ctx.String("cors"), ",") {
			origins[origin] = true
		}
		CORS = origins
	}
	if len(ctx.String("handler")) > 0 {
		Handler = ctx.String("handler")
	}
	if len(ctx.String("namespace")) > 0 {
		Namespace = ctx.String("namespace")
	}

	// Init plugins
	for _, p := range Plugins() {
		p.Init(ctx)
	}

	var opts []server.Option

	if ctx.GlobalBool("enable_tls") {
		config, err := helper.TLSConfig(ctx)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		opts = append(opts, server.EnableTLS(true))
		opts = append(opts, server.TLSConfig(config))
	}

	r := mux.NewRouter()
	s := &srv{r}

	var h http.Handler = s

	if ctx.GlobalBool("enable_stats") {
		st := stats.New()
		r.Handle("/stats", http.HandlerFunc(st.StatsHandler))
		h = st.ServeHTTP(r)
		st.Start()
		defer st.Stop()
	}

	// new server
	srv := server.NewServer(Address)
	srv.Init(opts...)

	// register handlers
	if car != nil {
		log.Logf("Registering Health handler at %s", HealthPath)
		r.Handle(HealthPath, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if c, err := car.hc(); err != nil {
				http.Error(w, err.Error(), c)
				return
			}
		}))
	}

	log.Logf("Registering Registry handler at %s", RegistryPath)
	r.Handle(RegistryPath, http.HandlerFunc(handler.Registry))

	log.Logf("Registering RPC handler at %s", RPCPath)
	r.Handle(RPCPath, http.HandlerFunc(handler.RPC))

	log.Logf("Registering Broker handler at %s", BrokerPath)
	r.Handle(BrokerPath, http.HandlerFunc(handler.Broker))

	switch Handler {
	case "proxy":
		log.Logf("Registering Proxy Handler at %s", ProxyPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Proxy))
		r.PathPrefix(ProxyPath).Handler(handler.Proxy(rt, nil, false))
	// rpc
	default:
		log.Logf("Registering Root Handler at %s", RootPath)
		rt := router.NewRouter(router.WithNamespace(Namespace), router.WithHandler(api.Rpc))
		r.PathPrefix(RootPath).Handler(handler.RPCX(rt, nil))
	}

	// reverse wrap handler
	plugins := append(Plugins(), plugin.Plugins()...)
	for i := len(plugins); i > 0; i-- {
		h = plugins[i-1].Handler()(h)
	}

	srv.Handle("/", h)

	// Initialise Server
	service := micro.NewService(
		micro.Name(Name),
		micro.RegisterTTL(
			time.Duration(ctx.GlobalInt("register_ttl"))*time.Second,
		),
		micro.RegisterInterval(
			time.Duration(ctx.GlobalInt("register_interval"))*time.Second,
		),
	)

	if err := srv.Start(); err != nil {
		log.Fatal(err)
	}

	// Run server
	if err := service.Run(); err != nil {
		log.Fatal(err)
	}

	if err := srv.Stop(); err != nil {
		log.Fatal(err)
	}
}

func (s *sidecar) hc() (int, error) {
	if len(s.hcUrl) == 0 {
		return 200, nil
	}
	rsp, err := http.Get(s.hcUrl)
	if err != nil {
		return 500, err
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != 200 {
		return rsp.StatusCode, fmt.Errorf("Non 200 response: %d", rsp.StatusCode)
	}
	return 200, nil
}

func (s *sidecar) hcLoop(service *registry.Service, exitCh chan bool) {
	tick := time.NewTicker(time.Second * 30)
	registered := true

	for {
		select {
		case <-tick.C:
			_, err := s.hc()
			if err != nil && registered {
				log.Logf("Healthcheck error. Deregistering %v", service.Nodes[0].Id)
				(*cmd.DefaultOptions().Registry).Deregister(service)
				registered = false
			} else if err == nil && !registered {
				log.Logf("Healthcheck success. Registering %v", service.Nodes[0].Id)
				(*cmd.DefaultOptions().Registry).Register(service)
				registered = true
			}
		case <-exitCh:
			return
		}
	}
}

// run healthchecker
func (s *sidecar) run(exit chan bool) {
	parts := strings.Split(s.address, ":")
	host := strings.Join(parts[:len(parts)-1], ":")
	port, _ := strconv.Atoi(parts[len(parts)-1])

	id := s.name + "-" + uuid.NewUUID().String()
	node := &registry.Node{
		Id:      id,
		Address: host,
		Port:    port,
	}

	service := &registry.Service{
		Name:  s.name,
		Nodes: []*registry.Node{node},
	}

	log.Logf("Registering %s", node.Id)
	(*cmd.DefaultOptions().Registry).Register(service)

	if len(s.hcUrl) == 0 {
		return
	}

	log.Log("Starting sidecar healthchecker")
	go s.hcLoop(service, exit)
	<-exit
}

func Commands() []cli.Command {
	command := cli.Command{
		Name:  "sidecar",
		Usage: "Run the micro sidecar",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:   "address",
				Usage:  "Set the sidecar address e.g 0.0.0.0:8081",
				EnvVar: "MICRO_SIDECAR_ADDRESS",
			},
			cli.StringFlag{
				Name:   "cors",
				Usage:  "Comma separated whitelist of allowed origins for CORS",
				EnvVar: "MICRO_SIDECAR_CORS",
			},
			cli.StringFlag{
				Name:   "handler",
				Usage:  "Specify the request handler to be used for mapping HTTP requests to services; {proxy, rpc}",
				EnvVar: "MICRO_SIDECAR_HANDLER",
			},
			cli.StringFlag{
				Name:   "namespace",
				Usage:  "Set the namespace used by the sidecar e.g. com.example.srv",
				EnvVar: "MICRO_SIDECAR_NAMESPACE",
			},
			cli.StringFlag{
				Name:  "server_name",
				Usage: "Server name of the app",
			},
			cli.StringFlag{
				Name:  "server_address",
				Usage: "Server address and port of the app",
			},
			cli.StringFlag{
				Name:  "healthcheck_url",
				Usage: "URL to check health of the app",
			},
		},
		Action: func(c *cli.Context) {
			name := c.String("server_name")
			address := c.String("server_address")
			hcUrl := c.String("healthcheck_url")

			if len(name) == 0 && len(address) == 0 {
				run(c, nil)
				return
			}

			if len(name) == 0 {
				fmt.Println("Require server name")
				return
			}

			if len(address) == 0 {
				fmt.Println("Require server address")
				return
			}

			// exit chan
			exit := make(chan bool)

			// start the healthchecker
			car := newSidecar(name, address, hcUrl)
			go car.run(exit)

			// run the server
			run(c, car)

			// kill healthchecker
			close(exit)
		},
	}

	for _, p := range Plugins() {
		if cmds := p.Commands(); len(cmds) > 0 {
			command.Subcommands = append(command.Subcommands, cmds...)
		}

		if flags := p.Flags(); len(flags) > 0 {
			command.Flags = append(command.Flags, flags...)
		}
	}

	return []cli.Command{command}
}
<|endoftext|>


<commit_before>package glob

import (
	"io"
	"os/exec"
	"path/filepath"
	"strconv"
)

// Runner contains information related to creating blobs.
type Runner struct {
	Src    io.Reader
	Dest   string
	Amount int
	Unit   string
}

func NewRunner(src io.Reader, dst, unit string, amnt int) *Runner {
	r := new(Runner)

	r.Src = src
	r.Dest = dst
	r.Amount = amnt
	r.Unit = unit

	return r
}

func (r *Runner) Mk() error {
	for i := 1; i <= r.Amount; i++ {
		fileName := strconv.Itoa(i) + r.Unit

		err := newCreateFile(r.Src, r.Dest, fileName, r.Unit)
		if err != nil {
			return err
		}
	}

	return nil
}

func newCreateFile(src io.Reader, dst, fileName, unit string) error {
	cmd := exec.Command("touch", filepath.Join(dst, fileName))

	err := cmd.Run()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>blob content can now be filled with stdin.<commit_after>package glob

import (
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"sync"
)

var (
	once sync.Once
)

// Runner contains information related to creating blobs.
type Runner struct {
	Src    io.Reader
	Dest   string
	Amount int
	Unit   string
}

func NewRunner(src io.Reader, dst, unit string, amnt int) *Runner {
	r := new(Runner)

	r.Src = src
	r.Dest = dst
	r.Amount = amnt
	r.Unit = unit

	return r
}

func (r *Runner) Mk() error {
	srcContent, err := ioutil.ReadAll(r.Src)
	if err != nil {
		return err
	}

	for i := 1; i <= r.Amount; i++ {
		fileName := strconv.Itoa(i) + r.Unit

		err := CreateBlob(srcContent, r.Dest, fileName, r.Unit)
		if err != nil {
			return err
		}
	}

	return nil
}

func CreateBlob(content []byte, dst, fileName, unit string) error {
	fullBlobPath := filepath.Join(dst, fileName)

	// Create a new file.
	newFile, err := createBlobFile(fullBlobPath)
	if err != nil {
		return err
	}
	defer newFile.Close()

	// Fill it with junk.
	err = fillFile(newFile, content)
	if err != nil {
		return err
	}

	return nil
}

// should be the new create file, need to rename.
func createBlobFile(src string) (*os.File, error) {
	return os.Create(src)
}

func fillFile(file *os.File, content []byte) error {

	bytesWritten, err := file.Write(content)
	if err != nil {
		return err
	}

	log.Printf("%d bytes written to file.", bytesWritten)

	return err
}
<|endoftext|>


<commit_before>package message

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"strings"

	"lib/api"
	"lib/drawer"
	"lib/types"

	"github.com/bwmarrin/discordgo"
)

// Create :: called once for every message on any channel that the autenticated bot has access to.
func Create(s *discordgo.Session, m *discordgo.MessageCreate) {

	// prevent overflow
	// // //
	if len(m.Content) <= 2 {
		return
	}

	hasBeenInvoked := strings.HasPrefix(m.Content, "!") // check invocation
	authorIsHuman := (m.Author.ID != s.State.User.ID)   // check humanity of invoker

	if authorIsHuman && hasBeenInvoked {
		// separate ticker from invocation
		// // //
		splitCommand := strings.Split(m.Content, " ")
		candle := "minute"
		if len(splitCommand) > 1 {
			flag := splitCommand[len(splitCommand)-1]

			if flag == "-w" {
				candle = "hour"
				splitCommand = splitCommand[:len(splitCommand)-1]
			} else if flag == "-m" {
				candle = "day"
				splitCommand = splitCommand[:len(splitCommand)-1]
			} else if flag == "-3m" {
				candle = "3m"
				splitCommand = splitCommand[:len(splitCommand)-1]
			} else if flag == "-6m" {
				candle = "6m"
				splitCommand = splitCommand[:len(splitCommand)-1]
			}

		}

		// prevent overflow
		// // //
		if len(splitCommand) <= 2 {
			// get tickers
			// // //
			var base string
			coin := strings.ToUpper(splitCommand[0][1:])
			if len(splitCommand) == 2 {
				base = strings.ToUpper(splitCommand[1])
			} else {
				base = "USD"
			}

			// fetch data
			// // //
			var histoData types.HistoResponse
			var apiURL, timerange string
			if candle == "hour" {
				apiURL = api.BuildHistoHourURL(coin, base)
				timerange = "7D"
			} else if candle == "minute" {
				apiURL = api.BuildHistoMinuteURL(coin, base)
				timerange = "24H"
			} else if candle == "day" {
				apiURL = api.BuildHistoDayURL(coin, base)
				timerange = "1M"
			} else if candle == "3m" {
				apiURL = api.BuildHistoHourAllURL(coin, base)
				timerange = "3M"
			} else if candle == "6m" {
				apiURL = api.BuildHisto6mURL(coin, base)
				timerange = "6M"
			}

			resp, err := http.Get(apiURL)
			if err != nil {
				fmt.Println(err)
				return
			}
			defer resp.Body.Close()

			histoMinuteBody, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				fmt.Println(err)
				return
			}

			err = json.Unmarshal(histoMinuteBody, &histoData)
			if err != nil {
				fmt.Println(err)
				return
			}

			// format axes
			// // //
			axes := drawer.ParsePriceData(histoData.Data)

			// draw chart
			// // //
			buffer, err := drawer.DrawChart(axes)
			if err != nil {
				fmt.Println(err)
				return
			}

			// format closing price
			// // //
			var sym, changeSign string
			var lastPrice, firstPrice float64
			var color int

			switch base {
			case "usd":
			case "usdt":
			case "USDT":
			case "USD":
				sym = "$"
			case "btc":
			case "BTC":
				sym = "Ƀ"
			case "eth":
			case "ETH":
				sym = "Ξ"
			default:
				sym = ""
			}

			if len(axes.Y) > 0 {
				lastPrice = axes.Y[len(axes.Y)-1]
				firstPrice = axes.Y[0]
			} else {
				firstPrice = 0.0
				lastPrice = 0.0
			}

			if lastPrice >= firstPrice {
				changeSign = "+"
			} else {
				changeSign = ""
			}

			//	build message
			//	//
			delta := lastPrice - firstPrice
			pairing := fmt.Sprintf("%s/%s Price Chart (%s)", coin, base, timerange)
			deltaPct := fmt.Sprintf("%.2f%%", delta/firstPrice*100)

			if delta < 0 {
				color = 0xE94335
			} else {
				color = 0x5dff9f
			}

			embed := NewEmbed().
				SetAuthor(pairing, "https://cdn.discordapp.com/app-icons/359564584564293632/21fb4ad276ed1ddc3318ce0b1a663395.png").
				AddField("Last", fmt.Sprintf("%s%f", sym, lastPrice)).
				AddField("Hi", fmt.Sprintf("%s%f", sym, axes.Ymax)).
				AddField("Lo", fmt.Sprintf("%s%f", sym, axes.Ymin)).
				AddField("∆", fmt.Sprintf("`%s%s%f (%s%s)`", changeSign, sym, math.Abs(delta), changeSign, deltaPct)).
				InlineAllFields().
				SetColor(color).
				MessageEmbed

			s.ChannelMessageSendEmbed(m.ChannelID, embed)
			s.ChannelFileSendWithMessage(m.ChannelID, "", coin+base+".png", bytes.NewReader(buffer.Bytes()))

		}
	}
}
<commit_msg>add to options in message/Create.go<commit_after>package message

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math"
	"net/http"
	"strings"

	"lib/api"
	"lib/drawer"
	"lib/types"

	"github.com/bwmarrin/discordgo"
)

// Create :: called once for every message on any channel that the autenticated bot has access to.
func Create(s *discordgo.Session, m *discordgo.MessageCreate) {

	// prevent overflow
	// // //
	if len(m.Content) <= 2 {
		return
	}

	hasBeenInvoked := strings.HasPrefix(m.Content, "!") // check invocation
	authorIsHuman := (m.Author.ID != s.State.User.ID)   // check humanity of invoker

	if authorIsHuman && hasBeenInvoked {
		// separate ticker from invocation
		// // //
		splitCommand := strings.Split(m.Content, " ")
		candle := "minute"
		if len(splitCommand) > 1 {
			flag := splitCommand[len(splitCommand)-1]

			if flag == "-3d" {
				candle = "3d"
				splitCommand = splitCommand[:len(splitCommand)-1]
			} else if flag == "-w" {
				candle = "hour"
				splitCommand = splitCommand[:len(splitCommand)-1]
			} else if flag == "-m" {
				candle = "day"
				splitCommand = splitCommand[:len(splitCommand)-1]
			} else if flag == "-3m" {
				candle = "3m"
				splitCommand = splitCommand[:len(splitCommand)-1]
			} else if flag == "-6m" {
				candle = "6m"
				splitCommand = splitCommand[:len(splitCommand)-1]
			}

		}

		// prevent overflow
		// // //
		if len(splitCommand) <= 2 {
			// get tickers
			// // //
			var base string
			coin := strings.ToUpper(splitCommand[0][1:])
			if len(splitCommand) == 2 {
				base = strings.ToUpper(splitCommand[1])
			} else {
				base = "USD"
			}

			// fetch data
			// // //
			var histoData types.HistoResponse
			var apiURL, timerange string
			if candle == "3d" {
				apiURL = api.BuildThreeDayURL(coin, base)
				timerange = "3D"
			} else if candle == "hour" {
				apiURL = api.BuildHistoHourURL(coin, base)
				timerange = "7D"
			} else if candle == "minute" {
				apiURL = api.BuildHistoMinuteURL(coin, base)
				timerange = "24H"
			} else if candle == "day" {
				apiURL = api.BuildHistoDayURL(coin, base)
				timerange = "1M"
			} else if candle == "3m" {
				apiURL = api.BuildHistoHourAllURL(coin, base)
				timerange = "3M"
			} else if candle == "6m" {
				apiURL = api.BuildHisto6mURL(coin, base)
				timerange = "6M"
			}

			resp, err := http.Get(apiURL)
			if err != nil {
				fmt.Println(err)
				return
			}
			defer resp.Body.Close()

			histoMinuteBody, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				fmt.Println(err)
				return
			}

			err = json.Unmarshal(histoMinuteBody, &histoData)
			if err != nil {
				fmt.Println(err)
				return
			}

			// format axes
			// // //
			axes := drawer.ParsePriceData(histoData.Data)

			// draw chart
			// // //
			buffer, err := drawer.DrawChart(axes)
			if err != nil {
				fmt.Println(err)
				return
			}

			// format closing price
			// // //
			var sym, changeSign string
			var lastPrice, firstPrice float64
			var color int

			switch base {
			case "usd":
			case "usdt":
			case "USDT":
			case "USD":
				sym = "$"
			case "btc":
			case "BTC":
				sym = "Ƀ"
			case "eth":
			case "ETH":
				sym = "Ξ"
			default:
				sym = ""
			}

			if len(axes.Y) > 0 {
				lastPrice = axes.Y[len(axes.Y)-1]
				firstPrice = axes.Y[0]
			} else {
				firstPrice = 0.0
				lastPrice = 0.0
			}

			if lastPrice >= firstPrice {
				changeSign = "+"
			} else {
				changeSign = ""
			}

			//	build message
			//	//
			delta := lastPrice - firstPrice
			pairing := fmt.Sprintf("%s/%s Price Chart (%s)", coin, base, timerange)
			deltaPct := fmt.Sprintf("%.2f%%", delta/firstPrice*100)

			if delta < 0 {
				color = 0xE94335
			} else {
				color = 0x5dff9f
			}

			embed := NewEmbed().
				SetAuthor(pairing, "https://cdn.discordapp.com/app-icons/359564584564293632/21fb4ad276ed1ddc3318ce0b1a663395.png").
				AddField("Last", fmt.Sprintf("%s%f", sym, lastPrice)).
				AddField("Hi", fmt.Sprintf("%s%f", sym, axes.Ymax)).
				AddField("Lo", fmt.Sprintf("%s%f", sym, axes.Ymin)).
				AddField("∆", fmt.Sprintf("`%s%s%f (%s%s)`", changeSign, sym, math.Abs(delta), changeSign, deltaPct)).
				InlineAllFields().
				SetColor(color).
				MessageEmbed

			s.ChannelMessageSendEmbed(m.ChannelID, embed)
			s.ChannelFileSendWithMessage(m.ChannelID, "", coin+base+".png", bytes.NewReader(buffer.Bytes()))

		}
	}
}
<|endoftext|>


<commit_before>package gorp

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

// The Dialect interface encapsulates behaviors that differ across
// SQL databases.  At present the Dialect is only used by CreateTables()
// but this could change in the future
type Dialect interface {

	// ToSqlType returns the SQL column type to use when creating a
	// table of the given Go Type.  maxsize can be used to switch based on
	// size.  For example, in MySQL []byte could map to BLOB, MEDIUMBLOB,
	// or LONGBLOB depending on the maxsize
	ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string

	// string to append to primary key column definitions
	AutoIncrStr() string

	AutoIncrBindValue() string

	AutoIncrInsertSuffix(col *ColumnMap) string

	// string to append to "create table" statement for vendor specific
	// table attributes
	CreateTableSuffix() string

	// string to truncate tables
	TruncateClause() string

	// bind variable string to use when forming SQL statements
	// in many dbs it is "?", but Postgres appears to use $1
	//
	// i is a zero based index of the bind variable in this statement
	//
	BindVar(i int) string

	// Handles quoting of a field name to ensure that it doesn't raise any
	// SQL parsing exceptions by using a reserved word as a field name.
	QuoteField(field string) string

	// Handles building up of a schema.database string that is compatible with
	// the given dialect
	//
	// schema - The schema that <table> lives in
	// table - The table name
	QuotedTableForQuery(schema string, table string) string
}

// IntegerAutoIncrInserter is implemented by dialects that can perform
// inserts with automatically incremented integer primary keys.  If
// the dialect can handle automatic assignment of more than just
// integers, see TargetedAutoIncrInserter.
type IntegerAutoIncrInserter interface {
	InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error)
}

// TargetedAutoIncrInserter is implemented by dialects that can
// perform automatic assignment of any primary key type (i.e. strings
// for uuids, integers for serials, etc).
type TargetedAutoIncrInserter interface {
	// InsertAutoIncrToTarget runs an insert operation and assigns the
	// automatically generated primary key directly to the passed in
	// target.  The target should be a pointer to the primary key
	// field of the value being inserted.
	InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error
}

func standardInsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
	res, err := exec.Exec(insertSql, params...)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

///////////////////////////////////////////////////////
// sqlite3 //
/////////////

type SqliteDialect struct {
	suffix string
}

func (d SqliteDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
	switch val.Kind() {
	case reflect.Ptr:
		return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
	case reflect.Bool:
		return "integer"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return "integer"
	case reflect.Float64, reflect.Float32:
		return "real"
	case reflect.Slice:
		if val.Elem().Kind() == reflect.Uint8 {
			return "blob"
		}
	}

	switch val.Name() {
	case "NullInt64":
		return "integer"
	case "NullFloat64":
		return "real"
	case "NullBool":
		return "integer"
	case "Time":
		return "datetime"
	}

	if maxsize < 1 {
		maxsize = 255
	}
	return fmt.Sprintf("varchar(%d)", maxsize)
}

// Returns autoincrement
func (d SqliteDialect) AutoIncrStr() string {
	return "autoincrement"
}

func (d SqliteDialect) AutoIncrBindValue() string {
	return "null"
}

func (d SqliteDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
	return ""
}

// Returns suffix
func (d SqliteDialect) CreateTableSuffix() string {
	return d.suffix
}

// With sqlite, there technically isn't a TRUNCATE statement,
// but a DELETE FROM uses a truncate optimization:
// http://www.sqlite.org/lang_delete.html
func (d SqliteDialect) TruncateClause() string {
	return "delete from"
}

// Returns "?"
func (d SqliteDialect) BindVar(i int) string {
	return "?"
}

func (d SqliteDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
	return standardInsertAutoIncr(exec, insertSql, params...)
}

func (d SqliteDialect) QuoteField(f string) string {
	return `"` + f + `"`
}

// sqlite does not have schemas like PostgreSQL does, so just escape it like normal
func (d SqliteDialect) QuotedTableForQuery(schema string, table string) string {
	return d.QuoteField(table)
}

///////////////////////////////////////////////////////
// PostgreSQL //
////////////////

type PostgresDialect struct {
	suffix string
}

func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
	switch val.Kind() {
	case reflect.Ptr:
		return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
	case reflect.Bool:
		return "boolean"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		if isAutoIncr {
			return "serial"
		}
		return "integer"
	case reflect.Int64, reflect.Uint64:
		if isAutoIncr {
			return "bigserial"
		}
		return "bigint"
	case reflect.Float64:
		return "double precision"
	case reflect.Float32:
		return "real"
	case reflect.Slice:
		if val.Elem().Kind() == reflect.Uint8 {
			return "bytea"
		}
	}

	switch val.Name() {
	case "NullInt64":
		return "bigint"
	case "NullFloat64":
		return "double precision"
	case "NullBool":
		return "boolean"
	case "Time":
		return "timestamp with time zone"
	}

	if maxsize > 0 {
		return fmt.Sprintf("varchar(%d)", maxsize)
	} else {
		return "text"
	}

}

// Returns empty string
func (d PostgresDialect) AutoIncrStr() string {
	return ""
}

func (d PostgresDialect) AutoIncrBindValue() string {
	return "default"
}

func (d PostgresDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
	return " returning " + col.ColumnName
}

// Returns suffix
func (d PostgresDialect) CreateTableSuffix() string {
	return d.suffix
}

func (d PostgresDialect) TruncateClause() string {
	return "truncate"
}

// Returns "$(i+1)"
func (d PostgresDialect) BindVar(i int) string {
	return fmt.Sprintf("$%d", i+1)
}

func (d PostgresDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error {
	rows, err := exec.query(insertSql, params...)
	if err != nil {
		return err
	}
	defer rows.Close()

	if rows.Next() {
		err := rows.Scan(target)
		return err
	}

	return errors.New("No serial value returned for insert: " + insertSql + " Encountered error: " + rows.Err().Error())
}

func (d PostgresDialect) QuoteField(f string) string {
	return `"` + strings.ToLower(f) + `"`
}

func (d PostgresDialect) QuotedTableForQuery(schema string, table string) string {
	if strings.TrimSpace(schema) == "" {
		return d.QuoteField(table)
	}

	return schema + "." + d.QuoteField(table)
}

///////////////////////////////////////////////////////
// MySQL //
///////////

// Implementation of Dialect for MySQL databases.
type MySQLDialect struct {

	// Engine is the storage engine to use "InnoDB" vs "MyISAM" for example
	Engine string

	// Encoding is the character encoding to use for created tables
	Encoding string
}

func (m MySQLDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
	switch val.Kind() {
	case reflect.Ptr:
		return m.ToSqlType(val.Elem(), maxsize, isAutoIncr)
	case reflect.Bool:
		return "boolean"
	case reflect.Int8:
		return "tinyint"
	case reflect.Uint8:
		return "tinyint unsigned"
	case reflect.Int16:
		return "smallint"
	case reflect.Uint16:
		return "smallint unsigned"
	case reflect.Int, reflect.Int32:
		return "int"
	case reflect.Uint, reflect.Uint32:
		return "int unsigned"
	case reflect.Int64:
		return "bigint"
	case reflect.Uint64:
		return "bigint unsigned"
	case reflect.Float64, reflect.Float32:
		return "double"
	case reflect.Slice:
		if val.Elem().Kind() == reflect.Uint8 {
			return "mediumblob"
		}
	}

	switch val.Name() {
	case "NullInt64":
		return "bigint"
	case "NullFloat64":
		return "double"
	case "NullBool":
		return "tinyint"
	case "Time":
		return "datetime"
	}

	if maxsize < 1 {
		maxsize = 255
	}
	return fmt.Sprintf("varchar(%d)", maxsize)
}

// Returns auto_increment
func (m MySQLDialect) AutoIncrStr() string {
	return "auto_increment"
}

func (m MySQLDialect) AutoIncrBindValue() string {
	return "null"
}

func (m MySQLDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
	return ""
}

// Returns engine=%s charset=%s  based on values stored on struct
func (m MySQLDialect) CreateTableSuffix() string {
	if m.Engine == "" || m.Encoding == "" {
		msg := "gorp - undefined"

		if m.Engine == "" {
			msg += " MySQLDialect.Engine"
		}
		if m.Engine == "" && m.Encoding == "" {
			msg += ","
		}
		if m.Encoding == "" {
			msg += " MySQLDialect.Encoding"
		}
		msg += ". Check that your MySQLDialect was correctly initialized when declared."
		panic(msg)
	}

	return fmt.Sprintf(" engine=%s charset=%s", m.Engine, m.Encoding)
}

func (m MySQLDialect) TruncateClause() string {
	return "truncate"
}

// Returns "?"
func (m MySQLDialect) BindVar(i int) string {
	return "?"
}

func (m MySQLDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
	return standardInsertAutoIncr(exec, insertSql, params...)
}

func (d MySQLDialect) QuoteField(f string) string {
	return "`" + f + "`"
}

// MySQL does not have schemas like PostgreSQL does, so just escape it like normal
func (d MySQLDialect) QuotedTableForQuery(schema string, table string) string {
	return d.QuoteField(table)
}
<commit_msg>MySQL certainly does have schemas<commit_after>package gorp

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

// The Dialect interface encapsulates behaviors that differ across
// SQL databases.  At present the Dialect is only used by CreateTables()
// but this could change in the future
type Dialect interface {

	// ToSqlType returns the SQL column type to use when creating a
	// table of the given Go Type.  maxsize can be used to switch based on
	// size.  For example, in MySQL []byte could map to BLOB, MEDIUMBLOB,
	// or LONGBLOB depending on the maxsize
	ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string

	// string to append to primary key column definitions
	AutoIncrStr() string

	AutoIncrBindValue() string

	AutoIncrInsertSuffix(col *ColumnMap) string

	// string to append to "create table" statement for vendor specific
	// table attributes
	CreateTableSuffix() string

	// string to truncate tables
	TruncateClause() string

	// bind variable string to use when forming SQL statements
	// in many dbs it is "?", but Postgres appears to use $1
	//
	// i is a zero based index of the bind variable in this statement
	//
	BindVar(i int) string

	// Handles quoting of a field name to ensure that it doesn't raise any
	// SQL parsing exceptions by using a reserved word as a field name.
	QuoteField(field string) string

	// Handles building up of a schema.database string that is compatible with
	// the given dialect
	//
	// schema - The schema that <table> lives in
	// table - The table name
	QuotedTableForQuery(schema string, table string) string
}

// IntegerAutoIncrInserter is implemented by dialects that can perform
// inserts with automatically incremented integer primary keys.  If
// the dialect can handle automatic assignment of more than just
// integers, see TargetedAutoIncrInserter.
type IntegerAutoIncrInserter interface {
	InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error)
}

// TargetedAutoIncrInserter is implemented by dialects that can
// perform automatic assignment of any primary key type (i.e. strings
// for uuids, integers for serials, etc).
type TargetedAutoIncrInserter interface {
	// InsertAutoIncrToTarget runs an insert operation and assigns the
	// automatically generated primary key directly to the passed in
	// target.  The target should be a pointer to the primary key
	// field of the value being inserted.
	InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error
}

func standardInsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
	res, err := exec.Exec(insertSql, params...)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

///////////////////////////////////////////////////////
// sqlite3 //
/////////////

type SqliteDialect struct {
	suffix string
}

func (d SqliteDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
	switch val.Kind() {
	case reflect.Ptr:
		return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
	case reflect.Bool:
		return "integer"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return "integer"
	case reflect.Float64, reflect.Float32:
		return "real"
	case reflect.Slice:
		if val.Elem().Kind() == reflect.Uint8 {
			return "blob"
		}
	}

	switch val.Name() {
	case "NullInt64":
		return "integer"
	case "NullFloat64":
		return "real"
	case "NullBool":
		return "integer"
	case "Time":
		return "datetime"
	}

	if maxsize < 1 {
		maxsize = 255
	}
	return fmt.Sprintf("varchar(%d)", maxsize)
}

// Returns autoincrement
func (d SqliteDialect) AutoIncrStr() string {
	return "autoincrement"
}

func (d SqliteDialect) AutoIncrBindValue() string {
	return "null"
}

func (d SqliteDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
	return ""
}

// Returns suffix
func (d SqliteDialect) CreateTableSuffix() string {
	return d.suffix
}

// With sqlite, there technically isn't a TRUNCATE statement,
// but a DELETE FROM uses a truncate optimization:
// http://www.sqlite.org/lang_delete.html
func (d SqliteDialect) TruncateClause() string {
	return "delete from"
}

// Returns "?"
func (d SqliteDialect) BindVar(i int) string {
	return "?"
}

func (d SqliteDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
	return standardInsertAutoIncr(exec, insertSql, params...)
}

func (d SqliteDialect) QuoteField(f string) string {
	return `"` + f + `"`
}

// sqlite does not have schemas like PostgreSQL does, so just escape it like normal
func (d SqliteDialect) QuotedTableForQuery(schema string, table string) string {
	return d.QuoteField(table)
}

///////////////////////////////////////////////////////
// PostgreSQL //
////////////////

type PostgresDialect struct {
	suffix string
}

func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
	switch val.Kind() {
	case reflect.Ptr:
		return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
	case reflect.Bool:
		return "boolean"
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		if isAutoIncr {
			return "serial"
		}
		return "integer"
	case reflect.Int64, reflect.Uint64:
		if isAutoIncr {
			return "bigserial"
		}
		return "bigint"
	case reflect.Float64:
		return "double precision"
	case reflect.Float32:
		return "real"
	case reflect.Slice:
		if val.Elem().Kind() == reflect.Uint8 {
			return "bytea"
		}
	}

	switch val.Name() {
	case "NullInt64":
		return "bigint"
	case "NullFloat64":
		return "double precision"
	case "NullBool":
		return "boolean"
	case "Time":
		return "timestamp with time zone"
	}

	if maxsize > 0 {
		return fmt.Sprintf("varchar(%d)", maxsize)
	} else {
		return "text"
	}

}

// Returns empty string
func (d PostgresDialect) AutoIncrStr() string {
	return ""
}

func (d PostgresDialect) AutoIncrBindValue() string {
	return "default"
}

func (d PostgresDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
	return " returning " + col.ColumnName
}

// Returns suffix
func (d PostgresDialect) CreateTableSuffix() string {
	return d.suffix
}

func (d PostgresDialect) TruncateClause() string {
	return "truncate"
}

// Returns "$(i+1)"
func (d PostgresDialect) BindVar(i int) string {
	return fmt.Sprintf("$%d", i+1)
}

func (d PostgresDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error {
	rows, err := exec.query(insertSql, params...)
	if err != nil {
		return err
	}
	defer rows.Close()

	if rows.Next() {
		err := rows.Scan(target)
		return err
	}

	return errors.New("No serial value returned for insert: " + insertSql + " Encountered error: " + rows.Err().Error())
}

func (d PostgresDialect) QuoteField(f string) string {
	return `"` + strings.ToLower(f) + `"`
}

func (d PostgresDialect) QuotedTableForQuery(schema string, table string) string {
	if strings.TrimSpace(schema) == "" {
		return d.QuoteField(table)
	}

	return schema + "." + d.QuoteField(table)
}

///////////////////////////////////////////////////////
// MySQL //
///////////

// Implementation of Dialect for MySQL databases.
type MySQLDialect struct {

	// Engine is the storage engine to use "InnoDB" vs "MyISAM" for example
	Engine string

	// Encoding is the character encoding to use for created tables
	Encoding string
}

func (m MySQLDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
	switch val.Kind() {
	case reflect.Ptr:
		return m.ToSqlType(val.Elem(), maxsize, isAutoIncr)
	case reflect.Bool:
		return "boolean"
	case reflect.Int8:
		return "tinyint"
	case reflect.Uint8:
		return "tinyint unsigned"
	case reflect.Int16:
		return "smallint"
	case reflect.Uint16:
		return "smallint unsigned"
	case reflect.Int, reflect.Int32:
		return "int"
	case reflect.Uint, reflect.Uint32:
		return "int unsigned"
	case reflect.Int64:
		return "bigint"
	case reflect.Uint64:
		return "bigint unsigned"
	case reflect.Float64, reflect.Float32:
		return "double"
	case reflect.Slice:
		if val.Elem().Kind() == reflect.Uint8 {
			return "mediumblob"
		}
	}

	switch val.Name() {
	case "NullInt64":
		return "bigint"
	case "NullFloat64":
		return "double"
	case "NullBool":
		return "tinyint"
	case "Time":
		return "datetime"
	}

	if maxsize < 1 {
		maxsize = 255
	}
	return fmt.Sprintf("varchar(%d)", maxsize)
}

// Returns auto_increment
func (m MySQLDialect) AutoIncrStr() string {
	return "auto_increment"
}

func (m MySQLDialect) AutoIncrBindValue() string {
	return "null"
}

func (m MySQLDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
	return ""
}

// Returns engine=%s charset=%s  based on values stored on struct
func (m MySQLDialect) CreateTableSuffix() string {
	if m.Engine == "" || m.Encoding == "" {
		msg := "gorp - undefined"

		if m.Engine == "" {
			msg += " MySQLDialect.Engine"
		}
		if m.Engine == "" && m.Encoding == "" {
			msg += ","
		}
		if m.Encoding == "" {
			msg += " MySQLDialect.Encoding"
		}
		msg += ". Check that your MySQLDialect was correctly initialized when declared."
		panic(msg)
	}

	return fmt.Sprintf(" engine=%s charset=%s", m.Engine, m.Encoding)
}

func (m MySQLDialect) TruncateClause() string {
	return "truncate"
}

// Returns "?"
func (m MySQLDialect) BindVar(i int) string {
	return "?"
}

func (m MySQLDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
	return standardInsertAutoIncr(exec, insertSql, params...)
}

func (d MySQLDialect) QuoteField(f string) string {
	return "`" + f + "`"
}

func (d MySQLDialect) QuotedTableForQuery(schema string, table string) string {
	if strings.TrimSpace(schema) == "" {
		return d.QuoteField(table)
	}

	return schema + "." + d.QuoteField(table)
}
<|endoftext|>