<commit_before>package mat64

import (
	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/matrix"
)

var (
	triDense *TriDense
	_        Matrix        = triDense
	_        Triangular    = triDense
	_        RawTriangular = triDense
)

const badTriCap = "mat64: bad capacity for TriDense"

// TriDense represents an upper or lower triangular matrix in dense storage
// format.
type TriDense struct {
	mat blas64.Triangular
	cap int
}

type Triangular interface {
	Matrix
	// Triangular returns the number of rows/columns in the matrix and if it is
	// an upper triangular matrix.
	Triangle() (n int, upper bool)

	// TTri is the equivalent of the T() method in the Matrix interface but
	// guarantees the transpose is of triangular type.
	TTri() Triangular
}

type RawTriangular interface {
	RawTriangular() blas64.Triangular
}

var (
	_ Matrix     = TransposeTri{}
	_ Triangular = TransposeTri{}
)

// TransposeTri is a type for performing an implicit transpose of a Triangular
// matrix. It implements the Triangular interface, returning values from the
// transpose of the matrix within.
type TransposeTri struct {
	Triangular Triangular
}

// At returns the value of the element at row i and column j of the transposed
// matrix, that is, row j and column i of the Triangular field.
func (t TransposeTri) At(i, j int) float64 {
	return t.Triangular.At(j, i)
}

// Dims returns the dimensions of the transposed matrix. Triangular matrices are
// square and thus this is the same size as the original Triangular.
func (t TransposeTri) Dims() (r, c int) {
	c, r = t.Triangular.Dims()
	return r, c
}

// T performs an implicit transpose by returning the Triangular field.
func (t TransposeTri) T() Matrix {
	return t.Triangular
}

// Triangle returns the number of rows/columns in the matrix and if it is
// an upper triangular matrix.
func (t TransposeTri) Triangle() (int, bool) {
	n, upper := t.Triangular.Triangle()
	return n, !upper
}

// TTri performs an implicit transpose by returning the Triangular field.
func (t TransposeTri) TTri() Triangular {
	return t.Triangular
}

// Untranspose returns the Triangular field.
func (t TransposeTri) Untranspose() Matrix {
	return t.Triangular
}

// NewTriangular constructs an n x n triangular matrix. The constructed matrix
// is upper triangular if upper == true and lower triangular otherwise.
// If len(mat) == n * n, mat will be used to hold the underlying data, if
// mat == nil, new data will be allocated, and will panic if neither of these
// cases is true.
// The underlying data representation is the same as that of a Dense matrix,
// except the values of the entries in the opposite half are completely ignored.
func NewTriDense(n int, upper bool, mat []float64) *TriDense {
	if n < 0 {
		panic("mat64: negative dimension")
	}
	if mat != nil && len(mat) != n*n {
		panic(matrix.ErrShape)
	}
	if mat == nil {
		mat = make([]float64, n*n)
	}
	uplo := blas.Lower
	if upper {
		uplo = blas.Upper
	}
	return &TriDense{
		mat: blas64.Triangular{
			N:      n,
			Stride: n,
			Data:   mat,
			Uplo:   uplo,
			Diag:   blas.NonUnit,
		},
		cap: n,
	}
}

func (t *TriDense) Dims() (r, c int) {
	return t.mat.N, t.mat.N
}

// Triangle returns the dimension of t and whether t is an upper triangular
// matrix. The returned boolean upper is only valid when n is not zero.
func (t *TriDense) Triangle() (n int, upper bool) {
	return t.mat.N, !t.isZero() && t.isUpper()
}

func (t *TriDense) isUpper() bool {
	return isUpperUplo(t.mat.Uplo)
}

func isUpperUplo(u blas.Uplo) bool {
	switch u {
	case blas.Upper:
		return true
	case blas.Lower:
		return false
	default:
		panic(badTriangle)
	}
}

// asSymBlas returns the receiver restructured as a blas64.Symmetric with the
// same backing memory. Panics if the receiver is unit.
// This returns a blas64.Symmetric and not a *SymDense because SymDense can only
// be upper triangular.
func (t *TriDense) asSymBlas() blas64.Symmetric {
	if t.mat.Diag == blas.Unit {
		panic("mat64: cannot convert unit TriDense into blas64.Symmetric")
	}
	return blas64.Symmetric{
		N:      t.mat.N,
		Stride: t.mat.Stride,
		Data:   t.mat.Data,
		Uplo:   t.mat.Uplo,
	}
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
func (t *TriDense) T() Matrix {
	return Transpose{t}
}

// TTri performs an implicit transpose by returning the receiver inside a TransposeTri.
func (t *TriDense) TTri() Triangular {
	return TransposeTri{t}
}

func (t *TriDense) RawTriangular() blas64.Triangular {
	return t.mat
}

func (t *TriDense) isZero() bool {
	// It must be the case that t.Dims() returns
	// zeros in this case. See comment in Reset().
	return t.mat.Stride == 0
}

// reuseAS resizes a zero receiver to an n×n triangular matrix with the given
// orientation. If the receiver is non-zero, reuseAs checks that the receiver
// is the correct size and orientation.
func (t *TriDense) reuseAs(n int, ul blas.Uplo) {
	if t.mat.N > t.cap {
		panic(badTriCap)
	}
	if t.isZero() {
		t.mat = blas64.Triangular{
			N:      n,
			Stride: n,
			Diag:   blas.NonUnit,
			Data:   use(t.mat.Data, n*n),
			Uplo:   ul,
		}
		t.cap = n
		return
	}
	if t.mat.N != n || t.mat.Uplo != ul {
		panic(matrix.ErrShape)
	}
}

// Reset zeros the dimensions of the matrix so that it can be reused as the
// receiver of a dimensionally restricted operation.
//
// See the Reseter interface for more information.
func (t *TriDense) Reset() {
	// No change of Stride, N to 0 may
	// be made unless both are set to 0.
	t.mat.N, t.mat.Stride = 0, 0
	// Defensively zero Uplo to ensure
	// it is set correctly later.
	t.mat.Uplo = 0
	t.mat.Data = t.mat.Data[:0]
}

// Copy makes a copy of elements of a into the receiver. It is similar to the
// built-in copy; it copies as much as the overlap between the two matrices and
// returns the number of rows and columns it copied. Only elements within the
// receiver's non-zero triangle are set.
//
// See the Copier interface for more information.
func (t *TriDense) Copy(a Matrix) (r, c int) {
	r, c = a.Dims()
	r = min(r, t.mat.N)
	c = min(c, t.mat.N)
	if r == 0 || c == 0 {
		return 0, 0
	}

	switch a := a.(type) {
	case RawMatrixer:
		amat := a.RawMatrix()
		if t.isUpper() {
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
			}
		} else {
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
			}
		}
	case RawTriangular:
		amat := a.RawTriangular()
		aIsUpper := isUpperUplo(amat.Uplo)
		tIsUpper := t.isUpper()
		switch {
		case tIsUpper && aIsUpper:
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
			}
		case !tIsUpper && !aIsUpper:
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
			}
		default:
			for i := 0; i < r; i++ {
				t.set(i, i, amat.Data[i*amat.Stride+i])
			}
		}
	case Vectorer:
		row := make([]float64, c)
		if t.isUpper() {
			for i := 0; i < r; i++ {
				a.Row(row, i)
				copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], row[i:])
			}
		} else {
			for i := 0; i < r; i++ {
				a.Row(row, i)
				copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], row[:i+1])
			}
		}
	default:
		isUpper := t.isUpper()
		for i := 0; i < r; i++ {
			if isUpper {
				for j := i; j < c; j++ {
					t.set(i, j, a.At(i, j))
				}
			} else {
				for j := 0; j <= i; j++ {
					t.set(i, j, a.At(i, j))
				}
			}
		}
	}

	return r, c
}

// getBlasTriangular transforms t into a blas64.Triangular. If t is a RawTriangular,
// the direct matrix representation is returned, otherwise t is copied into one.
func getBlasTriangular(t Triangular) blas64.Triangular {
	n, upper := t.Triangle()
	rt, ok := t.(RawTriangular)
	if ok {
		return rt.RawTriangular()
	}
	ta := blas64.Triangular{
		N:      n,
		Stride: n,
		Diag:   blas.NonUnit,
		Data:   make([]float64, n*n),
	}
	if upper {
		ta.Uplo = blas.Upper
		for i := 0; i < n; i++ {
			for j := i; j < n; j++ {
				ta.Data[i*n+j] = t.At(i, j)
			}
		}
		return ta
	}
	ta.Uplo = blas.Lower
	for i := 0; i < n; i++ {
		for j := 0; j < i; j++ {
			ta.Data[i*n+j] = t.At(i, j)
		}
	}
	return ta
}

// copySymIntoTriangle copies a symmetric matrix into a TriDense
func copySymIntoTriangle(t *TriDense, s Symmetric) {
	n, upper := t.Triangle()
	ns := s.Symmetric()
	if n != ns {
		panic("mat64: triangle size mismatch")
	}
	ts := t.mat.Stride
	if rs, ok := s.(RawSymmetricer); ok {
		sd := rs.RawSymmetric()
		ss := sd.Stride
		if upper {
			if sd.Uplo == blas.Upper {
				for i := 0; i < n; i++ {
					copy(t.mat.Data[i*ts+i:i*ts+n], sd.Data[i*ss+i:i*ss+n])
				}
				return
			}
			for i := 0; i < n; i++ {
				for j := i; j < n; j++ {
					t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
				}
				return
			}
		}
		if sd.Uplo == blas.Upper {
			for i := 0; i < n; i++ {
				for j := 0; j <= i; j++ {
					t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
				}
			}
			return
		}
		for i := 0; i < n; i++ {
			copy(t.mat.Data[i*ts:i*ts+i+1], sd.Data[i*ss:i*ss+i+1])
		}
		return
	}
	if upper {
		for i := 0; i < n; i++ {
			for j := i; j < n; j++ {
				t.mat.Data[i*ts+j] = s.At(i, j)
			}
		}
		return
	}
	for i := 0; i < n; i++ {
		for j := 0; j <= i; j++ {
			t.mat.Data[i*ts+j] = s.At(i, j)
		}
	}
}
<commit_msg>mat64: fix comment for NewTriDense<commit_after>package mat64

import (
	"github.com/gonum/blas"
	"github.com/gonum/blas/blas64"
	"github.com/gonum/matrix"
)

var (
	triDense *TriDense
	_        Matrix        = triDense
	_        Triangular    = triDense
	_        RawTriangular = triDense
)

const badTriCap = "mat64: bad capacity for TriDense"

// TriDense represents an upper or lower triangular matrix in dense storage
// format.
type TriDense struct {
	mat blas64.Triangular
	cap int
}

type Triangular interface {
	Matrix
	// Triangular returns the number of rows/columns in the matrix and if it is
	// an upper triangular matrix.
	Triangle() (n int, upper bool)

	// TTri is the equivalent of the T() method in the Matrix interface but
	// guarantees the transpose is of triangular type.
	TTri() Triangular
}

type RawTriangular interface {
	RawTriangular() blas64.Triangular
}

var (
	_ Matrix     = TransposeTri{}
	_ Triangular = TransposeTri{}
)

// TransposeTri is a type for performing an implicit transpose of a Triangular
// matrix. It implements the Triangular interface, returning values from the
// transpose of the matrix within.
type TransposeTri struct {
	Triangular Triangular
}

// At returns the value of the element at row i and column j of the transposed
// matrix, that is, row j and column i of the Triangular field.
func (t TransposeTri) At(i, j int) float64 {
	return t.Triangular.At(j, i)
}

// Dims returns the dimensions of the transposed matrix. Triangular matrices are
// square and thus this is the same size as the original Triangular.
func (t TransposeTri) Dims() (r, c int) {
	c, r = t.Triangular.Dims()
	return r, c
}

// T performs an implicit transpose by returning the Triangular field.
func (t TransposeTri) T() Matrix {
	return t.Triangular
}

// Triangle returns the number of rows/columns in the matrix and if it is
// an upper triangular matrix.
func (t TransposeTri) Triangle() (int, bool) {
	n, upper := t.Triangular.Triangle()
	return n, !upper
}

// TTri performs an implicit transpose by returning the Triangular field.
func (t TransposeTri) TTri() Triangular {
	return t.Triangular
}

// Untranspose returns the Triangular field.
func (t TransposeTri) Untranspose() Matrix {
	return t.Triangular
}

