<commit_before>package build

import (
	"fmt"
	"neon/util"
	"reflect"
	"strings"
)

// character for expressions
const (
	// character that start expressions
	CharExpression = "="
	// expression curly brace
	CurlyExpression = "{"
	// tag name
	NeonTag = "neon"
	// tag separator
	TagSeparator = ","
	// field might not be provided
	FieldOptional = "optional"
	// field is a file name that is expanded for user home
	FieldFile = "file"
	// field is an expression
	FieldExpression = "expression"
	// field should be rapped in a slice of its type
	FieldWrap = "wrap"
	// field is a list of steps
	FieldSteps = "steps"
	// field has a different name
	FieldName = "name"
)

// TaskMap is a map that gives constructor for given task name
var TaskMap = make(map[string]TaskDesc)

// AddTask adds a task in the map:
// - task: description of the task
func AddTask(task TaskDesc) {
	if _, ok := TaskMap[task.Name]; ok {
		panic(fmt.Errorf("task '%s' already defined", task.Name))
	}
	err := CheckTaskArgs(TaskMap, task)
	if err != nil {
		panic(err)
	}
	TaskMap[task.Name] = task
}

// CheckTaskArgs checks that task argument names don't collide with with the
// name of an existing task. For instance, a task can't have an argument named
// copy as a task named copy already exists.
// - map: the tasks map.
// - task: the task description.
// Return: an error if argument collides.
func CheckTaskArgs(m map[string]TaskDesc, t TaskDesc) error {
	for n := range m {
		if HasField(t.Args, n) {
			return fmt.Errorf("task '%s' cannot have a field named '%s' as a task with this name exists", t.Name, n)
		}
	}
	return nil
}

// HasField tells if given structure has named field.
// - t: the type to check (must be a struct).
// - n: the name of the field to check as a string.
// Return: a boolean that tells if field exists.
func HasField(t reflect.Type, n string) bool {
	if t.Kind() != reflect.Struct {
		panic("task args must be a struct")
	}
	for i := 0; i < t.NumField(); i++ {
		if strings.ToLower(t.Field(i).Name) == n {
			return true
		}
	}
	return false
}

// TaskDesc is a task descriptor is made of a task constructor and an help string
type TaskDesc struct {
	Name string
	Args reflect.Type
	Func TaskFunc
	Help string
}

// TaskArgs is a type for task arguments as parsed in build file
type TaskArgs map[interface{}]interface{}

// TaskFunc is a type for task function called to run task
type TaskFunc func(ctx *Context, args interface{}) error

// ValidateTaskArgs validates arguments against task arguments definition
// - args: task arguments parsed in build file
// - typ: type of the arguments
// Return: an error (detailing the fault) if arguments are illegal
func ValidateTaskArgs(args TaskArgs, typ reflect.Type) error {
	if typ.Kind() != reflect.Struct {
		return fmt.Errorf("params must be a pointer on a struct")
	}
	var fields []string
	// iterate on fields of the parameters types and check argument types
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		name := GetQuality(field, FieldName)
		if name == "" {
			name = strings.ToLower(field.Name)
		}
		fields = append(fields, name)
		// check field is not missing
		if _, ok := args[name]; !ok {
			if !FieldIs(field, FieldOptional) {
				return fmt.Errorf("missing mandatory field '%s'", name)
			}
		}
		value := args[name]
		// parse steps fields
		if FieldIs(field, "steps") && value != nil {
			steps, err := NewSteps(value)
			if err != nil {
				return fmt.Errorf("parsing field '%s': %v", name, err)
			}
			args[name] = steps
		}
		// check field type
		if !CheckType(field, value) {
			return fmt.Errorf("field '%s' must be of type '%s' ('%s' provided)",
				name, field.Type, reflect.TypeOf(value))
		}
	}
	// check that we don't have unknown args
	if !(typ.NumField() == 0 && len(args) == 1) {
		for name := range args {
			found := false
			for _, n := range fields {
				if n == name {
					found = true
					continue
				}
			}
			if !found {
				return fmt.Errorf("unknown parameter '%s'", name)
			}
		}
	}
	return nil
}

// CheckType checks that given value is compatible with field type
// - field: the field of the parameters as reflect.StructField
// - value: the value of the argument
// Return: a bool that tells if type is OK
func CheckType(field reflect.StructField, value interface{}) bool {
	valueType := reflect.TypeOf(value)
	// if field is optional and argument nil, it's OK
	if FieldIs(field, FieldOptional) && value == nil {
		return true
	}
	// if argument is an expression it's OK whatever the type
	if valueType.Kind() == reflect.String &&
		(IsExpression(value.(string)) ||
			FieldIs(field, FieldExpression)) {
		return true
	}
	// if type of field is slice of the type of the argument and wrap, it's OK
	if field.Type.Kind() == reflect.Slice &&
		reflect.SliceOf(valueType) == field.Type &&
		FieldIs(field, FieldWrap) {
		return true
	}
	// if type is slice and argument is steps, it's OK
	if field.Type.Kind() == reflect.Slice &&
		FieldIs(field, FieldSteps) {
		return true
	}
	// check that value is of given type
	return IsValueOfType(value, field.Type)
}

// IsValueOfType tells if a value is of given type
// - value: the value to test as an interface{}
// - type: the type to check as a reflect.Type
// Return: a bool telling if value is of given type
func IsValueOfType(value interface{}, typ reflect.Type) bool {
	// if value is of given type it's true
	if reflect.TypeOf(value) == typ {
		return true
	}
	// if value and type are slices, test elements
	if reflect.TypeOf(value).Kind() == reflect.Slice && typ.Kind() == reflect.Slice {
		return IsValueOfType(reflect.ValueOf(value).Index(0).Interface(), typ.Elem())
	}
	// if value and type are maps, test key and value
	if reflect.TypeOf(value).Kind() == reflect.Map && typ.Kind() == reflect.Map {
		key := reflect.ValueOf(value).MapKeys()[0].Interface()
		val := reflect.ValueOf(value).MapIndex(reflect.ValueOf(key)).Interface()
		return IsValueOfType(key, typ.Key()) && IsValueOfType(val, typ.Elem())
	}
	// else return false
	return false
}

