<commit_before>package pixelgl

import (
	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/pkg/errors"
)

// VertexFormat defines a data format in a vertex buffer.
//
// Example:
//
//   vf := VertexFormat{{Position, 2}, {Color, 4}, {TexCoord, 2}}
type VertexFormat []VertexAttribute

// Size returns the total size of all vertex attributes in a vertex format.
func (vf VertexFormat) Size() int {
	size := 0
	for _, va := range vf {
		size += va.Size
	}
	return size
}

// VertexAttribute specifies a single attribute in a vertex buffer.
// All vertex attributes are composed of float64s.
//
// A vertex attribute has a Purpose (such as Position, Color, etc.) and Size. Size specifies
// the number of float64s the vertex attribute is composed of.
type VertexAttribute struct {
	Purpose VertexAttributePurpose
	Size    int
}

// VertexAttributePurpose clarifies the purpose of a vertex attribute. This can be a color, position, texture
// coordinates or anything else.
//
// VertexAttributePurpose may be used to correctly assign data to a vertex buffer.
type VertexAttributePurpose int

// Position, Color and TexCoord are the standard vertex attributes.
//
// Feel free to define more vertex attribute purposes (e.g. in an effects library).
const (
	Position VertexAttributePurpose = iota
	Color
	TexCoord
	NumStandardVertexAttrib
)

// VertexUsage specifies how often the vertex array data will be updated.
type VertexUsage int

const (
	// StaticUsage means the data never or rarely gets updated.
	StaticUsage VertexUsage = gl.STATIC_DRAW

	// DynamicUsage means the data gets updated often.
	DynamicUsage VertexUsage = gl.DYNAMIC_DRAW

	// StreamUsage means the data gets updated every frame.
	StreamUsage VertexUsage = gl.STREAM_DRAW
)

// VertexDrawMode specifies how should the vertices be drawn.
type VertexDrawMode int

const (
	// PointsDrawMode just draws individual points
	PointsDrawMode VertexDrawMode = gl.POINTS

	// LinesDrawMode takes pairs of vertices and draws a line from each pair
	LinesDrawMode VertexDrawMode = gl.LINES

	// LineStripDrawMode takes each two subsequent vertices and draws a line from each two
	LineStripDrawMode VertexDrawMode = gl.LINE_STRIP

	// LineLoopDrawMode is same as line strip, but also draws a line between the first and the last vertex
	LineLoopDrawMode VertexDrawMode = gl.LINE_LOOP

	// TrianglesDrawMode takes triples of vertices and draws a triangle from each triple
	TrianglesDrawMode VertexDrawMode = gl.TRIANGLES

	// TriangleStripDrawMode takes each three subsequent vertices and draws a triangle from each three
	TriangleStripDrawMode VertexDrawMode = gl.TRIANGLE_STRIP

	// TriangleFanDrawMode draws triangles from the first vertex and each two subsequent: {0, 1, 2, 3} -> {0, 1, 2}, {0, 2, 3}.
	TriangleFanDrawMode VertexDrawMode = gl.TRIANGLE_FAN
)

// VertexArray is an OpenGL vertex array object that also holds it's own vertex buffer object.
// From the user's points of view, VertexArray is an array of vertices that can be drawn.
type VertexArray struct {
	parent BeginEnder
	format VertexFormat
	vao    uint32
	vbo    uint32
	mode   VertexDrawMode
	count  int
}

// NewVertexArray creates a new vertex array and wraps another BeginEnder around it.
func NewVertexArray(parent BeginEnder, format VertexFormat, mode VertexDrawMode, usage VertexUsage, data []float64) (*VertexArray, error) {
	parent.Begin()
	defer parent.End()

	va := &VertexArray{
		parent: parent,
		format: format,
		mode:   mode,
	}

	err := DoGLErr(func() {
		gl.GenVertexArrays(1, &va.vao)
		gl.BindVertexArray(va.vao)

		gl.GenBuffers(1, &va.vbo)
		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
		gl.BufferData(gl.ARRAY_BUFFER, 8*len(data), gl.Ptr(data), uint32(usage))

		stride := format.Size()
		va.count = len(data) / stride

		offset := 0
		for i, attr := range format {
			gl.VertexAttribPointer(
				uint32(i),
				int32(attr.Size),
				gl.DOUBLE,
				false,
				int32(8*stride),
				gl.PtrOffset(8*offset),
			)
			gl.EnableVertexAttribArray(uint32(i))
			offset += attr.Size
		}

		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
		gl.BindVertexArray(0)
	})
	if err != nil {
		return nil, errors.Wrap(err, "failed to create a vertex array")
	}

	return va, nil
}

// Delete deletes a vertex array and it's associated vertex buffer. Don't use a vertex array after deletion.
func (va *VertexArray) Delete() {
	DoNoBlock(func() {
		gl.DeleteVertexArrays(1, &va.vao)
		gl.DeleteBuffers(1, &va.vbo)
	})
}

// VertexFormat returns the format of the vertices inside a vertex array.
//
// Do not change this format!
func (va *VertexArray) VertexFormat() VertexFormat {
	return va.format
}

// SetDrawMode sets the draw mode of a vertex array. Subsequent calls to Draw will use this draw mode.
func (va *VertexArray) SetDrawMode(mode VertexDrawMode) {
	DoNoBlock(func() {
		va.mode = mode
	})
}

// DrawMode returns the most recently set draw mode of a vertex array.
func (va *VertexArray) DrawMode() VertexDrawMode {
	mode := DoVal(func() interface{} {
		return va.mode
	})
	return mode.(VertexDrawMode)
}

// Draw draws a vertex array.
func (va *VertexArray) Draw() {
	va.Begin()
	va.End()
}

// UpdateData overwrites the current vertex array data starting at the index offset.
//
// Offset is not a number of bytes, instead, it's an index in the array.
//
// If offset is negative or offset+len(data)>len(originaldata) the program panics.
func (va *VertexArray) UpdateData(offset int, data []float64) {
	DoNoBlock(func() {
		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
		gl.BufferSubData(gl.ARRAY_BUFFER, 8*offset, 8*len(data), gl.Ptr(data))
		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
		if err := getLastGLErr(); err != nil {
			panic(errors.Wrap(err, "failed to update vertex array"))
		}
	})
}

// Begin binds a vertex array and it's associated vertex buffer.
func (va *VertexArray) Begin() {
	va.parent.Begin()
	DoNoBlock(func() {
		gl.BindVertexArray(va.vao)
		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
	})
}

// End draws a vertex array and unbinds it alongside with it's associated vertex buffer.
func (va *VertexArray) End() {
	DoNoBlock(func() {
		gl.DrawArrays(uint32(va.mode), 0, int32(va.count))
		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
		gl.BindVertexArray(0)
	})
	va.parent.End()
}
<commit_msg>add VertexArray.Data function<commit_after>package pixelgl

import (
	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/pkg/errors"
)

// VertexFormat defines a data format in a vertex buffer.
//
// Example:
//
//   vf := VertexFormat{{Position, 2}, {Color, 4}, {TexCoord, 2}}
type VertexFormat []VertexAttribute

// Size returns the total size of all vertex attributes in a vertex format.
func (vf VertexFormat) Size() int {
	size := 0
	for _, va := range vf {
		size += va.Size
	}
	return size
}

// VertexAttribute specifies a single attribute in a vertex buffer.
// All vertex attributes are composed of float64s.
//
// A vertex attribute has a Purpose (such as Position, Color, etc.) and Size. Size specifies
// the number of float64s the vertex attribute is composed of.
type VertexAttribute struct {
	Purpose VertexAttributePurpose
	Size    int
}

// VertexAttributePurpose clarifies the purpose of a vertex attribute. This can be a color, position, texture
// coordinates or anything else.
//
// VertexAttributePurpose may be used to correctly assign data to a vertex buffer.
type VertexAttributePurpose int

// Position, Color and TexCoord are the standard vertex attributes.
//
// Feel free to define more vertex attribute purposes (e.g. in an effects library).
const (
	Position VertexAttributePurpose = iota
	Color
	TexCoord
	NumStandardVertexAttrib
)

// VertexUsage specifies how often the vertex array data will be updated.
type VertexUsage int

const (
	// StaticUsage means the data never or rarely gets updated.
	StaticUsage VertexUsage = gl.STATIC_DRAW

	// DynamicUsage means the data gets updated often.
	DynamicUsage VertexUsage = gl.DYNAMIC_DRAW

	// StreamUsage means the data gets updated every frame.
	StreamUsage VertexUsage = gl.STREAM_DRAW
)

// VertexDrawMode specifies how should the vertices be drawn.
type VertexDrawMode int

const (
	// PointsDrawMode just draws individual points
	PointsDrawMode VertexDrawMode = gl.POINTS

	// LinesDrawMode takes pairs of vertices and draws a line from each pair
	LinesDrawMode VertexDrawMode = gl.LINES

	// LineStripDrawMode takes each two subsequent vertices and draws a line from each two
	LineStripDrawMode VertexDrawMode = gl.LINE_STRIP

	// LineLoopDrawMode is same as line strip, but also draws a line between the first and the last vertex
	LineLoopDrawMode VertexDrawMode = gl.LINE_LOOP

	// TrianglesDrawMode takes triples of vertices and draws a triangle from each triple
	TrianglesDrawMode VertexDrawMode = gl.TRIANGLES

	// TriangleStripDrawMode takes each three subsequent vertices and draws a triangle from each three
	TriangleStripDrawMode VertexDrawMode = gl.TRIANGLE_STRIP

	// TriangleFanDrawMode draws triangles from the first vertex and each two subsequent: {0, 1, 2, 3} -> {0, 1, 2}, {0, 2, 3}.
	TriangleFanDrawMode VertexDrawMode = gl.TRIANGLE_FAN
)

// VertexArray is an OpenGL vertex array object that also holds it's own vertex buffer object.
// From the user's points of view, VertexArray is an array of vertices that can be drawn.
type VertexArray struct {
	parent BeginEnder
	format VertexFormat
	vao    uint32
	vbo    uint32
	mode   VertexDrawMode
	count  int
}

// NewVertexArray creates a new vertex array and wraps another BeginEnder around it.
func NewVertexArray(parent BeginEnder, format VertexFormat, mode VertexDrawMode, usage VertexUsage, data []float64) (*VertexArray, error) {
	parent.Begin()
	defer parent.End()

	va := &VertexArray{
		parent: parent,
		format: format,
		mode:   mode,
	}

	err := DoGLErr(func() {
		gl.GenVertexArrays(1, &va.vao)
		gl.BindVertexArray(va.vao)

		gl.GenBuffers(1, &va.vbo)
		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
		gl.BufferData(gl.ARRAY_BUFFER, 8*len(data), gl.Ptr(data), uint32(usage))

		stride := format.Size()
		va.count = len(data) / stride

		offset := 0
		for i, attr := range format {
			gl.VertexAttribPointer(
				uint32(i),
				int32(attr.Size),
				gl.DOUBLE,
				false,
				int32(8*stride),
				gl.PtrOffset(8*offset),
			)
			gl.EnableVertexAttribArray(uint32(i))
			offset += attr.Size
		}

		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
		gl.BindVertexArray(0)
	})
	if err != nil {
		return nil, errors.Wrap(err, "failed to create a vertex array")
	}

	return va, nil
}

// Delete deletes a vertex array and it's associated vertex buffer. Don't use a vertex array after deletion.
func (va *VertexArray) Delete() {
	DoNoBlock(func() {
		gl.DeleteVertexArrays(1, &va.vao)
		gl.DeleteBuffers(1, &va.vbo)
	})
}

// VertexFormat returns the format of the vertices inside a vertex array.
//
// Do not change this format!
func (va *VertexArray) VertexFormat() VertexFormat {
	return va.format
}

// SetDrawMode sets the draw mode of a vertex array. Subsequent calls to Draw will use this draw mode.
func (va *VertexArray) SetDrawMode(mode VertexDrawMode) {
	DoNoBlock(func() {
		va.mode = mode
	})
}

// DrawMode returns the most recently set draw mode of a vertex array.
func (va *VertexArray) DrawMode() VertexDrawMode {
	mode := DoVal(func() interface{} {
		return va.mode
	})
	return mode.(VertexDrawMode)
}