// NewTriDense constructs an n x n triangular matrix. The constructed matrix
// is upper triangular if upper == true and lower triangular otherwise.
// If len(mat) == n * n, mat will be used to hold the underlying data, if
// mat == nil, new data will be allocated, and will panic if neither of these
// cases is true.
// The underlying data representation is the same as that of a Dense matrix,
// except the values of the entries in the opposite half are completely ignored.
func NewTriDense(n int, upper bool, mat []float64) *TriDense {
	if n < 0 {
		panic("mat64: negative dimension")
	}
	if mat != nil && len(mat) != n*n {
		panic(matrix.ErrShape)
	}
	if mat == nil {
		mat = make([]float64, n*n)
	}
	uplo := blas.Lower
	if upper {
		uplo = blas.Upper
	}
	return &TriDense{
		mat: blas64.Triangular{
			N:      n,
			Stride: n,
			Data:   mat,
			Uplo:   uplo,
			Diag:   blas.NonUnit,
		},
		cap: n,
	}
}

func (t *TriDense) Dims() (r, c int) {
	return t.mat.N, t.mat.N
}

// Triangle returns the dimension of t and whether t is an upper triangular
// matrix. The returned boolean upper is only valid when n is not zero.
func (t *TriDense) Triangle() (n int, upper bool) {
	return t.mat.N, !t.isZero() && t.isUpper()
}

func (t *TriDense) isUpper() bool {
	return isUpperUplo(t.mat.Uplo)
}

func isUpperUplo(u blas.Uplo) bool {
	switch u {
	case blas.Upper:
		return true
	case blas.Lower:
		return false
	default:
		panic(badTriangle)
	}
}

// asSymBlas returns the receiver restructured as a blas64.Symmetric with the
// same backing memory. Panics if the receiver is unit.
// This returns a blas64.Symmetric and not a *SymDense because SymDense can only
// be upper triangular.
func (t *TriDense) asSymBlas() blas64.Symmetric {
	if t.mat.Diag == blas.Unit {
		panic("mat64: cannot convert unit TriDense into blas64.Symmetric")
	}
	return blas64.Symmetric{
		N:      t.mat.N,
		Stride: t.mat.Stride,
		Data:   t.mat.Data,
		Uplo:   t.mat.Uplo,
	}
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
func (t *TriDense) T() Matrix {
	return Transpose{t}
}

// TTri performs an implicit transpose by returning the receiver inside a TransposeTri.
func (t *TriDense) TTri() Triangular {
	return TransposeTri{t}
}

func (t *TriDense) RawTriangular() blas64.Triangular {
	return t.mat
}

func (t *TriDense) isZero() bool {
	// It must be the case that t.Dims() returns
	// zeros in this case. See comment in Reset().
	return t.mat.Stride == 0
}

// reuseAS resizes a zero receiver to an n×n triangular matrix with the given
// orientation. If the receiver is non-zero, reuseAs checks that the receiver
// is the correct size and orientation.
func (t *TriDense) reuseAs(n int, ul blas.Uplo) {
	if t.mat.N > t.cap {
		panic(badTriCap)
	}
	if t.isZero() {
		t.mat = blas64.Triangular{
			N:      n,
			Stride: n,
			Diag:   blas.NonUnit,
			Data:   use(t.mat.Data, n*n),
			Uplo:   ul,
		}
		t.cap = n
		return
	}
	if t.mat.N != n || t.mat.Uplo != ul {
		panic(matrix.ErrShape)
	}
}

// Reset zeros the dimensions of the matrix so that it can be reused as the
// receiver of a dimensionally restricted operation.
//
// See the Reseter interface for more information.
func (t *TriDense) Reset() {
	// No change of Stride, N to 0 may
	// be made unless both are set to 0.
	t.mat.N, t.mat.Stride = 0, 0
	// Defensively zero Uplo to ensure
	// it is set correctly later.
	t.mat.Uplo = 0
	t.mat.Data = t.mat.Data[:0]
}

// Copy makes a copy of elements of a into the receiver. It is similar to the
// built-in copy; it copies as much as the overlap between the two matrices and
// returns the number of rows and columns it copied. Only elements within the
// receiver's non-zero triangle are set.
//
// See the Copier interface for more information.
func (t *TriDense) Copy(a Matrix) (r, c int) {
	r, c = a.Dims()
	r = min(r, t.mat.N)
	c = min(c, t.mat.N)
	if r == 0 || c == 0 {
		return 0, 0
	}

	switch a := a.(type) {
	case RawMatrixer:
		amat := a.RawMatrix()
		if t.isUpper() {
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
			}
		} else {
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
			}
		}
	case RawTriangular:
		amat := a.RawTriangular()
		aIsUpper := isUpperUplo(amat.Uplo)
		tIsUpper := t.isUpper()
		switch {
		case tIsUpper && aIsUpper:
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], amat.Data[i*amat.Stride+i:i*amat.Stride+c])
			}
		case !tIsUpper && !aIsUpper:
			for i := 0; i < r; i++ {
				copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], amat.Data[i*amat.Stride:i*amat.Stride+i+1])
			}
		default:
			for i := 0; i < r; i++ {
				t.set(i, i, amat.Data[i*amat.Stride+i])
			}
		}
	case Vectorer:
		row := make([]float64, c)
		if t.isUpper() {
			for i := 0; i < r; i++ {
				a.Row(row, i)
				copy(t.mat.Data[i*t.mat.Stride+i:i*t.mat.Stride+c], row[i:])
			}
		} else {
			for i := 0; i < r; i++ {
				a.Row(row, i)
				copy(t.mat.Data[i*t.mat.Stride:i*t.mat.Stride+i+1], row[:i+1])
			}
		}
	default:
		isUpper := t.isUpper()
		for i := 0; i < r; i++ {
			if isUpper {
				for j := i; j < c; j++ {
					t.set(i, j, a.At(i, j))
				}
			} else {
				for j := 0; j <= i; j++ {
					t.set(i, j, a.At(i, j))
				}
			}
		}
	}

	return r, c
}

// getBlasTriangular transforms t into a blas64.Triangular. If t is a RawTriangular,
// the direct matrix representation is returned, otherwise t is copied into one.
func getBlasTriangular(t Triangular) blas64.Triangular {
	n, upper := t.Triangle()
	rt, ok := t.(RawTriangular)
	if ok {
		return rt.RawTriangular()
	}
	ta := blas64.Triangular{
		N:      n,
		Stride: n,
		Diag:   blas.NonUnit,
		Data:   make([]float64, n*n),
	}
	if upper {
		ta.Uplo = blas.Upper
		for i := 0; i < n; i++ {
			for j := i; j < n; j++ {
				ta.Data[i*n+j] = t.At(i, j)
			}
		}
		return ta
	}
	ta.Uplo = blas.Lower
	for i := 0; i < n; i++ {
		for j := 0; j < i; j++ {
			ta.Data[i*n+j] = t.At(i, j)
		}
	}
	return ta
}

// copySymIntoTriangle copies a symmetric matrix into a TriDense
func copySymIntoTriangle(t *TriDense, s Symmetric) {
	n, upper := t.Triangle()
	ns := s.Symmetric()
	if n != ns {
		panic("mat64: triangle size mismatch")
	}
	ts := t.mat.Stride
	if rs, ok := s.(RawSymmetricer); ok {
		sd := rs.RawSymmetric()
		ss := sd.Stride
		if upper {
			if sd.Uplo == blas.Upper {
				for i := 0; i < n; i++ {
					copy(t.mat.Data[i*ts+i:i*ts+n], sd.Data[i*ss+i:i*ss+n])
				}
				return
			}
			for i := 0; i < n; i++ {
				for j := i; j < n; j++ {
					t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
				}
				return
			}
		}
		if sd.Uplo == blas.Upper {
			for i := 0; i < n; i++ {
				for j := 0; j <= i; j++ {
					t.mat.Data[i*ts+j] = sd.Data[j*ss+i]
				}
			}
			return
		}
		for i := 0; i < n; i++ {
			copy(t.mat.Data[i*ts:i*ts+i+1], sd.Data[i*ss:i*ss+i+1])
		}
		return
	}
	if upper {
		for i := 0; i < n; i++ {
			for j := i; j < n; j++ {
				t.mat.Data[i*ts+j] = s.At(i, j)
			}
		}
		return
	}
	for i := 0; i < n; i++ {
		for j := 0; j <= i; j++ {
			t.mat.Data[i*ts+j] = s.At(i, j)
		}
	}
}
<|endoftext|>


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

package service

import (
	"log"
	"net"
	"net/rpc"
)

type Type uint

// Monsti service types.
const (
	MonstiService Type = iota
	/*
		InfoService Type = iota
		DataService
		LoginService
		NodeService
		MailService
	*/
)

func (t Type) String() string {
	serviceNames := [...]string{
		"Monsti"}
	return serviceNames[t]
}

// Client represents the rpc connection to a service.
type Client struct {
	RPCClient *rpc.Client
	// Error holds the last error if any.
	Error error
	// Id is a unique identifier for this client.
	Id string
}

// Connect establishes a new RPC connection to the given service.
//
// path is the unix domain socket path to the service.
func (s *Client) Connect(path string) error {
	conn, err := net.Dial("unix", path)
	if err != nil {
		return err
	}
	s.Id = conn.LocalAddr().String()
	log.Println(s.Id) // DEBUG
	s.RPCClient = rpc.NewClient(conn)
	return nil
}

// Close closes the client's RPC connection.
func (s *Client) Close() error {
	return s.RPCClient.Close()
}
<commit_msg>Remove debug message.<commit_after>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

package service

import (
	"net"
	"net/rpc"
)

type Type uint

// Monsti service types.
const (
	MonstiService Type = iota
	/*
		InfoService Type = iota
		DataService
		LoginService
		NodeService
		MailService
	*/
)

func (t Type) String() string {
	serviceNames := [...]string{
		"Monsti"}
	return serviceNames[t]
}

// Client represents the rpc connection to a service.
type Client struct {
	RPCClient *rpc.Client
	// Error holds the last error if any.
	Error error
	// Id is a unique identifier for this client.
	Id string
}

// Connect establishes a new RPC connection to the given service.
//
// path is the unix domain socket path to the service.
func (s *Client) Connect(path string) error {
	conn, err := net.Dial("unix", path)
	if err != nil {
		return err
	}
	s.Id = conn.LocalAddr().String()
	// TODO Fix id
	s.RPCClient = rpc.NewClient(conn)
	return nil
}

// Close closes the client's RPC connection.
func (s *Client) Close() error {
	return s.RPCClient.Close()
}
<|endoftext|>


<commit_before>// meow_hash_set.go

package meow-data-structures

import (
	"fmt"
	"bytes"
	"sync"
)

type meowHashSet struct {
	meowLock *sync.Mutex
	stuffs map[interface{}]interface{}
}

// meowNewHashSet
func meowNewHashSet() *meowHashSet {
	meowInstance := &meowHashSet{}
	meowInstance.meowLock = &sync.Mutex{}
	meowInstance.stuffs = make(map[interface{}]interface{})
	return meowInstance
}

// meowLen
func (my *meowHashSet) meowLen() int {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	return meowLen(my.stuffs)
}

// slicing
func (my *meowHashSet) meowSlice() []interface{} {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	var out []interface{}
	for k := range my.stuffs {
		out = append(out, k)
	}
	return out
}

// if empty
func (my *meowHashSet) meowEmpty() bool {
	return my.meowLen() == 0
}

// meowAdd
func (my *meowHashSet) meowAdd(objects ...interface{}) {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	for o := range objects {
		my.stuffs[o] = true
	}
}

// meowFetch
func (my *meowHashSet) meowFetch(k interface{}) interface{} {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	return my.stuffs[k]
}

// meowRegisters
func (my *meowHashSet) meowRegisters(k interface{}) bool {
	return my.meowFetch(k) != nil
}

// meowRemove
func (my *meowHashSet) meowRemove(k interface{}) bool {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()

	findOk := my.stuffs[k]
	if findOk != nil {
		delete(my.stuffs, k)
		return true
	} else {
		return false
	}
}

// resetting
func (my *meowHashSet) meowReset() {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	my.stuffs = make(map[interface{}]interface{})
}<commit_msg>add meow_hash_set<commit_after>// meow_hash_set.go

package meow-data-structures

import (
	"fmt"
	"bytes"
	"sync"
)

type meowHashSet struct {
	meowLock *sync.Mutex
	stuffs map[interface{}]interface{}
}

// meowNewHashSet
func meowNewHashSet() *meowHashSet {
	meowInstance := &meowHashSet{}
	meowInstance.meowLock = &sync.Mutex{}
	meowInstance.stuffs = make(map[interface{}]interface{})
	return meowInstance
}