// EvaluateTaskArgs builds task arguments from task params and return it
// - args: task arguments parsed in build file
// - typ: the type of the arguments
// - context: the build context to evaluate arguments into
// Return:
// - result: as an interface{}
// - error: if something went wrong
func EvaluateTaskArgs(args TaskArgs, typ reflect.Type, context *Context) (interface{}, error) {
	var err error
	value := reflect.New(typ).Elem()
	for i := 0; i < value.NumField(); i++ {
		field := typ.Field(i)
		name := GetQuality(field, FieldName)
		if name == "" {
			name = strings.ToLower(field.Name)
		}
		if args[name] != nil {
			val := args[name]
			// evaluate expressions in context
			if reflect.TypeOf(val).Kind() == reflect.String &&
				(IsExpression(val.(string)) || FieldIs(field, FieldExpression)) {
				str := val.(string)
				if IsExpression(str) {
					str = str[1:]
				}
				val, err = context.EvaluateExpression(str)
				if err != nil {
					return nil, err
				}
				expected := field.Type
				actual := reflect.TypeOf(val)
				if actual != expected {
					// we accept if expected is slice of interfaces and actual is slice
					if !(expected.Kind() == reflect.Slice && actual.Kind() == reflect.Slice) &&
						// or if slice and wrap
						!(expected == reflect.SliceOf(actual) && FieldIs(field, FieldWrap)) {
						return nil, fmt.Errorf("bad expression return type, expected '%v' but '%v' was returned",
							expected, actual)
					}
				}
			}
			// evaluate arguments
			val, err = context.EvaluateObject(val)
			if err != nil {
				return nil, err
			}
			// evaluate strings to replace "={expression}" with its value
			if reflect.TypeOf(val).Kind() == reflect.String {
				str := val.(string)
				// replace '\=' with '='
				if strings.HasPrefix(str, `\`+CharExpression) {
					str = str[1:]
				}
				// expand home if field tagged 'file'
				if FieldIs(field, FieldFile) {
					str = util.ExpandUserHome(str)
				}
				val = str
			}
			// wrap values if necessary
			if FieldIs(field, FieldWrap) && !(reflect.TypeOf(val).Kind() == reflect.Slice) {
				slice := reflect.New(field.Type).Elem()
				slice = reflect.Append(slice, reflect.ValueOf(val))
				val = slice.Interface()
			}
			// put value in params
			CopyValue(reflect.ValueOf(val), value.Field(i))
		}
	}
	return value.Interface(), nil
}

// CopyValue copy given value in another
// - orig: origin value
// - dest: destination value
func CopyValue(orig, dest reflect.Value) {
	// loop on slices
	if orig.Type().Kind() == reflect.Slice && dest.Type().Kind() == reflect.Slice {
		newSlice := reflect.MakeSlice(dest.Type(), orig.Len(), orig.Len())
		for i := 0; i < orig.Len(); i++ {
			CopyValue(orig.Index(i), newSlice.Index(i))
		}
		dest.Set(newSlice)
	} else
	// loop on maps
	if orig.Type().Kind() == reflect.Map && dest.Type().Kind() == reflect.Map {
		keyType := dest.Type().Key()
		valType := dest.Type().Elem()
		newMap := reflect.MakeMap(reflect.MapOf(keyType, valType))
		for _, key := range orig.MapKeys() {
			if key.Type().Kind() == reflect.Interface {
				key = key.Elem()
			}
			val := orig.MapIndex(key)
			if val.Type().Kind() == reflect.Interface {
				val = val.Elem()
			}
			newMap.SetMapIndex(key, val)
		}
		dest.Set(newMap)
	} else
	// get value of interfaces
	if orig.Kind() == reflect.Interface {
		CopyValue(orig.Elem(), dest)
	} else
	// other types
	{
		dest.Set(orig)
	}
}

// FieldIs tells if given field tag contains quality
// - field: the struct field
// - quality: the tested quality (such as "optional")
func FieldIs(field reflect.StructField, quality string) bool {
	tags := field.Tag.Get(NeonTag)
	qualities := strings.Split(tags, TagSeparator)
	for _, q := range qualities {
		if q == quality {
			return true
		}
	}
	return false
}

// GetQuality returns value of given quality
// - field: the field to examine
// - quality: quality to get
func GetQuality(field reflect.StructField, quality string) string {
	tags := field.Tag.Get(NeonTag)
	qualities := strings.Split(tags, TagSeparator)
	for _, q := range qualities {
		prefix := quality + "="
		if strings.HasPrefix(q, prefix) {
			return q[len(prefix):]
		}
	}
	return ""
}

// IsExpression tells if given string is an expression
// - s: the string to test
// Return: a bool that tells if the string is an expression
func IsExpression(s string) bool {
	if len(s) < 2 {
		return false
	}
	return s[0:1] == CharExpression && s[1:2] != CurlyExpression
}
<commit_msg>Fixed gocyclo warning<commit_after>package build

import (
	"fmt"
	"neon/util"
	"reflect"
	"strings"
)

// character for expressions
const (
	// character that start expressions
	CharExpression = "="
	// expression curly brace
	CurlyExpression = "{"
	// tag name
	NeonTag = "neon"
	// tag separator
	TagSeparator = ","
	// field might not be provided
	FieldOptional = "optional"
	// field is a file name that is expanded for user home
	FieldFile = "file"
	// field is an expression
	FieldExpression = "expression"
	// field should be rapped in a slice of its type
	FieldWrap = "wrap"
	// field is a list of steps
	FieldSteps = "steps"
	// field has a different name
	FieldName = "name"
)

// TaskMap is a map that gives constructor for given task name
var TaskMap = make(map[string]TaskDesc)

// AddTask adds a task in the map:
// - task: description of the task
func AddTask(task TaskDesc) {
	if _, ok := TaskMap[task.Name]; ok {
		panic(fmt.Errorf("task '%s' already defined", task.Name))
	}
	err := CheckTaskArgs(TaskMap, task)
	if err != nil {
		panic(err)
	}
	TaskMap[task.Name] = task
}

// CheckTaskArgs checks that task argument names don't collide with with the
// name of an existing task. For instance, a task can't have an argument named
// copy as a task named copy already exists.
// - map: the tasks map.
// - task: the task description.
// Return: an error if argument collides.
func CheckTaskArgs(m map[string]TaskDesc, t TaskDesc) error {
	for n := range m {
		if HasField(t.Args, n) {
			return fmt.Errorf("task '%s' cannot have a field named '%s' as a task with this name exists", t.Name, n)
		}
	}
	return nil
}

// HasField tells if given structure has named field.
// - t: the type to check (must be a struct).
// - n: the name of the field to check as a string.
// Return: a boolean that tells if field exists.
func HasField(t reflect.Type, n string) bool {
	if t.Kind() != reflect.Struct {
		panic("task args must be a struct")
	}
	for i := 0; i < t.NumField(); i++ {
		if strings.ToLower(t.Field(i).Name) == n {
			return true
		}
	}
	return false
}

// TaskDesc is a task descriptor is made of a task constructor and an help string
type TaskDesc struct {
	Name string
	Args reflect.Type
	Func TaskFunc
	Help string
}

// TaskArgs is a type for task arguments as parsed in build file
type TaskArgs map[interface{}]interface{}

// TaskFunc is a type for task function called to run task
type TaskFunc func(ctx *Context, args interface{}) error

// ValidateTaskArgs validates arguments against task arguments definition
// - args: task arguments parsed in build file
// - typ: type of the arguments
// Return: an error (detailing the fault) if arguments are illegal
func ValidateTaskArgs(args TaskArgs, typ reflect.Type) error {
	if typ.Kind() != reflect.Struct {
		return fmt.Errorf("params must be a pointer on a struct")
	}
	var fields []string
	// iterate on fields of the parameters types and check argument types
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		name := GetQuality(field, FieldName)
		if name == "" {
			name = strings.ToLower(field.Name)
		}
		fields = append(fields, name)
		// check field is not missing
		if _, ok := args[name]; !ok {
			if !FieldIs(field, FieldOptional) {
				return fmt.Errorf("missing mandatory field '%s'", name)
			}
		}
		value := args[name]
		// parse steps fields
		if FieldIs(field, "steps") && value != nil {
			steps, err := NewSteps(value)
			if err != nil {
				return fmt.Errorf("parsing field '%s': %v", name, err)
			}
			args[name] = steps
		}
		// check field type
		if !CheckType(field, value) {
			return fmt.Errorf("field '%s' must be of type '%s' ('%s' provided)",
				name, field.Type, reflect.TypeOf(value))
		}
	}
	// check that we don't have unknown args
	if !(typ.NumField() == 0 && len(args) == 1) {
		for name := range args {
			found := false
			for _, n := range fields {
				if n == name {
					found = true
					continue
				}
			}
			if !found {
				return fmt.Errorf("unknown parameter '%s'", name)
			}
		}
	}
	return nil
}

// CheckType checks that given value is compatible with field type
// - field: the field of the parameters as reflect.StructField
// - value: the value of the argument
// Return: a bool that tells if type is OK
func CheckType(field reflect.StructField, value interface{}) bool {
	valueType := reflect.TypeOf(value)
	// if field is optional and argument nil, it's OK
	if FieldIs(field, FieldOptional) && value == nil {
		return true
	}
	// if argument is an expression it's OK whatever the type
	if valueType.Kind() == reflect.String &&
		(IsExpression(value.(string)) ||
			FieldIs(field, FieldExpression)) {
		return true
	}
	// if type of field is slice of the type of the argument and wrap, it's OK
	if field.Type.Kind() == reflect.Slice &&
		reflect.SliceOf(valueType) == field.Type &&
		FieldIs(field, FieldWrap) {
		return true
	}
	// if type is slice and argument is steps, it's OK
	if field.Type.Kind() == reflect.Slice &&
		FieldIs(field, FieldSteps) {
		return true
	}
	// check that value is of given type
	return IsValueOfType(value, field.Type)
}

// IsValueOfType tells if a value is of given type
// - value: the value to test as an interface{}
// - type: the type to check as a reflect.Type
// Return: a bool telling if value is of given type
func IsValueOfType(value interface{}, typ reflect.Type) bool {
	// if value is of given type it's true
	if reflect.TypeOf(value) == typ {
		return true
	}
	// if value and type are slices, test elements
	if reflect.TypeOf(value).Kind() == reflect.Slice && typ.Kind() == reflect.Slice {
		return IsValueOfType(reflect.ValueOf(value).Index(0).Interface(), typ.Elem())
	}
	// if value and type are maps, test key and value
	if reflect.TypeOf(value).Kind() == reflect.Map && typ.Kind() == reflect.Map {
		key := reflect.ValueOf(value).MapKeys()[0].Interface()
		val := reflect.ValueOf(value).MapIndex(reflect.ValueOf(key)).Interface()
		return IsValueOfType(key, typ.Key()) && IsValueOfType(val, typ.Elem())
	}
	// else return false
	return false
}

// EvaluateTaskArgs builds task arguments from task params and return it
// - args: task arguments parsed in build file
// - typ: the type of the arguments
// - context: the build context to evaluate arguments into
// Return:
// - result: as an interface{}
// - error: if something went wrong
func EvaluateTaskArgs(args TaskArgs, typ reflect.Type, context *Context) (interface{}, error) {
	var err error
	value := reflect.New(typ).Elem()
	for i := 0; i < value.NumField(); i++ {
		field := typ.Field(i)
		name := GetQuality(field, FieldName)
		if name == "" {
			name = strings.ToLower(field.Name)
		}
		if args[name] != nil {
			val := args[name]
			// evaluate expressions in context
			if reflect.TypeOf(val).Kind() == reflect.String &&
				(IsExpression(val.(string)) || FieldIs(field, FieldExpression)) {
				val, err = evaluateExpression(field, val, context)
				if err != nil {
					return nil, err
				}
			}
			// evaluate arguments
			val, err = context.EvaluateObject(val)
			if err != nil {
				return nil, err
			}
			// evaluate strings to replace "={expression}" with its value
			if reflect.TypeOf(val).Kind() == reflect.String {
				val = evaluateStrings(val, field)
			}
			// wrap values if necessary
			if FieldIs(field, FieldWrap) && !(reflect.TypeOf(val).Kind() == reflect.Slice) {
				slice := reflect.New(field.Type).Elem()
				slice = reflect.Append(slice, reflect.ValueOf(val))
				val = slice.Interface()
			}
			// put value in params
			CopyValue(reflect.ValueOf(val), value.Field(i))
		}
	}
	return value.Interface(), nil
}

func evaluateStrings(val interface{}, field reflect.StructField) interface{} {
	str := val.(string)
	// replace '\=' with '='
	if strings.HasPrefix(str, `\`+CharExpression) {
		str = str[1:]
	}
	// expand home if field tagged 'file'
	if FieldIs(field, FieldFile) {
		str = util.ExpandUserHome(str)
	}
	val = str
	return val
}

func evaluateExpression(field reflect.StructField, val interface{}, context *Context) (interface{}, error) {
	var err error
	str := val.(string)
	if IsExpression(str) {
		str = str[1:]
	}
	val, err = context.EvaluateExpression(str)
	if err != nil {
		return nil, err
	}
	expected := field.Type
	actual := reflect.TypeOf(val)
	if actual != expected {
		// we accept if expected is slice of interfaces and actual is slice
		if !(expected.Kind() == reflect.Slice && actual.Kind() == reflect.Slice) &&
		// or if slice and wrap
			!(expected == reflect.SliceOf(actual) && FieldIs(field, FieldWrap)) {
			return nil, fmt.Errorf("bad expression return type, expected '%v' but '%v' was returned",
				expected, actual)
		}
	}
	return val, nil
}

// CopyValue copy given value in another
// - orig: origin value
// - dest: destination value
func CopyValue(orig, dest reflect.Value) {
	// loop on slices
	if orig.Type().Kind() == reflect.Slice && dest.Type().Kind() == reflect.Slice {
		newSlice := reflect.MakeSlice(dest.Type(), orig.Len(), orig.Len())
		for i := 0; i < orig.Len(); i++ {
			CopyValue(orig.Index(i), newSlice.Index(i))
		}
		dest.Set(newSlice)
	} else
	// loop on maps
	if orig.Type().Kind() == reflect.Map && dest.Type().Kind() == reflect.Map {
		keyType := dest.Type().Key()
		valType := dest.Type().Elem()
		newMap := reflect.MakeMap(reflect.MapOf(keyType, valType))
		for _, key := range orig.MapKeys() {
			if key.Type().Kind() == reflect.Interface {
				key = key.Elem()
			}
			val := orig.MapIndex(key)
			if val.Type().Kind() == reflect.Interface {
				val = val.Elem()
			}
			newMap.SetMapIndex(key, val)
		}
		dest.Set(newMap)
	} else
	// get value of interfaces
	if orig.Kind() == reflect.Interface {
		CopyValue(orig.Elem(), dest)
	} else
	// other types
	{
		dest.Set(orig)
	}
}

// FieldIs tells if given field tag contains quality
// - field: the struct field
// - quality: the tested quality (such as "optional")
func FieldIs(field reflect.StructField, quality string) bool {
	tags := field.Tag.Get(NeonTag)
	qualities := strings.Split(tags, TagSeparator)
	for _, q := range qualities {
		if q == quality {
			return true
		}
	}
	return false
}

// GetQuality returns value of given quality
// - field: the field to examine
// - quality: quality to get
func GetQuality(field reflect.StructField, quality string) string {
	tags := field.Tag.Get(NeonTag)
	qualities := strings.Split(tags, TagSeparator)
	for _, q := range qualities {
		prefix := quality + "="
		if strings.HasPrefix(q, prefix) {
			return q[len(prefix):]
		}
	}
	return ""
}

// IsExpression tells if given string is an expression
// - s: the string to test
// Return: a bool that tells if the string is an expression
func IsExpression(s string) bool {
	if len(s) < 2 {
		return false
	}
	return s[0:1] == CharExpression && s[1:2] != CurlyExpression
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/anchor/chevalier"
	zmq "github.com/pebbe/zmq4"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

func queryES(origin string, req *chevalier.SourceRequest, host string) {
	engine := chevalier.NewQueryEngine(host, "chevalier", "datasource")
	results, err := engine.GetSources(origin, req)
	if err != nil {
		log.Println("Search error: %v", err)
	}
	if err != nil {
		log.Fatal(err)
	}
	for _, source := range results.GetSources() {
		fmt.Println(source)
	}
}

func queryChevalier(origin string, req *chevalier.SourceRequest, endpoint string) {
	sock, err := zmq.NewSocket(zmq.REQ)
	if err != nil {
		log.Fatal(err)
	}
	err = sock.Connect(endpoint)
	if err != nil {
		log.Fatal(err)
	}
	packet, err := chevalier.MarshalSourceRequest(req)
	if err != nil {
		log.Fatal(err)
	}
	_, err = sock.SendBytes(packet, 0)
	response, err := sock.RecvBytes(0)
	if err != nil {
		log.Fatal(err)
	}
	burst, err := chevalier.UnmarshalSourceBurst(response)
	if err != nil {
		log.Fatal(err)
	}
	for _, source := range burst.GetSources() {
		fmt.Println(source)
	}
}

func main() {
	esHost := flag.String("host", "localhost", "Elasticsearch host to connect to")
	protobuf := flag.Bool("protobuf", false, "Read a SourceRequest from stdin rather than accepting field:value pairs on the command line.")
	es := flag.Bool("es", false, "Read from Elasticsearch directly rather than chevalier.")
	startPage := flag.Int("start-page", 0, "Obtain results from this page.")
	pageSize := flag.Int("page-size", 0, "Number of results per page.")
	endpoint := flag.String("endpoint", "tcp://127.0.0.1:6283", "Chevalier endpoint (as a ZMQ URI).")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "%s <origin> <field:value> [field:value ...] [args]\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(1)
	}
	origin := flag.Arg(0)
	var req *chevalier.SourceRequest
	if *protobuf {
		reader := io.Reader(os.Stdin)
		packet, err := ioutil.ReadAll(reader)
		if err != nil {
			log.Fatal("Could not read from stdin: %v", err)
		}
		req, err = chevalier.UnmarshalSourceRequest(packet)
		if err != nil {
			log.Fatal("Could not unmarshal request: %v", err)
		}
	} else {
		tags := make([]*chevalier.SourceRequest_Tag, flag.NArg())
		for i, arg := range flag.Args()[1:] {
			pair := strings.Split(arg, ":")
			if len(pair) < 2 {
				log.Fatal("Could not parse %v: must be a 'field:value' pair.")
			}
			tags[i] = chevalier.NewSourceRequestTag(pair[0], pair[1])
		}
		req = chevalier.NewSourceRequest(tags)
		if *startPage > 0 {
			page := int64(*startPage)
			req.StartPage = &page
		}
		if *pageSize > 0 {
			size := int64(*pageSize)
			req.SourcesPerPage = &size
		}
	}
	if *es {
		queryES(origin, req, *esHost)
	} else {
		queryChevalier(origin, req, *endpoint)
	}
}
<commit_msg>Send a multipart request message from request_sources<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/anchor/chevalier"
	zmq "github.com/pebbe/zmq4"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

func queryES(origin string, req *chevalier.SourceRequest, host string) {
	engine := chevalier.NewQueryEngine(host, "chevalier", "datasource")
	results, err := engine.GetSources(origin, req)
	if err != nil {
		log.Println("Search error: %v", err)
	}
	if err != nil {
		log.Fatal(err)
	}
	for _, source := range results.GetSources() {
		fmt.Println(source)
	}
}

func queryChevalier(origin string, req *chevalier.SourceRequest, endpoint string) {
	sock, err := zmq.NewSocket(zmq.REQ)
	if err != nil {
		log.Fatal(err)
	}
	err = sock.Connect(endpoint)
	if err != nil {
		log.Fatal(err)
	}
	packet, err := chevalier.MarshalSourceRequest(req)
	if err != nil {
		log.Fatal(err)
	}
	_, err = sock.SendMessage(origin, packet, 0)
	response, err := sock.RecvBytes(0)
	if err != nil {
		log.Fatal(err)
	}
	burst, err := chevalier.UnmarshalSourceBurst(response)
	if err != nil {
		log.Fatal(err)
	}
	for _, source := range burst.GetSources() {
		fmt.Println(source)
	}
}

func main() {
	esHost := flag.String("host", "localhost", "Elasticsearch host to connect to")
	protobuf := flag.Bool("protobuf", false, "Read a SourceRequest from stdin rather than accepting field:value pairs on the command line.")
	es := flag.Bool("es", false, "Read from Elasticsearch directly rather than chevalier.")
	startPage := flag.Int("start-page", 0, "Obtain results from this page.")
	pageSize := flag.Int("page-size", 0, "Number of results per page.")
	endpoint := flag.String("endpoint", "tcp://127.0.0.1:6283", "Chevalier endpoint (as a ZMQ URI).")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "%s <origin> <field:value> [field:value ...] [args]\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(1)
	}
	origin := flag.Arg(0)
	var req *chevalier.SourceRequest
	if *protobuf {
		reader := io.Reader(os.Stdin)
		packet, err := ioutil.ReadAll(reader)
		if err != nil {
			log.Fatal("Could not read from stdin: %v", err)
		}
		req, err = chevalier.UnmarshalSourceRequest(packet)
		if err != nil {
			log.Fatal("Could not unmarshal request: %v", err)
		}
	} else {
		tags := make([]*chevalier.SourceRequest_Tag, flag.NArg())
		for i, arg := range flag.Args()[1:] {
			pair := strings.Split(arg, ":")
			if len(pair) < 2 {
				log.Fatal("Could not parse %v: must be a 'field:value' pair.")
			}
			tags[i] = chevalier.NewSourceRequestTag(pair[0], pair[1])
		}
		req = chevalier.NewSourceRequest(tags)
		if *startPage > 0 {
			page := int64(*startPage)
			req.StartPage = &page
		}
		if *pageSize > 0 {
			size := int64(*pageSize)
			req.SourcesPerPage = &size
		}
	}
	if *es {
		queryES(origin, req, *esHost)
	} else {
		queryChevalier(origin, req, *endpoint)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package geom

import (
	"unsafe"
)

// #cgo darwin LDFLAGS: -framework Cocoa
// #include <CoreGraphics/CoreGraphics.h>
import "C"

func (p *Path) PlatformPtr() unsafe.Pointer {
	path := C.CGPathCreateMutable()
	for _, node := range p.data {
		switch t := node.(type) {
		case *moveToPathNode:
			C.CGPathMoveToPoint(path, nil, C.CGFloat(t.x), C.CGFloat(t.y))
		case *lineToPathNode:
			C.CGPathAddLineToPoint(path, nil, C.CGFloat(t.x), C.CGFloat(t.y))
		case *arcPathNode:
			C.CGPathAddArc(path, nil, C.CGFloat(t.cx), C.CGFloat(t.cy), C.CGFloat(t.radius), C.CGFloat(t.startAngleRadians), C.CGFloat(t.endAngleRadians), C._Bool(t.clockwise))
		case *arcToPathNode:
			C.CGPathAddArcToPoint(path, nil, C.CGFloat(t.x1), C.CGFloat(t.y1), C.CGFloat(t.x2), C.CGFloat(t.y2), C.CGFloat(t.radius))
		case *curveToPathNode:
			C.CGPathAddCurveToPoint(path, nil, C.CGFloat(t.cp1x), C.CGFloat(t.cp1y), C.CGFloat(t.cp2x), C.CGFloat(t.cp2y), C.CGFloat(t.x), C.CGFloat(t.y))
		case *quadCurveToPathNode:
			C.CGPathAddQuadCurveToPoint(path, nil, C.CGFloat(t.cpx), C.CGFloat(t.cpy), C.CGFloat(t.x), C.CGFloat(t.y))
		case *rectPathNode:
			C.CGPathAddRect(path, nil, toCGRect(t.bounds))
		case *ellipsePathNode:
			C.CGPathAddEllipseInRect(path, nil, toCGRect(t.bounds))
		case *closePathNode:
			C.CGPathCloseSubpath(path)
		default:
			panic("Unknown path node type")
		}
	}
	return unsafe.Pointer(path)
}

func toCGRect(bounds Rect) C.CGRect {
	return C.CGRectMake(C.CGFloat(bounds.X), C.CGFloat(bounds.Y), C.CGFloat(bounds.Width), C.CGFloat(bounds.Height))
}
<commit_msg>Add comments<commit_after>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package geom

import (
	"unsafe"
)

// #cgo darwin LDFLAGS: -framework Cocoa
// #include <CoreGraphics/CoreGraphics.h>
import "C"

// PlatformPtr returns a pointer to the underlying platform-specific data.
func (p *Path) PlatformPtr() unsafe.Pointer {
	path := C.CGPathCreateMutable()
	for _, node := range p.data {
		switch t := node.(type) {
		case *moveToPathNode:
			C.CGPathMoveToPoint(path, nil, C.CGFloat(t.x), C.CGFloat(t.y))
		case *lineToPathNode:
			C.CGPathAddLineToPoint(path, nil, C.CGFloat(t.x), C.CGFloat(t.y))
		case *arcPathNode:
			C.CGPathAddArc(path, nil, C.CGFloat(t.cx), C.CGFloat(t.cy), C.CGFloat(t.radius), C.CGFloat(t.startAngleRadians), C.CGFloat(t.endAngleRadians), C._Bool(t.clockwise))
		case *arcToPathNode:
			C.CGPathAddArcToPoint(path, nil, C.CGFloat(t.x1), C.CGFloat(t.y1), C.CGFloat(t.x2), C.CGFloat(t.y2), C.CGFloat(t.radius))
		case *curveToPathNode:
			C.CGPathAddCurveToPoint(path, nil, C.CGFloat(t.cp1x), C.CGFloat(t.cp1y), C.CGFloat(t.cp2x), C.CGFloat(t.cp2y), C.CGFloat(t.x), C.CGFloat(t.y))
		case *quadCurveToPathNode:
			C.CGPathAddQuadCurveToPoint(path, nil, C.CGFloat(t.cpx), C.CGFloat(t.cpy), C.CGFloat(t.x), C.CGFloat(t.y))
		case *rectPathNode:
			C.CGPathAddRect(path, nil, toCGRect(t.bounds))
		case *ellipsePathNode:
			C.CGPathAddEllipseInRect(path, nil, toCGRect(t.bounds))
		case *closePathNode:
			C.CGPathCloseSubpath(path)
		default:
			panic("Unknown path node type")
		}
	}
	return unsafe.Pointer(path)
}

func toCGRect(bounds Rect) C.CGRect {
	return C.CGRectMake(C.CGFloat(bounds.X), C.CGFloat(bounds.Y), C.CGFloat(bounds.Width), C.CGFloat(bounds.Height))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/hashicorp/terraform/helper/schema"
	"k8s.io/kubernetes/pkg/api"
)

func buildVolumes(volumesSpecs []interface{}) []api.Volume {
	volumes := make([]api.Volume, len(volumeSpecs))
	if len(volumeSpecs) == 0 {
		return volumes
	}

	for volumeSpec

	pod := &api.Pod{
		Spec: buildPodSpec(d.Get("spec").([]interface{})),
	}

	pod.Kind = "Pod"
	pod.APIVersion = version

	populateMetadata(&pod.ObjectMeta, d.Get("metadata").([]interface{}))

	return pod
}

func buildVolume(volumeSpecs []interface{}) api.Volume {

}

func buildPodSpec(podSpecs []interface{}) api.PodSpec {
	if len(podSpecs) == 0 {
		return api.PodSpec{}
	}
	userPodSpec := podSpecs[0].(map[string]interface{})

	podSpec := api.PodSpec{
		Containers:                    buildContainers(userPodSpec["containers"].([]interface{})),
		ActiveDeadlineSeconds:         nil,
		TerminationGracePeriodSeconds: nil,
	}

	if _, ok := userPodSpec["node_selector"]; ok {
		podSpec.NodeSelector = convertMapTypeToStringMap(userPodSpec["node_selector"].(map[string]interface{}))
	}
	if _, ok := userPodSpec["node_name"]; ok {
		podSpec.NodeName = userPodSpec["node_name"].(string)
	}
	if _, ok := userPodSpec["service_account_name"]; ok {
		podSpec.ServiceAccountName = userPodSpec["service_account_name"].(string)
	}
	if _, ok := userPodSpec["host_network"]; ok {
		podSpec.HostNetwork = userPodSpec["host_network"].(bool)
	}
	if _, ok := userPodSpec["termination_grace_period"]; ok {
		helper := int64(userPodSpec["termination_grace_period"].(int))
		podSpec.TerminationGracePeriodSeconds = &helper
		if helper > 0 {
			podSpec.TerminationGracePeriodSeconds = &helper
		} else {
			podSpec.TerminationGracePeriodSeconds = nil
		}
	} else {
		podSpec.TerminationGracePeriodSeconds = nil
	}
	if _, ok := userPodSpec["active_deadline_seconds"]; ok {
		helper := int64(userPodSpec["active_deadline_seconds"].(int))
		if helper > 0 {
			podSpec.ActiveDeadlineSeconds = &helper
		} else {
			podSpec.ActiveDeadlineSeconds = nil
		}
	} else {
		podSpec.ActiveDeadlineSeconds = nil
	}
	if _, ok := userPodSpec["restart_policy"]; ok {
		podSpec.RestartPolicy = api.RestartPolicy(userPodSpec["restart_policy"].(string))
	}

	return podSpec
}
<commit_msg>adding in volume sources<commit_after>package main

import (
	"github.com/hashicorp/terraform/helper/schema"
	"k8s.io/kubernetes/pkg/api"
)

func buildVolumes(userVolumes []interface{}) []api.Volume {
	volumes := make([]api.Volume, len(userVolumes))
	if len(userVolumes) == 0 {
		return volumes
	}

	for index, userVolume := range userVolumes {
		volumes[index] = buildVolume(userVolume.(map[string]interface{}))
	}

	return volumes
}

func buildVolume(userVolume map[string]interface{}) api.Volume {
	volume := api.Volume{
		Name:	userVolume["name"].(string),
	}
	volume.VolumeSource.populateVolumeSource(userVolume)
}

func (volume api.VolumeSource) populateVolumeSource(userVolumeSource map[string]interface{}) {

}

func buildPodSpec(podSpecs []interface{}) api.PodSpec {
	if len(podSpecs) == 0 {
		return api.PodSpec{}
	}
	userPodSpec := podSpecs[0].(map[string]interface{})

	podSpec := api.PodSpec{
		Containers:                    buildContainers(userPodSpec["containers"].([]interface{})),
		ActiveDeadlineSeconds:         nil,
		TerminationGracePeriodSeconds: nil,
	}

	if _, ok := userPodSpec["node_selector"]; ok {
		podSpec.NodeSelector = convertMapTypeToStringMap(userPodSpec["node_selector"].(map[string]interface{}))
	}
	if _, ok := userPodSpec["node_name"]; ok {
		podSpec.NodeName = userPodSpec["node_name"].(string)
	}
	if _, ok := userPodSpec["service_account_name"]; ok {
		podSpec.ServiceAccountName = userPodSpec["service_account_name"].(string)
	}
	if _, ok := userPodSpec["host_network"]; ok {
		podSpec.HostNetwork = userPodSpec["host_network"].(bool)
	}
	if _, ok := userPodSpec["termination_grace_period"]; ok {
		helper := int64(userPodSpec["termination_grace_period"].(int))
		podSpec.TerminationGracePeriodSeconds = &helper
		if helper > 0 {
			podSpec.TerminationGracePeriodSeconds = &helper
		} else {
			podSpec.TerminationGracePeriodSeconds = nil
		}
	} else {
		podSpec.TerminationGracePeriodSeconds = nil
	}
	if _, ok := userPodSpec["active_deadline_seconds"]; ok {
		helper := int64(userPodSpec["active_deadline_seconds"].(int))
		if helper > 0 {
			podSpec.ActiveDeadlineSeconds = &helper
		} else {
			podSpec.ActiveDeadlineSeconds = nil
		}
	} else {
		podSpec.ActiveDeadlineSeconds = nil
	}
	if _, ok := userPodSpec["restart_policy"]; ok {
		podSpec.RestartPolicy = api.RestartPolicy(userPodSpec["restart_policy"].(string))
	}

	return podSpec
}
<|endoftext|>


<commit_before>package fix

const helpString = `
Usage: packer fix [options] TEMPLATE

  Reads the JSON template and attempts to fix known backwards
  incompatibilities. The fixed template will be outputted to standard out.

  If the template cannot be fixed due to an error, the command will exit
  with a non-zero exit status. Error messages will appear on standard error.

Fixes that are run:

  iso-md5         Replaces "iso_md5" in builders with newer "iso_checksum"

`
<commit_msg>command/fix: update help<commit_after>package fix

const helpString = `
Usage: packer fix [options] TEMPLATE

  Reads the JSON template and attempts to fix known backwards
  incompatibilities. The fixed template will be outputted to standard out.

  If the template cannot be fixed due to an error, the command will exit
  with a non-zero exit status. Error messages will appear on standard error.

Fixes that are run:

  iso-md5             Replaces "iso_md5" in builders with newer "iso_checksum"
  createtime          Replaces ".CreateTime" in builder configs with "{{timestamp}}"
  virtualbox-gaattach Updates VirtualBox builders using "guest_additions_attach"
                      to use "guest_additions_mode"
  pp-vagrant-override Replaces old-style provider overrides for the Vagrant
                      post-processor to new-style as of Packer 0.5.0.

`
<|endoftext|>


<commit_before>// Keybase file system

package main

import (
	"flag"
	"fmt"
	"os"

	"bazil.org/fuse"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/libfuse"
	"github.com/keybase/kbfs/libkbfs"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to file")
var local = flag.Bool("local", false,
	"use a fake local user DB instead of Keybase")
var localUserFlag = flag.String("localuser", "strib",
	"fake local user (only valid when local=true)")
var clientFlag = flag.Bool("client", false, "use keybase daemon")
var serverRootDirFlag = flag.String("server-root", "", "directory to put local server files (default is cwd)")
var serverInMemoryFlag = flag.Bool("server-in-memory", false, "use in-memory server (and ignore -server-root)")
var versionFile = flag.String("version-file", "", "write version to file on successful startup")
var mountType = flag.String("mount-type", "", "mount type: default, force")
var debug = flag.Bool("debug", false, "Print debug messages")
var version = flag.Bool("version", false, "Print version")

const usageStr = `Usage:
  kbfsfuse [-client | -local [-localuser=<user>]] [-debug]
    [-server-in-memory|-server-root=path/to/dir] /path/to/mountpoint

`

func start() *libfuse.Error {
	flag.Parse()

	if *version {
		fmt.Printf("%s\n", libkbfs.Version)
		return nil
	}

	if len(flag.Args()) < 1 {
		fmt.Print(usageStr)
		return libfuse.InitError("no mount specified")
	}

	var localUser string
	if *local {
		localUser = *localUserFlag
	} else if *clientFlag {
		localUser = ""
	} else {
		return libfuse.InitError("either -client or -local must be used")
	}

	if *debug {
		log := logger.NewWithCallDepth("FUSE", 1)
		log.Configure("", true, "")
		fuse.Debug = func(msg interface{}) {
			log.Debug("%s", msg)
		}
	}

	var serverRootDir *string
	if !*serverInMemoryFlag {
		serverRootDir = serverRootDirFlag
	}

	mountpoint := flag.Arg(0)
	var mounter libfuse.Mounter
	if *mountType == "force" {
		mounter = libfuse.ForceMounter{mountpoint}
	} else {
		mounter = libfuse.DefaultMounter{mountpoint}
	}

	options := libfuse.StartOptions{
		LocalUser:     localUser,
		ServerRootDir: *serverRootDir,
		CPUProfile:    *cpuprofile,
		MemProfile:    *memprofile,
		VersionFile:   *versionFile,
		Debug:         *debug,
	}

	return libfuse.Start(mounter, options)
}

func main() {
	err := start()
	if err != nil {
		fmt.Fprintf(os.Stderr, "kbfsfuse error: (%d) %s\n", err.Code, err.Message)

		os.Exit(err.Code)
	}
	os.Exit(0)
}
<commit_msg>Fix 'go vet' errors<commit_after>// Keybase file system

package main

import (
	"flag"
	"fmt"
	"os"

	"bazil.org/fuse"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/libfuse"
	"github.com/keybase/kbfs/libkbfs"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to file")
var local = flag.Bool("local", false,
	"use a fake local user DB instead of Keybase")
var localUserFlag = flag.String("localuser", "strib",
	"fake local user (only valid when local=true)")
var clientFlag = flag.Bool("client", false, "use keybase daemon")
var serverRootDirFlag = flag.String("server-root", "", "directory to put local server files (default is cwd)")
var serverInMemoryFlag = flag.Bool("server-in-memory", false, "use in-memory server (and ignore -server-root)")
var versionFile = flag.String("version-file", "", "write version to file on successful startup")
var mountType = flag.String("mount-type", "", "mount type: default, force")
var debug = flag.Bool("debug", false, "Print debug messages")
var version = flag.Bool("version", false, "Print version")

const usageStr = `Usage:
  kbfsfuse [-client | -local [-localuser=<user>]] [-debug]
    [-server-in-memory|-server-root=path/to/dir] /path/to/mountpoint

`

func start() *libfuse.Error {
	flag.Parse()

	if *version {
		fmt.Printf("%s\n", libkbfs.Version)
		return nil
	}

	if len(flag.Args()) < 1 {
		fmt.Print(usageStr)
		return libfuse.InitError("no mount specified")
	}

	var localUser string
	if *local {
		localUser = *localUserFlag
	} else if *clientFlag {
		localUser = ""
	} else {
		return libfuse.InitError("either -client or -local must be used")
	}

	if *debug {
		log := logger.NewWithCallDepth("FUSE", 1)
		log.Configure("", true, "")
		fuse.Debug = func(msg interface{}) {
			log.Debug("%s", msg)
		}
	}

	var serverRootDir *string
	if !*serverInMemoryFlag {
		serverRootDir = serverRootDirFlag
	}

	mountpoint := flag.Arg(0)
	var mounter libfuse.Mounter
	if *mountType == "force" {
		mounter = libfuse.ForceMounter{Dir: mountpoint}
	} else {
		mounter = libfuse.DefaultMounter{Dir: mountpoint}
	}

	options := libfuse.StartOptions{
		LocalUser:     localUser,
		ServerRootDir: *serverRootDir,
		CPUProfile:    *cpuprofile,
		MemProfile:    *memprofile,
		VersionFile:   *versionFile,
		Debug:         *debug,
	}

	return libfuse.Start(mounter, options)
}

func main() {
	err := start()
	if err != nil {
		fmt.Fprintf(os.Stderr, "kbfsfuse error: (%d) %s\n", err.Code, err.Message)

		os.Exit(err.Code)
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>package orbitus

import (
	"errors"
)

// inputOrbiter unmarshals messages and coordinates journalling and replication.
type inputOrbiter struct {
	orbiter

	// Receiver
	receiverIndex   uint64
	receiverHandler Handler
	receiverBuffer  chan []byte

	// Journaler
	journalerIndex   uint64
	journalerHandler Handler

	// Replicator
	replicatorIndex   uint64
	replicatorHandler Handler

	// Unmarshaller
	unmarshallerIndex   uint64
	unmarshallerHandler Handler
}

// NewReceiverOrbiter initializes a new inputOrbiter.
//
// All indexes are set to 0 and Handlers are assigned.
//
// Space for the buffer is allocated and is filled with empty Message objects.
//
// It returns a pointer to the initialized inputOrbiter.
func NewReceiverOrbiter(
	size uint64,
	receiver Handler,
	journaler Handler,
	replicator Handler,
	unmarshaller Handler,
	executor Handler,
) *inputOrbiter {
	orbiter := &inputOrbiter{
		// Handlers
		receiverHandler:     receiver,
		journalerHandler:    journaler,
		replicatorHandler:   replicator,
		unmarshallerHandler: unmarshaller,

		// Allocate the buffer
		orbiter: orbiter{
			buffer_size:     size,
			buffer:          make([]*Message, size),
			executorHandler: executor,

			// Start in stopped state
			running: false,
		},

		// Create the channel for the receiverBuffer
		receiverBuffer: make(chan []byte, 4096),
	}
	// Start at index 4 so we don't have index underflow
	orbiter.Reset(4)

	// Create 'size' new Message objects and store them in the buffer
	var i uint64
	for i = 0; i < size; i++ {
		orbiter.buffer[i] = new(Message)
	}

	return orbiter
}

// Reset sets all indexes to a given value.
// This is useful for rebuilding Orbiter state from an input file
// (eg: journaled output) instead of manually looping through the buffer until
// the desired index is reached.
//
// Returns an error if called while Orbiter is running. Stop Orbiter with
// Orbiter.Stop() before resetting.
func (o *inputOrbiter) Reset(i uint64) error {
	if o.running {
		return errors.New("Cannot reset a running Orbiter")
	}

	// Bypass the setters otherwise their sanity checks will error
	//
	o.receiverIndex = i
	o.journalerIndex = i - 1
	o.replicatorIndex = i - 2
	o.unmarshallerIndex = i - 3
	o.executorIndex = i - 4

	return nil
}

// Start starts the Orbiter processing.
// It launches a number of goroutines (one for each Handler + one manager).
//
// These goroutines handle the index checking logic and call the provided
// Handler function when there is data in the buffer available for it to
// process.
func (o *inputOrbiter) Start() {
	go o.run()
}

// SetExecutorIndex sets the inputOrbiter's executorIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current unmarshallerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetExecutorIndex(i uint64) error {
	if i < o.GetExecutorIndex() {
		return errors.New("New executor index cannot be less than current " +
			"index")
	} else if i > o.GetUnmarshallerIndex()-1 {
		return errors.New("New executor index cannot be greater than the " +
			"current unmarshaller index")
	}

	o.executorIndex = i
	return nil
}

// SetReceiverIndex sets the inputOrbiter's receiverIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current executorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReceiverIndex(i uint64) error {
	if i < o.GetReceiverIndex() {
		return errors.New("New receiver index cannot be less than current " +
			"index")
	} else if i >= o.GetExecutorIndex()+o.GetBufferSize() {
		return errors.New("The Receiver Consumer cannot pass the Business " +
			"Logic Consumer")
	}

	o.receiverIndex = i
	return nil
}

// GetReceiverIndex returns the inputOrbiter's current receiverIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetReceiverIndex() uint64 {
	return o.receiverIndex
}

// SetJournalerIndex sets the inputOrbiter's journalerIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current receiverIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetJournalerIndex(i uint64) error {
	if i < o.GetJournalerIndex() {
		return errors.New("New journaler index cannot be less than current " +
			"index")
	} else if i > o.GetReceiverIndex()-1 {
		return errors.New("New journaler index cannot be greater than the " +
			"current receiver index")
	}

	o.journalerIndex = i
	return nil
}

// GetJournalerIndex returns the inputOrbiter's current journalerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetJournalerIndex() uint64 {
	return o.journalerIndex
}

// SetReplicatorIndex sets the inputOrbiter's replicatorIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current journalerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReplicatorIndex(i uint64) error {
	if i < o.GetReplicatorIndex() {
		return errors.New("New replicator index cannot be less than current " +
			"index")
	} else if i > o.GetJournalerIndex()-1 {
		return errors.New("New replicator index cannot be greater than the " +
			"current journaler index")
	}

	o.replicatorIndex = i
	return nil
}

// GetReplicatorIndex returns the inputOrbiter's current replicatorIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetReplicatorIndex() uint64 {
	return o.replicatorIndex
}

// SetUnmarshallerIndex sets the inputOrbiter's unmarshallerIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current replicatorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetUnmarshallerIndex(i uint64) error {
	if i < o.GetUnmarshallerIndex() {
		return errors.New("New unmarshaller index cannot be less than " +
			"current index")
	} else if i > o.GetReplicatorIndex()-1 {
		return errors.New("New unmarshaller index cannot be greater than the " +
			"current replicator index")
	}

	o.unmarshallerIndex = i
	return nil
}

// GetUnmarshallerIndex returns the inputOrbiter's current unmarshallerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetUnmarshallerIndex() uint64 {
	return o.unmarshallerIndex
}

// runOrbiter starts all the Handler management goroutines.
func (o *inputOrbiter) run() {
	o.running = true
	go o.runReceiver(o.receiverHandler)
	go o.runHandler(o.journalerHandler, "journaler")
	go o.runHandler(o.replicatorHandler, "replicator")
	go o.runHandler(o.unmarshallerHandler, "unmarshaller")
	go o.runHandler(o.executorHandler, "executor")
}

// runReceiver processes messages sent to it until the channel is closed.
func (o *inputOrbiter) runReceiver(h Handler) {
	var i uint64
	for msg := range o.receiverBuffer {
		i = o.GetReceiverIndex()
		o.buffer[i%o.GetBufferSize()] = &Message{
			id:         i,
			marshalled: msg,
		}
		h(o, []uint64{i})
	}
}

// runHandler loops, calling the Handler when Messages are available to process.
//
// TODO gracefully handle Orbiter.Stop(). Currently all handlers stop
// immediately. Better behaviour would be for Receiver to stop first and the
// rest of the handlers finish processing anything available to them before
// stopping. This could be achieved better by the Orbiter.Stop() function
// closing the channel buffer and the receiver exiting on no more data.
func (o *inputOrbiter) runHandler(h Handler, t string) {
	var this, last, i, j uint64
	for o.running {
		// Get the current indexes.
		// this - current index of this Handler
		// last - highest index that this Handler can process
		switch t {
		case "journaler":
			this = o.GetJournalerIndex()
			last = o.GetReceiverIndex() - 1
		case "replicator":
			this = o.GetReplicatorIndex()
			last = o.GetJournalerIndex() - 1
		case "unmarshaller":
			this = o.GetUnmarshallerIndex()
			last = o.GetReplicatorIndex() - 1
		case "executor":
			this = o.GetExecutorIndex()
			last = o.GetUnmarshallerIndex() - 1
		}

		// Check if we can process anything
		if this < last {
			// Build list of indexes to process
			indexes := make([]uint64, last-this)
			for i, j = this+1, 0; i <= last; i, j = i+1, j+1 {
				indexes[j] = i
			}

			// Call the Handler
			h(o, indexes)
		}
	}
}
<commit_msg>Removed memory allocation and nil checked runReceiver loop<commit_after>package orbitus

import (
	"errors"
)

// inputOrbiter unmarshals messages and coordinates journalling and replication.
type inputOrbiter struct {
	orbiter

	// Receiver
	receiverIndex   uint64
	receiverHandler Handler
	receiverBuffer  chan []byte

	// Journaler
	journalerIndex   uint64
	journalerHandler Handler

	// Replicator
	replicatorIndex   uint64
	replicatorHandler Handler

	// Unmarshaller
	unmarshallerIndex   uint64
	unmarshallerHandler Handler
}

// NewReceiverOrbiter initializes a new inputOrbiter.
//
// All indexes are set to 0 and Handlers are assigned.
//
// Space for the buffer is allocated and is filled with empty Message objects.
//
// It returns a pointer to the initialized inputOrbiter.
func NewReceiverOrbiter(
	size uint64,
	receiver Handler,
	journaler Handler,
	replicator Handler,
	unmarshaller Handler,
	executor Handler,
) *inputOrbiter {
	orbiter := &inputOrbiter{
		// Handlers
		receiverHandler:     receiver,
		journalerHandler:    journaler,
		replicatorHandler:   replicator,
		unmarshallerHandler: unmarshaller,

		// Allocate the buffer
		orbiter: orbiter{
			buffer_size:     size,
			buffer:          make([]*Message, size),
			executorHandler: executor,

			// Start in stopped state
			running: false,
		},

		// Create the channel for the receiverBuffer
		receiverBuffer: make(chan []byte, 4096),
	}
	// Start at index 4 so we don't have index underflow
	orbiter.Reset(4)

	// Create 'size' new Message objects and store them in the buffer
	var i uint64
	for i = 0; i < size; i++ {
		orbiter.buffer[i] = new(Message)
	}

	return orbiter
}

// Reset sets all indexes to a given value.
// This is useful for rebuilding Orbiter state from an input file
// (eg: journaled output) instead of manually looping through the buffer until
// the desired index is reached.
//
// Returns an error if called while Orbiter is running. Stop Orbiter with
// Orbiter.Stop() before resetting.
func (o *inputOrbiter) Reset(i uint64) error {
	if o.running {
		return errors.New("Cannot reset a running Orbiter")
	}

	// Bypass the setters otherwise their sanity checks will error
	//
	o.receiverIndex = i
	o.journalerIndex = i - 1
	o.replicatorIndex = i - 2
	o.unmarshallerIndex = i - 3
	o.executorIndex = i - 4

	return nil
}

// Start starts the Orbiter processing.
// It launches a number of goroutines (one for each Handler + one manager).
//
// These goroutines handle the index checking logic and call the provided
// Handler function when there is data in the buffer available for it to
// process.
func (o *inputOrbiter) Start() {
	go o.run()
}

// SetExecutorIndex sets the inputOrbiter's executorIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current unmarshallerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetExecutorIndex(i uint64) error {
	if i < o.GetExecutorIndex() {
		return errors.New("New executor index cannot be less than current " +
			"index")
	} else if i > o.GetUnmarshallerIndex()-1 {
		return errors.New("New executor index cannot be greater than the " +
			"current unmarshaller index")
	}

	o.executorIndex = i
	return nil
}

// SetReceiverIndex sets the inputOrbiter's receiverIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current executorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReceiverIndex(i uint64) error {
	if i < o.GetReceiverIndex() {
		return errors.New("New receiver index cannot be less than current " +
			"index")
	} else if i >= o.GetExecutorIndex()+o.GetBufferSize() {
		return errors.New("The Receiver Consumer cannot pass the Business " +
			"Logic Consumer")
	}

	o.receiverIndex = i
	return nil
}

// GetReceiverIndex returns the inputOrbiter's current receiverIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetReceiverIndex() uint64 {
	return o.receiverIndex
}

// SetJournalerIndex sets the inputOrbiter's journalerIndex to the given value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current receiverIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetJournalerIndex(i uint64) error {
	if i < o.GetJournalerIndex() {
		return errors.New("New journaler index cannot be less than current " +
			"index")
	} else if i > o.GetReceiverIndex()-1 {
		return errors.New("New journaler index cannot be greater than the " +
			"current receiver index")
	}

	o.journalerIndex = i
	return nil
}

// GetJournalerIndex returns the inputOrbiter's current journalerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetJournalerIndex() uint64 {
	return o.journalerIndex
}

// SetReplicatorIndex sets the inputOrbiter's replicatorIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current journalerIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetReplicatorIndex(i uint64) error {
	if i < o.GetReplicatorIndex() {
		return errors.New("New replicator index cannot be less than current " +
			"index")
	} else if i > o.GetJournalerIndex()-1 {
		return errors.New("New replicator index cannot be greater than the " +
			"current journaler index")
	}

	o.replicatorIndex = i
	return nil
}

// GetReplicatorIndex returns the inputOrbiter's current replicatorIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetReplicatorIndex() uint64 {
	return o.replicatorIndex
}

// SetUnmarshallerIndex sets the inputOrbiter's unmarshallerIndex to the given
// value.
//
// The provided value is checked to ensure that it is within acceptable bounds.
// Specifically, it cannot be less than the current index or greater than the
// current replicatorIndex.
//
// If the above rules are broken an error is returned, else nil.
func (o *inputOrbiter) SetUnmarshallerIndex(i uint64) error {
	if i < o.GetUnmarshallerIndex() {
		return errors.New("New unmarshaller index cannot be less than " +
			"current index")
	} else if i > o.GetReplicatorIndex()-1 {
		return errors.New("New unmarshaller index cannot be greater than the " +
			"current replicator index")
	}

	o.unmarshallerIndex = i
	return nil
}

// GetUnmarshallerIndex returns the inputOrbiter's current unmarshallerIndex.
// This index may be larger than the buffer size, as the modulus is used to get
// a valid array index.
func (o *inputOrbiter) GetUnmarshallerIndex() uint64 {
	return o.unmarshallerIndex
}

// runOrbiter starts all the Handler management goroutines.
func (o *inputOrbiter) run() {
	o.running = true
	go o.runReceiver(o.receiverHandler)
	go o.runHandler(o.journalerHandler, "journaler")
	go o.runHandler(o.replicatorHandler, "replicator")
	go o.runHandler(o.unmarshallerHandler, "unmarshaller")
	go o.runHandler(o.executorHandler, "executor")
}

// runReceiver processes messages sent to it until the channel is closed.
func (o *inputOrbiter) runReceiver(h Handler) {
	var i uint64
	for msg := range o.receiverBuffer {
		i = o.GetReceiverIndex()

		// Store message and current index
		elem := o.buffer[i%o.GetBufferSize()]
		elem.id = i
		elem.marshalled = msg

		// Run handler
		if h != nil {
			h(o, []uint64{i})
		}
	}
}

// runHandler loops, calling the Handler when Messages are available to process.
//
// TODO gracefully handle Orbiter.Stop(). Currently all handlers stop
// immediately. Better behaviour would be for Receiver to stop first and the
// rest of the handlers finish processing anything available to them before
// stopping. This could be achieved better by the Orbiter.Stop() function
// closing the channel buffer and the receiver exiting on no more data.
func (o *inputOrbiter) runHandler(h Handler, t string) {
	var this, last, i, j uint64
	for o.running {
		// Get the current indexes.
		// this - current index of this Handler
		// last - highest index that this Handler can process
		switch t {
		case "journaler":
			this = o.GetJournalerIndex()
			last = o.GetReceiverIndex() - 1
		case "replicator":
			this = o.GetReplicatorIndex()
			last = o.GetJournalerIndex() - 1
		case "unmarshaller":
			this = o.GetUnmarshallerIndex()
			last = o.GetReplicatorIndex() - 1
		case "executor":
			this = o.GetExecutorIndex()
			last = o.GetUnmarshallerIndex() - 1
		}

		// Check if we can process anything
		if this < last {
			// Build list of indexes to process
			indexes := make([]uint64, last-this)
			for i, j = this+1, 0; i <= last; i, j = i+1, j+1 {
				indexes[j] = i
			}

			// Call the Handler
			h(o, indexes)
		}
	}
}
<|endoftext|>


<commit_before>// Package azureFS implements fs.FileProvider
// and handles Azure blob storage
package azureFS

//"github.com/Azure/azure-sdk-for-go/storage"
import (
	"fmt"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/storage"
	log "github.com/Sirupsen/logrus"
	"github.com/mindflavor/ftpserver2/ftp/fs"
	"github.com/mindflavor/ftpserver2/ftp/fs/azure/azureBlob"
	"github.com/mindflavor/ftpserver2/ftp/fs/azure/azureContainer"
	"github.com/mindflavor/ftpserver2/identity"
)

type azureFS struct {
	id                   identity.Identity
	client               storage.BlobStorageClient
	currentRealDirectory string
}

func (pfs *azureFS) String() string {
	return fmt.Sprintf("id:%s, currentRealDirectory: %s", pfs.id, pfs.currentRealDirectory)
}

// New initializes a new fs.FileProvider with a specific Azure account and key
func New(account, secret string) (fs.FileProvider, error) {
	cli, err := storage.NewClient(account, secret, storage.DefaultBaseURL, storage.DefaultAPIVersion, true)
	if err != nil {
		return nil, err
	}

	return &azureFS{
		id:                   nil,
		client:               cli.GetBlobService(),
		currentRealDirectory: "",
	}, nil
}

func (pfs *azureFS) Identity() identity.Identity {
	return pfs.id
}
func (pfs *azureFS) SetIdentity(identity identity.Identity) {
	pfs.id = identity
}

func (pfs *azureFS) CurrentDirectory() string {
	return "/" + pfs.currentRealDirectory
}

func (pfs *azureFS) List() ([]fs.File, error) {
	if pfs.CurrentDirectory() == "/" {
		// list containers

		// TODO
		// we should check for more than 1000 entries
		lcParams := storage.ListContainersParameters{MaxResults: 1000}
		lbr, err := pfs.client.ListContainers(lcParams)
		if err != nil {
			return nil, err
		}

		cnts := make([]fs.File, len(lbr.Containers))

		for i, item := range lbr.Containers {
			cnts[i] = azureContainer.New(item.Name, parseAzureTime(item.Properties.LastModified), pfs.client)
		}

		return cnts, nil
	}

	// files!
	lbParams := storage.ListBlobsParameters{MaxResults: 1000}
	lbr, err := pfs.client.ListBlobs(pfs.currentRealDirectory, lbParams)
	if err != nil {
		return nil, err
	}

	blobs := make([]fs.File, len(lbr.Blobs))

	for i, item := range lbr.Blobs {
		blobs[i] = azureBlob.New(item.Name, pfs.currentRealDirectory, item.Properties.ContentLength, parseAzureTime(item.Properties.LastModified), 0666, pfs.client)
	}

	return blobs, nil
}

func (pfs *azureFS) Get(filename string) (fs.File, error) {
	fullpath := filename
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + filename
	}

	toks := splitAndCleanPath(fullpath)
	log.WithFields(log.Fields{"pfs": pfs, "filename": filename, "fullpath": fullpath, "toks": toks}).Debug("azureFS::azureFS::Get called")

	if len(toks) == 0 { // root
		return azureContainer.New("", time.Now(), pfs.client), nil
	}
	if len(toks) == 1 { // containter
		return azureContainer.New(filename, time.Now(), pfs.client), nil
	}

	// else blob
	return azureBlob.New(toks[1], toks[0], 0, time.Now(), 0666, pfs.client), nil
}

func (pfs *azureFS) New(filename string, isDirectory bool) (fs.File, error) {
	fullpath := filename
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + filename
	}

	log.WithFields(log.Fields{"pfs": pfs, "filename": filename, "fullpath": fullpath, "isDirectory": isDirectory}).Debug("azureFS::azureFS::New called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) == 1 { // container
		return azureContainer.New(filename, time.Now(), pfs.client), nil
	}

	return azureBlob.New(toks[1], toks[0], 0, time.Now(), 0666, pfs.client), nil
}

func (pfs *azureFS) Clone() fs.FileProvider {
	return &azureFS{
		id:                   pfs.id,
		client:               pfs.client,
		currentRealDirectory: pfs.currentRealDirectory,
	}
}

func (pfs *azureFS) ChangeDirectory(path string) error {
	fullpath := path

	if len(path) == 0 {
		pfs.currentRealDirectory = ""
		log.WithFields(log.Fields{"pfs": pfs, "path": path}).Debug("azureFS::azureFS::ChangeDirectory changed to root /")
		return nil
	}

	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + path
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "fullpath": fullpath}).Debug("azureFS::azureFS::ChangeDirectory called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) == 0 {
		pfs.currentRealDirectory = ""
		log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Debug("azureFS::azureFS::ChangeDirectory changed to root /")
		return nil
	}

	if toks[len(toks)-1] == ".." { // strip .. folder
		if len(toks) == 1 { // root
			pfs.currentRealDirectory = ""
			log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Debug("azureFS::azureFS::ChangeDirectory changed to root /")
			return nil
		}
		toks = toks[:len(toks)-2]
	}

	if len(toks) == 1 {
		pfs.currentRealDirectory = toks[0]
		log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Debug("azureFS::azureFS::ChangeDirectory changed to container")
		return nil
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Warn("azureFS::azureFS::ChangeDirectory azure storage does not support nested containers")
	return fmt.Errorf("cannot change directory: azure storage supports only root level container")
}

func (pfs *azureFS) CreateDirectory(path string) error {
	fullpath := path
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + path
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "fullpath": fullpath}).Debug("azureFS::azureFS::CreateDirectory called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) > 1 {
		return fmt.Errorf("cannot nest subdirectories in azure storage")
	}

	return pfs.client.CreateContainer(path, storage.ContainerAccessTypePrivate)

}

func (pfs *azureFS) RemoveDirectory(path string) error {
	fullpath := path
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + path
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "fullpath": fullpath}).Debug("azureFS::azureFS::RemoveDirectory called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) > 1 {
		return fmt.Errorf("there are no subdirectories in Azure storage")
	}

	return pfs.client.DeleteContainer(path)
}

func parseAzureTime(tToParse string) time.Time {
	log.WithFields(log.Fields{"tToParse": tToParse}).Debug("azureFS::parseAzureTime called")
	t, _ := time.Parse(time.RFC1123, tToParse)
	return t
}

func splitAndCleanPath(s string) []string {
	var toks []string
	for _, item := range strings.Split(s, "/") {
		if item != "" {
			toks = append(toks, item)
		}
	}

	return toks
}
<commit_msg>Correct blob name and propaties<commit_after>// Package azureFS implements fs.FileProvider
// and handles Azure blob storage
package azureFS

//"github.com/Azure/azure-sdk-for-go/storage"
import (
	"fmt"
	"strings"
	"time"

	"github.com/Azure/azure-sdk-for-go/storage"
	log "github.com/Sirupsen/logrus"
	"github.com/mindflavor/ftpserver2/ftp/fs"
	"github.com/mindflavor/ftpserver2/ftp/fs/azure/azureBlob"
	"github.com/mindflavor/ftpserver2/ftp/fs/azure/azureContainer"
	"github.com/mindflavor/ftpserver2/identity"
)

type azureFS struct {
	id                   identity.Identity
	client               storage.BlobStorageClient
	currentRealDirectory string
}

func (pfs *azureFS) String() string {
	return fmt.Sprintf("id:%s, currentRealDirectory: %s", pfs.id, pfs.currentRealDirectory)
}

// New initializes a new fs.FileProvider with a specific Azure account and key
func New(account, secret string) (fs.FileProvider, error) {
	cli, err := storage.NewClient(account, secret, storage.DefaultBaseURL, storage.DefaultAPIVersion, true)
	if err != nil {
		return nil, err
	}

	return &azureFS{
		id:                   nil,
		client:               cli.GetBlobService(),
		currentRealDirectory: "",
	}, nil
}

func (pfs *azureFS) Identity() identity.Identity {
	return pfs.id
}
func (pfs *azureFS) SetIdentity(identity identity.Identity) {
	pfs.id = identity
}

func (pfs *azureFS) CurrentDirectory() string {
	return "/" + pfs.currentRealDirectory
}

func (pfs *azureFS) List() ([]fs.File, error) {
	if pfs.CurrentDirectory() == "/" {
		// list containers

		// TODO
		// we should check for more than 1000 entries
		lcParams := storage.ListContainersParameters{MaxResults: 1000}
		lbr, err := pfs.client.ListContainers(lcParams)
		if err != nil {
			return nil, err
		}

		cnts := make([]fs.File, len(lbr.Containers))

		for i, item := range lbr.Containers {
			cnts[i] = azureContainer.New(item.Name, parseAzureTime(item.Properties.LastModified), pfs.client)
		}

		return cnts, nil
	}

	// files!
	lbParams := storage.ListBlobsParameters{MaxResults: 1000}
	lbr, err := pfs.client.ListBlobs(pfs.currentRealDirectory, lbParams)
	if err != nil {
		return nil, err
	}

	blobs := make([]fs.File, len(lbr.Blobs))

	for i, item := range lbr.Blobs {
		blobs[i] = azureBlob.New(item.Name, pfs.currentRealDirectory, item.Properties.ContentLength, parseAzureTime(item.Properties.LastModified), 0666, pfs.client)
	}

	return blobs, nil
}

func (pfs *azureFS) Get(filename string) (fs.File, error) {
	fullpath := filename
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + filename
	}

	toks := splitAndCleanPath(fullpath)
	log.WithFields(log.Fields{"pfs": pfs, "filename": filename, "fullpath": fullpath, "toks": toks}).Debug("azureFS::azureFS::Get called")

	if len(toks) == 0 { // root
		return azureContainer.New("", time.Now(), pfs.client), nil
	}
	if len(toks) == 1 { // containter
		return azureContainer.New(filename, time.Now(), pfs.client), nil
	}

	// else blob
	props, err := pfs.client.GetBlobProperties(toks[0], strings.Join(toks[1:], "/"))
	if err != nil {
		return nil, err
	}
	return azureBlob.New(strings.Join(toks[1:], "/"), toks[0], props.ContentLength, parseAzureTime(props.LastModified), 0666, pfs.client), nil
}

func (pfs *azureFS) New(filename string, isDirectory bool) (fs.File, error) {
	fullpath := filename
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + filename
	}

	log.WithFields(log.Fields{"pfs": pfs, "filename": filename, "fullpath": fullpath, "isDirectory": isDirectory}).Debug("azureFS::azureFS::New called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) == 1 { // container
		return azureContainer.New(filename, time.Now(), pfs.client), nil
	}

	return azureBlob.New(toks[1], toks[0], 0, time.Now(), 0666, pfs.client), nil
}

func (pfs *azureFS) Clone() fs.FileProvider {
	return &azureFS{
		id:                   pfs.id,
		client:               pfs.client,
		currentRealDirectory: pfs.currentRealDirectory,
	}
}

func (pfs *azureFS) ChangeDirectory(path string) error {
	fullpath := path

	if len(path) == 0 {
		pfs.currentRealDirectory = ""
		log.WithFields(log.Fields{"pfs": pfs, "path": path}).Debug("azureFS::azureFS::ChangeDirectory changed to root /")
		return nil
	}

	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + path
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "fullpath": fullpath}).Debug("azureFS::azureFS::ChangeDirectory called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) == 0 {
		pfs.currentRealDirectory = ""
		log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Debug("azureFS::azureFS::ChangeDirectory changed to root /")
		return nil
	}

	if toks[len(toks)-1] == ".." { // strip .. folder
		if len(toks) == 1 { // root
			pfs.currentRealDirectory = ""
			log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Debug("azureFS::azureFS::ChangeDirectory changed to root /")
			return nil
		}
		toks = toks[:len(toks)-2]
	}

	if len(toks) == 1 {
		pfs.currentRealDirectory = toks[0]
		log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Debug("azureFS::azureFS::ChangeDirectory changed to container")
		return nil
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "len(toks)": len(toks), "toks": toks}).Warn("azureFS::azureFS::ChangeDirectory azure storage does not support nested containers")
	return fmt.Errorf("cannot change directory: azure storage supports only root level container")
}

func (pfs *azureFS) CreateDirectory(path string) error {
	fullpath := path
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + path
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "fullpath": fullpath}).Debug("azureFS::azureFS::CreateDirectory called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) > 1 {
		return fmt.Errorf("cannot nest subdirectories in azure storage")
	}

	return pfs.client.CreateContainer(path, storage.ContainerAccessTypePrivate)

}

func (pfs *azureFS) RemoveDirectory(path string) error {
	fullpath := path
	if fullpath[0] != '/' {
		fullpath = "/" + pfs.currentRealDirectory + "/" + path
	}

	log.WithFields(log.Fields{"pfs": pfs, "path": path, "fullpath": fullpath}).Debug("azureFS::azureFS::RemoveDirectory called")

	toks := splitAndCleanPath(fullpath)

	if len(toks) > 1 {
		return fmt.Errorf("there are no subdirectories in Azure storage")
	}

	return pfs.client.DeleteContainer(path)
}

func parseAzureTime(tToParse string) time.Time {
	log.WithFields(log.Fields{"tToParse": tToParse}).Debug("azureFS::parseAzureTime called")
	t, _ := time.Parse(time.RFC1123, tToParse)
	return t
}

func splitAndCleanPath(s string) []string {
	var toks []string
	for _, item := range strings.Split(s, "/") {
		if item != "" {
			toks = append(toks, item)
		}
	}

	return toks
}
<|endoftext|>


<commit_before>// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package specs

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 1
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-rc6-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>version: release v1.0.0-rc7<commit_after>// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package specs

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 1
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-rc7"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>/**

SQL生成模板
用于根据struct的定义生成update语句和insert语句
规则
  1、表名
   默认t_stuct的名称(小写，驼峰转 xx_xx)
   可以通过setTablePreFix来指定默认的表前缀
   可以通过tag Table:""指定表名

  2、字段名称
    默认字段名称(小写，驼峰转 xx_xx)
	可以通过 tag Field:""指定字段名

  3、特例
    通过tag Option:"" 来指定。
	可选值：auto、pk、not 分别表示 自动增长、主健、忽略

*/
package sql

import (
	"reflect"
	"strings"
	"github.com/aosfather/bingo/utils"
	"fmt"
)

var (
	table_prefix       string = "t_"
	table_insert_cache map[string]string
)

func init() {
	table_insert_cache = make(map[string]string)
}
//mysql的分页sql生成
func buildMySqlLimitSql(page Page) string {
	if page.Index<1 {
		page.Index=1
	}

	if page.Size==0 {
		page.Size=10
	}

	return fmt.Sprint(" limit %d,%d",page.Size*(page.Index-1),page.Size)

}

func SetTablePreFix(pfix string) {
	table_prefix = pfix
}

func GetInsertSql(target interface{}) (string, []interface{}, error) {
	objT, _, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	key := objT.Name()
	sql := table_insert_cache[key]

	if sql == "" {
		sql, args, err := CreateInserSql(target)
		if err != nil {
			return "", nil, err
		}
		table_insert_cache[key] = sql
		return sql, args, err

	}

	args, err := structValueToArray(target)
	if err != nil {
		return "", nil, err
	}
	return sql, args, nil
}

func StructValueToCustomArray(target interface{}, col ...string) ([]interface{}, error) {
	_, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return nil, err
	}
	args := make([]interface{}, len(col))
	for i, field := range col {
		vf := objV.FieldByName(field)
		if !vf.CanInterface() {
			args[i] = nil
		} else {
			args[i] = objV.FieldByName(field).Interface()
		}

	}
	return args, nil
}
func structValueToArray(target interface{}) ([]interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return nil, err
	}

	args := make([]interface{}, 0, 0)
	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}

		//对于自增长和明确忽略的字段不做转换
		if isFieldIgnore(f) {
			continue
		}

		args = append(args, vf.Interface())

	}
	return args, nil

}

func CreateInserSql(target interface{}) (string, []interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlFields string
	var sqlValues string
	args := make([]interface{}, 0, 0)
	fieldIndex := 0
	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}

		colName := utils.GetColName(f)
		//对于自增长和明确忽略的字段不做转换
		tagOption := f.Tag.Get("Option")
		if tagOption != "" {
			if strings.Index(tagOption, "auto") != -1 || strings.Index(tagOption, "not") != -1 {
				continue
			}
		}

		args = append(args, vf.Interface())
		if fieldIndex > 0 {
			sqlFields += ","
			sqlValues += ","
		}

		sqlFields += colName
		sqlValues += "?"
		fieldIndex++

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	return "Insert into " + tagTableName + "(" + sqlFields + ") Values(" + sqlValues + ")", args, nil
}
func CreateDeleteSql(target interface{}, col ...string) (string, []interface{}, error) {
   //类似于查询只是把查询变成了删除
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlwheres string
	argsWhere := make([]interface{}, 0, 0)
	whereFields := 0
	if len(col) != 0 {
		for _, fieldName := range col {
			f, b := objT.FieldByName(fieldName)
			vf := objV.FieldByName(fieldName)
			if !b || !vf.CanInterface() {
				continue
			}
			colName := utils.GetColName(f)
			if whereFields > 0 {
				sqlwheres += " and "
			}
			sqlwheres += colName + "=?"
			argsWhere = append(argsWhere, vf.Interface())
			whereFields++
		}
	}

	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}
		if len(col) == 0 {
			colName := utils.GetColName(f)
			//对于标识为pk的字段做为条件
			tagOption := f.Tag.Get("Option")
			if tagOption != "" {
				if strings.Index(tagOption, "pk") != -1 {
					//where的处理
					if whereFields > 0 {
						sqlwheres += " and "
					}
					sqlwheres += colName + " =?"
					argsWhere = append(argsWhere, vf.Interface())
					whereFields++
				}
			}
		}

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	return "delete from " + tagTableName + " where " + sqlwheres, argsWhere, nil

}

func CreateUpdateSql(target interface{}, col ...string) (string, []interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlFields string
	var sqlwheres string
	args := make([]interface{}, 0, 0)
	argsWhere := make([]interface{}, 0, 0)
	fieldIndex := 0
	whereFields := 0
	if len(col) != 0 {
		for _, fieldName := range col {
			f, b := objT.FieldByName(fieldName)
			vf := objV.FieldByName(fieldName)
			if !b || !vf.CanInterface() {
				continue
			}
			colName := utils.GetColName(f)
			if fieldIndex > 0 {
				sqlFields += ","
			}
			sqlFields += colName + "=?"
			args = append(args, vf.Interface())
			fieldIndex++
		}
	}

	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}

		colName := utils.GetColName(f)
		if len(col) == 0 {

			if fieldIndex > 0 {
				sqlFields += ","
			}
			sqlFields += colName + "=?"
			args = append(args, vf.Interface())
			fieldIndex++
		}

		//对于自增长和明确忽略的字段不做转换
		tagOption := f.Tag.Get("Option")
		if tagOption != "" {
			if strings.Index(tagOption, "pk") != -1 {
				//where的处理
				if whereFields > 0 {
					sqlwheres += " and "
				}
				sqlwheres += colName + " =?"
				whereFields++
				argsWhere = append(argsWhere, vf.Interface())
			}
		}

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	args = append(args, argsWhere...)

	return "update " + tagTableName + " set " + sqlFields + " where " + sqlwheres, args, nil
}

func CreateQuerySql(target interface{}, col ...string) (string, []interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlwheres string
	argsWhere := make([]interface{}, 0, 0)
	whereFields := 0
	if len(col) != 0 {
		for _, fieldName := range col {
			f, b := objT.FieldByName(fieldName)
			vf := objV.FieldByName(fieldName)
			if !b || !vf.CanInterface() {
				continue
			}
			colName := utils.GetColName(f)
			if whereFields > 0 {
				sqlwheres += " and "
			}
			sqlwheres += colName + "=?"
			argsWhere = append(argsWhere, vf.Interface())
			whereFields++
		}
	}

	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}
		if len(col) == 0 {
			colName := utils.GetColName(f)
			//对于标识为pk的字段做为条件
			tagOption := f.Tag.Get("Option")
			if tagOption != "" {
				if strings.Index(tagOption, "pk") != -1 {
					//where的处理
					if whereFields > 0 {
						sqlwheres += " and "
					}
					sqlwheres += colName + " =?"
					argsWhere = append(argsWhere, vf.Interface())
					whereFields++
				}
			}
		}

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	return "select * from " + tagTableName + " where " + sqlwheres, argsWhere, nil
}

func isFieldIgnore(field reflect.StructField) bool {
	//对于自增长和明确忽略的字段不做转换
	tagOption := field.Tag.Get("Option")
	if tagOption != "" {
		if strings.Index(tagOption, "auto") != -1 || strings.Index(tagOption, "not") != -1 {
			return true
		}
	}
	return false
}
<commit_msg>修正limit的生成<commit_after>/**

SQL生成模板
用于根据struct的定义生成update语句和insert语句
规则
  1、表名
   默认t_stuct的名称(小写，驼峰转 xx_xx)
   可以通过setTablePreFix来指定默认的表前缀
   可以通过tag Table:""指定表名

  2、字段名称
    默认字段名称(小写，驼峰转 xx_xx)
	可以通过 tag Field:""指定字段名

  3、特例
    通过tag Option:"" 来指定。
	可选值：auto、pk、not 分别表示 自动增长、主健、忽略

*/
package sql

import (
	"reflect"
	"strings"
	"github.com/aosfather/bingo/utils"
	"fmt"
)

var (
	table_prefix       string = "t_"
	table_insert_cache map[string]string
)

func init() {
	table_insert_cache = make(map[string]string)
}
//mysql的分页sql生成
func buildMySqlLimitSql(page Page) string {
	if page.Index<1 {
		page.Index=1
	}

	if page.Size==0 {
		page.Size=10
	}

	return fmt.Sprintf(" limit %d,%d",page.Size*(page.Index-1),page.Size)

}

func SetTablePreFix(pfix string) {
	table_prefix = pfix
}

func GetInsertSql(target interface{}) (string, []interface{}, error) {
	objT, _, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	key := objT.Name()
	sql := table_insert_cache[key]

	if sql == "" {
		sql, args, err := CreateInserSql(target)
		if err != nil {
			return "", nil, err
		}
		table_insert_cache[key] = sql
		return sql, args, err

	}

	args, err := structValueToArray(target)
	if err != nil {
		return "", nil, err
	}
	return sql, args, nil
}

func StructValueToCustomArray(target interface{}, col ...string) ([]interface{}, error) {
	_, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return nil, err
	}
	args := make([]interface{}, len(col))
	for i, field := range col {
		vf := objV.FieldByName(field)
		if !vf.CanInterface() {
			args[i] = nil
		} else {
			args[i] = objV.FieldByName(field).Interface()
		}

	}
	return args, nil
}
func structValueToArray(target interface{}) ([]interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return nil, err
	}

	args := make([]interface{}, 0, 0)
	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}

		//对于自增长和明确忽略的字段不做转换
		if isFieldIgnore(f) {
			continue
		}

		args = append(args, vf.Interface())

	}
	return args, nil

}

func CreateInserSql(target interface{}) (string, []interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlFields string
	var sqlValues string
	args := make([]interface{}, 0, 0)
	fieldIndex := 0
	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}

		colName := utils.GetColName(f)
		//对于自增长和明确忽略的字段不做转换
		tagOption := f.Tag.Get("Option")
		if tagOption != "" {
			if strings.Index(tagOption, "auto") != -1 || strings.Index(tagOption, "not") != -1 {
				continue
			}
		}

		args = append(args, vf.Interface())
		if fieldIndex > 0 {
			sqlFields += ","
			sqlValues += ","
		}

		sqlFields += colName
		sqlValues += "?"
		fieldIndex++

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	return "Insert into " + tagTableName + "(" + sqlFields + ") Values(" + sqlValues + ")", args, nil
}
func CreateDeleteSql(target interface{}, col ...string) (string, []interface{}, error) {
   //类似于查询只是把查询变成了删除
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlwheres string
	argsWhere := make([]interface{}, 0, 0)
	whereFields := 0
	if len(col) != 0 {
		for _, fieldName := range col {
			f, b := objT.FieldByName(fieldName)
			vf := objV.FieldByName(fieldName)
			if !b || !vf.CanInterface() {
				continue
			}
			colName := utils.GetColName(f)
			if whereFields > 0 {
				sqlwheres += " and "
			}
			sqlwheres += colName + "=?"
			argsWhere = append(argsWhere, vf.Interface())
			whereFields++
		}
	}

	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}
		if len(col) == 0 {
			colName := utils.GetColName(f)
			//对于标识为pk的字段做为条件
			tagOption := f.Tag.Get("Option")
			if tagOption != "" {
				if strings.Index(tagOption, "pk") != -1 {
					//where的处理
					if whereFields > 0 {
						sqlwheres += " and "
					}
					sqlwheres += colName + " =?"
					argsWhere = append(argsWhere, vf.Interface())
					whereFields++
				}
			}
		}

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	return "delete from " + tagTableName + " where " + sqlwheres, argsWhere, nil

}

func CreateUpdateSql(target interface{}, col ...string) (string, []interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlFields string
	var sqlwheres string
	args := make([]interface{}, 0, 0)
	argsWhere := make([]interface{}, 0, 0)
	fieldIndex := 0
	whereFields := 0
	if len(col) != 0 {
		for _, fieldName := range col {
			f, b := objT.FieldByName(fieldName)
			vf := objV.FieldByName(fieldName)
			if !b || !vf.CanInterface() {
				continue
			}
			colName := utils.GetColName(f)
			if fieldIndex > 0 {
				sqlFields += ","
			}
			sqlFields += colName + "=?"
			args = append(args, vf.Interface())
			fieldIndex++
		}
	}

	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}

		colName := utils.GetColName(f)
		if len(col) == 0 {

			if fieldIndex > 0 {
				sqlFields += ","
			}
			sqlFields += colName + "=?"
			args = append(args, vf.Interface())
			fieldIndex++
		}

		//对于自增长和明确忽略的字段不做转换
		tagOption := f.Tag.Get("Option")
		if tagOption != "" {
			if strings.Index(tagOption, "pk") != -1 {
				//where的处理
				if whereFields > 0 {
					sqlwheres += " and "
				}
				sqlwheres += colName + " =?"
				whereFields++
				argsWhere = append(argsWhere, vf.Interface())
			}
		}

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	args = append(args, argsWhere...)

	return "update " + tagTableName + " set " + sqlFields + " where " + sqlwheres, args, nil
}

func CreateQuerySql(target interface{}, col ...string) (string, []interface{}, error) {
	objT, objV, err := utils.GetStructTypeValue(target)
	if err != nil {
		return "", nil, err
	}
	var tagTableName string
	var sqlwheres string
	argsWhere := make([]interface{}, 0, 0)
	whereFields := 0
	if len(col) != 0 {
		for _, fieldName := range col {
			f, b := objT.FieldByName(fieldName)
			vf := objV.FieldByName(fieldName)
			if !b || !vf.CanInterface() {
				continue
			}
			colName := utils.GetColName(f)
			if whereFields > 0 {
				sqlwheres += " and "
			}
			sqlwheres += colName + "=?"
			argsWhere = append(argsWhere, vf.Interface())
			whereFields++
		}
	}

	for i := 0; i < objT.NumField(); i++ {
		f := objT.Field(i)
		vf := objV.Field(i)
		if !vf.CanInterface() {
			continue
		}
		tagTable := f.Tag.Get("Table")
		if tagTable != "" {
			tagTableName = tagTable
		}
		if len(col) == 0 {
			colName := utils.GetColName(f)
			//对于标识为pk的字段做为条件
			tagOption := f.Tag.Get("Option")
			if tagOption != "" {
				if strings.Index(tagOption, "pk") != -1 {
					//where的处理
					if whereFields > 0 {
						sqlwheres += " and "
					}
					sqlwheres += colName + " =?"
					argsWhere = append(argsWhere, vf.Interface())
					whereFields++
				}
			}
		}

	}

	//如果没有指定表名就使用默认规则
	if tagTableName == "" {
		tagTableName = table_prefix + utils.BingoString(objT.Name()).SnakeString()
	}

	return "select * from " + tagTableName + " where " + sqlwheres, argsWhere, nil
}

func isFieldIgnore(field reflect.StructField) bool {
	//对于自增长和明确忽略的字段不做转换
	tagOption := field.Tag.Get("Option")
	if tagOption != "" {
		if strings.Index(tagOption, "auto") != -1 || strings.Index(tagOption, "not") != -1 {
			return true
		}
	}
	return false
}
<|endoftext|>