// Draw draws a vertex array.
func (va *VertexArray) Draw() {
	va.Begin()
	va.End()
}

// Data returns a copy of data inside a vertex array (actually it's vertex buffer).
func (va *VertexArray) Data() []float64 {
	data := make([]float64, va.count*va.format.Size())
	Do(func() {
		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
		gl.GetBufferSubData(gl.ARRAY_BUFFER, 0, 8*len(data), gl.Ptr(data))
		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	})
	return data
}

// UpdateData overwrites the current vertex array data starting at the index offset.
//
// Offset is not a number of bytes, instead, it's an index in the array.
//
// If offset is negative or offset+len(data)>len(originaldata) the program panics.
func (va *VertexArray) UpdateData(offset int, data []float64) {
	DoNoBlock(func() {
		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
		gl.BufferSubData(gl.ARRAY_BUFFER, 8*offset, 8*len(data), gl.Ptr(data))
		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
		if err := getLastGLErr(); err != nil {
			panic(errors.Wrap(err, "failed to update vertex array"))
		}
	})
}

// Begin binds a vertex array and it's associated vertex buffer.
func (va *VertexArray) Begin() {
	va.parent.Begin()
	DoNoBlock(func() {
		gl.BindVertexArray(va.vao)
		gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo)
	})
}

// End draws a vertex array and unbinds it alongside with it's associated vertex buffer.
func (va *VertexArray) End() {
	DoNoBlock(func() {
		gl.DrawArrays(uint32(va.mode), 0, int32(va.count))
		gl.BindBuffer(gl.ARRAY_BUFFER, 0)
		gl.BindVertexArray(0)
	})
	va.parent.End()
}
<|endoftext|>


<commit_before>package cluster

import (
	"fmt"
	"time"

	"github.com/gogo/protobuf/proto"
	"github.com/influxdb/influxdb/cluster/internal"
	"github.com/influxdb/influxdb/models"
)

//go:generate protoc --gogo_out=. internal/data.proto

// MapShardRequest represents the request to map a remote shard for a query.
type MapShardRequest struct {
	pb internal.MapShardRequest
}

// ShardID of the storage
func (m *MapShardRequest) ShardID() uint64 { return m.pb.GetShardID() }

// Query returns the protocol buffers' query string
func (m *MapShardRequest) Query() string { return m.pb.GetQuery() }

// ChunkSize - proto buff's chunk size
func (m *MapShardRequest) ChunkSize() int32 { return m.pb.GetChunkSize() }

// SetShardID sets the shard id
func (m *MapShardRequest) SetShardID(id uint64) { m.pb.ShardID = &id }

// SetQuery sets the proto buffs query
func (m *MapShardRequest) SetQuery(query string) { m.pb.Query = &query }

// SetChunkSize sets the proto buffs chunk size
func (m *MapShardRequest) SetChunkSize(chunkSize int32) { m.pb.ChunkSize = &chunkSize }

// MarshalBinary encodes the object to a binary format.
func (m *MapShardRequest) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&m.pb)
}

// UnmarshalBinary populates MapShardRequest from a binary format.
func (m *MapShardRequest) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &m.pb); err != nil {
		return err
	}
	return nil
}

// MapShardResponse represents the response returned from a remote MapShardRequest call
type MapShardResponse struct {
	pb internal.MapShardResponse
}

// NewMapShardResponse returns the response returned from a remote MapShardRequest call
func NewMapShardResponse(code int, message string) *MapShardResponse {
	m := &MapShardResponse{}
	m.SetCode(code)
	m.SetMessage(message)
	return m
}

// Code returns the proto buff code
func (r *MapShardResponse) Code() int { return int(r.pb.GetCode()) }

// Message returns the proto buff Message
func (r *MapShardResponse) Message() string { return r.pb.GetMessage() }

// TagSets returns the proto buff tag sets
func (r *MapShardResponse) TagSets() []string { return r.pb.GetTagSets() }

// Fields returns the proto buff Fields
func (r *MapShardResponse) Fields() []string { return r.pb.GetFields() }

// Data returns the proto buff Data
func (r *MapShardResponse) Data() []byte { return r.pb.GetData() }

// SetCode sets the proto buff code
func (r *MapShardResponse) SetCode(code int) { r.pb.Code = proto.Int32(int32(code)) }

// SetMessage sets the proto buff message
func (r *MapShardResponse) SetMessage(message string) { r.pb.Message = &message }

// SetTagSets sets the proto buff tagsets
func (r *MapShardResponse) SetTagSets(tagsets []string) { r.pb.TagSets = tagsets }

// SetFields sets the proto buff Fields
func (r *MapShardResponse) SetFields(fields []string) { r.pb.Fields = fields }

// SetData sets the proto buff Data
func (r *MapShardResponse) SetData(data []byte) { r.pb.Data = data }

// MarshalBinary encodes the object to a binary format.
func (r *MapShardResponse) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&r.pb)
}

// UnmarshalBinary populates WritePointRequest from a binary format.
func (r *MapShardResponse) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &r.pb); err != nil {
		return err
	}
	return nil
}

// WritePointsRequest represents a request to write point data to the cluster
type WritePointsRequest struct {
	Database         string
	RetentionPolicy  string
	ConsistencyLevel ConsistencyLevel
	Points           []models.Point
}

// AddPoint adds a point to the WritePointRequest with field name 'value'
func (w *WritePointsRequest) AddPoint(name string, value interface{}, timestamp time.Time, tags map[string]string) {
	w.Points = append(w.Points, models.NewPoint(
		name, tags, map[string]interface{}{"value": value}, timestamp,
	))
}

// WriteShardRequest represents the a request to write a slice of points to a shard
type WriteShardRequest struct {
	pb internal.WriteShardRequest
}

// WriteShardResponse represents the response returned from a remote WriteShardRequest call
type WriteShardResponse struct {
	pb internal.WriteShardResponse
}

// SetShardID sets the ShardID
func (w *WriteShardRequest) SetShardID(id uint64) { w.pb.ShardID = &id }

// ShardID gets the ShardID
func (w *WriteShardRequest) ShardID() uint64 { return w.pb.GetShardID() }

// Points returns the time series Points
func (w *WriteShardRequest) Points() []models.Point { return w.unmarshalPoints() }

// AddPoint adds a new time series point
func (w *WriteShardRequest) AddPoint(name string, value interface{}, timestamp time.Time, tags map[string]string) {
	w.AddPoints([]models.Point{models.NewPoint(
		name, tags, map[string]interface{}{"value": value}, timestamp,
	)})
}

// AddPoints adds a new time series point
func (w *WriteShardRequest) AddPoints(points []models.Point) {
	for _, p := range points {
		w.pb.Points = append(w.pb.Points, []byte(p.String()))
	}
}

// MarshalBinary encodes the object to a binary format.
func (w *WriteShardRequest) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&w.pb)
}

// UnmarshalBinary populates WritePointRequest from a binary format.
func (w *WriteShardRequest) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &w.pb); err != nil {
		return err
	}
	return nil
}

func (w *WriteShardRequest) unmarshalPoints() []models.Point {
	points := make([]models.Point, len(w.pb.GetPoints()))
	for i, p := range w.pb.GetPoints() {
		pt, err := models.ParsePoints(p)
		if err != nil {
			// A error here means that one node parsed the point correctly but sent an
			// unparseable version to another node.  We could log and drop the point and allow
			// anti-entropy to resolve the discrepancy but this shouldn't ever happen.
			panic(fmt.Sprintf("failed to parse point: `%v`: %v", string(p), err))
		}
		points[i] = pt[0]
	}
	return points
}

// SetCode sets the Code
func (w *WriteShardResponse) SetCode(code int) { w.pb.Code = proto.Int32(int32(code)) }

// SetMessage sets the Message
func (w *WriteShardResponse) SetMessage(message string) { w.pb.Message = &message }

// Code returns the Code
func (w *WriteShardResponse) Code() int { return int(w.pb.GetCode()) }

// Message returns the Message
func (w *WriteShardResponse) Message() string { return w.pb.GetMessage() }

// MarshalBinary encodes the object to a binary format.
func (w *WriteShardResponse) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&w.pb)
}

// UnmarshalBinary populates WritePointRequest from a binary format.
func (w *WriteShardResponse) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &w.pb); err != nil {
		return err
	}
	return nil
}
<commit_msg>Fixed comments. Issue: Enable golint on the code base #4098 (changes only for the cluster subpackage)<commit_after>package cluster

import (
	"fmt"
	"time"

	"github.com/gogo/protobuf/proto"
	"github.com/influxdb/influxdb/cluster/internal"
	"github.com/influxdb/influxdb/models"
)

//go:generate protoc --gogo_out=. internal/data.proto

// MapShardRequest represents the request to map a remote shard for a query.
type MapShardRequest struct {
	pb internal.MapShardRequest
}

// ShardID of the map request
func (m *MapShardRequest) ShardID() uint64 { return m.pb.GetShardID() }

// Query returns the Shard map request's query
func (m *MapShardRequest) Query() string { return m.pb.GetQuery() }

// ChunkSize returns Shard map request's chunk size
func (m *MapShardRequest) ChunkSize() int32 { return m.pb.GetChunkSize() }

// SetShardID sets the map request's shard id
func (m *MapShardRequest) SetShardID(id uint64) { m.pb.ShardID = &id }

// SetQuery sets the Shard map request's Query
func (m *MapShardRequest) SetQuery(query string) { m.pb.Query = &query }

// SetChunkSize sets the Shard map request's chunk size
func (m *MapShardRequest) SetChunkSize(chunkSize int32) { m.pb.ChunkSize = &chunkSize }

// MarshalBinary encodes the object to a binary format.
func (m *MapShardRequest) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&m.pb)
}

// UnmarshalBinary populates MapShardRequest from a binary format.
func (m *MapShardRequest) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &m.pb); err != nil {
		return err
	}
	return nil
}

// MapShardResponse represents the response returned from a remote MapShardRequest call
type MapShardResponse struct {
	pb internal.MapShardResponse
}

// NewMapShardResponse returns the response returned from a remote MapShardRequest call
func NewMapShardResponse(code int, message string) *MapShardResponse {
	m := &MapShardResponse{}
	m.SetCode(code)
	m.SetMessage(message)
	return m
}

// Code returns the Shard map response's code
func (r *MapShardResponse) Code() int { return int(r.pb.GetCode()) }

// Message returns the the Shard map response's Message
func (r *MapShardResponse) Message() string { return r.pb.GetMessage() }

// TagSets returns Shard map response's tag sets
func (r *MapShardResponse) TagSets() []string { return r.pb.GetTagSets() }

// Fields returns the Shard map response's Fields
func (r *MapShardResponse) Fields() []string { return r.pb.GetFields() }

// Data returns the Shard map response's Data
func (r *MapShardResponse) Data() []byte { return r.pb.GetData() }

// SetCode sets the Shard map response's code
func (r *MapShardResponse) SetCode(code int) { r.pb.Code = proto.Int32(int32(code)) }

// SetMessage sets Shard map response's message
func (r *MapShardResponse) SetMessage(message string) { r.pb.Message = &message }

// SetTagSets sets Shard map response's tagsets
func (r *MapShardResponse) SetTagSets(tagsets []string) { r.pb.TagSets = tagsets }

// SetFields sets the Shard map response's Fields
func (r *MapShardResponse) SetFields(fields []string) { r.pb.Fields = fields }

// SetData sets the Shard map response's Data
func (r *MapShardResponse) SetData(data []byte) { r.pb.Data = data }

// MarshalBinary encodes the object to a binary format.
func (r *MapShardResponse) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&r.pb)
}

// UnmarshalBinary populates WritePointRequest from a binary format.
func (r *MapShardResponse) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &r.pb); err != nil {
		return err
	}
	return nil
}

// WritePointsRequest represents a request to write point data to the cluster
type WritePointsRequest struct {
	Database         string
	RetentionPolicy  string
	ConsistencyLevel ConsistencyLevel
	Points           []models.Point
}

// AddPoint adds a point to the WritePointRequest with field name 'value'
func (w *WritePointsRequest) AddPoint(name string, value interface{}, timestamp time.Time, tags map[string]string) {
	w.Points = append(w.Points, models.NewPoint(
		name, tags, map[string]interface{}{"value": value}, timestamp,
	))
}