// meowLen
func (my *meowHashSet) meowLen() int {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	return meowLen(my.stuffs)
}

// slicing
func (my *meowHashSet) meowSlice() []interface{} {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	var out []interface{}
	for k := range my.stuffs {
		out = append(out, k)
	}
	return out
}

// if empty
func (my *meowHashSet) meowEmpty() bool {
	return my.meowLen() == 0
}

// meowAdd
func (my *meowHashSet) meowAdd(objects ...interface{}) {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	for o := range objects {
		my.stuffs[o] = true
	}
}

// meowFetch
func (my *meowHashSet) meowFetch(k interface{}) interface{} {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	return my.stuffs[k]
}

// meowRegisters
func (my *meowHashSet) meowRegisters(k interface{}) bool {
	return my.meowFetch(k) != nil
}

// meowRemove
func (my *meowHashSet) meowRemove(k interface{}) bool {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()

	findOk := my.stuffs[k]
	if findOk != nil {
		delete(my.stuffs, k)
		return true
	} else {
		return false
	}
}

// resetting
func (my *meowHashSet) meowReset() {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	my.stuffs = make(map[interface{}]interface{})
}

// meowString
func (my *meowHashSet) meowString() string {
	my.meowLock.Lock()
	defer my.meowLock.Unlock()
	var meowBuffer bytes.Buffer
	x := 0
	for k := range my.stuffs {
		meowStrfy := fmt.Sprintf("%s", k)
		meowBuffer.WriteString(meowStrfy)
		if x != meowLen(my.stuffs)-1 {
			meowBuffer.WriteString(", ")
		}
		x++
	}
	return fmt.Sprintf("{ %s }", meowBuffer.meowString())
}<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.65"
<commit_msg>functions: 0.3.66 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.66"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.29"
<commit_msg>functions: 0.3.30 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.30"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.708"
<commit_msg>fnserver: v0.3.709 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.709"
<|endoftext|>


<commit_before>// errchk $G $D/$F.go

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

package main
type I int
type S struct { f map[I]int }
var v1 = S{ make(map[int]int) }		// OK--names are ignored.
var v2 map[I]int = map[int]int{}	// OK.
var v3 = S{ make(map[uint]int) }	// ERROR "cannot|illegal|incompatible|wrong"
<commit_msg>We should not silently permit a named type to match an unnamed type.  This is OK in a conversion but not in an assignment.<commit_after>// errchk $G $D/$F.go

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

package main
type I int
type S struct { f map[I]int }
var v1 = S{ make(map[int]int) }		// ERROR "cannot|illegal|incompatible|wrong"
var v2 map[I]int = map[int]int{}	// ERROR "cannot|illegal|incompatible|wrong"
var v3 = S{ make(map[uint]int) }	// ERROR "cannot|illegal|incompatible|wrong"
<|endoftext|>


<commit_before>package meep_test

import (
	"fmt"
	"os"
	"runtime"
	"testing"

	"."
	"./fixtures"
)

var cwd, _ = os.Getwd()

var use14fnnames bool

func init() {
	gover := runtime.Version()
	fmt.Fprintf(os.Stderr, "go version reports as %q\n", gover)
	// I have truely minimal desire to parse this "well".
	// If it's not recognized, we'll assume it's new.
	if gover[0:4] != "go1." {
		return
	}
	switch gover[4] {
	case '0', '1', '2', '3', '4':
		use14fnnames = true
	}
}

type stackFrameExpectation struct {
	n      int
	file   string
	line   int
	func14 string
	func15 string
}

func TestStacksStraightforward(t *testing.T) {
	here := 40
	var result meep.Stack
	fn := func() {
		result = *(meep.CaptureStack())
	}
	fixtures.WheeOne(fn)
	expects := []stackFrameExpectation{
		{0, cwd + "/stackinfo_test.go", here + 3, "meep_test.func·001", "meep_test.TestStacksStraightforward.func1"}, // right here, where we call `CaptureStack`
		{1, cwd + "/fixtures/stack1.go", 9, "", "fixtures.wheeTwo"},                                                  // should be in the body of the func
		{2, cwd + "/fixtures/stack1.go", 5, "", "fixtures.WheeOne"},                                                  // should be in the body of the func
		{3, cwd + "/stackinfo_test.go", here + 5, "", "meep_test.TestStacksStraightforward"},                         // right here, where we call `fixtures.*`
		// No need to get overly precise about line numbers in the stdlib:
		//{4, "/usr/local/go/src/testing/testing.go", 447, "", "testing.tRunner"},
		//{5, "/usr/local/go/src/runtime/asm_amd64.s", 2232, "", "runtime.goexit"},
	}
	expectLen := len(expects) + 2
	assertStack(t, result, expects, expectLen)
}

func TestStacksPlusDeferral(t *testing.T) {
	here := 60
	var result meep.Stack
	fn := func() {
		result = *(meep.CaptureStack())
	}
	fixtures.WheeTree(fn)
	expects := []stackFrameExpectation{
		// note the total lack of 'wheeTwo'; it's called, but already returned before the defer path is hit, so of course it's absent here.
		{0, cwd + "/stackinfo_test.go", here + 3, "meep_test.func·002", "meep_test.TestStacksPlusDeferral.func1"}, // right here, where we call `CaptureStack`
		{1, cwd + "/fixtures/stack1.go", 19, "", "fixtures.wheedee"},                                              // should be in the body of the func (natch, the declare location -- the defer location never shows up; that's not a new func)
		{2, cwd + "/fixtures/stack1.go", 16, "", "fixtures.WheeTree"},                                             // golang considers 'defer' to run on the last line of the parent func.  even if that's "}\n".
		{3, cwd + "/stackinfo_test.go", here + 5, "", "meep_test.TestStacksPlusDeferral"},                         // right here, where we call `fixtures.*`
		// No need to get overly precise about line numbers in the stdlib:
		//{4, "/usr/local/go/src/testing/testing.go", 447, "", "testing.tRunner"},
		//{5, "/usr/local/go/src/runtime/asm_amd64.s", 2232, "", "runtime.goexit"},
	}
	expectLen := len(expects) + 2
	assertStack(t, result, expects, expectLen)
}

func TestStacksPanickingInDefersOhMy(t *testing.T) {
	here := 81
	var result meep.Stack
	fixtures.BeesBuzz(func() {
		result = *(meep.CaptureStack())
	})
	expects := []stackFrameExpectation{
		// note the total lack of reference to where "recover" is called.  (That happened after the stack capture... not that that really matters;
		//   if you flip the recover before the BeesBuzz defer'd func's call to our thunk, this thing on line 9 just moves to 10, that's it -- there's no other flow change.)
		{0, cwd + "/stackinfo_test.go", here + 3, "meep_test.func·003", "meep_test.TestStacksPanickingInDefersOhMy.func1"}, // right here, where we call `CaptureStack` in our thunk
		{1, cwd + "/fixtures/stack2.go", 9, "fixtures.func·002", "fixtures.BeesBuzz.func1"},                                // the line in the deferred function that called our thunk
		// No need to get overly precise about line numbers in the stdlib:
		//{2, "/usr/local/go/src/runtime/asm_amd64.s", 401, "", "runtime.call16"}, // if this isn't a single line on some platforms... uff.
		//{3, "/usr/local/go/src/runtime/panic.go", 387, "", "runtime.gopanic"},  // it might be reasonable to detect these and elide everything following from `runtime.*`.
		{4, cwd + "/fixtures/stack2.go", 22, "", "fixtures.buzzkill"},                              // the line that panicked!
		{5, cwd + "/fixtures/stack2.go", 19, "", "fixtures.beesWuz"},                               // the trailing `}` of `beesWuz`, because we left it via defer
		{6, cwd + "/fixtures/stack2.go", 14, "", "fixtures.BeesBuzz"},                              // the body line the calls down to `beesWuz`
		{7, cwd + "/stackinfo_test.go", here + 4, "", "meep_test.TestStacksPanickingInDefersOhMy"}, // obtw!  when we split the `fixtures.*()` *invocation* across lines, this becomes the last one!
		// No need to get overly precise about line numbers in the stdlib",
		//{8, "/usr/local/go/src/testing/testing.go", 447, "", "testing.tRunner"},
		//{9, "/usr/local/go/src/runtime/asm_amd64.s", 2232, "", "runtime.goexit"},
	}
	expectLen := len(expects) + 4
	assertStack(t, result, expects, expectLen)
}

func assertStack(t *testing.T, result meep.Stack, expects []stackFrameExpectation, expectLen int) {
	// Some quick cleanup on the expectations:
	// If no exceptions were specified, the old 1.4 funcname is expected to be same as the new
	for i, ex := range expects {
		if ex.func14 == "" {
			expects[i].func14 = ex.func15
		}
	}

	// Assertions!
	for _, tr := range expects {
		file, line, fnname := result.Frames[tr.n].Where()
		if file != tr.file {
			t.Errorf("Stack[%d] file should be %q, was %q", tr.n, tr.file, file)
		}
		if line != tr.line {
			t.Errorf("Stack[%d] line should be %d, was %d", tr.n, tr.line, line)
		}
		expectedFnname := tr.func15
		if use14fnnames {
			expectedFnname = tr.func14
		}
		if fnname != expectedFnname {
			t.Errorf("Stack[%d] func name should be %q, was %q", tr.n, expectedFnname, fnname)
		}
	}
	for i, fr := range result.Frames {
		if i < expectLen {
			continue
		}
		t.Errorf("Stack[%d] was expected to be empty, was %q", i, fr.String())
	}
}
<commit_msg>Apparently we count from 2 now.<commit_after>package meep_test

import (
	"fmt"
	"os"
	"runtime"
	"testing"

	"."
	"./fixtures"
)

var cwd, _ = os.Getwd()

var use14fnnames bool

func init() {
	gover := runtime.Version()
	fmt.Fprintf(os.Stderr, "go version reports as %q\n", gover)
	// I have truely minimal desire to parse this "well".
	// If it's not recognized, we'll assume it's new.
	if gover[0:4] != "go1." {
		return
	}
	switch gover[4] {
	case '0', '1', '2', '3', '4':
		use14fnnames = true
	}
}

type stackFrameExpectation struct {
	n      int
	file   string
	line   int
	func14 string
	func15 string
}

func TestStacksStraightforward(t *testing.T) {
	here := 40
	var result meep.Stack
	fn := func() {
		result = *(meep.CaptureStack())
	}
	fixtures.WheeOne(fn)
	expects := []stackFrameExpectation{
		{0, cwd + "/stackinfo_test.go", here + 3, "meep_test.func·002", "meep_test.TestStacksStraightforward.func1"}, // right here, where we call `CaptureStack`
		{1, cwd + "/fixtures/stack1.go", 9, "", "fixtures.wheeTwo"},                                                  // should be in the body of the func
		{2, cwd + "/fixtures/stack1.go", 5, "", "fixtures.WheeOne"},                                                  // should be in the body of the func
		{3, cwd + "/stackinfo_test.go", here + 5, "", "meep_test.TestStacksStraightforward"},                         // right here, where we call `fixtures.*`
		// No need to get overly precise about line numbers in the stdlib:
		//{4, "/usr/local/go/src/testing/testing.go", 447, "", "testing.tRunner"},
		//{5, "/usr/local/go/src/runtime/asm_amd64.s", 2232, "", "runtime.goexit"},
	}
	expectLen := len(expects) + 2
	assertStack(t, result, expects, expectLen)
}

func TestStacksPlusDeferral(t *testing.T) {
	here := 60
	var result meep.Stack
	fn := func() {
		result = *(meep.CaptureStack())
	}
	fixtures.WheeTree(fn)
	expects := []stackFrameExpectation{
		// note the total lack of 'wheeTwo'; it's called, but already returned before the defer path is hit, so of course it's absent here.
		{0, cwd + "/stackinfo_test.go", here + 3, "meep_test.func·003", "meep_test.TestStacksPlusDeferral.func1"}, // right here, where we call `CaptureStack`
		{1, cwd + "/fixtures/stack1.go", 19, "", "fixtures.wheedee"},                                              // should be in the body of the func (natch, the declare location -- the defer location never shows up; that's not a new func)
		{2, cwd + "/fixtures/stack1.go", 16, "", "fixtures.WheeTree"},                                             // golang considers 'defer' to run on the last line of the parent func.  even if that's "}\n".
		{3, cwd + "/stackinfo_test.go", here + 5, "", "meep_test.TestStacksPlusDeferral"},                         // right here, where we call `fixtures.*`
		// No need to get overly precise about line numbers in the stdlib:
		//{4, "/usr/local/go/src/testing/testing.go", 447, "", "testing.tRunner"},
		//{5, "/usr/local/go/src/runtime/asm_amd64.s", 2232, "", "runtime.goexit"},
	}
	expectLen := len(expects) + 2
	assertStack(t, result, expects, expectLen)
}

