<commit_before>package utils

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"

	"github.com/zenoss/glog"
	docker "github.com/zenoss/go-dockerclient"
)

// connection to the docker client
var dockerClient *docker.Client

// Opens a connection to docker if not already connected
func connectDocker() (*docker.Client, error) {
	if dockerClient == nil {
		const DockerEndpoint string = "unix:///var/run/docker.sock"
		var err error
		if dockerClient, err = docker.NewClient(DockerEndpoint); err != nil {
			return nil, fmt.Errorf("could not create a client to docker: %s", err)
		}
	}
	return dockerClient, nil
}

// getPIDFromDockerID returns the pid of a docker container
func getPIDFromDockerID(containerID string) (string, error) {
	// retrieve host PID from containerID
	dockerClient, err := connectDocker()
	if err != nil {
		glog.Errorf("could not attach to docker client error:%v\n\n", err)
		return "", err
	}
	container, err := dockerClient.InspectContainer(containerID)
	if err != nil {
		glog.Errorf("could not inspect container error:%v\n\n", err)
		return "", err
	}

	pid := fmt.Sprintf("%d", container.State.Pid)
	return pid, nil
}

// ExecNSEnter execs the command using nsenter
func ExecNSEnter(containerID string, bashcmd []string) error {
	command, err := generateNSEnterCommand(containerID, bashcmd)
	if err != nil {
		return err
	}
	glog.V(1).Infof("exec command for container:%v command: %v\n", containerID, command)
	return syscall.Exec(command[0], command[0:], os.Environ())
}

// RunNSEnter runs the command using nsenter
func RunNSEnter(containerID string, bashcmd []string) ([]byte, error) {
	command, err := generateNSEnterCommand(containerID, bashcmd)
	if err != nil {
		return nil, err
	}
	thecmd := exec.Command(command[0], command[1:]...)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		glog.Errorf("Error running command:'%s' output: %s  error: %s\n", command, output, err)
		return output, err
	}
	glog.V(1).Infof("Successfully ran command:'%s' output: %s\n", command, output)
	return output, nil
}

// generateNSEnterCommand returns a slice containing nsenter command to exec
func generateNSEnterCommand(containerID string, bashcmd []string) ([]string, error) {
	if containerID == "" {
		return []string{}, fmt.Errorf("will not attach to container with empty containerID")
	}

	exeMap, err := exePaths([]string{"sudo", "nsenter"})
	if err != nil {
		return []string{}, err
	}

	pid, err := getPIDFromDockerID(containerID)
	if err != nil {
		return []string{}, err
	}

	attachCmd := []string{exeMap["sudo"], exeMap["nsenter"], "-m", "-u", "-i", "-n", "-p", "-t", pid, "--"}
	attachCmd = append(attachCmd, bashcmd...)
	glog.V(1).Infof("attach command for container:%v command: %v\n", containerID, attachCmd)
	return attachCmd, nil
}

// AttachAndRun attaches to a container and runs the command
func AttachAndRun(containerID string, bashcmd []string) ([]byte, error) {
	_, err := exec.LookPath("nsenter")
	if err != nil {
		return RunNSInitWithRetry(containerID, bashcmd)
	}

	return RunNSEnter(containerID, bashcmd)
}

// AttachAndExec attaches to a container and execs the command
func AttachAndExec(containerID string, bashcmd []string) error {
	_, err := exec.LookPath("nsenter")
	if err != nil {
		return ExecNSInitWithRetry(containerID, bashcmd)
	}

	return ExecNSEnter(containerID, bashcmd)
}<commit_msg>prepend bash -c for RunNSEnter() - leave ExecNSEnter alone<commit_after>package utils

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/zenoss/glog"
	docker "github.com/zenoss/go-dockerclient"
)

// connection to the docker client
var dockerClient *docker.Client

// Opens a connection to docker if not already connected
func connectDocker() (*docker.Client, error) {
	if dockerClient == nil {
		const DockerEndpoint string = "unix:///var/run/docker.sock"
		var err error
		if dockerClient, err = docker.NewClient(DockerEndpoint); err != nil {
			return nil, fmt.Errorf("could not create a client to docker: %s", err)
		}
	}
	return dockerClient, nil
}

// getPIDFromDockerID returns the pid of a docker container
func getPIDFromDockerID(containerID string) (string, error) {
	// retrieve host PID from containerID
	dockerClient, err := connectDocker()
	if err != nil {
		glog.Errorf("could not attach to docker client error:%v\n\n", err)
		return "", err
	}
	container, err := dockerClient.InspectContainer(containerID)
	if err != nil {
		glog.Errorf("could not inspect container error:%v\n\n", err)
		return "", err
	}

	pid := fmt.Sprintf("%d", container.State.Pid)
	return pid, nil
}

// ExecNSEnter execs the command using nsenter
func ExecNSEnter(containerID string, bashcmd []string) error {
	command, err := generateNSEnterCommand(containerID, bashcmd, false)
	if err != nil {
		return err
	}
	glog.V(1).Infof("exec command for container:%v command: %v\n", containerID, command)
	return syscall.Exec(command[0], command[0:], os.Environ())
}

// RunNSEnter runs the command using nsenter
func RunNSEnter(containerID string, bashcmd []string) ([]byte, error) {
	command, err := generateNSEnterCommand(containerID, bashcmd, true)
	if err != nil {
		return nil, err
	}
	thecmd := exec.Command(command[0], command[1:]...)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		glog.Errorf("Error running command:'%s' output: %s  error: %s\n", command, output, err)
		return output, err
	}
	glog.V(1).Infof("Successfully ran command:'%s' output: %s\n", command, output)
	return output, nil
}

// generateNSEnterCommand returns a slice containing nsenter command to exec
func generateNSEnterCommand(containerID string, bashcmd []string, prependBash bool) ([]string, error) {
	if containerID == "" {
		return []string{}, fmt.Errorf("will not attach to container with empty containerID")
	}

	exeMap, err := exePaths([]string{"sudo", "nsenter"})
	if err != nil {
		return []string{}, err
	}

	pid, err := getPIDFromDockerID(containerID)
	if err != nil {
		return []string{}, err
	}

	attachCmd := []string{exeMap["sudo"], exeMap["nsenter"], "-m", "-u", "-i", "-n", "-p", "-t", pid, "--"}
	if prependBash {
		attachCmd = append(attachCmd, "/bin/bash", "-c", fmt.Sprintf("%s", strings.Join(bashcmd, " ")))
	} else {
		attachCmd = append(attachCmd, bashcmd...)
	}
	glog.V(1).Infof("attach command for container:%v command: %v\n", containerID, attachCmd)
	return attachCmd, nil
}

// AttachAndRun attaches to a container and runs the command
func AttachAndRun(containerID string, bashcmd []string) ([]byte, error) {
	_, err := exec.LookPath("nsenter")
	if err != nil {
		return RunNSInitWithRetry(containerID, bashcmd)
	}

	return RunNSEnter(containerID, bashcmd)
}

// AttachAndExec attaches to a container and execs the command
func AttachAndExec(containerID string, bashcmd []string) error {
	_, err := exec.LookPath("nsenter")
	if err != nil {
		return ExecNSInitWithRetry(containerID, bashcmd)
	}

	return ExecNSEnter(containerID, bashcmd)
}<|endoftext|>


<commit_before>package utils

import (
  "runtime"
  "strings"
  "strconv"
)

// Get the version of go.
func GoVersion() string {
  return runtime.Version()
}

// Determine whether the version is 1.3+ to support syscall.FcntlFlock.
func IsSupportFLock() bool {
  versions := strings.Split(GoVersion()[2:], ".")

  majorVersion, _ := strconv.Atoi(versions[0])
  if (majorVersion > 1) {
    return true
  } else if (majorVersion == 1) {
    minorVersion, _ := strconv.Atoi(versions[1])
    if (minorVersion >= 3) {
      return true
    } else {
      return false
    }
  } else {
    return false
  }
}
<commit_msg>Format version.go<commit_after>package utils

import (
	"runtime"
	"strconv"
	"strings"
)

// Get the version of go.
func GoVersion() string {
	return runtime.Version()
}

// Determine whether the version is 1.3+ to support syscall.FcntlFlock.
func IsSupportFLock() bool {
	versions := strings.Split(GoVersion()[2:], ".")

	majorVersion, _ := strconv.Atoi(versions[0])
	if majorVersion > 1 {
		return true
	} else if majorVersion == 1 {
		minorVersion, _ := strconv.Atoi(versions[1])
		if minorVersion >= 3 {
			return true
		} else {
			return false
		}
	} else {
		return false
	}
}
<|endoftext|>


<commit_before>package yaml_test

import (
	"strings"
	"testing"

	"github.com/go-playground/validator/v10"
	"github.com/goccy/go-yaml"
)

func TestStructValidator(t *testing.T) {

	cases := []struct {
		TestName    string
		YAMLContent string
		ExpectedErr string
		Instance    interface{}
	}{
		{
			TestName: "Test Simple Validation",
			YAMLContent: `---
- name: john
  age: 20
- name: tom
  age: -1
- name: ken
  age: 10`,
			ExpectedErr: `[5:8] Key: 'Age' Error:Field validation for 'Age' failed on the 'gte' tag
   2 | - name: john
   3 |   age: 20
   4 | - name: tom
>  5 |   age: -1
              ^
   6 | - name: ken
   7 |   age: 10`,
			Instance: &[]struct {
				Name string `yaml:"name" validate:"required"`
				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
			}{},
		},
		{
			TestName: "Test Nested Validation Missing Internal Required",
			YAMLContent: `---
name: john
age: 10
addr:
  number: seven`,
			ExpectedErr: `[4:5] Key: 'State' Error:Field validation for 'State' failed on the 'required' tag
   1 | ---
   2 | name: john
   3 | age: 10
>  4 | addr:
           ^
   5 |   number: seven`,
			Instance: &struct {
				Name string `yaml:"name" validate:"required"`
				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
				Addr struct {
					Number string `yaml:"number" validate:"required"`
					State  string `yaml:"state" validate:"required"`
				} `yaml:"addr"`
			}{},
		},
		{
			TestName: "Test nested Validation with unknown field",
			YAMLContent: `---
name: john
age: 20
addr:
  number: seven
  state: washington
  error: error
`,
			ExpectedErr: `[7:3] unknown field "error"
   4 | addr:
   5 |   number: seven
   6 |   state: washington
>  7 |   error: error
         ^
`,
			Instance: &struct {
				Name string `yaml:"name" validate:"required"`
				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
				Addr *struct {
					Number string `yaml:"number" validate:"required"`
					State  string `yaml:"state" validate:"required"`
				} `yaml:"addr" validate:"required"`
			}{},
		},
	}

	for _, tc := range cases {
		tc := tc // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables
		t.Run(tc.TestName, func(t *testing.T) {
			validate := validator.New()
			dec := yaml.NewDecoder(
				strings.NewReader(tc.YAMLContent),
				yaml.Validator(validate),
				yaml.Strict(),
			)
			err := dec.Decode(tc.Instance)
			switch {
			case tc.ExpectedErr != "" && err == nil:
				t.Fatal("expected error")
			case tc.ExpectedErr == "" && err != nil:
				t.Fatalf("unexpected error: %v", err)
			case tc.ExpectedErr != "" && tc.ExpectedErr != err.Error():
				t.Fatalf("expected `%s` but actual `%s`", tc.ExpectedErr, err.Error())
			}
		})
	}
}
<commit_msg>Added a test case with top level required field<commit_after>package yaml_test

import (
	"strings"
	"testing"

	"github.com/go-playground/validator/v10"
	"github.com/goccy/go-yaml"
)