// WriteShardRequest represents the a request to write a slice of points to a shard
type WriteShardRequest struct {
	pb internal.WriteShardRequest
}

// WriteShardResponse represents the response returned from a remote WriteShardRequest call
type WriteShardResponse struct {
	pb internal.WriteShardResponse
}

// SetShardID sets the ShardID
func (w *WriteShardRequest) SetShardID(id uint64) { w.pb.ShardID = &id }

// ShardID gets the ShardID
func (w *WriteShardRequest) ShardID() uint64 { return w.pb.GetShardID() }

// Points returns the time series Points
func (w *WriteShardRequest) Points() []models.Point { return w.unmarshalPoints() }

// AddPoint adds a new time series point
func (w *WriteShardRequest) AddPoint(name string, value interface{}, timestamp time.Time, tags map[string]string) {
	w.AddPoints([]models.Point{models.NewPoint(
		name, tags, map[string]interface{}{"value": value}, timestamp,
	)})
}

// AddPoints adds a new time series point
func (w *WriteShardRequest) AddPoints(points []models.Point) {
	for _, p := range points {
		w.pb.Points = append(w.pb.Points, []byte(p.String()))
	}
}

// MarshalBinary encodes the object to a binary format.
func (w *WriteShardRequest) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&w.pb)
}

// UnmarshalBinary populates WritePointRequest from a binary format.
func (w *WriteShardRequest) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &w.pb); err != nil {
		return err
	}
	return nil
}

func (w *WriteShardRequest) unmarshalPoints() []models.Point {
	points := make([]models.Point, len(w.pb.GetPoints()))
	for i, p := range w.pb.GetPoints() {
		pt, err := models.ParsePoints(p)
		if err != nil {
			// A error here means that one node parsed the point correctly but sent an
			// unparseable version to another node.  We could log and drop the point and allow
			// anti-entropy to resolve the discrepancy but this shouldn't ever happen.
			panic(fmt.Sprintf("failed to parse point: `%v`: %v", string(p), err))
		}
		points[i] = pt[0]
	}
	return points
}

// SetCode sets the Code
func (w *WriteShardResponse) SetCode(code int) { w.pb.Code = proto.Int32(int32(code)) }

// SetMessage sets the Message
func (w *WriteShardResponse) SetMessage(message string) { w.pb.Message = &message }

// Code returns the Code
func (w *WriteShardResponse) Code() int { return int(w.pb.GetCode()) }

// Message returns the Message
func (w *WriteShardResponse) Message() string { return w.pb.GetMessage() }

// MarshalBinary encodes the object to a binary format.
func (w *WriteShardResponse) MarshalBinary() ([]byte, error) {
	return proto.Marshal(&w.pb)
}

// UnmarshalBinary populates WritePointRequest from a binary format.
func (w *WriteShardResponse) UnmarshalBinary(buf []byte) error {
	if err := proto.Unmarshal(buf, &w.pb); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"log"
	"strconv"

	bitcoin "github.com/btcsuite/btcrpcclient"
	"github.com/heraware/cryptodev/clients"
	"github.com/spf13/cobra"
)

// bitcoinCmd represents the bitcoin command
var bitcoinCmd = &cobra.Command{
	Use:   "bitcoin",
	Short: "Run RPC command over Bitcoin Node (getinfo, getnewaddress, listaccounts)",
	Run: func(cmd *cobra.Command, args []string) {
		bitcoinClient := clients.NewBitcoinClient()

		if len(args) == 0 {
			log.Fatalln("Action not provided. Actions list: getinfo, getnewaddress, listaccounts")
		}
		switch args[0] {
		case "getinfo":
			getInfo(bitcoinClient)
		case "getnewaddress":
			getNewAddress(bitcoinClient, &args)
		case "listaccounts":
			listAccounts(bitcoinClient)
		case "newblocks":
			newBlocks(bitcoinClient, &args)
		default:
			log.Fatal(fmt.Sprintf("Action %s is not valid.", args[0]))
		}
	},
}

func init() {
	RootCmd.AddCommand(bitcoinCmd)
}

func getNewAddress(bitcoinClient *bitcoin.Client, args *[]string) {
	account := ""
	if len(*args) > 1 {
		account = (*args)[1]
	}
	address, err := bitcoinClient.GetNewAddress(account)
	if err != nil {
		log.Fatal(err)
	}
	result := fmt.Sprintf("Address: %s Account: %s", address, account)
	fmt.Println(result)
}

func listAccounts(bitcoinClient *bitcoin.Client) {
	accounts, err := bitcoinClient.ListAccounts()
	if err != nil {
		log.Fatal(err)
	}
	for accountName, amountBTC := range accounts {
		fmt.Println(fmt.Sprintf(
			"Account name: %s - BTC Amount: %s", accountName, amountBTC))
	}
}

func getInfo(bitcoinClient *bitcoin.Client) {
	info, err := bitcoinClient.GetInfo()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fmt.Sprintf(`
Version         %d
ProtocolVersion %d
WalletVersion   %d
Balance         %f
Blocks          %d
TimeOffset      %d
Connections     %d
Proxy           %s
Difficulty      %f
TestNet         %t
KeypoolOldest   %d
KeypoolSize     %d
UnlockedUntil   %d
PaytxFee        %f
RelayFee        %f
Errors          %s
		`, info.Version, info.ProtocolVersion, info.WalletVersion, info.Balance,
		info.Blocks, info.TimeOffset, info.Connections, info.Proxy,
		info.Difficulty, info.TestNet, info.KeypoolOldest, info.KeypoolSize,
		info.UnlockedUntil, info.PaytxFee, info.RelayFee, info.Errors))
}

func newBlocks(bitcoinClient *bitcoin.Client, args *[]string) {
	var amountBlocks uint64 = 1
	var err error
	if len(*args) > 1 {
		amountBlocks, err = strconv.ParseUint((*args)[1], 10, 32)
		if err != nil {
			log.Fatal(err)
		}
	}
	hashes, err := bitcoinClient.Generate(uint32(amountBlocks))
	if err != nil {
		log.Fatal(err)
	}
	for i := 0; i < len(hashes); i++ {
		fmt.Println(fmt.Sprintf("Block: %v", hashes[i]))
	}
}
<commit_msg>Add send bitcoin function<commit_after>package cmd

import (
	"fmt"
	"log"
	"strconv"

	bitcoin "github.com/btcsuite/btcrpcclient"
	"github.com/btcsuite/btcutil"
	"github.com/heraware/cryptodev/clients"
	"github.com/spf13/cobra"
)

// bitcoinCmd represents the bitcoin command
var bitcoinCmd = &cobra.Command{
	Use:   "bitcoin",
	Short: "Run RPC command over Bitcoin Node (getinfo, getnewaddress, listaccounts)",
	Run: func(cmd *cobra.Command, args []string) {
		bitcoinClient := clients.NewBitcoinClient()

		if len(args) == 0 {
			log.Fatalln("Action not provided. Actions list: getinfo, getnewaddress, listaccounts")
		}
		switch args[0] {
		case "getinfo":
			getInfo(bitcoinClient)
		case "getnewaddress":
			getNewAddress(bitcoinClient, &args)
		case "listaccounts":
			listAccounts(bitcoinClient)
		case "newblocks":
			newBlocks(bitcoinClient, &args)
		case "send":
			send(bitcoinClient, &args)
		default:
			log.Fatal(fmt.Sprintf("Action %s is not valid.", args[0]))
		}
	},
}

func init() {
	RootCmd.AddCommand(bitcoinCmd)
}

func getNewAddress(bitcoinClient *bitcoin.Client, args *[]string) {
	account := ""
	if len(*args) > 1 {
		account = (*args)[1]
	}
	address, err := bitcoinClient.GetNewAddress(account)
	if err != nil {
		log.Fatal(err)
	}
	result := fmt.Sprintf("Address: %s Account: %s", address, account)
	fmt.Println(result)
}

func listAccounts(bitcoinClient *bitcoin.Client) {
	accounts, err := bitcoinClient.ListAccounts()
	if err != nil {
		log.Fatal(err)
	}
	for accountName, amountBTC := range accounts {
		fmt.Println(fmt.Sprintf(
			"Account name: %s - BTC Amount: %s", accountName, amountBTC))
	}
}

func getInfo(bitcoinClient *bitcoin.Client) {
	info, err := bitcoinClient.GetInfo()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(fmt.Sprintf(`
Version         %d
ProtocolVersion %d
WalletVersion   %d
Balance         %f
Blocks          %d
TimeOffset      %d
Connections     %d
Proxy           %s
Difficulty      %f
TestNet         %t
KeypoolOldest   %d
KeypoolSize     %d
UnlockedUntil   %d
PaytxFee        %f
RelayFee        %f
Errors          %s
		`, info.Version, info.ProtocolVersion, info.WalletVersion, info.Balance,
		info.Blocks, info.TimeOffset, info.Connections, info.Proxy,
		info.Difficulty, info.TestNet, info.KeypoolOldest, info.KeypoolSize,
		info.UnlockedUntil, info.PaytxFee, info.RelayFee, info.Errors))
}

func newBlocks(bitcoinClient *bitcoin.Client, args *[]string) {
	var amountBlocks uint64 = 1
	var err error
	if len(*args) > 1 {
		amountBlocks, err = strconv.ParseUint((*args)[1], 10, 32)
		if err != nil {
			log.Fatal(err)
		}
	}
	hashes, err := bitcoinClient.Generate(uint32(amountBlocks))
	if err != nil {
		log.Fatal(err)
	}
	for i := 0; i < len(hashes); i++ {
		fmt.Println(fmt.Sprintf("Block: %v", hashes[i]))
	}
}

func send(bitcoinClient *bitcoin.Client, args *[]string) {
	var address btcutil.Address
	var amountFloat float64
	var amount btcutil.Amount
	var err error
	if len(*args) > 2 {
		address, err = btcutil.DecodeAddress((*args)[1], nil)
		if err != nil {
			log.Fatal(err)
		}
		amountFloat, err = strconv.ParseFloat((*args)[2], 64)
		if err != nil {
			log.Fatal(err)
		}
		amount, err = btcutil.NewAmount(amountFloat)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		log.Fatal("Put all arguments to this action. send <BTC ADDRESS> <BTC AMOUNT>")
	}
	bitcoinClient.SendToAddress(address, amount)
}
<|endoftext|>


<commit_before>package paths