func TestStacksPanickingInDefersOhMy(t *testing.T) {
	here := 81
	var result meep.Stack
	fixtures.BeesBuzz(func() {
		result = *(meep.CaptureStack())
	})
	expects := []stackFrameExpectation{
		// note the total lack of reference to where "recover" is called.  (That happened after the stack capture... not that that really matters;
		//   if you flip the recover before the BeesBuzz defer'd func's call to our thunk, this thing on line 9 just moves to 10, that's it -- there's no other flow change.)
		{0, cwd + "/stackinfo_test.go", here + 3, "meep_test.func·004", "meep_test.TestStacksPanickingInDefersOhMy.func1"}, // right here, where we call `CaptureStack` in our thunk
		{1, cwd + "/fixtures/stack2.go", 9, "fixtures.func·002", "fixtures.BeesBuzz.func1"},                                // the line in the deferred function that called our thunk
		// No need to get overly precise about line numbers in the stdlib:
		//{2, "/usr/local/go/src/runtime/asm_amd64.s", 401, "", "runtime.call16"}, // if this isn't a single line on some platforms... uff.
		//{3, "/usr/local/go/src/runtime/panic.go", 387, "", "runtime.gopanic"},  // it might be reasonable to detect these and elide everything following from `runtime.*`.
		{4, cwd + "/fixtures/stack2.go", 22, "", "fixtures.buzzkill"},                              // the line that panicked!
		{5, cwd + "/fixtures/stack2.go", 19, "", "fixtures.beesWuz"},                               // the trailing `}` of `beesWuz`, because we left it via defer
		{6, cwd + "/fixtures/stack2.go", 14, "", "fixtures.BeesBuzz"},                              // the body line the calls down to `beesWuz`
		{7, cwd + "/stackinfo_test.go", here + 4, "", "meep_test.TestStacksPanickingInDefersOhMy"}, // obtw!  when we split the `fixtures.*()` *invocation* across lines, this becomes the last one!
		// No need to get overly precise about line numbers in the stdlib",
		//{8, "/usr/local/go/src/testing/testing.go", 447, "", "testing.tRunner"},
		//{9, "/usr/local/go/src/runtime/asm_amd64.s", 2232, "", "runtime.goexit"},
	}
	expectLen := len(expects) + 4
	assertStack(t, result, expects, expectLen)
}

func assertStack(t *testing.T, result meep.Stack, expects []stackFrameExpectation, expectLen int) {
	// Some quick cleanup on the expectations:
	// If no exceptions were specified, the old 1.4 funcname is expected to be same as the new
	for i, ex := range expects {
		if ex.func14 == "" {
			expects[i].func14 = ex.func15
		}
	}

	// Assertions!
	for _, tr := range expects {
		file, line, fnname := result.Frames[tr.n].Where()
		if file != tr.file {
			t.Errorf("Stack[%d] file should be %q, was %q", tr.n, tr.file, file)
		}
		if line != tr.line {
			t.Errorf("Stack[%d] line should be %d, was %d", tr.n, tr.line, line)
		}
		expectedFnname := tr.func15
		if use14fnnames {
			expectedFnname = tr.func14
		}
		if fnname != expectedFnname {
			t.Errorf("Stack[%d] func name should be %q, was %q", tr.n, expectedFnname, fnname)
		}
	}
	for i, fr := range result.Frames {
		if i < expectLen {
			continue
		}
		t.Errorf("Stack[%d] was expected to be empty, was %q", i, fr.String())
	}
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"text/tabwriter"

	"golang.org/x/net/context"

	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/filters"
	Cli "github.com/hyperhq/hypercli/cli"
	"github.com/hyperhq/hypercli/opts"
	flag "github.com/hyperhq/hypercli/pkg/mflag"
)

// CmdSnapshot is the parent subcommand for all snapshot commands
//
// Usage: docker snapshot <COMMAND> <OPTS>
func (cli *DockerCli) CmdSnapshot(args ...string) error {
	description := Cli.DockerCommands["snaphot"].Description + "\n\nSnapshots:\n"
	commands := [][]string{
		{"create", "Create a snaphot"},
		{"inspect", "Return low-level information on a snaphot"},
		{"ls", "List snaphots"},
		{"rm", "Remove a snaphot"},
	}

	for _, cmd := range commands {
		description += fmt.Sprintf("  %-25.25s%s\n", cmd[0], cmd[1])
	}

	description += "\nRun 'docker snaphot COMMAND --help' for more information on a command"
	cmd := Cli.Subcmd("snaphot", []string{"[COMMAND]"}, description, false)

	cmd.Require(flag.Exact, 0)
	err := cmd.ParseFlags(args, true)
	cmd.Usage()
	return err
}

// CmdSnapshotLs outputs a list of Docker snapshots.
//
// Usage: docker snapshot ls [OPTIONS]
func (cli *DockerCli) CmdSnapshotLs(args ...string) error {
	cmd := Cli.Subcmd("snapshot ls", nil, "List snapshots", true)

	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display snapshot names")
	flFilter := opts.NewListOpts(nil)
	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")

	cmd.Require(flag.Exact, 0)
	cmd.ParseFlags(args, true)

	volFilterArgs := filters.NewArgs()
	for _, f := range flFilter.GetAll() {
		var err error
		volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
		if err != nil {
			return err
		}
	}

	snapshots, err := cli.client.SnapshotList(context.Background(), volFilterArgs)
	if err != nil {
		return err
	}

	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
	if !*quiet {
		for _, warn := range snapshots.Warnings {
			fmt.Fprintln(cli.err, warn)
		}
		fmt.Fprintf(w, "Snapshot Name \tVolume\tSize")
		fmt.Fprintf(w, "\n")
	}

	for _, vol := range snapshots.Snapshots {
		if *quiet {
			fmt.Fprintln(w, vol.Name)
			continue
		}
		fmt.Fprintf(w, "%s\t%s\t%d\n", vol.Name, vol.Volume, vol.Size)
	}
	w.Flush()
	return nil
}

// CmdSnapshotInspect displays low-level information on one or more snapshots.
//
// Usage: docker snapshot inspect [OPTIONS] snapshot [snapshot...]
func (cli *DockerCli) CmdSnapshotInspect(args ...string) error {
	cmd := Cli.Subcmd("snapshot inspect", []string{"snapshot [snapshot...]"}, "Return low-level information on a snapshot", true)
	tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")

	cmd.Require(flag.Min, 1)
	cmd.ParseFlags(args, true)

	if err := cmd.Parse(args); err != nil {
		return nil
	}

	inspectSearcher := func(name string) (interface{}, []byte, error) {
		i, err := cli.client.SnapshotInspect(context.Background(), name)
		return i, nil, err
	}

	return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
}

// CmdSnapshotCreate creates a new snapshot.
//
// Usage: docker snapshot create [OPTIONS]
func (cli *DockerCli) CmdSnapshotCreate(args ...string) error {
	cmd := Cli.Subcmd("snapshot create", []string{"-v volume"}, "Create a snapshot", true)
	flForce := cmd.Bool([]string{"f", "-force"}, false, "Force to create snapshot, needed if volume is in use")
	flVolume := cmd.String([]string{"v", "-volume"}, "", "Specify volume to create snapshot")
	flName := cmd.String([]string{"-name"}, "", "Specify snapshot name")

	cmd.Require(flag.Exact, 0)
	cmd.ParseFlags(args, true)

	volReq := types.SnapshotCreateRequest{
		Name:   *flName,
		Volume: *flVolume,
		Force:  *flForce,
	}

	vol, err := cli.client.SnapshotCreate(context.Background(), volReq)
	if err != nil {
		return err
	}

	fmt.Fprintf(cli.out, "%s\n", vol.Name)
	return nil
}

// CmdSnapshotRm removes one or more snapshots.
//
// Usage: docker snapshot rm snapshot [snapshot...]
func (cli *DockerCli) CmdSnapshotRm(args ...string) error {
	cmd := Cli.Subcmd("snapshot rm", []string{"snapshot [snapshot...]"}, "Remove a snapshot", true)
	cmd.Require(flag.Min, 1)
	cmd.ParseFlags(args, true)

	var status = 0

	for _, name := range cmd.Args() {
		if err := cli.client.SnapshotRemove(context.Background(), name); err != nil {
			fmt.Fprintf(cli.err, "%s\n", err)
			status = 1
			continue
		}
		fmt.Fprintf(cli.out, "%s\n", name)
	}

	if status != 0 {
		return Cli.StatusError{StatusCode: status}
	}
	return nil
}
<commit_msg>fixed help typo<commit_after>package client

import (
	"fmt"
	"text/tabwriter"

	"golang.org/x/net/context"

	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/filters"
	Cli "github.com/hyperhq/hypercli/cli"
	"github.com/hyperhq/hypercli/opts"
	flag "github.com/hyperhq/hypercli/pkg/mflag"
)

// CmdSnapshot is the parent subcommand for all snapshot commands
//
// Usage: docker snapshot <COMMAND> <OPTS>
func (cli *DockerCli) CmdSnapshot(args ...string) error {
	description := Cli.DockerCommands["snaphot"].Description + "\n\nSnapshots:\n"
	commands := [][]string{
		{"create", "Create a snaphot"},
		{"inspect", "Return low-level information on a snaphot"},
		{"ls", "List snaphots"},
		{"rm", "Remove a snaphot"},
	}

	for _, cmd := range commands {
		description += fmt.Sprintf("  %-25.25s%s\n", cmd[0], cmd[1])
	}

	description += "\nRun 'hyper snaphot COMMAND --help' for more information on a command"
	cmd := Cli.Subcmd("snaphot", []string{"[COMMAND]"}, description, false)

	cmd.Require(flag.Exact, 0)
	err := cmd.ParseFlags(args, true)
	cmd.Usage()
	return err
}

// CmdSnapshotLs outputs a list of Docker snapshots.
//
// Usage: docker snapshot ls [OPTIONS]
func (cli *DockerCli) CmdSnapshotLs(args ...string) error {
	cmd := Cli.Subcmd("snapshot ls", nil, "List snapshots", true)

	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display snapshot names")
	flFilter := opts.NewListOpts(nil)
	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")

	cmd.Require(flag.Exact, 0)
	cmd.ParseFlags(args, true)

	volFilterArgs := filters.NewArgs()
	for _, f := range flFilter.GetAll() {
		var err error
		volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
		if err != nil {
			return err
		}
	}

	snapshots, err := cli.client.SnapshotList(context.Background(), volFilterArgs)
	if err != nil {
		return err
	}

	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
	if !*quiet {
		for _, warn := range snapshots.Warnings {
			fmt.Fprintln(cli.err, warn)
		}
		fmt.Fprintf(w, "Snapshot Name \tVolume\tSize")
		fmt.Fprintf(w, "\n")
	}

	for _, vol := range snapshots.Snapshots {
		if *quiet {
			fmt.Fprintln(w, vol.Name)
			continue
		}
		fmt.Fprintf(w, "%s\t%s\t%d\n", vol.Name, vol.Volume, vol.Size)
	}
	w.Flush()
	return nil
}

// CmdSnapshotInspect displays low-level information on one or more snapshots.
//
// Usage: docker snapshot inspect [OPTIONS] snapshot [snapshot...]
func (cli *DockerCli) CmdSnapshotInspect(args ...string) error {
	cmd := Cli.Subcmd("snapshot inspect", []string{"snapshot [snapshot...]"}, "Return low-level information on a snapshot", true)
	tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")

	cmd.Require(flag.Min, 1)
	cmd.ParseFlags(args, true)

	if err := cmd.Parse(args); err != nil {
		return nil
	}

	inspectSearcher := func(name string) (interface{}, []byte, error) {
		i, err := cli.client.SnapshotInspect(context.Background(), name)
		return i, nil, err
	}

	return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
}

