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

// plt contains functions for plotting
package plt

import (
	"bytes"
	"os"
	"os/exec"

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

var bb bytes.Buffer // the buffer
var ea bytes.Buffer // extra artists

func init() {
	Reset()
}

func Reset() {
	bb.Reset()
	ea.Reset()
	io.Ff(&bb, "from gosl import *\n")
	io.Ff(&ea, "ea = []\n")
}

func SetXlog() {
	io.Ff(&bb, "SetXlog()\n")
}

func SetYlog() {
	io.Ff(&bb, "SetYlog()\n")
}

func SetXnticks(num int) {
	io.Ff(&bb, "SetXnticks(%d)\n", num)
}

func SetYnticks(num int) {
	io.Ff(&bb, "SetYnticks(%d)\n", num)
}

func SetScientific(axis string, min_order, max_order int) {
	io.Ff(&bb, "SetScientificFmt(axis='%s', min_order=%d, max_order=%d)\n", axis, min_order, max_order)
}

func Arrow(xi, yi, xf, yf float64, args string) {
	cmd := io.Sf("Arrow(%g,%g, %g,%g", xi, yi, xf, yf)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func AxHline(y float64, args string) {
	cmd := io.Sf("axhline(%g", y)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func AxVline(x float64, args string) {
	cmd := io.Sf("axvline(%g", x)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func HideTRframe() {
	io.Ff(&bb, "HideFrameLines()\n")
}

func Annotate(x, y float64, txt string, args string) {
	cmd := io.Sf("annotate(%s, xy=(%g,%g)", txt, x, y)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func AnnotateXlabels(x float64, txt string, args string) {
	cmd := io.Sf("AnnotateXlabels(%g, %s", x, txt)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func SupTitle(txt, args string) {
	n := bb.Len()
	if len(args) > 0 {
		io.Ff(&bb, "st%d = suptitle('%s',%s)\n", n, txt, args)
	} else {
		io.Ff(&bb, "st%d = suptitle('%s')\n", n, txt)
	}
	io.Ff(&bb, "ea.append(st%d)\n", n)
}

func Title(txt, args string) {
	if len(args) > 0 {
		io.Ff(&bb, "title('%s',%s)\n", txt, args)
	} else {
		io.Ff(&bb, "title('%s')\n", txt)
	}
}

func Text(x, y float64, txt, args string) {
	if len(args) > 0 {
		io.Ff(&bb, "text(%g,%g,'%s',%s)\n", x, y, txt, args)
	} else {
		io.Ff(&bb, "text(%g,%g,'%s')\n", x, y, txt)
	}
}

func Cross() {
	io.Ff(&bb, "Cross()\n")
}

func SplotGap(w, h float64) {
	io.Ff(&bb, "SplotGap(%g, %g)\n", w, h)
}

func Subplot(i, j, k int) {
	io.Ff(&bb, "subplot(%d,%d,%d)\n", i, j, k)
}

func SubplotI(I []int) {
	if len(I) != 3 {
		return
	}
	io.Ff(&bb, "subplot(%d,%d,%d)\n", I[0], I[1], I[2])
}

func SetHspace(hspace float64) {
	io.Ff(&bb, "subplots_adjust(hspace=%g)\n", hspace)
}

func SetVspace(vspace float64) {
	io.Ff(&bb, "subplots_adjust(vspace=%g)\n", vspace)
}

func AxisXmin(xmin float64) {
	io.Ff(&bb, "axis([%g, axis()[1], axis()[2], axis()[3]])\n", xmin)
}

func AxisXmax(xmax float64) {
	io.Ff(&bb, "axis([axis()[0], %g, axis()[2], axis()[3]])\n", xmax)
}

func AxisYmin(ymin float64) {
	io.Ff(&bb, "axis([axis()[0], axis()[1], %g, axis()[3]])\n", ymin)
}

func AxisYmax(ymax float64) {
	io.Ff(&bb, "axis([axis()[0], axis()[1], axis()[2], %g])\n", ymax)
}

func AxisXrange(xmin, xmax float64) {
	io.Ff(&bb, "axis([%g, %g, axis()[2], axis()[3]])\n", xmin, xmax)
}

func AxisYrange(ymin, ymax float64) {
	io.Ff(&bb, "axis([axis()[0], axis()[1], %g, %g])\n", ymin, ymax)
}

func AxisRange(xmin, xmax, ymin, ymax float64) {
	io.Ff(&bb, "axis([%g, %g, %g, %g])\n", xmin, xmax, ymin, ymax)
}

func AxisLims(lims []float64) {
	io.Ff(&bb, "axis([%g, %g, %g, %g])\n", lims[0], lims[1], lims[2], lims[3])
}

func Plot(x, y []float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	Gen2Arrays(&bb, sx, sy, x, y)
	if len(args) > 0 {
		io.Ff(&bb, "plot(%s,%s,%s)\n", sx, sy, args)
	} else {
		io.Ff(&bb, "plot(%s,%s)\n", sx, sy)
	}
}

func PlotOne(x, y float64, args string) {
	if len(args) > 0 {
		io.Ff(&bb, "plot(%23.15e,%23.15e,%s)\n", x, y, args)
	} else {
		io.Ff(&bb, "plot(%23.15e,%23.15e)\n", x, y)
	}
}

func Contour(x, y, z [][]float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	sz := io.Sf("z%d", n)
	GenMat(&bb, sx, x)
	GenMat(&bb, sy, y)
	GenMat(&bb, sz, z)
	cmd := io.Sf("Contour(%s,%s,%s", sx, sy, sz)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func ContourSimple(x, y, z [][]float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	sz := io.Sf("z%d", n)
	GenMat(&bb, sx, x)
	GenMat(&bb, sy, y)
	GenMat(&bb, sz, z)
	cmd := io.Sf("contour(%s,%s,%s", sx, sy, sz)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func Quiver(x, y, gx, gy [][]float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	sgx := io.Sf("gx%d", n)
	sgy := io.Sf("gy%d", n)
	GenMat(&bb, sx, x)
	GenMat(&bb, sy, y)
	GenMat(&bb, sgx, gx)
	GenMat(&bb, sgy, gy)
	cmd := io.Sf("quiver(%s,%s,%s,%s", sx, sy, sgx, sgy)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func Grid(args string) {
	io.Ff(&bb, "grid(%s)\n", args)
}

func Gll(xl, yl string, args string) {
	n := bb.Len()
	cmd := io.Sf("lg%d = Gll(r'%s',r'%s'", n, xl, yl)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\nea.append(lg%d)\n", cmd, n)
}

func Clf() {
	io.Ff(&bb, "clf()\n")
}

func SetFontSize(args string) {
	io.Ff(&bb, "SetFontSize(%s)\n", args)
}

func SetForEps(prop, widpt float64) {
	io.Ff(&bb, "SetForEps(%g,%g)\n", prop, widpt)
}

func SetForPng(prop, widpt float64, dpi int) {
	io.Ff(&bb, "SetForPng(%g,%g,%d)\n", prop, widpt, dpi)
}

func Save(fname string) {
	var buf bytes.Buffer
	io.Ff(&buf, "Save('%s', ea=ea, verbose=1)\n", fname)
	run(&buf)
}

func SaveD(dirout, fname string) {
	os.MkdirAll(dirout, 0777)
	var buf bytes.Buffer
	io.Ff(&buf, "Save('%s/%s', ea=ea, verbose=1)\n", dirout, fname)
	run(&buf)
}

func SetAxis(xmin, xmax, ymin, ymax float64) {
	io.Ff(&bb, "axis([%g, %g, %g, %g])\n", xmin, xmax, ymin, ymax)
}

func AxisOff() {
	io.Ff(&bb, "axis('off')\n")
}

func Equal() {
	io.Ff(&bb, "axis('equal')\n")
}

func Show() {
	io.Ff(&bb, "show()\n")
	run(nil)
}

func Circle(xc, yc, r float64, args string) {
	cmd := io.Sf("Circle(%g,%g,%g", xc, yc, r)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func run(extra *bytes.Buffer) {
	fn := "/tmp/gosl_mplotlib_go.py"
	if extra != nil {
		io.WriteFile(fn, &ea, &bb, extra)
	} else {
		io.WriteFile(fn, &ea, &bb)
	}
	cmd := exec.Command("python", fn)
	var out, serr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &serr
	err := cmd.Run()
	if err != nil {
		chk.Panic(_mplotlib_err1, serr.String())
	}
	io.Pf("%s", out.String())
}

// Auxiliary functions
func GenMat(buf *bytes.Buffer, name string, a [][]float64) {
	io.Ff(buf, "%s=array([", name)
	for i, _ := range a {
		io.Ff(buf, "[")
		for j, _ := range a[i] {
			io.Ff(buf, "%g,", a[i][j])
		}
		io.Ff(buf, "],")
	}
	io.Ff(buf, "],dtype=float)\n")
}

// GenArray generates the NumPy text in 'b' corresponding to an array of float point numbers
func GenArray(b *bytes.Buffer, name string, u []float64) {
	io.Ff(b, "%s=array([", name)
	for i, _ := range u {
		io.Ff(b, "%g,", u[i])
	}
	io.Ff(b, "],dtype=float)\n")
}

// Gen2Arrays generates the NumPy text in 'b' corresponding to 2 arrays of float point numbers
func Gen2Arrays(buf *bytes.Buffer, nameA, nameB string, a, b []float64) {
	GenArray(buf, nameA, a)
	GenArray(buf, nameB, b)
}

var (
	_mplotlib_err1 = "mplotlib.go: python failed:\n%v"
)
<commit_msg>histogram added to plt<commit_after>// Copyright 2015 Dorival Pedroso and Raul Durand. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// plt contains functions for plotting
package plt

import (
	"bytes"
	"os"
	"os/exec"

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

var bb bytes.Buffer // the buffer
var ea bytes.Buffer // extra artists

func init() {
	Reset()
}

func Reset() {
	bb.Reset()
	ea.Reset()
	io.Ff(&bb, "from gosl import *\n")
	io.Ff(&ea, "ea = []\n")
}

func SetXlog() {
	io.Ff(&bb, "SetXlog()\n")
}

func SetYlog() {
	io.Ff(&bb, "SetYlog()\n")
}

func SetXnticks(num int) {
	io.Ff(&bb, "SetXnticks(%d)\n", num)
}

func SetYnticks(num int) {
	io.Ff(&bb, "SetYnticks(%d)\n", num)
}

func SetScientific(axis string, min_order, max_order int) {
	io.Ff(&bb, "SetScientificFmt(axis='%s', min_order=%d, max_order=%d)\n", axis, min_order, max_order)
}

func Arrow(xi, yi, xf, yf float64, args string) {
	cmd := io.Sf("Arrow(%g,%g, %g,%g", xi, yi, xf, yf)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func AxHline(y float64, args string) {
	cmd := io.Sf("axhline(%g", y)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func AxVline(x float64, args string) {
	cmd := io.Sf("axvline(%g", x)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func HideTRframe() {
	io.Ff(&bb, "HideFrameLines()\n")
}

func Annotate(x, y float64, txt string, args string) {
	cmd := io.Sf("annotate(%s, xy=(%g,%g)", txt, x, y)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func AnnotateXlabels(x float64, txt string, args string) {
	cmd := io.Sf("AnnotateXlabels(%g, %s", x, txt)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func SupTitle(txt, args string) {
	n := bb.Len()
	if len(args) > 0 {
		io.Ff(&bb, "st%d = suptitle('%s',%s)\n", n, txt, args)
	} else {
		io.Ff(&bb, "st%d = suptitle('%s')\n", n, txt)
	}
	io.Ff(&bb, "ea.append(st%d)\n", n)
}

func Title(txt, args string) {
	if len(args) > 0 {
		io.Ff(&bb, "title('%s',%s)\n", txt, args)
	} else {
		io.Ff(&bb, "title('%s')\n", txt)
	}
}

func Text(x, y float64, txt, args string) {
	if len(args) > 0 {
		io.Ff(&bb, "text(%g,%g,'%s',%s)\n", x, y, txt, args)
	} else {
		io.Ff(&bb, "text(%g,%g,'%s')\n", x, y, txt)
	}
}

func Cross() {
	io.Ff(&bb, "Cross()\n")
}

func SplotGap(w, h float64) {
	io.Ff(&bb, "SplotGap(%g, %g)\n", w, h)
}

func Subplot(i, j, k int) {
	io.Ff(&bb, "subplot(%d,%d,%d)\n", i, j, k)
}

func SubplotI(I []int) {
	if len(I) != 3 {
		return
	}
	io.Ff(&bb, "subplot(%d,%d,%d)\n", I[0], I[1], I[2])
}

func SetHspace(hspace float64) {
	io.Ff(&bb, "subplots_adjust(hspace=%g)\n", hspace)
}

func SetVspace(vspace float64) {
	io.Ff(&bb, "subplots_adjust(vspace=%g)\n", vspace)
}

func AxisXmin(xmin float64) {
	io.Ff(&bb, "axis([%g, axis()[1], axis()[2], axis()[3]])\n", xmin)
}

func AxisXmax(xmax float64) {
	io.Ff(&bb, "axis([axis()[0], %g, axis()[2], axis()[3]])\n", xmax)
}

func AxisYmin(ymin float64) {
	io.Ff(&bb, "axis([axis()[0], axis()[1], %g, axis()[3]])\n", ymin)
}

func AxisYmax(ymax float64) {
	io.Ff(&bb, "axis([axis()[0], axis()[1], axis()[2], %g])\n", ymax)
}

func AxisXrange(xmin, xmax float64) {
	io.Ff(&bb, "axis([%g, %g, axis()[2], axis()[3]])\n", xmin, xmax)
}

func AxisYrange(ymin, ymax float64) {
	io.Ff(&bb, "axis([axis()[0], axis()[1], %g, %g])\n", ymin, ymax)
}

func AxisRange(xmin, xmax, ymin, ymax float64) {
	io.Ff(&bb, "axis([%g, %g, %g, %g])\n", xmin, xmax, ymin, ymax)
}

func AxisLims(lims []float64) {
	io.Ff(&bb, "axis([%g, %g, %g, %g])\n", lims[0], lims[1], lims[2], lims[3])
}

func Plot(x, y []float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	Gen2Arrays(&bb, sx, sy, x, y)
	if len(args) > 0 {
		io.Ff(&bb, "plot(%s,%s,%s)\n", sx, sy, args)
	} else {
		io.Ff(&bb, "plot(%s,%s)\n", sx, sy)
	}
}

func PlotOne(x, y float64, args string) {
	if len(args) > 0 {
		io.Ff(&bb, "plot(%23.15e,%23.15e,%s)\n", x, y, args)
	} else {
		io.Ff(&bb, "plot(%23.15e,%23.15e)\n", x, y)
	}
}

func Hist(x [][]float64, labels []string, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	GenList(&bb, sx, x)
	GenStrArray(&bb, sy, labels)
	if len(args) > 0 {
		io.Ff(&bb, "hist(%s,label=%s,%s)\n", sx, sy, args)
	} else {
		io.Ff(&bb, "hist(%s,label=%s)\n", sx, sy)
	}
}

func Contour(x, y, z [][]float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	sz := io.Sf("z%d", n)
	GenMat(&bb, sx, x)
	GenMat(&bb, sy, y)
	GenMat(&bb, sz, z)
	cmd := io.Sf("Contour(%s,%s,%s", sx, sy, sz)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func ContourSimple(x, y, z [][]float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	sz := io.Sf("z%d", n)
	GenMat(&bb, sx, x)
	GenMat(&bb, sy, y)
	GenMat(&bb, sz, z)
	cmd := io.Sf("contour(%s,%s,%s", sx, sy, sz)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func Quiver(x, y, gx, gy [][]float64, args string) {
	n := bb.Len()
	sx := io.Sf("x%d", n)
	sy := io.Sf("y%d", n)
	sgx := io.Sf("gx%d", n)
	sgy := io.Sf("gy%d", n)
	GenMat(&bb, sx, x)
	GenMat(&bb, sy, y)
	GenMat(&bb, sgx, gx)
	GenMat(&bb, sgy, gy)
	cmd := io.Sf("quiver(%s,%s,%s,%s", sx, sy, sgx, sgy)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func Grid(args string) {
	io.Ff(&bb, "grid(%s)\n", args)
}

func Gll(xl, yl string, args string) {
	n := bb.Len()
	cmd := io.Sf("lg%d = Gll(r'%s',r'%s'", n, xl, yl)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\nea.append(lg%d)\n", cmd, n)
}

func Clf() {
	io.Ff(&bb, "clf()\n")
}

func SetFontSize(args string) {
	io.Ff(&bb, "SetFontSize(%s)\n", args)
}

func SetForEps(prop, widpt float64) {
	io.Ff(&bb, "SetForEps(%g,%g)\n", prop, widpt)
}

func SetForPng(prop, widpt float64, dpi int) {
	io.Ff(&bb, "SetForPng(%g,%g,%d)\n", prop, widpt, dpi)
}

func Save(fname string) {
	var buf bytes.Buffer
	io.Ff(&buf, "Save('%s', ea=ea, verbose=1)\n", fname)
	run(&buf)
}

func SaveD(dirout, fname string) {
	os.MkdirAll(dirout, 0777)
	var buf bytes.Buffer
	io.Ff(&buf, "Save('%s/%s', ea=ea, verbose=1)\n", dirout, fname)
	run(&buf)
}

func SetAxis(xmin, xmax, ymin, ymax float64) {
	io.Ff(&bb, "axis([%g, %g, %g, %g])\n", xmin, xmax, ymin, ymax)
}

func AxisOff() {
	io.Ff(&bb, "axis('off')\n")
}

func Equal() {
	io.Ff(&bb, "axis('equal')\n")
}

func Show() {
	io.Ff(&bb, "show()\n")
	run(nil)
}

func Circle(xc, yc, r float64, args string) {
	cmd := io.Sf("Circle(%g,%g,%g", xc, yc, r)
	if len(args) > 0 {
		cmd += io.Sf(",%s", args)
	}
	io.Ff(&bb, "%s)\n", cmd)
}

func run(extra *bytes.Buffer) {
	fn := "/tmp/gosl_mplotlib_go.py"
	if extra != nil {
		io.WriteFile(fn, &ea, &bb, extra)
	} else {
		io.WriteFile(fn, &ea, &bb)
	}
	cmd := exec.Command("python", fn)
	var out, serr bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &serr
	err := cmd.Run()
	if err != nil {
		chk.Panic(_mplotlib_err1, serr.String())
	}
	io.Pf("%s", out.String())
}

// GenMat generates matrix
func GenMat(buf *bytes.Buffer, name string, a [][]float64) {
	io.Ff(buf, "%s=array([", name)
	for i, _ := range a {
		io.Ff(buf, "[")
		for j, _ := range a[i] {
			io.Ff(buf, "%g,", a[i][j])
		}
		io.Ff(buf, "],")
	}
	io.Ff(buf, "],dtype=float)\n")
}

// GenList generates list
func GenList(buf *bytes.Buffer, name string, a [][]float64) {
	io.Ff(buf, "%s=[", name)
	for i, _ := range a {
		io.Ff(buf, "[")
		for j, _ := range a[i] {
			io.Ff(buf, "%g,", a[i][j])
		}
		io.Ff(buf, "],")
	}
	io.Ff(buf, "]\n")
}

// GenArray generates the NumPy text in 'b' corresponding to an array of float point numbers
func GenArray(b *bytes.Buffer, name string, u []float64) {
	io.Ff(b, "%s=array([", name)
	for i, _ := range u {
		io.Ff(b, "%g,", u[i])
	}
	io.Ff(b, "],dtype=float)\n")
}

// Gen2Arrays generates the NumPy text in 'b' corresponding to 2 arrays of float point numbers
func Gen2Arrays(buf *bytes.Buffer, nameA, nameB string, a, b []float64) {
	GenArray(buf, nameA, a)
	GenArray(buf, nameB, b)
}

// GenStrArray generates the NumPy text in 'b' corresponding to an array of strings
func GenStrArray(b *bytes.Buffer, name string, u []string) {
	io.Ff(b, "%s=[", name)
	for i, _ := range u {
		io.Ff(b, "%q,", u[i])
	}
	io.Ff(b, "]\n")
}

var (
	_mplotlib_err1 = "mplotlib.go: python failed:\n%v"
)
<|endoftext|>


<commit_before>package conio

import "github.com/mattn/go-runewidth"

var widthCache = map[rune]int{
	rune(0x262D): 2, // Hammer and sickle: http://unicode-table.com/en/262D/
	rune(0x270F): 2,
}

func GetCharWidth(n rune) int {
	width, ok := widthCache[n]
	if !ok {
		width = runewidth.RuneWidth(n)
		widthCache[n] = width
	}
	return width
	// if n > 0xFF {
	//	return 2;
	//}else{
	//	return 1;
	//}
}

func GetStringWidth(s string) int {
	width := 0
	for _, ch := range s {
		width += GetCharWidth(ch)
	}
	return width
}
<commit_msg>modify unicode size for U+262A (Star and Crescent)<commit_after>package conio

import "github.com/mattn/go-runewidth"

var widthCache = map[rune]int{
	rune(0x262D): 2, // Hammer and sickle: http://unicode-table.com/en/262D/
	rune(0x262A): 2, // Star And Crescent
	rune(0x270F): 2, // Pencil
}

func GetCharWidth(n rune) int {
	width, ok := widthCache[n]
	if !ok {
		width = runewidth.RuneWidth(n)
		widthCache[n] = width
	}
	return width
	// if n > 0xFF {
	//	return 2;
	//}else{
	//	return 1;
	//}
}

func GetStringWidth(s string) int {
	width := 0
	for _, ch := range s {
		width += GetCharWidth(ch)
	}
	return width
}
<|endoftext|>


<commit_before>// Copyright 2017 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package frontend

import (
	"net/http"

	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/server/auth"
	"go.chromium.org/luci/server/router"
	"go.chromium.org/luci/server/templates"

	"go.chromium.org/luci/milo/common"
)

// ErrorHandler renders an error page for the user.
func ErrorHandler(c *router.Context, err error) {
	// TODO(iannucci): tag/extract other information from error, like a link to the
	// 'container'; i.e. a build may link to its builder, a builder to its
	// master/bucket, etc.

	code := common.ErrorCodeIn(err)
	switch code {
	case common.CodeUnknown:
		errors.Log(c.Context, err)
	case common.CodeUnauthorized:
		loginURL, err := auth.LoginURL(c.Context, c.Request.URL.RequestURI())
		if err == nil {
			http.Redirect(c.Writer, c.Request, loginURL, http.StatusFound)
			return
		}
		errors.Log(
			c.Context, errors.Annotate(err, "Failed to retrieve login URL").Err())
	}

	status := code.HTTPStatus()
	c.Writer.WriteHeader(status)
	templates.MustRender(c.Context, c.Writer, "pages/error.html", templates.Args{
		"Code":    status,
		"Message": err.Error(),
	})
}
<commit_msg>milo: log stacktrace on all errors by default.<commit_after>// Copyright 2017 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package frontend

import (
	"net/http"

	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/server/auth"
	"go.chromium.org/luci/server/router"
	"go.chromium.org/luci/server/templates"

	"go.chromium.org/luci/milo/common"
)

// ErrorHandler renders an error page for the user.
func ErrorHandler(c *router.Context, err error) {
	// TODO(iannucci): tag/extract other information from error, like a link to the
	// 'container'; i.e. a build may link to its builder, a builder to its
	// master/bucket, etc.

	code := common.ErrorCodeIn(err)
	switch code {
	case common.CodeUnauthorized:
		loginURL, err := auth.LoginURL(c.Context, c.Request.URL.RequestURI())
		if err == nil {
			http.Redirect(c.Writer, c.Request, loginURL, http.StatusFound)
			return
		}
		errors.Log(
			c.Context, errors.Annotate(err, "Failed to retrieve login URL").Err())
	case common.CodeOK:
		// All good.
	default:
		errors.Log(c.Context, err)
	}

	status := code.HTTPStatus()
	c.Writer.WriteHeader(status)
	templates.MustRender(c.Context, c.Writer, "pages/error.html", templates.Args{
		"Code":    status,
		"Message": err.Error(),
	})
}
<|endoftext|>


<commit_before>package builder

// nginx
const (
	NginxVersion           = "1.20.1"
	NginxDownloadURLPrefix = "https://nginx.org/download"
)

// pcre
const (
	PcreVersion           = "8.44"
	PcreDownloadURLPrefix = "https://ftp.pcre.org/pub/pcre"
)

// openssl
const (
	OpenSSLVersion           = "1.1.1k"
	OpenSSLDownloadURLPrefix = "https://www.openssl.org/source"
)

// libressl
const (
	LibreSSLVersion           = "3.2.4"
	LibreSSLDownloadURLPrefix = "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL"
)

// zlib
const (
	ZlibVersion           = "1.2.11"
	ZlibDownloadURLPrefix = "https://zlib.net/fossils"
)

// openResty
const (
	OpenRestyVersion           = "1.19.3.2"
	OpenRestyDownloadURLPrefix = "https://openresty.org/download"
)

// tengine
const (
	TengineVersion           = "2.3.2"
	TengineDownloadURLPrefix = "https://tengine.taobao.org/download"
)

// component enumerations
const (
	ComponentNginx = iota
	ComponentOpenResty
	ComponentTengine
	ComponentPcre
	ComponentOpenSSL
	ComponentLibreSSL
	ComponentZlib
	ComponentMax
)
<commit_msg>bumped default tengine version to 2.3.3.<commit_after>package builder

// nginx
const (
	NginxVersion           = "1.20.1"
	NginxDownloadURLPrefix = "https://nginx.org/download"
)

// pcre
const (
	PcreVersion           = "8.44"
	PcreDownloadURLPrefix = "https://ftp.pcre.org/pub/pcre"
)

// openssl
const (
	OpenSSLVersion           = "1.1.1k"
	OpenSSLDownloadURLPrefix = "https://www.openssl.org/source"
)

// libressl
const (
	LibreSSLVersion           = "3.2.4"
	LibreSSLDownloadURLPrefix = "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL"
)

// zlib
const (
	ZlibVersion           = "1.2.11"
	ZlibDownloadURLPrefix = "https://zlib.net/fossils"
)

// openResty
const (
	OpenRestyVersion           = "1.19.3.2"
	OpenRestyDownloadURLPrefix = "https://openresty.org/download"
)

// tengine
const (
	TengineVersion           = "2.3.3"
	TengineDownloadURLPrefix = "https://tengine.taobao.org/download"
)

// component enumerations
const (
	ComponentNginx = iota
	ComponentOpenResty
	ComponentTengine
	ComponentPcre
	ComponentOpenSSL
	ComponentLibreSSL
	ComponentZlib
	ComponentMax
)
<|endoftext|>


<commit_before>package builtin

import (
	"log"

	. "github.com/wanliu/flow/builtin/ai"
	config "github.com/wanliu/flow/builtin/config"
	. "github.com/wanliu/flow/context"
	flow "github.com/wanliu/goflow"
)

func NewApiAi() interface{} {
	return new(ApiAi)
}

type ApiAi struct {
	flow.Component

	MultiField

	token     string
	sessionId string
	proxyUrl  string

	Echo      <-chan bool
	In        <-chan string
	Token     <-chan string
	SessionId <-chan string
	ProxyUrl  <-chan string
	Out       chan<- Context
	Ctx       <-chan Context
}

func (c *ApiAi) Init() {
	c.Fields = []string{config.ValueKeyCtx, config.ValueKeyText}

	c.Process = func() error {
		txt, tok := c.Value(config.ValueKeyText).(string)
		ctx, cok := c.Value(config.ValueKeyCtx).(Context)

		if tok && cok {
			go func() {
				res, _ := ApiAiQuery(txt, c.token, c.sessionId, c.proxyUrl)

				ctx.SetValue(config.CtxkeyResult, res)
				intent := res.Metadata.IntentName
				score := res.Score
				query := res.ResolvedQuery

				log.Printf("意图解析\"%s\" -> %s 准确度: %2.2f%%", query, intent, score*100)
				c.Out <- ctx
			}()
		}

		return nil
	}
}

func (c *ApiAi) OnIn(input string) {
	c.SetValue(config.ValueKeyText, input)
}

func (c *ApiAi) OnToken(token string) {
	c.token = token
}

func (c *ApiAi) OnSessionId(sessionId string) {
	c.sessionId = sessionId
}

func (c *ApiAi) OnProxyUrl(proxy string) {
	c.proxyUrl = proxy
}

func (c *ApiAi) OnCtx(ctx Context) {
	c.SetValue(config.ValueKeyCtx, ctx)
}
<commit_msg>fix ai miss msg<commit_after>package builtin

import (
	"log"
	"sync"

	"github.com/oleiade/lane"

	. "github.com/wanliu/flow/builtin/ai"
	. "github.com/wanliu/flow/context"

	config "github.com/wanliu/flow/builtin/config"
	flow "github.com/wanliu/goflow"
)

func NewApiAi() interface{} {
	return new(ApiAi)
}

type ApiAi struct {
	flow.Component

	MultiField

	sync.RWMutex

	token     string
	sessionId string
	proxyUrl  string

	CtxQueue *lane.Queue
	TxtQueue *lane.Queue

	Echo      <-chan bool
	In        <-chan string
	Token     <-chan string
	SessionId <-chan string
	ProxyUrl  <-chan string
	Out       chan<- Context
	Ctx       <-chan Context
}

func (c *ApiAi) Init() {
	c.CtxQueue = lane.NewQueue()
	c.TxtQueue = lane.NewQueue()
}

func (c *ApiAi) OnIn(input string) {
	// c.SetValue(config.ValueKeyText, input)
	c.Lock()
	c.TxtQueue.Enqueue(input)
	c.Unlock()

	c.SendQuery()
}

func (c *ApiAi) OnToken(token string) {
	c.token = token
}

func (c *ApiAi) OnSessionId(sessionId string) {
	c.sessionId = sessionId
}

func (c *ApiAi) OnProxyUrl(proxy string) {
	c.proxyUrl = proxy
}

func (c *ApiAi) OnCtx(ctx Context) {
	// c.SetValue(config.ValueKeyCtx, ctx)
	c.Lock()
	c.CtxQueue.Enqueue(ctx)
	c.Unlock()

	c.SendQuery()
}

func (c *ApiAi) SendQuery() {
	c.RLock()

	for c.CtxQueue.Head() != nil && c.TxtQueue.Head() != nil {
		txt := c.TxtQueue.Dequeue().(string)
		ctx := c.CtxQueue.Dequeue().(Context)

		res, _ := ApiAiQuery(txt, c.token, c.sessionId, c.proxyUrl)

		ctx.SetValue(config.CtxkeyResult, res)

		intent := res.Metadata.IntentName
		score := res.Score
		query := res.ResolvedQuery

		log.Printf("意图解析\"%s\" -> %s 准确度: %2.2f%%", query, intent, score*100)
		c.Out <- ctx
	}

	c.RUnlock()
}
<|endoftext|>


<commit_before>package accounts

import (
	"bytes"
	"math/rand"
	"os"
	"testing"
	"time"

	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/crypto"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/stretchr/testify/assert"
)

func TestEncryptDecrytCredentials(t *testing.T) {
	encryptedCreds1, err := EncryptCredentials("me@mycozy.cloud", "fzEE6HFWsSp8jP")
	if !assert.NoError(t, err) {
		return
	}
	encryptedCreds2, err := EncryptCredentials("me@mycozy.cloud", "fzEE6HFWsSp8jP")
	if !assert.NoError(t, err) {
		return
	}
	assert.False(t, bytes.Equal(encryptedCreds1, encryptedCreds2))

	{
		login, password, err := DecryptCredentials(encryptedCreds1)
		if !assert.NoError(t, err) {
			return
		}
		assert.Equal(t, "me@mycozy.cloud", login)
		assert.Equal(t, "fzEE6HFWsSp8jP", password)
	}
	{
		login, password, err := DecryptCredentials(encryptedCreds2)
		if !assert.NoError(t, err) {
			return
		}
		assert.Equal(t, "me@mycozy.cloud", login)
		assert.Equal(t, "fzEE6HFWsSp8jP", password)
	}
}

func TestEncryptDecrytUTF8Credentials(t *testing.T) {
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 1024; i++ {
		login := string(crypto.GenerateRandomBytes(rng.Intn(256)))
		password := string(crypto.GenerateRandomBytes(rng.Intn(256)))

		encryptedCreds, err := EncryptCredentials(login, password)
		if !assert.NoError(t, err) {
			return
		}

		loginDec, passwordDec, err := DecryptCredentials(encryptedCreds)
		if !assert.NoError(t, err) {
			return
		}

		assert.Equal(t, loginDec, login)
		assert.Equal(t, passwordDec, password)
	}

	for i := 0; i < 1024; i++ {
		login := string(utils.RandomString(rng.Intn(256)))
		password := string(utils.RandomString(rng.Intn(256)))

		encryptedCreds, err := EncryptCredentials(login, password)
		if !assert.NoError(t, err) {
			return
		}

		loginDec, passwordDec, err := DecryptCredentials(encryptedCreds)
		if !assert.NoError(t, err) {
			return
		}

		assert.True(t, bytes.Equal(encryptedCreds[:len(cipherHeader)], []byte(cipherHeader)))
		assert.Equal(t, loginDec, login)
		assert.Equal(t, passwordDec, password)
	}
}

func TestDecryptCredentialsRandom(t *testing.T) {
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 1024; i++ {
		encrypted := crypto.GenerateRandomBytes(rng.Intn(256))
		_, _, err := DecryptCredentials(encrypted)
		assert.Error(t, err)
	}
	for i := 0; i < 1024; i++ {
		encrypted := crypto.GenerateRandomBytes(rng.Intn(256))
		encryptedWithHeader := make([]byte, len(cipherHeader)+len(encrypted))
		copy(encryptedWithHeader[0:], cipherHeader)
		copy(encryptedWithHeader[len(cipherHeader):], encrypted)
		_, _, err := DecryptCredentials(encryptedWithHeader)
		assert.Error(t, err)
	}
}

func TestRandomBitFlips(t *testing.T) {
	original, err := EncryptCredentials("toto@titi.com", "X3hVYLJLRiUyCs")
	if !assert.NoError(t, err) {
		return
	}

	flipped := make([]byte, len(original))
	copy(flipped, original)
	login, passwd, err := DecryptCredentials(flipped)
	if !assert.NoError(t, err) {
		return
	}
	assert.Equal(t, "toto@titi.com", login)
	assert.Equal(t, "X3hVYLJLRiUyCs", passwd)

	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 100000; i++ {
		copy(flipped, original)
		flipsLen := rng.Intn(30) + 1
		flipsSet := make([]int, 0, flipsLen)
		for len(flipsSet) < flipsLen {
			flipValue := rng.Intn(len(original) * 8)
			flipFound := false
			for j := 0; j < len(flipsSet); j++ {
				if flipsSet[j] == flipValue {
					flipFound = true
					break
				}
			}
			if !flipFound {
				flipsSet = append(flipsSet, flipValue)
			}
		}
		for _, flipValue := range flipsSet {
			mask := byte(0x1 << uint(flipValue%8))
			flipped[flipValue/8] ^= mask
		}
		_, _, err := DecryptCredentials(flipped)
		if !assert.Error(t, err) {
			t.Fatalf("Failed with flips %v", flipsSet)
			return
		}
	}
}

func TestMain(m *testing.M) {
	config.UseTestFile()
	os.Exit(m.Run())
}
<commit_msg>Add credentials test for empty login<commit_after>package accounts

import (
	"bytes"
	"math/rand"
	"os"
	"testing"
	"time"

	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/crypto"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/stretchr/testify/assert"
)

func TestEncryptDecrytCredentials(t *testing.T) {
	encryptedCreds1, err := EncryptCredentials("me@mycozy.cloud", "fzEE6HFWsSp8jP")
	if !assert.NoError(t, err) {
		return
	}
	encryptedCreds2, err := EncryptCredentials("me@mycozy.cloud", "fzEE6HFWsSp8jP")
	if !assert.NoError(t, err) {
		return
	}
	encryptedCreds3, err := EncryptCredentials("", "fzEE6HFWsSp8jP")
	if !assert.NoError(t, err) {
		return
	}
	assert.False(t, bytes.Equal(encryptedCreds1, encryptedCreds2))

	{
		login, password, err := DecryptCredentials(encryptedCreds1)
		if !assert.NoError(t, err) {
			return
		}
		assert.Equal(t, "me@mycozy.cloud", login)
		assert.Equal(t, "fzEE6HFWsSp8jP", password)
	}
	{
		login, password, err := DecryptCredentials(encryptedCreds2)
		if !assert.NoError(t, err) {
			return
		}
		assert.Equal(t, "me@mycozy.cloud", login)
		assert.Equal(t, "fzEE6HFWsSp8jP", password)
	}
	{
		login, password, err := DecryptCredentials(encryptedCreds3)
		if !assert.NoError(t, err) {
			return
		}
		assert.Equal(t, "", login)
		assert.Equal(t, "fzEE6HFWsSp8jP", password)
	}
}

func TestEncryptDecrytUTF8Credentials(t *testing.T) {
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 1024; i++ {
		login := string(crypto.GenerateRandomBytes(rng.Intn(256)))
		password := string(crypto.GenerateRandomBytes(rng.Intn(256)))

		encryptedCreds, err := EncryptCredentials(login, password)
		if !assert.NoError(t, err) {
			return
		}

		loginDec, passwordDec, err := DecryptCredentials(encryptedCreds)
		if !assert.NoError(t, err) {
			return
		}

		assert.Equal(t, loginDec, login)
		assert.Equal(t, passwordDec, password)
	}

	for i := 0; i < 1024; i++ {
		login := string(utils.RandomString(rng.Intn(256)))
		password := string(utils.RandomString(rng.Intn(256)))

		encryptedCreds, err := EncryptCredentials(login, password)
		if !assert.NoError(t, err) {
			return
		}

		loginDec, passwordDec, err := DecryptCredentials(encryptedCreds)
		if !assert.NoError(t, err) {
			return
		}

		assert.True(t, bytes.Equal(encryptedCreds[:len(cipherHeader)], []byte(cipherHeader)))
		assert.Equal(t, loginDec, login)
		assert.Equal(t, passwordDec, password)
	}
}

func TestDecryptCredentialsRandom(t *testing.T) {
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 1024; i++ {
		encrypted := crypto.GenerateRandomBytes(rng.Intn(256))
		_, _, err := DecryptCredentials(encrypted)
		assert.Error(t, err)
	}
	for i := 0; i < 1024; i++ {
		encrypted := crypto.GenerateRandomBytes(rng.Intn(256))
		encryptedWithHeader := make([]byte, len(cipherHeader)+len(encrypted))
		copy(encryptedWithHeader[0:], cipherHeader)
		copy(encryptedWithHeader[len(cipherHeader):], encrypted)
		_, _, err := DecryptCredentials(encryptedWithHeader)
		assert.Error(t, err)
	}
}

func TestRandomBitFlips(t *testing.T) {
	original, err := EncryptCredentials("toto@titi.com", "X3hVYLJLRiUyCs")
	if !assert.NoError(t, err) {
		return
	}

	flipped := make([]byte, len(original))
	copy(flipped, original)
	login, passwd, err := DecryptCredentials(flipped)
	if !assert.NoError(t, err) {
		return
	}
	assert.Equal(t, "toto@titi.com", login)
	assert.Equal(t, "X3hVYLJLRiUyCs", passwd)

	rng := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 100000; i++ {
		copy(flipped, original)
		flipsLen := rng.Intn(30) + 1
		flipsSet := make([]int, 0, flipsLen)
		for len(flipsSet) < flipsLen {
			flipValue := rng.Intn(len(original) * 8)
			flipFound := false
			for j := 0; j < len(flipsSet); j++ {
				if flipsSet[j] == flipValue {
					flipFound = true
					break
				}
			}
			if !flipFound {
				flipsSet = append(flipsSet, flipValue)
			}
		}
		for _, flipValue := range flipsSet {
			mask := byte(0x1 << uint(flipValue%8))
			flipped[flipValue/8] ^= mask
		}
		_, _, err := DecryptCredentials(flipped)
		if !assert.Error(t, err) {
			t.Fatalf("Failed with flips %v", flipsSet)
			return
		}
	}
}

func TestMain(m *testing.M) {
	config.UseTestFile()
	os.Exit(m.Run())
}
<|endoftext|>


<commit_before>package app

import (
	"net/http"

	"fmt"

	"reflect"

	"github.com/rancher/norman/api/access"
	"github.com/rancher/norman/parse"
	"github.com/rancher/norman/types"
	"github.com/rancher/norman/types/convert"
	"github.com/rancher/rancher/pkg/controllers/management/compose/common"
	"github.com/rancher/rancher/pkg/ref"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	pv3 "github.com/rancher/types/apis/project.cattle.io/v3"
	projectschema "github.com/rancher/types/apis/project.cattle.io/v3/schema"
	projectv3 "github.com/rancher/types/client/project/v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type Wrapper struct {
	Clusters              v3.ClusterInterface
	KubeConfigGetter      common.KubeConfigGetter
	TemplateContentClient v3.TemplateContentInterface
	AppGetter             pv3.AppsGetter
}

const appLabel = "io.cattle.field/appId"

func Formatter(apiContext *types.APIContext, resource *types.RawResource) {
	resource.AddAction(apiContext, "upgrade")
	resource.AddAction(apiContext, "rollback")
	resource.Links["revision"] = apiContext.URLBuilder.Link("revision", resource)
	if _, ok := resource.Values["status"]; ok {
		if status, ok := resource.Values["status"].(map[string]interface{}); ok {
			delete(status, "lastAppliedTemplate")
		}
	}
}

func (w Wrapper) ActionHandler(actionName string, action *types.Action, apiContext *types.APIContext) error {
	var app projectv3.App
	if err := access.ByID(apiContext, &projectschema.Version, projectv3.AppType, apiContext.ID, &app); err != nil {
		return err
	}
	actionInput, err := parse.ReadBody(apiContext.Request)
	if err != nil {
		return err
	}
	switch actionName {
	case "upgrade":
		externalID := actionInput["externalId"]
		answers := actionInput["answers"]
		_, namespace := ref.Parse(app.ProjectId)
		obj, err := w.AppGetter.Apps(namespace).Get(app.Name, metav1.GetOptions{})
		if err != nil {
			return err
		}
		if answers != nil {
			m, ok := answers.(map[string]interface{})
			if ok {
				if obj.Spec.Answers == nil {
					obj.Spec.Answers = make(map[string]string)
				}
				for k, v := range m {
					obj.Spec.Answers[k] = convert.ToString(v)
				}
			}
		}
		obj.Spec.ExternalID = convert.ToString(externalID)
		if _, err := w.AppGetter.Apps(namespace).Update(obj); err != nil {
			return err
		}
		return nil
	case "rollback":
		revision := actionInput["revisionId"]
		if convert.ToString(revision) == "" {
			return fmt.Errorf("revision is empty")
		}
		var appRevision projectv3.AppRevision
		_, projectID := ref.Parse(app.ProjectId)
		revisionID := fmt.Sprintf("%s:%s", projectID, convert.ToString(revision))
		if err := access.ByID(apiContext, &projectschema.Version, projectv3.AppRevisionType, revisionID, &appRevision); err != nil {
			return err
		}
		_, namespace := ref.Parse(app.ProjectId)
		obj, err := w.AppGetter.Apps(namespace).Get(app.Name, metav1.GetOptions{})
		if err != nil {
			return err
		}
		obj.Spec.Answers = appRevision.Status.Answers
		obj.Spec.ExternalID = appRevision.Status.ExternalID
		if _, err := w.AppGetter.Apps(namespace).Update(obj); err != nil {
			return err
		}
		return nil
	}
	return nil
}

func (w Wrapper) LinkHandler(apiContext *types.APIContext, next types.RequestHandler) error {
	switch apiContext.Link {
	case "revision":
		var app projectv3.App
		if err := access.ByID(apiContext, &projectschema.Version, projectv3.AppType, apiContext.ID, &app); err != nil {
			return err
		}
		var appRevisions, filtered []map[string]interface{}
		if err := access.List(apiContext, &projectschema.Version, projectv3.AppRevisionType, &types.QueryOptions{}, &appRevisions); err != nil {
			return err
		}
		for _, re := range appRevisions {
			labels := convert.ToMapInterface(re["labels"])
			if reflect.DeepEqual(labels[appLabel], app.Name) {
				filtered = append(filtered, re)
			}
		}
		apiContext.Type = projectv3.AppRevisionType
		apiContext.WriteResponse(http.StatusOK, filtered)
		return nil
	}
	return nil
}
<commit_msg>inherit workload state to app<commit_after>package app

import (
	"net/http"

	"fmt"

	"reflect"

	"github.com/rancher/norman/api/access"
	"github.com/rancher/norman/parse"
	"github.com/rancher/norman/types"
	"github.com/rancher/norman/types/convert"
	"github.com/rancher/rancher/pkg/controllers/management/compose/common"
	"github.com/rancher/rancher/pkg/ref"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	pv3 "github.com/rancher/types/apis/project.cattle.io/v3"
	projectschema "github.com/rancher/types/apis/project.cattle.io/v3/schema"
	projectv3 "github.com/rancher/types/client/project/v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type Wrapper struct {
	Clusters              v3.ClusterInterface
	KubeConfigGetter      common.KubeConfigGetter
	TemplateContentClient v3.TemplateContentInterface
	AppGetter             pv3.AppsGetter
}

const (
	appLabel       = "io.cattle.field/appId"
	activeState    = "active"
	deployingState = "deploying"
)

func Formatter(apiContext *types.APIContext, resource *types.RawResource) {
	resource.AddAction(apiContext, "upgrade")
	resource.AddAction(apiContext, "rollback")
	resource.Links["revision"] = apiContext.URLBuilder.Link("revision", resource)
	if _, ok := resource.Values["status"]; ok {
		if status, ok := resource.Values["status"].(map[string]interface{}); ok {
			delete(status, "lastAppliedTemplate")
		}
	}
	var workloads []projectv3.Workload
	if err := access.List(apiContext, &projectschema.Version, projectv3.WorkloadType, &types.QueryOptions{}, &workloads); err == nil {
		for _, w := range workloads {
			_, appID := ref.Parse(resource.ID)
			if w.WorkloadLabels[appLabel] == appID && w.State != activeState {
				resource.Values["state"] = deployingState
				resource.Values["transitioning"] = "yes"
				transitionMsg := convert.ToString(resource.Values["transitioningMessage"])
				if transitionMsg != "" {
					transitionMsg += "; "
				}
				resource.Values["transitioningMessage"] = transitionMsg + fmt.Sprintf("Workload %s: %s", w.Name, w.TransitioningMessage)
			}
		}
	}
}

func (w Wrapper) ActionHandler(actionName string, action *types.Action, apiContext *types.APIContext) error {
	var app projectv3.App
	if err := access.ByID(apiContext, &projectschema.Version, projectv3.AppType, apiContext.ID, &app); err != nil {
		return err
	}
	actionInput, err := parse.ReadBody(apiContext.Request)
	if err != nil {
		return err
	}
	switch actionName {
	case "upgrade":
		externalID := actionInput["externalId"]
		answers := actionInput["answers"]
		_, namespace := ref.Parse(app.ProjectId)
		obj, err := w.AppGetter.Apps(namespace).Get(app.Name, metav1.GetOptions{})
		if err != nil {
			return err
		}
		if answers != nil {
			m, ok := answers.(map[string]interface{})
			if ok {
				if obj.Spec.Answers == nil {
					obj.Spec.Answers = make(map[string]string)
				}
				for k, v := range m {
					obj.Spec.Answers[k] = convert.ToString(v)
				}
			}
		}
		obj.Spec.ExternalID = convert.ToString(externalID)
		if _, err := w.AppGetter.Apps(namespace).Update(obj); err != nil {
			return err
		}
		return nil
	case "rollback":
		revision := actionInput["revisionId"]
		if convert.ToString(revision) == "" {
			return fmt.Errorf("revision is empty")
		}
		var appRevision projectv3.AppRevision
		_, projectID := ref.Parse(app.ProjectId)
		revisionID := fmt.Sprintf("%s:%s", projectID, convert.ToString(revision))
		if err := access.ByID(apiContext, &projectschema.Version, projectv3.AppRevisionType, revisionID, &appRevision); err != nil {
			return err
		}
		_, namespace := ref.Parse(app.ProjectId)
		obj, err := w.AppGetter.Apps(namespace).Get(app.Name, metav1.GetOptions{})
		if err != nil {
			return err
		}
		obj.Spec.Answers = appRevision.Status.Answers
		obj.Spec.ExternalID = appRevision.Status.ExternalID
		if _, err := w.AppGetter.Apps(namespace).Update(obj); err != nil {
			return err
		}
		return nil
	}
	return nil
}

func (w Wrapper) LinkHandler(apiContext *types.APIContext, next types.RequestHandler) error {
	switch apiContext.Link {
	case "revision":
		var app projectv3.App
		if err := access.ByID(apiContext, &projectschema.Version, projectv3.AppType, apiContext.ID, &app); err != nil {
			return err
		}
		var appRevisions, filtered []map[string]interface{}
		if err := access.List(apiContext, &projectschema.Version, projectv3.AppRevisionType, &types.QueryOptions{}, &appRevisions); err != nil {
			return err
		}
		for _, re := range appRevisions {
			labels := convert.ToMapInterface(re["labels"])
			if reflect.DeepEqual(labels[appLabel], app.Name) {
				filtered = append(filtered, re)
			}
		}
		apiContext.Type = projectv3.AppRevisionType
		apiContext.WriteResponse(http.StatusOK, filtered)
		return nil
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/url"
	"testing"
	"time"

	"github.com/ashwanthkumar/marathon-alerts/mocks"
	marathon "github.com/gambol99/go-marathon"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

func TestProcessCheckForAllSubscribers(t *testing.T) {
	appLabels := make(map[string]string)
	client := new(mocks.Marathon)
	apps := marathon.Applications{
		Apps: []marathon.Application{marathon.Application{Labels: appLabels}},
	}
	var urlValues url.Values
	client.On("Applications", urlValues).Return(&apps, nil)

	alertChan := make(chan AppCheck)
	check, now := CreateMockChecker(appLabels)

	appChecker := AppChecker{
		Client:        client,
		AlertsChannel: alertChan,
		Checks:        []Checker{check},
	}

	expectedCheck := AppCheck{Result: Critical, Timestamp: now, App: "/foo-app", Labels: appLabels}
	wg := AssertOnChannel(t, alertChan, 5*time.Second, func(t *testing.T, actualData AppCheck) {
		assert.Equal(t, expectedCheck, actualData)
	})
	err := appChecker.processChecks()
	assert.Nil(t, err)
	wg.Wait()
}

func TestProcessCheckForWithNoSubscribers(t *testing.T) {
	appLabels := make(map[string]string)
	appLabels["alerts.checks.subscribe"] = "check-that-does-not-exist"
	client := new(mocks.Marathon)
	apps := marathon.Applications{
		Apps: []marathon.Application{marathon.Application{Labels: appLabels}},
	}
	var urlValues url.Values
	client.On("Applications", urlValues).Return(&apps, nil)

	alertChan := make(chan AppCheck)
	check, _ := CreateMockChecker(appLabels)

	appChecker := AppChecker{
		Client:        client,
		AlertsChannel: alertChan,
		Checks:        []Checker{check},
	}

	wg := AssertOnChannel(t, alertChan, 5*time.Second, func(t *testing.T, actualData AppCheck) {
		log.Println("Should not be called")
		t.FailNow()
	})
	err := appChecker.processChecks()
	assert.Nil(t, err)
	wg.Wait()
}

func CreateMockChecker(appLabels map[string]string) (Checker, time.Time) {
	now := time.Now()
	check := new(MockChecker)
	check.On("Name").Return("mock-check")
	check.On("Check", mock.AnythingOfType("Application")).Return(AppCheck{
		Result:    Critical,
		Timestamp: now,
		App:       "/foo-app",
		Labels:    appLabels,
	})

	return check, now
}
<commit_msg>Simplifing the test using buffered channels - WIP<commit_after>package main

import (
	"log"
	"net/url"
	"testing"
	"time"

	"github.com/ashwanthkumar/marathon-alerts/mocks"
	marathon "github.com/gambol99/go-marathon"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

func TestProcessCheckForAllSubscribers(t *testing.T) {
	appLabels := make(map[string]string)
	client := new(mocks.Marathon)
	apps := marathon.Applications{
		Apps: []marathon.Application{marathon.Application{Labels: appLabels}},
	}
	var urlValues url.Values
	client.On("Applications", urlValues).Return(&apps, nil)

	alertChan := make(chan AppCheck, 1)
	check, now := CreateMockChecker(appLabels)

	appChecker := AppChecker{
		Client:        client,
		AlertsChannel: alertChan,
		Checks:        []Checker{check},
	}

	expectedCheck := AppCheck{Result: Critical, Timestamp: now, App: "/foo-app", Labels: appLabels}
	err := appChecker.processChecks()
	assert.Nil(t, err)
	assert.Len(t, alertChan, 1)
	actualCheck := <-alertChan
	assert.Equal(t, actualCheck, expectedCheck)
}

func TestProcessCheckForWithNoSubscribers(t *testing.T) {
	appLabels := make(map[string]string)
	appLabels["alerts.checks.subscribe"] = "check-that-does-not-exist"
	client := new(mocks.Marathon)
	apps := marathon.Applications{
		Apps: []marathon.Application{marathon.Application{Labels: appLabels}},
	}
	var urlValues url.Values
	client.On("Applications", urlValues).Return(&apps, nil)

	alertChan := make(chan AppCheck)
	check, _ := CreateMockChecker(appLabels)

	appChecker := AppChecker{
		Client:        client,
		AlertsChannel: alertChan,
		Checks:        []Checker{check},
	}

	wg := AssertOnChannel(t, alertChan, 5*time.Second, func(t *testing.T, actualData AppCheck) {
		log.Println("Should not be called")
		t.FailNow()
	})
	err := appChecker.processChecks()
	assert.Nil(t, err)
	wg.Wait()
}

func CreateMockChecker(appLabels map[string]string) (Checker, time.Time) {
	now := time.Now()
	check := new(MockChecker)
	check.On("Name").Return("mock-check")
	check.On("Check", mock.AnythingOfType("Application")).Return(AppCheck{
		Result:    Critical,
		Timestamp: now,
		App:       "/foo-app",
		Labels:    appLabels,
	})

	return check, now
}
<|endoftext|>


<commit_before>// Copyright 2017 Pilosa Corp.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

package pilosa_test

import (
	"errors"
	"io"
	"reflect"
	"strings"
	"testing"

	pilosa "github.com/pilosa/go-pilosa"
)

func TestCSVBitIterator(t *testing.T) {
	iterator := pilosa.NewCSVBitIterator(strings.NewReader(`1,10,683793200
		5,20,683793300
		3,41,683793385`))
	bits := []pilosa.RowContainer{}
	for {
		bit, err := iterator.NextRow()
		if err == io.EOF {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		bits = append(bits, bit)
	}
	if len(bits) != 3 {
		t.Fatalf("There should be 3 bits")
	}
	target := []pilosa.Bit{
		{RowID: 1, ColumnID: 10, Timestamp: 683793200},
		{RowID: 5, ColumnID: 20, Timestamp: 683793300},
		{RowID: 3, ColumnID: 41, Timestamp: 683793385},
	}
	for i := range target {
		if !reflect.DeepEqual(target[i], bits[i]) {
			t.Fatalf("%v != %v", target, bits)
		}
	}
}

func TestCSVBitIteratorWithTimestampFormat(t *testing.T) {
	format := "2014-07-16T20:55"
	iterator := pilosa.NewCSVBitIteratorWithTimestampFormat(strings.NewReader(`1,10,1991-09-02T09:33
		5,20,1991-09-02T09:35
		3,41,1991-09-02T09:36`), format)
	bits := []pilosa.RowContainer{}
	for {
		bit, err := iterator.NextRow()
		if err == io.EOF {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		bits = append(bits, bit)
	}
	target := []pilosa.Bit{
		{RowID: 1, ColumnID: 10, Timestamp: 683803980},
		{RowID: 5, ColumnID: 20, Timestamp: 683804100},
		{RowID: 3, ColumnID: 41, Timestamp: 683804160},
	}
	if len(bits) != len(target) {
		t.Fatalf("There should be %d bits", len(target))
	}
	for i := range target {
		if !reflect.DeepEqual(target[i], bits[i]) {
			t.Fatalf("%v != %v", target, bits)
		}
	}
}

func TestCSVBitIteratorWithTimestampFormatFail(t *testing.T) {
	format := "2014-07-16"
	iterator := pilosa.NewCSVBitIteratorWithTimestampFormat(strings.NewReader(`1,10,X`), format)
	_, err := iterator.NextRow()
	if err == nil {
		t.Fatalf("Should have failed")
	}
}

func TestCSVValueIterator(t *testing.T) {
	iterator := pilosa.NewCSVValueIterator(strings.NewReader(`1,10
		5,-20
		3,41
	`))
	values := []pilosa.FieldValue{}
	for {
		value, err := iterator.NextValue()
		if err != nil {
			break
		}
		values = append(values, value)
	}
	if len(values) != 3 {
		t.Fatalf("There should be 3 values")
	}
	target := []pilosa.FieldValue{
		{ColumnID: 1, Value: 10},
		{ColumnID: 5, Value: -20},
		{ColumnID: 3, Value: 41},
	}
	if !reflect.DeepEqual(target, values) {
		t.Fatalf("%v != %v", target, values)
	}
}

func TestCSVBitIteratorInvalidInput(t *testing.T) {
	invalidInputs := []string{
		// less than 2 columns
		"155",
		// invalid row ID
		"a5,155",
		// invalid column ID
		"155,a5",
		// invalid timestamp
		"155,255,a5",
	}
	for _, text := range invalidInputs {
		iterator := pilosa.NewCSVBitIterator(strings.NewReader(text))
		_, err := iterator.NextRow()
		if err == nil {
			t.Fatalf("CSVBitIterator input: %s should fail", text)
		}
	}
}

func TestCSVValueIteratorInvalidInput(t *testing.T) {
	invalidInputs := []string{
		// less than 2 columns
		"155",
		// invalid column ID
		"a5,155",
		// invalid value
		"155,a5",
	}
	for _, text := range invalidInputs {
		iterator := pilosa.NewCSVValueIterator(strings.NewReader(text))
		_, err := iterator.NextValue()
		if err == nil {
			t.Fatalf("CSVValueIterator input: %s should fail", text)
		}
	}
}

func TestCSVBitIteratorError(t *testing.T) {
	iterator := pilosa.NewCSVBitIterator(&BrokenReader{})
	_, err := iterator.NextRow()
	if err == nil {
		t.Fatal("CSVBitIterator should fail with error")
	}
}

func TestCSVValueIteratorError(t *testing.T) {
	iterator := pilosa.NewCSVValueIterator(&BrokenReader{})
	_, err := iterator.NextValue()
	if err == nil {
		t.Fatal("CSVValueIterator should fail with error")
	}
}

type BrokenReader struct{}

func (r BrokenReader) Read(p []byte) (n int, err error) {
	return 0, errors.New("broken reader")
}

func TestBitInt64Field(t *testing.T) {
	b := pilosa.Bit{RowID: 15, ColumnID: 55, Timestamp: 100101}
	target := []int64{15, 55, 100101, 0}
	checkInt64RowContainer(t, target, b)
}

func TestBitUint64Field(t *testing.T) {
	b := pilosa.Bit{RowID: 15, ColumnID: 55, Timestamp: 100101}
	target := []uint64{15, 55, 100101, 0}
	checkUint64RowContainer(t, target, b)
}

func TestBitStringField(t *testing.T) {
	b := pilosa.Bit{RowKey: "abc", ColumnKey: "def", Timestamp: 100101}
	target := []string{"abc", "def", ""}
	checkStringRowContainer(t, target, b)
}

func TestFieldValueInt64Field(t *testing.T) {
	b := pilosa.FieldValue{ColumnID: 55, Value: 125}
	target := []int64{55, 125, 0}
	checkInt64RowContainer(t, target, b)
}

func TestFieldValueUint64Field(t *testing.T) {
	b := pilosa.FieldValue{ColumnID: 55, Value: 125}
	target := []uint64{55, 125, 0}
	checkUint64RowContainer(t, target, b)
}

func TestFieldValueStringField(t *testing.T) {
	b := pilosa.FieldValue{ColumnKey: "abc", Value: 125}
	target := []string{"abc", ""}
	checkStringRowContainer(t, target, b)
}

func checkInt64RowContainer(t *testing.T, target []int64, rc pilosa.RowContainer) {
	for i := range target {
		value := rc.Int64Field(i)
		if target[i] != value {
			t.Fatalf("%d != %d", target[i], value)
		}
	}
}

func checkUint64RowContainer(t *testing.T, target []uint64, rc pilosa.RowContainer) {
	for i := range target {
		value := rc.Uint64Field(i)
		if target[i] != value {
			t.Fatalf("%d != %d", target[i], value)
		}
	}
}

func checkStringRowContainer(t *testing.T, target []string, rc pilosa.RowContainer) {
	for i := range target {
		value := rc.StringField(i)
		if target[i] != value {
			t.Fatalf("%s != %s", target[i], value)
		}
	}
}
<commit_msg>updated imports_test<commit_after>// Copyright 2017 Pilosa Corp.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.

package pilosa_test

import (
	"errors"
	"io"
	"reflect"
	"strings"
	"testing"

	pilosa "github.com/pilosa/go-pilosa"
)

func TestCSVBitIterator(t *testing.T) {
	reader := strings.NewReader(`1,10,683793200
		5,20,683793300
		3,41,683793385`)
	iterator := pilosa.NewCSVBitIterator(reader)
	bits := []pilosa.RowContainer{}
	for {
		bit, err := iterator.NextRow()
		if err == io.EOF {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		bits = append(bits, bit)
	}
	if len(bits) != 3 {
		t.Fatalf("There should be 3 bits")
	}
	target := []*pilosa.Bit{
		&pilosa.Bit{RowID: 1, ColumnID: 10, Timestamp: 683793200},
		&pilosa.Bit{RowID: 5, ColumnID: 20, Timestamp: 683793300},
		&pilosa.Bit{RowID: 3, ColumnID: 41, Timestamp: 683793385},
	}
	for i := range target {
		if !reflect.DeepEqual(target[i], bits[i]) {
			t.Fatalf("%v != %v", target[i], bits[i])
		}
	}
}

func TestCSVBitIteratorWithTimestampFormat(t *testing.T) {
	format := "2006-01-02T04:05"
	reader := strings.NewReader(`1,10,1991-09-02T09:33
		5,20,1991-09-02T09:35
		3,41,1991-09-02T09:36`)
	iterator := pilosa.NewCSVBitIteratorWithTimestampFormat(reader, format)
	bits := []pilosa.RowContainer{}
	for {
		bit, err := iterator.NextRow()
		if err == io.EOF {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		bits = append(bits, bit)
	}
	target := []*pilosa.Bit{
		&pilosa.Bit{RowID: 1, ColumnID: 10, Timestamp: 683770173},
		&pilosa.Bit{RowID: 5, ColumnID: 20, Timestamp: 683770175},
		&pilosa.Bit{RowID: 3, ColumnID: 41, Timestamp: 683770176},
	}
	if len(bits) != len(target) {
		t.Fatalf("There should be %d bits", len(target))
	}
	for i := range target {
		if !reflect.DeepEqual(target[i], bits[i]) {
			t.Fatalf("%v != %v", target[i], bits[i])
		}
	}
}

func TestCSVBitIteratorWithTimestampFormatFail(t *testing.T) {
	format := "2014-07-16"
	reader := strings.NewReader(`1,10,X`)
	iterator := pilosa.NewCSVBitIteratorWithTimestampFormat(reader, format)
	_, err := iterator.NextRow()
	if err == nil {
		t.Fatalf("Should have failed")
	}
}

func TestCSVValueIterator(t *testing.T) {
	reader := strings.NewReader(`1,10
		5,-20
		3,41
	`)
	iterator := pilosa.NewCSVValueIterator(reader)
	values := []pilosa.RowContainer{}
	for {
		value, err := iterator.NextRow()
		if err == io.EOF {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		values = append(values, value)
	}
	target := []pilosa.FieldValue{
		{ColumnID: 1, Value: 10},
		{ColumnID: 5, Value: -20},
		{ColumnID: 3, Value: 41},
	}
	if len(values) != len(target) {
		t.Fatalf("There should be %d values, got %d", len(target), len(values))
	}
	for i := range target {
		if !reflect.DeepEqual(values[i], target[i]) {
			t.Fatalf("%v != %v", target[i], values[i])
		}
	}
}

func TestCSVBitIteratorInvalidInput(t *testing.T) {
	invalidInputs := []string{
		// less than 2 columns
		"155",
		// invalid row ID
		"a5,155",
		// invalid column ID
		"155,a5",
		// invalid timestamp
		"155,255,a5",
	}
	for _, text := range invalidInputs {
		iterator := pilosa.NewCSVBitIterator(strings.NewReader(text))
		_, err := iterator.NextRow()
		if err == nil {
			t.Fatalf("CSVBitIterator input: %s should fail", text)
		}
	}
}

func TestCSVValueIteratorInvalidInput(t *testing.T) {
	invalidInputs := []string{
		// less than 2 columns
		"155",
		// invalid column ID
		"a5,155",
		// invalid value
		"155,a5",
	}
	for _, text := range invalidInputs {
		iterator := pilosa.NewCSVValueIterator(strings.NewReader(text))
		_, err := iterator.NextRow()
		if err == nil {
			t.Fatalf("CSVValueIterator input: %s should fail", text)
		}
	}
}

func TestCSVBitIteratorError(t *testing.T) {
	iterator := pilosa.NewCSVBitIterator(&BrokenReader{})
	_, err := iterator.NextRow()
	if err == nil {
		t.Fatal("CSVBitIterator should fail with error")
	}
}

func TestCSVValueIteratorError(t *testing.T) {
	iterator := pilosa.NewCSVValueIterator(&BrokenReader{})
	_, err := iterator.NextRow()
	if err == nil {
		t.Fatal("CSVValueIterator should fail with error")
	}
}

type BrokenReader struct{}

func (r BrokenReader) Read(p []byte) (n int, err error) {
	return 0, errors.New("broken reader")
}

func TestBitInt64Field(t *testing.T) {
	b := pilosa.Bit{RowID: 15, ColumnID: 55, Timestamp: 100101}
	target := []int64{15, 55, 100101, 0}
	checkInt64RowContainer(t, target, b)
}

func TestBitUint64Field(t *testing.T) {
	b := pilosa.Bit{RowID: 15, ColumnID: 55, Timestamp: 100101}
	target := []uint64{15, 55, 100101, 0}
	checkUint64RowContainer(t, target, b)
}

func TestBitStringField(t *testing.T) {
	b := pilosa.Bit{}
	target := []string{""}
	checkStringRowContainer(t, target, b)
}

func TestFieldValueInt64Field(t *testing.T) {
	b := pilosa.FieldValue{ColumnID: 55, Value: 125}
	target := []int64{55, 125, 0}
	checkInt64RowContainer(t, target, b)
}

func TestFieldValueUint64Field(t *testing.T) {
	b := pilosa.FieldValue{ColumnID: 55, Value: 125}
	target := []uint64{55, 125, 0}
	checkUint64RowContainer(t, target, b)
}

func TestFieldValueStringField(t *testing.T) {
	b := pilosa.FieldValue{ColumnKey: "abc", Value: 125}
	target := []string{"abc", ""}
	checkStringRowContainer(t, target, b)
}

func checkInt64RowContainer(t *testing.T, target []int64, rc pilosa.RowContainer) {
	for i := range target {
		value := rc.Int64Field(i)
		if target[i] != value {
			t.Fatalf("%d != %d", target[i], value)
		}
	}
}

func checkUint64RowContainer(t *testing.T, target []uint64, rc pilosa.RowContainer) {
	for i := range target {
		value := rc.Uint64Field(i)
		if target[i] != value {
			t.Fatalf("%d != %d", target[i], value)
		}
	}
}

func checkStringRowContainer(t *testing.T, target []string, rc pilosa.RowContainer) {
	for i := range target {
		value := rc.StringField(i)
		if target[i] != value {
			t.Fatalf("%s != %s", target[i], value)
		}
	}
}
<|endoftext|>


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

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

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

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

package issuers

import (
	"fmt"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
)

func (c *controller) issuersForSecret(secret *corev1.Secret) ([]*v1alpha2.Issuer, error) {
	issuers, err := c.issuerLister.List(labels.NewSelector())

	if err != nil {
		return nil, fmt.Errorf("error listing certificiates: %s", err.Error())
	}

	var affected []*v1alpha2.Issuer
	for _, iss := range issuers {
		if iss.Namespace != secret.Namespace {
			continue
		}
		if (iss.Spec.ACME != nil && iss.Spec.ACME.PrivateKey.Name == secret.Name) ||
			(iss.Spec.CA != nil && iss.Spec.CA.SecretName == secret.Name) ||
			(iss.Spec.Vault != nil && iss.Spec.Vault.Auth.TokenSecretRef.Name == secret.Name) ||
			(iss.Spec.Venafi != nil && iss.Spec.Venafi.TPP != nil && iss.Spec.Venafi.TPP.CredentialsRef.Name == secret.Name) ||
			(iss.Spec.Venafi != nil && iss.Spec.Venafi.Cloud != nil && iss.Spec.Venafi.Cloud.APITokenSecretRef.Name == secret.Name) {
			affected = append(affected, iss)
			continue
		}
	}

	return affected, nil
}
<commit_msg>Adds all vault Auth methods to secret checks and stops panic<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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

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

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

package issuers

import (
	"fmt"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
)

func (c *controller) issuersForSecret(secret *corev1.Secret) ([]*v1alpha2.Issuer, error) {
	issuers, err := c.issuerLister.List(labels.NewSelector())

	if err != nil {
		return nil, fmt.Errorf("error listing certificiates: %s", err.Error())
	}

	var affected []*v1alpha2.Issuer
	for _, iss := range issuers {
		if iss.Namespace != secret.Namespace {
			continue
		}
		if (iss.Spec.ACME != nil && iss.Spec.ACME.PrivateKey.Name == secret.Name) ||
			(iss.Spec.CA != nil && iss.Spec.CA.SecretName == secret.Name) ||

			(iss.Spec.Venafi != nil && iss.Spec.Venafi.TPP != nil && iss.Spec.Venafi.TPP.CredentialsRef.Name == secret.Name) ||
			(iss.Spec.Venafi != nil && iss.Spec.Venafi.Cloud != nil && iss.Spec.Venafi.Cloud.APITokenSecretRef.Name == secret.Name) {

			affected = append(affected, iss)
			continue
		}

		if iss.Spec.Vault != nil {
			if (iss.Spec.Vault.Auth.TokenSecretRef != nil &&
				iss.Spec.Vault.Auth.TokenSecretRef.Name == secret.Name) ||

				(iss.Spec.Vault.Auth.AppRole != nil &&
					iss.Spec.Vault.Auth.AppRole.SecretRef.Name == secret.Name) ||

				(iss.Spec.Vault.Auth.Kubernetes != nil &&
					iss.Spec.Vault.Auth.Kubernetes.SecretRef.Name == secret.Name) {
			}

			affected = append(affected, iss)
			continue
		}
	}

	return affected, nil
}
<|endoftext|>


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

// Package bundle implements bundle loading.
package bundle

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strings"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/util"
	"github.com/pkg/errors"
)

// Common file extensions and file names.
const (
	RegoExt     = ".rego"
	JSONExt     = ".json"
	ManifestExt = ".manifest"
	DataFileExt = "/data.json"
)

// Bundle represents a loaded bundle. The bundle can contain data and policies.
type Bundle struct {
	Manifest Manifest
	Data     map[string]interface{}
	Modules  []ModuleFile
}

// Manifest represents the manifest from a bundle. The manifest may contain
// metadata such as the bundle revision.
type Manifest struct {
	Revision string `json:"revision"`
}

// ModuleFile represents a single module contained a bundle.
type ModuleFile struct {
	Path   string
	Raw    []byte
	Parsed *ast.Module
}

// Write serializes the Bundle and writes it to w.
func Write(w io.Writer, bundle Bundle) error {
	gw := gzip.NewWriter(w)
	tw := tar.NewWriter(gw)

	var buf bytes.Buffer

	if err := json.NewEncoder(&buf).Encode(bundle.Data); err != nil {
		return err
	}

	if err := writeFile(tw, "data.json", buf.Bytes()); err != nil {
		return err
	}

	for _, module := range bundle.Modules {
		if err := writeFile(tw, module.Path, module.Raw); err != nil {
			return err
		}
	}

	if err := writeManifest(tw, bundle); err != nil {
		return err
	}

	if err := tw.Close(); err != nil {
		return err
	}

	return gw.Close()
}

func writeManifest(tw *tar.Writer, bundle Bundle) error {

	var buf bytes.Buffer

	if err := json.NewEncoder(&buf).Encode(bundle.Manifest); err != nil {
		return err
	}

	return writeFile(tw, ManifestExt, buf.Bytes())
}

// Read returns a new Bundle loaded from the reader.
func Read(r io.Reader) (Bundle, error) {

	var bundle Bundle

	bundle.Data = map[string]interface{}{}

	gr, err := gzip.NewReader(r)
	if err != nil {
		return bundle, errors.Wrap(err, "bundle read failed")
	}

	tr := tar.NewReader(gr)

	for {
		header, err := tr.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			return bundle, errors.Wrap(err, "bundle read failed")
		}

		if header.Typeflag != tar.TypeReg {
			continue
		}

		var buf bytes.Buffer
		io.Copy(&buf, tr)
		path := header.Name

		if strings.HasSuffix(path, RegoExt) {
			module, err := ast.ParseModule(path, buf.String())
			if err != nil {
				return bundle, errors.Wrap(err, "bundle load failed")
			}
			file := ModuleFile{
				Path:   path,
				Raw:    buf.Bytes(),
				Parsed: module,
			}
			bundle.Modules = append(bundle.Modules, file)

		} else if strings.HasSuffix(path, DataFileExt) {
			var value interface{}
			if err := util.NewJSONDecoder(&buf).Decode(&value); err != nil {
				return bundle, errors.Wrapf(err, "bundle load failed on %v", path)
			}
			dirpath := strings.Trim(strings.TrimSuffix(path, DataFileExt), "/")
			var key []string
			if dirpath != "" {
				key = strings.Split(dirpath, "/")
			}
			if err := bundle.insert(key, value); err != nil {
				return bundle, errors.Wrapf(err, "bundle load failed on %v", path)
			}

		} else if strings.HasSuffix(path, ManifestExt) {
			if err := util.NewJSONDecoder(&buf).Decode(&bundle.Manifest); err != nil {
				return bundle, errors.Wrapf(err, "bundle load failed on manifest")
			}
		}
	}

	return bundle, nil
}

// Equal returns true if this bundle's contents equal the other bundle's
// contents.
func (b Bundle) Equal(other Bundle) bool {
	if !reflect.DeepEqual(b.Data, other.Data) {
		return false
	}
	if len(b.Modules) != len(other.Modules) {
		return false
	}
	for i := range b.Modules {
		if b.Modules[i].Path != other.Modules[i].Path {
			return false
		}
		if !b.Modules[i].Parsed.Equal(other.Modules[i].Parsed) {
			return false
		}
		if !bytes.Equal(b.Modules[i].Raw, other.Modules[i].Raw) {
			return false
		}
	}
	return true
}

func (b *Bundle) insert(key []string, value interface{}) error {
	if len(key) == 0 {
		obj, ok := value.(map[string]interface{})
		if !ok {
			return fmt.Errorf("root value must be object")
		}
		b.Data = obj
		return nil
	}

	obj, err := b.mkdir(key[:len(key)-1])
	if err != nil {
		return err
	}

	obj[key[len(key)-1]] = value
	return nil
}

func (b *Bundle) mkdir(key []string) (map[string]interface{}, error) {
	obj := b.Data
	for i := 0; i < len(key); i++ {
		node, ok := obj[key[i]]
		if !ok {
			node = map[string]interface{}{}
			obj[key[i]] = node
		}
		obj, ok = node.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("non-leaf value must be object")
		}
	}
	return obj, nil
}

func writeFile(tw *tar.Writer, path string, bs []byte) error {

	hdr := &tar.Header{
		Name:     "/" + strings.TrimLeft(path, "/"),
		Mode:     0600,
		Typeflag: tar.TypeReg,
		Size:     int64(len(bs)),
	}

	if err := tw.WriteHeader(hdr); err != nil {
		return err
	}

	_, err := tw.Write(bs)
	return err
}
<commit_msg>Update bundle reader to cap buffer size<commit_after>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package bundle implements bundle loading.
package bundle

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strings"

	"github.com/open-policy-agent/opa/ast"
	"github.com/open-policy-agent/opa/util"
	"github.com/pkg/errors"
)

// Common file extensions and file names.
const (
	RegoExt     = ".rego"
	JSONExt     = ".json"
	ManifestExt = ".manifest"
	DataFileExt = "/data.json"
)

const bundleLimitBytes = (1024 * 1024 * 1024) + 1 // limit bundle reads to 1GB to protect against gzip bombs

// Bundle represents a loaded bundle. The bundle can contain data and policies.
type Bundle struct {
	Manifest Manifest
	Data     map[string]interface{}
	Modules  []ModuleFile
}

// Manifest represents the manifest from a bundle. The manifest may contain
// metadata such as the bundle revision.
type Manifest struct {
	Revision string `json:"revision"`
}

// ModuleFile represents a single module contained a bundle.
type ModuleFile struct {
	Path   string
	Raw    []byte
	Parsed *ast.Module
}

// Write serializes the Bundle and writes it to w.
func Write(w io.Writer, bundle Bundle) error {
	gw := gzip.NewWriter(w)
	tw := tar.NewWriter(gw)

	var buf bytes.Buffer

	if err := json.NewEncoder(&buf).Encode(bundle.Data); err != nil {
		return err
	}

	if err := writeFile(tw, "data.json", buf.Bytes()); err != nil {
		return err
	}

	for _, module := range bundle.Modules {
		if err := writeFile(tw, module.Path, module.Raw); err != nil {
			return err
		}
	}

	if err := writeManifest(tw, bundle); err != nil {
		return err
	}

	if err := tw.Close(); err != nil {
		return err
	}

	return gw.Close()
}

func writeManifest(tw *tar.Writer, bundle Bundle) error {

	var buf bytes.Buffer

	if err := json.NewEncoder(&buf).Encode(bundle.Manifest); err != nil {
		return err
	}

	return writeFile(tw, ManifestExt, buf.Bytes())
}

// Read returns a new Bundle loaded from the reader.
func Read(r io.Reader) (Bundle, error) {

	var bundle Bundle

	bundle.Data = map[string]interface{}{}

	gr, err := gzip.NewReader(r)
	if err != nil {
		return bundle, errors.Wrap(err, "bundle read failed")
	}

	tr := tar.NewReader(gr)

	for {
		header, err := tr.Next()
		if err == io.EOF {
			break
		} else if err != nil {
			return bundle, errors.Wrap(err, "bundle read failed")
		}

		if header.Typeflag != tar.TypeReg {
			continue
		}

		var buf bytes.Buffer
		n, err := io.CopyN(&buf, tr, bundleLimitBytes)
		if err != nil && err != io.EOF {
			return bundle, err
		} else if err == nil && n >= bundleLimitBytes {
			return bundle, fmt.Errorf("bundle exceeded max size (%v bytes)", bundleLimitBytes-1)
		}

		path := header.Name

		if strings.HasSuffix(path, RegoExt) {
			module, err := ast.ParseModule(path, buf.String())
			if err != nil {
				return bundle, errors.Wrap(err, "bundle load failed")
			}
			file := ModuleFile{
				Path:   path,
				Raw:    buf.Bytes(),
				Parsed: module,
			}
			bundle.Modules = append(bundle.Modules, file)

		} else if strings.HasSuffix(path, DataFileExt) {
			var value interface{}
			if err := util.NewJSONDecoder(&buf).Decode(&value); err != nil {
				return bundle, errors.Wrapf(err, "bundle load failed on %v", path)
			}
			dirpath := strings.Trim(strings.TrimSuffix(path, DataFileExt), "/")
			var key []string
			if dirpath != "" {
				key = strings.Split(dirpath, "/")
			}
			if err := bundle.insert(key, value); err != nil {
				return bundle, errors.Wrapf(err, "bundle load failed on %v", path)
			}

		} else if strings.HasSuffix(path, ManifestExt) {
			if err := util.NewJSONDecoder(&buf).Decode(&bundle.Manifest); err != nil {
				return bundle, errors.Wrapf(err, "bundle load failed on manifest")
			}
		}
	}

	return bundle, nil
}

// Equal returns true if this bundle's contents equal the other bundle's
// contents.
func (b Bundle) Equal(other Bundle) bool {
	if !reflect.DeepEqual(b.Data, other.Data) {
		return false
	}
	if len(b.Modules) != len(other.Modules) {
		return false
	}
	for i := range b.Modules {
		if b.Modules[i].Path != other.Modules[i].Path {
			return false
		}
		if !b.Modules[i].Parsed.Equal(other.Modules[i].Parsed) {
			return false
		}
		if !bytes.Equal(b.Modules[i].Raw, other.Modules[i].Raw) {
			return false
		}
	}
	return true
}

func (b *Bundle) insert(key []string, value interface{}) error {
	if len(key) == 0 {
		obj, ok := value.(map[string]interface{})
		if !ok {
			return fmt.Errorf("root value must be object")
		}
		b.Data = obj
		return nil
	}

	obj, err := b.mkdir(key[:len(key)-1])
	if err != nil {
		return err
	}

	obj[key[len(key)-1]] = value
	return nil
}

func (b *Bundle) mkdir(key []string) (map[string]interface{}, error) {
	obj := b.Data
	for i := 0; i < len(key); i++ {
		node, ok := obj[key[i]]
		if !ok {
			node = map[string]interface{}{}
			obj[key[i]] = node
		}
		obj, ok = node.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("non-leaf value must be object")
		}
	}
	return obj, nil
}

func writeFile(tw *tar.Writer, path string, bs []byte) error {

	hdr := &tar.Header{
		Name:     "/" + strings.TrimLeft(path, "/"),
		Mode:     0600,
		Typeflag: tar.TypeReg,
		Size:     int64(len(bs)),
	}

	if err := tw.WriteHeader(hdr); err != nil {
		return err
	}

	_, err := tw.Write(bs)
	return err
}
<|endoftext|>


<commit_before>package goDLX

// Matrix is the fundamental unit in the Algorithm X implementation
// as described in [Knuth, Donald (2000). "Dancing Links". _Millenial Perspectives in Computer Science_. P159 *187*.
// Name and size only apply to columns
type Matrix struct {
	L, R, U, D, C *Matrix
	Name          string
	size          int  // count of 1s in the column
	optional      bool // optional columns do not have to be satisfied but can be only once
	head          bool // checked for the root or head node
}

// New returns an empty matrix. This creates a single head or root node to which
// all other nodes are linked. According to the algorithm, only the left and right
// values are used for the root element.
func New() *Matrix {
	n := new(Matrix)
	n.initRoot()
	return n
}

func (r *Matrix) initRoot() {
	r.L = r
	r.R = r
	r.head = true
}
<commit_msg>Refactor `New()` for naming convention<commit_after>package goDLX

// Matrix is the fundamental unit in the Algorithm X implementation
// as described in [Knuth, Donald (2000). "Dancing Links". _Millenial Perspectives in Computer Science_. P159 *187*.
// Name and size only apply to columns
type Matrix struct {
	L, R, U, D, C *Matrix
	Name          string
	size          int  // count of 1s in the column
	optional      bool // optional columns do not have to be satisfied but can be only once
	head          bool // checked for the root or head node
}

// New returns an empty matrix. This creates a single head or root node to which
// all other nodes are linked. According to the algorithm, only the left and right
// values are used for the root element.
func New() *Matrix {
	r := new(Matrix)
	r.initRoot()
	return r
}

func (r *Matrix) initRoot() {
	r.L = r
	r.R = r
	r.head = true
}
<|endoftext|>


<commit_before>// Copyright 2020 The LUCI 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 txndefer implements a filter that calls best-effort callbacks on
// successful transaction commits.
//
// Useful when an activity inside a transaction has some best-effort follow up
// that should be done once the transaction has successfully landed.
package txndefer

import (
	"context"
	"sync"

	ds "go.chromium.org/gae/service/datastore"
)

// FilterRDS installs the datastore filter into the context.
func FilterRDS(ctx context.Context) context.Context {
	return ds.AddRawFilters(ctx, func(_ context.Context, inner ds.RawInterface) ds.RawInterface {
		return filteredDS{inner}
	})
}

// Defer schedules `cb` for execution when the current transaction successfully
// lands.
//
// Intended for a best-effort non-transactional follow up to a successful
// transaction. Note that in presence of failures there's no guarantee the
// callback will be called. For example, the callback won't ever be called if
// the process crashes right after landing the transaction. Or if the
// transaction really landed, but RunInTransaction finished with "deadline
// exceeded" (or some similar) error.
//
// Callbacks are executed sequentially in the reverse order they were deferred.
// They receive the non-transactional version of the context initially passed to
// RunInTransaction so that they inherit the deadline of the entire transaction.
//
// Panics if the given context is not transactional or there's no txndefer
// filter installed.
func Defer(ctx context.Context, cb func(context.Context)) {
	state, _ := ctx.Value(&ctxKey).(*txnState)
	if state == nil {
		panic("not a transactional context or no txndefer filter installed")
	}
	state.deferCB(cb)
}

////////////////////////////////////////////////////////////////////////////////

var ctxKey = "txndefer.txnState"

type txnState struct {
	ctx context.Context // the original transaction context
	m   sync.Mutex
	cbs []func(context.Context)
}

func (s *txnState) deferCB(cb func(context.Context)) {
	s.m.Lock()
	s.cbs = append(s.cbs, cb)
	s.m.Unlock()
}

func (s *txnState) execCBs() {
	s.m.Lock()
	defer s.m.Unlock()
	if len(s.cbs) != 0 {
		ctx := ds.WithoutTransaction(s.ctx)
		for i := len(s.cbs) - 1; i >= 0; i-- {
			s.cbs[i](ctx)
		}
	}
}

type filteredDS struct {
	ds.RawInterface
}

func (fds filteredDS) RunInTransaction(f func(ctx context.Context) error, opts *ds.TransactionOptions) error {
	var state *txnState
	err := fds.RawInterface.RunInTransaction(func(ctx context.Context) error {
		state = &txnState{ctx: ctx}
		return f(context.WithValue(ctx, &ctxKey, state))
	}, opts)
	if err == nil {
		state.execCBs()
	}
	return err
}
<commit_msg>[txndefer] Remove theoretically unnecessary locking.<commit_after>// Copyright 2020 The LUCI 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 txndefer implements a filter that calls best-effort callbacks on
// successful transaction commits.
//
// Useful when an activity inside a transaction has some best-effort follow up
// that should be done once the transaction has successfully landed.
package txndefer

import (
	"context"
	"sync"

	ds "go.chromium.org/gae/service/datastore"
)

// FilterRDS installs the datastore filter into the context.
func FilterRDS(ctx context.Context) context.Context {
	return ds.AddRawFilters(ctx, func(_ context.Context, inner ds.RawInterface) ds.RawInterface {
		return filteredDS{inner}
	})
}

// Defer schedules `cb` for execution when the current transaction successfully
// lands.
//
// Intended for a best-effort non-transactional follow up to a successful
// transaction. Note that in presence of failures there's no guarantee the
// callback will be called. For example, the callback won't ever be called if
// the process crashes right after landing the transaction. Or if the
// transaction really landed, but RunInTransaction finished with "deadline
// exceeded" (or some similar) error.
//
// Callbacks are executed sequentially in the reverse order they were deferred.
// They receive the non-transactional version of the context initially passed to
// RunInTransaction so that they inherit the deadline of the entire transaction.
//
// Panics if the given context is not transactional or there's no txndefer
// filter installed.
func Defer(ctx context.Context, cb func(context.Context)) {
	state, _ := ctx.Value(&ctxKey).(*txnState)
	if state == nil {
		panic("not a transactional context or no txndefer filter installed")
	}
	state.deferCB(cb)
}

////////////////////////////////////////////////////////////////////////////////

var ctxKey = "txndefer.txnState"

type txnState struct {
	ctx context.Context // the original transaction context
	m   sync.Mutex
	cbs []func(context.Context)
}

func (s *txnState) deferCB(cb func(context.Context)) {
	s.m.Lock()
	s.cbs = append(s.cbs, cb)
	s.m.Unlock()
}

func (s *txnState) execCBs() {
	// Note: execCBs happens after RunInTransaction has finished. If it spawned
	// any goroutines, they must have been finished already too (calling Defer
	// from a goroutine that outlives a transaction is rightfully a race). Thus
	// all writes to `s.cbs` are finished already and we also passed some
	// synchronization barrier that waited for the goroutines to join. It's fine
	// to avoid locking s.m in this case saving 200ns on hot code path.
	if len(s.cbs) != 0 {
		ctx := ds.WithoutTransaction(s.ctx)
		for i := len(s.cbs) - 1; i >= 0; i-- {
			s.cbs[i](ctx)
		}
	}
}

type filteredDS struct {
	ds.RawInterface
}

func (fds filteredDS) RunInTransaction(f func(ctx context.Context) error, opts *ds.TransactionOptions) error {
	var state *txnState
	err := fds.RawInterface.RunInTransaction(func(ctx context.Context) error {
		state = &txnState{ctx: ctx}
		return f(context.WithValue(ctx, &ctxKey, state))
	}, opts)
	if err == nil {
		state.execCBs()
	}
	return err
}
<|endoftext|>


<commit_before>// Copyright 2015 Netflix, Inc.
//
// 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 main

import (
	"bufio"
	"bytes"
	"log"
	"math/rand"
	"net/http"
	_ "net/http/pprof"
	"sync"
	"time"

	"github.com/netflix/rend/client/binprot"
	"github.com/netflix/rend/client/common"
	"github.com/netflix/rend/client/f"
	"github.com/netflix/rend/client/textprot"
)

func init() {
	go http.ListenAndServe("localhost:11337", nil)
}

func main() {
	var prot common.Prot
	if f.Binary {
		prot = binprot.BinProt{}
	} else {
		prot = textprot.TextProt{}
	}

	tasks := make(chan *common.Task)
	wg := new(sync.WaitGroup)
	wg.Add(f.NumWorkers)

	// spawn worker goroutines
	for i := 0; i < f.NumWorkers; i++ {
		conn, err := common.Connect(f.Host, f.Port)
		if err != nil {
			panic(err.Error())
		}
		rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
		go worker(prot, rw, tasks, wg)
	}

	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	for i := 0; i < f.NumOps; i++ {
		// Random length between 1k and 10k
		valLen := r.Intn(9*1024) + 1024

		tasks <- &common.Task{
			Key:   common.RandData(r, f.KeyLength, false),
			Value: common.RandData(nil, valLen, true),
		}

		if i%10000 == 0 {
			log.Printf("%v\r\n", i)
		}
	}

	close(tasks)
	wg.Wait()
}

func worker(prot common.Prot, rw *bufio.ReadWriter, tasks chan *common.Task, wg *sync.WaitGroup) {
	for item := range tasks {
		// continue on even if there's errors here
		if err := prot.Set(rw, item.Key, item.Value); err != nil {
			log.Println("Error during set:", err.Error())
		}

		// pass the test if the data matches
		ret, err := prot.Get(rw, item.Key)
		if err != nil {
			log.Println("Error getting data for key", string(item.Key), ":", err.Error())
			continue
		}

		if !bytes.Equal(item.Value, ret) {
			log.Println("Data returned from server does not match!",
				"\nData len sent:", len(item.Value),
				"\nData len recv:", len(ret))
		}
	}

	wg.Done()
}
<commit_msg>Improving setget workers<commit_after>// Copyright 2015 Netflix, Inc.
//
// 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 main

import (
	"bufio"
	"bytes"
	"log"
	"math"
	"math/rand"
	"net/http"
	_ "net/http/pprof"
	"sync"
	"sync/atomic"
	"time"

	"github.com/netflix/rend/client/binprot"
	"github.com/netflix/rend/client/common"
	"github.com/netflix/rend/client/f"
	_ "github.com/netflix/rend/client/sigs"
	"github.com/netflix/rend/client/textprot"
)

func init() {
	go http.ListenAndServe("localhost:11337", nil)
}

func main() {
	var prot common.Prot
	if f.Binary {
		prot = binprot.BinProt{}
	} else {
		prot = textprot.TextProt{}
	}

	wg := new(sync.WaitGroup)
	wg.Add(f.NumWorkers)

	// create and fill key channels to drive workers
	perChan := int(math.Ceil(float64(f.NumOps) / float64(f.NumWorkers)))
	chans := make([]chan []byte, f.NumWorkers)
	for i, _ := range chans {
		chans[i] = make(chan []byte, perChan)
	}
	fillKeys(chans)

	log.Println("Done generating keys")

	start := time.Now()
	// spawn worker goroutines
	for i := 0; i < f.NumWorkers; i++ {
		conn, err := common.Connect(f.Host, f.Port)
		if err != nil {
			panic(err.Error())
		}
		rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
		go worker(prot, rw, chans[i], wg)
	}

	wg.Wait()

	log.Println("Total comm time:", time.Since(start))
}

// fills a bunch of channels round robin with keys
func fillKeys(chans []chan []byte) {
	totalCap := 0
	for _, c := range chans {
		totalCap += cap(c)
	}
	if totalCap < f.NumOps {
		panic("Channels cannot hold all the ops. Deadlock guaranteed.")
	}

	ci := 0
	key := bytes.Repeat([]byte{byte('A')}, f.KeyLength)
	for i := 0; i < f.NumOps; i++ {
		key = nextKey(key)
		chans[ci] <- key
		ci = (ci + 1) % len(chans)
	}

	// close them as they have all the data they need
	for _, c := range chans {
		close(c)
	}
}

func nextKey(key []byte) []byte {
	// make a copy to avoid touching keys in use
	temp := make([]byte, len(key))
	copy(temp, key)
	key = temp

	for i := 0; i < len(key); i++ {
		key[i] -= byte('A')
	}

	// ripple carry adder anyone?
	i := 0
	carry := true
	for carry {
		key[i] = key[i] + 1%26
		carry = key[i] == 0
		i++
	}

	for i := 0; i < len(key); i++ {
		key[i] += byte('A')
	}

	return key
}

var opCount = new(uint64)

func worker(prot common.Prot, rw *bufio.ReadWriter, keys chan []byte, wg *sync.WaitGroup) {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	for key := range keys {
		curOpCount := atomic.AddUint64(opCount, 1)
		if curOpCount%10000 == 0 {
			log.Println(curOpCount)
		}

		valLen := r.Intn(9*1024) + 1024
		value := common.RandData(nil, valLen, true)

		// continue on even if there's errors here
		if err := prot.Set(rw, key, value); err != nil {
			log.Println("Error during set:", err.Error())
		}

		// pass the test if the data matches
		ret, err := prot.Get(rw, key)
		if err != nil {
			log.Println("Error getting data for key", string(key), ":", err.Error())
			continue
		}

		if !bytes.Equal(value, ret) {
			log.Println("Data returned from server does not match!",
				"\nData len sent:", len(value),
				"\nData len recv:", len(ret))
			//log.Println("sent:", string(value))
			//log.Println("got:", string(ret))
		}
	}

	wg.Done()
}
<|endoftext|>