func TestStructValidator(t *testing.T) {

	cases := []struct {
		TestName    string
		YAMLContent string
		ExpectedErr string
		Instance    interface{}
	}{
		{
			TestName: "Test Simple Validation",
			YAMLContent: `---
- name: john
  age: 20
- name: tom
  age: -1
- name: ken
  age: 10`,
			ExpectedErr: `[5:8] Key: 'Age' Error:Field validation for 'Age' failed on the 'gte' tag
   2 | - name: john
   3 |   age: 20
   4 | - name: tom
>  5 |   age: -1
              ^
   6 | - name: ken
   7 |   age: 10`,
			Instance: &[]struct {
				Name string `yaml:"name" validate:"required"`
				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
			}{},
		},
		{
			TestName: "Test Missing Required Field",
			YAMLContent: `---
- name: john
  age: 20
- age: 10`,
			ExpectedErr: `[4:1] Key: 'Name' Error:Field validation for 'Name' failed on the 'required' tag
   1 | ---
   2 | - name: john
   3 |   age: 20
>  4 | - age: 10
       ^
`,
			Instance: &[]struct {
				Name string `yaml:"name" validate:"required"`
				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
			}{},
		},
		{
			TestName: "Test Nested Validation Missing Internal Required",
			YAMLContent: `---
name: john
age: 10
addr:
  number: seven`,
			ExpectedErr: `[4:5] Key: 'State' Error:Field validation for 'State' failed on the 'required' tag
   1 | ---
   2 | name: john
   3 | age: 10
>  4 | addr:
           ^
   5 |   number: seven`,
			Instance: &struct {
				Name string `yaml:"name" validate:"required"`
				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
				Addr struct {
					Number string `yaml:"number" validate:"required"`
					State  string `yaml:"state" validate:"required"`
				} `yaml:"addr"`
			}{},
		},
		{
			TestName: "Test nested Validation with unknown field",
			YAMLContent: `---
name: john
age: 20
addr:
  number: seven
  state: washington
  error: error
`,
			ExpectedErr: `[7:3] unknown field "error"
   4 | addr:
   5 |   number: seven
   6 |   state: washington
>  7 |   error: error
         ^
`,
			Instance: &struct {
				Name string `yaml:"name" validate:"required"`
				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
				Addr *struct {
					Number string `yaml:"number" validate:"required"`
					State  string `yaml:"state" validate:"required"`
				} `yaml:"addr" validate:"required"`
			}{},
		},
	}

	for _, tc := range cases {
		tc := tc // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables
		t.Run(tc.TestName, func(t *testing.T) {
			validate := validator.New()
			dec := yaml.NewDecoder(
				strings.NewReader(tc.YAMLContent),
				yaml.Validator(validate),
				yaml.Strict(),
			)
			err := dec.Decode(tc.Instance)
			switch {
			case tc.ExpectedErr != "" && err == nil:
				t.Fatal("expected error")
			case tc.ExpectedErr == "" && err != nil:
				t.Fatalf("unexpected error: %v", err)
			case tc.ExpectedErr != "" && tc.ExpectedErr != err.Error():
				t.Fatalf("expected `%s` but actual `%s`", tc.ExpectedErr, err.Error())
			}
		})
	}
}
<|endoftext|>


<commit_before>package luar

import (
	"container/list"
	"reflect"
	"sync"

	"github.com/yuin/gopher-lua"
)

var (
	mu        sync.Mutex
	cache     = map[reflect.Type]lua.LValue{}
	typeCache = map[reflect.Type]lua.LValue{}
)

func addMethods(L *lua.LState, value reflect.Value, tbl *lua.LTable) {
	vtype := value.Type()
	for i := 0; i < vtype.NumMethod(); i++ {
		method := vtype.Method(i)
		if method.PkgPath != "" {
			continue
		}
		fn := New(L, method.Func.Interface())
		tbl.RawSetString(method.Name, fn)
		tbl.RawSetString(getUnexportedName(method.Name), fn)
	}
}

func addFields(L *lua.LState, value reflect.Value, tbl *lua.LTable) {
	type element struct {
		Type  reflect.Type
		Index []int
	}

	queue := list.New()
	vtype := value.Type()
	queue.PushFront(element{
		Type: vtype,
	})

	for queue.Len() > 0 {
		e := queue.Back()
		elem := e.Value.(element)
		vtype := elem.Type
		if vtype.Kind() == reflect.Ptr {
			vtype = vtype.Elem()
		}
	fields:
		for i := 0; i < vtype.NumField(); i++ {
			field := vtype.Field(i)
			if field.PkgPath != "" {
				continue
			}
			var names []string
			tag := field.Tag.Get("luar")
			if tag == "-" {
				continue
			}
			if tag != "" {
				names = []string{
					tag,
				}
			} else {
				names = []string{
					field.Name,
					getUnexportedName(field.Name),
				}
			}
			for _, key := range names {
				if tbl.RawGetString(key) != lua.LNil {
					continue fields
				}
			}
			index := make([]int, len(elem.Index)+1)
			copy(index, elem.Index)
			index[len(elem.Index)] = i

			ud := L.NewUserData()
			ud.Value = index
			for _, key := range names {
				tbl.RawSetString(key, ud)
			}
			if field.Anonymous {
				index := make([]int, len(elem.Index)+1)
				copy(index, elem.Index)
				index[len(elem.Index)] = i
				queue.PushFront(element{
					Type:  field.Type,
					Index: index,
				})
			}
		}

		queue.Remove(e)
	}
}

func getMetatable(L *lua.LState, value reflect.Value) lua.LValue {
	mu.Lock()
	defer mu.Unlock()

	vtype := value.Type()
	if v := cache[vtype]; v != nil {
		return v
	}

	mt := L.NewTable()

	switch vtype.Kind() {
	case reflect.Array:
		methods := L.NewTable()
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)

		mt.RawSetString("__index", L.NewFunction(arrayIndex))
		mt.RawSetString("__len", L.NewFunction(arrayLen))
		mt.RawSetString("__eq", L.NewFunction(arrayEq))
	case reflect.Chan:
		methods := L.NewTable()
		methods.RawSetString("send", L.NewFunction(chanSend))
		methods.RawSetString("receive", L.NewFunction(chanReceive))
		methods.RawSetString("close", L.NewFunction(chanClose))
		addMethods(L, value, methods)

		mt.RawSetString("__index", methods)
		mt.RawSetString("__len", L.NewFunction(chanLen))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__eq", L.NewFunction(chanEq))
	case reflect.Map:
		methods := L.NewTable()
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)

		mt.RawSetString("__index", L.NewFunction(mapIndex))
		mt.RawSetString("__newindex", L.NewFunction(mapNewIndex))
		mt.RawSetString("__len", L.NewFunction(mapLen))
		mt.RawSetString("__call", L.NewFunction(mapCall))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__eq", L.NewFunction(mapEq))
	case reflect.Ptr:
		ptrMethods := L.NewTable()
		addMethods(L, value, ptrMethods)
		mt.RawSetString("ptr_methods", ptrMethods)
		methods := L.NewTable()
		addMethods(L, value.Elem(), methods)
		mt.RawSetString("methods", methods)
		if value.Elem().Kind() == reflect.Struct {
			fields := L.NewTable()
			addFields(L, value.Elem(), fields)
			mt.RawSetString("fields", fields)
		}

		if value.Elem().Kind() == reflect.Array {
			mt.RawSetString("__index", L.NewFunction(arrayIndex))
		} else {
			mt.RawSetString("__index", L.NewFunction(ptrIndex))
		}
		switch value.Elem().Kind() {
		case reflect.Array:
			mt.RawSetString("__newindex", L.NewFunction(arrayNewIndex))
		case reflect.Struct:
			mt.RawSetString("__newindex", L.NewFunction(structNewIndex))
		}
		mt.RawSetString("__pow", L.NewFunction(ptrPow))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__unm", L.NewFunction(ptrUnm))
		if value.Elem().Kind() == reflect.Array {
			mt.RawSetString("__len", L.NewFunction(arrayLen))
		}
		mt.RawSetString("__eq", L.NewFunction(ptrEq))
	case reflect.Slice:
		methods := L.NewTable()
		methods.RawSetString("capacity", L.NewFunction(sliceCapacity))
		methods.RawSetString("append", L.NewFunction(sliceAppend))
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)

		mt.RawSetString("__index", L.NewFunction(sliceIndex))
		mt.RawSetString("__newindex", L.NewFunction(sliceNewIndex))
		mt.RawSetString("__len", L.NewFunction(sliceLen))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__eq", L.NewFunction(sliceEq))
	case reflect.Struct:
		methods := L.NewTable()
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)
		fields := L.NewTable()
		addFields(L, value, fields)
		mt.RawSetString("fields", fields)

		mt.RawSetString("__index", L.NewFunction(structIndex))
		mt.RawSetString("__newindex", L.NewFunction(structNewIndex))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
	}

	cache[vtype] = mt
	return mt
}

func getTypeMetatable(L *lua.LState, t reflect.Type) lua.LValue {
	mu.Lock()
	defer mu.Unlock()

	if v := typeCache[t]; v != nil {
		return v
	}

	mt := L.NewTable()
	mt.RawSetString("__call", L.NewFunction(typeCall))
	mt.RawSetString("__tostring", L.NewFunction(allTostring))
	mt.RawSetString("__eq", L.NewFunction(typeEq))

	typeCache[t] = mt
	return mt
}
<commit_msg>store cached metatables with Lua state<commit_after>package luar

import (
	"container/list"
	"reflect"
	"sync"

	"github.com/yuin/gopher-lua"
)

const cacheKey = "github.com/layeh/gopher-luar"

var mu sync.Mutex

type mtCache struct {
	regular, types map[reflect.Type]lua.LValue
}

func newMTCache() *mtCache {
	return &mtCache{
		regular: make(map[reflect.Type]lua.LValue),
		types:   make(map[reflect.Type]lua.LValue),
	}
}

func getMTCache(L *lua.LState) *mtCache {
	registry, ok := L.Get(lua.RegistryIndex).(*lua.LTable)
	if !ok {
		panic("gopher-luar: corrupt lua registry")
	}
	lCache, ok := registry.RawGetString(cacheKey).(*lua.LUserData)
	if !ok {
		lCache = L.NewUserData()
		lCache.Value = newMTCache()
		registry.RawSetString(cacheKey, lCache)
	}
	cache, ok := lCache.Value.(*mtCache)
	if !ok {
		panic("gopher-luar: corrupt luar metatable cache")
	}
	return cache
}

func addMethods(L *lua.LState, value reflect.Value, tbl *lua.LTable) {
	vtype := value.Type()
	for i := 0; i < vtype.NumMethod(); i++ {
		method := vtype.Method(i)
		if method.PkgPath != "" {
			continue
		}
		fn := New(L, method.Func.Interface())
		tbl.RawSetString(method.Name, fn)
		tbl.RawSetString(getUnexportedName(method.Name), fn)
	}
}

func addFields(L *lua.LState, value reflect.Value, tbl *lua.LTable) {
	type element struct {
		Type  reflect.Type
		Index []int
	}

	queue := list.New()
	vtype := value.Type()
	queue.PushFront(element{
		Type: vtype,
	})

	for queue.Len() > 0 {
		e := queue.Back()
		elem := e.Value.(element)
		vtype := elem.Type
		if vtype.Kind() == reflect.Ptr {
			vtype = vtype.Elem()
		}
	fields:
		for i := 0; i < vtype.NumField(); i++ {
			field := vtype.Field(i)
			if field.PkgPath != "" {
				continue
			}
			var names []string
			tag := field.Tag.Get("luar")
			if tag == "-" {
				continue
			}
			if tag != "" {
				names = []string{
					tag,
				}
			} else {
				names = []string{
					field.Name,
					getUnexportedName(field.Name),
				}
			}
			for _, key := range names {
				if tbl.RawGetString(key) != lua.LNil {
					continue fields
				}
			}
			index := make([]int, len(elem.Index)+1)
			copy(index, elem.Index)
			index[len(elem.Index)] = i

			ud := L.NewUserData()
			ud.Value = index
			for _, key := range names {
				tbl.RawSetString(key, ud)
			}
			if field.Anonymous {
				index := make([]int, len(elem.Index)+1)
				copy(index, elem.Index)
				index[len(elem.Index)] = i
				queue.PushFront(element{
					Type:  field.Type,
					Index: index,
				})
			}
		}

		queue.Remove(e)
	}
}

func getMetatable(L *lua.LState, value reflect.Value) lua.LValue {
	mu.Lock()
	defer mu.Unlock()

	cache := getMTCache(L)

	vtype := value.Type()
	if v := cache.regular[vtype]; v != nil {
		return v
	}

	mt := L.NewTable()

	switch vtype.Kind() {
	case reflect.Array:
		methods := L.NewTable()
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)

		mt.RawSetString("__index", L.NewFunction(arrayIndex))
		mt.RawSetString("__len", L.NewFunction(arrayLen))
		mt.RawSetString("__eq", L.NewFunction(arrayEq))
	case reflect.Chan:
		methods := L.NewTable()
		methods.RawSetString("send", L.NewFunction(chanSend))
		methods.RawSetString("receive", L.NewFunction(chanReceive))
		methods.RawSetString("close", L.NewFunction(chanClose))
		addMethods(L, value, methods)

		mt.RawSetString("__index", methods)
		mt.RawSetString("__len", L.NewFunction(chanLen))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__eq", L.NewFunction(chanEq))
	case reflect.Map:
		methods := L.NewTable()
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)

		mt.RawSetString("__index", L.NewFunction(mapIndex))
		mt.RawSetString("__newindex", L.NewFunction(mapNewIndex))
		mt.RawSetString("__len", L.NewFunction(mapLen))
		mt.RawSetString("__call", L.NewFunction(mapCall))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__eq", L.NewFunction(mapEq))
	case reflect.Ptr:
		ptrMethods := L.NewTable()
		addMethods(L, value, ptrMethods)
		mt.RawSetString("ptr_methods", ptrMethods)
		methods := L.NewTable()
		addMethods(L, value.Elem(), methods)
		mt.RawSetString("methods", methods)
		if value.Elem().Kind() == reflect.Struct {
			fields := L.NewTable()
			addFields(L, value.Elem(), fields)
			mt.RawSetString("fields", fields)
		}

		if value.Elem().Kind() == reflect.Array {
			mt.RawSetString("__index", L.NewFunction(arrayIndex))
		} else {
			mt.RawSetString("__index", L.NewFunction(ptrIndex))
		}
		switch value.Elem().Kind() {
		case reflect.Array:
			mt.RawSetString("__newindex", L.NewFunction(arrayNewIndex))
		case reflect.Struct:
			mt.RawSetString("__newindex", L.NewFunction(structNewIndex))
		}
		mt.RawSetString("__pow", L.NewFunction(ptrPow))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__unm", L.NewFunction(ptrUnm))
		if value.Elem().Kind() == reflect.Array {
			mt.RawSetString("__len", L.NewFunction(arrayLen))
		}
		mt.RawSetString("__eq", L.NewFunction(ptrEq))
	case reflect.Slice:
		methods := L.NewTable()
		methods.RawSetString("capacity", L.NewFunction(sliceCapacity))
		methods.RawSetString("append", L.NewFunction(sliceAppend))
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)

		mt.RawSetString("__index", L.NewFunction(sliceIndex))
		mt.RawSetString("__newindex", L.NewFunction(sliceNewIndex))
		mt.RawSetString("__len", L.NewFunction(sliceLen))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
		mt.RawSetString("__eq", L.NewFunction(sliceEq))
	case reflect.Struct:
		methods := L.NewTable()
		addMethods(L, value, methods)
		mt.RawSetString("methods", methods)
		fields := L.NewTable()
		addFields(L, value, fields)
		mt.RawSetString("fields", fields)

		mt.RawSetString("__index", L.NewFunction(structIndex))
		mt.RawSetString("__newindex", L.NewFunction(structNewIndex))
		mt.RawSetString("__tostring", L.NewFunction(allTostring))
	}

	cache.regular[vtype] = mt
	return mt
}