// CmdSnapshotCreate creates a new snapshot.
//
// Usage: docker snapshot create [OPTIONS]
func (cli *DockerCli) CmdSnapshotCreate(args ...string) error {
	cmd := Cli.Subcmd("snapshot create", []string{"-v volume"}, "Create a snapshot", true)
	flForce := cmd.Bool([]string{"f", "-force"}, false, "Force to create snapshot, needed if volume is in use")
	flVolume := cmd.String([]string{"v", "-volume"}, "", "Specify volume to create snapshot")
	flName := cmd.String([]string{"-name"}, "", "Specify snapshot name")

	cmd.Require(flag.Exact, 0)
	cmd.ParseFlags(args, true)

	volReq := types.SnapshotCreateRequest{
		Name:   *flName,
		Volume: *flVolume,
		Force:  *flForce,
	}

	vol, err := cli.client.SnapshotCreate(context.Background(), volReq)
	if err != nil {
		return err
	}

	fmt.Fprintf(cli.out, "%s\n", vol.Name)
	return nil
}

// CmdSnapshotRm removes one or more snapshots.
//
// Usage: docker snapshot rm snapshot [snapshot...]
func (cli *DockerCli) CmdSnapshotRm(args ...string) error {
	cmd := Cli.Subcmd("snapshot rm", []string{"snapshot [snapshot...]"}, "Remove a snapshot", true)
	cmd.Require(flag.Min, 1)
	cmd.ParseFlags(args, true)

	var status = 0

	for _, name := range cmd.Args() {
		if err := cli.client.SnapshotRemove(context.Background(), name); err != nil {
			fmt.Fprintf(cli.err, "%s\n", err)
			status = 1
			continue
		}
		fmt.Fprintf(cli.out, "%s\n", name)
	}

	if status != 0 {
		return Cli.StatusError{StatusCode: status}
	}
	return nil
}
<|endoftext|>


<commit_before>package mesh

import (
	"fmt"
	"sync"
	"testing"

	"github.com/stretchr/testify/require"
)

// TODO test gossip unicast; atm we only test topology gossip and
// surrogates, neither of which employ unicast.

type mockChannelConnection struct {
	RemoteConnection
	dest *Router
}

func NewTestRouter(name string) *Router {
	peerName, _ := PeerNameFromString(name)
	router := NewRouter(Config{}, peerName, "nick", nil)
	router.Start()
	return router
}

func (conn *mockChannelConnection) SendProtocolMsg(protocolMsg ProtocolMsg) {
	if err := conn.dest.handleGossip(protocolMsg.tag, protocolMsg.msg); err != nil {
		panic(err)
	}
}

func sendPendingGossip(routers ...*Router) {
	// Loop until all routers report they didn't send anything
	for sentSomething := true; sentSomething; {
		sentSomething = false
		for _, router := range routers {
			sentSomething = router.sendPendingGossip() || sentSomething
		}
	}
}

func (router *Router) AddTestChannelConnection(r *Router) {
	fromPeer := NewPeerFrom(router.Ourself.Peer)
	toPeer := NewPeerFrom(r.Ourself.Peer)

	r.Peers.FetchWithDefault(fromPeer)             // Has side-effect of incrementing refcount
	toPeer = router.Peers.FetchWithDefault(toPeer) //

	conn := &mockChannelConnection{RemoteConnection{router.Ourself.Peer, toPeer, "", false, true}, r}
	router.Ourself.handleAddConnection(conn)
	router.Ourself.handleConnectionEstablished(conn)
}

func (router *Router) DeleteTestChannelConnection(r *Router) {
	fromName := router.Ourself.Peer.Name
	toName := r.Ourself.Peer.Name

	fromPeer := r.Peers.Fetch(fromName)
	toPeer := router.Peers.Fetch(toName)

	r.Peers.Dereference(fromPeer)
	router.Peers.Dereference(toPeer)

	conn, _ := router.Ourself.ConnectionTo(toName)
	router.Ourself.handleDeleteConnection(conn)
}

// Create a Peer representing the receiver router, with connections to
// the routers supplied as arguments, carrying across all UID and
// version information.
func (router *Router) tp(routers ...*Router) *Peer {
	peer := NewPeerFrom(router.Ourself.Peer)
	connections := make(map[PeerName]Connection)
	for _, r := range routers {
		p := NewPeerFrom(r.Ourself.Peer)
		connections[r.Ourself.Peer.Name] = newMockConnection(peer, p)
	}
	peer.Version = router.Ourself.Peer.Version
	peer.connections = connections
	return peer
}

// Check that the topology of router matches the peers and all of their connections
func checkTopology(t *testing.T, router *Router, wantedPeers ...*Peer) {
	router.Peers.RLock()
	checkTopologyPeers(t, true, router.Peers.allPeers(), wantedPeers...)
	router.Peers.RUnlock()
}

func TestGossipTopology(t *testing.T) {
	// Create some peers that will talk to each other
	r1 := NewTestRouter("01:00:00:01:00:00")
	r2 := NewTestRouter("02:00:00:02:00:00")
	r3 := NewTestRouter("03:00:00:03:00:00")

	// Check state when they have no connections
	checkTopology(t, r1, r1.tp())
	checkTopology(t, r2, r2.tp())

	// Now try adding some connections
	r1.AddTestChannelConnection(r2)
	sendPendingGossip(r1, r2)
	checkTopology(t, r1, r1.tp(r2), r2.tp())
	checkTopology(t, r2, r1.tp(r2), r2.tp())
	r2.AddTestChannelConnection(r1)
	sendPendingGossip(r1, r2)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1))

	// Currently, the connection from 2 to 3 is one-way only
	r2.AddTestChannelConnection(r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp())
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp())
	// When r2 gossiped to r3, 1 was unreachable from r3 so it got removed from the
	// list of peers, but remains referenced in the connection from 1 to 3.
	checkTopology(t, r3, r2.tp(r1, r3), r3.tp())

	// Add a connection from 3 to 1 and now r1 is reachable.
	r3.AddTestChannelConnection(r1)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r1))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r1))
	checkTopology(t, r3, r1.tp(), r2.tp(r1, r3), r3.tp(r1))

	r1.AddTestChannelConnection(r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
	checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
	checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))

	// Drop the connection from 2 to 3
	r2.DeleteTestChannelConnection(r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
	checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
	checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))

	// Drop the connection from 1 to 3
	r1.DeleteTestChannelConnection(r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1))
	// r3 still thinks r1 has a connection to it
	checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))

	// On a timer, r3 will gossip to r1
	r3.SendAllGossip()
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1))
}

func TestGossipSurrogate(t *testing.T) {
	// create the topology r1 <-> r2 <-> r3
	r1 := NewTestRouter("01:00:00:01:00:00")
	r2 := NewTestRouter("02:00:00:02:00:00")
	r3 := NewTestRouter("03:00:00:03:00:00")
	r1.AddTestChannelConnection(r2)
	r2.AddTestChannelConnection(r1)
	r3.AddTestChannelConnection(r2)
	r2.AddTestChannelConnection(r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
	checkTopology(t, r3, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))

	// create a gossiper at either end, but not the middle
	g1 := newTestGossiper()
	g3 := newTestGossiper()
	s1 := r1.NewGossip("Test", g1)
	s3 := r3.NewGossip("Test", g3)

	// broadcast a message from each end, check it reaches the other
	broadcast(s1, 1)
	broadcast(s3, 2)
	sendPendingGossip(r1, r2, r3)
	g1.checkHas(t, 2)
	g3.checkHas(t, 1)

	// check that each end gets their message back through periodic
	// gossip
	r1.SendAllGossip()
	r3.SendAllGossip()
	sendPendingGossip(r1, r2, r3)
	g1.checkHas(t, 1, 2)
	g3.checkHas(t, 1, 2)
}

type testGossiper struct {
	sync.RWMutex
	state map[byte]struct{}
}

func newTestGossiper() *testGossiper {
	return &testGossiper{state: make(map[byte]struct{})}
}

func (g *testGossiper) OnGossipUnicast(sender PeerName, msg []byte) error {
	return nil
}

func (g *testGossiper) OnGossipBroadcast(_ PeerName, update []byte) (GossipData, error) {
	g.Lock()
	defer g.Unlock()
	for _, v := range update {
		g.state[v] = void
	}
	return NewSurrogateGossipData(update), nil
}

func (g *testGossiper) Gossip() GossipData {
	g.RLock()
	defer g.RUnlock()
	state := make([]byte, len(g.state))
	for v := range g.state {
		state = append(state, v)
	}
	return NewSurrogateGossipData(state)
}

func (g *testGossiper) OnGossip(update []byte) (GossipData, error) {
	g.Lock()
	defer g.Unlock()
	var delta []byte
	for _, v := range update {
		if _, found := g.state[v]; !found {
			delta = append(delta, v)
			g.state[v] = void
		}
	}
	if len(delta) == 0 {
		return nil, nil
	}
	return NewSurrogateGossipData(delta), nil
}

func (g *testGossiper) checkHas(t *testing.T, vs ...byte) {
	g.RLock()
	defer g.RUnlock()
	for _, v := range vs {
		if _, found := g.state[v]; !found {
			require.FailNow(t, fmt.Sprintf("%d is missing", v))
		}
	}
}

func broadcast(s Gossip, v byte) {
	s.GossipBroadcast(NewSurrogateGossipData([]byte{v}))
}
<commit_msg>better emulation of connections in gossip tests<commit_after>package mesh

import (
	"fmt"
	"sync"
	"testing"

	"github.com/stretchr/testify/require"
)

// TODO test gossip unicast; atm we only test topology gossip and
// surrogates, neither of which employ unicast.

type mockChannelConnection struct {
	RemoteConnection
	router *Router
	dest   *Router
	start  chan struct{}
}

func NewTestRouter(name string) *Router {
	peerName, _ := PeerNameFromString(name)
	router := NewRouter(Config{}, peerName, "nick", nil)
	router.Start()
	return router
}

func (conn *mockChannelConnection) SendProtocolMsg(protocolMsg ProtocolMsg) {
	<-conn.start
	if err := conn.dest.handleGossip(protocolMsg.tag, protocolMsg.msg); err != nil {
		panic(err)
	}
}

func (conn *mockChannelConnection) Connect() {
	conn.router.Ourself.handleAddConnection(conn)
	conn.router.Ourself.handleConnectionEstablished(conn)
}

func (conn *mockChannelConnection) Start() {
	close(conn.start)
}

func sendPendingGossip(routers ...*Router) {
	// Loop until all routers report they didn't send anything
	for sentSomething := true; sentSomething; {
		sentSomething = false
		for _, router := range routers {
			sentSomething = router.sendPendingGossip() || sentSomething
		}
	}
}

func AddTestGossipConnection(r1, r2 *Router) {
	c1 := r1.NewTestChannelConnection(r2)
	c2 := r2.NewTestChannelConnection(r1)
	c1.Connect()
	c2.Start()
	c2.Connect()
	c1.Start()
}

func (router *Router) NewTestChannelConnection(r *Router) *mockChannelConnection {
	fromPeer := NewPeerFrom(router.Ourself.Peer)
	toPeer := NewPeerFrom(r.Ourself.Peer)

	r.Peers.FetchWithDefault(fromPeer)             // Has side-effect of incrementing refcount
	toPeer = router.Peers.FetchWithDefault(toPeer) //

	return &mockChannelConnection{
		RemoteConnection{router.Ourself.Peer, toPeer, "", false, true}, router, r, make(chan struct{})}
}

func (router *Router) DeleteTestChannelConnection(r *Router) {
	fromName := router.Ourself.Peer.Name
	toName := r.Ourself.Peer.Name

	fromPeer := r.Peers.Fetch(fromName)
	toPeer := router.Peers.Fetch(toName)

	r.Peers.Dereference(fromPeer)
	router.Peers.Dereference(toPeer)

	conn, _ := router.Ourself.ConnectionTo(toName)
	router.Ourself.handleDeleteConnection(conn)
}

// Create a Peer representing the receiver router, with connections to
// the routers supplied as arguments, carrying across all UID and
// version information.
func (router *Router) tp(routers ...*Router) *Peer {
	peer := NewPeerFrom(router.Ourself.Peer)
	connections := make(map[PeerName]Connection)
	for _, r := range routers {
		p := NewPeerFrom(r.Ourself.Peer)
		connections[r.Ourself.Peer.Name] = newMockConnection(peer, p)
	}
	peer.Version = router.Ourself.Peer.Version
	peer.connections = connections
	return peer
}

// Check that the topology of router matches the peers and all of their connections
func checkTopology(t *testing.T, router *Router, wantedPeers ...*Peer) {
	router.Peers.RLock()
	checkTopologyPeers(t, true, router.Peers.allPeers(), wantedPeers...)
	router.Peers.RUnlock()
}