import (
	"archive/zip"
	"fmt"
	"io"
	"os"
	"os/exec"
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestArchive(t *testing.T) {

	Convey("Tests for Uncompress", t, func() {

		testHas7 = false
		Convey("Uncompress fails if p is a folder", func() {
			p := NewPath(".")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip '.\' for '<nil>'
'read .\: The handle is invalid.'`)
		})

		Convey("Uncompress fails if p is a non-existing file", func() {
			p := NewPath("xxx")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'xxx' for '<nil>'
'open xxx: The system cannot find the file specified.'`)
		})

		Convey("Uncompress fails if p is not a zip file", func() {
			p := NewPath("paths.go")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'paths.go' for '<nil>'
'zip: not a valid zip file'`)
		})

		Convey("cloneZipItem can fail on a particular item", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			testmkd = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while mkdir for zip element: 'testzip'`)
			testmkd = false
		})

		Convey("cloneZipItem can fail on opening a particular item file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fzipfileopen = testfzipfileopen
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while checking if zip element is a file: 'testzip/'
'Error (Open) zip.File for 'testzip/''`)
			fzipfileopen = ifzipfileopen
		})

		Convey("cloneZipItem can fail on creating a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscreate = testfoscreate
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while creating zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (Create) zip element '.\testzip\a.txt''`)
			foscreate = ifoscreate
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on copying a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fiocopy = testfiocopy
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while copying zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (io.Copy) zip element'`)
			fiocopy = ifiocopy
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscloseze = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip element '.\testzip\a.txt'
err='Error (Close) closing zip element '.\testzip\a.txt''`)
			foscloseze = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a zip file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclose = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip file 'testzip/'
err='Error (Close) closing zip element 'testzip/''`)
			fosclose = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing zip archive file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclosearc = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [func] (*Path.Uncompress) (func)
      Error while closing zip archive 'testzip.zip'
err='Error (Close) closing zip element 'testzip.zip''`)
			fosclosearc = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem of a valid zip archives succeed", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeTrue)
			So(NoOutput(), ShouldBeTrue)
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

	})

	Convey("Tests for Uncompress 7z", t, func() {

		p := NewPath("testzip.zip")
		So(check7z(), ShouldBeNil)
		Convey("fcmd should not be empty", func() {
			SetBuffers(nil)
			fc := cmd7z()
			So(fc, ShouldBeEmpty)
			fcmd = "7z/7z.exe"
			fc = cmd7z()
			So(fc, ShouldEndWith, `7z/7z.exe`)
		})

		Convey("uncompress7z is false if destination folder is empty", func() {
			SetBuffers(nil)
			b := p.uncompress7z(nil, nil, "test", false)
			So(b, ShouldBeFalse)
		})

		Convey("Uncompress can call 7z if path ends with .7z", func() {
			testHas7 = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			testHas7 = false
		})
	})
}

func check7z() error {
	p := NewPath("7z/7z.exe")
	if p.Exists() {
		return nil
	}
	cmdStr := "git submodule update --init"
	out, err := exec.Command("cmd", "/c", cmdStr).Output()
	Perrdbgf("Init 7z '%v", string(out))
	return err
}

func testfzipfileopen(f *zip.File) (rc io.ReadCloser, err error) {
	return nil, fmt.Errorf("Error (Open) zip.File for '%s'", f.Name)
}
func testfoscreate(name string) (file *os.File, err error) {
	return nil, fmt.Errorf("Error (Create) zip element '%s'", name)
}
func testfiocopy(dst io.Writer, src io.Reader) (written int64, err error) {
	return 0, fmt.Errorf("Error (io.Copy) zip element")
}
func testfosclose(f io.ReadCloser, name string) (err error) {
	ifosclose(f, name)
	return fmt.Errorf("Error (Close) closing zip element '%v'", name)
}

/*
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo a> testzip\a.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo ab> testzip\b.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip\c
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo abcd> testzip\c\abcd.txt
http://askubuntu.com/questions/58889/how-can-i-create-a-zip-archive-of-a-whole-directory-via-terminal-without-hidden
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>zip -r testzip.zip testzip
  adding: testzip/ (164 bytes security) (stored 0%)
  adding: testzip/a.txt (164 bytes security) (stored 0%)
  adding: testzip/b.txt (164 bytes security) (stored 0%)
  adding: testzip/c/ (164 bytes security) (stored 0%)
  adding: testzip/c/abcd.txt (164 bytes security) (stored 0%)
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>testzip.zip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>rm -Rf testzip
*/
<commit_msg>Test Paths uncompress7z which fails when fcmd is empty<commit_after>package paths

import (
	"archive/zip"
	"fmt"
	"io"
	"os"
	"os/exec"
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestArchive(t *testing.T) {

	Convey("Tests for Uncompress", t, func() {

		testHas7 = false
		Convey("Uncompress fails if p is a folder", func() {
			p := NewPath(".")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip '.\' for '<nil>'
'read .\: The handle is invalid.'`)
		})

		Convey("Uncompress fails if p is a non-existing file", func() {
			p := NewPath("xxx")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'xxx' for '<nil>'
'open xxx: The system cannot find the file specified.'`)
		})

		Convey("Uncompress fails if p is not a zip file", func() {
			p := NewPath("paths.go")
			SetBuffers(nil)
			b := p.Uncompress(nil)
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `  [*Path.Uncompress] (func)
    Error while opening zip 'paths.go' for '<nil>'
'zip: not a valid zip file'`)
		})

		Convey("cloneZipItem can fail on a particular item", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			testmkd = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while mkdir for zip element: 'testzip'`)
			testmkd = false
		})

		Convey("cloneZipItem can fail on opening a particular item file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fzipfileopen = testfzipfileopen
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while checking if zip element is a file: 'testzip/'
'Error (Open) zip.File for 'testzip/''`)
			fzipfileopen = ifzipfileopen
		})

		Convey("cloneZipItem can fail on creating a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscreate = testfoscreate
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while creating zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (Create) zip element '.\testzip\a.txt''`)
			foscreate = ifoscreate
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on copying a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fiocopy = testfiocopy
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [cloneZipItem] (*Path.Uncompress) (func)
      Error while copying zip element to '.\testzip\a.txt' from 'testzip/a.txt'
err='Error (io.Copy) zip element'`)
			fiocopy = ifiocopy
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a particular item element", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			foscloseze = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip element '.\testzip\a.txt'
err='Error (Close) closing zip element '.\testzip\a.txt''`)
			foscloseze = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing a zip file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclose = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `      [func] (cloneZipItem) (*Path.Uncompress) (func)
        Error while closing zip file 'testzip/'
err='Error (Close) closing zip element 'testzip/''`)
			fosclose = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem can fail on closing zip archive file", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			fosclosearc = testfosclose
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			So(OutString(), ShouldBeEmpty)
			So(ErrString(), ShouldEqualNL, `    [func] (*Path.Uncompress) (func)
      Error while closing zip archive 'testzip.zip'
err='Error (Close) closing zip element 'testzip.zip''`)
			fosclosearc = ifosclose
			NewPath("testzip").DeleteFolder()
		})

		Convey("cloneZipItem of a valid zip archives succeed", func() {
			p := NewPath("testzip.zip")
			SetBuffers(nil)
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeTrue)
			So(NoOutput(), ShouldBeTrue)
			So(NewPath("testzip").DeleteFolder(), ShouldBeNil)
		})

	})

	Convey("Tests for Uncompress 7z", t, func() {

		p := NewPath("testzip.zip")
		folder := NewPath(".")
		So(check7z(), ShouldBeNil)
		Convey("fcmd should not be empty", func() {
			SetBuffers(nil)
			fc := cmd7z()
			So(fc, ShouldBeEmpty)
			fcmd = "7z/7z.exe"
			fc = cmd7z()
			So(fc, ShouldEndWith, `7z/7z.exe`)
		})

		Convey("uncompress7z is false if destination folder is empty", func() {
			SetBuffers(nil)
			b := p.uncompress7z(nil, nil, "test", false)
			So(b, ShouldBeFalse)
		})

		Convey("uncompress7z is false if fcmd is empty", func() {
			SetBuffers(nil)
			fcmd = ""
			b := p.uncompress7z(folder, nil, "test", false)
			So(b, ShouldBeFalse)
			So(fcmd, ShouldBeEmpty)
			fcmd = "7z/7z.exe"
		})

		Convey("Uncompress can call 7z if path ends with .7z", func() {
			testHas7 = true
			b := p.Uncompress(NewPath("."))
			So(b, ShouldBeFalse)
			testHas7 = false
		})
	})
}

func check7z() error {
	p := NewPath("7z/7z.exe")
	if p.Exists() {
		return nil
	}
	cmdStr := "git submodule update --init"
	out, err := exec.Command("cmd", "/c", cmdStr).Output()
	Perrdbgf("Init 7z '%v", string(out))
	return err
}

func testfzipfileopen(f *zip.File) (rc io.ReadCloser, err error) {
	return nil, fmt.Errorf("Error (Open) zip.File for '%s'", f.Name)
}
func testfoscreate(name string) (file *os.File, err error) {
	return nil, fmt.Errorf("Error (Create) zip element '%s'", name)
}
func testfiocopy(dst io.Writer, src io.Reader) (written int64, err error) {
	return 0, fmt.Errorf("Error (io.Copy) zip element")
}
func testfosclose(f io.ReadCloser, name string) (err error) {
	ifosclose(f, name)
	return fmt.Errorf("Error (Close) closing zip element '%v'", name)
}

/*
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo a> testzip\a.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo ab> testzip\b.txt
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>mkdir testzip\c
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>echo abcd> testzip\c\abcd.txt
http://askubuntu.com/questions/58889/how-can-i-create-a-zip-archive-of-a-whole-directory-via-terminal-without-hidden
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>zip -r testzip.zip testzip
  adding: testzip/ (164 bytes security) (stored 0%)
  adding: testzip/a.txt (164 bytes security) (stored 0%)
  adding: testzip/b.txt (164 bytes security) (stored 0%)
  adding: testzip/c/ (164 bytes security) (stored 0%)
  adding: testzip/c/abcd.txt (164 bytes security) (stored 0%)
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>testzip.zip
C:\Users\vonc\prog\go\src\github.com\VonC\senvgo\paths>rm -Rf testzip
*/
<|endoftext|>


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

package cmd

import (
	"context"
	"fmt"
	"net/url"
	"strings"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/colorjson"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/pkg/console"
)

// du specific flags.
var (
	duFlags = []cli.Flag{
		cli.IntFlag{
			Name:  "depth, d",
			Usage: "print the total for a folder prefix only if it is N or fewer levels below the command line argument",
		},
		cli.BoolFlag{
			Name:  "recursive, r",
			Usage: "recursively print the total for a folder prefix",
		},
		cli.StringFlag{
			Name:  "rewind",
			Usage: "include all object versions no later than specified date",
		},
		cli.BoolFlag{
			Name:  "versions",
			Usage: "include all object versions",
		},
	}
)

// Summarize disk usage.
var duCmd = cli.Command{
	Name:         "du",
	Usage:        "summarize disk usage recursively",
	Action:       mainDu,
	OnUsageError: onUsageError,
	Before:       setGlobalsFromContext,
	Flags:        append(append(duFlags, ioFlags...), globalFlags...),
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} [FLAGS] TARGET

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
ENVIRONMENT VARIABLES:
  MC_ENCRYPT_KEY: list of comma delimited prefix=secret values

EXAMPLES:
  1. Summarize disk usage of 'jazz-songs' bucket recursively.
     {{.Prompt}} {{.HelpName}} s3/jazz-songs

  2. Summarize disk usage of 'louis' prefix in 'jazz-songs' bucket upto two levels.
     {{.Prompt}} {{.HelpName}} --depth=2 s3/jazz-songs/louis/

  3. Summarize disk usage of 'jazz-songs' bucket at a fixed date/time
     {{.Prompt}} {{.HelpName}} --rewind "2020.01.01" s3/jazz-songs/

  4. Summarize disk usage of 'jazz-songs' bucket with all objects versions
     {{.Prompt}} {{.HelpName}} --versions s3/jazz-songs/