func getTypeMetatable(L *lua.LState, t reflect.Type) lua.LValue {
	mu.Lock()
	defer mu.Unlock()

	cache := getMTCache(L)

	if v := cache.types[t]; v != nil {
		return v
	}

	mt := L.NewTable()
	mt.RawSetString("__call", L.NewFunction(typeCall))
	mt.RawSetString("__tostring", L.NewFunction(allTostring))
	mt.RawSetString("__eq", L.NewFunction(typeEq))

	cache.types[t] = mt
	return mt
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/garyburd/redigo/redis"
)

type Cache struct {
	pool *redis.Pool
}

// set records a key in cache (redis)
func (c *Cache) set(key string, value []byte) error {
	client := c.pool.Get()
	defer client.Close()

	_, err := client.Do("SET", key, value)

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to record request...")
	} else {
		log.WithFields(log.Fields{}).Info("Request recorded!")
	}
}

// getRedisPool returns thread safe Redis connection pool
func getRedisPool() *redis.Pool {

	// getting redis connection
	maxConnections := 10
	mc := os.Getenv("MaxConnections")
	if mc != "" {
		maxCons, err := strconv.Atoi(mc)
		if err != nil {
			maxConnections = 10
		} else {
			maxConnections = maxCons
		}
	}
	// getting redis client for state storing
	redisPool := redis.NewPool(func() (redis.Conn, error) {
		c, err := redis.Dial("tcp", AppConfig.redisAddress)

		if err != nil {
			log.WithFields(log.Fields{"Error": err.Error()}).Panic("Failed to create Redis connection pool!")
			return nil, err
		}
		if AppConfig.redisPassword != "" {
			if _, err := c.Do("AUTH", AppConfig.redisPassword); err != nil {
				log.WithFields(log.Fields{
					"Error":        err.Error(),
					"PasswordUsed": AppConfig.redisPassword,
				}).Panic("Failed to authenticate to Redis!")
				c.Close()
				return nil, err
			} else {
				log.Info("Authenticated to Redis successfully! ")
			}
		}

		return c, err
	}, maxConnections)

	defer redisPool.Close()

	return redisPool
}
<commit_msg>more logging<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/garyburd/redigo/redis"
)

const prefix = "genproxy:"

type Cache struct {
	pool *redis.Pool
}

// set records a key in cache (redis)
func (c *Cache) set(key string, value []byte) error {
	client := c.pool.Get()
	defer client.Close()

	_, err := client.Do("SET", fmt.Sprintf(prefix+key), value)

	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Failed to record request...")
	} else {
		log.WithFields(log.Fields{
			"key": fmt.Sprintf(prefix + key),
		}).Info("Request recorded!")
	}

	return err
}

// getRedisPool returns thread safe Redis connection pool
func getRedisPool() *redis.Pool {

	// getting redis connection
	maxConnections := 10
	mc := os.Getenv("MaxConnections")
	if mc != "" {
		maxCons, err := strconv.Atoi(mc)
		if err != nil {
			maxConnections = 10
		} else {
			maxConnections = maxCons
		}
	}
	// getting redis client for state storing
	redisPool := redis.NewPool(func() (redis.Conn, error) {
		c, err := redis.Dial("tcp", AppConfig.redisAddress)

		if err != nil {
			log.WithFields(log.Fields{"Error": err.Error()}).Panic("Failed to create Redis connection pool!")
			return nil, err
		}
		if AppConfig.redisPassword != "" {
			if _, err := c.Do("AUTH", AppConfig.redisPassword); err != nil {
				log.WithFields(log.Fields{
					"Error":        err.Error(),
					"PasswordUsed": AppConfig.redisPassword,
				}).Panic("Failed to authenticate to Redis!")
				c.Close()
				return nil, err
			} else {
				log.Info("Authenticated to Redis successfully! ")
			}
		}

		return c, err
	}, maxConnections)

	defer redisPool.Close()

	return redisPool
}
<|endoftext|>


<commit_before>package kubernetes

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/rusenask/cron"

	"k8s.io/api/core/v1"

	"github.com/prometheus/client_golang/prometheus"

	"github.com/keel-hq/keel/approvals"
	"github.com/keel-hq/keel/extension/notification"
	"github.com/keel-hq/keel/internal/k8s"
	"github.com/keel-hq/keel/internal/policy"
	"github.com/keel-hq/keel/types"
	"github.com/keel-hq/keel/util/image"
	"github.com/keel-hq/keel/util/policies"

	log "github.com/sirupsen/logrus"
)

var kubernetesVersionedUpdatesCounter = prometheus.NewCounterVec(
	prometheus.CounterOpts{
		Name: "kubernetes_versioned_updates_total",
		Help: "How many versioned deployments were updated, partitioned by deployment name.",
	},
	[]string{"kubernetes"},
)

var kubernetesUnversionedUpdatesCounter = prometheus.NewCounterVec(
	prometheus.CounterOpts{
		Name: "kubernetes_unversioned_updates_total",
		Help: "How many unversioned deployments were updated, partitioned by deployment name.",
	},
	[]string{"kubernetes"},
)

func init() {
	prometheus.MustRegister(kubernetesVersionedUpdatesCounter)
	prometheus.MustRegister(kubernetesUnversionedUpdatesCounter)
}

// ProviderName - provider name
const ProviderName = "kubernetes"

var versionreg = regexp.MustCompile(`:[^:]*$`)

// GenericResourceCache an interface for generic resource cache.
type GenericResourceCache interface {
	// Values returns a copy of the contents of the cache.
	// The slice and its contents should be treated as read-only.
	Values() []*k8s.GenericResource

	// Register registers ch to receive a value when Notify is called.
	Register(chan int, int)
}

// UpdatePlan - deployment update plan
type UpdatePlan struct {
	// Updated deployment version
	// Deployment v1beta1.Deployment
	Resource *k8s.GenericResource

	// Current (last seen cluster version)
	CurrentVersion string
	// New version that's already in the deployment
	NewVersion string
}

func (p *UpdatePlan) String() string {
	if p.Resource != nil {
		return fmt.Sprintf("%s %s->%s", p.Resource.Identifier, p.CurrentVersion, p.NewVersion)
	}
	return "empty plan"
}

// Provider - kubernetes provider for auto update
type Provider struct {
	implementer Implementer

	sender notification.Sender

	approvalManager approvals.Manager

	cache GenericResourceCache

	events chan *types.Event
	stop   chan struct{}
}

// NewProvider - create new kubernetes based provider
func NewProvider(implementer Implementer, sender notification.Sender, approvalManager approvals.Manager, cache GenericResourceCache) (*Provider, error) {
	return &Provider{
		implementer:     implementer,
		cache:           cache,
		approvalManager: approvalManager,
		events:          make(chan *types.Event, 100),
		stop:            make(chan struct{}),
		sender:          sender,
	}, nil
}

// Submit - submit event to provider
func (p *Provider) Submit(event types.Event) error {
	p.events <- &event
	return nil
}

// GetName - get provider name
func (p *Provider) GetName() string {
	return ProviderName
}

// Start - starts kubernetes provider, waits for events
func (p *Provider) Start() error {
	return p.startInternal()
}

// Stop - stops kubernetes provider
func (p *Provider) Stop() {
	close(p.stop)
}

// TrackedImages returns a list of tracked images.
func (p *Provider) TrackedImages() ([]*types.TrackedImage, error) {
	var trackedImages []*types.TrackedImage

	for _, gr := range p.cache.Values() {
		labels := gr.GetLabels()
		annotations := gr.GetAnnotations()

		// ignoring unlabelled deployments
		plc := policy.GetPolicyFromLabelsOrAnnotations(labels, annotations)
		if plc.Type() == policy.PolicyTypeNone {
			continue
		}

		schedule, ok := annotations[types.KeelPollScheduleAnnotation]
		if ok {
			_, err := cron.Parse(schedule)
			if err != nil {
				log.WithFields(log.Fields{
					"error":     err,
					"schedule":  schedule,
					"name":      gr.Name,
					"namespace": gr.Namespace,
				}).Error("provider.kubernetes: failed to parse poll schedule, setting default schedule")
				schedule = types.KeelPollDefaultSchedule
			}
		} else {
			schedule = types.KeelPollDefaultSchedule
		}

		// trigger type, we only care for "poll" type triggers
		trigger := policies.GetTriggerPolicy(labels, annotations)
		secrets := gr.GetImagePullSecrets()
		images := gr.GetImages()
		for _, img := range images {
			ref, err := image.Parse(img)
			if err != nil {
				log.WithFields(log.Fields{
					"error":     err,
					"image":     img,
					"namespace": gr.Namespace,
					"name":      gr.Name,
				}).Error("provider.kubernetes: failed to parse image")
				continue
			}
			trackedImages = append(trackedImages, &types.TrackedImage{
				Image:                ref,
				PollSchedule:         schedule,
				Trigger:              trigger,
				Provider:             ProviderName,
				Namespace:            gr.Namespace,
				Secrets:              secrets,
				Meta:                 make(map[string]string),
				SemverPreReleaseTags: make(map[string]string),
			})
		}
	}

	return trackedImages, nil
}

func (p *Provider) startInternal() error {
	for {
		select {
		case event := <-p.events:
			log.WithFields(log.Fields{
				"repository": event.Repository.Name,
				"tag":        event.Repository.Tag,
				"registry":   event.Repository.Host,
			}).Info("provider.kubernetes: processing event")
			_, err := p.processEvent(event)
			if err != nil {
				log.WithFields(log.Fields{
					"error": err,
					"image": event.Repository.Name,
					"tag":   event.Repository.Tag,
				}).Error("provider.kubernetes: failed to process event")
			}
		case <-p.stop:
			log.Info("provider.kubernetes: got shutdown signal, stopping...")
			return nil
		}
	}
}

func (p *Provider) processEvent(event *types.Event) (updated []*k8s.GenericResource, err error) {
	plans, err := p.createUpdatePlans(&event.Repository)
	if err != nil {
		return nil, err
	}

	if len(plans) == 0 {
		log.WithFields(log.Fields{
			"image": event.Repository.Name,
			"tag":   event.Repository.Tag,
		}).Info("provider.kubernetes: no plans for deployment updates found for this event")
		return
	}

	approvedPlans := p.checkForApprovals(event, plans)

	return p.updateDeployments(approvedPlans)
}