func TestGossipTopology(t *testing.T) {
	// Create some peers that will talk to each other
	r1 := NewTestRouter("01:00:00:01:00:00")
	r2 := NewTestRouter("02:00:00:02:00:00")
	r3 := NewTestRouter("03:00:00:03:00:00")

	// Check state when they have no connections
	checkTopology(t, r1, r1.tp())
	checkTopology(t, r2, r2.tp())

	// Now try adding some connections
	AddTestGossipConnection(r1, r2)
	sendPendingGossip(r1, r2)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1))

	AddTestGossipConnection(r2, r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
	checkTopology(t, r3, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))

	AddTestGossipConnection(r3, r1)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1, r2))
	checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1, r2))
	checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1, r2))

	// Drop the connection from 2 to 3
	r2.DeleteTestChannelConnection(r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1, r2))
	checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1, r2))
	checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1, r2))

	// Drop the connection from 1 to 3
	r1.DeleteTestChannelConnection(r3)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1, r2))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1), r3.tp(r1, r2))
	// r3 still thinks r1 has a connection to it
	checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1, r2))

	// On a timer, r3 will gossip to r1
	r3.SendAllGossip()
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1, r2))
}

func TestGossipSurrogate(t *testing.T) {
	// create the topology r1 <-> r2 <-> r3
	r1 := NewTestRouter("01:00:00:01:00:00")
	r2 := NewTestRouter("02:00:00:02:00:00")
	r3 := NewTestRouter("03:00:00:03:00:00")
	AddTestGossipConnection(r1, r2)
	AddTestGossipConnection(r3, r2)
	sendPendingGossip(r1, r2, r3)
	checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
	checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
	checkTopology(t, r3, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))

	// create a gossiper at either end, but not the middle
	g1 := newTestGossiper()
	g3 := newTestGossiper()
	s1 := r1.NewGossip("Test", g1)
	s3 := r3.NewGossip("Test", g3)

	// broadcast a message from each end, check it reaches the other
	broadcast(s1, 1)
	broadcast(s3, 2)
	sendPendingGossip(r1, r2, r3)
	g1.checkHas(t, 2)
	g3.checkHas(t, 1)

	// check that each end gets their message back through periodic
	// gossip
	r1.SendAllGossip()
	r3.SendAllGossip()
	sendPendingGossip(r1, r2, r3)
	g1.checkHas(t, 1, 2)
	g3.checkHas(t, 1, 2)
}

type testGossiper struct {
	sync.RWMutex
	state map[byte]struct{}
}

func newTestGossiper() *testGossiper {
	return &testGossiper{state: make(map[byte]struct{})}
}

func (g *testGossiper) OnGossipUnicast(sender PeerName, msg []byte) error {
	return nil
}

func (g *testGossiper) OnGossipBroadcast(_ PeerName, update []byte) (GossipData, error) {
	g.Lock()
	defer g.Unlock()
	for _, v := range update {
		g.state[v] = void
	}
	return NewSurrogateGossipData(update), nil
}

func (g *testGossiper) Gossip() GossipData {
	g.RLock()
	defer g.RUnlock()
	state := make([]byte, len(g.state))
	for v := range g.state {
		state = append(state, v)
	}
	return NewSurrogateGossipData(state)
}

func (g *testGossiper) OnGossip(update []byte) (GossipData, error) {
	g.Lock()
	defer g.Unlock()
	var delta []byte
	for _, v := range update {
		if _, found := g.state[v]; !found {
			delta = append(delta, v)
			g.state[v] = void
		}
	}
	if len(delta) == 0 {
		return nil, nil
	}
	return NewSurrogateGossipData(delta), nil
}

func (g *testGossiper) checkHas(t *testing.T, vs ...byte) {
	g.RLock()
	defer g.RUnlock()
	for _, v := range vs {
		if _, found := g.state[v]; !found {
			require.FailNow(t, fmt.Sprintf("%d is missing", v))
		}
	}
}

func broadcast(s Gossip, v byte) {
	s.GossipBroadcast(NewSurrogateGossipData([]byte{v}))
}
<|endoftext|>


<commit_before>package elastic

import (
	"context"
	"fmt"
	"math"
	"strings"

	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	weed_util "github.com/chrislusf/seaweedfs/weed/util"
	jsoniter "github.com/json-iterator/go"
	elastic "github.com/olivere/elastic/v7"
)

var (
	indexType           = "_doc"
	indexPrefix         = ".seaweedfs_"
	indexKV             = ".seaweedfs_kv_entries"
	mappingWithoutQuery = ` {
		     "mappings": {
		   	"enabled": false,
		       "properties": {
		         "Value":{
		           "type": "binary"
		         }
		       }
		     }
		   }`
)

type ESEntry struct {
	ParentId string `json:"ParentId"`
	Entry    *filer.Entry
}

type ESKVEntry struct {
	Value []byte `json:"Value"`
}

func init() {
	filer.Stores = append(filer.Stores, &ElasticStore{})
}

type ElasticStore struct {
	client      *elastic.Client
	maxPageSize int
}

func (store *ElasticStore) GetName() string {
	return "elastic7"
}

func (store *ElasticStore) Initialize(configuration weed_util.Configuration, prefix string) (err error) {
	options := store.initialize(configuration, prefix)
	store.client, err = elastic.NewClient(options...)
	if err != nil {
		return fmt.Errorf("init elastic %v.", err)
	}
	if ok, err := store.client.IndexExists(indexKV).Do(context.Background()); err == nil && !ok {
		_, err = store.client.CreateIndex(indexKV).Body(mappingWithoutQuery).Do(context.Background())
		if err != nil {
			return fmt.Errorf("create index(%s) %v.", indexKV, err)
		}
	}
	return nil
}

func (store *ElasticStore) initialize(configuration weed_util.Configuration, prefix string) (options []elastic.ClientOptionFunc) {
	servers := configuration.GetStringSlice(prefix + "servers")
	options = append(options, elastic.SetURL(servers...))
	username := configuration.GetString(prefix + "username")
	password := configuration.GetString(prefix + "password")
	if username != "" && password != "" {
		options = append(options, elastic.SetBasicAuth(username, password))
	}
	options = append(options, elastic.SetSniff(configuration.GetBool(prefix+"sniff_enabled")))
	options = append(options, elastic.SetHealthcheck(configuration.GetBool(prefix+"healthcheck_enabled")))
	store.maxPageSize = configuration.GetInt(prefix + "index.max_result_window")
	if store.maxPageSize <= 0 {
		store.maxPageSize = 10000
	}
	glog.Infof("filer store elastic endpoints: %v.", servers)
	return options
}

func (store *ElasticStore) BeginTransaction(ctx context.Context) (context.Context, error) {
	return ctx, nil
}
func (store *ElasticStore) CommitTransaction(ctx context.Context) error {
	return nil
}
func (store *ElasticStore) RollbackTransaction(ctx context.Context) error {
	return nil
}

func (store *ElasticStore) ListDirectoryPrefixedEntries(ctx context.Context, fullpath weed_util.FullPath, startFileName string, inclusive bool, limit int, prefix string) (entries []*filer.Entry, err error) {
	return nil, filer.ErrUnsupportedListDirectoryPrefixed
}

func (store *ElasticStore) InsertEntry(ctx context.Context, entry *filer.Entry) (err error) {
	index := getIndex(entry.FullPath)
	dir, _ := entry.FullPath.DirAndName()
	id := weed_util.Md5String([]byte(entry.FullPath))
	esEntry := &ESEntry{
		ParentId: weed_util.Md5String([]byte(dir)),
		Entry:    entry,
	}
	value, err := jsoniter.Marshal(esEntry)
	if err != nil {
		glog.Errorf("insert entry(%s) %v.", string(entry.FullPath), err)
		return fmt.Errorf("insert entry %v.", err)
	}
	_, err = store.client.Index().
		Index(index).
		Type(indexType).
		Id(id).
		BodyJson(string(value)).
		Do(ctx)
	if err != nil {
		glog.Errorf("insert entry(%s) %v.", string(entry.FullPath), err)
		return fmt.Errorf("insert entry %v.", err)
	}
	return nil
}

func (store *ElasticStore) UpdateEntry(ctx context.Context, entry *filer.Entry) (err error) {
	return store.InsertEntry(ctx, entry)
}

func (store *ElasticStore) FindEntry(ctx context.Context, fullpath weed_util.FullPath) (entry *filer.Entry, err error) {
	index := getIndex(fullpath)
	id := weed_util.Md5String([]byte(fullpath))
	searchResult, err := store.client.Get().
		Index(index).
		Type(indexType).
		Id(id).
		Do(ctx)
	if elastic.IsNotFound(err) {
		return nil, filer_pb.ErrNotFound
	}
	if searchResult != nil && searchResult.Found {
		esEntry := &ESEntry{
			ParentId: "",
			Entry:    &filer.Entry{},
		}
		err := jsoniter.Unmarshal(searchResult.Source, esEntry)
		return esEntry.Entry, err
	}
	glog.Errorf("find entry(%s),%v.", string(fullpath), err)
	return nil, filer_pb.ErrNotFound
}

func (store *ElasticStore) DeleteEntry(ctx context.Context, fullpath weed_util.FullPath) (err error) {
	index := getIndex(fullpath)
	id := weed_util.Md5String([]byte(fullpath))
	if strings.Count(string(fullpath), "/") == 1 {
		return store.deleteIndex(ctx, index)
	}
	return store.deleteEntry(ctx, index, id)
}

func (store *ElasticStore) deleteIndex(ctx context.Context, index string) (err error) {
	deleteResult, err := store.client.DeleteIndex(index).Do(ctx)
	if elastic.IsNotFound(err) || (err == nil && deleteResult.Acknowledged) {
		return nil
	}
	glog.Errorf("delete index(%s) %v.", index, err)
	return err
}

func (store *ElasticStore) deleteEntry(ctx context.Context, index, id string) (err error) {
	deleteResult, err := store.client.Delete().
		Index(index).
		Type(indexType).
		Id(id).
		Do(ctx)
	if err == nil {
		if deleteResult.Result == "deleted" || deleteResult.Result == "not_found" {
			return nil
		}
	}
	glog.Errorf("delete entry(index:%s,_id:%s) %v.", index, id, err)
	return fmt.Errorf("delete entry %v.", err)
}

func (store *ElasticStore) DeleteFolderChildren(ctx context.Context, fullpath weed_util.FullPath) (err error) {
	if entries, err := store.ListDirectoryEntries(ctx, fullpath, "", false, math.MaxInt32); err == nil {
		for _, entry := range entries {
			store.DeleteEntry(ctx, entry.FullPath)
		}
	}
	return nil
}

func (store *ElasticStore) ListDirectoryEntries(
	ctx context.Context, fullpath weed_util.FullPath, startFileName string, inclusive bool, limit int,
) (entries []*filer.Entry, err error) {
	if string(fullpath) == "/" {
		return store.listRootDirectoryEntries(ctx, startFileName, inclusive, limit)
	}
	return store.listDirectoryEntries(ctx, fullpath, startFileName, inclusive, limit)
}

func (store *ElasticStore) listRootDirectoryEntries(ctx context.Context, startFileName string, inclusive bool, limit int) (entries []*filer.Entry, err error) {
	indexResult, err := store.client.CatIndices().Do(ctx)
	if err != nil {
		glog.Errorf("list indices %v.", err)
		return entries, err
	}
	for _, index := range indexResult {
		if index.Index == indexKV {
			continue
		}
		if strings.HasPrefix(index.Index, indexPrefix) {
			if entry, err := store.FindEntry(ctx,
				weed_util.FullPath("/"+strings.Replace(index.Index, indexPrefix, "", 1))); err == nil {
				fileName := getFileName(entry.FullPath)
				if fileName == startFileName && !inclusive {
					continue
				}
				limit--
				if limit < 0 {
					break
				}
				entries = append(entries, entry)
			}
		}
	}
	return entries, nil
}