`,
}

// Structured message depending on the type of console.
type duMessage struct {
	Prefix string `json:"prefix"`
	Size   int64  `json:"size"`
	Status string `json:"status"`
}

// Colorized message for console printing.
func (r duMessage) String() string {
	humanSize := strings.Join(strings.Fields(humanize.IBytes(uint64(r.Size))), "")

	return fmt.Sprintf("%s\t%s", console.Colorize("Size", humanSize),
		console.Colorize("Prefix", r.Prefix))
}

// JSON'ified message for scripting.
func (r duMessage) JSON() string {
	msgBytes, e := json.MarshalIndent(r, "", " ")
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
	return string(msgBytes)
}

func du(ctx context.Context, urlStr string, timeRef time.Time, withVersions bool, depth int, encKeyDB map[string][]prefixSSEPair) (int64, error) {
	targetAlias, targetURL, _ := mustExpandAlias(urlStr)
	if !strings.HasSuffix(targetURL, "/") {
		targetURL += "/"
	}

	clnt, pErr := newClientFromAlias(targetAlias, targetURL)
	if pErr != nil {
		errorIf(pErr.Trace(urlStr), "Failed to summarize disk usage `"+urlStr+"`.")
		return 0, exitStatus(globalErrorExitStatus) // End of journey.
	}

	// No disk usage details below this level,
	// just do a recursive listing
	recursive := depth == 1

	contentCh := clnt.List(ctx, ListOptions{
		TimeRef:           timeRef,
		WithOlderVersions: withVersions,
		Recursive:         recursive,
		ShowDir:           DirFirst,
	})
	size := int64(0)
	for content := range contentCh {
		if content.Err != nil {
			switch content.Err.ToGoError().(type) {
			// handle this specifically for filesystem related errors.
			case BrokenSymlink, TooManyLevelsSymlink, PathNotFound, ObjectOnGlacier:
				continue
			case PathInsufficientPermission:
				errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.")
				continue
			}
			errorIf(content.Err.Trace(urlStr), "Failed to find disk usage of `"+urlStr+"` recursively.")
			return 0, exitStatus(globalErrorExitStatus)
		}
		if content.URL.String() == targetURL {
			continue
		}

		if content.Type.IsDir() && !recursive {
			depth := depth
			if depth > 0 {
				depth--
			}

			subDirAlias := content.URL.Path
			if targetAlias != "" {
				subDirAlias = targetAlias + "/" + content.URL.Path
			}
			used, err := du(ctx, subDirAlias, timeRef, withVersions, depth, encKeyDB)
			if err != nil {
				return 0, err
			}
			size += used
		} else {
			size += content.Size
		}
	}

	if depth != 0 {
		u, err := url.Parse(targetURL)
		if err != nil {
			panic(err)
		}

		printMsg(duMessage{
			Prefix: strings.Trim(u.Path, "/"),
			Size:   size,
			Status: "success",
		})
	}

	return size, nil
}

// main for du command.
func mainDu(cliCtx *cli.Context) error {
	if !cliCtx.Args().Present() {
		cli.ShowCommandHelpAndExit(cliCtx, "du", 1)
	}

	// Set colors.
	console.SetColor("Remove", color.New(color.FgGreen, color.Bold))
	console.SetColor("Prefix", color.New(color.FgCyan, color.Bold))
	console.SetColor("Size", color.New(color.FgYellow))

	ctx, cancelRm := context.WithCancel(globalContext)
	defer cancelRm()

	// Parse encryption keys per command.
	encKeyDB, err := getEncKeys(cliCtx)
	fatalIf(err, "Unable to parse encryption keys.")

	// du specific flags.
	depth := cliCtx.Int("depth")
	if depth == 0 {
		if cliCtx.Bool("recursive") {
			if !cliCtx.IsSet("depth") {
				depth = -1
			}
		} else {
			depth = 1
		}
	}

	withVersions := cliCtx.Bool("versions")
	timeRef := parseRewindFlag(cliCtx.String("rewind"))

	var duErr error
	for _, urlStr := range cliCtx.Args() {
		if !isAliasURLDir(ctx, urlStr, nil, time.Time{}) {
			fatalIf(errInvalidArgument().Trace(urlStr), fmt.Sprintf("Source `%s` is not a folder. Only folders are supported by 'du' command.", urlStr))
		}

		if _, err := du(ctx, urlStr, timeRef, withVersions, depth, encKeyDB); duErr == nil {
			duErr = err
		}
	}

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

package cmd

import (
	"context"
	"fmt"
	"net/url"
	"strings"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/colorjson"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/pkg/console"
)

// du specific flags.
var (
	duFlags = []cli.Flag{
		cli.IntFlag{
			Name:  "depth, d",
			Usage: "print the total for a folder prefix only if it is N or fewer levels below the command line argument",
		},
		cli.BoolFlag{
			Name:  "recursive, r",
			Usage: "recursively print the total for a folder prefix",
		},
		cli.StringFlag{
			Name:  "rewind",
			Usage: "include all object versions no later than specified date",
		},
		cli.BoolFlag{
			Name:  "versions",
			Usage: "include all object versions",
		},
	}
)

// Summarize disk usage.
var duCmd = cli.Command{
	Name:         "du",
	Usage:        "summarize disk usage recursively",
	Action:       mainDu,
	OnUsageError: onUsageError,
	Before:       setGlobalsFromContext,
	Flags:        append(append(duFlags, ioFlags...), globalFlags...),
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} [FLAGS] TARGET

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
ENVIRONMENT VARIABLES:
  MC_ENCRYPT_KEY: list of comma delimited prefix=secret values

EXAMPLES:
  1. Summarize disk usage of 'jazz-songs' bucket recursively.
     {{.Prompt}} {{.HelpName}} s3/jazz-songs

  2. Summarize disk usage of 'louis' prefix in 'jazz-songs' bucket upto two levels.
     {{.Prompt}} {{.HelpName}} --depth=2 s3/jazz-songs/louis/

  3. Summarize disk usage of 'jazz-songs' bucket at a fixed date/time
     {{.Prompt}} {{.HelpName}} --rewind "2020.01.01" s3/jazz-songs/

  4. Summarize disk usage of 'jazz-songs' bucket with all objects versions
     {{.Prompt}} {{.HelpName}} --versions s3/jazz-songs/
`,
}

// Structured message depending on the type of console.
type duMessage struct {
	Prefix     string `json:"prefix"`
	Size       int64  `json:"size"`
	Objects    int64  `json:"objects"`
	Status     string `json:"status"`
	IsVersions bool   `json:"isVersions"`
}

// Colorized message for console printing.
func (r duMessage) String() string {
	humanSize := strings.Join(strings.Fields(humanize.IBytes(uint64(r.Size))), "")
	cnt := fmt.Sprintf("%d object", r.Objects)
	if r.IsVersions {
		cnt = fmt.Sprintf("%d version", r.Objects)
	}
	if r.Objects != 1 {
		cnt += "s" // pluralize
	}
	return fmt.Sprintf("%s\t%s\t%s", console.Colorize("Size", humanSize),
		console.Colorize("Objects", cnt),
		console.Colorize("Prefix", r.Prefix))
}

// JSON'ified message for scripting.
func (r duMessage) JSON() string {
	msgBytes, e := json.MarshalIndent(r, "", " ")
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
	return string(msgBytes)
}

func du(ctx context.Context, urlStr string, timeRef time.Time, withVersions bool, depth int, encKeyDB map[string][]prefixSSEPair) (sz, objs int64, err error) {
	targetAlias, targetURL, _ := mustExpandAlias(urlStr)
	if !strings.HasSuffix(targetURL, "/") {
		targetURL += "/"
	}

	clnt, pErr := newClientFromAlias(targetAlias, targetURL)
	if pErr != nil {
		errorIf(pErr.Trace(urlStr), "Failed to summarize disk usage `"+urlStr+"`.")
		return 0, 0, exitStatus(globalErrorExitStatus) // End of journey.
	}

	// No disk usage details below this level,
	// just do a recursive listing
	recursive := depth == 1

	contentCh := clnt.List(ctx, ListOptions{
		TimeRef:           timeRef,
		WithOlderVersions: withVersions,
		Recursive:         recursive,
		ShowDir:           DirFirst,
	})
	size := int64(0)
	objects := int64(0)
	for content := range contentCh {
		if content.Err != nil {
			switch content.Err.ToGoError().(type) {
			// handle this specifically for filesystem related errors.
			case BrokenSymlink, TooManyLevelsSymlink, PathNotFound, ObjectOnGlacier:
				continue
			case PathInsufficientPermission:
				errorIf(content.Err.Trace(clnt.GetURL().String()), "Unable to list folder.")
				continue
			}
			errorIf(content.Err.Trace(urlStr), "Failed to find disk usage of `"+urlStr+"` recursively.")
			return 0, 0, exitStatus(globalErrorExitStatus)
		}
		if content.URL.String() == targetURL {
			continue
		}

		if content.Type.IsDir() && !recursive {
			depth := depth
			if depth > 0 {
				depth--
			}

			subDirAlias := content.URL.Path
			if targetAlias != "" {
				subDirAlias = targetAlias + "/" + content.URL.Path
			}
			used, n, err := du(ctx, subDirAlias, timeRef, withVersions, depth, encKeyDB)
			if err != nil {
				return 0, 0, err
			}
			size += used
			objects += n
		} else {
			size += content.Size
			if !content.IsDeleteMarker {
				objects++
			}
		}
	}

	if depth != 0 {
		u, err := url.Parse(targetURL)
		if err != nil {
			panic(err)
		}

		printMsg(duMessage{
			Prefix:     strings.Trim(u.Path, "/"),
			Size:       size,
			Objects:    objects,
			Status:     "success",
			IsVersions: withVersions,
		})
	}

	return size, objects, nil
}

// main for du command.
func mainDu(cliCtx *cli.Context) error {
	if !cliCtx.Args().Present() {
		cli.ShowCommandHelpAndExit(cliCtx, "du", 1)
	}

	// Set colors.
	console.SetColor("Remove", color.New(color.FgGreen, color.Bold))
	console.SetColor("Prefix", color.New(color.FgCyan, color.Bold))
	console.SetColor("Objects", color.New(color.FgGreen))
	console.SetColor("Size", color.New(color.FgYellow))

	ctx, cancelRm := context.WithCancel(globalContext)
	defer cancelRm()

	// Parse encryption keys per command.
	encKeyDB, err := getEncKeys(cliCtx)
	fatalIf(err, "Unable to parse encryption keys.")

	// du specific flags.
	depth := cliCtx.Int("depth")
	if depth == 0 {
		if cliCtx.Bool("recursive") {
			if !cliCtx.IsSet("depth") {
				depth = -1
			}
		} else {
			depth = 1
		}
	}

	withVersions := cliCtx.Bool("versions")
	timeRef := parseRewindFlag(cliCtx.String("rewind"))

	var duErr error
	for _, urlStr := range cliCtx.Args() {
		if !isAliasURLDir(ctx, urlStr, nil, time.Time{}) {
			fatalIf(errInvalidArgument().Trace(urlStr), fmt.Sprintf("Source `%s` is not a folder. Only folders are supported by 'du' command.", urlStr))
		}

		if _, _, err := du(ctx, urlStr, timeRef, withVersions, depth, encKeyDB); duErr == nil {
			duErr = err
		}
	}

	return duErr
}
<|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/micro/cli/v2"
	goclient "github.com/micro/go-micro/v3/client"
	goregistry "github.com/micro/go-micro/v3/registry"
	"github.com/micro/micro/v3/client/cli/namespace"
	"github.com/micro/micro/v3/client/cli/util"
	"github.com/micro/micro/v3/service/client"
	"github.com/micro/micro/v3/service/registry"
)

// lookupService queries the service for a service with the given alias. If
// no services are found for a given alias, the registry will return nil and
// the error will also be nil. An error is only returned if there was an issue
// listing from the registry.
func lookupService(ctx *cli.Context) (*goregistry.Service, error) {
	// use the first arg as the name, e.g. "micro helloworld foo"
	// would try to call the helloworld service
	name := ctx.Args().First()

	// get the namespace to query the services from
	dom, err := namespace.Get(util.GetEnv(ctx).Name)
	if err != nil {
		return nil, err
	}

	// lookup from the registry in the current namespace
	if srv, err := serviceWithName(name, dom); err != nil {
		return nil, err
	} else if srv != nil {
		return srv, nil
	}

	// check for the service in the default namespace also
	if dom == goregistry.DefaultDomain {
		return nil, nil
	}
	return serviceWithName(name, goregistry.DefaultDomain)
}

// formatServiceUsage returns a string containing the service usage.
func formatServiceUsage(srv *goregistry.Service, alias string) string {
	commands := make([]string, len(srv.Endpoints))
	for i, e := range srv.Endpoints {
		// map "Helloworld.Call" to "helloworld.call"
		name := strings.ToLower(e.Name)

		// remove the prefix if it is the service name, e.g. rather than
		// "micro run helloworld helloworld call", it would be
		// "micro run helloworld call".
		name = strings.TrimPrefix(name, alias+".")

		// instead of "micro run helloworld foo.bar", the command should
		// be "micro run helloworld foo bar".
		commands[i] = strings.Replace(name, ".", " ", 1)
	}

	// sort the command names alphabetically
	sort.Strings(commands)

	result := fmt.Sprintf("NAME:\n\t%v\n\n", srv.Name)
	result += fmt.Sprintf("VERSION:\n\t%v\n\n", srv.Version)
	result += fmt.Sprintf("USAGE:\n\tmicro %v [flags] [command]\n\n", alias)
	result += fmt.Sprintf("COMMANDS:\n\t%v\n\n", strings.Join(commands, "\n\t"))
	return result
}