func (p *Provider) updateDeployments(plans []*UpdatePlan) (updated []*k8s.GenericResource, err error) {
	for _, plan := range plans {
		resource := plan.Resource

		annotations := resource.GetAnnotations()

		notificationChannels := types.ParseEventNotificationChannels(annotations)

		p.sender.Send(types.EventNotification{
			Name:      "preparing to update resource",
			Message:   fmt.Sprintf("Preparing to update %s %s/%s %s->%s (%s)", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, strings.Join(resource.GetImages(), ", ")),
			CreatedAt: time.Now(),
			Type:      types.NotificationPreDeploymentUpdate,
			Level:     types.LevelDebug,
			Channels:  notificationChannels,
		})

		var err error

		timestamp := time.Now().Format(time.RFC3339)
		annotations["kubernetes.io/change-cause"] = fmt.Sprintf("keel automated update, version %s -> %s [%s]", plan.CurrentVersion, plan.NewVersion, timestamp)

		resource.SetAnnotations(annotations)

		err = p.implementer.Update(resource)
		kubernetesVersionedUpdatesCounter.With(prometheus.Labels{"kubernetes": fmt.Sprintf("%s/%s", resource.Namespace, resource.Name)}).Inc()
		if err != nil {
			log.WithFields(log.Fields{
				"error":      err,
				"namespace":  resource.Namespace,
				"deployment": resource.Name,
				"kind":       resource.Kind(),
				"update":     fmt.Sprintf("%s->%s", plan.CurrentVersion, plan.NewVersion),
			}).Error("provider.kubernetes: got error while updating resource")

			p.sender.Send(types.EventNotification{
				Name:      "update resource",
				Message:   fmt.Sprintf("%s %s/%s update %s->%s failed, error: %s", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, err),
				CreatedAt: time.Now(),
				Type:      types.NotificationDeploymentUpdate,
				Level:     types.LevelError,
				Channels:  notificationChannels,
			})

			continue
		}

		err = p.updateComplete(plan)
		if err != nil {
			log.WithFields(log.Fields{
				"error":     err,
				"name":      resource.Name,
				"kind":      resource.Kind(),
				"namespace": resource.Namespace,
			}).Warn("provider.kubernetes: got error while resetting approvals counter after successful update")
		}

		var msg string
		releaseNotes := types.ParseReleaseNotesURL(resource.GetAnnotations())
		if releaseNotes != "" {
			msg = fmt.Sprintf("Successfully updated %s %s/%s %s->%s (%s). Release notes: %s", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, strings.Join(resource.GetImages(), ", "), releaseNotes)
		} else {
			msg = fmt.Sprintf("Successfully updated %s %s/%s %s->%s (%s)", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, strings.Join(resource.GetImages(), ", "))
		}

		p.sender.Send(types.EventNotification{
			Name:      "update resource",
			Message:   msg,
			CreatedAt: time.Now(),
			Type:      types.NotificationDeploymentUpdate,
			Level:     types.LevelSuccess,
			Channels:  notificationChannels,
		})

		log.WithFields(log.Fields{
			"name":      resource.Name,
			"kind":      resource.Kind(),
			"previous":  plan.CurrentVersion,
			"new":       plan.NewVersion,
			"namespace": resource.Namespace,
		}).Info("provider.kubernetes: resource updated")
		updated = append(updated, resource)
	}

	return
}

func getDesiredImage(delta map[string]string, currentImage string) (string, error) {
	currentRef, err := image.Parse(currentImage)
	if err != nil {
		return "", err
	}
	for repository, tag := range delta {
		if repository == currentRef.Repository() {
			ref, err := image.Parse(repository)
			if err != nil {
				return "", err
			}

			// updating image
			if ref.Registry() == image.DefaultRegistryHostname {
				return fmt.Sprintf("%s:%s", ref.ShortName(), tag), nil
			}
			return fmt.Sprintf("%s:%s", ref.Repository(), tag), nil
		}
	}
	return "", fmt.Errorf("image %s not found in deltas", currentImage)
}

// createUpdatePlans - impacted deployments by changed repository
func (p *Provider) createUpdatePlans(repo *types.Repository) ([]*UpdatePlan, error) {
	impacted := []*UpdatePlan{}

	for _, resource := range p.cache.Values() {

		labels := resource.GetLabels()
		annotations := resource.GetAnnotations()

		plc := policy.GetPolicyFromLabelsOrAnnotations(labels, annotations)
		if plc.Type() == policy.PolicyTypeNone {
			log.Debugf("no policy defined, skipping: %s, labels: %s, annotations: %s", resource.Identifier, labels, annotations)
			continue
		}

		updated, shouldUpdateDeployment, err := checkForUpdate(plc, repo, resource)
		if err != nil {
			log.WithFields(log.Fields{
				"error":      err,
				"deployment": resource.Name,
				"kind":       resource.Kind(),
				"namespace":  resource.Namespace,
			}).Error("provider.kubernetes: got error while checking versioned resource")
			continue
		}

		if shouldUpdateDeployment {
			impacted = append(impacted, updated)
		}
	}

	return impacted, nil
}

func (p *Provider) namespaces() (*v1.NamespaceList, error) {
	return p.implementer.Namespaces()
}
<commit_msg>including pre-releases<commit_after>package kubernetes

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/Masterminds/semver"
	"github.com/rusenask/cron"

	"k8s.io/api/core/v1"

	"github.com/prometheus/client_golang/prometheus"

	"github.com/keel-hq/keel/approvals"
	"github.com/keel-hq/keel/extension/notification"
	"github.com/keel-hq/keel/internal/k8s"
	"github.com/keel-hq/keel/internal/policy"
	"github.com/keel-hq/keel/types"
	"github.com/keel-hq/keel/util/image"
	"github.com/keel-hq/keel/util/policies"

	log "github.com/sirupsen/logrus"
)

var kubernetesVersionedUpdatesCounter = prometheus.NewCounterVec(
	prometheus.CounterOpts{
		Name: "kubernetes_versioned_updates_total",
		Help: "How many versioned deployments were updated, partitioned by deployment name.",
	},
	[]string{"kubernetes"},
)

var kubernetesUnversionedUpdatesCounter = prometheus.NewCounterVec(
	prometheus.CounterOpts{
		Name: "kubernetes_unversioned_updates_total",
		Help: "How many unversioned deployments were updated, partitioned by deployment name.",
	},
	[]string{"kubernetes"},
)

func init() {
	prometheus.MustRegister(kubernetesVersionedUpdatesCounter)
	prometheus.MustRegister(kubernetesUnversionedUpdatesCounter)
}

// ProviderName - provider name
const ProviderName = "kubernetes"

var versionreg = regexp.MustCompile(`:[^:]*$`)

// GenericResourceCache an interface for generic resource cache.
type GenericResourceCache interface {
	// Values returns a copy of the contents of the cache.
	// The slice and its contents should be treated as read-only.
	Values() []*k8s.GenericResource

	// Register registers ch to receive a value when Notify is called.
	Register(chan int, int)
}

// UpdatePlan - deployment update plan
type UpdatePlan struct {
	// Updated deployment version
	// Deployment v1beta1.Deployment
	Resource *k8s.GenericResource

	// Current (last seen cluster version)
	CurrentVersion string
	// New version that's already in the deployment
	NewVersion string
}

func (p *UpdatePlan) String() string {
	if p.Resource != nil {
		return fmt.Sprintf("%s %s->%s", p.Resource.Identifier, p.CurrentVersion, p.NewVersion)
	}
	return "empty plan"
}

// Provider - kubernetes provider for auto update
type Provider struct {
	implementer Implementer

	sender notification.Sender

	approvalManager approvals.Manager

	cache GenericResourceCache

	events chan *types.Event
	stop   chan struct{}
}

// NewProvider - create new kubernetes based provider
func NewProvider(implementer Implementer, sender notification.Sender, approvalManager approvals.Manager, cache GenericResourceCache) (*Provider, error) {
	return &Provider{
		implementer:     implementer,
		cache:           cache,
		approvalManager: approvalManager,
		events:          make(chan *types.Event, 100),
		stop:            make(chan struct{}),
		sender:          sender,
	}, nil
}

// Submit - submit event to provider
func (p *Provider) Submit(event types.Event) error {
	p.events <- &event
	return nil
}

// GetName - get provider name
func (p *Provider) GetName() string {
	return ProviderName
}

// Start - starts kubernetes provider, waits for events
func (p *Provider) Start() error {
	return p.startInternal()
}

// Stop - stops kubernetes provider
func (p *Provider) Stop() {
	close(p.stop)
}

// TrackedImages returns a list of tracked images.
func (p *Provider) TrackedImages() ([]*types.TrackedImage, error) {
	var trackedImages []*types.TrackedImage

	for _, gr := range p.cache.Values() {
		labels := gr.GetLabels()
		annotations := gr.GetAnnotations()

		// ignoring unlabelled deployments
		plc := policy.GetPolicyFromLabelsOrAnnotations(labels, annotations)
		if plc.Type() == policy.PolicyTypeNone {
			continue
		}

		schedule, ok := annotations[types.KeelPollScheduleAnnotation]
		if ok {
			_, err := cron.Parse(schedule)
			if err != nil {
				log.WithFields(log.Fields{
					"error":     err,
					"schedule":  schedule,
					"name":      gr.Name,
					"namespace": gr.Namespace,
				}).Error("provider.kubernetes: failed to parse poll schedule, setting default schedule")
				schedule = types.KeelPollDefaultSchedule
			}
		} else {
			schedule = types.KeelPollDefaultSchedule
		}

		// trigger type, we only care for "poll" type triggers
		trigger := policies.GetTriggerPolicy(labels, annotations)
		secrets := gr.GetImagePullSecrets()
		images := gr.GetImages()
		for _, img := range images {
			ref, err := image.Parse(img)
			if err != nil {
				log.WithFields(log.Fields{
					"error":     err,
					"image":     img,
					"namespace": gr.Namespace,
					"name":      gr.Name,
				}).Error("provider.kubernetes: failed to parse image")
				continue
			}
			svp := make(map[string]string)

			semverTag, err := semver.NewVersion(ref.Tag())
			if err == nil {
				if semverTag.Prerelease() != "" {
					svp[semverTag.Prerelease()] = ref.Tag()
				}
			}

			trackedImages = append(trackedImages, &types.TrackedImage{
				Image:                ref,
				PollSchedule:         schedule,
				Trigger:              trigger,
				Provider:             ProviderName,
				Namespace:            gr.Namespace,
				Secrets:              secrets,
				Meta:                 make(map[string]string),
				SemverPreReleaseTags: svp,
			})
		}
	}

	return trackedImages, nil
}

func (p *Provider) startInternal() error {
	for {
		select {
		case event := <-p.events:
			log.WithFields(log.Fields{
				"repository": event.Repository.Name,
				"tag":        event.Repository.Tag,
				"registry":   event.Repository.Host,
			}).Info("provider.kubernetes: processing event")
			_, err := p.processEvent(event)
			if err != nil {
				log.WithFields(log.Fields{
					"error": err,
					"image": event.Repository.Name,
					"tag":   event.Repository.Tag,
				}).Error("provider.kubernetes: failed to process event")
			}
		case <-p.stop:
			log.Info("provider.kubernetes: got shutdown signal, stopping...")
			return nil
		}
	}
}

func (p *Provider) processEvent(event *types.Event) (updated []*k8s.GenericResource, err error) {
	plans, err := p.createUpdatePlans(&event.Repository)
	if err != nil {
		return nil, err
	}

	if len(plans) == 0 {
		log.WithFields(log.Fields{
			"image": event.Repository.Name,
			"tag":   event.Repository.Tag,
		}).Info("provider.kubernetes: no plans for deployment updates found for this event")
		return
	}

	approvedPlans := p.checkForApprovals(event, plans)

	return p.updateDeployments(approvedPlans)
}

func (p *Provider) updateDeployments(plans []*UpdatePlan) (updated []*k8s.GenericResource, err error) {
	for _, plan := range plans {
		resource := plan.Resource

		annotations := resource.GetAnnotations()

		notificationChannels := types.ParseEventNotificationChannels(annotations)

		p.sender.Send(types.EventNotification{
			Name:      "preparing to update resource",
			Message:   fmt.Sprintf("Preparing to update %s %s/%s %s->%s (%s)", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, strings.Join(resource.GetImages(), ", ")),
			CreatedAt: time.Now(),
			Type:      types.NotificationPreDeploymentUpdate,
			Level:     types.LevelDebug,
			Channels:  notificationChannels,
		})

		var err error

		timestamp := time.Now().Format(time.RFC3339)
		annotations["kubernetes.io/change-cause"] = fmt.Sprintf("keel automated update, version %s -> %s [%s]", plan.CurrentVersion, plan.NewVersion, timestamp)

		resource.SetAnnotations(annotations)

		err = p.implementer.Update(resource)
		kubernetesVersionedUpdatesCounter.With(prometheus.Labels{"kubernetes": fmt.Sprintf("%s/%s", resource.Namespace, resource.Name)}).Inc()
		if err != nil {
			log.WithFields(log.Fields{
				"error":      err,
				"namespace":  resource.Namespace,
				"deployment": resource.Name,
				"kind":       resource.Kind(),
				"update":     fmt.Sprintf("%s->%s", plan.CurrentVersion, plan.NewVersion),
			}).Error("provider.kubernetes: got error while updating resource")

			p.sender.Send(types.EventNotification{
				Name:      "update resource",
				Message:   fmt.Sprintf("%s %s/%s update %s->%s failed, error: %s", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, err),
				CreatedAt: time.Now(),
				Type:      types.NotificationDeploymentUpdate,
				Level:     types.LevelError,
				Channels:  notificationChannels,
			})

			continue
		}

		err = p.updateComplete(plan)
		if err != nil {
			log.WithFields(log.Fields{
				"error":     err,
				"name":      resource.Name,
				"kind":      resource.Kind(),
				"namespace": resource.Namespace,
			}).Warn("provider.kubernetes: got error while resetting approvals counter after successful update")
		}

		var msg string
		releaseNotes := types.ParseReleaseNotesURL(resource.GetAnnotations())
		if releaseNotes != "" {
			msg = fmt.Sprintf("Successfully updated %s %s/%s %s->%s (%s). Release notes: %s", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, strings.Join(resource.GetImages(), ", "), releaseNotes)
		} else {
			msg = fmt.Sprintf("Successfully updated %s %s/%s %s->%s (%s)", resource.Kind(), resource.Namespace, resource.Name, plan.CurrentVersion, plan.NewVersion, strings.Join(resource.GetImages(), ", "))
		}

		p.sender.Send(types.EventNotification{
			Name:      "update resource",
			Message:   msg,
			CreatedAt: time.Now(),
			Type:      types.NotificationDeploymentUpdate,
			Level:     types.LevelSuccess,
			Channels:  notificationChannels,
		})

		log.WithFields(log.Fields{
			"name":      resource.Name,
			"kind":      resource.Kind(),
			"previous":  plan.CurrentVersion,
			"new":       plan.NewVersion,
			"namespace": resource.Namespace,
		}).Info("provider.kubernetes: resource updated")
		updated = append(updated, resource)
	}

	return
}