func (store *ElasticStore) listDirectoryEntries(
	ctx context.Context, fullpath weed_util.FullPath, startFileName string, inclusive bool, limit int,
) (entries []*filer.Entry, err error) {
	first := true
	index := getIndex(fullpath)
	nextStart := ""
	parentId := weed_util.Md5String([]byte(fullpath))
	if _, err := store.client.Refresh(index).Do(ctx); err != nil {
		if elastic.IsNotFound(err) {
			store.client.CreateIndex(index).Do(ctx)
			return entries, nil
		}
	}
	for {
		result := &elastic.SearchResult{}
		if (startFileName == "" && first) || inclusive {
			if result, err = store.search(ctx, index, parentId); err != nil {
				glog.Errorf("search (%s,%s,%t,%d) %v.", string(fullpath), startFileName, inclusive, limit, err)
				return entries, err
			}
		} else {
			fullPath := string(fullpath) + "/" + startFileName
			if !first {
				fullPath = nextStart
			}
			after := weed_util.Md5String([]byte(fullPath))
			if result, err = store.searchAfter(ctx, index, parentId, after); err != nil {
				glog.Errorf("searchAfter (%s,%s,%t,%d) %v.", string(fullpath), startFileName, inclusive, limit, err)
				return entries, err
			}
		}
		first = false
		for _, hit := range result.Hits.Hits {
			esEntry := &ESEntry{
				ParentId: "",
				Entry:    &filer.Entry{},
			}
			if err := jsoniter.Unmarshal(hit.Source, esEntry); err == nil {
				limit--
				if limit < 0 {
					return entries, nil
				}
				nextStart = string(esEntry.Entry.FullPath)
				fileName := getFileName(esEntry.Entry.FullPath)
				if fileName == startFileName && !inclusive {
					continue
				}
				entries = append(entries, esEntry.Entry)
			}
		}
		if len(result.Hits.Hits) < store.maxPageSize {
			break
		}
	}
	return entries, nil
}

func (store *ElasticStore) search(ctx context.Context, index, parentId string) (result *elastic.SearchResult, err error) {
	if count, err := store.client.Count(index).Do(ctx); err == nil && count == 0 {
		return &elastic.SearchResult{
			Hits: &elastic.SearchHits{
				Hits: make([]*elastic.SearchHit, 0)},
		}, nil
	}
	queryResult, err := store.client.Search().
		Index(index).
		Query(elastic.NewMatchQuery("ParentId", parentId)).
		Size(store.maxPageSize).
		Sort("_id", false).
		Do(ctx)
	return queryResult, err
}

func (store *ElasticStore) searchAfter(ctx context.Context, index, parentId, after string) (result *elastic.SearchResult, err error) {
	queryResult, err := store.client.Search().
		Index(index).
		Query(elastic.NewMatchQuery("ParentId", parentId)).
		SearchAfter(after).
		Size(store.maxPageSize).
		Sort("_id", false).
		Do(ctx)
	return queryResult, err

}

func (store *ElasticStore) Shutdown() {
	store.client.Stop()
}

func getIndex(fullpath weed_util.FullPath) string {
	path := strings.Split(string(fullpath), "/")
	if len(path) > 1 {
		return indexPrefix + path[1]
	}
	return ""
}

func getFileName(fullpath weed_util.FullPath) string {
	path := strings.Split(string(fullpath), "/")
	if len(path) > 1 {
		return path[len(path)-1]
	}
	return ""
}
<commit_msg>change elastic initialize process similar as others.<commit_after>package elastic

import (
	"context"
	"fmt"
	"math"
	"strings"

	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	weed_util "github.com/chrislusf/seaweedfs/weed/util"
	jsoniter "github.com/json-iterator/go"
	elastic "github.com/olivere/elastic/v7"
)

var (
	indexType   = "_doc"
	indexPrefix = ".seaweedfs_"
	indexKV     = ".seaweedfs_kv_entries"
	kvMappings  = ` {
		     "mappings": {
		   	"enabled": false,
		       "properties": {
		         "Value":{
		           "type": "binary"
		         }
		       }
		     }
		   }`
)

type ESEntry struct {
	ParentId string `json:"ParentId"`
	Entry    *filer.Entry
}

type ESKVEntry struct {
	Value []byte `json:"Value"`
}

func init() {
	filer.Stores = append(filer.Stores, &ElasticStore{})
}

type ElasticStore struct {
	client      *elastic.Client
	maxPageSize int
}

func (store *ElasticStore) GetName() string {
	return "elastic7"
}

func (store *ElasticStore) Initialize(configuration weed_util.Configuration, prefix string) (err error) {
	options := []elastic.ClientOptionFunc{}
	servers := configuration.GetStringSlice(prefix + "servers")
	options = append(options, elastic.SetURL(servers...))
	username := configuration.GetString(prefix + "username")
	password := configuration.GetString(prefix + "password")
	if username != "" && password != "" {
		options = append(options, elastic.SetBasicAuth(username, password))
	}
	options = append(options, elastic.SetSniff(configuration.GetBool(prefix+"sniff_enabled")))
	options = append(options, elastic.SetHealthcheck(configuration.GetBool(prefix+"healthcheck_enabled")))
	store.maxPageSize = configuration.GetInt(prefix + "index.max_result_window")
	if store.maxPageSize <= 0 {
		store.maxPageSize = 10000
	}
	glog.Infof("filer store elastic endpoints: %v.", servers)
	return store.initialize(options)
}

func (store *ElasticStore) initialize(options []elastic.ClientOptionFunc) (err error) {
	ctx := context.Background()
	store.client, err = elastic.NewClient(options...)
	if err != nil {
		return fmt.Errorf("init elastic %v.", err)
	}
	if ok, err := store.client.IndexExists(indexKV).Do(ctx); err == nil && !ok {
		_, err = store.client.CreateIndex(indexKV).Body(kvMappings).Do(ctx)
		if err != nil {
			return fmt.Errorf("create index(%s) %v.", indexKV, err)
		}
	}
	return nil
}

func (store *ElasticStore) BeginTransaction(ctx context.Context) (context.Context, error) {
	return ctx, nil
}
func (store *ElasticStore) CommitTransaction(ctx context.Context) error {
	return nil
}
func (store *ElasticStore) RollbackTransaction(ctx context.Context) error {
	return nil
}

func (store *ElasticStore) ListDirectoryPrefixedEntries(ctx context.Context, fullpath weed_util.FullPath, startFileName string, inclusive bool, limit int, prefix string) (entries []*filer.Entry, err error) {
	return nil, filer.ErrUnsupportedListDirectoryPrefixed
}

func (store *ElasticStore) InsertEntry(ctx context.Context, entry *filer.Entry) (err error) {
	index := getIndex(entry.FullPath)
	dir, _ := entry.FullPath.DirAndName()
	id := weed_util.Md5String([]byte(entry.FullPath))
	esEntry := &ESEntry{
		ParentId: weed_util.Md5String([]byte(dir)),
		Entry:    entry,
	}
	value, err := jsoniter.Marshal(esEntry)
	if err != nil {
		glog.Errorf("insert entry(%s) %v.", string(entry.FullPath), err)
		return fmt.Errorf("insert entry %v.", err)
	}
	_, err = store.client.Index().
		Index(index).
		Type(indexType).
		Id(id).
		BodyJson(string(value)).
		Do(ctx)
	if err != nil {
		glog.Errorf("insert entry(%s) %v.", string(entry.FullPath), err)
		return fmt.Errorf("insert entry %v.", err)
	}
	return nil
}

func (store *ElasticStore) UpdateEntry(ctx context.Context, entry *filer.Entry) (err error) {
	return store.InsertEntry(ctx, entry)
}

func (store *ElasticStore) FindEntry(ctx context.Context, fullpath weed_util.FullPath) (entry *filer.Entry, err error) {
	index := getIndex(fullpath)
	id := weed_util.Md5String([]byte(fullpath))
	searchResult, err := store.client.Get().
		Index(index).
		Type(indexType).
		Id(id).
		Do(ctx)
	if elastic.IsNotFound(err) {
		return nil, filer_pb.ErrNotFound
	}
	if searchResult != nil && searchResult.Found {
		esEntry := &ESEntry{
			ParentId: "",
			Entry:    &filer.Entry{},
		}
		err := jsoniter.Unmarshal(searchResult.Source, esEntry)
		return esEntry.Entry, err
	}
	glog.Errorf("find entry(%s),%v.", string(fullpath), err)
	return nil, filer_pb.ErrNotFound
}

func (store *ElasticStore) DeleteEntry(ctx context.Context, fullpath weed_util.FullPath) (err error) {
	index := getIndex(fullpath)
	id := weed_util.Md5String([]byte(fullpath))
	if strings.Count(string(fullpath), "/") == 1 {
		return store.deleteIndex(ctx, index)
	}
	return store.deleteEntry(ctx, index, id)
}

func (store *ElasticStore) deleteIndex(ctx context.Context, index string) (err error) {
	deleteResult, err := store.client.DeleteIndex(index).Do(ctx)
	if elastic.IsNotFound(err) || (err == nil && deleteResult.Acknowledged) {
		return nil
	}
	glog.Errorf("delete index(%s) %v.", index, err)
	return err
}

func (store *ElasticStore) deleteEntry(ctx context.Context, index, id string) (err error) {
	deleteResult, err := store.client.Delete().
		Index(index).
		Type(indexType).
		Id(id).
		Do(ctx)
	if err == nil {
		if deleteResult.Result == "deleted" || deleteResult.Result == "not_found" {
			return nil
		}
	}
	glog.Errorf("delete entry(index:%s,_id:%s) %v.", index, id, err)
	return fmt.Errorf("delete entry %v.", err)
}

func (store *ElasticStore) DeleteFolderChildren(ctx context.Context, fullpath weed_util.FullPath) (err error) {
	if entries, err := store.ListDirectoryEntries(ctx, fullpath, "", false, math.MaxInt32); err == nil {
		for _, entry := range entries {
			store.DeleteEntry(ctx, entry.FullPath)
		}
	}
	return nil
}

func (store *ElasticStore) ListDirectoryEntries(
	ctx context.Context, fullpath weed_util.FullPath, startFileName string, inclusive bool, limit int,
) (entries []*filer.Entry, err error) {
	if string(fullpath) == "/" {
		return store.listRootDirectoryEntries(ctx, startFileName, inclusive, limit)
	}
	return store.listDirectoryEntries(ctx, fullpath, startFileName, inclusive, limit)
}

func (store *ElasticStore) listRootDirectoryEntries(ctx context.Context, startFileName string, inclusive bool, limit int) (entries []*filer.Entry, err error) {
	indexResult, err := store.client.CatIndices().Do(ctx)
	if err != nil {
		glog.Errorf("list indices %v.", err)
		return entries, err
	}
	for _, index := range indexResult {
		if index.Index == indexKV {
			continue
		}
		if strings.HasPrefix(index.Index, indexPrefix) {
			if entry, err := store.FindEntry(ctx,
				weed_util.FullPath("/"+strings.Replace(index.Index, indexPrefix, "", 1))); err == nil {
				fileName := getFileName(entry.FullPath)
				if fileName == startFileName && !inclusive {
					continue
				}
				limit--
				if limit < 0 {
					break
				}
				entries = append(entries, entry)
			}
		}
	}
	return entries, nil
}

func (store *ElasticStore) listDirectoryEntries(
	ctx context.Context, fullpath weed_util.FullPath, startFileName string, inclusive bool, limit int,
) (entries []*filer.Entry, err error) {
	first := true
	index := getIndex(fullpath)
	nextStart := ""
	parentId := weed_util.Md5String([]byte(fullpath))
	if _, err := store.client.Refresh(index).Do(ctx); err != nil {
		if elastic.IsNotFound(err) {
			store.client.CreateIndex(index).Do(ctx)
			return entries, nil
		}
	}
	for {
		result := &elastic.SearchResult{}
		if (startFileName == "" && first) || inclusive {
			if result, err = store.search(ctx, index, parentId); err != nil {
				glog.Errorf("search (%s,%s,%t,%d) %v.", string(fullpath), startFileName, inclusive, limit, err)
				return entries, err
			}
		} else {
			fullPath := string(fullpath) + "/" + startFileName
			if !first {
				fullPath = nextStart
			}
			after := weed_util.Md5String([]byte(fullPath))
			if result, err = store.searchAfter(ctx, index, parentId, after); err != nil {
				glog.Errorf("searchAfter (%s,%s,%t,%d) %v.", string(fullpath), startFileName, inclusive, limit, err)
				return entries, err
			}
		}
		first = false
		for _, hit := range result.Hits.Hits {
			esEntry := &ESEntry{
				ParentId: "",
				Entry:    &filer.Entry{},
			}
			if err := jsoniter.Unmarshal(hit.Source, esEntry); err == nil {
				limit--
				if limit < 0 {
					return entries, nil
				}
				nextStart = string(esEntry.Entry.FullPath)
				fileName := getFileName(esEntry.Entry.FullPath)
				if fileName == startFileName && !inclusive {
					continue
				}
				entries = append(entries, esEntry.Entry)
			}
		}
		if len(result.Hits.Hits) < store.maxPageSize {
			break
		}
	}
	return entries, nil
}