// callService will call a service using the arguments and flags provided
// in the context. It will print the result or error to stdout. If there
// was an error performing the call, it will be returned.
func callService(srv *goregistry.Service, ctx *cli.Context) error {
	// parse the flags and args
	args, flags, err := splitCmdArgs(ctx)
	if err != nil {
		return err
	}

	// construct the endpoint
	endpoint, err := constructEndpoint(args)
	if err != nil {
		return err
	}

	// ensure the endpoint exists on the service
	var ep *goregistry.Endpoint
	for _, e := range srv.Endpoints {
		if e.Name == endpoint {
			ep = e
			break
		}
	}
	if ep == nil {
		return fmt.Errorf("Endpoint %v not found for service %v", endpoint, srv.Name)
	}

	// parse the flags
	body, err := flagsToRequest(flags, ep.Request)
	if err != nil {
		return err
	}

	// construct and execute the request using the json content type
	req := client.NewRequest(srv.Name, endpoint, body, goclient.WithContentType("application/json"))
	var rsp json.RawMessage
	if err := client.Call(ctx.Context, req, &rsp); err != nil {
		return err
	}

	// format the response
	var out bytes.Buffer
	defer out.Reset()
	if err := json.Indent(&out, rsp, "", "\t"); err != nil {
		return err
	}
	out.WriteTo(os.Stdout)

	return nil
}

// splitCmdArgs takes a cli context and parses out the args and flags, for
// example "micro helloworld --name=foo call apple" would result in "call",
// "apple" as args and {"name":"foo"} as the flags.
func splitCmdArgs(ctx *cli.Context) ([]string, map[string]string, error) {
	args := []string{}
	flags := map[string]string{}

	for _, a := range ctx.Args().Slice() {
		if !strings.HasPrefix(a, "--") {
			args = append(args, a)
			continue
		}

		// comps would be "foo", "bar" for "--foo=bar"
		comps := strings.Split(strings.TrimPrefix(a, "--"), "=")
		if len(comps) != 2 {
			return nil, nil, fmt.Errorf("Invalid flag: %v. Expected format: --foo=bar", a)
		}
		flags[comps[0]] = comps[1]
	}

	return args, flags, nil
}

// constructEndpoint takes a slice of args and converts it into a valid endpoint
// such as Helloworld.Call or Foo.Bar, it will return an error if an invalid number
// of arguments were provided
func constructEndpoint(args []string) (string, error) {
	var epComps []string
	switch len(args) {
	case 2:
		epComps = args
	case 3:
		epComps = args[1:3]
	default:
		return "", fmt.Errorf("Incorrect number of arguments")
	}

	// transform the endpoint components, e.g ["helloworld", "call"] to the
	// endpoint name: "Helloworld.Call".
	return fmt.Sprintf("%v.%v", strings.Title(epComps[0]), strings.Title(epComps[1])), nil
}

// flagsToRequeest parses a set of flags, e.g {name:"Foo", "options_surname","Bar"} and
// converts it into a request body. If the key is not a valid object in the request, an
// error will be returned.
func flagsToRequest(flags map[string]string, req *goregistry.Value) (map[string]interface{}, error) {
	result := map[string]interface{}{}

loop:
	for key, value := range flags {
		for _, attr := range req.Values {
			// matches at a top level
			if attr.Name == key {
				result[key] = value
				continue loop
			}

			// check for matches at the second level
			if !strings.HasPrefix(key, attr.Name+"_") {
				continue
			}
			for _, attr2 := range attr.Values {
				if attr.Name+"_"+attr2.Name != key {
					continue
				}

				if _, ok := result[attr.Name]; !ok {
					result[attr.Name] = map[string]string{}
				} else if _, ok := result[attr.Name].(map[string]string); !ok {
					return nil, fmt.Errorf("Error parsing request, duplicate key: %v", key)
				}
				result[attr.Name].(map[string]string)[attr2.Name] = value
				continue loop
			}
		}

		return nil, fmt.Errorf("Unknown flag: %v", key)
	}

	return result, nil
}

// find a service in a domain matching the name
func serviceWithName(name, domain string) (*goregistry.Service, error) {
	srvs, err := registry.GetService(name, goregistry.GetDomain(domain))
	if err == goregistry.ErrNotFound {
		return nil, nil
	} else if err != nil {
		return nil, err
	}
	return srvs[0], nil
}
<commit_msg>newline character after command output<commit_after>package cmd

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/micro/cli/v2"
	goclient "github.com/micro/go-micro/v3/client"
	goregistry "github.com/micro/go-micro/v3/registry"
	"github.com/micro/micro/v3/client/cli/namespace"
	"github.com/micro/micro/v3/client/cli/util"
	"github.com/micro/micro/v3/service/client"
	"github.com/micro/micro/v3/service/registry"
)

// lookupService queries the service for a service with the given alias. If
// no services are found for a given alias, the registry will return nil and
// the error will also be nil. An error is only returned if there was an issue
// listing from the registry.
func lookupService(ctx *cli.Context) (*goregistry.Service, error) {
	// use the first arg as the name, e.g. "micro helloworld foo"
	// would try to call the helloworld service
	name := ctx.Args().First()

	// get the namespace to query the services from
	dom, err := namespace.Get(util.GetEnv(ctx).Name)
	if err != nil {
		return nil, err
	}

	// lookup from the registry in the current namespace
	if srv, err := serviceWithName(name, dom); err != nil {
		return nil, err
	} else if srv != nil {
		return srv, nil
	}

	// check for the service in the default namespace also
	if dom == goregistry.DefaultDomain {
		return nil, nil
	}
	return serviceWithName(name, goregistry.DefaultDomain)
}

// formatServiceUsage returns a string containing the service usage.
func formatServiceUsage(srv *goregistry.Service, alias string) string {
	commands := make([]string, len(srv.Endpoints))
	for i, e := range srv.Endpoints {
		// map "Helloworld.Call" to "helloworld.call"
		name := strings.ToLower(e.Name)

		// remove the prefix if it is the service name, e.g. rather than
		// "micro run helloworld helloworld call", it would be
		// "micro run helloworld call".
		name = strings.TrimPrefix(name, alias+".")

		// instead of "micro run helloworld foo.bar", the command should
		// be "micro run helloworld foo bar".
		commands[i] = strings.Replace(name, ".", " ", 1)
	}

	// sort the command names alphabetically
	sort.Strings(commands)

	result := fmt.Sprintf("NAME:\n\t%v\n\n", srv.Name)
	result += fmt.Sprintf("VERSION:\n\t%v\n\n", srv.Version)
	result += fmt.Sprintf("USAGE:\n\tmicro %v [flags] [command]\n\n", alias)
	result += fmt.Sprintf("COMMANDS:\n\t%v\n\n", strings.Join(commands, "\n\t"))
	return result
}

// callService will call a service using the arguments and flags provided
// in the context. It will print the result or error to stdout. If there
// was an error performing the call, it will be returned.
func callService(srv *goregistry.Service, ctx *cli.Context) error {
	// parse the flags and args
	args, flags, err := splitCmdArgs(ctx)
	if err != nil {
		return err
	}

	// construct the endpoint
	endpoint, err := constructEndpoint(args)
	if err != nil {
		return err
	}

	// ensure the endpoint exists on the service
	var ep *goregistry.Endpoint
	for _, e := range srv.Endpoints {
		if e.Name == endpoint {
			ep = e
			break
		}
	}
	if ep == nil {
		return fmt.Errorf("Endpoint %v not found for service %v", endpoint, srv.Name)
	}

	// parse the flags
	body, err := flagsToRequest(flags, ep.Request)
	if err != nil {
		return err
	}

	// construct and execute the request using the json content type
	req := client.NewRequest(srv.Name, endpoint, body, goclient.WithContentType("application/json"))
	var rsp json.RawMessage
	if err := client.Call(ctx.Context, req, &rsp); err != nil {
		return err
	}

	// format the response
	var out bytes.Buffer
	defer out.Reset()
	if err := json.Indent(&out, rsp, "", "\t"); err != nil {
		return err
	}
	out.Write([]byte("\n"))
	out.WriteTo(os.Stdout)

	return nil
}

// splitCmdArgs takes a cli context and parses out the args and flags, for
// example "micro helloworld --name=foo call apple" would result in "call",
// "apple" as args and {"name":"foo"} as the flags.
func splitCmdArgs(ctx *cli.Context) ([]string, map[string]string, error) {
	args := []string{}
	flags := map[string]string{}

	for _, a := range ctx.Args().Slice() {
		if !strings.HasPrefix(a, "--") {
			args = append(args, a)
			continue
		}

		// comps would be "foo", "bar" for "--foo=bar"
		comps := strings.Split(strings.TrimPrefix(a, "--"), "=")
		if len(comps) != 2 {
			return nil, nil, fmt.Errorf("Invalid flag: %v. Expected format: --foo=bar", a)
		}
		flags[comps[0]] = comps[1]
	}

	return args, flags, nil
}

// constructEndpoint takes a slice of args and converts it into a valid endpoint
// such as Helloworld.Call or Foo.Bar, it will return an error if an invalid number
// of arguments were provided
func constructEndpoint(args []string) (string, error) {
	var epComps []string
	switch len(args) {
	case 2:
		epComps = args
	case 3:
		epComps = args[1:3]
	default:
		return "", fmt.Errorf("Incorrect number of arguments")
	}

	// transform the endpoint components, e.g ["helloworld", "call"] to the
	// endpoint name: "Helloworld.Call".
	return fmt.Sprintf("%v.%v", strings.Title(epComps[0]), strings.Title(epComps[1])), nil
}

// flagsToRequeest parses a set of flags, e.g {name:"Foo", "options_surname","Bar"} and
// converts it into a request body. If the key is not a valid object in the request, an
// error will be returned.
func flagsToRequest(flags map[string]string, req *goregistry.Value) (map[string]interface{}, error) {
	result := map[string]interface{}{}

loop:
	for key, value := range flags {
		for _, attr := range req.Values {
			// matches at a top level
			if attr.Name == key {
				result[key] = value
				continue loop
			}

			// check for matches at the second level
			if !strings.HasPrefix(key, attr.Name+"_") {
				continue
			}
			for _, attr2 := range attr.Values {
				if attr.Name+"_"+attr2.Name != key {
					continue
				}

				if _, ok := result[attr.Name]; !ok {
					result[attr.Name] = map[string]string{}
				} else if _, ok := result[attr.Name].(map[string]string); !ok {
					return nil, fmt.Errorf("Error parsing request, duplicate key: %v", key)
				}
				result[attr.Name].(map[string]string)[attr2.Name] = value
				continue loop
			}
		}

		return nil, fmt.Errorf("Unknown flag: %v", key)
	}

	return result, nil
}

// find a service in a domain matching the name
func serviceWithName(name, domain string) (*goregistry.Service, error) {
	srvs, err := registry.GetService(name, goregistry.GetDomain(domain))
	if err == goregistry.ErrNotFound {
		return nil, nil
	} else if err != nil {
		return nil, err
	}
	return srvs[0], nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	. "github.com/antonmedv/expr/ast"
	"os"
)

const format = `digraph {
	ranksep=.3;
	node [shape=oval, fontname="Helvetica-bold"];
%v
%v}
`

func dotAst(node Node) {
	v := &visitor{}
	Walk(&node, v)
	dot := fmt.Sprintf(format, v.nodes, v.links)
	_, _ = fmt.Fprintf(os.Stdout, dot)
}

type visitor struct {
	nodes string
	links string
	index int
	stack []int
}

func (v *visitor) push(label string) {
	v.index++
	v.nodes += fmt.Sprintf("	n%v [label=%q];\n", v.index, label)
	v.stack = append(v.stack, v.index)
}

func (v *visitor) pop() int {
	node := v.stack[len(v.stack)-1]
	v.stack = v.stack[:len(v.stack)-1]
	return node
}

func (v *visitor) link(node int) {
	v.links += fmt.Sprintf("	n%v -> n%v\n", v.index, node)
}