func getDesiredImage(delta map[string]string, currentImage string) (string, error) {
	currentRef, err := image.Parse(currentImage)
	if err != nil {
		return "", err
	}
	for repository, tag := range delta {
		if repository == currentRef.Repository() {
			ref, err := image.Parse(repository)
			if err != nil {
				return "", err
			}

			// updating image
			if ref.Registry() == image.DefaultRegistryHostname {
				return fmt.Sprintf("%s:%s", ref.ShortName(), tag), nil
			}
			return fmt.Sprintf("%s:%s", ref.Repository(), tag), nil
		}
	}
	return "", fmt.Errorf("image %s not found in deltas", currentImage)
}

// createUpdatePlans - impacted deployments by changed repository
func (p *Provider) createUpdatePlans(repo *types.Repository) ([]*UpdatePlan, error) {
	impacted := []*UpdatePlan{}

	for _, resource := range p.cache.Values() {

		labels := resource.GetLabels()
		annotations := resource.GetAnnotations()

		plc := policy.GetPolicyFromLabelsOrAnnotations(labels, annotations)
		if plc.Type() == policy.PolicyTypeNone {
			log.Debugf("no policy defined, skipping: %s, labels: %s, annotations: %s", resource.Identifier, labels, annotations)
			continue
		}

		updated, shouldUpdateDeployment, err := checkForUpdate(plc, repo, resource)
		if err != nil {
			log.WithFields(log.Fields{
				"error":      err,
				"deployment": resource.Name,
				"kind":       resource.Kind(),
				"namespace":  resource.Namespace,
			}).Error("provider.kubernetes: got error while checking versioned resource")
			continue
		}

		if shouldUpdateDeployment {
			impacted = append(impacted, updated)
		}
	}

	return impacted, nil
}

func (p *Provider) namespaces() (*v1.NamespaceList, error) {
	return p.implementer.Namespaces()
}
<|endoftext|>


<commit_before>// Copyright 2017-2018 Authors of Cilium
//
// 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 test