func (store *ElasticStore) search(ctx context.Context, index, parentId string) (result *elastic.SearchResult, err error) {
	if count, err := store.client.Count(index).Do(ctx); err == nil && count == 0 {
		return &elastic.SearchResult{
			Hits: &elastic.SearchHits{
				Hits: make([]*elastic.SearchHit, 0)},
		}, nil
	}
	queryResult, err := store.client.Search().
		Index(index).
		Query(elastic.NewMatchQuery("ParentId", parentId)).
		Size(store.maxPageSize).
		Sort("_id", false).
		Do(ctx)
	return queryResult, err
}

func (store *ElasticStore) searchAfter(ctx context.Context, index, parentId, after string) (result *elastic.SearchResult, err error) {
	queryResult, err := store.client.Search().
		Index(index).
		Query(elastic.NewMatchQuery("ParentId", parentId)).
		SearchAfter(after).
		Size(store.maxPageSize).
		Sort("_id", false).
		Do(ctx)
	return queryResult, err

}

func (store *ElasticStore) Shutdown() {
	store.client.Stop()
}

func getIndex(fullpath weed_util.FullPath) string {
	path := strings.Split(string(fullpath), "/")
	if len(path) > 1 {
		return indexPrefix + path[1]
	}
	return ""
}

func getFileName(fullpath weed_util.FullPath) string {
	path := strings.Split(string(fullpath), "/")
	if len(path) > 1 {
		return path[len(path)-1]
	}
	return ""
}
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.91"
<commit_msg>functions: 0.3.92 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.92"
<|endoftext|>


<commit_before>// Copyright 2017 Google 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"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

// grep checks whether the given file's contents match the pattern.
func grep(pattern string, file string) (bool, error) {
	input, err := os.OpenFile(file, os.O_RDONLY, 0)
	if err != nil {
		return false, fmt.Errorf("failed to open %s for read: %v", file, err)
	}
	defer input.Close()

	matched, err := regexp.MatchReader(pattern, bufio.NewReader(input))
	if err != nil {
		return false, fmt.Errorf("failed to search for %s in %s: %v", pattern, file, err)
	}

	return matched, nil
}

// checkLicense checks if the given file contains the necessary license information and returns an
// error if this is not true or if the check cannot be performed.
func checkLicense(workspaceDir string, file string) error {
	for _, pattern := range []string{
		`Copyright.*Google`,
		`Apache License.*2.0`,
	} {
		matched, err := grep(pattern, file)
		if err != nil {
			return fmt.Errorf("license check failed for %s: %v", file, err)
		}
		if !matched {
			return fmt.Errorf("license check failed for %s: %s not found", file, pattern)
		}
	}

	return nil
}

// checkNoTabs checks if the given file contains any tabs as indentation and, if it does, returns
// an error.
func checkNoTabs(workspaceDir string, file string) error {
	input, err := os.OpenFile(file, os.O_RDONLY, 0)
	if err != nil {
		return fmt.Errorf("failed to open %s for read: %v", file, err)
	}
	defer input.Close()

	preg := regexp.MustCompile(`^ *\t`)

	reader := bufio.NewReader(input)
	lineNo := 1
	done := false
	for !done {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			done = true
			// Fall through to process the last line in case it's not empty (when the
			// file didn't end with a newline).
		} else if err != nil {
			return fmt.Errorf("no tabs check failed for %s: %v", file, err)
		}
		if preg.MatchString(line) {
			return fmt.Errorf("no tabs check failed for %s: indentation tabs found at line %d", file, lineNo)
		}
		lineNo++
	}

	return nil
}

// runLinter is a helper function to run a linter that prints diagnostics to stdout and returns true
// even when the given files are not compliant.  The arguments indicate the full command line to
// run, including the path to the tool as the first argument.  The file to check is expected to
// appear as the last argument.
func runLinter(toolName string, arg ...string) error {
	file := arg[len(arg)-1]

	var output bytes.Buffer
	cmd := exec.Command(toolName, arg...)
	cmd.Stdout = &output
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("%s check failed for %s: %v", toolName, file, err)
	}
	if output.Len() > 0 {
		fmt.Printf("%s does not pass %s:\n", file, toolName)
		fmt.Println(output.String())
		return fmt.Errorf("%s check failed for %s: not compliant", toolName, file)
	}
	return nil
}

// checkGoFmt checks if the given file is formatted according to gofmt and, if not, prints a diff
// detailing what's wrong with the file to stdout and returns an error.
func checkGofmt(workspaceDir string, file string) error {
	return runLinter("gofmt", "-d", "-e", "-s", file)
}

// checkGoLint checks if the given file passes golint checks and, if not, prints diagnostic messages
// to stdout and returns an error.
func checkGolint(workspaceDir string, file string) error {
	// Lower confidence levels raise a per-file warning to remind about having a package-level
	// docstring... but the warning is issued blindly without checking for the existing of this
	// docstring in other packages.
	minConfidenceFlag := "-min_confidence=0.3"

	return runLinter("golint", minConfidenceFlag, file)
}

// checkAll runs all possible checks on a file.  Returns true if all checks pass, and false
// otherwise.  Error details are dumped to stderr.
func checkAll(workspaceDir string, file string) bool {
	isBuildFile := filepath.Base(file) == "Makefile.in"

	// If a file starts with an upper-case letter, assume it's supporting package documentation
	// (all those files in the root directory) and avoid linting it.
	isDocumentation := mustMatch(`^[A-Z]`, filepath.Base(file)) && !isBuildFile

	log.Printf("Linting file %s", file)
	ok := true

	runCheck := func(checker func(string, string) error, file string) {
		if err := checker(workspaceDir, file); err != nil {
			fmt.Fprintf(os.Stderr, "%s: %v\n", file, err)
			ok = false
		}
	}

	if !isDocumentation && filepath.Base(file) != "settings.json.in" {
		runCheck(checkLicense, file)
	}

	if filepath.Ext(file) == ".go" {
		runCheck(checkGofmt, file)
		runCheck(checkGolint, file)
	} else if !isBuildFile {
		runCheck(checkNoTabs, file)
	}

	return ok
}

// mustMatch returns true if the given regular expression matches the string.  The regular
// expression is assumed to be valid.
func mustMatch(pattern string, str string) bool {
	matched, err := regexp.MatchString(pattern, str)
	if err != nil {
		panic("invalid regexp")
	}
	return matched
}
<commit_msg>Lint manual pages<commit_after>// Copyright 2017 Google 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"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

// grep checks whether the given file's contents match the pattern.
func grep(pattern string, file string) (bool, error) {
	input, err := os.OpenFile(file, os.O_RDONLY, 0)
	if err != nil {
		return false, fmt.Errorf("failed to open %s for read: %v", file, err)
	}
	defer input.Close()

	matched, err := regexp.MatchReader(pattern, bufio.NewReader(input))
	if err != nil {
		return false, fmt.Errorf("failed to search for %s in %s: %v", pattern, file, err)
	}

	return matched, nil
}

// checkLicense checks if the given file contains the necessary license information and returns an
// error if this is not true or if the check cannot be performed.
func checkLicense(workspaceDir string, file string) error {
	for _, pattern := range []string{
		`Copyright.*Google`,
		`Apache License.*2.0`,
	} {
		matched, err := grep(pattern, file)
		if err != nil {
			return fmt.Errorf("license check failed for %s: %v", file, err)
		}
		if !matched {
			return fmt.Errorf("license check failed for %s: %s not found", file, pattern)
		}
	}

	return nil
}

// checkNoTabs checks if the given file contains any tabs as indentation and, if it does, returns
// an error.
func checkNoTabs(workspaceDir string, file string) error {
	input, err := os.OpenFile(file, os.O_RDONLY, 0)
	if err != nil {
		return fmt.Errorf("failed to open %s for read: %v", file, err)
	}
	defer input.Close()

	preg := regexp.MustCompile(`^ *\t`)

	reader := bufio.NewReader(input)
	lineNo := 1
	done := false
	for !done {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			done = true
			// Fall through to process the last line in case it's not empty (when the
			// file didn't end with a newline).
		} else if err != nil {
			return fmt.Errorf("no tabs check failed for %s: %v", file, err)
		}
		if preg.MatchString(line) {
			return fmt.Errorf("no tabs check failed for %s: indentation tabs found at line %d", file, lineNo)
		}
		lineNo++
	}

	return nil
}

// captureErrorsFromStdout configures the given non-started "cmd" to save its stdout into "output"
// and to print stderr to this process' stderr.
func captureErrorsFromStdout(cmd *exec.Cmd, output *bytes.Buffer) {
	cmd.Stdout = output
	cmd.Stderr = os.Stderr
}

// captureErrorsFromStderr configures the given non-started "cmd" to save its stderr into "output"
// and to silence its stdout.
func captureErrorsFromStderr(cmd *exec.Cmd, output *bytes.Buffer) {
	cmd.Stdout = nil
	cmd.Stderr = output
}

// runLinter runs a "linting" helper binary that prints diagnostics to some output and whose exit
// status is always true.  "captureErrors" takes a lambda to configure the command to save its
// diagnostics to the given buffer, and is used to account for tools that print messages to either
// stdout or stderr.  The remaining arguments indicate the full command line to run, including the
// path to the tool as the first argument.  The file to check is expected to appear as the last
// argument.
func runLinter(captureErrors func(*exec.Cmd, *bytes.Buffer), toolName string, arg ...string) error {
	file := arg[len(arg)-1]

	var output bytes.Buffer
	cmd := exec.Command(toolName, arg...)
	captureErrors(cmd, &output)
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("%s check failed for %s: %v", toolName, file, err)
	}
	if output.Len() > 0 {
		fmt.Printf("%s does not pass %s:\n", file, toolName)
		fmt.Println(output.String())
		return fmt.Errorf("%s check failed for %s: not compliant", toolName, file)
	}
	return nil
}

// checkGoFmt checks if the given file is formatted according to gofmt and, if not, prints a diff
// detailing what's wrong with the file to stdout and returns an error.
func checkGofmt(workspaceDir string, file string) error {
	return runLinter(captureErrorsFromStdout, "gofmt", "-d", "-e", "-s", file)
}

// checkGoLint checks if the given file passes golint checks and, if not, prints diagnostic messages
// to stdout and returns an error.
func checkGolint(workspaceDir string, file string) error {
	// Lower confidence levels raise a per-file warning to remind about having a package-level
	// docstring... but the warning is issued blindly without checking for the existing of this
	// docstring in other packages.
	minConfidenceFlag := "-min_confidence=0.3"

	return runLinter(captureErrorsFromStdout, "golint", minConfidenceFlag, file)
}

// checkManpage checks if the given manual page contains any formatting errors by attempting to
// render it.  The output of the rendering is ignored and any errors are printed to stdout,
// returning an error.
func checkManpage(workspaceDir string, file string) error {
	return runLinter(captureErrorsFromStderr, "man", file)
}

// checkAll runs all possible checks on a file.  Returns true if all checks pass, and false
// otherwise.  Error details are dumped to stderr.
func checkAll(workspaceDir string, file string) bool {
	isBuildFile := filepath.Base(file) == "Makefile.in"

	// If a file starts with an upper-case letter, assume it's supporting package documentation
	// (all those files in the root directory) and avoid linting it.
	isDocumentation := mustMatch(`^[A-Z]`, filepath.Base(file)) && !isBuildFile

	log.Printf("Linting file %s", file)
	ok := true

	runCheck := func(checker func(string, string) error, file string) {
		if err := checker(workspaceDir, file); err != nil {
			fmt.Fprintf(os.Stderr, "%s: %v\n", file, err)
			ok = false
		}
	}

	if !isDocumentation && filepath.Base(file) != "settings.json.in" {
		runCheck(checkLicense, file)
	}

	if filepath.Ext(file) == ".go" {
		runCheck(checkGofmt, file)
		runCheck(checkGolint, file)
	} else if mustMatch("^\\.[0-9]$", filepath.Ext(file)) {
		runCheck(checkManpage, file)
	} else if !isBuildFile {
		runCheck(checkNoTabs, file)
	}

	return ok
}

// mustMatch returns true if the given regular expression matches the string.  The regular
// expression is assumed to be valid.
func mustMatch(pattern string, str string) bool {
	matched, err := regexp.MatchString(pattern, str)
	if err != nil {
		panic("invalid regexp")
	}
	return matched
}
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.452"
<commit_msg>fnserver: 0.3.453 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.453"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.241"
<commit_msg>fnserver: 0.3.242 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.242"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.262"
<commit_msg>fnserver: 0.3.263 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.263"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.102"
<commit_msg>functions: 0.3.103 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.103"
<|endoftext|>