func (v *visitor) Enter(node *Node) {}
func (v *visitor) Exit(ref *Node) {
	switch node := (*ref).(type) {

	case *NilNode:
		v.push("nil")

	case *IdentifierNode:
		v.push(node.Value)

	case *IntegerNode:
		v.push(fmt.Sprintf("%v", node.Value))

	case *FloatNode:
		v.push(fmt.Sprintf("%v", node.Value))

	case *BoolNode:
		v.push(fmt.Sprintf("%v", node.Value))

	case *StringNode:
		v.push(fmt.Sprintf("%q", node.Value))

	case *UnaryNode:
		n := v.pop()
		v.push(node.Operator)
		v.link(n)

	case *BinaryNode:
		b := v.pop()
		a := v.pop()
		v.push(node.Operator)
		v.link(a)
		v.link(b)

	case *MatchesNode:
		b := v.pop()
		a := v.pop()
		v.push("matches")
		v.link(a)
		v.link(b)

	case *PropertyNode:
		a := v.pop()
		v.push(fmt.Sprintf(".%v", node.Property))
		v.link(a)

	case *IndexNode:
		b := v.pop()
		a := v.pop()
		v.push("[...]")
		v.link(a)
		v.link(b)

	case *MethodNode:
		args := make([]int, 0)
		for range node.Arguments {
			args = append(args, v.pop())
		}
		a := v.pop()
		v.push(fmt.Sprintf(".%v(...)", node.Method))
		v.link(a)
		for i := len(args) - 1; i >= 0; i-- {
			v.link(args[i])
		}

	case *FunctionNode:
		args := make([]int, 0)
		for range node.Arguments {
			args = append(args, v.pop())
		}
		v.push(fmt.Sprintf("%v(...)", node.Name))
		for i := len(args) - 1; i >= 0; i-- {
			v.link(args[i])
		}

	case *BuiltinNode:
		args := make([]int, 0)
		for range node.Arguments {
			args = append(args, v.pop())
		}
		v.push(fmt.Sprintf("%v(...)", node.Name))
		for i := len(args) - 1; i >= 0; i-- {
			v.link(args[i])
		}

	case *ClosureNode:
		a := v.pop()
		v.push("func {...}")
		v.link(a)

	case *PointerNode:
		v.push("#")

	case *ConditionalNode:
		e2 := v.pop()
		e1 := v.pop()
		c := v.pop()
		v.push("? :")
		v.link(c)
		v.link(e1)
		v.link(e2)

	case *ArrayNode:
		n := make([]int, 0)
		for range node.Nodes {
			n = append(n, v.pop())
		}
		v.push("[...]")
		for i := len(n) - 1; i >= 0; i-- {
			v.link(n[i])
		}

	case *MapNode:
		n := make([]int, 0)
		for range node.Pairs {
			n = append(n, v.pop())
		}
		v.push("{...}")
		for i := len(n) - 1; i >= 0; i-- {
			v.link(n[i])
		}

	case *PairNode:
		a := v.pop()
		v.push(fmt.Sprintf("%q:", node.Key.(*StringNode).Value))
		v.link(a)
	}
}
<commit_msg>Fix dot formatter<commit_after>package main

import (
	"fmt"
	. "github.com/antonmedv/expr/ast"
	"os"
)

const format = `digraph {
	ranksep=.3;
	node [shape=oval, fontname="Helvetica-bold"];
%v
%v}
`

func dotAst(node Node) {
	v := &visitor{}
	Walk(&node, v)
	dot := fmt.Sprintf(format, v.nodes, v.links)
	_, _ = fmt.Fprintf(os.Stdout, dot)
}

type visitor struct {
	nodes string
	links string
	index int
	stack []int
}

func (v *visitor) push(label string) {
	v.index++
	v.nodes += fmt.Sprintf("	n%v [label=%q];\n", v.index, label)
	v.stack = append(v.stack, v.index)
}

func (v *visitor) pop() int {
	node := v.stack[len(v.stack)-1]
	v.stack = v.stack[:len(v.stack)-1]
	return node
}

func (v *visitor) link(node int) {
	v.links += fmt.Sprintf("	n%v -> n%v\n", v.index, node)
}

func (v *visitor) Enter(node *Node) {}
func (v *visitor) Exit(ref *Node) {
	switch node := (*ref).(type) {

	case *NilNode:
		v.push("nil")

	case *IdentifierNode:
		v.push(node.Value)

	case *IntegerNode:
		v.push(fmt.Sprintf("%v", node.Value))

	case *FloatNode:
		v.push(fmt.Sprintf("%v", node.Value))

	case *BoolNode:
		v.push(fmt.Sprintf("%v", node.Value))

	case *StringNode:
		v.push(fmt.Sprintf("%q", node.Value))

	case *UnaryNode:
		n := v.pop()
		v.push(node.Operator)
		v.link(n)

	case *BinaryNode:
		b := v.pop()
		a := v.pop()
		v.push(node.Operator)
		v.link(a)
		v.link(b)

	case *MatchesNode:
		b := v.pop()
		a := v.pop()
		v.push("matches")
		v.link(a)
		v.link(b)

	case *PropertyNode:
		a := v.pop()
		v.push(fmt.Sprintf(".%v", node.Property))
		v.link(a)

	case *IndexNode:
		b := v.pop()
		a := v.pop()
		v.push(fmt.Sprintf("%T", node))
		v.link(a)
		v.link(b)

	case *MethodNode:
		args := make([]int, 0)
		for range node.Arguments {
			args = append(args, v.pop())
		}
		a := v.pop()
		v.push(fmt.Sprintf(".%v(...)", node.Method))
		v.link(a)
		for i := len(args) - 1; i >= 0; i-- {
			v.link(args[i])
		}

	case *FunctionNode:
		args := make([]int, 0)
		for range node.Arguments {
			args = append(args, v.pop())
		}
		v.push(fmt.Sprintf("%v(...)", node.Name))
		for i := len(args) - 1; i >= 0; i-- {
			v.link(args[i])
		}

	case *BuiltinNode:
		args := make([]int, 0)
		for range node.Arguments {
			args = append(args, v.pop())
		}
		v.push(fmt.Sprintf("%v", node.Name))
		for i := len(args) - 1; i >= 0; i-- {
			v.link(args[i])
		}

	case *ClosureNode:
		a := v.pop()
		v.push(fmt.Sprintf("%T", node))
		v.link(a)

	case *PointerNode:
		v.push("#")

	case *ConditionalNode:
		e2 := v.pop()
		e1 := v.pop()
		c := v.pop()
		v.push(fmt.Sprintf("%T", node))
		v.link(c)
		v.link(e1)
		v.link(e2)

	case *ArrayNode:
		n := make([]int, 0)
		for range node.Nodes {
			n = append(n, v.pop())
		}
		v.push("[...]")
		for i := len(n) - 1; i >= 0; i-- {
			v.link(n[i])
		}

	case *MapNode:
		n := make([]int, 0)
		for range node.Pairs {
			n = append(n, v.pop())
		}
		v.push("{...}")
		for i := len(n) - 1; i >= 0; i-- {
			v.link(n[i])
		}

	case *PairNode:
		b := v.pop()
		a := v.pop()
		v.push(fmt.Sprintf("%T", node))
		v.link(a)
		v.link(b)

	default:
		v.push(fmt.Sprintf("%T", node))
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/gt/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package zlog

import (
	// "errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/go-vgo/gt/conf"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// Zlog zlog struct
type Zlog struct {
	// log.Logger
}

var (
	logger, errLogger *zap.Logger
	sugar, errSugar   *zap.SugaredLogger

	zapErr error
	// ZlogTime zlog time, zapcore.Field
	ZlogTime = zap.String("time", time.Now().Format("2006-01-02 15:04:05"))
)

type logConfig struct {
	Mode    string
	Path    string
	Name    string
	MaxDays int64 `toml:"max_days"`
	// Srv  Server     `toml:"server"`
}

var config logConfig

// Init zap log and config
func Init(tpath string) {
	// if _, err := toml.DecodeFile(tpath, &config); err != nil {
	// 	fmt.Println(err)
	// 	return
	// }
	conf.Init(tpath, &config)
	go conf.Watch(tpath, &config)

	go deleteOldLog()

	if config.Mode == "dev" {
		InitDev()
		ZlogTime = zap.Error(nil)
	} else {
		InitLog()
		// InitErrLog()
		go InitErrLog()
	}
}

func deleteOldLog() {
	fileDir, _ := confPath()
	var maxDays int64 = 28

	if config.MaxDays != 0 {
		maxDays = config.MaxDays
	}

	filepath.Walk(fileDir, func(path string, info os.FileInfo, err error) (
		returnErr error) {
		defer func() {
			if r := recover(); r != nil {
				returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v",
					path, r)
			}
		}()

		if info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*maxDays) {

			if strings.HasPrefix(filepath.Base(path), filepath.Base(fileDir)) {
				// if err := os.Remove(path); err != nil {
				if err := os.RemoveAll(path); err != nil {
					returnErr = fmt.Errorf("Failed to remove %s: %v", path, err)
				}
			}
		}
		return returnErr
	})
}

// InitDev init dev mode
func InitDev() {
	// logger, _ = zap.NewProduction()
	logCfg := zap.NewDevelopmentConfig()
	logCfg.Sampling = nil
	logger, zapErr = logCfg.Build()
	if zapErr != nil {
		log.Fatal("zap.NewDevelopmentConfig error: ", zapErr)
	}

	errLogger = logger

	defer logger.Sync() // flushes buffer, if any
	sugar = logger.Sugar()
	errSugar = sugar
}

func confPath() (string, string) {
	// var lpath, name string
	var lpath, name string = "./log", "log"

	if config.Path != "" {
		lpath = config.Path
	}

	if config.Name != "" {
		name = config.Name
	}

	return lpath, name
}

// InitLog init log lumberjack
func InitLog() {
	lpath, name := confPath()
	maxDays := 28
	if config.MaxDays != 0 {
		maxDays = int(config.MaxDays)
	}

	logTime := time.Now().Format("2006-01-02")
	logPath := lpath + "/" + logTime + "/" + name + ".json"
	ws := zapcore.AddSync(&lumberjack.Logger{
		Filename:   logPath,
		MaxSize:    500, // megabytes
		MaxBackups: 3,
		MaxAge:     maxDays, // days
	})
	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		ws,
		zap.InfoLevel,
	)
	// logger = zap.New(core).WithOptions(zap.AddCaller())
	logger = zap.New(core).WithOptions(zap.AddStacktrace(zap.InfoLevel))

	defer logger.Sync() // flushes buffer, if any
	sugar = logger.Sugar()
}

// InitErrLog init error log and lumberjack
func InitErrLog() {
	// lumberjack.Logger is already safe for concurrent use, so we don't need to
	// lock it.
	lpath, name := confPath()
	maxDays := 28
	if config.MaxDays != 0 {
		maxDays = int(config.MaxDays)
	}

	logTime := time.Now().Format("2006-01-02")
	logPath := lpath + "/" + logTime + "/" + name + "_err.json"
	ws := zapcore.AddSync(&lumberjack.Logger{
		Filename:   logPath,
		MaxSize:    500, // megabytes
		MaxBackups: 3,
		MaxAge:     maxDays, // days
	})

	highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
		return lvl >= zapcore.ErrorLevel
	})

	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		ws,
		// zap.ErrorLevel,
		highPriority,
	)

	errLogger = zap.New(core).WithOptions(zap.AddStacktrace(zap.ErrorLevel))
	defer logger.Sync() // flushes buffer, if any
	errSugar = errLogger.Sugar()
}

// Err zap.Error
func Err(err error) zapcore.Field {
	return zap.Error(err)
}

// Str zap.String
func Str(key, val string) zapcore.Field {
	return zap.String(key, val)
}

// Int zap.Int
func Int(key string, val int) zapcore.Field {
	return zap.Int(key, val)
}

// Any zap.Any
func Any(key string, val interface{}) zapcore.Field {
	return zap.Any(key, val)
}

// Bool zap.Bool
func Bool(key string, val bool) zapcore.Field {
	return zap.Bool(key, val)
}

// Print fmt.Sprintf
func Print(args ...interface{}) string {
	if len(args) == 0 {
		return ""
	}
	return fmt.Sprintf("%v ", args[0])
}

// Printf fmt.Sprintf
func Printf(args ...interface{}) string {
	if len(args) < 5 {
		return ""
	}

	return fmt.Sprintf(
		"method: %v, statusCode: %v, req: %s, ip: %s, time: %fs",
		args[0],
		args[1],
		args[2],
		args[3],
		args[4])
}