import (
	"errors"
	"io"
	"net"
	"os"
	"path/filepath"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/cilium/cilium/pkg/inctimer"
	cilium "github.com/cilium/proxy/go/cilium/api"

	"github.com/golang/protobuf/proto"
	log "github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

type AccessLogServer struct {
	Path     string
	Logs     chan cilium.EntryType
	closing  uint32 // non-zero if closing, accessed atomically
	listener *net.UnixListener
	conns    []*net.UnixConn
}

// Close removes the unix domain socket from the filesystem
func (s *AccessLogServer) Close() {
	if s != nil {
		atomic.StoreUint32(&s.closing, 1)
		s.listener.Close()
		for _, conn := range s.conns {
			conn.Close()
		}
		os.Remove(s.Path)
	}
}

// Clear empties the access log server buffer, counting the passes and drops
func (s *AccessLogServer) Clear() (passed, drops int) {
	passes, drops := 0, 0
	empty := false
	for !empty {
		select {
		case entryType := <-s.Logs:
			if entryType == cilium.EntryType_Denied {
				drops++
			} else {
				passes++
			}
		case <-inctimer.After(10 * time.Millisecond):
			empty = true
		}
	}
	return passes, drops
}

// StartAccessLogServer starts the access log server.
func StartAccessLogServer(accessLogName string, bufSize int) *AccessLogServer {
	accessLogPath := filepath.Join(Tmpdir, accessLogName)

	server := &AccessLogServer{
		Path: accessLogPath,
		Logs: make(chan cilium.EntryType, bufSize),
	}

	// Create the access log listener
	os.Remove(accessLogPath) // Remove/Unlink the old unix domain socket, if any.
	var err error
	server.listener, err = net.ListenUnix("unixpacket", &net.UnixAddr{Name: accessLogPath, Net: "unixpacket"})
	if err != nil {
		log.Fatalf("Failed to open access log listen socket at %s: %v", accessLogPath, err)
	}
	server.listener.SetUnlinkOnClose(true)

	// Make the socket accessible by non-root Envoy proxies, e.g. running in
	// sidecar containers.
	if err = os.Chmod(accessLogPath, 0777); err != nil {
		log.Fatalf("Failed to change mode of access log listen socket at %s: %v", accessLogPath, err)
	}

	log.Debug("Starting Access Log Server")
	go func() {
		for {
			// Each Envoy listener opens a new connection over the Unix domain socket.
			// Multiple worker threads serving the listener share that same connection
			uc, err := server.listener.AcceptUnix()
			if err != nil {
				// These errors are expected when we are closing down
				if atomic.LoadUint32(&server.closing) != 0 ||
					errors.Is(err, net.ErrClosed) ||
					errors.Is(err, syscall.EINVAL) {
					break
				}
				log.WithError(err).Warn("Failed to accept access log connection")
				continue
			}
			log.Debug("Accepted access log connection")

			server.conns = append(server.conns, uc)
			// Serve this access log socket in a goroutine, so we can serve multiple
			// connections concurrently.
			go server.accessLogger(uc)
		}
	}()

	return server
}

// isEOF returns true if the error message ends in "EOF". ReadMsgUnix returns extra info in the beginning.
func isEOF(err error) bool {
	strerr := err.Error()
	errlen := len(strerr)
	return errlen >= 3 && strerr[errlen-3:] == io.EOF.Error()
}

func (s *AccessLogServer) accessLogger(conn *net.UnixConn) {
	defer func() {
		log.Debug("Closing access log connection")
		conn.Close()
	}()

	buf := make([]byte, 4096)
	for {
		n, _, flags, _, err := conn.ReadMsgUnix(buf, nil)
		if err != nil {
			if !isEOF(err) && atomic.LoadUint32(&s.closing) == 0 {
				log.WithError(err).Error("Error while reading from access log connection")
			}
			break
		}
		if flags&unix.MSG_TRUNC != 0 {
			log.Warning("Discarded truncated access log message")
			continue
		}
		pblog := cilium.LogEntry{}
		err = proto.Unmarshal(buf[:n], &pblog)
		if err != nil {
			log.WithError(err).Warning("Discarded invalid access log message")
			continue
		}

		log.Debugf("Access log message: %s", pblog.String())
		s.Logs <- pblog.EntryType
	}
}
<commit_msg>proxylib/test: fix data race between StartAccessLogServer and Close<commit_after>// Copyright 2017-2018 Authors of Cilium
//
// 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 test

import (
	"errors"
	"io"
	"net"
	"os"
	"path/filepath"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/cilium/cilium/pkg/inctimer"
	cilium "github.com/cilium/proxy/go/cilium/api"

	"github.com/golang/protobuf/proto"
	log "github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

type AccessLogServer struct {
	Path     string
	Logs     chan cilium.EntryType
	closing  uint32 // non-zero if closing, accessed atomically
	listener *net.UnixListener
	conns    []*net.UnixConn
}

// Close removes the unix domain socket from the filesystem
func (s *AccessLogServer) Close() {
	if s != nil {
		atomic.StoreUint32(&s.closing, 1)
		s.listener.Close()
		for _, conn := range s.conns {
			conn.Close()
		}
		os.Remove(s.Path)
	}
}

// Clear empties the access log server buffer, counting the passes and drops
func (s *AccessLogServer) Clear() (passed, drops int) {
	passes, drops := 0, 0
	empty := false
	for !empty {
		select {
		case entryType := <-s.Logs:
			if entryType == cilium.EntryType_Denied {
				drops++
			} else {
				passes++
			}
		case <-inctimer.After(10 * time.Millisecond):
			empty = true
		}
	}
	return passes, drops
}

// StartAccessLogServer starts the access log server.
func StartAccessLogServer(accessLogName string, bufSize int) *AccessLogServer {
	accessLogPath := filepath.Join(Tmpdir, accessLogName)

	server := &AccessLogServer{
		Path: accessLogPath,
		Logs: make(chan cilium.EntryType, bufSize),
	}

	// Create the access log listener
	os.Remove(accessLogPath) // Remove/Unlink the old unix domain socket, if any.
	var err error
	server.listener, err = net.ListenUnix("unixpacket", &net.UnixAddr{Name: accessLogPath, Net: "unixpacket"})
	if err != nil {
		log.Fatalf("Failed to open access log listen socket at %s: %v", accessLogPath, err)
	}
	server.listener.SetUnlinkOnClose(true)

	// Make the socket accessible by non-root Envoy proxies, e.g. running in
	// sidecar containers.
	if err = os.Chmod(accessLogPath, 0777); err != nil {
		log.Fatalf("Failed to change mode of access log listen socket at %s: %v", accessLogPath, err)
	}

	log.Debug("Starting Access Log Server")
	go func() {
		for {
			// Each Envoy listener opens a new connection over the Unix domain socket.
			// Multiple worker threads serving the listener share that same connection
			uc, err := server.listener.AcceptUnix()
			if err != nil {
				// These errors are expected when we are closing down
				if atomic.LoadUint32(&server.closing) != 0 ||
					errors.Is(err, net.ErrClosed) ||
					errors.Is(err, syscall.EINVAL) {
					break
				}
				log.WithError(err).Warn("Failed to accept access log connection")
				continue
			}

			if atomic.LoadUint32(&server.closing) != 0 {
				break
			}

			log.Debug("Accepted access log connection")

			server.conns = append(server.conns, uc)
			// Serve this access log socket in a goroutine, so we can serve multiple
			// connections concurrently.
			go server.accessLogger(uc)
		}
	}()

	return server
}

// isEOF returns true if the error message ends in "EOF". ReadMsgUnix returns extra info in the beginning.
func isEOF(err error) bool {
	strerr := err.Error()
	errlen := len(strerr)
	return errlen >= 3 && strerr[errlen-3:] == io.EOF.Error()
}

func (s *AccessLogServer) accessLogger(conn *net.UnixConn) {
	defer func() {
		log.Debug("Closing access log connection")
		conn.Close()
	}()

	buf := make([]byte, 4096)
	for {
		n, _, flags, _, err := conn.ReadMsgUnix(buf, nil)
		if err != nil {
			if !isEOF(err) && atomic.LoadUint32(&s.closing) == 0 {
				log.WithError(err).Error("Error while reading from access log connection")
			}
			break
		}
		if flags&unix.MSG_TRUNC != 0 {
			log.Warning("Discarded truncated access log message")
			continue
		}
		pblog := cilium.LogEntry{}
		err = proto.Unmarshal(buf[:n], &pblog)
		if err != nil {
			log.WithError(err).Warning("Discarded invalid access log message")
			continue
		}

		log.Debugf("Access log message: %s", pblog.String())
		s.Logs <- pblog.EntryType
	}
}
<|endoftext|>


<commit_before>package main

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

	"github.com/couchbaselabs/cbfs/client"
	"github.com/couchbaselabs/cbfs/tools"
	"github.com/dustin/httputil"
)

type findType int

const (
	findTypeAny = findType(iota)
	findTypeFile
	findTypeDir
)

var findFlags = flag.NewFlagSet("find", flag.ExitOnError)
var findTemplate = findFlags.String("t", "", "Display template")
var findTemplateFile = findFlags.String("T", "", "Display template filename")
var findDashName = findFlags.String("name", "", "Glob name to match")
var findDashIName = findFlags.String("iname", "",
	"Case insensitive glob name to match")
var findDashMTime = findFlags.Duration("mtime", 0, "Find by mod time")

var findDashType findType

const defaultFindTemplate = `{{.Name}}
`

func (t findType) String() string {
	switch t {
	case findTypeAny:
		return ""
	case findTypeFile:
		return "f"
	case findTypeDir:
		return "d"
	}
	panic("unreachable")
}

func (t *findType) Set(s string) error {
	switch s {
	case "":
		*t = findTypeAny
	case "f":
		*t = findTypeFile
	case "d":
		*t = findTypeDir
	default:
		return fmt.Errorf("must be 'f' or 'd'")
	}
	return nil
}

func init() {
	findFlags.Var(&findDashType, "type", "Type to match (f or d)")
}

type dirAndFileMatcher struct {
	m map[string]struct{}
	p string
	i bool // if true, case insensitive
}

func newDirAndFileMatcher() dirAndFileMatcher {
	rv := dirAndFileMatcher{map[string]struct{}{}, *findDashName, false}
	if *findDashIName != "" {
		rv.i = true
		rv.p = strings.ToLower(*findDashIName)
	}

	return rv
}

type findMatch struct {
	path  string
	isDir bool
}

func (d dirAndFileMatcher) match(name string, isdir bool) bool {
	switch findDashType {
	case findTypeAny:
	case findTypeFile:
		if isdir {
			return false
		}
	case findTypeDir:
		if !isdir {
			return false
		}
	}
	m := name
	if d.i {
		m = strings.ToLower(m)
	}
	matched, err := filepath.Match(d.p, m)
	if err != nil {
		log.Fatalf("Error globbing: %v", err)
	}
	return matched
}

func (d dirAndFileMatcher) matches(name string) []findMatch {
	if d.p == "" {
		return []findMatch{{name, false}}
	}
	var matches []findMatch

	dir := filepath.Dir(name)
	for dir != "." {
		if _, seen := d.m[dir]; !seen {
			d.m[dir] = struct{}{}
			if d.match(filepath.Base(dir), true) {
				matches = append(matches, findMatch{dir, true})
			}
		}
		dir = filepath.Dir(dir)
	}
	// Reverse these so the traversal order makes sense
	for i := 0; i < len(matches)/2; i++ {
		j := len(matches) - i - 1
		matches[i], matches[j] = matches[j], matches[i]
	}

	if d.match(filepath.Base(name), false) {
		matches = append(matches, findMatch{name, false})
	}
	return matches
}

func findMetaMatch(ref func(time.Time) bool, c cbfsclient.FileMeta) bool {
	return true
}

func findGetRefTimeMatch(now time.Time) func(time.Time) bool {
	switch {
	case *findDashMTime > 0:
		return now.Add(-*findDashMTime).Before
	case *findDashMTime < 0:
		return now.Add(*findDashMTime).After
	}
	return func(time.Time) bool { return true }
}

func findCommand(u string, args []string) {
	if *findDashName != "" && *findDashIName != "" {
		log.Fatalf("Can't specify both -name and -iname")
	}
	src := findFlags.Arg(0)
	for src[len(src)-1] == '/' {
		src = src[:len(src)-1]
	}

	tmpl := cbfstool.GetTemplate(*findTemplate, *findTemplateFile,
		defaultFindTemplate)

	httputil.InitHTTPTracker(false)

	client, err := cbfsclient.New(u)
	cbfstool.MaybeFatal(err, "Can't build a client: %v", err)

	things, err := client.ListDepth(src, 4096)
	cbfstool.MaybeFatal(err, "Can't list things: %v", err)

	metaMatcher := findGetRefTimeMatch(time.Now())
	matcher := newDirAndFileMatcher()
	for fn, inf := range things.Files {
		if !metaMatcher(inf.Modified) {
			continue
		}
		fn = fn[len(src)+1:]
		for _, match := range matcher.matches(fn) {
			if err := tmpl.Execute(os.Stdout, struct {
				Name  string
				IsDir bool
				Meta  cbfsclient.FileMeta
			}{match.path, match.isDir, inf}); err != nil {
				log.Fatalf("Error executing template: %v", err)
			}
		}
	}
}
<commit_msg>Added find -depth, which seems to demonstate a bug. :(<commit_after>package main

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

	"github.com/couchbaselabs/cbfs/client"
	"github.com/couchbaselabs/cbfs/tools"
	"github.com/dustin/httputil"
)

type findType int

const (
	findTypeAny = findType(iota)
	findTypeFile
	findTypeDir
)

var findFlags = flag.NewFlagSet("find", flag.ExitOnError)
var findTemplate = findFlags.String("t", "", "Display template")
var findTemplateFile = findFlags.String("T", "", "Display template filename")
var findDashName = findFlags.String("name", "", "Glob name to match")
var findDashIName = findFlags.String("iname", "",
	"Case insensitive glob name to match")
var findDashMTime = findFlags.Duration("mtime", 0, "Find by mod time")
var findDashDepth = findFlags.Int("depth", 4096, "Maximum search depth")

var findDashType findType

const defaultFindTemplate = `{{.Name}}
`

func (t findType) String() string {
	switch t {
	case findTypeAny:
		return ""
	case findTypeFile:
		return "f"
	case findTypeDir:
		return "d"
	}
	panic("unreachable")
}

func (t *findType) Set(s string) error {
	switch s {
	case "":
		*t = findTypeAny
	case "f":
		*t = findTypeFile
	case "d":
		*t = findTypeDir
	default:
		return fmt.Errorf("must be 'f' or 'd'")
	}
	return nil
}

func init() {
	findFlags.Var(&findDashType, "type", "Type to match (f or d)")
}

type dirAndFileMatcher struct {
	m map[string]struct{}
	p string
	i bool // if true, case insensitive
}

func newDirAndFileMatcher() dirAndFileMatcher {
	rv := dirAndFileMatcher{map[string]struct{}{}, *findDashName, false}
	if *findDashIName != "" {
		rv.i = true
		rv.p = strings.ToLower(*findDashIName)
	}

	return rv
}

type findMatch struct {
	path  string
	isDir bool
}

func (d dirAndFileMatcher) match(name string, isdir bool) bool {
	switch findDashType {
	case findTypeAny:
	case findTypeFile:
		if isdir {
			return false
		}
	case findTypeDir:
		if !isdir {
			return false
		}
	}
	m := name
	if d.i {
		m = strings.ToLower(m)
	}
	matched, err := filepath.Match(d.p, m)
	if err != nil {
		log.Fatalf("Error globbing: %v", err)
	}
	return matched
}

func (d dirAndFileMatcher) matches(name string) []findMatch {
	if d.p == "" {
		return []findMatch{{name, false}}
	}
	var matches []findMatch

	dir := filepath.Dir(name)
	for dir != "." {
		if _, seen := d.m[dir]; !seen {
			d.m[dir] = struct{}{}
			if d.match(filepath.Base(dir), true) {
				matches = append(matches, findMatch{dir, true})
			}
		}
		dir = filepath.Dir(dir)
	}
	// Reverse these so the traversal order makes sense
	for i := 0; i < len(matches)/2; i++ {
		j := len(matches) - i - 1
		matches[i], matches[j] = matches[j], matches[i]
	}

	if d.match(filepath.Base(name), false) {
		matches = append(matches, findMatch{name, false})
	}
	return matches
}

func findMetaMatch(ref func(time.Time) bool, c cbfsclient.FileMeta) bool {
	return true
}

func findGetRefTimeMatch(now time.Time) func(time.Time) bool {
	switch {
	case *findDashMTime > 0:
		return now.Add(-*findDashMTime).Before
	case *findDashMTime < 0:
		return now.Add(*findDashMTime).After
	}
	return func(time.Time) bool { return true }
}

func findCommand(u string, args []string) {
	if *findDashName != "" && *findDashIName != "" {
		log.Fatalf("Can't specify both -name and -iname")
	}
	src := findFlags.Arg(0)
	for src[len(src)-1] == '/' {
		src = src[:len(src)-1]
	}

	tmpl := cbfstool.GetTemplate(*findTemplate, *findTemplateFile,
		defaultFindTemplate)

	httputil.InitHTTPTracker(false)

	client, err := cbfsclient.New(u)
	cbfstool.MaybeFatal(err, "Can't build a client: %v", err)

	things, err := client.ListDepth(src, *findDashDepth)
	cbfstool.MaybeFatal(err, "Can't list things: %v", err)

	metaMatcher := findGetRefTimeMatch(time.Now())
	matcher := newDirAndFileMatcher()
	for fn, inf := range things.Files {
		if !metaMatcher(inf.Modified) {
			continue
		}
		fn = fn[len(src)+1:]
		for _, match := range matcher.matches(fn) {
			if err := tmpl.Execute(os.Stdout, struct {
				Name  string
				IsDir bool
				Meta  cbfsclient.FileMeta
			}{match.path, match.isDir, inf}); err != nil {
				log.Fatalf("Error executing template: %v", err)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE.txt file.

// This program is an example of how you can use the gohg library.

package main

import (
	. "bitbucket.org/gohg/gohg"
	"fmt"
	"log"
)

func main() {
	// Set var hgexe to whatever is appropriate for your situation.
	// You can also change it to test with different versions of Mercurial.
	hgexe := "hg"
	repo := "."
	var cfg []string

	hgcl := NewHgClient()
	if err := hgcl.Connect(hgexe, repo, cfg); err != nil {
		log.Fatal(err)
	}
	defer hgcl.Disconnect()

	hc, _ := NewHgCmd("log")
	o := make([]Option, 2)
	var lim Limit = 2
	o[0] = lim
	var verb Verbose = true
	o[1] = verb
	hc.SetOptions(o)
	// hc.SetParams([]string{"\"my param\""})
	cl, _ := hc.CmdLine(hgcl)
	fmt.Printf("%s\n", cl)
	res, _ := hc.Exec(hgcl)
	fmt.Printf("result:\n%s", string(res))
}
<commit_msg>example2: corrected call to NewHgCmd()<commit_after>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE.txt file.

// This program is an example of how you can use the gohg library.

package main

import (
	. "bitbucket.org/gohg/gohg"
	"fmt"
	"log"
)

func main() {
	// Set var hgexe to whatever is appropriate for your situation.
	// You can also change it to test with different versions of Mercurial.
	hgexe := "hg"
	repo := "."
	var cfg []string

	hgcl := NewHgClient()
	if err := hgcl.Connect(hgexe, repo, cfg); err != nil {
		log.Fatal(err)
	}
	defer hgcl.Disconnect()

	hc, _ := NewHgCmd("log", nil, nil)
	o := make([]Option, 2)
	var lim Limit = 2
	o[0] = lim
	var verb Verbose = true
	o[1] = verb
	hc.SetOptions(o)
	// hc.SetParams([]string{"\"my param\""})
	cl, _ := hc.CmdLine(hgcl)
	fmt.Printf("%s\n", cl)
	res, _ := hc.Exec(hgcl)
	fmt.Printf("result:\n%s", string(res))
}
<|endoftext|>


<commit_before>package eventapi

import (
	"github.com/agoravoting/authapi/middleware"
	s "github.com/agoravoting/authapi/server"
	"github.com/agoravoting/authapi/util"
	"github.com/codegangsta/negroni"
	"github.com/jmoiron/sqlx"
	"github.com/julienschmidt/httprouter"
	// 	"net/http/httputil"
	"encoding/json"
	"net/http"
	"strconv"
)

const (
	SESSION_EXPIRE = 3600
)

type EventApi struct {
	router *httprouter.Router
	name   string

	insertStmt *sqlx.NamedStmt
	getStmt    *sqlx.Stmt
}

func (ea *EventApi) Name() string {
	return ea.name
}

func (ea *EventApi) Init() (err error) {
	// setup the routes
	ea.router = httprouter.New()
	ea.router.GET("/", middleware.Join(
		s.Server.ErrorWrap.Do(ea.list),
		s.Server.CheckPerms("superuser", SESSION_EXPIRE)))
	ea.router.POST("/", middleware.Join(
		s.Server.ErrorWrap.Do(ea.post),
		s.Server.CheckPerms("superuser", SESSION_EXPIRE)))

	ea.router.GET("/:id", middleware.Join(
		s.Server.ErrorWrap.Do(ea.get),
		s.Server.CheckPerms("(superuser|admin-auth-event-${id})", SESSION_EXPIRE)))

	// setup prepared sql queries
	if ea.insertStmt, err = s.Server.Db.PrepareNamed("INSERT INTO event (name, auth_method, auth_method_config) VALUES (:name, :auth_method, :auth_method_config) RETURNING id"); err != nil {
		return
	}

	if ea.getStmt, err = s.Server.Db.Preparex("SELECT * FROM event WHERE id = $1"); err != nil {
		return
	}

	// add the routes to the server
	handler := negroni.New(negroni.Wrap(ea.router))
	s.Server.Mux.OnMux("api/v1/event", handler)
	return
}

// lists the available events
func (ea *EventApi) list(w http.ResponseWriter, r *http.Request, _ httprouter.Params) *middleware.HandledError {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Hello world!"))
	return nil
}

// returns an event
func (ea *EventApi) get(w http.ResponseWriter, r *http.Request, p httprouter.Params) *middleware.HandledError {
	var (
		e   []Event
		err error
		id  int
	)
	if id, err := strconv.ParseInt(p.ByName("id"), 10, 32); err != nil || id <= 0 {
		return &middleware.HandledError{err, 400, "Invalid id format", "invalid-format"}
	}

	if err = ea.getStmt.Select(&e, id); err != nil {
		return &middleware.HandledError{err, 500, "Database error", "error-select"}
	}

	if len(e) == 0 {
		return &middleware.HandledError{err, 404, "Not found", "not-found"}
	}

	b, err := e[0].Marshal()
	if err != nil {
		return &middleware.HandledError{err, 500, "Error marshalling the data", "marshall-error"}
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(b)
	return nil
}

// parses an event from a request.
// TODO: generalize and move to utils pkg
func parseEvent(r *http.Request) (e Event, err error) {
	// 	rb, err := httputil.DumpRequest(r, true)
	if err != nil {
		return
	}
	decoder := json.NewDecoder(r.Body)
	err = decoder.Decode(&e)
	if err != nil {
		return
	}
	return
}

// add a new event
func (ea *EventApi) post(w http.ResponseWriter, r *http.Request, _ httprouter.Params) *middleware.HandledError {
	var (
		tx    = s.Server.Db.MustBegin()
		event Event
		id    int
		err   error
	)
	event, err = parseEvent(r)
	if err != nil {
		return &middleware.HandledError{err, 400, "Invalid json-encoded event", "invalid-json"}
	}
	event_json, err := event.Json()
	if err != nil {
		return &middleware.HandledError{err, 500, "Error re-writing the data to json", "error-json-encode"}
	}

	if err = tx.NamedStmt(ea.insertStmt).QueryRowx(event_json).Scan(&id); err != nil {
		tx.Rollback()
		return &middleware.HandledError{err, 500, "Error inserting the event", "error-insert"}
	}
	err = tx.Commit()
	if err != nil {
		tx.Rollback()
		return &middleware.HandledError{err, 500, "Error comitting the event", "error-commit"}
	}

	// return id
	if err = util.WriteIdJson(w, id); err != nil {
		return &middleware.HandledError{err, 500, "Error returing the id", "error-return"}
	}
	return nil
}

// add the modules to available modules on startup
func init() {
	s.Server.AvailableModules = append(s.Server.AvailableModules, &EventApi{name: "github.com/agoravoting/authapi/eventapi"})
}
<commit_msg>fixing composite literal uses unkeyed fields with HandledError, flagged by go vet tool<commit_after>package eventapi

import (
	"github.com/agoravoting/authapi/middleware"
	s "github.com/agoravoting/authapi/server"
	"github.com/agoravoting/authapi/util"
	"github.com/codegangsta/negroni"
	"github.com/jmoiron/sqlx"
	"github.com/julienschmidt/httprouter"
	// 	"net/http/httputil"
	"encoding/json"
	"net/http"
	"strconv"
)

const (
	SESSION_EXPIRE = 3600
)

type EventApi struct {
	router *httprouter.Router
	name   string

	insertStmt *sqlx.NamedStmt
	getStmt    *sqlx.Stmt
}

func (ea *EventApi) Name() string {
	return ea.name
}

func (ea *EventApi) Init() (err error) {
	// setup the routes
	ea.router = httprouter.New()
	ea.router.GET("/", middleware.Join(
		s.Server.ErrorWrap.Do(ea.list),
		s.Server.CheckPerms("superuser", SESSION_EXPIRE)))
	ea.router.POST("/", middleware.Join(
		s.Server.ErrorWrap.Do(ea.post),
		s.Server.CheckPerms("superuser", SESSION_EXPIRE)))

	ea.router.GET("/:id", middleware.Join(
		s.Server.ErrorWrap.Do(ea.get),
		s.Server.CheckPerms("(superuser|admin-auth-event-${id})", SESSION_EXPIRE)))

	// setup prepared sql queries
	if ea.insertStmt, err = s.Server.Db.PrepareNamed("INSERT INTO event (name, auth_method, auth_method_config) VALUES (:name, :auth_method, :auth_method_config) RETURNING id"); err != nil {
		return
	}

	if ea.getStmt, err = s.Server.Db.Preparex("SELECT * FROM event WHERE id = $1"); err != nil {
		return
	}

	// add the routes to the server
	handler := negroni.New(negroni.Wrap(ea.router))
	s.Server.Mux.OnMux("api/v1/event", handler)
	return
}

// lists the available events
func (ea *EventApi) list(w http.ResponseWriter, r *http.Request, _ httprouter.Params) *middleware.HandledError {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Hello world!"))
	return nil
}

// returns an event
func (ea *EventApi) get(w http.ResponseWriter, r *http.Request, p httprouter.Params) *middleware.HandledError {
	var (
		e   []Event
		err error
		id  int
	)
	if id, err := strconv.ParseInt(p.ByName("id"), 10, 32); err != nil || id <= 0 {
		return &middleware.HandledError{Err: err, Code: 400, Message: "Invalid id format", CodedMessage: "invalid-format"}
	}

	if err = ea.getStmt.Select(&e, id); err != nil {
		return &middleware.HandledError{Err: err, Code: 500, Message: "Database error", CodedMessage: "error-select"}
	}

	if len(e) == 0 {
		return &middleware.HandledError{Err: err, Code: 404, Message: "Not found", CodedMessage: "not-found"}
	}

	b, err := e[0].Marshal()
	if err != nil {
		return &middleware.HandledError{Err: err, Code: 500, Message: "Error marshalling the data", CodedMessage: "marshall-error"}
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(b)
	return nil
}

// parses an event from a request.
// TODO: generalize and move to utils pkg
func parseEvent(r *http.Request) (e Event, err error) {
	// 	rb, err := httputil.DumpRequest(r, true)
	if err != nil {
		return
	}
	decoder := json.NewDecoder(r.Body)
	err = decoder.Decode(&e)
	if err != nil {
		return
	}
	return
}

// add a new event
func (ea *EventApi) post(w http.ResponseWriter, r *http.Request, _ httprouter.Params) *middleware.HandledError {
	var (
		tx    = s.Server.Db.MustBegin()
		event Event
		id    int
		err   error
	)
	event, err = parseEvent(r)
	if err != nil {
		return &middleware.HandledError{Err: err, Code: 400, Message: "Invalid json-encoded event", CodedMessage: "invalid-json"}
	}
	event_json, err := event.Json()
	if err != nil {
		return &middleware.HandledError{Err: err, Code: 500, Message: "Error re-writing the data to json", CodedMessage: "error-json-encode"}
	}

	if err = tx.NamedStmt(ea.insertStmt).QueryRowx(event_json).Scan(&id); err != nil {
		tx.Rollback()
		return &middleware.HandledError{Err: err, Code: 500, Message: "Error inserting the event", CodedMessage: "error-insert"}
	}
	err = tx.Commit()
	if err != nil {
		tx.Rollback()
		return &middleware.HandledError{Err: err, Code: 500, Message: "Error comitting the event", CodedMessage: "error-commit"}
	}

	// return id
	if err = util.WriteIdJson(w, id); err != nil {
		return &middleware.HandledError{Err: err, Code: 500, Message: "Error returing the id", CodedMessage: "error-return"}
	}
	return nil
}

// add the modules to available modules on startup
func init() {
	s.Server.AvailableModules = append(s.Server.AvailableModules, &EventApi{name: "github.com/agoravoting/authapi/eventapi"})
}
<|endoftext|>


<commit_before>package eventsocketclient

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

	"github.com/gorilla/websocket"
)

var d websocket.Dialer

func init() {
	d = websocket.Dialer{
		NetDial:          nil,
		TLSClientConfig:  nil,
		HandshakeTimeout: time.Second * 5,
		ReadBufferSize:   4096,
		WriteBufferSize:  4096,
	}
}

// Client is the main eventsocket client
type Client struct {
	// The client Id, provided by the server
	Id string `json:"Id"`

	// channels for receiving messages
	RecvBroadcast chan *Received `json:"-"`
	RecvRequest   chan *Received `json:"-"`
	RecvError     chan error     `json:"-"`

	// the URL to the server
	url string

	// the actual websocket connection, after we've connected
	ws *websocket.Conn

	// a mapping of all requests that are currently inflight
	liveRequests map[string]chan *Received

	// a mapping of the subscription return channels
	subscriptions map[string]chan *Received
}

// NewClient registers a new client with the server
func NewClient(url string) (*Client, error) {
	resp, err := http.Post(fmt.Sprintf("http://%s/v1/clients", url), "application/json", strings.NewReader(""))
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	client := Client{
		url:           url,
		liveRequests:  make(map[string]chan *Received),
		subscriptions: make(map[string]chan *Received),
		RecvBroadcast: make(chan *Received),
		RecvRequest:   make(chan *Received),
		RecvError:     make(chan error),
	}

	// unmarshal the response body
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	json.Unmarshal(body, &client)

	return &client, nil
}

// DialWs will dial the websocket server, and get a websocket connection in return
func (client *Client) DialWs() error {
	headers := http.Header{}
	ws, _, err := d.Dial(fmt.Sprintf("ws://%s/v1/clients/%s/ws", client.url, client.Id), headers)
	if err != nil {
		return err
	}

	client.ws = ws

	return nil
}

// Reconnect attempts a reconnect with the server
func (client *Client) Reconnect() error {
	client.ws.Close()

	return client.DialWs()
}

// Close closes the connections
func (client *Client) Close() {
	client.ws.Close()
}

// Recv reads from the socket
func (client *Client) Recv() error {
	for {
		m := &Message{}
		client.SetReadDeadline(30 * time.Second)
		if err := client.ws.ReadJSON(m); err != nil {
			// TODO: something other than panic
			client.RecvError <- err
			continue
		}

		r := &Received{
			Message: m,
			Err:     nil,
		}

		switch m.MessageType {
		case MESSAGE_TYPE_BROADCAST:
			client.RecvBroadcast <- r
		case MESSAGE_TYPE_STANDARD:
			client.subscriptions[r.Message.Event] <- r
		case MESSAGE_TYPE_REQUEST:
			client.RecvRequest <- r
		case MESSAGE_TYPE_REPLY:
			client.liveRequests[m.RequestId] <- r
			close(client.liveRequests[m.RequestId])
			delete(client.liveRequests, m.RequestId)
		}
	}

	return nil
}

// Broadcast a payload
func (client *Client) Broadcast(p *Payload) error {
	m := &Message{
		MessageType: MESSAGE_TYPE_BROADCAST,
		Payload:     p,
	}

	return client.write(m)
}

// Emit an event
func (client *Client) Emit(event string, p *Payload) error {
	m := &Message{
		MessageType: MESSAGE_TYPE_STANDARD,
		Event:       event,
		Payload:     p,
	}

	return client.write(m)
}

// Suscribe to an event(s)
func (client *Client) Suscribe(events ...string) (<-chan *Received, error) {
	p := NewPayload()
	p["Events"] = events

	m := &Message{
		MessageType: MESSAGE_TYPE_SUSCRIBE,
		Payload:     &p,
	}

	if err := client.write(m); err != nil {
		return nil, err
	}

	// create the return channel
	c := make(chan *Received)
	for _, event := range events {
		client.subscriptions[event] = c
	}

	return c, nil
}

// Request will execute a request against a client
func (client *Client) Request(id string, p *Payload) (<-chan *Received, error) {
	requestID := makeUuid()
	m := &Message{
		MessageType:     MESSAGE_TYPE_REQUEST,
		RequestId:       requestID,
		RequestClientId: id,
		Payload:         p,
	}

	if err := client.write(m); err != nil {
		return nil, err
	}

	c := make(chan *Received)
	client.liveRequests[requestID] = c
	return c, nil
}

// Reply sends a reply to a request
func (client *Client) Reply(requestID, cid string, p *Payload) error {
	m := &Message{
		MessageType:   MESSAGE_TYPE_REPLY,
		ReplyClientId: cid,
		RequestId:     requestID,
		Payload:       p,
	}

	return client.write(m)

}

// write a message to the socket
func (client *Client) write(m *Message) error {
	return client.ws.WriteJSON(m)
}

// SetMaxMessageSize sets the max message size. Note: this is not the max frame size
func (client *Client) SetMaxMessageSize(limit int64) {
	client.ws.SetReadLimit(limit)
}

// SetReadDeadline sets the deadline to receive a response on the socket
func (client *Client) SetReadDeadline(t time.Duration) {
	client.ws.SetReadDeadline(time.Now().Add(t))
}
<commit_msg>Remove 30 second ReadDeadline<commit_after>package eventsocketclient

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

	"github.com/gorilla/websocket"
)

var d websocket.Dialer

func init() {
	d = websocket.Dialer{
		NetDial:          nil,
		TLSClientConfig:  nil,
		HandshakeTimeout: time.Second * 5,
		ReadBufferSize:   4096,
		WriteBufferSize:  4096,
	}
}

// Client is the main eventsocket client
type Client struct {
	// The client Id, provided by the server
	Id string `json:"Id"`

	// channels for receiving messages
	RecvBroadcast chan *Received `json:"-"`
	RecvRequest   chan *Received `json:"-"`
	RecvError     chan error     `json:"-"`

	// the URL to the server
	url string

	// the actual websocket connection, after we've connected
	ws *websocket.Conn

	// a mapping of all requests that are currently inflight
	liveRequests map[string]chan *Received

	// a mapping of the subscription return channels
	subscriptions map[string]chan *Received
}

// NewClient registers a new client with the server
func NewClient(url string) (*Client, error) {
	resp, err := http.Post(fmt.Sprintf("http://%s/v1/clients", url), "application/json", strings.NewReader(""))
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	client := Client{
		url:           url,
		liveRequests:  make(map[string]chan *Received),
		subscriptions: make(map[string]chan *Received),
		RecvBroadcast: make(chan *Received),
		RecvRequest:   make(chan *Received),
		RecvError:     make(chan error),
	}

	// unmarshal the response body
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	json.Unmarshal(body, &client)

	return &client, nil
}

// DialWs will dial the websocket server, and get a websocket connection in return
func (client *Client) DialWs() error {
	headers := http.Header{}
	ws, _, err := d.Dial(fmt.Sprintf("ws://%s/v1/clients/%s/ws", client.url, client.Id), headers)
	if err != nil {
		return err
	}

	client.ws = ws

	return nil
}

// Reconnect attempts a reconnect with the server
func (client *Client) Reconnect() error {
	client.ws.Close()

	return client.DialWs()
}

// Close closes the connections
func (client *Client) Close() {
	client.ws.Close()
}

// Recv reads from the socket
func (client *Client) Recv() error {
	for {
		m := &Message{}
		if err := client.ws.ReadJSON(m); err != nil {
			// TODO: something other than panic
			client.RecvError <- err
			continue
		}

		r := &Received{
			Message: m,
			Err:     nil,
		}

		switch m.MessageType {
		case MESSAGE_TYPE_BROADCAST:
			client.RecvBroadcast <- r
		case MESSAGE_TYPE_STANDARD:
			client.subscriptions[r.Message.Event] <- r
		case MESSAGE_TYPE_REQUEST:
			client.RecvRequest <- r
		case MESSAGE_TYPE_REPLY:
			client.liveRequests[m.RequestId] <- r
			close(client.liveRequests[m.RequestId])
			delete(client.liveRequests, m.RequestId)
		}
	}

	return nil
}

// Broadcast a payload
func (client *Client) Broadcast(p *Payload) error {
	m := &Message{
		MessageType: MESSAGE_TYPE_BROADCAST,
		Payload:     p,
	}

	return client.write(m)
}

// Emit an event
func (client *Client) Emit(event string, p *Payload) error {
	m := &Message{
		MessageType: MESSAGE_TYPE_STANDARD,
		Event:       event,
		Payload:     p,
	}

	return client.write(m)
}

// Suscribe to an event(s)
func (client *Client) Suscribe(events ...string) (<-chan *Received, error) {
	p := NewPayload()
	p["Events"] = events

	m := &Message{
		MessageType: MESSAGE_TYPE_SUSCRIBE,
		Payload:     &p,
	}

	if err := client.write(m); err != nil {
		return nil, err
	}

	// create the return channel
	c := make(chan *Received)
	for _, event := range events {
		client.subscriptions[event] = c
	}

	return c, nil
}

// Request will execute a request against a client
func (client *Client) Request(id string, p *Payload) (<-chan *Received, error) {
	requestID := makeUuid()
	m := &Message{
		MessageType:     MESSAGE_TYPE_REQUEST,
		RequestId:       requestID,
		RequestClientId: id,
		Payload:         p,
	}

	if err := client.write(m); err != nil {
		return nil, err
	}

	c := make(chan *Received)
	client.liveRequests[requestID] = c
	return c, nil
}

// Reply sends a reply to a request
func (client *Client) Reply(requestID, cid string, p *Payload) error {
	m := &Message{
		MessageType:   MESSAGE_TYPE_REPLY,
		ReplyClientId: cid,
		RequestId:     requestID,
		Payload:       p,
	}

	return client.write(m)

}

// write a message to the socket
func (client *Client) write(m *Message) error {
	return client.ws.WriteJSON(m)
}

// SetMaxMessageSize sets the max message size. Note: this is not the max frame size
func (client *Client) SetMaxMessageSize(limit int64) {
	client.ws.SetReadLimit(limit)
}

// SetReadDeadline sets the deadline to receive a response on the socket
func (client *Client) SetReadDeadline(t time.Duration) {
	client.ws.SetReadDeadline(time.Now().Add(t))
}
<|endoftext|>


<commit_before>package algorithm

//SkipList
//author:Xiong Chuan Liang
//date:2014-1-27

import (
	"fmt"
	"math/rand"
)

const SKIPLIST_MAXLEVEL = 8 //32
const SKIPLIST_P = 4

type SkipList struct {
	Header []List
	Level  int
}

func NewSkipList() *SkipList {
	return &SkipList{Level: 1, Header: make([]List, SKIPLIST_MAXLEVEL)}

}

func (skipList *SkipList) Insert(key int) {
	update := make(map[int]*Node)

	for i := len(skipList.Header) - 1; i >= 0; i-- {
		if skipList.Header[i].Len() > 0 {
			for e := skipList.Header[i].Front(); e != nil; e = e.Next() {
				if e.Value.(int) >= key {
					update[i] = e
					break
				}
			}
		} //Heaer[lv].List
	} //Header Level

	level := skipList.Random_level()
	if level > skipList.Level {
		skipList.Level = level
	}

	for i := 0; i < level; i++ {
		if v, ok := update[i]; ok {
			skipList.Header[i].InsertBefore(key, v)
		} else {
			skipList.Header[i].PushBack(key)
		}
	}

}

func (skipList *SkipList) Search(key int) *Node {

	for i := len(skipList.Header) - 1; i >= 0; i-- {
		if skipList.Header[i].Len() > 0 {
			for e := skipList.Header[i].Front(); e != nil; e = e.Next() {
				switch {
				case e.Value.(int) == key:
					fmt.Println("Found level=", i, " key=", key)
					return e
				case e.Value.(int) > key:
					break
				}
			} //end for

		} //end if

	} //end for
	return nil
}

func (skipList *SkipList) Delete(key int) {
	for i := len(skipList.Header) - 1; i >= 0; i-- {
		if skipList.Header[i].Len() > 0 {
			for e := skipList.Header[i].Front(); e != nil; e = e.Next() {
				switch {
				case e.Value.(int) == key:
					fmt.Println("Delete level=", i, " key=", key)
					skipList.Header[i].remove(e)

				case e.Value.(int) > key:
					break
				}
			} //end for

		} //end if

	} //end for

}

func (skipList *SkipList) PrintSkipList() {
	fmt.Println("\nSkipList-------------------------------------------")
	for i := SKIPLIST_MAXLEVEL - 1; i >= 0; i-- {
		fmt.Println("level:", i)
		if skipList.Header[i].Len() > 0 {
			for e := skipList.Header[i].Front(); e != nil; e = e.Next() {
				fmt.Printf("%d ", e.Value)
			} //end for
		} //end if
		fmt.Println("\n--------------------------------------------------------")
	} //end for
}

func (skipList *SkipList) Random_level() int {

	level := 1
	for (rand.Int31()&0xFFFF)%SKIPLIST_P == 0 {
		level += 1
	}
	if level < SKIPLIST_MAXLEVEL {
		return level
	} else {
		return SKIPLIST_MAXLEVEL
	}
}

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

type Node struct {
	next, prev *Node
	list       *List

	Value interface{}
}

type List struct {
	root Node
	len  int
}

func (node *Node) Next() *Node {
	if p := node.next; node.list != nil && p != &node.list.root {
		return p
	}
	return nil
}

func (node *Node) Prev() *Node {
	if p := node.prev; node.list != nil && p != &node.list.root {
		return p
	}
	return nil
}

func (list *List) Init() *List {
	list.root.next = &list.root
	list.root.prev = &list.root
	list.len = 0
	return list
}

func New() *List {
	return new(List).Init()
}

func (list *List) lazyInit() {
	if list.root.next == nil {
		list.Init()
	}
}

func (list *List) Len() int {
	return list.len
}

func (list *List) remove(e *Node) *Node {
	e.prev.next = e.next
	e.next.prev = e.prev
	e.next = nil
	e.prev = nil
	e.list = nil
	list.len--
	return e
}

func (list *List) Remove(e *Node) interface{} {
	if e.list == list {
		list.remove(e)
	}
	return e.Value
}

func (list *List) Front() *Node {
	if list.len == 0 {
		return nil
	}
	return list.root.next
}

func (list *List) Back() *Node {
	if list.len == 0 {
		return nil
	}
	return list.root.prev
}

func (list *List) insert(e, at *Node) *Node {
	n := at.next
	at.next = e
	e.prev = at
	e.next = n
	n.prev = e
	e.list = list

	list.len++
	return e
}

func (list *List) insertValue(v interface{}, at *Node) *Node {

	return list.insert(&Node{Value: v}, at)
}

func (list *List) InsertBefore(v interface{}, mark *Node) *Node {
	if mark.list != list {
		return nil
	}
	return list.insertValue(v, mark.prev)
}

func (list *List) PushBack(v interface{}) *Node {
	list.lazyInit()
	return list.insertValue(v, list.root.prev)
}
<commit_msg>Update skiplist.go<commit_after>package algorithm

//SkipList
//author:Xiong Chuan Liang
//date:2014-1-28

import (
	"fmt"
	//"github.com/xclpkg/algorithm"
	"math/rand"
)

const SKIPLIST_MAXLEVEL = 8 //32
const SKIPLIST_P = 4

type Node struct {
	Forward  []Node
	Value interface{}
}

func NewNode(v interface{},level int) *Node {
	return &Node{Value: v, Forward: make([]Node, level)}
}

type SkipList struct {
	Header *Node
	Level  int
}

func NewSkipList() *SkipList {
	return &SkipList{Level: 1, Header: NewNode(0,SKIPLIST_MAXLEVEL)}
}

func (skipList *SkipList) Insert(key int) {

	update := make(map[int]*Node)
	node := skipList.Header

	for i := skipList.Level - 1; i >= 0; i-- {
		 for {
		 	 if node.Forward[i].Value != nil && node.Forward[i].Value.(int) < key {
		 	 	node = &node.Forward[i]
		 	 }else{
		 	 	break;
		 	 }
		 }
		 update[i] = node
	}

	level := skipList.Random_level()
	if level > skipList.Level {
		for i := skipList.Level; i < level; i++ {
			update[i] = skipList.Header
		}
		skipList.Level = level
	}

	newNode := NewNode(key,level)

	for i := 0; i < level; i++ {
		newNode.Forward[i] = update[i].Forward[i]
		update[i].Forward[i] = *newNode
	}

}

func (skipList *SkipList) Random_level() int {

	level := 1
	for (rand.Int31()&0xFFFF)%SKIPLIST_P == 0 {
		level += 1
	}
	if level < SKIPLIST_MAXLEVEL {
		return level
	} else {
		return SKIPLIST_MAXLEVEL
	}
}

func (skipList *SkipList) PrintSkipList() {

	fmt.Println("\nSkipList-------------------------------------------")
	for i := SKIPLIST_MAXLEVEL - 1; i >= 0; i-- {

		 fmt.Println("level:", i)
		 node := skipList.Header.Forward[i]
		 for {
		 	 if node.Value != nil {
		 	 	fmt.Printf("%d ", node.Value.(int))
		 	 	node = node.Forward[i]
		 	 }else{
		 	 	break;
		 	 }
		 }
		 fmt.Println("\n--------------------------------------------------------")
	} //end for

	fmt.Println("Current MaxLevel:", skipList.Level)
}

func (skipList *SkipList) Search(key int) *Node {

	node := skipList.Header
	for i := skipList.Level - 1; i >= 0; i-- {

		fmt.Println("\n Search() Level=", i)
		for {
			if node.Forward[i].Value == nil {
				break
			}

			fmt.Printf("  %d ", node.Forward[i].Value)
			if node.Forward[i].Value.(int) == key {
				fmt.Println("\nFound level=", i, " key=", key)
				return &node.Forward[i]
			}

			if  node.Forward[i].Value.(int) < key {
				node = &node.Forward[i]
				continue
			}else{ // > key
				break
			}
		 } //end for find

	} //end level
	return nil
}

func (skipList *SkipList)Remove(key int) {

	update := make(map[int]*Node)
	node := skipList.Header
	for i := skipList.Level - 1; i >= 0; i-- {

		for {

			if node.Forward[i].Value == nil {
				break
			}

			if node.Forward[i].Value.(int) == key {
				fmt.Println("Remove() level=", i, " key=", key)
				update[i] = node
				break
			}

			if  node.Forward[i].Value.(int) < key {
				node = &node.Forward[i]
				continue
			}else{ // > key
				break
			}

		 } //end for find

	} //end level

	for i,v := range update {
		if v == skipList.Header {
			skipList.Level --
		}
 		v.Forward[i] = v.Forward[i].Forward[i]
	}
}
<|endoftext|>