func (z *Zlog) Error(msg string, err error) {
	errLogger.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// LogInfo info log
func LogInfo(msg string, info ...string) {
	var logInfo string
	if len(info) > 0 {
		logInfo = info[0]
	}

	errLogger.Info(msg,
		ZlogTime,
		zap.String("info", logInfo),
	)
}

// Error error log
func Error(msg string, err ...error) {
	var logErr error
	if len(err) > 0 {
		logErr = err[0]
	}
	errLogger.Error(msg,
		ZlogTime,
		zap.Error(logErr),
	)
}

// Errorm more
func Errorm(msg string, fields ...zapcore.Field) {
	errLogger.Error(msg,
		fields...,
	)
}

// SugarErrorm more
func SugarErrorm(msg string, fields ...zapcore.Field) {
	errSugar.Error(msg,
		fields,
	)
}

// Fatal fatal log
func Fatal(msg string, err ...error) {
	var logErr error
	if len(err) > 0 {
		logErr = err[0]
	}
	errLogger.Fatal(msg,
		ZlogTime,
		zap.Error(logErr),
	)
}

// Panic panic log
func Panic(msg string, err ...error) {
	var logErr error
	if len(err) > 0 {
		logErr = err[0]
	}
	errLogger.Panic(msg,
		ZlogTime,
		zap.Error(logErr),
	)
}

// LogsError sugar error log
func LogsError(msg string, err error) {
	errSugar.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// SugarError sugar error log
func SugarError(msg string, err error) {
	errSugar.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// SugarFatal sugar fatal log
func SugarFatal(msg string, err error) {
	errSugar.Fatal(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// SugarPanic sugar panic log
func SugarPanic(msg string, err error) {
	errSugar.Panic(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// Info info log
func Info(msg string, info ...string) {
	var logInfo string
	if len(info) > 0 {
		logInfo = info[0]
	}
	logger.Info(msg,
		ZlogTime,
		zap.String("info", logInfo),
	// fields,
	)
}

// Infom more
func Infom(msg string, fields ...zapcore.Field) {
	logger.Info(msg, fields...)
}

// SugarInfom more
func SugarInfom(msg string, fields ...zapcore.Field) {
	sugar.Info(msg, fields)
}

// Warn warn log
func Warn(msg string, warn ...string) {
	var logWarn string
	if len(warn) > 0 {
		logWarn = warn[0]
	}
	logger.Warn(msg,
		ZlogTime,
		zap.String("warn", logWarn),
	)
}

// Debug debug log
func Debug(msg string, debug ...string) {
	var logDebug string
	if len(debug) > 0 {
		logDebug = debug[0]
	}
	logger.Debug(msg,
		ZlogTime,
		zap.String("debug", logDebug),
	)
}

// Infoff info log
func Infoff(msg string, fields ...zapcore.Field) {
	logger.Info(msg,
		ZlogTime,
		fields[0],
	)
}

// LogError error log
func LogError(msg string, err error) {
	logger.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// LogPanic panic log
func LogPanic(msg string, err error) {
	logger.Panic(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// LogFatal fatal log
func LogFatal(msg string, err error) {
	logger.Fatal(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// Infof infof log
func Infof(msg, info string) {
	sugar.Infof(msg,
		ZlogTime,
		zap.String("info", info),
	)
}

// InfoW infow log
func InfoW(msg, info string) {
	sugar.Infow(msg,
		ZlogTime,
		"info", info,
	)
}

// Errorf errorf log
func Errorf(msg string, err error) {
	sugar.Errorf(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// Warnf warnf log
func Warnf(msg, warn string) {
	sugar.Warnf(msg,
		ZlogTime,
		zap.String("warn", warn),
	)
}
<commit_msg>update zlog code<commit_after>// Copyright 2017 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/gt/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package zlog

import (
	// "errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/go-vgo/gt/conf"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// Zlog zlog struct
type Zlog struct {
	// log.Logger
}

type logConfig struct {
	Mode    string
	Path    string
	Name    string
	MaxDays int64 `toml:"max_days"`
	// Srv  Server     `toml:"server"`
}

var (
	logger, errLogger *zap.Logger
	sugar, errSugar   *zap.SugaredLogger
	config            logConfig

	zapErr error
	// ZlogTime zlog time, zapcore.Field
	ZlogTime = zap.String("time", time.Now().Format("2006-01-02 15:04:05"))
)

// Init zap log and config
func Init(tpath string) {
	// if _, err := toml.DecodeFile(tpath, &config); err != nil {
	// 	fmt.Println(err)
	// 	return
	// }
	conf.Init(tpath, &config)
	go conf.Watch(tpath, &config)

	go deleteOldLog()

	if config.Mode == "dev" {
		InitDev()
		ZlogTime = zap.Error(nil)
	} else {
		InitLog()
		// InitErrLog()
		go InitErrLog()
	}
}

func deleteOldLog() {
	fileDir, _ := confPath()
	var maxDays int64 = 28

	if config.MaxDays != 0 {
		maxDays = config.MaxDays
	}

	filepath.Walk(fileDir, func(path string, info os.FileInfo, err error) (
		returnErr error) {
		defer func() {
			if r := recover(); r != nil {
				returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v",
					path, r)
			}
		}()

		if info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*maxDays) {

			if strings.HasPrefix(filepath.Base(path), filepath.Base(fileDir)) {
				// if err := os.Remove(path); err != nil {
				if err := os.RemoveAll(path); err != nil {
					returnErr = fmt.Errorf("Failed to remove %s: %v", path, err)
				}
			}
		}
		return returnErr
	})
}

// InitDev init dev mode
func InitDev() {
	// logger, _ = zap.NewProduction()
	logCfg := zap.NewDevelopmentConfig()
	logCfg.Sampling = nil
	logger, zapErr = logCfg.Build()
	if zapErr != nil {
		log.Fatal("zap.NewDevelopmentConfig error: ", zapErr)
	}

	errLogger = logger

	defer logger.Sync() // flushes buffer, if any
	sugar = logger.Sugar()
	errSugar = sugar
}

func confPath() (string, string) {
	// var lpath, name string
	var lpath, name string = "./log", "log"

	if config.Path != "" {
		lpath = config.Path
	}

	if config.Name != "" {
		name = config.Name
	}

	return lpath, name
}

// InitLog init log lumberjack
func InitLog() {
	lpath, name := confPath()
	maxDays := 28
	if config.MaxDays != 0 {
		maxDays = int(config.MaxDays)
	}

	logTime := time.Now().Format("2006-01-02")
	logPath := lpath + "/" + logTime + "/" + name + ".json"
	ws := zapcore.AddSync(&lumberjack.Logger{
		Filename:   logPath,
		MaxSize:    500, // megabytes
		MaxBackups: 3,
		MaxAge:     maxDays, // days
	})
	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		ws,
		zap.InfoLevel,
	)
	// logger = zap.New(core).WithOptions(zap.AddCaller())
	logger = zap.New(core).WithOptions(zap.AddStacktrace(zap.InfoLevel))

	defer logger.Sync() // flushes buffer, if any
	sugar = logger.Sugar()
}

// InitErrLog init error log and lumberjack
func InitErrLog() {
	// lumberjack.Logger is already safe for concurrent use, so we don't need to
	// lock it.
	lpath, name := confPath()
	maxDays := 28
	if config.MaxDays != 0 {
		maxDays = int(config.MaxDays)
	}

	logTime := time.Now().Format("2006-01-02")
	logPath := lpath + "/" + logTime + "/" + name + "_err.json"
	ws := zapcore.AddSync(&lumberjack.Logger{
		Filename:   logPath,
		MaxSize:    500, // megabytes
		MaxBackups: 3,
		MaxAge:     maxDays, // days
	})

	highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
		return lvl >= zapcore.ErrorLevel
	})

	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		ws,
		// zap.ErrorLevel,
		highPriority,
	)

	errLogger = zap.New(core).WithOptions(zap.AddStacktrace(zap.ErrorLevel))
	defer logger.Sync() // flushes buffer, if any
	errSugar = errLogger.Sugar()
}

// Err zap.Error
func Err(err error) zapcore.Field {
	return zap.Error(err)
}

// Str zap.String
func Str(key, val string) zapcore.Field {
	return zap.String(key, val)
}

// Int zap.Int
func Int(key string, val int) zapcore.Field {
	return zap.Int(key, val)
}

// Any zap.Any
func Any(key string, val interface{}) zapcore.Field {
	return zap.Any(key, val)
}

// Bool zap.Bool
func Bool(key string, val bool) zapcore.Field {
	return zap.Bool(key, val)
}

// Print fmt.Sprintf
func Print(args ...interface{}) string {
	if len(args) == 0 {
		return ""
	}
	return fmt.Sprintf("%v ", args[0])
}

// Printf fmt.Sprintf
func Printf(args ...interface{}) string {
	if len(args) < 5 {
		return ""
	}

	return fmt.Sprintf(
		"method: %v, statusCode: %v, req: %s, ip: %s, time: %fs",
		args[0],
		args[1],
		args[2],
		args[3],
		args[4])
}

func (z *Zlog) Error(msg string, err error) {
	errLogger.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// LogInfo info log
func LogInfo(msg string, info ...string) {
	var logInfo string
	if len(info) > 0 {
		logInfo = info[0]
	}

	errLogger.Info(msg,
		ZlogTime,
		zap.String("info", logInfo),
	)
}

// Error error log
func Error(msg string, err ...error) {
	var logErr error
	if len(err) > 0 {
		logErr = err[0]
	}
	errLogger.Error(msg,
		ZlogTime,
		zap.Error(logErr),
	)
}

// Errorm more
func Errorm(msg string, fields ...zapcore.Field) {
	errLogger.Error(msg,
		fields...,
	)
}

// SugarErrorm more
func SugarErrorm(msg string, fields ...zapcore.Field) {
	errSugar.Error(msg,
		fields,
	)
}

// Fatal fatal log
func Fatal(msg string, err ...error) {
	var logErr error
	if len(err) > 0 {
		logErr = err[0]
	}
	errLogger.Fatal(msg,
		ZlogTime,
		zap.Error(logErr),
	)
}

// Panic panic log
func Panic(msg string, err ...error) {
	var logErr error
	if len(err) > 0 {
		logErr = err[0]
	}
	errLogger.Panic(msg,
		ZlogTime,
		zap.Error(logErr),
	)
}

// LogsError sugar error log
func LogsError(msg string, err error) {
	errSugar.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// SugarError sugar error log
func SugarError(msg string, err error) {
	errSugar.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// SugarFatal sugar fatal log
func SugarFatal(msg string, err error) {
	errSugar.Fatal(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// SugarPanic sugar panic log
func SugarPanic(msg string, err error) {
	errSugar.Panic(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// Info info log
func Info(msg string, info ...string) {
	var logInfo string
	if len(info) > 0 {
		logInfo = info[0]
	}
	logger.Info(msg,
		ZlogTime,
		zap.String("info", logInfo),
	// fields,
	)
}

// Infom more
func Infom(msg string, fields ...zapcore.Field) {
	logger.Info(msg, fields...)
}

// SugarInfom more
func SugarInfom(msg string, fields ...zapcore.Field) {
	sugar.Info(msg, fields)
}

// Warn warn log
func Warn(msg string, warn ...string) {
	var logWarn string
	if len(warn) > 0 {
		logWarn = warn[0]
	}
	logger.Warn(msg,
		ZlogTime,
		zap.String("warn", logWarn),
	)
}

// Debug debug log
func Debug(msg string, debug ...string) {
	var logDebug string
	if len(debug) > 0 {
		logDebug = debug[0]
	}
	logger.Debug(msg,
		ZlogTime,
		zap.String("debug", logDebug),
	)
}

// Infoff info log
func Infoff(msg string, fields ...zapcore.Field) {
	logger.Info(msg,
		ZlogTime,
		fields[0],
	)
}

// LogError error log
func LogError(msg string, err error) {
	logger.Error(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// LogPanic panic log
func LogPanic(msg string, err error) {
	logger.Panic(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// LogFatal fatal log
func LogFatal(msg string, err error) {
	logger.Fatal(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// Infof infof log
func Infof(msg, info string) {
	sugar.Infof(msg,
		ZlogTime,
		zap.String("info", info),
	)
}

// InfoW infow log
func InfoW(msg, info string) {
	sugar.Infow(msg,
		ZlogTime,
		"info", info,
	)
}

// Errorf errorf log
func Errorf(msg string, err error) {
	sugar.Errorf(msg,
		ZlogTime,
		zap.Error(err),
	)
}

// Warnf warnf log
func Warnf(msg, warn string) {
	sugar.Warnf(msg,
		ZlogTime,
		zap.String("warn", warn),
	)
}
<|endoftext|>